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 .control = control, 158 }; 159 struct sta_info *sta; 160 int opt_len = 0; 161 162 if (!ieee80211_vif_is_mld(&sdata->vif)) 163 return; 164 165 /* eMLSR and eMLMR can't be enabled at the same time */ 166 if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) && 167 (control & IEEE80211_EML_CTRL_EMLMR_MODE)) 168 return; 169 170 if ((control & IEEE80211_EML_CTRL_EMLMR_MODE) && 171 (control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE)) 172 return; 173 174 ift_ext_capa = cfg80211_get_iftype_ext_capa(local->hw.wiphy, type); 175 if (!ift_ext_capa) 176 return; 177 178 if (!status->link_valid) 179 return; 180 181 sta = sta_info_get_bss(sdata, mgmt->sa); 182 if (!sta) 183 return; 184 185 if (control & IEEE80211_EML_CTRL_EMLSR_MODE) { 186 u8 emlsr_param_update_len; 187 188 if (!(ift_ext_capa->eml_capabilities & 189 IEEE80211_EML_CAP_EMLSR_SUPP)) 190 return; 191 192 opt_len += sizeof(__le16); /* eMLSR link_bitmap */ 193 /* eMLSR param update field is not part of Notfication frame 194 * sent by the AP to client so account it separately. 195 */ 196 emlsr_param_update_len = 197 !!(control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE); 198 199 if (skb->len < len + opt_len + emlsr_param_update_len) 200 return; 201 202 if (control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE) { 203 u8 pad_delay, trans_delay; 204 205 pad_delay = u8_get_bits(ptr[2], 206 IEEE80211_EML_EMLSR_PAD_DELAY); 207 if (pad_delay > 208 IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US) 209 return; 210 211 trans_delay = u8_get_bits(ptr[2], 212 IEEE80211_EML_EMLSR_TRANS_DELAY); 213 if (trans_delay > 214 IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US) 215 return; 216 217 /* Update sta padding and transition delay */ 218 sta->sta.eml_cap = 219 u8_replace_bits(sta->sta.eml_cap, 220 pad_delay, 221 IEEE80211_EML_CAP_EMLSR_PADDING_DELAY); 222 sta->sta.eml_cap = 223 u8_replace_bits(sta->sta.eml_cap, 224 trans_delay, 225 IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY); 226 } 227 } 228 229 if (control & IEEE80211_EML_CTRL_EMLMR_MODE) { 230 u8 mcs_map_size; 231 int i; 232 233 if (!(ift_ext_capa->eml_capabilities & 234 IEEE80211_EML_CAP_EMLMR_SUPPORT)) 235 return; 236 237 opt_len += sizeof(__le16); /* eMLMR link_bitmap */ 238 opt_len++; /* eMLMR mcs_map_count */ 239 if (skb->len < len + opt_len) 240 return; 241 242 eml_params.emlmr_mcs_map_count = ptr[2]; 243 if (eml_params.emlmr_mcs_map_count > 2) 244 return; 245 246 mcs_map_size = 3 * (1 + eml_params.emlmr_mcs_map_count); 247 opt_len += mcs_map_size; 248 if (skb->len < len + opt_len) 249 return; 250 251 for (i = 0; i < mcs_map_size; i++) { 252 u8 rx_mcs, tx_mcs; 253 254 rx_mcs = u8_get_bits(ptr[3 + i], 255 IEEE80211_EML_EMLMR_RX_MCS_MAP); 256 if (rx_mcs > 8) 257 return; 258 259 tx_mcs = u8_get_bits(ptr[3 + i], 260 IEEE80211_EML_EMLMR_TX_MCS_MAP); 261 if (tx_mcs > 8) 262 return; 263 } 264 265 memcpy(eml_params.emlmr_mcs_map_bw, &ptr[3], mcs_map_size); 266 } 267 268 if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) || 269 (control & IEEE80211_EML_CTRL_EMLMR_MODE)) { 270 eml_params.link_bitmap = get_unaligned_le16(ptr); 271 if ((eml_params.link_bitmap & sdata->vif.active_links) != 272 eml_params.link_bitmap) 273 return; 274 } 275 276 if (drv_set_eml_op_mode(sdata, &sta->sta, &eml_params)) 277 return; 278 279 ieee80211_send_eml_op_mode_notif(sdata, mgmt, opt_len); 280 } 281