mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-03 22:44:27 -05:00 
			
		
		
		
	mac80211: Update to version 5.15-rc6-1
The removed patches were applied upstream. The Cisco Aironet 802.11b driver was removed from backports, remove it also from OpenWrt. Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
		
							parent
							
								
									cfe0eb7485
								
							
						
					
					
						commit
						0a274d67b8
					
				@ -10,10 +10,10 @@ include $(INCLUDE_DIR)/kernel.mk
 | 
			
		||||
 | 
			
		||||
PKG_NAME:=mac80211
 | 
			
		||||
 | 
			
		||||
PKG_VERSION:=5.14.13-1
 | 
			
		||||
PKG_VERSION:=5.15-rc6-1
 | 
			
		||||
PKG_RELEASE:=1
 | 
			
		||||
PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.14.13/
 | 
			
		||||
PKG_HASH:=042aef20caf17ef649502d5f2e744a7676abe7faed18de83c96f37bc029635fe
 | 
			
		||||
PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.15-rc6/
 | 
			
		||||
PKG_HASH:=9282612c4c02ef9fc9d74405303033f6b53914cd63d631eef0f43155fcd38932
 | 
			
		||||
 | 
			
		||||
PKG_SOURCE:=backports-$(PKG_VERSION).tar.xz
 | 
			
		||||
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/backports-$(PKG_VERSION)
 | 
			
		||||
@ -23,7 +23,6 @@ PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
 | 
			
		||||
 | 
			
		||||
PKG_DRIVERS = \
 | 
			
		||||
	adm8211 \
 | 
			
		||||
	airo \
 | 
			
		||||
	hermes hermes-pci hermes-pcmcia hermes-plx\
 | 
			
		||||
	lib80211 \
 | 
			
		||||
	mac80211-hwsim \
 | 
			
		||||
@ -174,18 +173,6 @@ define KernelPackage/adm8211
 | 
			
		||||
  AUTOLOAD:=$(call AutoProbe,adm8211)
 | 
			
		||||
endef
 | 
			
		||||
 | 
			
		||||
define KernelPackage/airo
 | 
			
		||||
  $(call KernelPackage/mac80211/Default)
 | 
			
		||||
  TITLE:=Cisco Aironet driver
 | 
			
		||||
  DEPENDS+=@PCI_SUPPORT +@DRIVER_WEXT_SUPPORT +kmod-cfg80211 @TARGET_x86 @BROKEN
 | 
			
		||||
  FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/cisco/airo.ko
 | 
			
		||||
  AUTOLOAD:=$(call AutoProbe,airo)
 | 
			
		||||
endef
 | 
			
		||||
 | 
			
		||||
define KernelPackage/airo/description
 | 
			
		||||
 Kernel support for Cisco Aironet cards
 | 
			
		||||
endef
 | 
			
		||||
 | 
			
		||||
define KernelPackage/hermes
 | 
			
		||||
  $(call KernelPackage/mac80211/Default)
 | 
			
		||||
  TITLE:=Hermes 802.11b chipset support
 | 
			
		||||
@ -406,8 +393,6 @@ endif
 | 
			
		||||
 | 
			
		||||
config-$(call config_package,lib80211) += LIB80211 LIB80211_CRYPT_WEP LIB80211_CRYPT_CCMP LIB80211_CRYPT_TKIP
 | 
			
		||||
 | 
			
		||||
config-$(call config_package,airo) += AIRO
 | 
			
		||||
 | 
			
		||||
config-$(call config_package,mac80211-hwsim) += MAC80211_HWSIM
 | 
			
		||||
config-$(call config_package,mt7601u) += MT7601U
 | 
			
		||||
config-y += WL_MEDIATEK
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
--- a/net/wireless/reg.c
 | 
			
		||||
+++ b/net/wireless/reg.c
 | 
			
		||||
@@ -3292,6 +3292,8 @@ void regulatory_hint_country_ie(struct w
 | 
			
		||||
@@ -3299,6 +3299,8 @@ void regulatory_hint_country_ie(struct w
 | 
			
		||||
 	enum environment_cap env = ENVIRON_ANY;
 | 
			
		||||
 	struct regulatory_request *request = NULL, *lr;
 | 
			
		||||
 
 | 
			
		||||
@ -9,7 +9,7 @@
 | 
			
		||||
 	/* IE len must be evenly divisible by 2 */
 | 
			
		||||
 	if (country_ie_len & 0x01)
 | 
			
		||||
 		return;
 | 
			
		||||
@@ -3543,6 +3545,7 @@ static bool is_wiphy_all_set_reg_flag(en
 | 
			
		||||
@@ -3550,6 +3552,7 @@ static bool is_wiphy_all_set_reg_flag(en
 | 
			
		||||
 
 | 
			
		||||
 void regulatory_hint_disconnect(void)
 | 
			
		||||
 {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
--- a/drivers/net/wireless/ath/ath10k/Kconfig
 | 
			
		||||
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
 | 
			
		||||
@@ -85,6 +85,12 @@ config ATH10K_TRACING
 | 
			
		||||
@@ -86,6 +86,12 @@ config ATH10K_TRACING
 | 
			
		||||
 	help
 | 
			
		||||
 	  Select this to ath10k use tracing infrastructure.
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
@ -85,7 +85,7 @@ v13:
 | 
			
		||||
 create mode 100644 drivers/net/wireless/ath/ath10k/leds.h
 | 
			
		||||
--- a/drivers/net/wireless/ath/ath10k/Kconfig
 | 
			
		||||
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
 | 
			
		||||
@@ -70,6 +70,16 @@ config ATH10K_DEBUGFS
 | 
			
		||||
@@ -71,6 +71,16 @@ config ATH10K_DEBUGFS
 | 
			
		||||
 
 | 
			
		||||
 	  If unsure, say Y to make it easier to debug problems.
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
@ -20,8 +20,8 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
 | 
			
		||||
+	struct completion *completion;
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 static void brcmf_fw_request_done(const struct firmware *fw, void *ctx);
 | 
			
		||||
@@ -636,6 +637,8 @@ static void brcmf_fw_request_done(const
 | 
			
		||||
 #ifdef CONFIG_EFI
 | 
			
		||||
@@ -653,6 +654,8 @@ static void brcmf_fw_request_done(const
 | 
			
		||||
 		fwctx->req = NULL;
 | 
			
		||||
 	}
 | 
			
		||||
 	fwctx->done(fwctx->dev, ret, fwctx->req);
 | 
			
		||||
@ -30,16 +30,16 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
 | 
			
		||||
 	kfree(fwctx);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -660,6 +663,8 @@ int brcmf_fw_get_firmwares(struct device
 | 
			
		||||
@@ -693,6 +696,8 @@ int brcmf_fw_get_firmwares(struct device
 | 
			
		||||
 {
 | 
			
		||||
 	struct brcmf_fw_item *first = &req->items[0];
 | 
			
		||||
 	struct brcmf_fw *fwctx;
 | 
			
		||||
+	struct completion completion;
 | 
			
		||||
+	unsigned long time_left;
 | 
			
		||||
 	char *alt_path;
 | 
			
		||||
 	int ret;
 | 
			
		||||
 
 | 
			
		||||
 	brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
 | 
			
		||||
@@ -676,6 +681,9 @@ int brcmf_fw_get_firmwares(struct device
 | 
			
		||||
@@ -710,6 +715,9 @@ int brcmf_fw_get_firmwares(struct device
 | 
			
		||||
 	fwctx->dev = dev;
 | 
			
		||||
 	fwctx->req = req;
 | 
			
		||||
 	fwctx->done = fw_cb;
 | 
			
		||||
@ -47,9 +47,9 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
 | 
			
		||||
+	init_completion(&completion);
 | 
			
		||||
+	fwctx->completion = &completion;
 | 
			
		||||
 
 | 
			
		||||
 	ret = request_firmware_nowait(THIS_MODULE, true, first->path,
 | 
			
		||||
 				      fwctx->dev, GFP_KERNEL, fwctx,
 | 
			
		||||
@@ -683,6 +691,12 @@ int brcmf_fw_get_firmwares(struct device
 | 
			
		||||
 	/* First try alternative board-specific path if any */
 | 
			
		||||
 	alt_path = brcm_alt_fw_path(first->path, fwctx->req->board_type);
 | 
			
		||||
@@ -726,6 +734,12 @@ int brcmf_fw_get_firmwares(struct device
 | 
			
		||||
 	if (ret < 0)
 | 
			
		||||
 		brcmf_fw_request_done(NULL, fwctx);
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.org>
 | 
			
		||||
 | 
			
		||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
 | 
			
		||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
 | 
			
		||||
@@ -2966,6 +2966,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
 | 
			
		||||
@@ -2974,6 +2974,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
 | 
			
		||||
 	 * preference in cfg struct to apply this to
 | 
			
		||||
 	 * FW later while initializing the dongle
 | 
			
		||||
 	 */
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
 | 
			
		||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
 | 
			
		||||
@@ -2913,6 +2913,63 @@ done:
 | 
			
		||||
@@ -2921,6 +2921,63 @@ done:
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 static int
 | 
			
		||||
@ -64,7 +64,7 @@
 | 
			
		||||
 brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
 | 
			
		||||
 			    int idx, u8 *mac, struct station_info *sinfo)
 | 
			
		||||
 {
 | 
			
		||||
@@ -3013,6 +3070,7 @@ static s32 brcmf_inform_single_bss(struc
 | 
			
		||||
@@ -3021,6 +3078,7 @@ static s32 brcmf_inform_single_bss(struc
 | 
			
		||||
 	struct brcmu_chan ch;
 | 
			
		||||
 	u16 channel;
 | 
			
		||||
 	u32 freq;
 | 
			
		||||
@ -72,7 +72,7 @@
 | 
			
		||||
 	u16 notify_capability;
 | 
			
		||||
 	u16 notify_interval;
 | 
			
		||||
 	u8 *notify_ie;
 | 
			
		||||
@@ -3037,6 +3095,17 @@ static s32 brcmf_inform_single_bss(struc
 | 
			
		||||
@@ -3045,6 +3103,17 @@ static s32 brcmf_inform_single_bss(struc
 | 
			
		||||
 		band = NL80211_BAND_5GHZ;
 | 
			
		||||
 
 | 
			
		||||
 	freq = ieee80211_channel_to_frequency(channel, band);
 | 
			
		||||
@ -90,7 +90,7 @@
 | 
			
		||||
 	bss_data.chan = ieee80211_get_channel(wiphy, freq);
 | 
			
		||||
 	bss_data.scan_width = NL80211_BSS_CHAN_WIDTH_20;
 | 
			
		||||
 	bss_data.boottime_ns = ktime_to_ns(ktime_get_boottime());
 | 
			
		||||
@@ -5565,6 +5634,7 @@ static struct cfg80211_ops brcmf_cfg8021
 | 
			
		||||
@@ -5573,6 +5642,7 @@ static struct cfg80211_ops brcmf_cfg8021
 | 
			
		||||
 	.leave_ibss = brcmf_cfg80211_leave_ibss,
 | 
			
		||||
 	.get_station = brcmf_cfg80211_get_station,
 | 
			
		||||
 	.dump_station = brcmf_cfg80211_dump_station,
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
--- a/local-symbols
 | 
			
		||||
+++ b/local-symbols
 | 
			
		||||
@@ -431,43 +431,6 @@ USB_VL600=
 | 
			
		||||
@@ -421,43 +421,6 @@ USB_VL600=
 | 
			
		||||
 USB_NET_CH9200=
 | 
			
		||||
 USB_NET_AQC111=
 | 
			
		||||
 USB_RTL8153_ECM=
 | 
			
		||||
@ -192,7 +192,7 @@
 | 
			
		||||
 	select BRCMUTIL
 | 
			
		||||
--- a/Kconfig.local
 | 
			
		||||
+++ b/Kconfig.local
 | 
			
		||||
@@ -1297,117 +1297,6 @@ config BACKPORTED_USB_NET_AQC111
 | 
			
		||||
@@ -1267,117 +1267,6 @@ config BACKPORTED_USB_NET_AQC111
 | 
			
		||||
 config BACKPORTED_USB_RTL8153_ECM
 | 
			
		||||
 	tristate
 | 
			
		||||
 	default USB_RTL8153_ECM
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
--- a/local-symbols
 | 
			
		||||
+++ b/local-symbols
 | 
			
		||||
@@ -325,6 +325,7 @@ RT2X00_LIB_FIRMWARE=
 | 
			
		||||
@@ -315,6 +315,7 @@ RT2X00_LIB_FIRMWARE=
 | 
			
		||||
 RT2X00_LIB_CRYPTO=
 | 
			
		||||
 RT2X00_LIB_LEDS=
 | 
			
		||||
 RT2X00_LIB_DEBUGFS=
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ Used for AP+STA support in OpenWrt - preserve AP mode keys across STA reconnects
 | 
			
		||||
 | 
			
		||||
--- a/net/mac80211/cfg.c
 | 
			
		||||
+++ b/net/mac80211/cfg.c
 | 
			
		||||
@@ -1306,7 +1306,6 @@ static int ieee80211_stop_ap(struct wiph
 | 
			
		||||
@@ -1314,7 +1314,6 @@ static int ieee80211_stop_ap(struct wiph
 | 
			
		||||
 	sdata->vif.bss_conf.ftmr_params = NULL;
 | 
			
		||||
 
 | 
			
		||||
 	__sta_info_flush(sdata, true);
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
--- a/net/mac80211/cfg.c
 | 
			
		||||
+++ b/net/mac80211/cfg.c
 | 
			
		||||
@@ -2487,7 +2487,7 @@ static int ieee80211_scan(struct wiphy *
 | 
			
		||||
@@ -2495,7 +2495,7 @@ static int ieee80211_scan(struct wiphy *
 | 
			
		||||
 		 * the  frames sent while scanning on other channel will be
 | 
			
		||||
 		 * lost)
 | 
			
		||||
 		 */
 | 
			
		||||
 | 
			
		||||
@ -1,492 +0,0 @@
 | 
			
		||||
From 0d2ab3aea50bb02ff0c9c3d53c7b2b4b21cdd59d Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: John Crispin <john@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@kernel.org>
 | 
			
		||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
 | 
			
		||||
Signed-off-by: John Crispin <john@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@intel.com>
 | 
			
		||||
---
 | 
			
		||||
 include/net/cfg80211.h       |  92 ++++++++++++++++++++
 | 
			
		||||
 include/uapi/linux/nl80211.h |  43 ++++++++++
 | 
			
		||||
 net/wireless/nl80211.c       | 157 +++++++++++++++++++++++++++++++++++
 | 
			
		||||
 net/wireless/rdev-ops.h      |  13 +++
 | 
			
		||||
 net/wireless/trace.h         |  46 ++++++++++
 | 
			
		||||
 5 files changed, 351 insertions(+)
 | 
			
		||||
 | 
			
		||||
--- a/include/net/cfg80211.h
 | 
			
		||||
+++ b/include/net/cfg80211.h
 | 
			
		||||
@@ -1258,6 +1258,27 @@ struct cfg80211_csa_settings {
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 /**
 | 
			
		||||
+ * 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
 | 
			
		||||
@@ -4000,6 +4021,8 @@ struct mgmt_frame_regs {
 | 
			
		||||
  *	given TIDs. This callback may sleep.
 | 
			
		||||
  *
 | 
			
		||||
  * @set_sar_specs: Update the SAR (TX power) settings.
 | 
			
		||||
+ *
 | 
			
		||||
+ * @color_change: Initiate a color change.
 | 
			
		||||
  */
 | 
			
		||||
 struct cfg80211_ops {
 | 
			
		||||
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
 | 
			
		||||
@@ -4327,6 +4350,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);
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 /*
 | 
			
		||||
@@ -8226,4 +8252,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,
 | 
			
		||||
@@ -5953,6 +5992,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.
 | 
			
		||||
  */
 | 
			
		||||
@@ -6017,6 +6059,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
 | 
			
		||||
@@ -776,6 +776,10 @@ static const struct nla_policy nl80211_p
 | 
			
		||||
 	[NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT },
 | 
			
		||||
 	[NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy),
 | 
			
		||||
 	[NL80211_ATTR_DISABLE_HE] = { .type = NLA_FLAG },
 | 
			
		||||
+	[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 */
 | 
			
		||||
@@ -14823,6 +14827,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
 | 
			
		||||
@@ -15823,6 +15927,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 = {
 | 
			
		||||
@@ -17454,6 +17566,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
 | 
			
		||||
@@ -3597,6 +3597,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
 | 
			
		||||
@ -1,524 +0,0 @@
 | 
			
		||||
From: John Crispin <john@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@kernel.org>
 | 
			
		||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
 | 
			
		||||
Signed-off-by: John Crispin <john@phrozen.org>
 | 
			
		||||
Link: https://lore.kernel.org/r/057c1e67b82bee561ea44ce6a45a8462d3da6995.1625247619.git.lorenzo@kernel.org
 | 
			
		||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/include/net/mac80211.h
 | 
			
		||||
+++ b/include/net/mac80211.h
 | 
			
		||||
@@ -1715,6 +1715,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;
 | 
			
		||||
@@ -1743,6 +1747,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 *));
 | 
			
		||||
 };
 | 
			
		||||
@@ -5016,6 +5023,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.
 | 
			
		||||
@@ -6780,6 +6797,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
 | 
			
		||||
@@ -828,9 +828,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;
 | 
			
		||||
 
 | 
			
		||||
@@ -850,6 +852,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)
 | 
			
		||||
@@ -955,7 +959,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;
 | 
			
		||||
@@ -1004,6 +1009,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 */
 | 
			
		||||
@@ -1020,7 +1028,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;
 | 
			
		||||
@@ -1175,7 +1183,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;
 | 
			
		||||
@@ -1230,17 +1238,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);
 | 
			
		||||
@@ -3155,7 +3163,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;
 | 
			
		||||
 
 | 
			
		||||
@@ -3321,7 +3329,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;
 | 
			
		||||
@@ -3410,6 +3418,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)
 | 
			
		||||
@@ -3478,6 +3495,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);
 | 
			
		||||
@@ -4129,6 +4150,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,
 | 
			
		||||
@@ -4232,4 +4443,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;
 | 
			
		||||
@@ -927,6 +933,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 */
 | 
			
		||||
 
 | 
			
		||||
@@ -1891,6 +1899,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
 | 
			
		||||
@@ -462,6 +462,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);
 | 
			
		||||
 
 | 
			
		||||
@@ -1608,6 +1609,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
 | 
			
		||||
@@ -4796,11 +4796,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:
 | 
			
		||||
@@ -4820,21 +4820,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();
 | 
			
		||||
 }
 | 
			
		||||
@@ -5044,6 +5050,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;
 | 
			
		||||
@ -1,112 +0,0 @@
 | 
			
		||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
 | 
			
		||||
Date: Mon, 23 Aug 2021 20:02:38 +0200
 | 
			
		||||
Subject: [PATCH] ieee80211: add TWT element definitions
 | 
			
		||||
 | 
			
		||||
Introduce TWT definitions and TWT Information element structure
 | 
			
		||||
in ieee80211.h
 | 
			
		||||
 | 
			
		||||
Tested-by: Peter Chiu <chui-hao.chiu@mediatek.com>
 | 
			
		||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
 | 
			
		||||
Link: https://lore.kernel.org/r/71d8b581fe4b5abc5b92f8d77ac2de3e2f7591b6.1629741512.git.lorenzo@kernel.org
 | 
			
		||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
--- a/include/linux/ieee80211.h
 | 
			
		||||
+++ b/include/linux/ieee80211.h
 | 
			
		||||
@@ -1088,6 +1088,48 @@ struct ieee80211_ext {
 | 
			
		||||
 	} u;
 | 
			
		||||
 } __packed __aligned(2);
 | 
			
		||||
 
 | 
			
		||||
+#define IEEE80211_TWT_CONTROL_NDP			BIT(0)
 | 
			
		||||
+#define IEEE80211_TWT_CONTROL_RESP_MODE			BIT(1)
 | 
			
		||||
+#define IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST	BIT(3)
 | 
			
		||||
+#define IEEE80211_TWT_CONTROL_RX_DISABLED		BIT(4)
 | 
			
		||||
+#define IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT		BIT(5)
 | 
			
		||||
+
 | 
			
		||||
+#define IEEE80211_TWT_REQTYPE_REQUEST			BIT(0)
 | 
			
		||||
+#define IEEE80211_TWT_REQTYPE_SETUP_CMD			GENMASK(3, 1)
 | 
			
		||||
+#define IEEE80211_TWT_REQTYPE_TRIGGER			BIT(4)
 | 
			
		||||
+#define IEEE80211_TWT_REQTYPE_IMPLICIT			BIT(5)
 | 
			
		||||
+#define IEEE80211_TWT_REQTYPE_FLOWTYPE			BIT(6)
 | 
			
		||||
+#define IEEE80211_TWT_REQTYPE_FLOWID			GENMASK(9, 7)
 | 
			
		||||
+#define IEEE80211_TWT_REQTYPE_WAKE_INT_EXP		GENMASK(14, 10)
 | 
			
		||||
+#define IEEE80211_TWT_REQTYPE_PROTECTION		BIT(15)
 | 
			
		||||
+
 | 
			
		||||
+enum ieee80211_twt_setup_cmd {
 | 
			
		||||
+	TWT_SETUP_CMD_REQUEST,
 | 
			
		||||
+	TWT_SETUP_CMD_SUGGEST,
 | 
			
		||||
+	TWT_SETUP_CMD_DEMAND,
 | 
			
		||||
+	TWT_SETUP_CMD_GROUPING,
 | 
			
		||||
+	TWT_SETUP_CMD_ACCEPT,
 | 
			
		||||
+	TWT_SETUP_CMD_ALTERNATE,
 | 
			
		||||
+	TWT_SETUP_CMD_DICTATE,
 | 
			
		||||
+	TWT_SETUP_CMD_REJECT,
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+struct ieee80211_twt_params {
 | 
			
		||||
+	__le16 req_type;
 | 
			
		||||
+	__le64 twt;
 | 
			
		||||
+	u8 min_twt_dur;
 | 
			
		||||
+	__le16 mantissa;
 | 
			
		||||
+	u8 channel;
 | 
			
		||||
+} __packed;
 | 
			
		||||
+
 | 
			
		||||
+struct ieee80211_twt_setup {
 | 
			
		||||
+	u8 dialog_token;
 | 
			
		||||
+	u8 element_id;
 | 
			
		||||
+	u8 length;
 | 
			
		||||
+	u8 control;
 | 
			
		||||
+	u8 params[];
 | 
			
		||||
+} __packed;
 | 
			
		||||
+
 | 
			
		||||
 struct ieee80211_mgmt {
 | 
			
		||||
 	__le16 frame_control;
 | 
			
		||||
 	__le16 duration;
 | 
			
		||||
@@ -1252,6 +1294,10 @@ struct ieee80211_mgmt {
 | 
			
		||||
 					__le16 toa_error;
 | 
			
		||||
 					u8 variable[0];
 | 
			
		||||
 				} __packed ftm;
 | 
			
		||||
+				struct {
 | 
			
		||||
+					u8 action_code;
 | 
			
		||||
+					u8 variable[];
 | 
			
		||||
+				} __packed s1g;
 | 
			
		||||
 			} u;
 | 
			
		||||
 		} __packed action;
 | 
			
		||||
 	} u;
 | 
			
		||||
@@ -2881,6 +2927,7 @@ enum ieee80211_eid {
 | 
			
		||||
 	WLAN_EID_AID_RESPONSE = 211,
 | 
			
		||||
 	WLAN_EID_S1G_BCN_COMPAT = 213,
 | 
			
		||||
 	WLAN_EID_S1G_SHORT_BCN_INTERVAL = 214,
 | 
			
		||||
+	WLAN_EID_S1G_TWT = 216,
 | 
			
		||||
 	WLAN_EID_S1G_CAPABILITIES = 217,
 | 
			
		||||
 	WLAN_EID_VENDOR_SPECIFIC = 221,
 | 
			
		||||
 	WLAN_EID_QOS_PARAMETER = 222,
 | 
			
		||||
@@ -2950,6 +2997,7 @@ enum ieee80211_category {
 | 
			
		||||
 	WLAN_CATEGORY_FST = 18,
 | 
			
		||||
 	WLAN_CATEGORY_UNPROT_DMG = 20,
 | 
			
		||||
 	WLAN_CATEGORY_VHT = 21,
 | 
			
		||||
+	WLAN_CATEGORY_S1G = 22,
 | 
			
		||||
 	WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126,
 | 
			
		||||
 	WLAN_CATEGORY_VENDOR_SPECIFIC = 127,
 | 
			
		||||
 };
 | 
			
		||||
@@ -3023,6 +3071,20 @@ enum ieee80211_key_len {
 | 
			
		||||
 	WLAN_KEY_LEN_BIP_GMAC_256 = 32,
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
+enum ieee80211_s1g_actioncode {
 | 
			
		||||
+	WLAN_S1G_AID_SWITCH_REQUEST,
 | 
			
		||||
+	WLAN_S1G_AID_SWITCH_RESPONSE,
 | 
			
		||||
+	WLAN_S1G_SYNC_CONTROL,
 | 
			
		||||
+	WLAN_S1G_STA_INFO_ANNOUNCE,
 | 
			
		||||
+	WLAN_S1G_EDCA_PARAM_SET,
 | 
			
		||||
+	WLAN_S1G_EL_OPERATION,
 | 
			
		||||
+	WLAN_S1G_TWT_SETUP,
 | 
			
		||||
+	WLAN_S1G_TWT_TEARDOWN,
 | 
			
		||||
+	WLAN_S1G_SECT_GROUP_ID_LIST,
 | 
			
		||||
+	WLAN_S1G_SECT_ID_FEEDBACK,
 | 
			
		||||
+	WLAN_S1G_TWT_INFORMATION = 11,
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
 #define IEEE80211_WEP_IV_LEN		4
 | 
			
		||||
 #define IEEE80211_WEP_ICV_LEN		4
 | 
			
		||||
 #define IEEE80211_CCMP_HDR_LEN		8
 | 
			
		||||
@ -1,604 +0,0 @@
 | 
			
		||||
From f5a4c24e689f54e66201f04d343bdd2e8a1d7923 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
 | 
			
		||||
Date: Mon, 23 Aug 2021 20:02:39 +0200
 | 
			
		||||
Subject: [PATCH] mac80211: introduce individual TWT support in AP mode
 | 
			
		||||
 | 
			
		||||
Introduce TWT action frames parsing support to mac80211.
 | 
			
		||||
Currently just individual TWT agreement are support in AP mode.
 | 
			
		||||
Whenever the AP receives a TWT action frame from an associated client,
 | 
			
		||||
after performing sanity checks, it will notify the underlay driver with
 | 
			
		||||
requested parameters in order to check if they are supported and if there
 | 
			
		||||
is enough room for a new agreement. The driver is expected to set the
 | 
			
		||||
agreement result and report it to mac80211.
 | 
			
		||||
 | 
			
		||||
Drivers supporting this have two new callbacks:
 | 
			
		||||
 - add_twt_setup (mandatory)
 | 
			
		||||
 - twt_teardown_request (optional)
 | 
			
		||||
 | 
			
		||||
mac80211 will send an action frame reply according to the result
 | 
			
		||||
reported by the driver.
 | 
			
		||||
 | 
			
		||||
Tested-by: Peter Chiu <chui-hao.chiu@mediatek.com>
 | 
			
		||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
 | 
			
		||||
Link: https://lore.kernel.org/r/257512f2e22ba42b9f2624942a128dd8f141de4b.1629741512.git.lorenzo@kernel.org
 | 
			
		||||
[use le16p_replace_bits(), minor cleanups, use (void *) casts,
 | 
			
		||||
 fix to use ieee80211_get_he_iftype_cap() correctly]
 | 
			
		||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 | 
			
		||||
---
 | 
			
		||||
 include/net/mac80211.h     |  12 +++
 | 
			
		||||
 net/mac80211/driver-ops.h  |  36 ++++++++
 | 
			
		||||
 net/mac80211/ieee80211_i.h |   6 ++
 | 
			
		||||
 net/mac80211/iface.c       |  41 +++++++++
 | 
			
		||||
 net/mac80211/rx.c          |  73 +++++++++++++++
 | 
			
		||||
 net/mac80211/s1g.c         | 180 +++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 net/mac80211/status.c      |  17 +++-
 | 
			
		||||
 net/mac80211/trace.h       |  67 ++++++++++++++
 | 
			
		||||
 8 files changed, 430 insertions(+), 2 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/include/net/mac80211.h
 | 
			
		||||
+++ b/include/net/mac80211.h
 | 
			
		||||
@@ -3930,6 +3930,13 @@ struct ieee80211_prep_tx_info {
 | 
			
		||||
  * @set_sar_specs: Update the SAR (TX power) settings.
 | 
			
		||||
  * @sta_set_decap_offload: Called to notify the driver when a station is allowed
 | 
			
		||||
  *	to use rx decapsulation offload
 | 
			
		||||
+ * @add_twt_setup: Update hw with TWT agreement parameters received from the peer.
 | 
			
		||||
+ *	This callback allows the hw to check if requested parameters
 | 
			
		||||
+ *	are supported and if there is enough room for a new agreement.
 | 
			
		||||
+ *	The hw is expected to set agreement result in the req_type field of
 | 
			
		||||
+ *	twt structure.
 | 
			
		||||
+ * @twt_teardown_request: Update the hw with TWT teardown request received
 | 
			
		||||
+ *	from the peer.
 | 
			
		||||
  */
 | 
			
		||||
 struct ieee80211_ops {
 | 
			
		||||
 	void (*tx)(struct ieee80211_hw *hw,
 | 
			
		||||
@@ -4253,6 +4260,11 @@ struct ieee80211_ops {
 | 
			
		||||
 	void (*sta_set_decap_offload)(struct ieee80211_hw *hw,
 | 
			
		||||
 				      struct ieee80211_vif *vif,
 | 
			
		||||
 				      struct ieee80211_sta *sta, bool enabled);
 | 
			
		||||
+	void (*add_twt_setup)(struct ieee80211_hw *hw,
 | 
			
		||||
+			      struct ieee80211_sta *sta,
 | 
			
		||||
+			      struct ieee80211_twt_setup *twt);
 | 
			
		||||
+	void (*twt_teardown_request)(struct ieee80211_hw *hw,
 | 
			
		||||
+				     struct ieee80211_sta *sta, u8 flowid);
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 /**
 | 
			
		||||
--- a/net/mac80211/driver-ops.h
 | 
			
		||||
+++ b/net/mac80211/driver-ops.h
 | 
			
		||||
@@ -1447,4 +1447,40 @@ static inline void drv_sta_set_decap_off
 | 
			
		||||
 	trace_drv_return_void(local);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static inline void drv_add_twt_setup(struct ieee80211_local *local,
 | 
			
		||||
+				     struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
+				     struct ieee80211_sta *sta,
 | 
			
		||||
+				     struct ieee80211_twt_setup *twt)
 | 
			
		||||
+{
 | 
			
		||||
+	struct ieee80211_twt_params *twt_agrt;
 | 
			
		||||
+
 | 
			
		||||
+	might_sleep();
 | 
			
		||||
+
 | 
			
		||||
+	if (!check_sdata_in_driver(sdata))
 | 
			
		||||
+		return;
 | 
			
		||||
+
 | 
			
		||||
+	twt_agrt = (void *)twt->params;
 | 
			
		||||
+
 | 
			
		||||
+	trace_drv_add_twt_setup(local, sta, twt, twt_agrt);
 | 
			
		||||
+	local->ops->add_twt_setup(&local->hw, sta, twt);
 | 
			
		||||
+	trace_drv_return_void(local);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static inline void drv_twt_teardown_request(struct ieee80211_local *local,
 | 
			
		||||
+					    struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
+					    struct ieee80211_sta *sta,
 | 
			
		||||
+					    u8 flowid)
 | 
			
		||||
+{
 | 
			
		||||
+	might_sleep();
 | 
			
		||||
+	if (!check_sdata_in_driver(sdata))
 | 
			
		||||
+		return;
 | 
			
		||||
+
 | 
			
		||||
+	if (!local->ops->twt_teardown_request)
 | 
			
		||||
+		return;
 | 
			
		||||
+
 | 
			
		||||
+	trace_drv_twt_teardown_request(local, sta, flowid);
 | 
			
		||||
+	local->ops->twt_teardown_request(&local->hw, sta, flowid);
 | 
			
		||||
+	trace_drv_return_void(local);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 #endif /* __MAC80211_DRIVER_OPS */
 | 
			
		||||
--- a/net/mac80211/ieee80211_i.h
 | 
			
		||||
+++ b/net/mac80211/ieee80211_i.h
 | 
			
		||||
@@ -949,6 +949,7 @@ struct ieee80211_sub_if_data {
 | 
			
		||||
 
 | 
			
		||||
 	struct work_struct work;
 | 
			
		||||
 	struct sk_buff_head skb_queue;
 | 
			
		||||
+	struct sk_buff_head status_queue;
 | 
			
		||||
 
 | 
			
		||||
 	u8 needed_rx_chains;
 | 
			
		||||
 	enum ieee80211_smps_mode smps_mode;
 | 
			
		||||
@@ -2083,6 +2084,11 @@ ieee80211_he_op_ie_to_bss_conf(struct ie
 | 
			
		||||
 
 | 
			
		||||
 /* S1G */
 | 
			
		||||
 void ieee80211_s1g_sta_rate_init(struct sta_info *sta);
 | 
			
		||||
+bool ieee80211_s1g_is_twt_setup(struct sk_buff *skb);
 | 
			
		||||
+void ieee80211_s1g_rx_twt_action(struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
+				 struct sk_buff *skb);
 | 
			
		||||
+void ieee80211_s1g_status_twt_action(struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
+				     struct sk_buff *skb);
 | 
			
		||||
 
 | 
			
		||||
 /* Spectrum management */
 | 
			
		||||
 void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
--- a/net/mac80211/iface.c
 | 
			
		||||
+++ b/net/mac80211/iface.c
 | 
			
		||||
@@ -552,6 +552,7 @@ static void ieee80211_do_stop(struct iee
 | 
			
		||||
 		 */
 | 
			
		||||
 		ieee80211_free_keys(sdata, true);
 | 
			
		||||
 		skb_queue_purge(&sdata->skb_queue);
 | 
			
		||||
+		skb_queue_purge(&sdata->status_queue);
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
 | 
			
		||||
@@ -1055,6 +1056,7 @@ int ieee80211_add_virtual_monitor(struct
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	skb_queue_head_init(&sdata->skb_queue);
 | 
			
		||||
+	skb_queue_head_init(&sdata->status_queue);
 | 
			
		||||
 	INIT_WORK(&sdata->work, ieee80211_iface_work);
 | 
			
		||||
 
 | 
			
		||||
 	return 0;
 | 
			
		||||
@@ -1459,6 +1461,16 @@ static void ieee80211_iface_process_skb(
 | 
			
		||||
 			WARN_ON(1);
 | 
			
		||||
 			break;
 | 
			
		||||
 		}
 | 
			
		||||
+	} else if (ieee80211_is_action(mgmt->frame_control) &&
 | 
			
		||||
+		   mgmt->u.action.category == WLAN_CATEGORY_S1G) {
 | 
			
		||||
+		switch (mgmt->u.action.u.s1g.action_code) {
 | 
			
		||||
+		case WLAN_S1G_TWT_TEARDOWN:
 | 
			
		||||
+		case WLAN_S1G_TWT_SETUP:
 | 
			
		||||
+			ieee80211_s1g_rx_twt_action(sdata, skb);
 | 
			
		||||
+			break;
 | 
			
		||||
+		default:
 | 
			
		||||
+			break;
 | 
			
		||||
+		}
 | 
			
		||||
 	} else if (ieee80211_is_ext(mgmt->frame_control)) {
 | 
			
		||||
 		if (sdata->vif.type == NL80211_IFTYPE_STATION)
 | 
			
		||||
 			ieee80211_sta_rx_queued_ext(sdata, skb);
 | 
			
		||||
@@ -1514,6 +1526,24 @@ static void ieee80211_iface_process_skb(
 | 
			
		||||
 	}
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static void ieee80211_iface_process_status(struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
+					   struct sk_buff *skb)
 | 
			
		||||
+{
 | 
			
		||||
+	struct ieee80211_mgmt *mgmt = (void *)skb->data;
 | 
			
		||||
+
 | 
			
		||||
+	if (ieee80211_is_action(mgmt->frame_control) &&
 | 
			
		||||
+	    mgmt->u.action.category == WLAN_CATEGORY_S1G) {
 | 
			
		||||
+		switch (mgmt->u.action.u.s1g.action_code) {
 | 
			
		||||
+		case WLAN_S1G_TWT_TEARDOWN:
 | 
			
		||||
+		case WLAN_S1G_TWT_SETUP:
 | 
			
		||||
+			ieee80211_s1g_status_twt_action(sdata, skb);
 | 
			
		||||
+			break;
 | 
			
		||||
+		default:
 | 
			
		||||
+			break;
 | 
			
		||||
+		}
 | 
			
		||||
+	}
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 static void ieee80211_iface_work(struct work_struct *work)
 | 
			
		||||
 {
 | 
			
		||||
 	struct ieee80211_sub_if_data *sdata =
 | 
			
		||||
@@ -1543,6 +1573,16 @@ static void ieee80211_iface_work(struct
 | 
			
		||||
 		kcov_remote_stop();
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
+	/* process status queue */
 | 
			
		||||
+	while ((skb = skb_dequeue(&sdata->status_queue))) {
 | 
			
		||||
+		kcov_remote_start_common(skb_get_kcov_handle(skb));
 | 
			
		||||
+
 | 
			
		||||
+		ieee80211_iface_process_status(sdata, skb);
 | 
			
		||||
+		kfree_skb(skb);
 | 
			
		||||
+
 | 
			
		||||
+		kcov_remote_stop();
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
 	/* then other type-dependent work */
 | 
			
		||||
 	switch (sdata->vif.type) {
 | 
			
		||||
 	case NL80211_IFTYPE_STATION:
 | 
			
		||||
@@ -1606,6 +1646,7 @@ static void ieee80211_setup_sdata(struct
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	skb_queue_head_init(&sdata->skb_queue);
 | 
			
		||||
+	skb_queue_head_init(&sdata->status_queue);
 | 
			
		||||
 	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);
 | 
			
		||||
--- a/net/mac80211/rx.c
 | 
			
		||||
+++ b/net/mac80211/rx.c
 | 
			
		||||
@@ -3211,6 +3211,68 @@ ieee80211_rx_h_mgmt_check(struct ieee802
 | 
			
		||||
 	return RX_CONTINUE;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static bool
 | 
			
		||||
+ieee80211_process_rx_twt_action(struct ieee80211_rx_data *rx)
 | 
			
		||||
+{
 | 
			
		||||
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)rx->skb->data;
 | 
			
		||||
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
 | 
			
		||||
+	struct ieee80211_sub_if_data *sdata = rx->sdata;
 | 
			
		||||
+	const struct ieee80211_sta_he_cap *hecap;
 | 
			
		||||
+	struct ieee80211_supported_band *sband;
 | 
			
		||||
+
 | 
			
		||||
+	/* TWT actions are only supported in AP for the moment */
 | 
			
		||||
+	if (sdata->vif.type != NL80211_IFTYPE_AP)
 | 
			
		||||
+		return false;
 | 
			
		||||
+
 | 
			
		||||
+	if (!rx->local->ops->add_twt_setup)
 | 
			
		||||
+		return false;
 | 
			
		||||
+
 | 
			
		||||
+	sband = rx->local->hw.wiphy->bands[status->band];
 | 
			
		||||
+	hecap = ieee80211_get_he_iftype_cap(sband,
 | 
			
		||||
+					    ieee80211_vif_type_p2p(&sdata->vif));
 | 
			
		||||
+	if (!hecap)
 | 
			
		||||
+		return false;
 | 
			
		||||
+
 | 
			
		||||
+	if (!(hecap->he_cap_elem.mac_cap_info[0] &
 | 
			
		||||
+	      IEEE80211_HE_MAC_CAP0_TWT_RES))
 | 
			
		||||
+		return false;
 | 
			
		||||
+
 | 
			
		||||
+	if (!rx->sta)
 | 
			
		||||
+		return false;
 | 
			
		||||
+
 | 
			
		||||
+	switch (mgmt->u.action.u.s1g.action_code) {
 | 
			
		||||
+	case WLAN_S1G_TWT_SETUP: {
 | 
			
		||||
+		struct ieee80211_twt_setup *twt;
 | 
			
		||||
+
 | 
			
		||||
+		if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE +
 | 
			
		||||
+				   1 + /* action code */
 | 
			
		||||
+				   sizeof(struct ieee80211_twt_setup) +
 | 
			
		||||
+				   2 /* TWT req_type agrt */)
 | 
			
		||||
+			break;
 | 
			
		||||
+
 | 
			
		||||
+		twt = (void *)mgmt->u.action.u.s1g.variable;
 | 
			
		||||
+		if (twt->element_id != WLAN_EID_S1G_TWT)
 | 
			
		||||
+			break;
 | 
			
		||||
+
 | 
			
		||||
+		if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE +
 | 
			
		||||
+				   4 + /* action code + token + tlv */
 | 
			
		||||
+				   twt->length)
 | 
			
		||||
+			break;
 | 
			
		||||
+
 | 
			
		||||
+		return true; /* queue the frame */
 | 
			
		||||
+	}
 | 
			
		||||
+	case WLAN_S1G_TWT_TEARDOWN:
 | 
			
		||||
+		if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE + 2)
 | 
			
		||||
+			break;
 | 
			
		||||
+
 | 
			
		||||
+		return true; /* queue the frame */
 | 
			
		||||
+	default:
 | 
			
		||||
+		break;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return false;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 static ieee80211_rx_result debug_noinline
 | 
			
		||||
 ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 | 
			
		||||
 {
 | 
			
		||||
@@ -3490,6 +3552,17 @@ ieee80211_rx_h_action(struct ieee80211_r
 | 
			
		||||
 		    !mesh_path_sel_is_hwmp(sdata))
 | 
			
		||||
 			break;
 | 
			
		||||
 		goto queue;
 | 
			
		||||
+	case WLAN_CATEGORY_S1G:
 | 
			
		||||
+		switch (mgmt->u.action.u.s1g.action_code) {
 | 
			
		||||
+		case WLAN_S1G_TWT_SETUP:
 | 
			
		||||
+		case WLAN_S1G_TWT_TEARDOWN:
 | 
			
		||||
+			if (ieee80211_process_rx_twt_action(rx))
 | 
			
		||||
+				goto queue;
 | 
			
		||||
+			break;
 | 
			
		||||
+		default:
 | 
			
		||||
+			break;
 | 
			
		||||
+		}
 | 
			
		||||
+		break;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	return RX_CONTINUE;
 | 
			
		||||
--- a/net/mac80211/s1g.c
 | 
			
		||||
+++ b/net/mac80211/s1g.c
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
 #include <linux/ieee80211.h>
 | 
			
		||||
 #include <net/mac80211.h>
 | 
			
		||||
 #include "ieee80211_i.h"
 | 
			
		||||
+#include "driver-ops.h"
 | 
			
		||||
 
 | 
			
		||||
 void ieee80211_s1g_sta_rate_init(struct sta_info *sta)
 | 
			
		||||
 {
 | 
			
		||||
@@ -14,3 +15,182 @@ void ieee80211_s1g_sta_rate_init(struct
 | 
			
		||||
 	sta->rx_stats.last_rate =
 | 
			
		||||
 			STA_STATS_FIELD(TYPE, STA_STATS_RATE_TYPE_S1G);
 | 
			
		||||
 }
 | 
			
		||||
+
 | 
			
		||||
+bool ieee80211_s1g_is_twt_setup(struct sk_buff *skb)
 | 
			
		||||
+{
 | 
			
		||||
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
 | 
			
		||||
+
 | 
			
		||||
+	if (likely(!ieee80211_is_action(mgmt->frame_control)))
 | 
			
		||||
+		return false;
 | 
			
		||||
+
 | 
			
		||||
+	if (likely(mgmt->u.action.category != WLAN_CATEGORY_S1G))
 | 
			
		||||
+		return false;
 | 
			
		||||
+
 | 
			
		||||
+	return mgmt->u.action.u.s1g.action_code == WLAN_S1G_TWT_SETUP;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static void
 | 
			
		||||
+ieee80211_s1g_send_twt_setup(struct ieee80211_sub_if_data *sdata, const u8 *da,
 | 
			
		||||
+			     const u8 *bssid, struct ieee80211_twt_setup *twt)
 | 
			
		||||
+{
 | 
			
		||||
+	int len = IEEE80211_MIN_ACTION_SIZE + 4 + twt->length;
 | 
			
		||||
+	struct ieee80211_local *local = sdata->local;
 | 
			
		||||
+	struct ieee80211_mgmt *mgmt;
 | 
			
		||||
+	struct sk_buff *skb;
 | 
			
		||||
+
 | 
			
		||||
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
 | 
			
		||||
+	if (!skb)
 | 
			
		||||
+		return;
 | 
			
		||||
+
 | 
			
		||||
+	skb_reserve(skb, local->hw.extra_tx_headroom);
 | 
			
		||||
+	mgmt = skb_put_zero(skb, len);
 | 
			
		||||
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 | 
			
		||||
+					  IEEE80211_STYPE_ACTION);
 | 
			
		||||
+	memcpy(mgmt->da, da, ETH_ALEN);
 | 
			
		||||
+	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
 | 
			
		||||
+	memcpy(mgmt->bssid, bssid, ETH_ALEN);
 | 
			
		||||
+
 | 
			
		||||
+	mgmt->u.action.category = WLAN_CATEGORY_S1G;
 | 
			
		||||
+	mgmt->u.action.u.s1g.action_code = WLAN_S1G_TWT_SETUP;
 | 
			
		||||
+	memcpy(mgmt->u.action.u.s1g.variable, twt, 3 + twt->length);
 | 
			
		||||
+
 | 
			
		||||
+	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
 | 
			
		||||
+					IEEE80211_TX_INTFL_MLME_CONN_TX |
 | 
			
		||||
+					IEEE80211_TX_CTL_REQ_TX_STATUS;
 | 
			
		||||
+	ieee80211_tx_skb(sdata, skb);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static void
 | 
			
		||||
+ieee80211_s1g_send_twt_teardown(struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
+				const u8 *da, const u8 *bssid, u8 flowid)
 | 
			
		||||
+{
 | 
			
		||||
+	struct ieee80211_local *local = sdata->local;
 | 
			
		||||
+	struct ieee80211_mgmt *mgmt;
 | 
			
		||||
+	struct sk_buff *skb;
 | 
			
		||||
+	u8 *id;
 | 
			
		||||
+
 | 
			
		||||
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
 | 
			
		||||
+			    IEEE80211_MIN_ACTION_SIZE + 2);
 | 
			
		||||
+	if (!skb)
 | 
			
		||||
+		return;
 | 
			
		||||
+
 | 
			
		||||
+	skb_reserve(skb, local->hw.extra_tx_headroom);
 | 
			
		||||
+	mgmt = skb_put_zero(skb, IEEE80211_MIN_ACTION_SIZE + 2);
 | 
			
		||||
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 | 
			
		||||
+					  IEEE80211_STYPE_ACTION);
 | 
			
		||||
+	memcpy(mgmt->da, da, ETH_ALEN);
 | 
			
		||||
+	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
 | 
			
		||||
+	memcpy(mgmt->bssid, bssid, ETH_ALEN);
 | 
			
		||||
+
 | 
			
		||||
+	mgmt->u.action.category = WLAN_CATEGORY_S1G;
 | 
			
		||||
+	mgmt->u.action.u.s1g.action_code = WLAN_S1G_TWT_TEARDOWN;
 | 
			
		||||
+	id = (u8 *)mgmt->u.action.u.s1g.variable;
 | 
			
		||||
+	*id = flowid;
 | 
			
		||||
+
 | 
			
		||||
+	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
 | 
			
		||||
+					IEEE80211_TX_CTL_REQ_TX_STATUS;
 | 
			
		||||
+	ieee80211_tx_skb(sdata, skb);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static void
 | 
			
		||||
+ieee80211_s1g_rx_twt_setup(struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
+			   struct sta_info *sta, struct sk_buff *skb)
 | 
			
		||||
+{
 | 
			
		||||
+	struct ieee80211_mgmt *mgmt = (void *)skb->data;
 | 
			
		||||
+	struct ieee80211_twt_setup *twt = (void *)mgmt->u.action.u.s1g.variable;
 | 
			
		||||
+	struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
 | 
			
		||||
+
 | 
			
		||||
+	twt_agrt->req_type &= cpu_to_le16(~IEEE80211_TWT_REQTYPE_REQUEST);
 | 
			
		||||
+
 | 
			
		||||
+	/* broadcast TWT not supported yet */
 | 
			
		||||
+	if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST) {
 | 
			
		||||
+		le16p_replace_bits(&twt_agrt->req_type,
 | 
			
		||||
+				   TWT_SETUP_CMD_REJECT,
 | 
			
		||||
+				   IEEE80211_TWT_REQTYPE_SETUP_CMD);
 | 
			
		||||
+		goto out;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	drv_add_twt_setup(sdata->local, sdata, &sta->sta, twt);
 | 
			
		||||
+out:
 | 
			
		||||
+	ieee80211_s1g_send_twt_setup(sdata, mgmt->sa, sdata->vif.addr, twt);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static void
 | 
			
		||||
+ieee80211_s1g_rx_twt_teardown(struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
+			      struct sta_info *sta, struct sk_buff *skb)
 | 
			
		||||
+{
 | 
			
		||||
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
 | 
			
		||||
+
 | 
			
		||||
+	drv_twt_teardown_request(sdata->local, sdata, &sta->sta,
 | 
			
		||||
+				 mgmt->u.action.u.s1g.variable[0]);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static void
 | 
			
		||||
+ieee80211_s1g_tx_twt_setup_fail(struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
+				struct sta_info *sta, struct sk_buff *skb)
 | 
			
		||||
+{
 | 
			
		||||
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
 | 
			
		||||
+	struct ieee80211_twt_setup *twt = (void *)mgmt->u.action.u.s1g.variable;
 | 
			
		||||
+	struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
 | 
			
		||||
+	u8 flowid = le16_get_bits(twt_agrt->req_type,
 | 
			
		||||
+				  IEEE80211_TWT_REQTYPE_FLOWID);
 | 
			
		||||
+
 | 
			
		||||
+	drv_twt_teardown_request(sdata->local, sdata, &sta->sta, flowid);
 | 
			
		||||
+
 | 
			
		||||
+	ieee80211_s1g_send_twt_teardown(sdata, mgmt->sa, sdata->vif.addr,
 | 
			
		||||
+					flowid);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+void ieee80211_s1g_rx_twt_action(struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
+				 struct sk_buff *skb)
 | 
			
		||||
+{
 | 
			
		||||
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
 | 
			
		||||
+	struct ieee80211_local *local = sdata->local;
 | 
			
		||||
+	struct sta_info *sta;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&local->sta_mtx);
 | 
			
		||||
+
 | 
			
		||||
+	sta = sta_info_get_bss(sdata, mgmt->sa);
 | 
			
		||||
+	if (!sta)
 | 
			
		||||
+		goto out;
 | 
			
		||||
+
 | 
			
		||||
+	switch (mgmt->u.action.u.s1g.action_code) {
 | 
			
		||||
+	case WLAN_S1G_TWT_SETUP:
 | 
			
		||||
+		ieee80211_s1g_rx_twt_setup(sdata, sta, skb);
 | 
			
		||||
+		break;
 | 
			
		||||
+	case WLAN_S1G_TWT_TEARDOWN:
 | 
			
		||||
+		ieee80211_s1g_rx_twt_teardown(sdata, sta, skb);
 | 
			
		||||
+		break;
 | 
			
		||||
+	default:
 | 
			
		||||
+		break;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+out:
 | 
			
		||||
+	mutex_unlock(&local->sta_mtx);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+void ieee80211_s1g_status_twt_action(struct ieee80211_sub_if_data *sdata,
 | 
			
		||||
+				     struct sk_buff *skb)
 | 
			
		||||
+{
 | 
			
		||||
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
 | 
			
		||||
+	struct ieee80211_local *local = sdata->local;
 | 
			
		||||
+	struct sta_info *sta;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&local->sta_mtx);
 | 
			
		||||
+
 | 
			
		||||
+	sta = sta_info_get_bss(sdata, mgmt->da);
 | 
			
		||||
+	if (!sta)
 | 
			
		||||
+		goto out;
 | 
			
		||||
+
 | 
			
		||||
+	switch (mgmt->u.action.u.s1g.action_code) {
 | 
			
		||||
+	case WLAN_S1G_TWT_SETUP:
 | 
			
		||||
+		/* process failed twt setup frames */
 | 
			
		||||
+		ieee80211_s1g_tx_twt_setup_fail(sdata, sta, skb);
 | 
			
		||||
+		break;
 | 
			
		||||
+	default:
 | 
			
		||||
+		break;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+out:
 | 
			
		||||
+	mutex_unlock(&local->sta_mtx);
 | 
			
		||||
+}
 | 
			
		||||
--- a/net/mac80211/status.c
 | 
			
		||||
+++ b/net/mac80211/status.c
 | 
			
		||||
@@ -705,13 +705,26 @@ static void ieee80211_report_used_skb(st
 | 
			
		||||
 			/* Check to see if packet is a TDLS teardown packet */
 | 
			
		||||
 			if (ieee80211_is_data(hdr->frame_control) &&
 | 
			
		||||
 			    (ieee80211_get_tdls_action(skb, hdr_size) ==
 | 
			
		||||
-			     WLAN_TDLS_TEARDOWN))
 | 
			
		||||
+			     WLAN_TDLS_TEARDOWN)) {
 | 
			
		||||
 				ieee80211_tdls_td_tx_handle(local, sdata, skb,
 | 
			
		||||
 							    info->flags);
 | 
			
		||||
-			else
 | 
			
		||||
+			} else if (ieee80211_s1g_is_twt_setup(skb)) {
 | 
			
		||||
+				if (!acked) {
 | 
			
		||||
+					struct sk_buff *qskb;
 | 
			
		||||
+
 | 
			
		||||
+					qskb = skb_clone(skb, GFP_ATOMIC);
 | 
			
		||||
+					if (qskb) {
 | 
			
		||||
+						skb_queue_tail(&sdata->status_queue,
 | 
			
		||||
+							       qskb);
 | 
			
		||||
+						ieee80211_queue_work(&local->hw,
 | 
			
		||||
+								     &sdata->work);
 | 
			
		||||
+					}
 | 
			
		||||
+				}
 | 
			
		||||
+			} else {
 | 
			
		||||
 				ieee80211_mgd_conn_tx_status(sdata,
 | 
			
		||||
 							     hdr->frame_control,
 | 
			
		||||
 							     acked);
 | 
			
		||||
+			}
 | 
			
		||||
 		}
 | 
			
		||||
 
 | 
			
		||||
 		rcu_read_unlock();
 | 
			
		||||
--- a/net/mac80211/trace.h
 | 
			
		||||
+++ b/net/mac80211/trace.h
 | 
			
		||||
@@ -2825,6 +2825,73 @@ DEFINE_EVENT(sta_flag_evt, drv_sta_set_d
 | 
			
		||||
 	TP_ARGS(local, sdata, sta, enabled)
 | 
			
		||||
 );
 | 
			
		||||
 
 | 
			
		||||
+TRACE_EVENT(drv_add_twt_setup,
 | 
			
		||||
+	TP_PROTO(struct ieee80211_local *local,
 | 
			
		||||
+		 struct ieee80211_sta *sta,
 | 
			
		||||
+		 struct ieee80211_twt_setup *twt,
 | 
			
		||||
+		 struct ieee80211_twt_params *twt_agrt),
 | 
			
		||||
+
 | 
			
		||||
+	TP_ARGS(local, sta, twt, twt_agrt),
 | 
			
		||||
+
 | 
			
		||||
+	TP_STRUCT__entry(
 | 
			
		||||
+		LOCAL_ENTRY
 | 
			
		||||
+		STA_ENTRY
 | 
			
		||||
+		__field(u8, dialog_token)
 | 
			
		||||
+		__field(u8, control)
 | 
			
		||||
+		__field(__le16, req_type)
 | 
			
		||||
+		__field(__le64, twt)
 | 
			
		||||
+		__field(u8, duration)
 | 
			
		||||
+		__field(__le16, mantissa)
 | 
			
		||||
+		__field(u8, channel)
 | 
			
		||||
+	),
 | 
			
		||||
+
 | 
			
		||||
+	TP_fast_assign(
 | 
			
		||||
+		LOCAL_ASSIGN;
 | 
			
		||||
+		STA_ASSIGN;
 | 
			
		||||
+		__entry->dialog_token = twt->dialog_token;
 | 
			
		||||
+		__entry->control = twt->control;
 | 
			
		||||
+		__entry->req_type = twt_agrt->req_type;
 | 
			
		||||
+		__entry->twt = twt_agrt->twt;
 | 
			
		||||
+		__entry->duration = twt_agrt->min_twt_dur;
 | 
			
		||||
+		__entry->mantissa = twt_agrt->mantissa;
 | 
			
		||||
+		__entry->channel = twt_agrt->channel;
 | 
			
		||||
+	),
 | 
			
		||||
+
 | 
			
		||||
+	TP_printk(
 | 
			
		||||
+		LOCAL_PR_FMT STA_PR_FMT
 | 
			
		||||
+		" token:%d control:0x%02x req_type:0x%04x"
 | 
			
		||||
+		" twt:%llu duration:%d mantissa:%d channel:%d",
 | 
			
		||||
+		LOCAL_PR_ARG, STA_PR_ARG, __entry->dialog_token,
 | 
			
		||||
+		__entry->control, le16_to_cpu(__entry->req_type),
 | 
			
		||||
+		le64_to_cpu(__entry->twt), __entry->duration,
 | 
			
		||||
+		le16_to_cpu(__entry->mantissa), __entry->channel
 | 
			
		||||
+	)
 | 
			
		||||
+);
 | 
			
		||||
+
 | 
			
		||||
+TRACE_EVENT(drv_twt_teardown_request,
 | 
			
		||||
+	TP_PROTO(struct ieee80211_local *local,
 | 
			
		||||
+		 struct ieee80211_sta *sta, u8 flowid),
 | 
			
		||||
+
 | 
			
		||||
+	TP_ARGS(local, sta, flowid),
 | 
			
		||||
+
 | 
			
		||||
+	TP_STRUCT__entry(
 | 
			
		||||
+		LOCAL_ENTRY
 | 
			
		||||
+		STA_ENTRY
 | 
			
		||||
+		__field(u8, flowid)
 | 
			
		||||
+	),
 | 
			
		||||
+
 | 
			
		||||
+	TP_fast_assign(
 | 
			
		||||
+		LOCAL_ASSIGN;
 | 
			
		||||
+		STA_ASSIGN;
 | 
			
		||||
+		__entry->flowid = flowid;
 | 
			
		||||
+	),
 | 
			
		||||
+
 | 
			
		||||
+	TP_printk(
 | 
			
		||||
+		LOCAL_PR_FMT STA_PR_FMT " flowid:%d",
 | 
			
		||||
+		LOCAL_PR_ARG, STA_PR_ARG, __entry->flowid
 | 
			
		||||
+	)
 | 
			
		||||
+);
 | 
			
		||||
+
 | 
			
		||||
 #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
 | 
			
		||||
 
 | 
			
		||||
 #undef TRACE_INCLUDE_PATH
 | 
			
		||||
@ -87,7 +87,7 @@
 | 
			
		||||
 	CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump)
 | 
			
		||||
--- a/net/mac80211/ieee80211_i.h
 | 
			
		||||
+++ b/net/mac80211/ieee80211_i.h
 | 
			
		||||
@@ -1428,6 +1428,7 @@ struct ieee80211_local {
 | 
			
		||||
@@ -1429,6 +1429,7 @@ struct ieee80211_local {
 | 
			
		||||
 	int dynamic_ps_forced_timeout;
 | 
			
		||||
 
 | 
			
		||||
 	int user_power_level; /* in dBm, for all interfaces */
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user