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>
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)
PKG_DRIVERS = \
adm8211 \
- airo \
hermes hermes-pci hermes-pcmcia hermes-plx\
lib80211 \
mac80211-hwsim \
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
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
--- 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;
/* 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)
{
--- 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.
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.
+ 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);
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;
+ 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);
--- 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
*/
--- 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
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;
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);
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,
--- 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=
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
--- 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=
--- 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);
--- 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)
*/
+++ /dev/null
-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
+++ /dev/null
-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;
+++ /dev/null
-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
+++ /dev/null
-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
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 */