@@ -1155,6 +1155,27 @@ struct cfg80211_csa_settings {
u8 count;
};
+/**
+ * struct cfg80211_cca_settings - color change settings
+ *
+ * Used for color change
+ *
+ * @beacon_cca: beacon data while performing the change
+ * @counter_offsets_beacon: offsets of the counters within the beacon (tail)
+ * @counter_offsets_presp: offsets of the counters within the probe response
+ * @beacon_after: beacon data to be used after the change
+ * @count: number of beacons until the change
+ * @color: the color that we will have after th change
+ */
+struct cfg80211_cca_settings {
+ struct cfg80211_beacon_data beacon_cca;
+ u16 counter_offset_beacon;
+ u16 counter_offset_presp;
+ struct cfg80211_beacon_data beacon_after;
+ u8 count;
+ u8 color;
+};
+
#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
/**
@@ -3795,6 +3816,7 @@ struct mgmt_frame_regs {
* This callback may sleep.
* @reset_tid_config: Reset TID specific configuration for the peer, for the
* given TIDs. This callback may sleep.
+ * @color_change: initiate a color change (with CCA).
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -4123,6 +4145,9 @@ struct cfg80211_ops {
struct cfg80211_tid_config *tid_conf);
int (*reset_tid_config)(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, u8 tids);
+ int (*color_change)(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_cca_settings *params);
};
/*
@@ -4172,6 +4197,7 @@ struct cfg80211_ops {
* @WIPHY_FLAG_HAS_STATIC_WEP: The device supports static WEP key installation
* before connection.
* @WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK: The device supports bigger kek and kck keys
+ * @WIPHY_FLAG_SUPPORTS_BSS_COLOR: Device supports BSS coloring
*/
enum wiphy_flags {
WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK = BIT(0),
@@ -4198,6 +4224,7 @@ enum wiphy_flags {
WIPHY_FLAG_SUPPORTS_5_10_MHZ = BIT(22),
WIPHY_FLAG_HAS_CHANNEL_SWITCH = BIT(23),
WIPHY_FLAG_HAS_STATIC_WEP = BIT(24),
+ WIPHY_FLAG_SUPPORTS_BSS_COLOR = BIT(25),
};
/**
@@ -7881,4 +7908,41 @@ void cfg80211_update_owe_info_event(struct net_device *netdev,
struct cfg80211_update_owe_info *owe_info,
gfp_t gfp);
+/**
+ * cfg80211_obss_color_collision_notify - notify about bss color collisions
+ * @dev: network device
+ * @color_bitmap: representations of the colors that the local BSS is aware of
+ */
+void cfg80211_obss_color_collision_notify(struct net_device *dev,
+ u64 color_bitmap);
+
+/*
+ * cfg80211_color_change_started_notify - notify color change start
+ * @dev: the device on which the color is switched
+ * @count: the number of TBTTs until the color change happens
+ *
+ * Inform the userspace about the color change that has just
+ * started.
+ */
+void cfg80211_color_change_started_notify(struct net_device *dev,
+ u8 count);
+
+/*
+ * cfg80211_color_change_aborted_notify - notify color change abort
+ * @dev: the device on which the color is switched
+ *
+ * Inform the userspace about the color change that has just
+ * started.
+ */
+void cfg80211_color_change_aborted_notify(struct net_device *dev);
+
+/*
+ * cfg80211_color_change_notify - notify color change completion
+ * @dev: the device on which the color was switched
+ *
+ * Inform the userspace about the color change that has just
+ * completed.
+ */
+void cfg80211_color_change_notify(struct net_device *dev);
+
#endif /* __NET_CFG80211_H */
@@ -1170,6 +1170,20 @@
* includes the contents of the frame. %NL80211_ATTR_ACK flag is included
* if the recipient acknowledged the frame.
*
+ * @NL80211_CMD_OBSS_COLOR_COLLISION: This notification is sent out whenever a
+ * mac detects a bss color collision.
+ *
+ * @NL80211_CMD_COLOR_CHANGE: This command is used to indicate that we want to
+ * change the BSS color.
+ *
+ * @NL80211_CMD_CCA_STARTED_NOTIFY: Notify userland, that we color change has
+ * started
+ *
+ * @NL80211_CMD_CCA_ABORTED_NOTIFY: Notify userland, that we color change has
+ * been aborted
+ *
+ * @NL80211_CMD_CCA_NOTIFY: Notify userland, that we color change has completed
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1400,6 +1414,13 @@ enum nl80211_commands {
NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS,
+ NL80211_CMD_OBSS_COLOR_COLLISION,
+
+ NL80211_CMD_COLOR_CHANGE,
+ NL80211_CMD_CCA_STARTED_NOTIFY,
+ NL80211_CMD_CCA_ABORTED_NOTIFY,
+ NL80211_CMD_CCA_NOTIFY,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -2505,6 +2526,20 @@ enum nl80211_commands {
* @NL80211_ATTR_HE_6GHZ_CAPABILITY: HE 6 GHz Band Capability element (from
* association request when used with NL80211_CMD_NEW_STATION).
*
+ * @NL80211_ATTR_OBSS_COLOR_BITMAP: bitmap of the 64 BSS colors for the
+ * %NL80211_CMD_OBSS_COLOR_COLLISION command.
+ *
+ * @NL80211_ATTR_CCA_COUNT: u8 attribute specifying the number of TBTT's
+ * until the color switch event.
+ * @NL80211_ATTR_CCA_COLOR: u8 attribute specifying the color that we are
+ * switching to
+ * @NL80211_ATTR_CCA_IES: Nested set of attributes containing the IE information
+ * for the time while performing a color switch.
+ * @NL80211_ATTR_CCA_C_OFF_BEACON: An array of offsets (u16) to the color
+ * switch counters in the beacons tail (%NL80211_ATTR_BEACON_TAIL).
+ * @NL80211_ATTR_CCA_C_OFF_PRESP: An array of offsets (u16) to the color
+ * switch counters in the probe response (%NL80211_ATTR_PROBE_RESP).
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2987,6 +3022,14 @@ enum nl80211_attrs {
NL80211_ATTR_HE_6GHZ_CAPABILITY,
+ NL80211_ATTR_OBSS_COLOR_BITMAP,
+
+ NL80211_ATTR_CCA_COUNT,
+ NL80211_ATTR_CCA_COLOR,
+ NL80211_ATTR_CCA_IES,
+ NL80211_ATTR_CCA_C_OFF_BEACON,
+ NL80211_ATTR_CCA_C_OFF_PRESP,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -658,6 +658,12 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
.type = NLA_EXACT_LEN,
.len = sizeof(struct ieee80211_he_6ghz_capa),
},
+ [NL80211_ATTR_OBSS_COLOR_BITMAP] = { .type = NLA_U64 },
+ [NL80211_ATTR_CCA_COUNT] = { .type = NLA_U8 },
+ [NL80211_ATTR_CCA_COLOR] = { .type = NLA_U8 },
+ [NL80211_ATTR_CCA_IES] = { .type = NLA_NESTED },
+ [NL80211_ATTR_CCA_C_OFF_BEACON] = { .type = NLA_U16 },
+ [NL80211_ATTR_CCA_C_OFF_PRESP] = { .type = NLA_U16 },
};
/* policy for the key attributes */
@@ -14274,6 +14280,76 @@ static int nl80211_set_tid_config(struct sk_buff *skb,
return ret;
}
+static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_cca_settings params;
+ static struct nlattr *cca_attrs[NL80211_ATTR_MAX + 1];
+ int err;
+
+ if (!rdev->ops->color_change ||
+ !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_BSS_COLOR))
+ return -EOPNOTSUPP;
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP)
+ return -EOPNOTSUPP;
+
+ memset(¶ms, 0, sizeof(params));
+
+ if (!info->attrs[NL80211_ATTR_CCA_COUNT] ||
+ !info->attrs[NL80211_ATTR_CCA_COLOR] ||
+ !info->attrs[NL80211_ATTR_CCA_IES])
+ return -EINVAL;
+
+ params.count = nla_get_u8(info->attrs[NL80211_ATTR_CCA_COUNT]);
+ params.color = nla_get_u8(info->attrs[NL80211_ATTR_CCA_COLOR]);
+
+ err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_after);
+ if (err)
+ return err;
+
+ err = nla_parse_nested_deprecated(cca_attrs, NL80211_ATTR_MAX,
+ info->attrs[NL80211_ATTR_CCA_IES],
+ nl80211_policy, info->extack);
+ if (err)
+ return err;
+
+ err = nl80211_parse_beacon(rdev, cca_attrs, ¶ms.beacon_cca);
+ if (err)
+ return err;
+
+ if (!cca_attrs[NL80211_ATTR_CCA_C_OFF_BEACON])
+ return -EINVAL;
+
+ params.counter_offset_beacon =
+ nla_get_u16(cca_attrs[NL80211_ATTR_CCA_C_OFF_BEACON]);
+
+ if (params.counter_offset_beacon >= params.beacon_cca.tail_len)
+ return -EINVAL;
+
+ if (params.beacon_cca.tail[params.counter_offset_beacon] != params.count)
+ return -EINVAL;
+
+ if (cca_attrs[NL80211_ATTR_CCA_C_OFF_PRESP]) {
+ params.counter_offset_presp =
+ nla_get_u16(cca_attrs[NL80211_ATTR_CCA_C_OFF_PRESP]);
+
+ if (params.counter_offset_presp >= params.beacon_cca.probe_resp_len)
+ return -EINVAL;
+
+ if (params.beacon_cca.probe_resp[params.counter_offset_presp] != params.count)
+ return -EINVAL;
+ }
+
+ wdev_lock(wdev);
+ err = rdev_color_change(rdev, dev, ¶ms);
+ wdev_unlock(wdev);
+
+ return err;
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -15235,6 +15311,14 @@ static const struct genl_ops nl80211_ops[] = {
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_COLOR_CHANGE,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .doit = nl80211_color_change,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_family nl80211_fam __ro_after_init = {
@@ -16848,6 +16932,86 @@ void cfg80211_ch_switch_started_notify(struct net_device *dev,
}
EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
+static void nl80211_bss_color_notify(struct net_device *netdev,
+ gfp_t gfp, enum nl80211_commands notif,
+ u8 count, u64 color_bitmap)
+{
+ struct wireless_dev *wdev = netdev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+ struct sk_buff *msg;
+ void *hdr;
+
+ ASSERT_WDEV_LOCK(wdev);
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, notif);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
+ goto nla_put_failure;
+
+ if (notif == NL80211_CMD_CCA_STARTED_NOTIFY &&
+ nla_put_u32(msg, NL80211_ATTR_CCA_COUNT, count))
+ goto nla_put_failure;
+
+ if (notif == NL80211_CMD_OBSS_COLOR_COLLISION &&
+ nla_put_u64_64bit(msg, NL80211_ATTR_OBSS_COLOR_BITMAP,
+ color_bitmap, NL80211_ATTR_PAD))
+ goto nla_put_failure;
+
+ genlmsg_end(msg, hdr);
+
+ genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+ NL80211_MCGRP_MLME, gfp);
+ return;
+
+ nla_put_failure:
+ nlmsg_free(msg);
+}
+
+void cfg80211_obss_color_collision_notify(struct net_device *dev,
+ u64 color_bitmap)
+{
+ nl80211_bss_color_notify(dev, GFP_KERNEL,
+ NL80211_CMD_OBSS_COLOR_COLLISION, 0,
+ color_bitmap);
+}
+EXPORT_SYMBOL(cfg80211_obss_color_collision_notify);
+
+void cfg80211_color_change_notify(struct net_device *dev)
+{
+ trace_cfg80211_color_change_notify(dev);
+
+ nl80211_bss_color_notify(dev, GFP_KERNEL,
+ NL80211_CMD_CCA_NOTIFY, 0, 0);
+}
+EXPORT_SYMBOL(cfg80211_color_change_notify);
+
+void cfg80211_color_change_started_notify(struct net_device *dev, u8 count)
+{
+ trace_cfg80211_color_change_started_notify(dev);
+
+ nl80211_bss_color_notify(dev, GFP_KERNEL,
+ NL80211_CMD_CCA_STARTED_NOTIFY, count, 0);
+}
+EXPORT_SYMBOL(cfg80211_color_change_started_notify);
+
+void cfg80211_color_change_aborted_notify(struct net_device *dev)
+{
+ trace_cfg80211_color_change_aborted_notify(dev);
+
+ nl80211_bss_color_notify(dev, GFP_KERNEL,
+ NL80211_CMD_CCA_ABORTED_NOTIFY, 0, 0);
+}
+EXPORT_SYMBOL(cfg80211_color_change_aborted_notify);
+
void
nl80211_radar_notify(struct cfg80211_registered_device *rdev,
const struct cfg80211_chan_def *chandef,
@@ -1356,4 +1356,16 @@ static inline int rdev_reset_tid_config(struct cfg80211_registered_device *rdev,
return ret;
}
+static inline int rdev_color_change(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_cca_settings *params)
+{
+ int ret;
+
+ trace_rdev_color_change(&rdev->wiphy, dev, params);
+ ret = rdev->ops->color_change(&rdev->wiphy, dev, params);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
#endif /* __CFG80211_RDEV_OPS */
@@ -3545,6 +3545,66 @@ TRACE_EVENT(rdev_reset_tid_config,
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT ", tids: 0x%x",
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tids)
);
+
+TRACE_EVENT(rdev_color_change,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ struct cfg80211_cca_settings *params),
+ TP_ARGS(wiphy, netdev, params),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ __field(u8, count)
+ __field(u16, bcn_ofs)
+ __field(u16, pres_ofs)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ __entry->count = params->count;
+ __entry->bcn_ofs = params->counter_offset_beacon;
+ __entry->pres_ofs = params->counter_offset_presp;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT
+ ", count: %u",
+ WIPHY_PR_ARG, NETDEV_PR_ARG,
+ __entry->count)
+);
+
+TRACE_EVENT(cfg80211_color_change_started_notify,
+ TP_PROTO(struct net_device *netdev),
+ TP_ARGS(netdev),
+ TP_STRUCT__entry(
+ NETDEV_ENTRY
+ ),
+ TP_fast_assign(
+ NETDEV_ASSIGN;
+ ),
+ TP_printk(NETDEV_PR_FMT ", ", NETDEV_PR_ARG)
+);
+
+TRACE_EVENT(cfg80211_color_change_notify,
+ TP_PROTO(struct net_device *netdev),
+ TP_ARGS(netdev),
+ TP_STRUCT__entry(
+ NETDEV_ENTRY
+ ),
+ TP_fast_assign(
+ NETDEV_ASSIGN;
+ ),
+ TP_printk(NETDEV_PR_FMT ", ", NETDEV_PR_ARG)
+);
+
+TRACE_EVENT(cfg80211_color_change_aborted_notify,
+ TP_PROTO(struct net_device *netdev),
+ TP_ARGS(netdev),
+ TP_STRUCT__entry(
+ NETDEV_ENTRY
+ ),
+ TP_fast_assign(
+ NETDEV_ASSIGN;
+ ),
+ TP_printk(NETDEV_PR_FMT ", ", NETDEV_PR_ARG)
+);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
Add the required functionality to nl80211 that we require to notify about color collisions, triggering the color change and notifying when it is completed. Signed-off-by: John Crispin <john@phrozen.org> --- include/net/cfg80211.h | 64 ++++++++++++++ include/uapi/linux/nl80211.h | 43 +++++++++ net/wireless/nl80211.c | 164 +++++++++++++++++++++++++++++++++++ net/wireless/rdev-ops.h | 12 +++ net/wireless/trace.h | 60 +++++++++++++ 5 files changed, 343 insertions(+)