From: Felix Fietkau Date: Fri, 24 Sep 2021 14:53:33 +0000 (+0200) Subject: mac80211: backport support for BSS color changes X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=2bfac61483db32f8bd1f5b38702b39f206256265;p=openwrt%2Fstaging%2Fansuel.git mac80211: backport support for BSS color changes This is needed for an upcoming mt76 update Signed-off-by: Felix Fietkau --- 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 diff --git a/package/kernel/mac80211/patches/subsys/388-mac80211-add-support-for-BSS-color-change.patch b/package/kernel/mac80211/patches/subsys/388-mac80211-add-support-for-BSS-color-change.patch new file mode 100644 index 0000000000..0a3118545f --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/388-mac80211-add-support-for-BSS-color-change.patch @@ -0,0 +1,524 @@ +From: John Crispin +Date: Fri, 2 Jul 2021 19:44:08 +0200 +Subject: [PATCH] mac80211: add support for BSS color change + +The color change announcement is very similar to how CSA works where +we have an IE that includes a counter. When the counter hits 0, the new +color is applied via an updated beacon. + +This patch makes the CSA counter functionality reusable, rather than +implementing it again. This also allows for future reuse incase support +for other counter IEs gets added. + +Co-developed-by: Lorenzo Bianconi +Signed-off-by: Lorenzo Bianconi +Signed-off-by: John Crispin +Link: https://lore.kernel.org/r/057c1e67b82bee561ea44ce6a45a8462d3da6995.1625247619.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -1710,6 +1710,10 @@ enum ieee80211_offload_flags { + * protected by fq->lock. + * @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see + * &enum ieee80211_offload_flags. ++ * @color_change_active: marks whether a color change is ongoing. Internally it is ++ * write-protected by sdata_lock and local->mtx so holding either is fine ++ * for read access. ++ * @color_change_color: the bss color that will be used after the change. + */ + struct ieee80211_vif { + enum nl80211_iftype type; +@@ -1738,6 +1742,9 @@ struct ieee80211_vif { + + bool txqs_stopped[IEEE80211_NUM_ACS]; + ++ bool color_change_active; ++ u8 color_change_color; ++ + /* must be last */ + u8 drv_priv[] __aligned(sizeof(void *)); + }; +@@ -4982,6 +4989,16 @@ void ieee80211_csa_finish(struct ieee802 + bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif); + + /** ++ * ieee80211_color_change_finish - notify mac80211 about color change ++ * @vif: &struct ieee80211_vif pointer from the add_interface callback. ++ * ++ * After a color change announcement was scheduled and the counter in this ++ * announcement hits 1, this function must be called by the driver to ++ * notify mac80211 that the color can be changed ++ */ ++void ieee80211_color_change_finish(struct ieee80211_vif *vif); ++ ++/** + * ieee80211_proberesp_get - retrieve a Probe Response template + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. +@@ -6726,6 +6743,18 @@ ieee80211_get_unsol_bcast_probe_resp_tmp + struct ieee80211_vif *vif); + + /** ++ * ieeee80211_obss_color_collision_notify - notify userland about a BSS color ++ * collision. ++ * ++ * @vif: &struct ieee80211_vif pointer from the add_interface callback. ++ * @color_bitmap: a 64 bit bitmap representing the colors that the local BSS is ++ * aware of. ++ */ ++void ++ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif, ++ u64 color_bitmap); ++ ++/** + * ieee80211_is_tx_data - check if frame is a data frame + * + * The function is used to check if a frame is a data frame. Frames with +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -827,9 +827,11 @@ static int ieee80211_set_monitor_channel + return ret; + } + +-static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, +- const u8 *resp, size_t resp_len, +- const struct ieee80211_csa_settings *csa) ++static int ++ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, ++ const u8 *resp, size_t resp_len, ++ const struct ieee80211_csa_settings *csa, ++ const struct ieee80211_color_change_settings *cca) + { + struct probe_resp *new, *old; + +@@ -849,6 +851,8 @@ static int ieee80211_set_probe_resp(stru + memcpy(new->cntdwn_counter_offsets, csa->counter_offsets_presp, + csa->n_counter_offsets_presp * + sizeof(new->cntdwn_counter_offsets[0])); ++ else if (cca) ++ new->cntdwn_counter_offsets[0] = cca->counter_offset_presp; + + rcu_assign_pointer(sdata->u.ap.probe_resp, new); + if (old) +@@ -954,7 +958,8 @@ static int ieee80211_set_ftm_responder_p + + static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, + struct cfg80211_beacon_data *params, +- const struct ieee80211_csa_settings *csa) ++ const struct ieee80211_csa_settings *csa, ++ const struct ieee80211_color_change_settings *cca) + { + struct beacon_data *new, *old; + int new_head_len, new_tail_len; +@@ -1003,6 +1008,9 @@ static int ieee80211_assign_beacon(struc + memcpy(new->cntdwn_counter_offsets, csa->counter_offsets_beacon, + csa->n_counter_offsets_beacon * + sizeof(new->cntdwn_counter_offsets[0])); ++ } else if (cca) { ++ new->cntdwn_current_counter = cca->count; ++ new->cntdwn_counter_offsets[0] = cca->counter_offset_beacon; + } + + /* copy in head */ +@@ -1019,7 +1027,7 @@ static int ieee80211_assign_beacon(struc + memcpy(new->tail, old->tail, new_tail_len); + + err = ieee80211_set_probe_resp(sdata, params->probe_resp, +- params->probe_resp_len, csa); ++ params->probe_resp_len, csa, cca); + if (err < 0) { + kfree(new); + return err; +@@ -1176,7 +1184,7 @@ static int ieee80211_start_ap(struct wip + if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) + sdata->vif.bss_conf.beacon_tx_rate = params->beacon_rate; + +- err = ieee80211_assign_beacon(sdata, ¶ms->beacon, NULL); ++ err = ieee80211_assign_beacon(sdata, ¶ms->beacon, NULL, NULL); + if (err < 0) + goto error; + changed |= err; +@@ -1231,17 +1239,17 @@ static int ieee80211_change_beacon(struc + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + sdata_assert_lock(sdata); + +- /* don't allow changing the beacon while CSA is in place - offset ++ /* don't allow changing the beacon while a countdown is in place - offset + * of channel switch counter may change + */ +- if (sdata->vif.csa_active) ++ if (sdata->vif.csa_active || sdata->vif.color_change_active) + return -EBUSY; + + old = sdata_dereference(sdata->u.ap.beacon, sdata); + if (!old) + return -ENOENT; + +- err = ieee80211_assign_beacon(sdata, params, NULL); ++ err = ieee80211_assign_beacon(sdata, params, NULL, NULL); + if (err < 0) + return err; + ieee80211_bss_info_change_notify(sdata, err); +@@ -3174,7 +3182,7 @@ static int ieee80211_set_after_csa_beaco + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: + err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, +- NULL); ++ NULL, NULL); + kfree(sdata->u.ap.next_beacon); + sdata->u.ap.next_beacon = NULL; + +@@ -3340,7 +3348,7 @@ static int ieee80211_set_csa_beacon(stru + csa.n_counter_offsets_presp = params->n_counter_offsets_presp; + csa.count = params->count; + +- err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa); ++ err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa, NULL); + if (err < 0) { + kfree(sdata->u.ap.next_beacon); + return err; +@@ -3428,6 +3436,15 @@ static int ieee80211_set_csa_beacon(stru + return 0; + } + ++static void ieee80211_color_change_abort(struct ieee80211_sub_if_data *sdata) ++{ ++ sdata->vif.color_change_active = false; ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; ++ ++ cfg80211_color_change_aborted_notify(sdata->dev); ++} ++ + static int + __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_csa_settings *params) +@@ -3496,6 +3513,10 @@ __ieee80211_channel_switch(struct wiphy + goto out; + } + ++ /* if there is a color change in progress, abort it */ ++ if (sdata->vif.color_change_active) ++ ieee80211_color_change_abort(sdata); ++ + err = ieee80211_set_csa_beacon(sdata, params, &changed); + if (err) { + ieee80211_vif_unreserve_chanctx(sdata); +@@ -4147,6 +4168,196 @@ static int ieee80211_set_sar_specs(struc + return local->ops->set_sar_specs(&local->hw, sar); + } + ++static int ++ieee80211_set_after_color_change_beacon(struct ieee80211_sub_if_data *sdata, ++ u32 *changed) ++{ ++ switch (sdata->vif.type) { ++ case NL80211_IFTYPE_AP: { ++ int ret; ++ ++ ret = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, ++ NULL, NULL); ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; ++ ++ if (ret < 0) ++ return ret; ++ ++ *changed |= ret; ++ break; ++ } ++ default: ++ WARN_ON_ONCE(1); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ++ieee80211_set_color_change_beacon(struct ieee80211_sub_if_data *sdata, ++ struct cfg80211_color_change_settings *params, ++ u32 *changed) ++{ ++ struct ieee80211_color_change_settings color_change = {}; ++ int err; ++ ++ switch (sdata->vif.type) { ++ case NL80211_IFTYPE_AP: ++ sdata->u.ap.next_beacon = ++ cfg80211_beacon_dup(¶ms->beacon_next); ++ if (!sdata->u.ap.next_beacon) ++ return -ENOMEM; ++ ++ if (params->count <= 1) ++ break; ++ ++ color_change.counter_offset_beacon = ++ params->counter_offset_beacon; ++ color_change.counter_offset_presp = ++ params->counter_offset_presp; ++ color_change.count = params->count; ++ ++ err = ieee80211_assign_beacon(sdata, ¶ms->beacon_color_change, ++ NULL, &color_change); ++ if (err < 0) { ++ kfree(sdata->u.ap.next_beacon); ++ return err; ++ } ++ *changed |= err; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static void ++ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata, ++ u8 color, int enable, u32 changed) ++{ ++ sdata->vif.bss_conf.he_bss_color.color = color; ++ sdata->vif.bss_conf.he_bss_color.enabled = enable; ++ changed |= BSS_CHANGED_HE_BSS_COLOR; ++ ++ ieee80211_bss_info_change_notify(sdata, changed); ++} ++ ++static int ieee80211_color_change_finalize(struct ieee80211_sub_if_data *sdata) ++{ ++ struct ieee80211_local *local = sdata->local; ++ u32 changed = 0; ++ int err; ++ ++ sdata_assert_lock(sdata); ++ lockdep_assert_held(&local->mtx); ++ ++ sdata->vif.color_change_active = false; ++ ++ err = ieee80211_set_after_color_change_beacon(sdata, &changed); ++ if (err) { ++ cfg80211_color_change_aborted_notify(sdata->dev); ++ return err; ++ } ++ ++ ieee80211_color_change_bss_config_notify(sdata, ++ sdata->vif.color_change_color, ++ 1, changed); ++ cfg80211_color_change_notify(sdata->dev); ++ ++ return 0; ++} ++ ++void ieee80211_color_change_finalize_work(struct work_struct *work) ++{ ++ struct ieee80211_sub_if_data *sdata = ++ container_of(work, struct ieee80211_sub_if_data, ++ color_change_finalize_work); ++ struct ieee80211_local *local = sdata->local; ++ ++ sdata_lock(sdata); ++ mutex_lock(&local->mtx); ++ ++ /* AP might have been stopped while waiting for the lock. */ ++ if (!sdata->vif.color_change_active) ++ goto unlock; ++ ++ if (!ieee80211_sdata_running(sdata)) ++ goto unlock; ++ ++ ieee80211_color_change_finalize(sdata); ++ ++unlock: ++ mutex_unlock(&local->mtx); ++ sdata_unlock(sdata); ++} ++ ++void ieee80211_color_change_finish(struct ieee80211_vif *vif) ++{ ++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); ++ ++ ieee80211_queue_work(&sdata->local->hw, ++ &sdata->color_change_finalize_work); ++} ++EXPORT_SYMBOL_GPL(ieee80211_color_change_finish); ++ ++void ++ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif, ++ u64 color_bitmap) ++{ ++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); ++ ++ if (sdata->vif.color_change_active || sdata->vif.csa_active) ++ return; ++ ++ cfg80211_obss_color_collision_notify(sdata->dev, color_bitmap); ++} ++EXPORT_SYMBOL_GPL(ieeee80211_obss_color_collision_notify); ++ ++static int ++ieee80211_color_change(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_color_change_settings *params) ++{ ++ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); ++ struct ieee80211_local *local = sdata->local; ++ u32 changed = 0; ++ int err; ++ ++ sdata_assert_lock(sdata); ++ ++ mutex_lock(&local->mtx); ++ ++ /* don't allow another color change if one is already active or if csa ++ * is active ++ */ ++ if (sdata->vif.color_change_active || sdata->vif.csa_active) { ++ err = -EBUSY; ++ goto out; ++ } ++ ++ err = ieee80211_set_color_change_beacon(sdata, params, &changed); ++ if (err) ++ goto out; ++ ++ sdata->vif.color_change_active = true; ++ sdata->vif.color_change_color = params->color; ++ ++ cfg80211_color_change_started_notify(sdata->dev, params->count); ++ ++ if (changed) ++ ieee80211_color_change_bss_config_notify(sdata, 0, 0, changed); ++ else ++ /* if the beacon didn't change, we can finalize immediately */ ++ ieee80211_color_change_finalize(sdata); ++ ++out: ++ mutex_unlock(&local->mtx); ++ ++ return err; ++} ++ + const struct cfg80211_ops mac80211_config_ops = { + .add_virtual_intf = ieee80211_add_iface, + .del_virtual_intf = ieee80211_del_iface, +@@ -4251,4 +4462,5 @@ const struct cfg80211_ops mac80211_confi + .set_tid_config = ieee80211_set_tid_config, + .reset_tid_config = ieee80211_reset_tid_config, + .set_sar_specs = ieee80211_set_sar_specs, ++ .color_change = ieee80211_color_change, + }; +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -248,6 +248,12 @@ struct ieee80211_csa_settings { + u8 count; + }; + ++struct ieee80211_color_change_settings { ++ u16 counter_offset_beacon; ++ u16 counter_offset_presp; ++ u8 count; ++}; ++ + struct beacon_data { + u8 *head, *tail; + int head_len, tail_len; +@@ -932,6 +938,8 @@ struct ieee80211_sub_if_data { + bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ + struct cfg80211_chan_def csa_chandef; + ++ struct work_struct color_change_finalize_work; ++ + struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */ + struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */ + +@@ -1900,6 +1908,9 @@ void ieee80211_csa_finalize_work(struct + int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_csa_settings *params); + ++/* color change handling */ ++void ieee80211_color_change_finalize_work(struct work_struct *work); ++ + /* interface handling */ + #define MAC80211_SUPPORTED_FEATURES_TX (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \ + NETIF_F_HW_CSUM | NETIF_F_SG | \ +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -465,6 +465,7 @@ static void ieee80211_do_stop(struct iee + sdata_unlock(sdata); + + cancel_work_sync(&sdata->csa_finalize_work); ++ cancel_work_sync(&sdata->color_change_finalize_work); + + cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); + +@@ -1639,6 +1640,7 @@ static void ieee80211_setup_sdata(struct + INIT_WORK(&sdata->work, ieee80211_iface_work); + INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work); + INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work); ++ INIT_WORK(&sdata->color_change_finalize_work, ieee80211_color_change_finalize_work); + INIT_LIST_HEAD(&sdata->assigned_chanctx_list); + INIT_LIST_HEAD(&sdata->reserved_chanctx_list); + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -4790,11 +4790,11 @@ static int ieee80211_beacon_add_tim(stru + static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, + struct beacon_data *beacon) + { ++ u8 *beacon_data, count, max_count = 1; + struct probe_resp *resp; +- u8 *beacon_data; + size_t beacon_data_len; ++ u16 *bcn_offsets; + int i; +- u8 count = beacon->cntdwn_current_counter; + + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: +@@ -4814,21 +4814,27 @@ static void ieee80211_set_beacon_cntdwn( + } + + rcu_read_lock(); +- for (i = 0; i < IEEE80211_MAX_CNTDWN_COUNTERS_NUM; ++i) { +- resp = rcu_dereference(sdata->u.ap.probe_resp); ++ resp = rcu_dereference(sdata->u.ap.probe_resp); + +- if (beacon->cntdwn_counter_offsets[i]) { +- if (WARN_ON_ONCE(beacon->cntdwn_counter_offsets[i] >= +- beacon_data_len)) { ++ bcn_offsets = beacon->cntdwn_counter_offsets; ++ count = beacon->cntdwn_current_counter; ++ if (sdata->vif.csa_active) ++ max_count = IEEE80211_MAX_CNTDWN_COUNTERS_NUM; ++ ++ for (i = 0; i < max_count; ++i) { ++ if (bcn_offsets[i]) { ++ if (WARN_ON_ONCE(bcn_offsets[i] >= beacon_data_len)) { + rcu_read_unlock(); + return; + } +- +- beacon_data[beacon->cntdwn_counter_offsets[i]] = count; ++ beacon_data[bcn_offsets[i]] = count; + } + +- if (sdata->vif.type == NL80211_IFTYPE_AP && resp) +- resp->data[resp->cntdwn_counter_offsets[i]] = count; ++ if (sdata->vif.type == NL80211_IFTYPE_AP && resp) { ++ u16 *resp_offsets = resp->cntdwn_counter_offsets; ++ ++ resp->data[resp_offsets[i]] = count; ++ } + } + rcu_read_unlock(); + } +@@ -5038,6 +5044,7 @@ __ieee80211_beacon_get(struct ieee80211_ + if (offs) { + offs->tim_offset = beacon->head_len; + offs->tim_length = skb->len - beacon->head_len; ++ offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0]; + + /* for AP the csa offsets are from tail */ + csa_off_base = skb->len; diff --git a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch index b2ee61a6dc..2755efb194 100644 --- a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch +++ b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch @@ -1,6 +1,6 @@ --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h -@@ -3793,6 +3793,7 @@ struct mgmt_frame_regs { +@@ -3814,6 +3814,7 @@ struct mgmt_frame_regs { * (as advertised by the nl80211 feature flag.) * @get_tx_power: store the current TX power into the dbm variable; * return 0 if successful @@ -8,7 +8,7 @@ * * @set_wds_peer: set the WDS peer for a WDS interface * -@@ -4115,6 +4116,7 @@ struct cfg80211_ops { +@@ -4138,6 +4139,7 @@ struct cfg80211_ops { enum nl80211_tx_power_setting type, int mbm); int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev, int *dbm); @@ -36,9 +36,9 @@ u8 ps_dtim_period; --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h -@@ -2560,6 +2560,9 @@ enum nl80211_commands { - * disassoc events to indicate that an immediate reconnect to the AP - * is desired. +@@ -2593,6 +2593,9 @@ enum nl80211_commands { + * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE + * information for the time while performing a color switch. * + * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce + * transmit power to stay within regulatory limits. u32, dBi. @@ -46,9 +46,9 @@ * @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 +3060,8 @@ enum nl80211_attrs { - - NL80211_ATTR_DISABLE_HE, +@@ -3096,6 +3099,8 @@ enum nl80211_attrs { + NL80211_ATTR_COLOR_CHANGE_COLOR, + NL80211_ATTR_COLOR_CHANGE_ELEMS, + NL80211_ATTR_WIPHY_ANTENNA_GAIN, + @@ -57,7 +57,7 @@ __NL80211_ATTR_AFTER_LAST, --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c -@@ -2761,6 +2761,19 @@ static int ieee80211_get_tx_power(struct +@@ -2769,6 +2769,19 @@ static int ieee80211_get_tx_power(struct return 0; } @@ -77,7 +77,7 @@ static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev, const u8 *addr) { -@@ -4202,6 +4215,7 @@ const struct cfg80211_ops mac80211_confi +@@ -4413,6 +4426,7 @@ const struct cfg80211_ops mac80211_confi .set_wiphy_params = ieee80211_set_wiphy_params, .set_tx_power = ieee80211_set_tx_power, .get_tx_power = ieee80211_get_tx_power, @@ -87,7 +87,7 @@ CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h -@@ -1426,6 +1426,7 @@ struct ieee80211_local { +@@ -1434,6 +1434,7 @@ struct ieee80211_local { int dynamic_ps_forced_timeout; int user_power_level; /* in dBm, for all interfaces */ @@ -129,15 +129,15 @@ local->hw.max_mtu = IEEE80211_MAX_DATA_LEN; --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c -@@ -753,6 +753,7 @@ 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 }, +@@ -757,6 +757,7 @@ static const struct nla_policy nl80211_p + [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), + [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 }, }; /* policy for the key attributes */ -@@ -3318,6 +3319,20 @@ static int nl80211_set_wiphy(struct sk_b +@@ -3322,6 +3323,20 @@ static int nl80211_set_wiphy(struct sk_b if (result) return result; }