[openwrt/openwrt] mac80211: backport AP mode TWT support

LEDE Commits lede-commits at lists.infradead.org
Mon Oct 11 04:28:33 PDT 2021


nbd pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/978e822db354daf974811f2717c6013fa3eb8079

commit 978e822db354daf974811f2717c6013fa3eb8079
Author: Felix Fietkau <nbd at nbd.name>
AuthorDate: Mon Oct 11 11:48:49 2021 +0200

    mac80211: backport AP mode TWT support
    
    Required for an upcoming mt76 update
    
    Signed-off-by: Felix Fietkau <nbd at nbd.name>
---
 ...389-ieee80211-add-TWT-element-definitions.patch | 112 ++++
 ...troduce-individual-TWT-support-in-AP-mode.patch | 580 +++++++++++++++++++++
 .../500-mac80211_configure_antenna_gain.patch      |   2 +-
 3 files changed, 693 insertions(+), 1 deletion(-)

diff --git a/package/kernel/mac80211/patches/subsys/389-ieee80211-add-TWT-element-definitions.patch b/package/kernel/mac80211/patches/subsys/389-ieee80211-add-TWT-element-definitions.patch
new file mode 100644
index 0000000000..369619938e
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/389-ieee80211-add-TWT-element-definitions.patch
@@ -0,0 +1,112 @@
+From: Lorenzo Bianconi <lorenzo at 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 at mediatek.com>
+Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
+Link: https://lore.kernel.org/r/71d8b581fe4b5abc5b92f8d77ac2de3e2f7591b6.1629741512.git.lorenzo@kernel.org
+Signed-off-by: Johannes Berg <johannes.berg at 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;
+@@ -2880,6 +2926,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,
+@@ -2948,6 +2995,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,
+ };
+@@ -3021,6 +3069,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
diff --git a/package/kernel/mac80211/patches/subsys/390-mac80211-introduce-individual-TWT-support-in-AP-mode.patch b/package/kernel/mac80211/patches/subsys/390-mac80211-introduce-individual-TWT-support-in-AP-mode.patch
new file mode 100644
index 0000000000..dbd98b96cc
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/390-mac80211-introduce-individual-TWT-support-in-AP-mode.patch
@@ -0,0 +1,580 @@
+From: Lorenzo Bianconi <lorenzo at 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 at mediatek.com>
+Signed-off-by: Lorenzo Bianconi <lorenzo at 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 at intel.com>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -4219,6 +4219,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
+@@ -1429,4 +1429,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
+@@ -954,6 +954,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;
+@@ -2093,6 +2094,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
+@@ -563,6 +563,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);
+@@ -1070,6 +1071,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;
+@@ -1442,6 +1444,24 @@ static void ieee80211_if_setup_no_queue(
+ #endif
+ }
+ 
++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 =
+@@ -1519,6 +1539,16 @@ static void ieee80211_iface_work(struct
+ 				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);
+@@ -1574,6 +1604,16 @@ static void ieee80211_iface_work(struct
+ 		kfree_skb(skb);
+ 	}
+ 
++	/* 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:
+@@ -1637,6 +1677,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
+@@ -3208,6 +3208,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)
+ {
+@@ -3487,6 +3549,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
+@@ -2804,6 +2804,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
diff --git a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
index 2755efb194..6f13f64208 100644
--- a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
+++ b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
@@ -87,7 +87,7 @@
  	CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
 --- a/net/mac80211/ieee80211_i.h
 +++ b/net/mac80211/ieee80211_i.h
-@@ -1434,6 +1434,7 @@ struct ieee80211_local {
+@@ -1435,6 +1435,7 @@ struct ieee80211_local {
  	int dynamic_ps_forced_timeout;
  
  	int user_power_level; /* in dBm, for all interfaces */



More information about the lede-commits mailing list