[openwrt/openwrt] mac80211: backport support for BSS color changes

LEDE Commits lede-commits at lists.infradead.org
Sat Sep 25 05:09:02 PDT 2021


nbd pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/2bfac61483db32f8bd1f5b38702b39f206256265

commit 2bfac61483db32f8bd1f5b38702b39f206256265
Author: Felix Fietkau <nbd at nbd.name>
AuthorDate: Fri Sep 24 16:53:33 2021 +0200

    mac80211: backport support for BSS color changes
    
    This is needed for an upcoming mt76 update
    
    Signed-off-by: Felix Fietkau <nbd at nbd.name>
---
 .../387-nl80211-add-support-for-BSS-coloring.patch | 485 +++++++++++++++++++
 ...mac80211-add-support-for-BSS-color-change.patch | 524 +++++++++++++++++++++
 .../500-mac80211_configure_antenna_gain.patch      |  32 +-
 3 files changed, 1025 insertions(+), 16 deletions(-)

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 <john at phrozen.org>
+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 <lorenzo at kernel.org>
+Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
+Signed-off-by: John Crispin <john at phrozen.org>
+Link: https://lore.kernel.org/r/500b3582aec8fe2c42ef46f3117b148cb7cbceb5.1625247619.git.lorenzo@kernel.org
+[remove unnecessary NULL initialisation]
+Signed-off-by: Johannes Berg <johannes.berg at intel.com>
+---
+
+--- 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, &params.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, &params.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, &params);
++	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 <john at phrozen.org>
+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 <lorenzo at kernel.org>
+Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
+Signed-off-by: John Crispin <john at phrozen.org>
+Link: https://lore.kernel.org/r/057c1e67b82bee561ea44ce6a45a8462d3da6995.1625247619.git.lorenzo@kernel.org
+Signed-off-by: Johannes Berg <johannes.berg at intel.com>
+---
+
+--- 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, &params->beacon, NULL);
++	err = ieee80211_assign_beacon(sdata, &params->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, &params->beacon_csa, &csa);
++		err = ieee80211_assign_beacon(sdata, &params->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(&params->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, &params->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;
  	}



More information about the lede-commits mailing list