1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * EHT handling 4 * 5 * Copyright(c) 2021-2025 Intel Corporation 6 */ 7 8 #include "driver-ops.h" 9 #include "ieee80211_i.h" 10 11 void 12 ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, 13 struct ieee80211_supported_band *sband, 14 const u8 *he_cap_ie, u8 he_cap_len, 15 const struct ieee80211_eht_cap_elem *eht_cap_ie_elem, 16 u8 eht_cap_len, 17 struct link_sta_info *link_sta) 18 { 19 struct ieee80211_sta_eht_cap *eht_cap = &link_sta->pub->eht_cap; 20 struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie; 21 u8 eht_ppe_size = 0; 22 u8 mcs_nss_size; 23 u8 eht_total_size = sizeof(eht_cap->eht_cap_elem); 24 u8 *pos = (u8 *)eht_cap_ie_elem; 25 26 memset(eht_cap, 0, sizeof(*eht_cap)); 27 28 if (!eht_cap_ie_elem || 29 !ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif)) 30 return; 31 32 mcs_nss_size = ieee80211_eht_mcs_nss_size(he_cap_ie_elem, 33 &eht_cap_ie_elem->fixed, 34 sdata->vif.type == 35 NL80211_IFTYPE_STATION); 36 37 eht_total_size += mcs_nss_size; 38 39 /* Calculate the PPE thresholds length only if the header is present */ 40 if (eht_cap_ie_elem->fixed.phy_cap_info[5] & 41 IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT) { 42 u16 eht_ppe_hdr; 43 44 if (eht_cap_len < eht_total_size + sizeof(u16)) 45 return; 46 47 eht_ppe_hdr = get_unaligned_le16(eht_cap_ie_elem->optional + mcs_nss_size); 48 eht_ppe_size = 49 ieee80211_eht_ppe_size(eht_ppe_hdr, 50 eht_cap_ie_elem->fixed.phy_cap_info); 51 eht_total_size += eht_ppe_size; 52 53 /* we calculate as if NSS > 8 are valid, but don't handle that */ 54 if (eht_ppe_size > sizeof(eht_cap->eht_ppe_thres)) 55 return; 56 } 57 58 if (eht_cap_len < eht_total_size) 59 return; 60 61 /* Copy the static portion of the EHT capabilities */ 62 memcpy(&eht_cap->eht_cap_elem, pos, sizeof(eht_cap->eht_cap_elem)); 63 pos += sizeof(eht_cap->eht_cap_elem); 64 65 /* Copy MCS/NSS which depends on the peer capabilities */ 66 memset(&eht_cap->eht_mcs_nss_supp, 0, 67 sizeof(eht_cap->eht_mcs_nss_supp)); 68 memcpy(&eht_cap->eht_mcs_nss_supp, pos, mcs_nss_size); 69 70 if (eht_ppe_size) 71 memcpy(eht_cap->eht_ppe_thres, 72 &eht_cap_ie_elem->optional[mcs_nss_size], 73 eht_ppe_size); 74 75 eht_cap->has_eht = true; 76 77 link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta); 78 link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta); 79 80 /* 81 * The MPDU length bits are reserved on all but 2.4 GHz and get set via 82 * VHT (5 GHz) or HE (6 GHz) capabilities. 83 */ 84 if (sband->band != NL80211_BAND_2GHZ) 85 return; 86 87 switch (u8_get_bits(eht_cap->eht_cap_elem.mac_cap_info[0], 88 IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK)) { 89 case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454: 90 link_sta->pub->agg.max_amsdu_len = 91 IEEE80211_MAX_MPDU_LEN_VHT_11454; 92 break; 93 case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991: 94 link_sta->pub->agg.max_amsdu_len = 95 IEEE80211_MAX_MPDU_LEN_VHT_7991; 96 break; 97 case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_3895: 98 default: 99 link_sta->pub->agg.max_amsdu_len = 100 IEEE80211_MAX_MPDU_LEN_VHT_3895; 101 break; 102 } 103 104 ieee80211_sta_recalc_aggregates(&link_sta->sta->sta); 105 } 106 107 static void 108 ieee80211_send_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata, 109 struct ieee80211_mgmt *req, int opt_len) 110 { 111 int len = offsetofend(struct ieee80211_mgmt, u.action.u.eml_omn); 112 struct ieee80211_local *local = sdata->local; 113 struct ieee80211_mgmt *mgmt; 114 struct sk_buff *skb; 115 116 len += opt_len; /* optional len */ 117 skb = dev_alloc_skb(local->tx_headroom + len); 118 if (!skb) 119 return; 120 121 skb_reserve(skb, local->tx_headroom); 122 mgmt = skb_put_zero(skb, len); 123 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 124 IEEE80211_STYPE_ACTION); 125 memcpy(mgmt->da, req->sa, ETH_ALEN); 126 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); 127 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); 128 129 mgmt->u.action.category = WLAN_CATEGORY_PROTECTED_EHT; 130 mgmt->u.action.u.eml_omn.action_code = 131 WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF; 132 mgmt->u.action.u.eml_omn.dialog_token = 133 req->u.action.u.eml_omn.dialog_token; 134 mgmt->u.action.u.eml_omn.control = req->u.action.u.eml_omn.control & 135 ~(IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE | 136 IEEE80211_EML_CTRL_INDEV_COEX_ACT); 137 /* Copy optional fields from the received notification frame */ 138 memcpy(mgmt->u.action.u.eml_omn.variable, 139 req->u.action.u.eml_omn.variable, opt_len); 140 141 ieee80211_tx_skb(sdata, skb); 142 } 143 144 void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata, 145 struct sk_buff *skb) 146 { 147 int len = offsetofend(struct ieee80211_mgmt, u.action.u.eml_omn); 148 enum nl80211_iftype type = ieee80211_vif_type_p2p(&sdata->vif); 149 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 150 const struct wiphy_iftype_ext_capab *ift_ext_capa; 151 struct ieee80211_mgmt *mgmt = (void *)skb->data; 152 struct ieee80211_local *local = sdata->local; 153 u8 control = mgmt->u.action.u.eml_omn.control; 154 u8 *ptr = mgmt->u.action.u.eml_omn.variable; 155 struct ieee80211_eml_params eml_params = { 156 .link_id = status->link_id, 157 }; 158 struct sta_info *sta; 159 int opt_len = 0; 160 161 if (!ieee80211_vif_is_mld(&sdata->vif)) 162 return; 163 164 /* eMLSR and eMLMR can't be enabled at the same time */ 165 if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) && 166 (control & IEEE80211_EML_CTRL_EMLMR_MODE)) 167 return; 168 169 if ((control & IEEE80211_EML_CTRL_EMLMR_MODE) && 170 (control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE)) 171 return; 172 173 ift_ext_capa = cfg80211_get_iftype_ext_capa(local->hw.wiphy, type); 174 if (!ift_ext_capa) 175 return; 176 177 if (!status->link_valid) 178 return; 179 180 sta = sta_info_get_bss(sdata, mgmt->sa); 181 if (!sta) 182 return; 183 184 if (control & IEEE80211_EML_CTRL_EMLSR_MODE) { 185 u8 emlsr_param_update_len; 186 187 if (!(ift_ext_capa->eml_capabilities & 188 IEEE80211_EML_CAP_EMLSR_SUPP)) 189 return; 190 191 opt_len += sizeof(__le16); /* eMLSR link_bitmap */ 192 /* eMLSR param update field is not part of Notfication frame 193 * sent by the AP to client so account it separately. 194 */ 195 emlsr_param_update_len = 196 !!(control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE); 197 198 if (skb->len < len + opt_len + emlsr_param_update_len) 199 return; 200 201 if (control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE) { 202 u8 pad_delay, trans_delay; 203 204 pad_delay = u8_get_bits(ptr[2], 205 IEEE80211_EML_EMLSR_PAD_DELAY); 206 if (pad_delay > 207 IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US) 208 return; 209 210 trans_delay = u8_get_bits(ptr[2], 211 IEEE80211_EML_EMLSR_TRANS_DELAY); 212 if (trans_delay > 213 IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US) 214 return; 215 216 /* Update sta padding and transition delay */ 217 sta->sta.eml_cap = 218 u8_replace_bits(sta->sta.eml_cap, 219 pad_delay, 220 IEEE80211_EML_CAP_EMLSR_PADDING_DELAY); 221 sta->sta.eml_cap = 222 u8_replace_bits(sta->sta.eml_cap, 223 trans_delay, 224 IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY); 225 } 226 } 227 228 if (control & IEEE80211_EML_CTRL_EMLMR_MODE) { 229 u8 mcs_map_size; 230 int i; 231 232 if (!(ift_ext_capa->eml_capabilities & 233 IEEE80211_EML_CAP_EMLMR_SUPPORT)) 234 return; 235 236 opt_len += sizeof(__le16); /* eMLMR link_bitmap */ 237 opt_len++; /* eMLMR mcs_map_count */ 238 if (skb->len < len + opt_len) 239 return; 240 241 eml_params.emlmr_mcs_map_count = ptr[2]; 242 if (eml_params.emlmr_mcs_map_count > 2) 243 return; 244 245 mcs_map_size = 3 * (1 + eml_params.emlmr_mcs_map_count); 246 opt_len += mcs_map_size; 247 if (skb->len < len + opt_len) 248 return; 249 250 for (i = 0; i < mcs_map_size; i++) { 251 u8 rx_mcs, tx_mcs; 252 253 rx_mcs = u8_get_bits(ptr[3 + i], 254 IEEE80211_EML_EMLMR_RX_MCS_MAP); 255 if (rx_mcs > 8) 256 return; 257 258 tx_mcs = u8_get_bits(ptr[3 + i], 259 IEEE80211_EML_EMLMR_TX_MCS_MAP); 260 if (tx_mcs > 8) 261 return; 262 } 263 264 memcpy(eml_params.emlmr_mcs_map_bw, &ptr[3], mcs_map_size); 265 } 266 267 if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) || 268 (control & IEEE80211_EML_CTRL_EMLMR_MODE)) { 269 eml_params.link_bitmap = get_unaligned_le16(ptr); 270 if ((eml_params.link_bitmap & sdata->vif.active_links) != 271 eml_params.link_bitmap) 272 return; 273 } 274 275 if (drv_set_eml_op_mode(sdata, &sta->sta, &eml_params)) 276 return; 277 278 ieee80211_send_eml_op_mode_notif(sdata, mgmt, opt_len); 279 } 280