149e62ec6SJohannes Berg // SPDX-License-Identifier: GPL-2.0-only 249e62ec6SJohannes Berg /* 349e62ec6SJohannes Berg * AP handling 449e62ec6SJohannes Berg * 549e62ec6SJohannes Berg * Partially 649e62ec6SJohannes Berg * Copyright (C) 2026 Intel Corporation 749e62ec6SJohannes Berg */ 849e62ec6SJohannes Berg 949e62ec6SJohannes Berg #include "driver-ops.h" 1049e62ec6SJohannes Berg #include "ieee80211_i.h" 11*14b1a855SJohannes Berg #include "rate.h" 1249e62ec6SJohannes Berg 1349e62ec6SJohannes Berg static void 1449e62ec6SJohannes Berg ieee80211_send_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata, 1549e62ec6SJohannes Berg struct ieee80211_mgmt *req, int opt_len) 1649e62ec6SJohannes Berg { 1749e62ec6SJohannes Berg int len = IEEE80211_MIN_ACTION_SIZE(eml_omn); 1849e62ec6SJohannes Berg struct ieee80211_local *local = sdata->local; 1949e62ec6SJohannes Berg struct ieee80211_mgmt *mgmt; 2049e62ec6SJohannes Berg struct sk_buff *skb; 2149e62ec6SJohannes Berg 2249e62ec6SJohannes Berg len += opt_len; /* optional len */ 2349e62ec6SJohannes Berg skb = dev_alloc_skb(local->tx_headroom + len); 2449e62ec6SJohannes Berg if (!skb) 2549e62ec6SJohannes Berg return; 2649e62ec6SJohannes Berg 2749e62ec6SJohannes Berg skb_reserve(skb, local->tx_headroom); 2849e62ec6SJohannes Berg mgmt = skb_put_zero(skb, len); 2949e62ec6SJohannes Berg mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 3049e62ec6SJohannes Berg IEEE80211_STYPE_ACTION); 3149e62ec6SJohannes Berg memcpy(mgmt->da, req->sa, ETH_ALEN); 3249e62ec6SJohannes Berg memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); 3349e62ec6SJohannes Berg memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); 3449e62ec6SJohannes Berg 3549e62ec6SJohannes Berg mgmt->u.action.category = WLAN_CATEGORY_PROTECTED_EHT; 3649e62ec6SJohannes Berg mgmt->u.action.action_code = 3749e62ec6SJohannes Berg WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF; 3849e62ec6SJohannes Berg mgmt->u.action.eml_omn.dialog_token = 3949e62ec6SJohannes Berg req->u.action.eml_omn.dialog_token; 4049e62ec6SJohannes Berg mgmt->u.action.eml_omn.control = req->u.action.eml_omn.control & 4149e62ec6SJohannes Berg ~(IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE | 4249e62ec6SJohannes Berg IEEE80211_EML_CTRL_INDEV_COEX_ACT); 4349e62ec6SJohannes Berg /* Copy optional fields from the received notification frame */ 4449e62ec6SJohannes Berg memcpy(mgmt->u.action.eml_omn.variable, 4549e62ec6SJohannes Berg req->u.action.eml_omn.variable, opt_len); 4649e62ec6SJohannes Berg 4749e62ec6SJohannes Berg ieee80211_tx_skb(sdata, skb); 4849e62ec6SJohannes Berg } 4949e62ec6SJohannes Berg 5049e62ec6SJohannes Berg static void 5149e62ec6SJohannes Berg ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata, 5249e62ec6SJohannes Berg struct sk_buff *skb) 5349e62ec6SJohannes Berg { 5449e62ec6SJohannes Berg int len = IEEE80211_MIN_ACTION_SIZE(eml_omn); 5549e62ec6SJohannes Berg enum nl80211_iftype type = ieee80211_vif_type_p2p(&sdata->vif); 5649e62ec6SJohannes Berg struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 5749e62ec6SJohannes Berg const struct wiphy_iftype_ext_capab *ift_ext_capa; 5849e62ec6SJohannes Berg struct ieee80211_mgmt *mgmt = (void *)skb->data; 5949e62ec6SJohannes Berg struct ieee80211_local *local = sdata->local; 6049e62ec6SJohannes Berg u8 control = mgmt->u.action.eml_omn.control; 6149e62ec6SJohannes Berg u8 *ptr = mgmt->u.action.eml_omn.variable; 6249e62ec6SJohannes Berg struct ieee80211_eml_params eml_params = { 6349e62ec6SJohannes Berg .link_id = status->link_id, 6449e62ec6SJohannes Berg .control = control, 6549e62ec6SJohannes Berg }; 6649e62ec6SJohannes Berg struct sta_info *sta; 6749e62ec6SJohannes Berg int opt_len = 0; 6849e62ec6SJohannes Berg 6949e62ec6SJohannes Berg if (!ieee80211_vif_is_mld(&sdata->vif)) 7049e62ec6SJohannes Berg return; 7149e62ec6SJohannes Berg 7249e62ec6SJohannes Berg /* eMLSR and eMLMR can't be enabled at the same time */ 7349e62ec6SJohannes Berg if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) && 7449e62ec6SJohannes Berg (control & IEEE80211_EML_CTRL_EMLMR_MODE)) 7549e62ec6SJohannes Berg return; 7649e62ec6SJohannes Berg 7749e62ec6SJohannes Berg if ((control & IEEE80211_EML_CTRL_EMLMR_MODE) && 7849e62ec6SJohannes Berg (control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE)) 7949e62ec6SJohannes Berg return; 8049e62ec6SJohannes Berg 8149e62ec6SJohannes Berg ift_ext_capa = cfg80211_get_iftype_ext_capa(local->hw.wiphy, type); 8249e62ec6SJohannes Berg if (!ift_ext_capa) 8349e62ec6SJohannes Berg return; 8449e62ec6SJohannes Berg 8549e62ec6SJohannes Berg if (!status->link_valid) 8649e62ec6SJohannes Berg return; 8749e62ec6SJohannes Berg 8849e62ec6SJohannes Berg sta = sta_info_get_bss(sdata, mgmt->sa); 8949e62ec6SJohannes Berg if (!sta) 9049e62ec6SJohannes Berg return; 9149e62ec6SJohannes Berg 9249e62ec6SJohannes Berg if (control & IEEE80211_EML_CTRL_EMLSR_MODE) { 9349e62ec6SJohannes Berg u8 emlsr_param_update_len; 9449e62ec6SJohannes Berg 9549e62ec6SJohannes Berg if (!(ift_ext_capa->eml_capabilities & 9649e62ec6SJohannes Berg IEEE80211_EML_CAP_EMLSR_SUPP)) 9749e62ec6SJohannes Berg return; 9849e62ec6SJohannes Berg 9949e62ec6SJohannes Berg opt_len += sizeof(__le16); /* eMLSR link_bitmap */ 10049e62ec6SJohannes Berg /* 10149e62ec6SJohannes Berg * eMLSR param update field is not part of Notification frame 10249e62ec6SJohannes Berg * sent by the AP to client so account it separately. 10349e62ec6SJohannes Berg */ 10449e62ec6SJohannes Berg emlsr_param_update_len = 10549e62ec6SJohannes Berg !!(control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE); 10649e62ec6SJohannes Berg 10749e62ec6SJohannes Berg if (skb->len < len + opt_len + emlsr_param_update_len) 10849e62ec6SJohannes Berg return; 10949e62ec6SJohannes Berg 11049e62ec6SJohannes Berg if (control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE) { 11149e62ec6SJohannes Berg u8 pad_delay, trans_delay; 11249e62ec6SJohannes Berg 11349e62ec6SJohannes Berg pad_delay = u8_get_bits(ptr[2], 11449e62ec6SJohannes Berg IEEE80211_EML_EMLSR_PAD_DELAY); 11549e62ec6SJohannes Berg if (pad_delay > 11649e62ec6SJohannes Berg IEEE80211_EML_CAP_EML_PADDING_DELAY_256US) 11749e62ec6SJohannes Berg return; 11849e62ec6SJohannes Berg 11949e62ec6SJohannes Berg trans_delay = u8_get_bits(ptr[2], 12049e62ec6SJohannes Berg IEEE80211_EML_EMLSR_TRANS_DELAY); 12149e62ec6SJohannes Berg if (trans_delay > 12249e62ec6SJohannes Berg IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US) 12349e62ec6SJohannes Berg return; 12449e62ec6SJohannes Berg 12549e62ec6SJohannes Berg /* Update sta padding and transition delay */ 12649e62ec6SJohannes Berg sta->sta.eml_cap = 12749e62ec6SJohannes Berg u8_replace_bits(sta->sta.eml_cap, 12849e62ec6SJohannes Berg pad_delay, 12949e62ec6SJohannes Berg IEEE80211_EML_CAP_EML_PADDING_DELAY); 13049e62ec6SJohannes Berg sta->sta.eml_cap = 13149e62ec6SJohannes Berg u8_replace_bits(sta->sta.eml_cap, 13249e62ec6SJohannes Berg trans_delay, 13349e62ec6SJohannes Berg IEEE80211_EML_CAP_EML_TRANSITION_DELAY); 13449e62ec6SJohannes Berg } 13549e62ec6SJohannes Berg } 13649e62ec6SJohannes Berg 13749e62ec6SJohannes Berg if (control & IEEE80211_EML_CTRL_EMLMR_MODE) { 13849e62ec6SJohannes Berg u8 mcs_map_size; 13949e62ec6SJohannes Berg int i; 14049e62ec6SJohannes Berg 14149e62ec6SJohannes Berg if (!(ift_ext_capa->eml_capabilities & 14249e62ec6SJohannes Berg IEEE80211_EML_CAP_EMLMR_SUPPORT)) 14349e62ec6SJohannes Berg return; 14449e62ec6SJohannes Berg 14549e62ec6SJohannes Berg opt_len += sizeof(__le16); /* eMLMR link_bitmap */ 14649e62ec6SJohannes Berg opt_len++; /* eMLMR mcs_map_count */ 14749e62ec6SJohannes Berg if (skb->len < len + opt_len) 14849e62ec6SJohannes Berg return; 14949e62ec6SJohannes Berg 15049e62ec6SJohannes Berg eml_params.emlmr_mcs_map_count = ptr[2]; 15149e62ec6SJohannes Berg if (eml_params.emlmr_mcs_map_count > 2) 15249e62ec6SJohannes Berg return; 15349e62ec6SJohannes Berg 15449e62ec6SJohannes Berg mcs_map_size = 3 * (1 + eml_params.emlmr_mcs_map_count); 15549e62ec6SJohannes Berg opt_len += mcs_map_size; 15649e62ec6SJohannes Berg if (skb->len < len + opt_len) 15749e62ec6SJohannes Berg return; 15849e62ec6SJohannes Berg 15949e62ec6SJohannes Berg for (i = 0; i < mcs_map_size; i++) { 16049e62ec6SJohannes Berg u8 rx_mcs, tx_mcs; 16149e62ec6SJohannes Berg 16249e62ec6SJohannes Berg rx_mcs = u8_get_bits(ptr[3 + i], 16349e62ec6SJohannes Berg IEEE80211_EML_EMLMR_RX_MCS_MAP); 16449e62ec6SJohannes Berg if (rx_mcs > 8) 16549e62ec6SJohannes Berg return; 16649e62ec6SJohannes Berg 16749e62ec6SJohannes Berg tx_mcs = u8_get_bits(ptr[3 + i], 16849e62ec6SJohannes Berg IEEE80211_EML_EMLMR_TX_MCS_MAP); 16949e62ec6SJohannes Berg if (tx_mcs > 8) 17049e62ec6SJohannes Berg return; 17149e62ec6SJohannes Berg } 17249e62ec6SJohannes Berg 17349e62ec6SJohannes Berg memcpy(eml_params.emlmr_mcs_map_bw, &ptr[3], mcs_map_size); 17449e62ec6SJohannes Berg } 17549e62ec6SJohannes Berg 17649e62ec6SJohannes Berg if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) || 17749e62ec6SJohannes Berg (control & IEEE80211_EML_CTRL_EMLMR_MODE)) { 17849e62ec6SJohannes Berg eml_params.link_bitmap = get_unaligned_le16(ptr); 17949e62ec6SJohannes Berg if ((eml_params.link_bitmap & sdata->vif.active_links) != 18049e62ec6SJohannes Berg eml_params.link_bitmap) 18149e62ec6SJohannes Berg return; 18249e62ec6SJohannes Berg } 18349e62ec6SJohannes Berg 18449e62ec6SJohannes Berg if (drv_set_eml_op_mode(sdata, &sta->sta, &eml_params)) 18549e62ec6SJohannes Berg return; 18649e62ec6SJohannes Berg 18749e62ec6SJohannes Berg ieee80211_send_eml_op_mode_notif(sdata, mgmt, opt_len); 18849e62ec6SJohannes Berg } 18949e62ec6SJohannes Berg 190*14b1a855SJohannes Berg static void 191*14b1a855SJohannes Berg ieee80211_rx_uhr_link_reconfig_req(struct ieee80211_sub_if_data *sdata, 192*14b1a855SJohannes Berg struct sk_buff *skb) 193*14b1a855SJohannes Berg { 194*14b1a855SJohannes Berg struct ieee80211_mgmt *mgmt = (void *)skb->data; 195*14b1a855SJohannes Berg const struct element *sub; 196*14b1a855SJohannes Berg struct sta_info *sta; 197*14b1a855SJohannes Berg 198*14b1a855SJohannes Berg /* 199*14b1a855SJohannes Berg * rx.c only accepts IEEE80211_UHR_LINK_RECONFIG_REQUEST_OMP_REQUEST 200*14b1a855SJohannes Berg * which is valid, so no need to check the frame type/format/etc. 201*14b1a855SJohannes Berg */ 202*14b1a855SJohannes Berg 203*14b1a855SJohannes Berg sta = sta_info_get_bss(sdata, mgmt->sa); 204*14b1a855SJohannes Berg if (!sta) 205*14b1a855SJohannes Berg return; 206*14b1a855SJohannes Berg 207*14b1a855SJohannes Berg struct ieee802_11_elems *elems __free(kfree) = 208*14b1a855SJohannes Berg ieee802_11_parse_elems(mgmt->u.action.uhr_link_reconf_req.variable, 209*14b1a855SJohannes Berg skb->len - IEEE80211_MIN_ACTION_SIZE(uhr_link_reconf_req), 210*14b1a855SJohannes Berg IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION, 211*14b1a855SJohannes Berg NULL); 212*14b1a855SJohannes Berg /* STA will assume we processed it, not good */ 213*14b1a855SJohannes Berg if (!elems) 214*14b1a855SJohannes Berg return; 215*14b1a855SJohannes Berg 216*14b1a855SJohannes Berg if (!elems->ml_reconf) 217*14b1a855SJohannes Berg return; 218*14b1a855SJohannes Berg 219*14b1a855SJohannes Berg for_each_mle_subelement(sub, (u8 *)elems->ml_reconf, 220*14b1a855SJohannes Berg elems->ml_reconf_len) { 221*14b1a855SJohannes Berg const struct ieee80211_mle_per_sta_profile *prof = 222*14b1a855SJohannes Berg (const void *)sub->data; 223*14b1a855SJohannes Berg struct ieee80211_chanctx_conf *chanctx_conf; 224*14b1a855SJohannes Berg struct ieee80211_chanctx *chanctx; 225*14b1a855SJohannes Berg struct ieee80211_link_data *link; 226*14b1a855SJohannes Berg struct link_sta_info *link_sta; 227*14b1a855SJohannes Berg const struct element *chg; 228*14b1a855SJohannes Berg u16 control; 229*14b1a855SJohannes Berg u8 link_id; 230*14b1a855SJohannes Berg 231*14b1a855SJohannes Berg if (sub->id != IEEE80211_MLE_SUBELEM_PER_STA_PROFILE) 232*14b1a855SJohannes Berg continue; 233*14b1a855SJohannes Berg 234*14b1a855SJohannes Berg if (!ieee80211_mle_reconf_sta_prof_size_ok(sub->data, 235*14b1a855SJohannes Berg sub->datalen)) 236*14b1a855SJohannes Berg return; 237*14b1a855SJohannes Berg 238*14b1a855SJohannes Berg control = le16_to_cpu(prof->control); 239*14b1a855SJohannes Berg link_id = control & IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID; 240*14b1a855SJohannes Berg 241*14b1a855SJohannes Berg if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS) 242*14b1a855SJohannes Berg return; 243*14b1a855SJohannes Berg 244*14b1a855SJohannes Berg link = sdata_dereference(sdata->link[link_id], sdata); 245*14b1a855SJohannes Berg if (!link) 246*14b1a855SJohannes Berg continue; 247*14b1a855SJohannes Berg 248*14b1a855SJohannes Berg chanctx_conf = sdata_dereference(link->conf->chanctx_conf, 249*14b1a855SJohannes Berg sdata); 250*14b1a855SJohannes Berg if (!chanctx_conf) 251*14b1a855SJohannes Berg continue; 252*14b1a855SJohannes Berg chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, 253*14b1a855SJohannes Berg conf); 254*14b1a855SJohannes Berg 255*14b1a855SJohannes Berg link_sta = sdata_dereference(sta->link[link_id], sdata); 256*14b1a855SJohannes Berg if (!link_sta) 257*14b1a855SJohannes Berg continue; 258*14b1a855SJohannes Berg 259*14b1a855SJohannes Berg /* do we need to handle any other bits? */ 260*14b1a855SJohannes Berg if (control & ~(IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID | 261*14b1a855SJohannes Berg IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE)) 262*14b1a855SJohannes Berg continue; 263*14b1a855SJohannes Berg 264*14b1a855SJohannes Berg if (u16_get_bits(control, IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE) != 265*14b1a855SJohannes Berg IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_TYPE_UHR_OMP_UPD) 266*14b1a855SJohannes Berg continue; 267*14b1a855SJohannes Berg 268*14b1a855SJohannes Berg for_each_element_extid(chg, WLAN_EID_EXT_UHR_MODE_CHG, 269*14b1a855SJohannes Berg prof->variable + prof->sta_info_len - 1, 270*14b1a855SJohannes Berg sub->datalen - sizeof(*prof) - 271*14b1a855SJohannes Berg prof->sta_info_len + 1) { 272*14b1a855SJohannes Berg const struct ieee80211_uhr_mode_change_tuple *tuple; 273*14b1a855SJohannes Berg 274*14b1a855SJohannes Berg for_each_uhr_mode_change_tuple(chg->data + 1, 275*14b1a855SJohannes Berg chg->datalen - 1, 276*14b1a855SJohannes Berg tuple) { 277*14b1a855SJohannes Berg u8 id = le16_get_bits(tuple->control, 278*14b1a855SJohannes Berg IEEE80211_UHR_MODE_CHANGE_CONTROL_MODE_ID); 279*14b1a855SJohannes Berg bool enabled = le16_get_bits(tuple->control, 280*14b1a855SJohannes Berg IEEE80211_UHR_MODE_CHANGE_CONTROL_MODE_ENABLE); 281*14b1a855SJohannes Berg 282*14b1a855SJohannes Berg /* only handle DBE (for now?) */ 283*14b1a855SJohannes Berg if (id != IEEE80211_UHR_MODE_CHANGE_MODE_ID_DBE) 284*14b1a855SJohannes Berg continue; 285*14b1a855SJohannes Berg 286*14b1a855SJohannes Berg link_sta->uhr_dbe_enabled = enabled; 287*14b1a855SJohannes Berg /* also recalculates and updates per-STA bw */ 288*14b1a855SJohannes Berg ieee80211_recalc_chanctx_min_def(sdata->local, 289*14b1a855SJohannes Berg chanctx); 290*14b1a855SJohannes Berg } 291*14b1a855SJohannes Berg } 292*14b1a855SJohannes Berg } 293*14b1a855SJohannes Berg 294*14b1a855SJohannes Berg /* TODO: send a response */ 295*14b1a855SJohannes Berg } 296*14b1a855SJohannes Berg 29749e62ec6SJohannes Berg void ieee80211_ap_rx_queued_frame(struct ieee80211_sub_if_data *sdata, 29849e62ec6SJohannes Berg struct sk_buff *skb) 29949e62ec6SJohannes Berg { 30049e62ec6SJohannes Berg struct ieee80211_mgmt *mgmt = (void *)skb->data; 30149e62ec6SJohannes Berg 30249e62ec6SJohannes Berg /* rx.c cannot queue any non-action frames to AP interfaces */ 30349e62ec6SJohannes Berg if (WARN_ON(!ieee80211_is_action(mgmt->frame_control))) 30449e62ec6SJohannes Berg return; 30549e62ec6SJohannes Berg 30649e62ec6SJohannes Berg switch (mgmt->u.action.category) { 30749e62ec6SJohannes Berg case WLAN_CATEGORY_PROTECTED_EHT: 30849e62ec6SJohannes Berg switch (mgmt->u.action.action_code) { 30949e62ec6SJohannes Berg case WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF: 31049e62ec6SJohannes Berg ieee80211_rx_eml_op_mode_notif(sdata, skb); 31149e62ec6SJohannes Berg break; 31249e62ec6SJohannes Berg } 31349e62ec6SJohannes Berg break; 314*14b1a855SJohannes Berg case WLAN_CATEGORY_PROTECTED_UHR: 315*14b1a855SJohannes Berg switch (mgmt->u.action.action_code) { 316*14b1a855SJohannes Berg case IEEE80211_PROTECTED_UHR_ACTION_LINK_RECONFIG_REQUEST: 317*14b1a855SJohannes Berg ieee80211_rx_uhr_link_reconfig_req(sdata, skb); 318*14b1a855SJohannes Berg break; 31949e62ec6SJohannes Berg } 320*14b1a855SJohannes Berg break; 321*14b1a855SJohannes Berg } 322*14b1a855SJohannes Berg } 323*14b1a855SJohannes Berg 324*14b1a855SJohannes Berg void ieee80211_uhr_disable_dbe_all_stas(struct ieee80211_link_data *link) 325*14b1a855SJohannes Berg { 326*14b1a855SJohannes Berg struct ieee80211_sub_if_data *sdata = link->sdata; 327*14b1a855SJohannes Berg struct ieee80211_local *local = sdata->local; 328*14b1a855SJohannes Berg struct ieee80211_chanctx_conf *chanctx_conf; 329*14b1a855SJohannes Berg struct ieee80211_chanctx *chanctx; 330*14b1a855SJohannes Berg int link_id = link->link_id; 331*14b1a855SJohannes Berg struct sta_info *sta; 332*14b1a855SJohannes Berg 333*14b1a855SJohannes Berg chanctx_conf = sdata_dereference(link->conf->chanctx_conf, sdata); 334*14b1a855SJohannes Berg if (!chanctx_conf) 335*14b1a855SJohannes Berg return; 336*14b1a855SJohannes Berg chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); 337*14b1a855SJohannes Berg 338*14b1a855SJohannes Berg list_for_each_entry(sta, &local->sta_list, list) { 339*14b1a855SJohannes Berg struct link_sta_info *link_sta; 340*14b1a855SJohannes Berg 341*14b1a855SJohannes Berg if (sta->sdata->bss != sdata->bss) 342*14b1a855SJohannes Berg continue; 343*14b1a855SJohannes Berg 344*14b1a855SJohannes Berg link_sta = sdata_dereference(sta->link[link_id], sdata); 345*14b1a855SJohannes Berg if (!link_sta) 346*14b1a855SJohannes Berg continue; 347*14b1a855SJohannes Berg 348*14b1a855SJohannes Berg link_sta->uhr_dbe_enabled = false; 349*14b1a855SJohannes Berg } 350*14b1a855SJohannes Berg 351*14b1a855SJohannes Berg /* also recalculates and updates per-STA bw */ 352*14b1a855SJohannes Berg ieee80211_recalc_chanctx_min_def(local, chanctx); 35349e62ec6SJohannes Berg } 354