1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * S1G handling 4 * Copyright(c) 2020 Adapt-IP 5 * Copyright (C) 2023, 2026 Intel Corporation 6 */ 7 #include <linux/ieee80211.h> 8 #include <net/mac80211.h> 9 #include "ieee80211_i.h" 10 #include "driver-ops.h" 11 12 void ieee80211_s1g_sta_rate_init(struct sta_info *sta) 13 { 14 /* avoid indicating legacy bitrates for S1G STAs */ 15 sta->deflink.tx_stats.last_rate.flags |= IEEE80211_TX_RC_S1G_MCS; 16 sta->deflink.rx_stats.last_rate = 17 STA_STATS_FIELD(TYPE, STA_STATS_RATE_TYPE_S1G); 18 } 19 20 bool ieee80211_s1g_is_twt_setup(struct sk_buff *skb) 21 { 22 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; 23 24 if (likely(!ieee80211_is_action(mgmt->frame_control))) 25 return false; 26 27 if (likely(mgmt->u.action.category != WLAN_CATEGORY_S1G)) 28 return false; 29 30 return mgmt->u.action.action_code == WLAN_S1G_TWT_SETUP; 31 } 32 33 static void 34 ieee80211_s1g_send_twt_setup(struct ieee80211_sub_if_data *sdata, const u8 *da, 35 const u8 *bssid, struct ieee80211_twt_setup *twt) 36 { 37 int len = IEEE80211_MIN_ACTION_SIZE(s1g) + 3 + twt->length; 38 struct ieee80211_local *local = sdata->local; 39 struct ieee80211_mgmt *mgmt; 40 struct sk_buff *skb; 41 42 skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); 43 if (!skb) 44 return; 45 46 skb_reserve(skb, local->hw.extra_tx_headroom); 47 mgmt = skb_put_zero(skb, len); 48 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 49 IEEE80211_STYPE_ACTION); 50 memcpy(mgmt->da, da, ETH_ALEN); 51 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); 52 memcpy(mgmt->bssid, bssid, ETH_ALEN); 53 54 mgmt->u.action.category = WLAN_CATEGORY_S1G; 55 mgmt->u.action.action_code = WLAN_S1G_TWT_SETUP; 56 memcpy(mgmt->u.action.s1g.variable, twt, 3 + twt->length); 57 58 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | 59 IEEE80211_TX_INTFL_MLME_CONN_TX | 60 IEEE80211_TX_CTL_REQ_TX_STATUS; 61 ieee80211_tx_skb(sdata, skb); 62 } 63 64 static void 65 ieee80211_s1g_send_twt_teardown(struct ieee80211_sub_if_data *sdata, 66 const u8 *da, const u8 *bssid, u8 flowid) 67 { 68 struct ieee80211_local *local = sdata->local; 69 struct ieee80211_mgmt *mgmt; 70 struct sk_buff *skb; 71 u8 *id; 72 73 skb = dev_alloc_skb(local->hw.extra_tx_headroom + 74 IEEE80211_MIN_ACTION_SIZE(s1g) + 1); 75 if (!skb) 76 return; 77 78 skb_reserve(skb, local->hw.extra_tx_headroom); 79 mgmt = skb_put_zero(skb, IEEE80211_MIN_ACTION_SIZE(s1g) + 1); 80 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 81 IEEE80211_STYPE_ACTION); 82 memcpy(mgmt->da, da, ETH_ALEN); 83 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); 84 memcpy(mgmt->bssid, bssid, ETH_ALEN); 85 86 mgmt->u.action.category = WLAN_CATEGORY_S1G; 87 mgmt->u.action.action_code = WLAN_S1G_TWT_TEARDOWN; 88 id = (u8 *)mgmt->u.action.s1g.variable; 89 *id = flowid; 90 91 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | 92 IEEE80211_TX_CTL_REQ_TX_STATUS; 93 ieee80211_tx_skb(sdata, skb); 94 } 95 96 static void 97 ieee80211_s1g_rx_twt_setup(struct ieee80211_sub_if_data *sdata, 98 struct sta_info *sta, struct sk_buff *skb) 99 { 100 struct ieee80211_mgmt *mgmt = (void *)skb->data; 101 struct ieee80211_twt_setup *twt = (void *)mgmt->u.action.s1g.variable; 102 struct ieee80211_twt_params *twt_agrt = (void *)twt->params; 103 104 if (!(twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST) && 105 twt->length < sizeof(twt->control) + sizeof(*twt_agrt)) 106 return; 107 108 twt_agrt->req_type &= cpu_to_le16(~IEEE80211_TWT_REQTYPE_REQUEST); 109 110 /* broadcast TWT not supported yet */ 111 if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST) { 112 twt_agrt->req_type &= 113 ~cpu_to_le16(IEEE80211_TWT_REQTYPE_SETUP_CMD); 114 twt_agrt->req_type |= 115 le16_encode_bits(TWT_SETUP_CMD_REJECT, 116 IEEE80211_TWT_REQTYPE_SETUP_CMD); 117 goto out; 118 } 119 120 /* TWT Information not supported yet */ 121 twt->control |= IEEE80211_TWT_CONTROL_RX_DISABLED; 122 123 drv_add_twt_setup(sdata->local, sdata, &sta->sta, twt); 124 out: 125 ieee80211_s1g_send_twt_setup(sdata, mgmt->sa, sdata->vif.addr, twt); 126 } 127 128 static void 129 ieee80211_s1g_rx_twt_teardown(struct ieee80211_sub_if_data *sdata, 130 struct sta_info *sta, struct sk_buff *skb) 131 { 132 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; 133 134 drv_twt_teardown_request(sdata->local, sdata, &sta->sta, 135 mgmt->u.action.s1g.variable[0]); 136 } 137 138 static void 139 ieee80211_s1g_tx_twt_setup_fail(struct ieee80211_sub_if_data *sdata, 140 struct sta_info *sta, struct sk_buff *skb) 141 { 142 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; 143 struct ieee80211_twt_setup *twt = (void *)mgmt->u.action.s1g.variable; 144 struct ieee80211_twt_params *twt_agrt = (void *)twt->params; 145 u8 flowid = le16_get_bits(twt_agrt->req_type, 146 IEEE80211_TWT_REQTYPE_FLOWID); 147 148 drv_twt_teardown_request(sdata->local, sdata, &sta->sta, flowid); 149 150 ieee80211_s1g_send_twt_teardown(sdata, mgmt->sa, sdata->vif.addr, 151 flowid); 152 } 153 154 void ieee80211_s1g_rx_twt_action(struct ieee80211_sub_if_data *sdata, 155 struct sk_buff *skb) 156 { 157 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; 158 struct ieee80211_local *local = sdata->local; 159 struct sta_info *sta; 160 161 lockdep_assert_wiphy(local->hw.wiphy); 162 163 sta = sta_info_get_bss(sdata, mgmt->sa); 164 if (!sta) 165 return; 166 167 switch (mgmt->u.action.action_code) { 168 case WLAN_S1G_TWT_SETUP: 169 ieee80211_s1g_rx_twt_setup(sdata, sta, skb); 170 break; 171 case WLAN_S1G_TWT_TEARDOWN: 172 ieee80211_s1g_rx_twt_teardown(sdata, sta, skb); 173 break; 174 default: 175 break; 176 } 177 } 178 179 void ieee80211_s1g_status_twt_action(struct ieee80211_sub_if_data *sdata, 180 struct sk_buff *skb) 181 { 182 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; 183 struct ieee80211_local *local = sdata->local; 184 struct sta_info *sta; 185 186 lockdep_assert_wiphy(local->hw.wiphy); 187 188 sta = sta_info_get_bss(sdata, mgmt->da); 189 if (!sta) 190 return; 191 192 switch (mgmt->u.action.action_code) { 193 case WLAN_S1G_TWT_SETUP: 194 /* process failed twt setup frames */ 195 ieee80211_s1g_tx_twt_setup_fail(sdata, sta, skb); 196 break; 197 default: 198 break; 199 } 200 } 201 202 void ieee80211_s1g_cap_to_sta_s1g_cap(struct ieee80211_sub_if_data *sdata, 203 const struct ieee80211_s1g_cap *s1g_cap_ie, 204 struct link_sta_info *link_sta) 205 { 206 struct ieee80211_sta_s1g_cap *s1g_cap = &link_sta->pub->s1g_cap; 207 208 memset(s1g_cap, 0, sizeof(*s1g_cap)); 209 210 memcpy(s1g_cap->cap, s1g_cap_ie->capab_info, sizeof(s1g_cap->cap)); 211 memcpy(s1g_cap->nss_mcs, s1g_cap_ie->supp_mcs_nss, 212 sizeof(s1g_cap->nss_mcs)); 213 214 s1g_cap->s1g = true; 215 216 /* Maximum MPDU length is 1 bit for S1G */ 217 if (s1g_cap->cap[3] & S1G_CAP3_MAX_MPDU_LEN) { 218 link_sta->pub->agg.max_amsdu_len = 219 IEEE80211_MAX_MPDU_LEN_VHT_7991; 220 } else { 221 link_sta->pub->agg.max_amsdu_len = 222 IEEE80211_MAX_MPDU_LEN_VHT_3895; 223 } 224 225 ieee80211_sta_recalc_aggregates(&link_sta->sta->sta); 226 } 227 228 bool ieee80211_s1g_use_ndp_ba(const struct ieee80211_sub_if_data *sdata, 229 const struct sta_info *sta) 230 { 231 return sdata->vif.cfg.s1g && 232 ieee80211_hw_check(&sdata->local->hw, SUPPORTS_NDP_BLOCKACK) && 233 (sta && sta->sta.deflink.s1g_cap.s1g); 234 } 235