From c5ef1cee8a72b7f954222e11388173465a4b29f3 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 24 Sep 2021 16:53:33 +0200 Subject: mac80211: backport support for BSS color changes This is needed for an upcoming mt76 update also sync iw nl80211 with kernel backports Signed-off-by: Felix Fietkau (cherry-picked from commit 2bfac61483db32f8bd1f5b38702b39f206256265) (cherry-picked from commit 36019ed5893cd11c86a7dbedca1c6a055654a3c0) --- .../387-nl80211-add-support-for-BSS-coloring.patch | 485 +++++++++++++++++++++ 1 file changed, 485 insertions(+) create mode 100644 package/kernel/mac80211/patches/subsys/387-nl80211-add-support-for-BSS-coloring.patch (limited to 'package/kernel/mac80211/patches/subsys/387-nl80211-add-support-for-BSS-coloring.patch') diff --git a/package/kernel/mac80211/patches/subsys/387-nl80211-add-support-for-BSS-coloring.patch b/package/kernel/mac80211/patches/subsys/387-nl80211-add-support-for-BSS-coloring.patch new file mode 100644 index 0000000000..36b705de12 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/387-nl80211-add-support-for-BSS-coloring.patch @@ -0,0 +1,485 @@ +From: John Crispin +Date: Fri, 2 Jul 2021 19:44:07 +0200 +Subject: [PATCH] nl80211: add support for BSS coloring + +This patch adds support for BSS color collisions to the wireless subsystem. +Add the required functionality to nl80211 that will notify about color +collisions, triggering the color change and notifying when it is completed. + +Co-developed-by: Lorenzo Bianconi +Signed-off-by: Lorenzo Bianconi +Signed-off-by: John Crispin +Link: https://lore.kernel.org/r/500b3582aec8fe2c42ef46f3117b148cb7cbceb5.1625247619.git.lorenzo@kernel.org +[remove unnecessary NULL initialisation] +Signed-off-by: Johannes Berg +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -1252,6 +1252,27 @@ struct cfg80211_csa_settings { + #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 + + /** ++ * struct cfg80211_color_change_settings - color change settings ++ * ++ * Used for bss color change ++ * ++ * @beacon_color_change: beacon data while performing the color countdown ++ * @counter_offsets_beacon: offsets of the counters within the beacon (tail) ++ * @counter_offsets_presp: offsets of the counters within the probe response ++ * @beacon_next: beacon data to be used after the color change ++ * @count: number of beacons until the color change ++ * @color: the color used after the change ++ */ ++struct cfg80211_color_change_settings { ++ struct cfg80211_beacon_data beacon_color_change; ++ u16 counter_offset_beacon; ++ u16 counter_offset_presp; ++ struct cfg80211_beacon_data beacon_next; ++ u8 count; ++ u8 color; ++}; ++ ++/** + * struct iface_combination_params - input parameters for interface combinations + * + * Used to pass interface combination parameters +@@ -3979,6 +4000,8 @@ 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. + */ + struct cfg80211_ops { + int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); +@@ -4309,6 +4332,9 @@ struct cfg80211_ops { + const u8 *peer, u8 tids); + int (*set_sar_specs)(struct wiphy *wiphy, + struct cfg80211_sar_specs *sar); ++ int (*color_change)(struct wiphy *wiphy, ++ struct net_device *dev, ++ struct cfg80211_color_change_settings *params); + }; + + /* +@@ -8094,4 +8120,70 @@ void cfg80211_update_owe_info_event(stru + */ + void cfg80211_bss_flush(struct wiphy *wiphy); + ++/** ++ * cfg80211_bss_color_notify - notify about bss color event ++ * @dev: network device ++ * @gfp: allocation flags ++ * @cmd: the actual event we want to notify ++ * @count: the number of TBTTs until the color change happens ++ * @color_bitmap: representations of the colors that the local BSS is aware of ++ */ ++int cfg80211_bss_color_notify(struct net_device *dev, gfp_t gfp, ++ enum nl80211_commands cmd, u8 count, ++ u64 color_bitmap); ++ ++/** ++ * cfg80211_obss_color_collision_notify - notify about bss color collision ++ * @dev: network device ++ * @color_bitmap: representations of the colors that the local BSS is aware of ++ */ ++static inline int cfg80211_obss_color_collision_notify(struct net_device *dev, ++ u64 color_bitmap) ++{ ++ return cfg80211_bss_color_notify(dev, GFP_KERNEL, ++ NL80211_CMD_OBSS_COLOR_COLLISION, ++ 0, 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 started. ++ */ ++static inline int cfg80211_color_change_started_notify(struct net_device *dev, ++ u8 count) ++{ ++ return cfg80211_bss_color_notify(dev, GFP_KERNEL, ++ NL80211_CMD_COLOR_CHANGE_STARTED, ++ count, 0); ++} ++ ++/** ++ * 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 aborted. ++ */ ++static inline int cfg80211_color_change_aborted_notify(struct net_device *dev) ++{ ++ return cfg80211_bss_color_notify(dev, GFP_KERNEL, ++ NL80211_CMD_COLOR_CHANGE_ABORTED, ++ 0, 0); ++} ++ ++/** ++ * 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 completed. ++ */ ++static inline int cfg80211_color_change_notify(struct net_device *dev) ++{ ++ return cfg80211_bss_color_notify(dev, GFP_KERNEL, ++ NL80211_CMD_COLOR_CHANGE_COMPLETED, ++ 0, 0); ++} ++ + #endif /* __NET_CFG80211_H */ +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -1185,6 +1185,21 @@ + * passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to + * specify the wiphy index to be applied to. + * ++ * @NL80211_CMD_OBSS_COLOR_COLLISION: This notification is sent out whenever ++ * mac80211/drv detects a bss color collision. ++ * ++ * @NL80211_CMD_COLOR_CHANGE_REQUEST: This command is used to indicate that ++ * userspace wants to change the BSS color. ++ * ++ * @NL80211_CMD_COLOR_CHANGE_STARTED: Notify userland, that a color change has ++ * started ++ * ++ * @NL80211_CMD_COLOR_CHANGE_ABORTED: Notify userland, that the color change has ++ * been aborted ++ * ++ * @NL80211_CMD_COLOR_CHANGE_COMPLETED: Notify userland that the color change ++ * has completed ++ * + * @NL80211_CMD_MAX: highest used command number + * @__NL80211_CMD_AFTER_LAST: internal use + */ +@@ -1417,6 +1432,14 @@ enum nl80211_commands { + + NL80211_CMD_SET_SAR_SPECS, + ++ NL80211_CMD_OBSS_COLOR_COLLISION, ++ ++ NL80211_CMD_COLOR_CHANGE_REQUEST, ++ ++ NL80211_CMD_COLOR_CHANGE_STARTED, ++ NL80211_CMD_COLOR_CHANGE_ABORTED, ++ NL80211_CMD_COLOR_CHANGE_COMPLETED, ++ + /* add new commands above here */ + + /* used to define NL80211_CMD_MAX below */ +@@ -2560,6 +2583,16 @@ enum nl80211_commands { + * disassoc events to indicate that an immediate reconnect to the AP + * is desired. + * ++ * @NL80211_ATTR_OBSS_COLOR_BITMAP: bitmap of the u64 BSS colors for the ++ * %NL80211_CMD_OBSS_COLOR_COLLISION event. ++ * ++ * @NL80211_ATTR_COLOR_CHANGE_COUNT: u8 attribute specifying the number of TBTT's ++ * until the color switch event. ++ * @NL80211_ATTR_COLOR_CHANGE_COLOR: u8 attribute specifying the color that we are ++ * switching to ++ * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE ++ * information for the time while performing a color switch. ++ * + * @NUM_NL80211_ATTR: total number of nl80211_attrs available + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use +@@ -3057,6 +3090,12 @@ enum nl80211_attrs { + + NL80211_ATTR_DISABLE_HE, + ++ NL80211_ATTR_OBSS_COLOR_BITMAP, ++ ++ NL80211_ATTR_COLOR_CHANGE_COUNT, ++ NL80211_ATTR_COLOR_CHANGE_COLOR, ++ NL80211_ATTR_COLOR_CHANGE_ELEMS, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +@@ -5950,6 +5989,9 @@ enum nl80211_feature_flags { + * frame protection for all management frames exchanged during the + * negotiation and range measurement procedure. + * ++ * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision ++ * detection and change announcemnts. ++ * + * @NUM_NL80211_EXT_FEATURES: number of extended features. + * @MAX_NL80211_EXT_FEATURES: highest extended feature index. + */ +@@ -6014,6 +6056,7 @@ enum nl80211_ext_feature_index { + NL80211_EXT_FEATURE_SECURE_LTF, + NL80211_EXT_FEATURE_SECURE_RTT, + NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, ++ NL80211_EXT_FEATURE_BSS_COLOR, + + /* add new features before the definition below */ + NUM_NL80211_EXT_FEATURES, +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -753,6 +753,10 @@ static const struct nla_policy nl80211_p + NL80211_SAE_PWE_BOTH), + [NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy), + [NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT }, ++ [NL80211_ATTR_OBSS_COLOR_BITMAP] = { .type = NLA_U64 }, ++ [NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 }, ++ [NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 }, ++ [NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy), + }; + + /* policy for the key attributes */ +@@ -14677,6 +14681,106 @@ bad_tid_conf: + 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 cfg80211_color_change_settings params = {}; ++ struct net_device *dev = info->user_ptr[1]; ++ struct wireless_dev *wdev = dev->ieee80211_ptr; ++ struct nlattr **tb; ++ u16 offset; ++ int err; ++ ++ if (!rdev->ops->color_change) ++ return -EOPNOTSUPP; ++ ++ if (!wiphy_ext_feature_isset(&rdev->wiphy, ++ NL80211_EXT_FEATURE_BSS_COLOR)) ++ return -EOPNOTSUPP; ++ ++ if (wdev->iftype != NL80211_IFTYPE_AP) ++ return -EOPNOTSUPP; ++ ++ if (!info->attrs[NL80211_ATTR_COLOR_CHANGE_COUNT] || ++ !info->attrs[NL80211_ATTR_COLOR_CHANGE_COLOR] || ++ !info->attrs[NL80211_ATTR_COLOR_CHANGE_ELEMS]) ++ return -EINVAL; ++ ++ params.count = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COUNT]); ++ params.color = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COLOR]); ++ ++ err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_next); ++ if (err) ++ return err; ++ ++ tb = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*tb), GFP_KERNEL); ++ if (!tb) ++ return -ENOMEM; ++ ++ err = nla_parse_nested(tb, NL80211_ATTR_MAX, ++ info->attrs[NL80211_ATTR_COLOR_CHANGE_ELEMS], ++ nl80211_policy, info->extack); ++ if (err) ++ goto out; ++ ++ err = nl80211_parse_beacon(rdev, tb, ¶ms.beacon_color_change); ++ if (err) ++ goto out; ++ ++ if (!tb[NL80211_ATTR_CNTDWN_OFFS_BEACON]) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ if (nla_len(tb[NL80211_ATTR_CNTDWN_OFFS_BEACON]) != sizeof(u16)) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ offset = nla_get_u16(tb[NL80211_ATTR_CNTDWN_OFFS_BEACON]); ++ if (offset >= params.beacon_color_change.tail_len) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ if (params.beacon_color_change.tail[offset] != params.count) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ params.counter_offset_beacon = offset; ++ ++ if (tb[NL80211_ATTR_CNTDWN_OFFS_PRESP]) { ++ if (nla_len(tb[NL80211_ATTR_CNTDWN_OFFS_PRESP]) != ++ sizeof(u16)) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ offset = nla_get_u16(tb[NL80211_ATTR_CNTDWN_OFFS_PRESP]); ++ if (offset >= params.beacon_color_change.probe_resp_len) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ if (params.beacon_color_change.probe_resp[offset] != ++ params.count) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ params.counter_offset_presp = offset; ++ } ++ ++ wdev_lock(wdev); ++ err = rdev_color_change(rdev, dev, ¶ms); ++ wdev_unlock(wdev); ++ ++out: ++ kfree(tb); ++ return err; ++} ++ + #define NL80211_FLAG_NEED_WIPHY 0x01 + #define NL80211_FLAG_NEED_NETDEV 0x02 + #define NL80211_FLAG_NEED_RTNL 0x04 +@@ -15758,6 +15862,14 @@ static const struct genl_small_ops nl802 + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, + }, ++ { ++ .cmd = NL80211_CMD_COLOR_CHANGE_REQUEST, ++ .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 __genl_ro_after_init = { +@@ -17384,6 +17496,51 @@ void cfg80211_ch_switch_started_notify(s + } + EXPORT_SYMBOL(cfg80211_ch_switch_started_notify); + ++int cfg80211_bss_color_notify(struct net_device *dev, gfp_t gfp, ++ enum nl80211_commands cmd, u8 count, ++ u64 color_bitmap) ++{ ++ struct wireless_dev *wdev = dev->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); ++ ++ trace_cfg80211_bss_color_notify(dev, cmd, count, color_bitmap); ++ ++ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); ++ if (!msg) ++ return -ENOMEM; ++ ++ hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); ++ if (!hdr) ++ goto nla_put_failure; ++ ++ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex)) ++ goto nla_put_failure; ++ ++ if (cmd == NL80211_CMD_COLOR_CHANGE_STARTED && ++ nla_put_u32(msg, NL80211_ATTR_COLOR_CHANGE_COUNT, count)) ++ goto nla_put_failure; ++ ++ if (cmd == 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); ++ ++ return genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), ++ msg, 0, NL80211_MCGRP_MLME, gfp); ++ ++nla_put_failure: ++ nlmsg_free(msg); ++ return -EINVAL; ++} ++EXPORT_SYMBOL(cfg80211_bss_color_notify); ++ + void + nl80211_radar_notify(struct cfg80211_registered_device *rdev, + const struct cfg80211_chan_def *chandef, +--- a/net/wireless/rdev-ops.h ++++ b/net/wireless/rdev-ops.h +@@ -1368,4 +1368,17 @@ static inline int rdev_set_sar_specs(str + return ret; + } + ++static inline int rdev_color_change(struct cfg80211_registered_device *rdev, ++ struct net_device *dev, ++ struct cfg80211_color_change_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 */ +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -3570,6 +3570,52 @@ TRACE_EVENT(rdev_set_sar_specs, + WIPHY_PR_ARG, __entry->type, __entry->num) + ); + ++TRACE_EVENT(rdev_color_change, ++ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, ++ struct cfg80211_color_change_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_bss_color_notify, ++ TP_PROTO(struct net_device *netdev, ++ enum nl80211_commands cmd, ++ u8 count, u64 color_bitmap), ++ TP_ARGS(netdev, cmd, count, color_bitmap), ++ TP_STRUCT__entry( ++ NETDEV_ENTRY ++ __field(enum nl80211_bss_scan_width, cmd) ++ __field(u8, count) ++ __field(u64, color_bitmap) ++ ), ++ TP_fast_assign( ++ NETDEV_ASSIGN; ++ __entry->cmd = cmd; ++ __entry->count = count; ++ __entry->color_bitmap = color_bitmap; ++ ), ++ TP_printk(NETDEV_PR_FMT ", cmd: %x, count: %u, bitmap: %llx", ++ NETDEV_PR_ARG, __entry->cmd, __entry->count, ++ __entry->color_bitmap) ++); ++ + #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ + + #undef TRACE_INCLUDE_PATH -- cgit v1.2.3