1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * AP handling 4 * 5 * Partially 6 * Copyright (C) 2026 Intel Corporation 7 */ 8 9 #include "driver-ops.h" 10 #include "ieee80211_i.h" 11 #include "rate.h" 12 13 static void 14 ieee80211_send_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata, 15 struct ieee80211_mgmt *req, int opt_len) 16 { 17 int len = IEEE80211_MIN_ACTION_SIZE(eml_omn); 18 struct ieee80211_local *local = sdata->local; 19 struct ieee80211_mgmt *mgmt; 20 struct sk_buff *skb; 21 22 len += opt_len; /* optional len */ 23 skb = dev_alloc_skb(local->tx_headroom + len); 24 if (!skb) 25 return; 26 27 skb_reserve(skb, local->tx_headroom); 28 mgmt = skb_put_zero(skb, len); 29 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 30 IEEE80211_STYPE_ACTION); 31 memcpy(mgmt->da, req->sa, ETH_ALEN); 32 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); 33 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); 34 35 mgmt->u.action.category = WLAN_CATEGORY_PROTECTED_EHT; 36 mgmt->u.action.action_code = 37 WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF; 38 mgmt->u.action.eml_omn.dialog_token = 39 req->u.action.eml_omn.dialog_token; 40 mgmt->u.action.eml_omn.control = req->u.action.eml_omn.control & 41 ~(IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE | 42 IEEE80211_EML_CTRL_INDEV_COEX_ACT); 43 /* Copy optional fields from the received notification frame */ 44 memcpy(mgmt->u.action.eml_omn.variable, 45 req->u.action.eml_omn.variable, opt_len); 46 47 ieee80211_tx_skb(sdata, skb); 48 } 49 50 static void 51 ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata, 52 struct sk_buff *skb) 53 { 54 int len = IEEE80211_MIN_ACTION_SIZE(eml_omn); 55 enum nl80211_iftype type = ieee80211_vif_type_p2p(&sdata->vif); 56 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 57 const struct wiphy_iftype_ext_capab *ift_ext_capa; 58 struct ieee80211_mgmt *mgmt = (void *)skb->data; 59 struct ieee80211_local *local = sdata->local; 60 u8 control = mgmt->u.action.eml_omn.control; 61 u8 *ptr = mgmt->u.action.eml_omn.variable; 62 struct ieee80211_eml_params eml_params = { 63 .link_id = status->link_id, 64 .control = control, 65 }; 66 struct sta_info *sta; 67 int opt_len = 0; 68 69 if (!ieee80211_vif_is_mld(&sdata->vif)) 70 return; 71 72 /* eMLSR and eMLMR can't be enabled at the same time */ 73 if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) && 74 (control & IEEE80211_EML_CTRL_EMLMR_MODE)) 75 return; 76 77 if ((control & IEEE80211_EML_CTRL_EMLMR_MODE) && 78 (control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE)) 79 return; 80 81 ift_ext_capa = cfg80211_get_iftype_ext_capa(local->hw.wiphy, type); 82 if (!ift_ext_capa) 83 return; 84 85 if (!status->link_valid) 86 return; 87 88 sta = sta_info_get_bss(sdata, mgmt->sa); 89 if (!sta) 90 return; 91 92 if (control & IEEE80211_EML_CTRL_EMLSR_MODE) { 93 u8 emlsr_param_update_len; 94 95 if (!(ift_ext_capa->eml_capabilities & 96 IEEE80211_EML_CAP_EMLSR_SUPP)) 97 return; 98 99 opt_len += sizeof(__le16); /* eMLSR link_bitmap */ 100 /* 101 * eMLSR param update field is not part of Notification frame 102 * sent by the AP to client so account it separately. 103 */ 104 emlsr_param_update_len = 105 !!(control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE); 106 107 if (skb->len < len + opt_len + emlsr_param_update_len) 108 return; 109 110 if (control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE) { 111 u8 pad_delay, trans_delay; 112 113 pad_delay = u8_get_bits(ptr[2], 114 IEEE80211_EML_EMLSR_PAD_DELAY); 115 if (pad_delay > 116 IEEE80211_EML_CAP_EML_PADDING_DELAY_256US) 117 return; 118 119 trans_delay = u8_get_bits(ptr[2], 120 IEEE80211_EML_EMLSR_TRANS_DELAY); 121 if (trans_delay > 122 IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US) 123 return; 124 125 /* Update sta padding and transition delay */ 126 sta->sta.eml_cap = 127 u8_replace_bits(sta->sta.eml_cap, 128 pad_delay, 129 IEEE80211_EML_CAP_EML_PADDING_DELAY); 130 sta->sta.eml_cap = 131 u8_replace_bits(sta->sta.eml_cap, 132 trans_delay, 133 IEEE80211_EML_CAP_EML_TRANSITION_DELAY); 134 } 135 } 136 137 if (control & IEEE80211_EML_CTRL_EMLMR_MODE) { 138 u8 mcs_map_size; 139 int i; 140 141 if (!(ift_ext_capa->eml_capabilities & 142 IEEE80211_EML_CAP_EMLMR_SUPPORT)) 143 return; 144 145 opt_len += sizeof(__le16); /* eMLMR link_bitmap */ 146 opt_len++; /* eMLMR mcs_map_count */ 147 if (skb->len < len + opt_len) 148 return; 149 150 eml_params.emlmr_mcs_map_count = ptr[2]; 151 if (eml_params.emlmr_mcs_map_count > 2) 152 return; 153 154 mcs_map_size = 3 * (1 + eml_params.emlmr_mcs_map_count); 155 opt_len += mcs_map_size; 156 if (skb->len < len + opt_len) 157 return; 158 159 for (i = 0; i < mcs_map_size; i++) { 160 u8 rx_mcs, tx_mcs; 161 162 rx_mcs = u8_get_bits(ptr[3 + i], 163 IEEE80211_EML_EMLMR_RX_MCS_MAP); 164 if (rx_mcs > 8) 165 return; 166 167 tx_mcs = u8_get_bits(ptr[3 + i], 168 IEEE80211_EML_EMLMR_TX_MCS_MAP); 169 if (tx_mcs > 8) 170 return; 171 } 172 173 memcpy(eml_params.emlmr_mcs_map_bw, &ptr[3], mcs_map_size); 174 } 175 176 if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) || 177 (control & IEEE80211_EML_CTRL_EMLMR_MODE)) { 178 eml_params.link_bitmap = get_unaligned_le16(ptr); 179 if ((eml_params.link_bitmap & sdata->vif.active_links) != 180 eml_params.link_bitmap) 181 return; 182 } 183 184 if (drv_set_eml_op_mode(sdata, &sta->sta, &eml_params)) 185 return; 186 187 ieee80211_send_eml_op_mode_notif(sdata, mgmt, opt_len); 188 } 189 190 static void 191 ieee80211_rx_uhr_link_reconfig_req(struct ieee80211_sub_if_data *sdata, 192 struct sk_buff *skb) 193 { 194 struct ieee80211_mgmt *mgmt = (void *)skb->data; 195 const struct element *sub; 196 struct sta_info *sta; 197 198 /* 199 * rx.c only accepts IEEE80211_UHR_LINK_RECONFIG_REQUEST_OMP_REQUEST 200 * which is valid, so no need to check the frame type/format/etc. 201 */ 202 203 sta = sta_info_get_bss(sdata, mgmt->sa); 204 if (!sta) 205 return; 206 207 struct ieee802_11_elems *elems __free(kfree) = 208 ieee802_11_parse_elems(mgmt->u.action.uhr_link_reconf_req.variable, 209 skb->len - IEEE80211_MIN_ACTION_SIZE(uhr_link_reconf_req), 210 IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION, 211 NULL); 212 /* STA will assume we processed it, not good */ 213 if (!elems) 214 return; 215 216 if (!elems->ml_reconf) 217 return; 218 219 for_each_mle_subelement(sub, (u8 *)elems->ml_reconf, 220 elems->ml_reconf_len) { 221 const struct ieee80211_mle_per_sta_profile *prof = 222 (const void *)sub->data; 223 struct ieee80211_chanctx_conf *chanctx_conf; 224 struct ieee80211_chanctx *chanctx; 225 struct ieee80211_link_data *link; 226 struct link_sta_info *link_sta; 227 const struct element *chg; 228 u16 control; 229 u8 link_id; 230 231 if (sub->id != IEEE80211_MLE_SUBELEM_PER_STA_PROFILE) 232 continue; 233 234 if (!ieee80211_mle_reconf_sta_prof_size_ok(sub->data, 235 sub->datalen)) 236 return; 237 238 control = le16_to_cpu(prof->control); 239 link_id = control & IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID; 240 241 if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS) 242 return; 243 244 link = sdata_dereference(sdata->link[link_id], sdata); 245 if (!link) 246 continue; 247 248 chanctx_conf = sdata_dereference(link->conf->chanctx_conf, 249 sdata); 250 if (!chanctx_conf) 251 continue; 252 chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, 253 conf); 254 255 link_sta = sdata_dereference(sta->link[link_id], sdata); 256 if (!link_sta) 257 continue; 258 259 /* do we need to handle any other bits? */ 260 if (control & ~(IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID | 261 IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE)) 262 continue; 263 264 if (u16_get_bits(control, IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE) != 265 IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE_UHR_OMP_UPD) 266 continue; 267 268 for_each_element_extid(chg, WLAN_EID_EXT_UHR_MODE_CHG, 269 prof->variable + prof->sta_info_len - 1, 270 sub->datalen - sizeof(*prof) - 271 prof->sta_info_len + 1) { 272 const struct ieee80211_uhr_mode_change_tuple *tuple; 273 274 for_each_uhr_mode_change_tuple(chg->data + 1, 275 chg->datalen - 1, 276 tuple) { 277 u8 id = le16_get_bits(tuple->control, 278 IEEE80211_UHR_MODE_CHANGE_CONTROL_MODE_ID); 279 bool enabled = le16_get_bits(tuple->control, 280 IEEE80211_UHR_MODE_CHANGE_CONTROL_MODE_ENABLE); 281 282 /* only handle DBE (for now?) */ 283 if (id != IEEE80211_UHR_MODE_CHANGE_MODE_ID_DBE) 284 continue; 285 286 link_sta->uhr_dbe_enabled = enabled; 287 /* also recalculates and updates per-STA bw */ 288 ieee80211_recalc_chanctx_min_def(sdata->local, 289 chanctx); 290 } 291 } 292 } 293 294 /* TODO: send a response */ 295 } 296 297 void ieee80211_ap_rx_queued_frame(struct ieee80211_sub_if_data *sdata, 298 struct sk_buff *skb) 299 { 300 struct ieee80211_mgmt *mgmt = (void *)skb->data; 301 302 /* rx.c cannot queue any non-action frames to AP interfaces */ 303 if (WARN_ON(!ieee80211_is_action(mgmt->frame_control))) 304 return; 305 306 switch (mgmt->u.action.category) { 307 case WLAN_CATEGORY_PROTECTED_EHT: 308 switch (mgmt->u.action.action_code) { 309 case WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF: 310 ieee80211_rx_eml_op_mode_notif(sdata, skb); 311 break; 312 } 313 break; 314 case WLAN_CATEGORY_PROTECTED_UHR: 315 switch (mgmt->u.action.action_code) { 316 case IEEE80211_PROTECTED_UHR_ACTION_LINK_RECONFIG_REQUEST: 317 ieee80211_rx_uhr_link_reconfig_req(sdata, skb); 318 break; 319 } 320 break; 321 } 322 } 323 324 void ieee80211_uhr_disable_dbe_all_stas(struct ieee80211_link_data *link) 325 { 326 struct ieee80211_sub_if_data *sdata = link->sdata; 327 struct ieee80211_local *local = sdata->local; 328 struct ieee80211_chanctx_conf *chanctx_conf; 329 struct ieee80211_chanctx *chanctx; 330 int link_id = link->link_id; 331 struct sta_info *sta; 332 333 chanctx_conf = sdata_dereference(link->conf->chanctx_conf, sdata); 334 if (!chanctx_conf) 335 return; 336 chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); 337 338 list_for_each_entry(sta, &local->sta_list, list) { 339 struct link_sta_info *link_sta; 340 341 if (sta->sdata->bss != sdata->bss) 342 continue; 343 344 link_sta = sdata_dereference(sta->link[link_id], sdata); 345 if (!link_sta) 346 continue; 347 348 link_sta->uhr_dbe_enabled = false; 349 } 350 351 /* also recalculates and updates per-STA bw */ 352 ieee80211_recalc_chanctx_min_def(local, chanctx); 353 } 354