From 978e822db354daf974811f2717c6013fa3eb8079 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 11 Oct 2021 11:48:49 +0200 Subject: [PATCH] mac80211: backport AP mode TWT support Required for an upcoming mt76 update Signed-off-by: Felix Fietkau --- ...eee80211-add-TWT-element-definitions.patch | 112 ++++ ...ce-individual-TWT-support-in-AP-mode.patch | 580 ++++++++++++++++++ .../500-mac80211_configure_antenna_gain.patch | 2 +- 3 files changed, 693 insertions(+), 1 deletion(-) create mode 100644 package/kernel/mac80211/patches/subsys/389-ieee80211-add-TWT-element-definitions.patch create mode 100644 package/kernel/mac80211/patches/subsys/390-mac80211-introduce-individual-TWT-support-in-AP-mode.patch 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 +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 +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/71d8b581fe4b5abc5b92f8d77ac2de3e2f7591b6.1629741512.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- 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 +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 +Signed-off-by: Lorenzo Bianconi +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 +--- + +--- 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 + #include + #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 */ -- 2.30.2