developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 1 | From d46df816cadde59bde528c08db281923874152cc Mon Sep 17 00:00:00 2001 |
| 2 | From: StanleyYP Wang <StanleyYP.Wang@mediatek.com> |
| 3 | Date: Tue, 23 Apr 2024 16:03:19 +0800 |
| 4 | Subject: [PATCH 085/126] mtk: hostapd: add critical update support |
| 5 | |
| 6 | Add critical update support |
| 7 | modification: wmm configuration |
| 8 | inclusion: channel switch |
| 9 | (affiliated link's per-STA profile CSA/eCSA countdown & |
| 10 | channel switch wrapper is included) |
| 11 | Note that max channel switch time IE is not implemented |
| 12 | in hostapd yet. |
| 13 | |
| 14 | 1.Add max channel switch time IE |
| 15 | Note that fw will find the MCST IE on its own, |
| 16 | so there is no need to send the offset of the MCST IE to the kernel. |
| 17 | The MCST's value is currently hardcoded to 500 TUs, since the WFA test plan |
| 18 | restricts it to not exceeding 500 TUs (APUT 4.22.1). |
| 19 | 2. Add critical update support for radar triggered channel switch |
| 20 | |
| 21 | According to the test plan of APUT 4.44, the CSA after beacon should also |
| 22 | include the CU flag and increase BPCC due to operation IE modification. |
| 23 | Additionally, avoid setting beacons in hostapd_event_ch_switch after CSA |
| 24 | is finished since it would conflict with the CSA after beacon. |
| 25 | |
| 26 | Signed-off-by: Shayne Chen <shayne.chen@mediatek.com> |
| 27 | Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com> |
| 28 | --- |
| 29 | hostapd/ctrl_iface.c | 88 +++++++++++++++++++ |
| 30 | hostapd/hostapd_cli.c | 8 ++ |
| 31 | hostapd/main.c | 4 +- |
| 32 | src/ap/beacon.c | 161 ++++++++++++++++++++++++++++++++++- |
| 33 | src/ap/beacon.h | 37 ++++++++ |
| 34 | src/ap/dfs.c | 12 +++ |
| 35 | src/ap/drv_callbacks.c | 1 - |
| 36 | src/ap/hostapd.c | 85 +++++++++++++++++- |
| 37 | src/ap/hostapd.h | 5 ++ |
| 38 | src/ap/ieee802_11.c | 15 ++++ |
| 39 | src/ap/ieee802_11_eht.c | 7 +- |
| 40 | src/ap/sta_info.h | 6 ++ |
| 41 | src/ap/ucode.c | 9 +- |
| 42 | src/common/ieee802_11_defs.h | 1 + |
| 43 | src/drivers/driver.h | 1 + |
| 44 | src/drivers/driver_nl80211.c | 53 +++++++----- |
| 45 | src/drivers/nl80211_copy.h | 8 ++ |
| 46 | 17 files changed, 470 insertions(+), 31 deletions(-) |
| 47 | |
| 48 | diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c |
| 49 | index e19502d1d..ebe9053cf 100644 |
| 50 | --- a/hostapd/ctrl_iface.c |
| 51 | +++ b/hostapd/ctrl_iface.c |
| 52 | @@ -2911,6 +2911,18 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface, |
| 53 | ret = err; |
| 54 | num_err++; |
| 55 | } |
| 56 | + |
| 57 | +#ifdef CONFIG_IEEE80211BE |
| 58 | + if (iface->bss[i]->conf->mld_ap) |
| 59 | + hostapd_update_aff_link_beacon(iface->bss[i], settings.cs_count); |
| 60 | + |
| 61 | + /* |
| 62 | + * Currently, no FW notification event for clearing CU flag after DTIM period. |
| 63 | + * Also, another CU or set beacon is not allowed during CSA period. |
| 64 | + * Therefore, just clear it manually here for workaround. |
| 65 | + */ |
| 66 | + iface->bss[i]->eht_mld_bss_critical_update = 0; |
| 67 | +#endif /* CONFIG_IEEE80211BE */ |
| 68 | } |
| 69 | |
| 70 | return (iface->num_bss == num_err) ? ret : 0; |
| 71 | @@ -5279,6 +5291,79 @@ hostapd_ctrl_iface_dump_csi(struct hostapd_data *hapd, char *cmd, |
| 72 | return 0; |
| 73 | } |
| 74 | |
| 75 | +static int |
| 76 | +hostapd_ctrl_iface_wmm(struct hostapd_data *hapd, char *cmd, char *buf, |
| 77 | + size_t buflen) |
| 78 | +{ |
| 79 | + char *pos = cmd, *ac, *token, *context = NULL; |
| 80 | + struct hostapd_wmm_ac_params *acp; |
| 81 | + int num; |
| 82 | + |
| 83 | + if (!hapd->conf->mld_ap) |
| 84 | + return -1; |
| 85 | + |
| 86 | + ac = pos; |
| 87 | + pos = os_strchr(pos, ' '); |
| 88 | + if (pos) |
| 89 | + *pos++ = '\0'; |
| 90 | + |
| 91 | + if (os_strncmp(ac, "BE", 2) == 0) { |
| 92 | + num = 0; |
| 93 | + } else if (os_strncmp(ac, "BK", 2) == 0) { |
| 94 | + num = 1; |
| 95 | + } else if (os_strncmp(ac, "VI", 2) == 0) { |
| 96 | + num = 2; |
| 97 | + } else if (os_strncmp(ac, "VO", 2) == 0) { |
| 98 | + num = 3; |
| 99 | + } else { |
| 100 | + wpa_printf(MSG_ERROR, "Unknown AC name '%s'", ac); |
| 101 | + return -1; |
| 102 | + } |
| 103 | + |
| 104 | + acp = &hapd->iconf->wmm_ac_params[num]; |
| 105 | + |
| 106 | + /* if only ac is provied, show wmm params */ |
| 107 | + if (!pos) |
| 108 | + return os_snprintf(buf, buflen, |
| 109 | + "link=%d ac=%s cwmin=%d cwmax=%d aifs=%d txop_limit=%d\n", |
| 110 | + hapd->mld_link_id, ac, acp->cwmin, acp->cwmax, acp->aifs, acp->txop_limit); |
| 111 | + |
| 112 | + while ((token = str_token(pos, " ", &context))) { |
| 113 | + if (os_strncmp(token, "cwmin=", 6) == 0) { |
| 114 | + acp->cwmin = atoi(token + 6); |
| 115 | + continue; |
| 116 | + } |
| 117 | + |
| 118 | + if (os_strncmp(token, "cwmax=", 6) == 0) { |
| 119 | + acp->cwmax = atoi(token + 6); |
| 120 | + continue; |
| 121 | + } |
| 122 | + |
| 123 | + if (os_strncmp(token, "aifs=", 5) == 0) { |
| 124 | + acp->aifs = atoi(token + 5); |
| 125 | + continue; |
| 126 | + } |
| 127 | + |
| 128 | + if (os_strncmp(token, "txop_limit=", 11) == 0) { |
| 129 | + acp->txop_limit = atoi(token + 11); |
| 130 | + continue; |
| 131 | + } |
| 132 | + |
| 133 | + wpa_printf(MSG_ERROR, "CTRL: Invalid WMM parameter: %s", token); |
| 134 | + return -1; |
| 135 | + } |
| 136 | + |
| 137 | + if (acp->cwmin > acp->cwmax) |
| 138 | + return -1; |
| 139 | + |
| 140 | + ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_EDCA); |
| 141 | + |
| 142 | + if (ieee802_11_set_beacon(hapd)) |
| 143 | + return -1; |
| 144 | + |
| 145 | + return os_snprintf(buf, buflen, "OK\n"); |
| 146 | +} |
| 147 | + |
| 148 | static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, |
| 149 | char *buf, char *reply, |
| 150 | int reply_size, |
| 151 | @@ -5946,6 +6031,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, |
| 152 | } else if (os_strncmp(buf, "DUMP_CSI ", 8) == 0) { |
| 153 | reply_len = hostapd_ctrl_iface_dump_csi(hapd, buf + 9, |
| 154 | reply, reply_size); |
| 155 | + } else if (os_strncmp(buf, "WMM", 3) == 0) { |
| 156 | + reply_len = hostapd_ctrl_iface_wmm(hapd, buf + 4, |
| 157 | + reply, reply_size); |
| 158 | } else { |
| 159 | os_memcpy(reply, "UNKNOWN COMMAND\n", 16); |
| 160 | reply_len = 16; |
| 161 | diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c |
| 162 | index 4e94db21d..e578c5b7e 100644 |
| 163 | --- a/hostapd/hostapd_cli.c |
| 164 | +++ b/hostapd/hostapd_cli.c |
| 165 | @@ -1767,6 +1767,12 @@ static int hostapd_cli_cmd_get_pp(struct wpa_ctrl *ctrl, int argc, |
| 166 | return hostapd_cli_cmd(ctrl, "get_pp", 1, argc, argv); |
| 167 | } |
| 168 | |
| 169 | +static int hostapd_cli_cmd_wmm(struct wpa_ctrl *ctrl, int argc, |
| 170 | + char *argv[]) |
| 171 | +{ |
| 172 | + return hostapd_cli_cmd(ctrl, "WMM", 1, argc, argv); |
| 173 | +} |
| 174 | + |
| 175 | struct hostapd_cli_cmd { |
| 176 | const char *cmd; |
| 177 | int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); |
| 178 | @@ -2023,6 +2029,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { |
| 179 | " = Set preamble puncture mode"}, |
| 180 | { "get_pp", hostapd_cli_cmd_get_pp, NULL, |
| 181 | " = Get preamble puncture status"}, |
| 182 | + { "wmm", hostapd_cli_cmd_wmm, NULL, |
| 183 | + " = <ac> [cwmin=] [cwmax=] [aifs=] [txop_limit=]"}, |
| 184 | { NULL, NULL, NULL, NULL } |
| 185 | }; |
| 186 | |
| 187 | diff --git a/hostapd/main.c b/hostapd/main.c |
| 188 | index e790f18ce..8ecec6c1a 100644 |
| 189 | --- a/hostapd/main.c |
| 190 | +++ b/hostapd/main.c |
| 191 | @@ -330,8 +330,8 @@ setup_mld: |
| 192 | return -1; |
| 193 | } |
| 194 | |
| 195 | - /* Initialize the BSS parameter change to 1 */ |
| 196 | - hapd->eht_mld_bss_param_change = 1; |
| 197 | + /* Initialize the BSS parameter change to 0 */ |
| 198 | + hapd->eht_mld_bss_param_change = 0; |
| 199 | |
| 200 | wpa_printf(MSG_DEBUG, |
| 201 | "MLD: Set link_id=%u, mld_addr=" MACSTR |
| 202 | diff --git a/src/ap/beacon.c b/src/ap/beacon.c |
| 203 | index 88e35acc2..9b5c4fc1e 100644 |
| 204 | --- a/src/ap/beacon.c |
| 205 | +++ b/src/ap/beacon.c |
| 206 | @@ -514,6 +514,23 @@ static u8 * hostapd_eid_ecsa(struct hostapd_data *hapd, u8 *eid) |
| 207 | } |
| 208 | |
| 209 | |
| 210 | +static u8 * hostapd_eid_max_chsw_time(struct hostapd_data *hapd, u8 *eid) |
| 211 | +{ |
| 212 | + u32 max_chsw_time = 800; |
| 213 | + |
| 214 | + if (!hapd->cs_freq_params.channel) |
| 215 | + return eid; |
| 216 | + |
| 217 | + *eid++ = WLAN_EID_EXTENSION; |
| 218 | + *eid++ = 4; |
| 219 | + *eid++ = WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME; |
| 220 | + WPA_PUT_LE24(eid, max_chsw_time); |
| 221 | + eid += 3; |
| 222 | + |
| 223 | + return eid; |
| 224 | +} |
| 225 | + |
| 226 | + |
| 227 | static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid) |
| 228 | { |
| 229 | u8 op_class, channel; |
| 230 | @@ -878,6 +895,7 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd, |
| 231 | #endif /* CONFIG_IEEE80211AX */ |
| 232 | |
| 233 | pos = hostapd_eid_wb_chsw_wrapper(hapd, pos); |
| 234 | + pos = hostapd_eid_max_chsw_time(hapd, pos); |
| 235 | |
| 236 | if (!params->is_ml_sta_info) |
| 237 | pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP, |
| 238 | @@ -2185,6 +2203,63 @@ static u8 * hostapd_fils_discovery(struct hostapd_data *hapd, |
| 239 | #endif /* CONFIG_FILS */ |
| 240 | |
| 241 | |
| 242 | +static void hostapd_fill_bcn_sta_profile(struct hostapd_data *hapd, |
| 243 | + struct mld_info *info) |
| 244 | +{ |
| 245 | + struct hostapd_data *h; |
| 246 | + |
| 247 | + if (!info) |
| 248 | + return; |
| 249 | + |
| 250 | + os_memset(info, 0, sizeof(*info)); |
| 251 | + |
| 252 | + for_each_mld_link(h, hapd) { |
| 253 | + unsigned int link_id = h->mld_link_id; |
| 254 | + struct mld_link_info *link = &info->links[link_id]; |
| 255 | + u8 *epos, *csa_pos, buf[EHT_ML_MAX_STA_PROF_LEN]; |
| 256 | + |
| 257 | + if (!h->started || h == hapd || |
| 258 | + h->eht_mld_bss_critical_update != BSS_CRIT_UPDATE_ALL) |
| 259 | + continue; |
| 260 | + |
| 261 | + link->valid = true; |
| 262 | + os_memcpy(link->local_addr, h->own_addr, ETH_ALEN); |
| 263 | + |
| 264 | + /* Build per-STA profile */ |
| 265 | + epos = buf; |
| 266 | + /* Capabilities */ |
| 267 | + WPA_PUT_LE16(epos, hostapd_own_capab_info(h)); |
| 268 | + epos += 2; |
| 269 | + |
| 270 | + /* CSA IE */ |
| 271 | + csa_pos = hostapd_eid_csa(h, epos); |
| 272 | + if (csa_pos != epos) |
| 273 | + link->sta_prof_csa_offset = csa_pos - 1 - buf; |
| 274 | + epos = csa_pos; |
| 275 | + |
| 276 | + /* eCSA IE */ |
| 277 | + csa_pos = hostapd_eid_ecsa(h, epos); |
| 278 | + if (csa_pos != epos) |
| 279 | + link->sta_prof_ecsa_offset = csa_pos - 1 - buf; |
| 280 | + epos = csa_pos; |
| 281 | + |
| 282 | + /* channel switch wrapper */ |
| 283 | + epos = hostapd_eid_wb_chsw_wrapper(h, epos); |
| 284 | + |
| 285 | + /* max channel switch time */ |
| 286 | + epos = hostapd_eid_max_chsw_time(h, epos); |
| 287 | + |
| 288 | + link->resp_sta_profile_len = epos - buf; |
| 289 | + link->resp_sta_profile = os_memdup(buf, link->resp_sta_profile_len); |
| 290 | + |
| 291 | + /* TODO: |
| 292 | + * 1. add other IEs |
| 293 | + * 2. handle per-STA profile inheritance |
| 294 | + * 3. handle csa offset if fragmentation is required |
| 295 | + */ |
| 296 | + } |
| 297 | +} |
| 298 | + |
| 299 | int ieee802_11_build_ap_params(struct hostapd_data *hapd, |
| 300 | struct wpa_driver_ap_params *params) |
| 301 | { |
| 302 | @@ -2394,6 +2469,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, |
| 303 | #endif /* CONFIG_IEEE80211AX */ |
| 304 | |
| 305 | tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos); |
| 306 | + tailpos = hostapd_eid_max_chsw_time(hapd, tailpos); |
| 307 | |
| 308 | tailpos = hostapd_eid_rnr(hapd, tailpos, WLAN_FC_STYPE_BEACON, true); |
| 309 | tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0); |
| 310 | @@ -2423,9 +2499,30 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, |
| 311 | |
| 312 | #ifdef CONFIG_IEEE80211BE |
| 313 | if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { |
| 314 | - if (hapd->conf->mld_ap) |
| 315 | - tailpos = hostapd_eid_eht_ml_beacon(hapd, NULL, |
| 316 | + if (hapd->conf->mld_ap) { |
| 317 | + struct hostapd_data *h; |
| 318 | + struct mld_info info; |
| 319 | + struct mld_link_info *link; |
| 320 | + u32 base; |
| 321 | + u8 link_id, *ml_pos = tailpos; |
| 322 | + |
| 323 | + hostapd_fill_bcn_sta_profile(hapd, &info); |
| 324 | + tailpos = hostapd_eid_eht_ml_beacon(hapd, &info, |
| 325 | tailpos, false); |
| 326 | + |
| 327 | + for_each_mld_link(h, hapd) { |
| 328 | + link_id = h->mld_link_id; |
| 329 | + link = &info.links[link_id]; |
| 330 | + base = ml_pos - tail + link->sta_prof_offset; |
| 331 | + if (link->sta_prof_csa_offset) |
| 332 | + hapd->cs_c_off_sta_prof[link_id] = |
| 333 | + base + link->sta_prof_csa_offset; |
| 334 | + if (link->sta_prof_ecsa_offset) |
| 335 | + hapd->cs_c_off_ecsa_sta_prof[link_id] = |
| 336 | + base + link->sta_prof_ecsa_offset; |
| 337 | + } |
| 338 | + ap_sta_free_sta_profile(&info); |
| 339 | + } |
| 340 | tailpos = hostapd_eid_eht_capab(hapd, tailpos, |
| 341 | IEEE80211_MODE_AP); |
| 342 | tailpos = hostapd_eid_eht_operation(hapd, tailpos); |
| 343 | @@ -2803,7 +2900,8 @@ void ieee802_11_set_beacon_per_bss_only(struct hostapd_data *hapd) |
| 344 | int ieee802_11_set_beacon(struct hostapd_data *hapd) |
| 345 | { |
| 346 | struct hostapd_iface *iface = hapd->iface; |
| 347 | - int ret; |
| 348 | + struct hostapd_data *h; |
| 349 | + int ret, link_id; |
| 350 | size_t i, j; |
| 351 | bool is_6g, hapd_mld = false; |
| 352 | |
| 353 | @@ -2846,6 +2944,17 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd) |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | +#ifdef CONFIG_IEEE80211BE |
| 358 | + /* clear critical update flag for UPDATE_SINGLE type, for other types, |
| 359 | + * we should get some notified events from driver |
| 360 | + */ |
| 361 | + if (hapd->conf->mld_ap) { |
| 362 | + for_each_mld_link(h, hapd) |
| 363 | + if (h->eht_mld_bss_critical_update == BSS_CRIT_UPDATE_SINGLE) |
| 364 | + h->eht_mld_bss_critical_update = 0; |
| 365 | + } |
| 366 | +#endif /* CONFIG_IEEE80211BE */ |
| 367 | + |
| 368 | return 0; |
| 369 | } |
| 370 | |
| 371 | @@ -2880,4 +2989,50 @@ int ieee802_11_update_beacons(struct hostapd_iface *iface) |
| 372 | return ret; |
| 373 | } |
| 374 | |
| 375 | + |
| 376 | +int ieee802_11_set_bss_critical_update(struct hostapd_data *hapd, |
| 377 | + enum bss_crit_update_event event) |
| 378 | +{ |
| 379 | + if (!hapd->conf->mld_ap) |
| 380 | + return 0; |
| 381 | + |
| 382 | + switch (event) { |
| 383 | + case BSS_CRIT_UPDATE_EVENT_CSA: |
| 384 | + case BSS_CRIT_UPDATE_EVENT_ECSA: |
| 385 | + case BSS_CRIT_UPDATE_EVENT_QUIET: |
| 386 | + case BSS_CRIT_UPDATE_EVENT_WBCS: |
| 387 | + case BSS_CRIT_UPDATE_EVENT_CS_WRAP: |
| 388 | + case BSS_CRIT_UPDATE_EVENT_OP_MODE_NOTIF: |
| 389 | + case BSS_CRIT_UPDATE_EVENT_QUIET_CH: |
| 390 | + case BSS_CRIT_UPDATE_EVENT_CCA: |
| 391 | + case BSS_CRIT_UPDATE_EVENT_BCAST_TWT: |
| 392 | + case BSS_CRIT_UPDATE_EVENT_BCAST_TWT_PARAM_SET: |
| 393 | + case BSS_CRIT_UPDATE_EVENT_IDX_ADJUST_FACTOR: |
| 394 | + case BSS_CRIT_UPDATE_EVENT_TPE: |
| 395 | + hapd->eht_mld_bss_param_change += 1; |
| 396 | + hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_ALL; |
| 397 | + return 0; |
| 398 | + case BSS_CRIT_UPDATE_EVENT_EDCA: |
| 399 | + case BSS_CRIT_UPDATE_EVENT_DSSS: |
| 400 | + case BSS_CRIT_UPDATE_EVENT_HT_OPERATION: |
| 401 | + case BSS_CRIT_UPDATE_EVENT_VHT_OPERATION: |
| 402 | + case BSS_CRIT_UPDATE_EVENT_HE_OPERATION: |
| 403 | + case BSS_CRIT_UPDATE_EVENT_MU_EDCA: |
| 404 | + case BSS_CRIT_UPDATE_EVENT_SR: |
| 405 | + case BSS_CRIT_UPDATE_EVENT_UORA: |
| 406 | + case BSS_CRIT_UPDATE_EVENT_EHT_OPERATION: |
| 407 | + hapd->eht_mld_bss_param_change += 1; |
| 408 | + hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_SINGLE; |
| 409 | + return 0; |
| 410 | + case BSS_CRIT_UPDATE_EVENT_RECONFIG: |
| 411 | + case BSS_CRIT_UPDATE_EVENT_ADD_LINK: |
| 412 | + case BSS_CRIT_UPDATE_EVENT_ATTLM: |
| 413 | + hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_FLAG; |
| 414 | + return 0; |
| 415 | + default: |
| 416 | + hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_NONE; |
| 417 | + return -1; |
| 418 | + } |
| 419 | +} |
| 420 | + |
| 421 | #endif /* CONFIG_NATIVE_WINDOWS */ |
| 422 | diff --git a/src/ap/beacon.h b/src/ap/beacon.h |
| 423 | index e381542a8..809393902 100644 |
| 424 | --- a/src/ap/beacon.h |
| 425 | +++ b/src/ap/beacon.h |
| 426 | @@ -12,12 +12,49 @@ |
| 427 | |
| 428 | struct ieee80211_mgmt; |
| 429 | |
| 430 | +enum bss_crit_update_event { |
| 431 | + BSS_CRIT_UPDATE_EVENT_CSA, |
| 432 | + BSS_CRIT_UPDATE_EVENT_ECSA, |
| 433 | + BSS_CRIT_UPDATE_EVENT_EDCA, |
| 434 | + BSS_CRIT_UPDATE_EVENT_QUIET, |
| 435 | + BSS_CRIT_UPDATE_EVENT_DSSS, |
| 436 | + BSS_CRIT_UPDATE_EVENT_HT_OPERATION, |
| 437 | + BSS_CRIT_UPDATE_EVENT_WBCS, |
| 438 | + BSS_CRIT_UPDATE_EVENT_CS_WRAP, |
| 439 | + BSS_CRIT_UPDATE_EVENT_OP_MODE_NOTIF, |
| 440 | + BSS_CRIT_UPDATE_EVENT_QUIET_CH, |
| 441 | + BSS_CRIT_UPDATE_EVENT_VHT_OPERATION, |
| 442 | + BSS_CRIT_UPDATE_EVENT_HE_OPERATION, |
| 443 | + BSS_CRIT_UPDATE_EVENT_BCAST_TWT, |
| 444 | + BSS_CRIT_UPDATE_EVENT_BCAST_TWT_PARAM_SET, |
| 445 | + BSS_CRIT_UPDATE_EVENT_CCA, |
| 446 | + BSS_CRIT_UPDATE_EVENT_MU_EDCA, |
| 447 | + BSS_CRIT_UPDATE_EVENT_SR, |
| 448 | + BSS_CRIT_UPDATE_EVENT_UORA, |
| 449 | + BSS_CRIT_UPDATE_EVENT_IDX_ADJUST_FACTOR, |
| 450 | + BSS_CRIT_UPDATE_EVENT_EHT_OPERATION, |
| 451 | + BSS_CRIT_UPDATE_EVENT_TPE, |
| 452 | + BSS_CRIT_UPDATE_EVENT_CH_CHANGED, |
| 453 | + BSS_CRIT_UPDATE_EVENT_RECONFIG, |
| 454 | + BSS_CRIT_UPDATE_EVENT_ADD_LINK, |
| 455 | + BSS_CRIT_UPDATE_EVENT_ATTLM |
| 456 | +}; |
| 457 | + |
| 458 | +enum { |
| 459 | + BSS_CRIT_UPDATE_NONE, |
| 460 | + BSS_CRIT_UPDATE_SINGLE, |
| 461 | + BSS_CRIT_UPDATE_ALL, |
| 462 | + BSS_CRIT_UPDATE_FLAG |
| 463 | +}; |
| 464 | + |
| 465 | void handle_probe_req(struct hostapd_data *hapd, |
| 466 | const struct ieee80211_mgmt *mgmt, size_t len, |
| 467 | int ssi_signal); |
| 468 | void ieee802_11_set_beacon_per_bss_only(struct hostapd_data *hapd); |
| 469 | int ieee802_11_set_beacon(struct hostapd_data *hapd); |
| 470 | int ieee802_11_set_beacons(struct hostapd_iface *iface); |
| 471 | +int ieee802_11_set_bss_critical_update(struct hostapd_data *hapd, |
| 472 | + enum bss_crit_update_event event); |
| 473 | int ieee802_11_update_beacons(struct hostapd_iface *iface); |
| 474 | int ieee802_11_build_ap_params(struct hostapd_data *hapd, |
| 475 | struct wpa_driver_ap_params *params); |
| 476 | diff --git a/src/ap/dfs.c b/src/ap/dfs.c |
| 477 | index fc7699973..697e6364c 100644 |
| 478 | --- a/src/ap/dfs.c |
| 479 | +++ b/src/ap/dfs.c |
| 480 | @@ -1120,6 +1120,18 @@ static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface, |
| 481 | err = hostapd_switch_channel(iface->bss[i], &csa_settings); |
| 482 | if (err) |
| 483 | num_err++; |
| 484 | + |
| 485 | +#ifdef CONFIG_IEEE80211BE |
| 486 | + if (iface->bss[i]->conf->mld_ap) |
| 487 | + hostapd_update_aff_link_beacon(iface->bss[i], csa_settings.cs_count); |
| 488 | + |
| 489 | + /* |
| 490 | + * Currently, no FW notification event for clearing CU flag after DTIM period. |
| 491 | + * Also, another CU or set beacon is not allowed during CSA period. |
| 492 | + * Therefore, just clear it manually here for workaround. |
| 493 | + */ |
| 494 | + iface->bss[i]->eht_mld_bss_critical_update = 0; |
| 495 | +#endif /* CONFIG_IEEE80211BE */ |
| 496 | } |
| 497 | |
| 498 | if (num_err == iface->num_bss) { |
| 499 | diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c |
| 500 | index 1107fd70e..705acfb67 100644 |
| 501 | --- a/src/ap/drv_callbacks.c |
| 502 | +++ b/src/ap/drv_callbacks.c |
| 503 | @@ -1314,7 +1314,6 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, |
| 504 | if (hapd->csa_in_progress && |
| 505 | freq == hapd->cs_freq_params.freq) { |
| 506 | hostapd_cleanup_cs_params(hapd); |
| 507 | - ieee802_11_set_beacon(hapd); |
| 508 | |
| 509 | wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED |
| 510 | "freq=%d dfs=%d", freq, is_dfs); |
| 511 | diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c |
| 512 | index 2c9e54b23..f03a6242f 100644 |
| 513 | --- a/src/ap/hostapd.c |
| 514 | +++ b/src/ap/hostapd.c |
| 515 | @@ -4524,6 +4524,9 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd, |
| 516 | old_punct_bitmap = iface->conf->punct_bitmap; |
| 517 | iface->conf->punct_bitmap = settings->punct_bitmap; |
| 518 | #endif /* CONFIG_IEEE80211BE */ |
| 519 | + |
| 520 | + /* Another CU in the new channel due to OP element modification */ |
| 521 | + ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_EHT_OPERATION); |
| 522 | ret = hostapd_build_beacon_data(hapd, &settings->beacon_after); |
| 523 | |
| 524 | /* change back the configuration */ |
| 525 | @@ -4541,20 +4544,32 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd, |
| 526 | hapd->cs_count = settings->cs_count; |
| 527 | hapd->cs_block_tx = settings->block_tx; |
| 528 | |
| 529 | +#ifdef CONFIG_IEEE80211BE |
| 530 | + /* Restore BPCC to build the CSA beacon */ |
| 531 | + hapd->eht_mld_bss_param_change--; |
| 532 | + hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_ALL; |
| 533 | +#endif /* CONFIG_IEEE80211BE */ |
| 534 | + |
| 535 | ret = hostapd_build_beacon_data(hapd, &settings->beacon_csa); |
| 536 | if (ret) { |
| 537 | free_beacon_data(&settings->beacon_after); |
| 538 | return ret; |
| 539 | } |
| 540 | |
| 541 | + /* Change back to the final BPCC and CU flag */ |
| 542 | + ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_EHT_OPERATION); |
| 543 | + |
| 544 | settings->counter_offset_beacon[0] = hapd->cs_c_off_beacon; |
| 545 | settings->counter_offset_presp[0] = hapd->cs_c_off_proberesp; |
| 546 | settings->counter_offset_beacon[1] = hapd->cs_c_off_ecsa_beacon; |
| 547 | settings->counter_offset_presp[1] = hapd->cs_c_off_ecsa_proberesp; |
| 548 | settings->link_id = -1; |
| 549 | + settings->freq_params.link_id = -1; |
| 550 | #ifdef CONFIG_IEEE80211BE |
| 551 | - if (hapd->conf->mld_ap) |
| 552 | + if (hapd->conf->mld_ap) { |
| 553 | settings->link_id = hapd->mld_link_id; |
| 554 | + settings->freq_params.link_id = hapd->mld_link_id; |
| 555 | + } |
| 556 | #endif /* CONFIG_IEEE80211BE */ |
| 557 | |
| 558 | #ifdef CONFIG_IEEE80211AX |
| 559 | @@ -4616,6 +4631,8 @@ int hostapd_switch_channel(struct hostapd_data *hapd, |
| 560 | return -1; |
| 561 | } |
| 562 | |
| 563 | + ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_CSA); |
| 564 | + |
| 565 | ret = hostapd_fill_csa_settings(hapd, settings); |
| 566 | if (ret) |
| 567 | return ret; |
| 568 | @@ -4637,6 +4654,72 @@ int hostapd_switch_channel(struct hostapd_data *hapd, |
| 569 | return 0; |
| 570 | } |
| 571 | |
| 572 | +int hostapd_update_aff_link_beacon(struct hostapd_data *hapd, u8 cs_count) |
| 573 | +{ |
| 574 | + struct hostapd_data *h; |
| 575 | + unsigned int cs_link_id = hapd->mld_link_id; |
| 576 | + int cs_channel = hapd->cs_freq_params.channel; |
| 577 | + |
| 578 | + /* TODO: add beacon offload driver flag */ |
| 579 | + for_each_mld_link(h, hapd) { |
| 580 | + struct hostapd_config *conf = h->iconf; |
| 581 | + struct hostapd_hw_modes *mode = h->iface->current_mode; |
| 582 | + struct csa_settings settings = {}; |
| 583 | + unsigned int link_id = h->mld_link_id; |
| 584 | + int ret; |
| 585 | + |
| 586 | + if (!h->started || h == hapd) |
| 587 | + continue; |
| 588 | + |
| 589 | + hostapd_set_freq_params(&settings.freq_params, conf->hw_mode, |
| 590 | + hostapd_hw_get_freq(h, conf->channel), |
| 591 | + conf->channel, conf->enable_edmg, |
| 592 | + conf->edmg_channel, conf->ieee80211n, |
| 593 | + conf->ieee80211ac, conf->ieee80211ax, |
| 594 | + conf->ieee80211be, conf->secondary_channel, |
| 595 | + hostapd_get_oper_chwidth(conf), |
| 596 | + hostapd_get_oper_centr_freq_seg0_idx(conf), |
| 597 | + hostapd_get_oper_centr_freq_seg1_idx(conf), |
| 598 | + conf->vht_capab, |
| 599 | + mode ? &mode->he_capab[IEEE80211_MODE_AP] : NULL, |
| 600 | + mode ? &mode->eht_capab[IEEE80211_MODE_AP] : NULL, |
| 601 | + hostapd_get_punct_bitmap(h)); |
| 602 | + hapd->cs_freq_params.channel = 0; |
| 603 | + ret = hostapd_build_beacon_data(h, &settings.beacon_after); |
| 604 | + if (ret) |
| 605 | + return ret; |
| 606 | + |
| 607 | + hapd->cs_freq_params.channel = cs_channel; |
| 608 | + /* Restore BPCC to build the RNR for the CS link */ |
| 609 | + hapd->eht_mld_bss_param_change--; |
| 610 | + hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_ALL; |
| 611 | + ret = hostapd_build_beacon_data(h, &settings.beacon_csa); |
| 612 | + if (ret) { |
| 613 | + free_beacon_data(&settings.beacon_after); |
| 614 | + return ret; |
| 615 | + } |
| 616 | + |
| 617 | + /* Change back to the final BPCC and CU flag */ |
| 618 | + ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_EHT_OPERATION); |
| 619 | + |
| 620 | + settings.counter_offset_sta_prof[cs_link_id][0] = |
| 621 | + h->cs_c_off_sta_prof[cs_link_id]; |
| 622 | + settings.counter_offset_sta_prof[cs_link_id][1] = |
| 623 | + h->cs_c_off_ecsa_sta_prof[cs_link_id]; |
| 624 | + settings.link_id = cs_link_id; |
| 625 | + settings.freq_params.link_id = link_id; |
| 626 | + settings.cs_count = cs_count; |
| 627 | + settings.punct_bitmap = conf->punct_bitmap; |
| 628 | + ret = hostapd_drv_switch_channel(h, &settings); |
| 629 | + free_beacon_data(&settings.beacon_csa); |
| 630 | + free_beacon_data(&settings.beacon_after); |
| 631 | + if (ret) |
| 632 | + return ret; |
| 633 | + } |
| 634 | + |
| 635 | + return 0; |
| 636 | +} |
| 637 | + |
| 638 | |
| 639 | void |
| 640 | hostapd_switch_channel_fallback(struct hostapd_iface *iface, |
| 641 | diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h |
| 642 | index 4db67096b..99d5a01d6 100644 |
| 643 | --- a/src/ap/hostapd.h |
| 644 | +++ b/src/ap/hostapd.h |
| 645 | @@ -342,6 +342,9 @@ struct hostapd_data { |
| 646 | unsigned int cs_c_off_ecsa_beacon; |
| 647 | unsigned int cs_c_off_ecsa_proberesp; |
| 648 | |
| 649 | + unsigned int cs_c_off_sta_prof[MAX_NUM_MLD_LINKS]; |
| 650 | + unsigned int cs_c_off_ecsa_sta_prof[MAX_NUM_MLD_LINKS]; |
| 651 | + |
| 652 | #ifdef CONFIG_IEEE80211AX |
| 653 | bool cca_in_progress; |
| 654 | u8 cca_count; |
| 655 | @@ -501,6 +504,7 @@ struct hostapd_data { |
| 656 | |
| 657 | #ifdef CONFIG_IEEE80211BE |
| 658 | u8 eht_mld_bss_param_change; |
| 659 | + u8 eht_mld_bss_critical_update; |
| 660 | struct hostapd_mld *mld; |
| 661 | struct dl_list link; |
| 662 | u8 mld_link_id; |
| 663 | @@ -850,6 +854,7 @@ void hostapd_chan_switch_config(struct hostapd_data *hapd, |
| 664 | struct hostapd_freq_params *freq_params); |
| 665 | int hostapd_switch_channel(struct hostapd_data *hapd, |
| 666 | struct csa_settings *settings); |
| 667 | +int hostapd_update_aff_link_beacon(struct hostapd_data *hapd, u8 cs_count); |
| 668 | void |
| 669 | hostapd_switch_channel_fallback(struct hostapd_iface *iface, |
| 670 | const struct hostapd_freq_params *freq_params); |
| 671 | diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c |
| 672 | index 1365bc822..bb508fe79 100644 |
| 673 | --- a/src/ap/ieee802_11.c |
| 674 | +++ b/src/ap/ieee802_11.c |
| 675 | @@ -282,6 +282,7 @@ u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid, |
| 676 | |
| 677 | u16 hostapd_own_capab_info(struct hostapd_data *hapd) |
| 678 | { |
| 679 | + struct hostapd_data *h; |
| 680 | int capab = WLAN_CAPABILITY_ESS; |
| 681 | int privacy = 0; |
| 682 | int dfs; |
| 683 | @@ -342,6 +343,18 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd) |
| 684 | } |
| 685 | } |
| 686 | |
| 687 | +#ifdef CONFIG_IEEE80211BE |
| 688 | + if (hapd->conf->mld_ap) { |
| 689 | + for_each_mld_link(h, hapd) { |
| 690 | + if (h->eht_mld_bss_critical_update) { |
| 691 | + capab |= WLAN_CAPABILITY_PBCC; |
| 692 | + break; |
| 693 | + } |
| 694 | + } |
| 695 | + } |
| 696 | +#endif /* CONFIG_IEEE80211BE */ |
| 697 | + |
| 698 | + |
| 699 | return capab; |
| 700 | } |
| 701 | |
| 702 | @@ -7838,6 +7851,8 @@ static bool hostapd_eid_rnr_bss(struct hostapd_data *hapd, |
| 703 | (MAX_NUM_MLD_LINKS | 0xF0); |
| 704 | /* BPCC (Bit 3 to Bit 0) */ |
| 705 | *eid = is_partner ? ((param_ch & 0xF0) >> 4) : 0x0F; |
| 706 | + if (bss->eht_mld_bss_critical_update == BSS_CRIT_UPDATE_ALL) |
| 707 | + *eid |= RNR_TBTT_INFO_MLD_PARAM2_ALL_UPDATE_INC; |
| 708 | #ifdef CONFIG_TESTING_OPTIONS |
| 709 | if (bss->conf->mld_indicate_disabled) |
| 710 | *eid |= RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED; |
| 711 | diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c |
| 712 | index a04eb23e0..2b5c06d6d 100644 |
| 713 | --- a/src/ap/ieee802_11_eht.c |
| 714 | +++ b/src/ap/ieee802_11_eht.c |
| 715 | @@ -495,7 +495,7 @@ static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd, |
| 716 | wpabuf_put_u8(buf, hapd->mld_link_id); |
| 717 | |
| 718 | /* Currently hard code the BSS Parameters Change Count to 0x1 */ |
| 719 | - wpabuf_put_u8(buf, 0x1); |
| 720 | + wpabuf_put_u8(buf, hapd->eht_mld_bss_param_change); |
| 721 | |
| 722 | wpa_printf(MSG_DEBUG, "MLD: EML Capabilities=0x%x", |
| 723 | hapd->iface->mld_eml_capa); |
| 724 | @@ -593,11 +593,14 @@ static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd, |
| 725 | wpabuf_put_u8(buf, link_bss->conf->dtim_period); |
| 726 | |
| 727 | /* BSS Parameters Change Count */ |
| 728 | - wpabuf_put_u8(buf, hapd->eht_mld_bss_param_change); |
| 729 | + wpabuf_put_u8(buf, link_bss->eht_mld_bss_param_change); |
| 730 | |
| 731 | if (!link->resp_sta_profile) |
| 732 | continue; |
| 733 | |
| 734 | +#define EXT_EID_TAG_LEN 3 |
| 735 | + link->sta_prof_offset = wpabuf_len(buf) + EXT_EID_TAG_LEN; |
| 736 | + |
| 737 | /* Fragment the sub element if needed */ |
| 738 | if (total_len <= 255) { |
| 739 | wpabuf_put_data(buf, link->resp_sta_profile, |
| 740 | diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h |
| 741 | index 67b97671a..60b33f049 100644 |
| 742 | --- a/src/ap/sta_info.h |
| 743 | +++ b/src/ap/sta_info.h |
| 744 | @@ -89,6 +89,12 @@ struct mld_info { |
| 745 | u16 status; |
| 746 | u16 resp_sta_profile_len; |
| 747 | u8 *resp_sta_profile; |
| 748 | + |
| 749 | + u32 sta_prof_csa_offset; |
| 750 | + u32 sta_prof_ecsa_offset; |
| 751 | + u32 sta_prof_offset; |
| 752 | + |
| 753 | + const u8 *rsne, *rsnxe; |
| 754 | } links[MAX_NUM_MLD_LINKS]; |
| 755 | }; |
| 756 | |
| 757 | diff --git a/src/ap/ucode.c b/src/ap/ucode.c |
| 758 | index da1c4c1ac..a72193282 100644 |
| 759 | --- a/src/ap/ucode.c |
| 760 | +++ b/src/ap/ucode.c |
| 761 | @@ -738,9 +738,16 @@ uc_hostapd_iface_switch_channel(uc_vm_t *vm, size_t nargs) |
| 762 | wpa_printf(MSG_INFO, " * center_freq2 is %d\n", |
| 763 | csa.freq_params.center_freq2); |
| 764 | |
| 765 | - for (i = 0; i < iface->num_bss; i++) |
| 766 | + for (i = 0; i < iface->num_bss; i++) { |
| 767 | ret = hostapd_switch_channel(iface->bss[i], &csa); |
| 768 | |
| 769 | + if (iface->bss[i]->conf->mld_ap) |
| 770 | + hostapd_update_aff_link_beacon(iface->bss[i], csa.cs_count); |
| 771 | + |
| 772 | + /* FIXME: remove this line after CU event merged */ |
| 773 | + iface->bss[i]->eht_mld_bss_critical_update = 0; |
| 774 | + } |
| 775 | + |
| 776 | return ucv_boolean_new(!ret); |
| 777 | } |
| 778 | |
| 779 | diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h |
| 780 | index c380d0c7e..efb584c66 100644 |
| 781 | --- a/src/common/ieee802_11_defs.h |
| 782 | +++ b/src/common/ieee802_11_defs.h |
| 783 | @@ -504,6 +504,7 @@ |
| 784 | #define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38 |
| 785 | #define WLAN_EID_EXT_SPATIAL_REUSE 39 |
| 786 | #define WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT 42 |
| 787 | +#define WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME 52 |
| 788 | #define WLAN_EID_EXT_OCV_OCI 54 |
| 789 | #define WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION 55 |
| 790 | #define WLAN_EID_EXT_NON_INHERITANCE 56 |
| 791 | diff --git a/src/drivers/driver.h b/src/drivers/driver.h |
| 792 | index b75580374..924a1baba 100644 |
| 793 | --- a/src/drivers/driver.h |
| 794 | +++ b/src/drivers/driver.h |
| 795 | @@ -2763,6 +2763,7 @@ struct csa_settings { |
| 796 | |
| 797 | u16 counter_offset_beacon[2]; |
| 798 | u16 counter_offset_presp[2]; |
| 799 | + u16 counter_offset_sta_prof[MAX_NUM_MLD_LINKS][2]; |
| 800 | |
| 801 | u16 punct_bitmap; |
| 802 | int link_id; |
| 803 | diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c |
| 804 | index 8b64c3983..555c97bf7 100644 |
| 805 | --- a/src/drivers/driver_nl80211.c |
| 806 | +++ b/src/drivers/driver_nl80211.c |
| 807 | @@ -11417,9 +11417,10 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) |
| 808 | struct i802_bss *bss = priv; |
| 809 | struct wpa_driver_nl80211_data *drv = bss->drv; |
| 810 | struct nlattr *beacon_csa; |
| 811 | - int ret = -ENOBUFS; |
| 812 | - int csa_off_len = 0; |
| 813 | - int i; |
| 814 | + int i, csa_off_len = 0, ret = -ENOBUFS; |
| 815 | + unsigned int cs_link_id = settings->link_id; |
| 816 | + u16 *counter_offset_beacon = settings->counter_offset_beacon; |
| 817 | + u16 *counter_offset_presp = settings->counter_offset_presp; |
| 818 | |
| 819 | wpa_printf(MSG_DEBUG, |
| 820 | "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d channel=%d sec_channel_offset=%d width=%d cf1=%d cf2=%d puncturing_bitmap=0x%04x link_id=%d%s%s%s)", |
| 821 | @@ -11431,7 +11432,7 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) |
| 822 | settings->freq_params.center_freq1, |
| 823 | settings->freq_params.center_freq2, |
| 824 | settings->punct_bitmap, |
| 825 | - settings->link_id, |
| 826 | + settings->freq_params.link_id, |
| 827 | settings->freq_params.ht_enabled ? " ht" : "", |
| 828 | settings->freq_params.vht_enabled ? " vht" : "", |
| 829 | settings->freq_params.he_enabled ? " he" : ""); |
| 830 | @@ -11451,18 +11452,19 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) |
| 831 | * counters match. This implementation assumes that there are only two |
| 832 | * counters. |
| 833 | */ |
| 834 | - if (settings->counter_offset_beacon[0] && |
| 835 | - !settings->counter_offset_beacon[1]) { |
| 836 | + if (cs_link_id != settings->freq_params.link_id) { |
| 837 | + counter_offset_beacon = settings->counter_offset_sta_prof[cs_link_id]; |
| 838 | + counter_offset_presp = NULL; |
| 839 | + } |
| 840 | + |
| 841 | + if (counter_offset_beacon[0] && !counter_offset_beacon[1]) { |
| 842 | csa_off_len = 1; |
| 843 | - } else if (settings->counter_offset_beacon[1] && |
| 844 | - !settings->counter_offset_beacon[0]) { |
| 845 | + } else if (counter_offset_beacon[1] && !counter_offset_beacon[0]) { |
| 846 | csa_off_len = 1; |
| 847 | - settings->counter_offset_beacon[0] = |
| 848 | - settings->counter_offset_beacon[1]; |
| 849 | - settings->counter_offset_presp[0] = |
| 850 | - settings->counter_offset_presp[1]; |
| 851 | - } else if (settings->counter_offset_beacon[1] && |
| 852 | - settings->counter_offset_beacon[0]) { |
| 853 | + counter_offset_beacon[0] = counter_offset_beacon[1]; |
| 854 | + if (counter_offset_presp) |
| 855 | + counter_offset_presp[0] = counter_offset_presp[1]; |
| 856 | + } else if (counter_offset_beacon[1] && counter_offset_beacon[0]) { |
| 857 | csa_off_len = 2; |
| 858 | } else { |
| 859 | wpa_printf(MSG_ERROR, "nl80211: No CSA counters provided"); |
| 860 | @@ -11481,14 +11483,18 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) |
| 861 | return -EINVAL; |
| 862 | |
| 863 | for (i = 0; i < csa_off_len; i++) { |
| 864 | - u16 csa_c_off_bcn = settings->counter_offset_beacon[i]; |
| 865 | - u16 csa_c_off_presp = settings->counter_offset_presp[i]; |
| 866 | + u16 csa_c_off_bcn = counter_offset_beacon[i]; |
| 867 | + u16 csa_c_off_presp; |
| 868 | |
| 869 | if ((settings->beacon_csa.tail_len <= csa_c_off_bcn) || |
| 870 | (settings->beacon_csa.tail[csa_c_off_bcn] != |
| 871 | settings->cs_count)) |
| 872 | return -EINVAL; |
| 873 | |
| 874 | + if (!counter_offset_presp) |
| 875 | + continue; |
| 876 | + |
| 877 | + csa_c_off_presp = counter_offset_presp[i]; |
| 878 | if (settings->beacon_csa.probe_resp && |
| 879 | ((settings->beacon_csa.probe_resp_len <= |
| 880 | csa_c_off_presp) || |
| 881 | @@ -11506,8 +11512,8 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) |
| 882 | (settings->punct_bitmap && |
| 883 | nla_put_u32(msg, NL80211_ATTR_PUNCT_BITMAP, |
| 884 | settings->punct_bitmap)) || |
| 885 | - (settings->link_id != NL80211_DRV_LINK_ID_NA && |
| 886 | - nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, settings->link_id))) |
| 887 | + (settings->freq_params.link_id != NL80211_DRV_LINK_ID_NA && |
| 888 | + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, settings->freq_params.link_id))) |
| 889 | goto error; |
| 890 | |
| 891 | /* beacon_after params */ |
| 892 | @@ -11528,9 +11534,14 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) |
| 893 | if (ret) |
| 894 | goto error; |
| 895 | |
| 896 | - if (nla_put(msg, NL80211_ATTR_CSA_C_OFF_BEACON, |
| 897 | - csa_off_len * sizeof(u16), |
| 898 | - settings->counter_offset_beacon) || |
| 899 | + if ((cs_link_id == settings->freq_params.link_id && |
| 900 | + nla_put(msg, NL80211_ATTR_CSA_C_OFF_BEACON, |
| 901 | + csa_off_len * sizeof(u16), |
| 902 | + settings->counter_offset_beacon)) || |
| 903 | + (cs_link_id != settings->freq_params.link_id && |
| 904 | + nla_put(msg, NL80211_ATTR_CSA_C_OFF_STA_PROF, |
| 905 | + csa_off_len * sizeof(u16), |
| 906 | + settings->counter_offset_sta_prof[cs_link_id])) || |
| 907 | (settings->beacon_csa.probe_resp && |
| 908 | nla_put(msg, NL80211_ATTR_CSA_C_OFF_PRESP, |
| 909 | csa_off_len * sizeof(u16), |
| 910 | diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h |
| 911 | index d425c797c..13837297c 100644 |
| 912 | --- a/src/drivers/nl80211_copy.h |
| 913 | +++ b/src/drivers/nl80211_copy.h |
| 914 | @@ -2868,6 +2868,10 @@ enum nl80211_commands { |
| 915 | * nested item, it contains attributes defined in |
| 916 | * &enum nl80211_if_combination_attrs. |
| 917 | * |
| 918 | + * @NL80211_ATTR_CNTDWN_OFFS_STA_PROF: An array of offsets (u16) to the channel |
| 919 | + * switch or color change counters in the per-STA profile corresponding to |
| 920 | + * the affected AP. |
| 921 | + * |
| 922 | * @NUM_NL80211_ATTR: total number of nl80211_attrs available |
| 923 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
| 924 | * @__NL80211_ATTR_AFTER_LAST: internal use |
| 925 | @@ -3418,6 +3422,9 @@ enum nl80211_attrs { |
| 926 | |
| 927 | /* add attributes here, update the policy in nl80211.c */ |
| 928 | |
| 929 | + /* MTK internal */ |
| 930 | + NL80211_ATTR_CNTDWN_OFFS_STA_PROF, |
| 931 | + |
| 932 | __NL80211_ATTR_AFTER_LAST, |
| 933 | NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST, |
| 934 | NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 |
| 935 | @@ -3430,6 +3437,7 @@ enum nl80211_attrs { |
| 936 | #define NL80211_ATTR_SAE_DATA NL80211_ATTR_AUTH_DATA |
| 937 | #define NL80211_ATTR_CSA_C_OFF_BEACON NL80211_ATTR_CNTDWN_OFFS_BEACON |
| 938 | #define NL80211_ATTR_CSA_C_OFF_PRESP NL80211_ATTR_CNTDWN_OFFS_PRESP |
| 939 | +#define NL80211_ATTR_CSA_C_OFF_STA_PROF NL80211_ATTR_CNTDWN_OFFS_STA_PROF |
| 940 | |
| 941 | /* |
| 942 | * Allow user space programs to use #ifdef on new attributes by defining them |
| 943 | -- |
| 944 | 2.18.0 |
| 945 | |