| From d46df816cadde59bde528c08db281923874152cc Mon Sep 17 00:00:00 2001 |
| From: StanleyYP Wang <StanleyYP.Wang@mediatek.com> |
| Date: Tue, 23 Apr 2024 16:03:19 +0800 |
| Subject: [PATCH 085/126] mtk: hostapd: add critical update support |
| |
| Add critical update support |
| modification: wmm configuration |
| inclusion: channel switch |
| (affiliated link's per-STA profile CSA/eCSA countdown & |
| channel switch wrapper is included) |
| Note that max channel switch time IE is not implemented |
| in hostapd yet. |
| |
| 1.Add max channel switch time IE |
| Note that fw will find the MCST IE on its own, |
| so there is no need to send the offset of the MCST IE to the kernel. |
| The MCST's value is currently hardcoded to 500 TUs, since the WFA test plan |
| restricts it to not exceeding 500 TUs (APUT 4.22.1). |
| 2. Add critical update support for radar triggered channel switch |
| |
| According to the test plan of APUT 4.44, the CSA after beacon should also |
| include the CU flag and increase BPCC due to operation IE modification. |
| Additionally, avoid setting beacons in hostapd_event_ch_switch after CSA |
| is finished since it would conflict with the CSA after beacon. |
| |
| Signed-off-by: Shayne Chen <shayne.chen@mediatek.com> |
| Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com> |
| --- |
| hostapd/ctrl_iface.c | 88 +++++++++++++++++++ |
| hostapd/hostapd_cli.c | 8 ++ |
| hostapd/main.c | 4 +- |
| src/ap/beacon.c | 161 ++++++++++++++++++++++++++++++++++- |
| src/ap/beacon.h | 37 ++++++++ |
| src/ap/dfs.c | 12 +++ |
| src/ap/drv_callbacks.c | 1 - |
| src/ap/hostapd.c | 85 +++++++++++++++++- |
| src/ap/hostapd.h | 5 ++ |
| src/ap/ieee802_11.c | 15 ++++ |
| src/ap/ieee802_11_eht.c | 7 +- |
| src/ap/sta_info.h | 6 ++ |
| src/ap/ucode.c | 9 +- |
| src/common/ieee802_11_defs.h | 1 + |
| src/drivers/driver.h | 1 + |
| src/drivers/driver_nl80211.c | 53 +++++++----- |
| src/drivers/nl80211_copy.h | 8 ++ |
| 17 files changed, 470 insertions(+), 31 deletions(-) |
| |
| diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c |
| index e19502d1d..ebe9053cf 100644 |
| --- a/hostapd/ctrl_iface.c |
| +++ b/hostapd/ctrl_iface.c |
| @@ -2911,6 +2911,18 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface, |
| ret = err; |
| num_err++; |
| } |
| + |
| +#ifdef CONFIG_IEEE80211BE |
| + if (iface->bss[i]->conf->mld_ap) |
| + hostapd_update_aff_link_beacon(iface->bss[i], settings.cs_count); |
| + |
| + /* |
| + * Currently, no FW notification event for clearing CU flag after DTIM period. |
| + * Also, another CU or set beacon is not allowed during CSA period. |
| + * Therefore, just clear it manually here for workaround. |
| + */ |
| + iface->bss[i]->eht_mld_bss_critical_update = 0; |
| +#endif /* CONFIG_IEEE80211BE */ |
| } |
| |
| return (iface->num_bss == num_err) ? ret : 0; |
| @@ -5279,6 +5291,79 @@ hostapd_ctrl_iface_dump_csi(struct hostapd_data *hapd, char *cmd, |
| return 0; |
| } |
| |
| +static int |
| +hostapd_ctrl_iface_wmm(struct hostapd_data *hapd, char *cmd, char *buf, |
| + size_t buflen) |
| +{ |
| + char *pos = cmd, *ac, *token, *context = NULL; |
| + struct hostapd_wmm_ac_params *acp; |
| + int num; |
| + |
| + if (!hapd->conf->mld_ap) |
| + return -1; |
| + |
| + ac = pos; |
| + pos = os_strchr(pos, ' '); |
| + if (pos) |
| + *pos++ = '\0'; |
| + |
| + if (os_strncmp(ac, "BE", 2) == 0) { |
| + num = 0; |
| + } else if (os_strncmp(ac, "BK", 2) == 0) { |
| + num = 1; |
| + } else if (os_strncmp(ac, "VI", 2) == 0) { |
| + num = 2; |
| + } else if (os_strncmp(ac, "VO", 2) == 0) { |
| + num = 3; |
| + } else { |
| + wpa_printf(MSG_ERROR, "Unknown AC name '%s'", ac); |
| + return -1; |
| + } |
| + |
| + acp = &hapd->iconf->wmm_ac_params[num]; |
| + |
| + /* if only ac is provied, show wmm params */ |
| + if (!pos) |
| + return os_snprintf(buf, buflen, |
| + "link=%d ac=%s cwmin=%d cwmax=%d aifs=%d txop_limit=%d\n", |
| + hapd->mld_link_id, ac, acp->cwmin, acp->cwmax, acp->aifs, acp->txop_limit); |
| + |
| + while ((token = str_token(pos, " ", &context))) { |
| + if (os_strncmp(token, "cwmin=", 6) == 0) { |
| + acp->cwmin = atoi(token + 6); |
| + continue; |
| + } |
| + |
| + if (os_strncmp(token, "cwmax=", 6) == 0) { |
| + acp->cwmax = atoi(token + 6); |
| + continue; |
| + } |
| + |
| + if (os_strncmp(token, "aifs=", 5) == 0) { |
| + acp->aifs = atoi(token + 5); |
| + continue; |
| + } |
| + |
| + if (os_strncmp(token, "txop_limit=", 11) == 0) { |
| + acp->txop_limit = atoi(token + 11); |
| + continue; |
| + } |
| + |
| + wpa_printf(MSG_ERROR, "CTRL: Invalid WMM parameter: %s", token); |
| + return -1; |
| + } |
| + |
| + if (acp->cwmin > acp->cwmax) |
| + return -1; |
| + |
| + ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_EDCA); |
| + |
| + if (ieee802_11_set_beacon(hapd)) |
| + return -1; |
| + |
| + return os_snprintf(buf, buflen, "OK\n"); |
| +} |
| + |
| static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, |
| char *buf, char *reply, |
| int reply_size, |
| @@ -5946,6 +6031,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, |
| } else if (os_strncmp(buf, "DUMP_CSI ", 8) == 0) { |
| reply_len = hostapd_ctrl_iface_dump_csi(hapd, buf + 9, |
| reply, reply_size); |
| + } else if (os_strncmp(buf, "WMM", 3) == 0) { |
| + reply_len = hostapd_ctrl_iface_wmm(hapd, buf + 4, |
| + reply, reply_size); |
| } else { |
| os_memcpy(reply, "UNKNOWN COMMAND\n", 16); |
| reply_len = 16; |
| diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c |
| index 4e94db21d..e578c5b7e 100644 |
| --- a/hostapd/hostapd_cli.c |
| +++ b/hostapd/hostapd_cli.c |
| @@ -1767,6 +1767,12 @@ static int hostapd_cli_cmd_get_pp(struct wpa_ctrl *ctrl, int argc, |
| return hostapd_cli_cmd(ctrl, "get_pp", 1, argc, argv); |
| } |
| |
| +static int hostapd_cli_cmd_wmm(struct wpa_ctrl *ctrl, int argc, |
| + char *argv[]) |
| +{ |
| + return hostapd_cli_cmd(ctrl, "WMM", 1, argc, argv); |
| +} |
| + |
| struct hostapd_cli_cmd { |
| const char *cmd; |
| int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); |
| @@ -2023,6 +2029,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { |
| " = Set preamble puncture mode"}, |
| { "get_pp", hostapd_cli_cmd_get_pp, NULL, |
| " = Get preamble puncture status"}, |
| + { "wmm", hostapd_cli_cmd_wmm, NULL, |
| + " = <ac> [cwmin=] [cwmax=] [aifs=] [txop_limit=]"}, |
| { NULL, NULL, NULL, NULL } |
| }; |
| |
| diff --git a/hostapd/main.c b/hostapd/main.c |
| index e790f18ce..8ecec6c1a 100644 |
| --- a/hostapd/main.c |
| +++ b/hostapd/main.c |
| @@ -330,8 +330,8 @@ setup_mld: |
| return -1; |
| } |
| |
| - /* Initialize the BSS parameter change to 1 */ |
| - hapd->eht_mld_bss_param_change = 1; |
| + /* Initialize the BSS parameter change to 0 */ |
| + hapd->eht_mld_bss_param_change = 0; |
| |
| wpa_printf(MSG_DEBUG, |
| "MLD: Set link_id=%u, mld_addr=" MACSTR |
| diff --git a/src/ap/beacon.c b/src/ap/beacon.c |
| index 88e35acc2..9b5c4fc1e 100644 |
| --- a/src/ap/beacon.c |
| +++ b/src/ap/beacon.c |
| @@ -514,6 +514,23 @@ static u8 * hostapd_eid_ecsa(struct hostapd_data *hapd, u8 *eid) |
| } |
| |
| |
| +static u8 * hostapd_eid_max_chsw_time(struct hostapd_data *hapd, u8 *eid) |
| +{ |
| + u32 max_chsw_time = 800; |
| + |
| + if (!hapd->cs_freq_params.channel) |
| + return eid; |
| + |
| + *eid++ = WLAN_EID_EXTENSION; |
| + *eid++ = 4; |
| + *eid++ = WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME; |
| + WPA_PUT_LE24(eid, max_chsw_time); |
| + eid += 3; |
| + |
| + return eid; |
| +} |
| + |
| + |
| static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid) |
| { |
| u8 op_class, channel; |
| @@ -878,6 +895,7 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd, |
| #endif /* CONFIG_IEEE80211AX */ |
| |
| pos = hostapd_eid_wb_chsw_wrapper(hapd, pos); |
| + pos = hostapd_eid_max_chsw_time(hapd, pos); |
| |
| if (!params->is_ml_sta_info) |
| pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP, |
| @@ -2185,6 +2203,63 @@ static u8 * hostapd_fils_discovery(struct hostapd_data *hapd, |
| #endif /* CONFIG_FILS */ |
| |
| |
| +static void hostapd_fill_bcn_sta_profile(struct hostapd_data *hapd, |
| + struct mld_info *info) |
| +{ |
| + struct hostapd_data *h; |
| + |
| + if (!info) |
| + return; |
| + |
| + os_memset(info, 0, sizeof(*info)); |
| + |
| + for_each_mld_link(h, hapd) { |
| + unsigned int link_id = h->mld_link_id; |
| + struct mld_link_info *link = &info->links[link_id]; |
| + u8 *epos, *csa_pos, buf[EHT_ML_MAX_STA_PROF_LEN]; |
| + |
| + if (!h->started || h == hapd || |
| + h->eht_mld_bss_critical_update != BSS_CRIT_UPDATE_ALL) |
| + continue; |
| + |
| + link->valid = true; |
| + os_memcpy(link->local_addr, h->own_addr, ETH_ALEN); |
| + |
| + /* Build per-STA profile */ |
| + epos = buf; |
| + /* Capabilities */ |
| + WPA_PUT_LE16(epos, hostapd_own_capab_info(h)); |
| + epos += 2; |
| + |
| + /* CSA IE */ |
| + csa_pos = hostapd_eid_csa(h, epos); |
| + if (csa_pos != epos) |
| + link->sta_prof_csa_offset = csa_pos - 1 - buf; |
| + epos = csa_pos; |
| + |
| + /* eCSA IE */ |
| + csa_pos = hostapd_eid_ecsa(h, epos); |
| + if (csa_pos != epos) |
| + link->sta_prof_ecsa_offset = csa_pos - 1 - buf; |
| + epos = csa_pos; |
| + |
| + /* channel switch wrapper */ |
| + epos = hostapd_eid_wb_chsw_wrapper(h, epos); |
| + |
| + /* max channel switch time */ |
| + epos = hostapd_eid_max_chsw_time(h, epos); |
| + |
| + link->resp_sta_profile_len = epos - buf; |
| + link->resp_sta_profile = os_memdup(buf, link->resp_sta_profile_len); |
| + |
| + /* TODO: |
| + * 1. add other IEs |
| + * 2. handle per-STA profile inheritance |
| + * 3. handle csa offset if fragmentation is required |
| + */ |
| + } |
| +} |
| + |
| int ieee802_11_build_ap_params(struct hostapd_data *hapd, |
| struct wpa_driver_ap_params *params) |
| { |
| @@ -2394,6 +2469,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, |
| #endif /* CONFIG_IEEE80211AX */ |
| |
| tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos); |
| + tailpos = hostapd_eid_max_chsw_time(hapd, tailpos); |
| |
| tailpos = hostapd_eid_rnr(hapd, tailpos, WLAN_FC_STYPE_BEACON, true); |
| tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0); |
| @@ -2423,9 +2499,30 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, |
| |
| #ifdef CONFIG_IEEE80211BE |
| if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { |
| - if (hapd->conf->mld_ap) |
| - tailpos = hostapd_eid_eht_ml_beacon(hapd, NULL, |
| + if (hapd->conf->mld_ap) { |
| + struct hostapd_data *h; |
| + struct mld_info info; |
| + struct mld_link_info *link; |
| + u32 base; |
| + u8 link_id, *ml_pos = tailpos; |
| + |
| + hostapd_fill_bcn_sta_profile(hapd, &info); |
| + tailpos = hostapd_eid_eht_ml_beacon(hapd, &info, |
| tailpos, false); |
| + |
| + for_each_mld_link(h, hapd) { |
| + link_id = h->mld_link_id; |
| + link = &info.links[link_id]; |
| + base = ml_pos - tail + link->sta_prof_offset; |
| + if (link->sta_prof_csa_offset) |
| + hapd->cs_c_off_sta_prof[link_id] = |
| + base + link->sta_prof_csa_offset; |
| + if (link->sta_prof_ecsa_offset) |
| + hapd->cs_c_off_ecsa_sta_prof[link_id] = |
| + base + link->sta_prof_ecsa_offset; |
| + } |
| + ap_sta_free_sta_profile(&info); |
| + } |
| tailpos = hostapd_eid_eht_capab(hapd, tailpos, |
| IEEE80211_MODE_AP); |
| tailpos = hostapd_eid_eht_operation(hapd, tailpos); |
| @@ -2803,7 +2900,8 @@ void ieee802_11_set_beacon_per_bss_only(struct hostapd_data *hapd) |
| int ieee802_11_set_beacon(struct hostapd_data *hapd) |
| { |
| struct hostapd_iface *iface = hapd->iface; |
| - int ret; |
| + struct hostapd_data *h; |
| + int ret, link_id; |
| size_t i, j; |
| bool is_6g, hapd_mld = false; |
| |
| @@ -2846,6 +2944,17 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd) |
| } |
| } |
| |
| +#ifdef CONFIG_IEEE80211BE |
| + /* clear critical update flag for UPDATE_SINGLE type, for other types, |
| + * we should get some notified events from driver |
| + */ |
| + if (hapd->conf->mld_ap) { |
| + for_each_mld_link(h, hapd) |
| + if (h->eht_mld_bss_critical_update == BSS_CRIT_UPDATE_SINGLE) |
| + h->eht_mld_bss_critical_update = 0; |
| + } |
| +#endif /* CONFIG_IEEE80211BE */ |
| + |
| return 0; |
| } |
| |
| @@ -2880,4 +2989,50 @@ int ieee802_11_update_beacons(struct hostapd_iface *iface) |
| return ret; |
| } |
| |
| + |
| +int ieee802_11_set_bss_critical_update(struct hostapd_data *hapd, |
| + enum bss_crit_update_event event) |
| +{ |
| + if (!hapd->conf->mld_ap) |
| + return 0; |
| + |
| + switch (event) { |
| + case BSS_CRIT_UPDATE_EVENT_CSA: |
| + case BSS_CRIT_UPDATE_EVENT_ECSA: |
| + case BSS_CRIT_UPDATE_EVENT_QUIET: |
| + case BSS_CRIT_UPDATE_EVENT_WBCS: |
| + case BSS_CRIT_UPDATE_EVENT_CS_WRAP: |
| + case BSS_CRIT_UPDATE_EVENT_OP_MODE_NOTIF: |
| + case BSS_CRIT_UPDATE_EVENT_QUIET_CH: |
| + case BSS_CRIT_UPDATE_EVENT_CCA: |
| + case BSS_CRIT_UPDATE_EVENT_BCAST_TWT: |
| + case BSS_CRIT_UPDATE_EVENT_BCAST_TWT_PARAM_SET: |
| + case BSS_CRIT_UPDATE_EVENT_IDX_ADJUST_FACTOR: |
| + case BSS_CRIT_UPDATE_EVENT_TPE: |
| + hapd->eht_mld_bss_param_change += 1; |
| + hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_ALL; |
| + return 0; |
| + case BSS_CRIT_UPDATE_EVENT_EDCA: |
| + case BSS_CRIT_UPDATE_EVENT_DSSS: |
| + case BSS_CRIT_UPDATE_EVENT_HT_OPERATION: |
| + case BSS_CRIT_UPDATE_EVENT_VHT_OPERATION: |
| + case BSS_CRIT_UPDATE_EVENT_HE_OPERATION: |
| + case BSS_CRIT_UPDATE_EVENT_MU_EDCA: |
| + case BSS_CRIT_UPDATE_EVENT_SR: |
| + case BSS_CRIT_UPDATE_EVENT_UORA: |
| + case BSS_CRIT_UPDATE_EVENT_EHT_OPERATION: |
| + hapd->eht_mld_bss_param_change += 1; |
| + hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_SINGLE; |
| + return 0; |
| + case BSS_CRIT_UPDATE_EVENT_RECONFIG: |
| + case BSS_CRIT_UPDATE_EVENT_ADD_LINK: |
| + case BSS_CRIT_UPDATE_EVENT_ATTLM: |
| + hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_FLAG; |
| + return 0; |
| + default: |
| + hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_NONE; |
| + return -1; |
| + } |
| +} |
| + |
| #endif /* CONFIG_NATIVE_WINDOWS */ |
| diff --git a/src/ap/beacon.h b/src/ap/beacon.h |
| index e381542a8..809393902 100644 |
| --- a/src/ap/beacon.h |
| +++ b/src/ap/beacon.h |
| @@ -12,12 +12,49 @@ |
| |
| struct ieee80211_mgmt; |
| |
| +enum bss_crit_update_event { |
| + BSS_CRIT_UPDATE_EVENT_CSA, |
| + BSS_CRIT_UPDATE_EVENT_ECSA, |
| + BSS_CRIT_UPDATE_EVENT_EDCA, |
| + BSS_CRIT_UPDATE_EVENT_QUIET, |
| + BSS_CRIT_UPDATE_EVENT_DSSS, |
| + BSS_CRIT_UPDATE_EVENT_HT_OPERATION, |
| + BSS_CRIT_UPDATE_EVENT_WBCS, |
| + BSS_CRIT_UPDATE_EVENT_CS_WRAP, |
| + BSS_CRIT_UPDATE_EVENT_OP_MODE_NOTIF, |
| + BSS_CRIT_UPDATE_EVENT_QUIET_CH, |
| + BSS_CRIT_UPDATE_EVENT_VHT_OPERATION, |
| + BSS_CRIT_UPDATE_EVENT_HE_OPERATION, |
| + BSS_CRIT_UPDATE_EVENT_BCAST_TWT, |
| + BSS_CRIT_UPDATE_EVENT_BCAST_TWT_PARAM_SET, |
| + BSS_CRIT_UPDATE_EVENT_CCA, |
| + BSS_CRIT_UPDATE_EVENT_MU_EDCA, |
| + BSS_CRIT_UPDATE_EVENT_SR, |
| + BSS_CRIT_UPDATE_EVENT_UORA, |
| + BSS_CRIT_UPDATE_EVENT_IDX_ADJUST_FACTOR, |
| + BSS_CRIT_UPDATE_EVENT_EHT_OPERATION, |
| + BSS_CRIT_UPDATE_EVENT_TPE, |
| + BSS_CRIT_UPDATE_EVENT_CH_CHANGED, |
| + BSS_CRIT_UPDATE_EVENT_RECONFIG, |
| + BSS_CRIT_UPDATE_EVENT_ADD_LINK, |
| + BSS_CRIT_UPDATE_EVENT_ATTLM |
| +}; |
| + |
| +enum { |
| + BSS_CRIT_UPDATE_NONE, |
| + BSS_CRIT_UPDATE_SINGLE, |
| + BSS_CRIT_UPDATE_ALL, |
| + BSS_CRIT_UPDATE_FLAG |
| +}; |
| + |
| void handle_probe_req(struct hostapd_data *hapd, |
| const struct ieee80211_mgmt *mgmt, size_t len, |
| int ssi_signal); |
| void ieee802_11_set_beacon_per_bss_only(struct hostapd_data *hapd); |
| int ieee802_11_set_beacon(struct hostapd_data *hapd); |
| int ieee802_11_set_beacons(struct hostapd_iface *iface); |
| +int ieee802_11_set_bss_critical_update(struct hostapd_data *hapd, |
| + enum bss_crit_update_event event); |
| int ieee802_11_update_beacons(struct hostapd_iface *iface); |
| int ieee802_11_build_ap_params(struct hostapd_data *hapd, |
| struct wpa_driver_ap_params *params); |
| diff --git a/src/ap/dfs.c b/src/ap/dfs.c |
| index fc7699973..697e6364c 100644 |
| --- a/src/ap/dfs.c |
| +++ b/src/ap/dfs.c |
| @@ -1120,6 +1120,18 @@ static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface, |
| err = hostapd_switch_channel(iface->bss[i], &csa_settings); |
| if (err) |
| num_err++; |
| + |
| +#ifdef CONFIG_IEEE80211BE |
| + if (iface->bss[i]->conf->mld_ap) |
| + hostapd_update_aff_link_beacon(iface->bss[i], csa_settings.cs_count); |
| + |
| + /* |
| + * Currently, no FW notification event for clearing CU flag after DTIM period. |
| + * Also, another CU or set beacon is not allowed during CSA period. |
| + * Therefore, just clear it manually here for workaround. |
| + */ |
| + iface->bss[i]->eht_mld_bss_critical_update = 0; |
| +#endif /* CONFIG_IEEE80211BE */ |
| } |
| |
| if (num_err == iface->num_bss) { |
| diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c |
| index 1107fd70e..705acfb67 100644 |
| --- a/src/ap/drv_callbacks.c |
| +++ b/src/ap/drv_callbacks.c |
| @@ -1314,7 +1314,6 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, |
| if (hapd->csa_in_progress && |
| freq == hapd->cs_freq_params.freq) { |
| hostapd_cleanup_cs_params(hapd); |
| - ieee802_11_set_beacon(hapd); |
| |
| wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED |
| "freq=%d dfs=%d", freq, is_dfs); |
| diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c |
| index 2c9e54b23..f03a6242f 100644 |
| --- a/src/ap/hostapd.c |
| +++ b/src/ap/hostapd.c |
| @@ -4524,6 +4524,9 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd, |
| old_punct_bitmap = iface->conf->punct_bitmap; |
| iface->conf->punct_bitmap = settings->punct_bitmap; |
| #endif /* CONFIG_IEEE80211BE */ |
| + |
| + /* Another CU in the new channel due to OP element modification */ |
| + ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_EHT_OPERATION); |
| ret = hostapd_build_beacon_data(hapd, &settings->beacon_after); |
| |
| /* change back the configuration */ |
| @@ -4541,20 +4544,32 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd, |
| hapd->cs_count = settings->cs_count; |
| hapd->cs_block_tx = settings->block_tx; |
| |
| +#ifdef CONFIG_IEEE80211BE |
| + /* Restore BPCC to build the CSA beacon */ |
| + hapd->eht_mld_bss_param_change--; |
| + hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_ALL; |
| +#endif /* CONFIG_IEEE80211BE */ |
| + |
| ret = hostapd_build_beacon_data(hapd, &settings->beacon_csa); |
| if (ret) { |
| free_beacon_data(&settings->beacon_after); |
| return ret; |
| } |
| |
| + /* Change back to the final BPCC and CU flag */ |
| + ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_EHT_OPERATION); |
| + |
| settings->counter_offset_beacon[0] = hapd->cs_c_off_beacon; |
| settings->counter_offset_presp[0] = hapd->cs_c_off_proberesp; |
| settings->counter_offset_beacon[1] = hapd->cs_c_off_ecsa_beacon; |
| settings->counter_offset_presp[1] = hapd->cs_c_off_ecsa_proberesp; |
| settings->link_id = -1; |
| + settings->freq_params.link_id = -1; |
| #ifdef CONFIG_IEEE80211BE |
| - if (hapd->conf->mld_ap) |
| + if (hapd->conf->mld_ap) { |
| settings->link_id = hapd->mld_link_id; |
| + settings->freq_params.link_id = hapd->mld_link_id; |
| + } |
| #endif /* CONFIG_IEEE80211BE */ |
| |
| #ifdef CONFIG_IEEE80211AX |
| @@ -4616,6 +4631,8 @@ int hostapd_switch_channel(struct hostapd_data *hapd, |
| return -1; |
| } |
| |
| + ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_CSA); |
| + |
| ret = hostapd_fill_csa_settings(hapd, settings); |
| if (ret) |
| return ret; |
| @@ -4637,6 +4654,72 @@ int hostapd_switch_channel(struct hostapd_data *hapd, |
| return 0; |
| } |
| |
| +int hostapd_update_aff_link_beacon(struct hostapd_data *hapd, u8 cs_count) |
| +{ |
| + struct hostapd_data *h; |
| + unsigned int cs_link_id = hapd->mld_link_id; |
| + int cs_channel = hapd->cs_freq_params.channel; |
| + |
| + /* TODO: add beacon offload driver flag */ |
| + for_each_mld_link(h, hapd) { |
| + struct hostapd_config *conf = h->iconf; |
| + struct hostapd_hw_modes *mode = h->iface->current_mode; |
| + struct csa_settings settings = {}; |
| + unsigned int link_id = h->mld_link_id; |
| + int ret; |
| + |
| + if (!h->started || h == hapd) |
| + continue; |
| + |
| + hostapd_set_freq_params(&settings.freq_params, conf->hw_mode, |
| + hostapd_hw_get_freq(h, conf->channel), |
| + conf->channel, conf->enable_edmg, |
| + conf->edmg_channel, conf->ieee80211n, |
| + conf->ieee80211ac, conf->ieee80211ax, |
| + conf->ieee80211be, conf->secondary_channel, |
| + hostapd_get_oper_chwidth(conf), |
| + hostapd_get_oper_centr_freq_seg0_idx(conf), |
| + hostapd_get_oper_centr_freq_seg1_idx(conf), |
| + conf->vht_capab, |
| + mode ? &mode->he_capab[IEEE80211_MODE_AP] : NULL, |
| + mode ? &mode->eht_capab[IEEE80211_MODE_AP] : NULL, |
| + hostapd_get_punct_bitmap(h)); |
| + hapd->cs_freq_params.channel = 0; |
| + ret = hostapd_build_beacon_data(h, &settings.beacon_after); |
| + if (ret) |
| + return ret; |
| + |
| + hapd->cs_freq_params.channel = cs_channel; |
| + /* Restore BPCC to build the RNR for the CS link */ |
| + hapd->eht_mld_bss_param_change--; |
| + hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_ALL; |
| + ret = hostapd_build_beacon_data(h, &settings.beacon_csa); |
| + if (ret) { |
| + free_beacon_data(&settings.beacon_after); |
| + return ret; |
| + } |
| + |
| + /* Change back to the final BPCC and CU flag */ |
| + ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_EHT_OPERATION); |
| + |
| + settings.counter_offset_sta_prof[cs_link_id][0] = |
| + h->cs_c_off_sta_prof[cs_link_id]; |
| + settings.counter_offset_sta_prof[cs_link_id][1] = |
| + h->cs_c_off_ecsa_sta_prof[cs_link_id]; |
| + settings.link_id = cs_link_id; |
| + settings.freq_params.link_id = link_id; |
| + settings.cs_count = cs_count; |
| + settings.punct_bitmap = conf->punct_bitmap; |
| + ret = hostapd_drv_switch_channel(h, &settings); |
| + free_beacon_data(&settings.beacon_csa); |
| + free_beacon_data(&settings.beacon_after); |
| + if (ret) |
| + return ret; |
| + } |
| + |
| + return 0; |
| +} |
| + |
| |
| void |
| hostapd_switch_channel_fallback(struct hostapd_iface *iface, |
| diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h |
| index 4db67096b..99d5a01d6 100644 |
| --- a/src/ap/hostapd.h |
| +++ b/src/ap/hostapd.h |
| @@ -342,6 +342,9 @@ struct hostapd_data { |
| unsigned int cs_c_off_ecsa_beacon; |
| unsigned int cs_c_off_ecsa_proberesp; |
| |
| + unsigned int cs_c_off_sta_prof[MAX_NUM_MLD_LINKS]; |
| + unsigned int cs_c_off_ecsa_sta_prof[MAX_NUM_MLD_LINKS]; |
| + |
| #ifdef CONFIG_IEEE80211AX |
| bool cca_in_progress; |
| u8 cca_count; |
| @@ -501,6 +504,7 @@ struct hostapd_data { |
| |
| #ifdef CONFIG_IEEE80211BE |
| u8 eht_mld_bss_param_change; |
| + u8 eht_mld_bss_critical_update; |
| struct hostapd_mld *mld; |
| struct dl_list link; |
| u8 mld_link_id; |
| @@ -850,6 +854,7 @@ void hostapd_chan_switch_config(struct hostapd_data *hapd, |
| struct hostapd_freq_params *freq_params); |
| int hostapd_switch_channel(struct hostapd_data *hapd, |
| struct csa_settings *settings); |
| +int hostapd_update_aff_link_beacon(struct hostapd_data *hapd, u8 cs_count); |
| void |
| hostapd_switch_channel_fallback(struct hostapd_iface *iface, |
| const struct hostapd_freq_params *freq_params); |
| diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c |
| index 1365bc822..bb508fe79 100644 |
| --- a/src/ap/ieee802_11.c |
| +++ b/src/ap/ieee802_11.c |
| @@ -282,6 +282,7 @@ u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid, |
| |
| u16 hostapd_own_capab_info(struct hostapd_data *hapd) |
| { |
| + struct hostapd_data *h; |
| int capab = WLAN_CAPABILITY_ESS; |
| int privacy = 0; |
| int dfs; |
| @@ -342,6 +343,18 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd) |
| } |
| } |
| |
| +#ifdef CONFIG_IEEE80211BE |
| + if (hapd->conf->mld_ap) { |
| + for_each_mld_link(h, hapd) { |
| + if (h->eht_mld_bss_critical_update) { |
| + capab |= WLAN_CAPABILITY_PBCC; |
| + break; |
| + } |
| + } |
| + } |
| +#endif /* CONFIG_IEEE80211BE */ |
| + |
| + |
| return capab; |
| } |
| |
| @@ -7838,6 +7851,8 @@ static bool hostapd_eid_rnr_bss(struct hostapd_data *hapd, |
| (MAX_NUM_MLD_LINKS | 0xF0); |
| /* BPCC (Bit 3 to Bit 0) */ |
| *eid = is_partner ? ((param_ch & 0xF0) >> 4) : 0x0F; |
| + if (bss->eht_mld_bss_critical_update == BSS_CRIT_UPDATE_ALL) |
| + *eid |= RNR_TBTT_INFO_MLD_PARAM2_ALL_UPDATE_INC; |
| #ifdef CONFIG_TESTING_OPTIONS |
| if (bss->conf->mld_indicate_disabled) |
| *eid |= RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED; |
| diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c |
| index a04eb23e0..2b5c06d6d 100644 |
| --- a/src/ap/ieee802_11_eht.c |
| +++ b/src/ap/ieee802_11_eht.c |
| @@ -495,7 +495,7 @@ static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd, |
| wpabuf_put_u8(buf, hapd->mld_link_id); |
| |
| /* Currently hard code the BSS Parameters Change Count to 0x1 */ |
| - wpabuf_put_u8(buf, 0x1); |
| + wpabuf_put_u8(buf, hapd->eht_mld_bss_param_change); |
| |
| wpa_printf(MSG_DEBUG, "MLD: EML Capabilities=0x%x", |
| hapd->iface->mld_eml_capa); |
| @@ -593,11 +593,14 @@ static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd, |
| wpabuf_put_u8(buf, link_bss->conf->dtim_period); |
| |
| /* BSS Parameters Change Count */ |
| - wpabuf_put_u8(buf, hapd->eht_mld_bss_param_change); |
| + wpabuf_put_u8(buf, link_bss->eht_mld_bss_param_change); |
| |
| if (!link->resp_sta_profile) |
| continue; |
| |
| +#define EXT_EID_TAG_LEN 3 |
| + link->sta_prof_offset = wpabuf_len(buf) + EXT_EID_TAG_LEN; |
| + |
| /* Fragment the sub element if needed */ |
| if (total_len <= 255) { |
| wpabuf_put_data(buf, link->resp_sta_profile, |
| diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h |
| index 67b97671a..60b33f049 100644 |
| --- a/src/ap/sta_info.h |
| +++ b/src/ap/sta_info.h |
| @@ -89,6 +89,12 @@ struct mld_info { |
| u16 status; |
| u16 resp_sta_profile_len; |
| u8 *resp_sta_profile; |
| + |
| + u32 sta_prof_csa_offset; |
| + u32 sta_prof_ecsa_offset; |
| + u32 sta_prof_offset; |
| + |
| + const u8 *rsne, *rsnxe; |
| } links[MAX_NUM_MLD_LINKS]; |
| }; |
| |
| diff --git a/src/ap/ucode.c b/src/ap/ucode.c |
| index da1c4c1ac..a72193282 100644 |
| --- a/src/ap/ucode.c |
| +++ b/src/ap/ucode.c |
| @@ -738,9 +738,16 @@ uc_hostapd_iface_switch_channel(uc_vm_t *vm, size_t nargs) |
| wpa_printf(MSG_INFO, " * center_freq2 is %d\n", |
| csa.freq_params.center_freq2); |
| |
| - for (i = 0; i < iface->num_bss; i++) |
| + for (i = 0; i < iface->num_bss; i++) { |
| ret = hostapd_switch_channel(iface->bss[i], &csa); |
| |
| + if (iface->bss[i]->conf->mld_ap) |
| + hostapd_update_aff_link_beacon(iface->bss[i], csa.cs_count); |
| + |
| + /* FIXME: remove this line after CU event merged */ |
| + iface->bss[i]->eht_mld_bss_critical_update = 0; |
| + } |
| + |
| return ucv_boolean_new(!ret); |
| } |
| |
| diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h |
| index c380d0c7e..efb584c66 100644 |
| --- a/src/common/ieee802_11_defs.h |
| +++ b/src/common/ieee802_11_defs.h |
| @@ -504,6 +504,7 @@ |
| #define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38 |
| #define WLAN_EID_EXT_SPATIAL_REUSE 39 |
| #define WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT 42 |
| +#define WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME 52 |
| #define WLAN_EID_EXT_OCV_OCI 54 |
| #define WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION 55 |
| #define WLAN_EID_EXT_NON_INHERITANCE 56 |
| diff --git a/src/drivers/driver.h b/src/drivers/driver.h |
| index b75580374..924a1baba 100644 |
| --- a/src/drivers/driver.h |
| +++ b/src/drivers/driver.h |
| @@ -2763,6 +2763,7 @@ struct csa_settings { |
| |
| u16 counter_offset_beacon[2]; |
| u16 counter_offset_presp[2]; |
| + u16 counter_offset_sta_prof[MAX_NUM_MLD_LINKS][2]; |
| |
| u16 punct_bitmap; |
| int link_id; |
| diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c |
| index 8b64c3983..555c97bf7 100644 |
| --- a/src/drivers/driver_nl80211.c |
| +++ b/src/drivers/driver_nl80211.c |
| @@ -11417,9 +11417,10 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) |
| struct i802_bss *bss = priv; |
| struct wpa_driver_nl80211_data *drv = bss->drv; |
| struct nlattr *beacon_csa; |
| - int ret = -ENOBUFS; |
| - int csa_off_len = 0; |
| - int i; |
| + int i, csa_off_len = 0, ret = -ENOBUFS; |
| + unsigned int cs_link_id = settings->link_id; |
| + u16 *counter_offset_beacon = settings->counter_offset_beacon; |
| + u16 *counter_offset_presp = settings->counter_offset_presp; |
| |
| wpa_printf(MSG_DEBUG, |
| "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)", |
| @@ -11431,7 +11432,7 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) |
| settings->freq_params.center_freq1, |
| settings->freq_params.center_freq2, |
| settings->punct_bitmap, |
| - settings->link_id, |
| + settings->freq_params.link_id, |
| settings->freq_params.ht_enabled ? " ht" : "", |
| settings->freq_params.vht_enabled ? " vht" : "", |
| settings->freq_params.he_enabled ? " he" : ""); |
| @@ -11451,18 +11452,19 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) |
| * counters match. This implementation assumes that there are only two |
| * counters. |
| */ |
| - if (settings->counter_offset_beacon[0] && |
| - !settings->counter_offset_beacon[1]) { |
| + if (cs_link_id != settings->freq_params.link_id) { |
| + counter_offset_beacon = settings->counter_offset_sta_prof[cs_link_id]; |
| + counter_offset_presp = NULL; |
| + } |
| + |
| + if (counter_offset_beacon[0] && !counter_offset_beacon[1]) { |
| csa_off_len = 1; |
| - } else if (settings->counter_offset_beacon[1] && |
| - !settings->counter_offset_beacon[0]) { |
| + } else if (counter_offset_beacon[1] && !counter_offset_beacon[0]) { |
| csa_off_len = 1; |
| - settings->counter_offset_beacon[0] = |
| - settings->counter_offset_beacon[1]; |
| - settings->counter_offset_presp[0] = |
| - settings->counter_offset_presp[1]; |
| - } else if (settings->counter_offset_beacon[1] && |
| - settings->counter_offset_beacon[0]) { |
| + counter_offset_beacon[0] = counter_offset_beacon[1]; |
| + if (counter_offset_presp) |
| + counter_offset_presp[0] = counter_offset_presp[1]; |
| + } else if (counter_offset_beacon[1] && counter_offset_beacon[0]) { |
| csa_off_len = 2; |
| } else { |
| wpa_printf(MSG_ERROR, "nl80211: No CSA counters provided"); |
| @@ -11481,14 +11483,18 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) |
| return -EINVAL; |
| |
| for (i = 0; i < csa_off_len; i++) { |
| - u16 csa_c_off_bcn = settings->counter_offset_beacon[i]; |
| - u16 csa_c_off_presp = settings->counter_offset_presp[i]; |
| + u16 csa_c_off_bcn = counter_offset_beacon[i]; |
| + u16 csa_c_off_presp; |
| |
| if ((settings->beacon_csa.tail_len <= csa_c_off_bcn) || |
| (settings->beacon_csa.tail[csa_c_off_bcn] != |
| settings->cs_count)) |
| return -EINVAL; |
| |
| + if (!counter_offset_presp) |
| + continue; |
| + |
| + csa_c_off_presp = counter_offset_presp[i]; |
| if (settings->beacon_csa.probe_resp && |
| ((settings->beacon_csa.probe_resp_len <= |
| csa_c_off_presp) || |
| @@ -11506,8 +11512,8 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) |
| (settings->punct_bitmap && |
| nla_put_u32(msg, NL80211_ATTR_PUNCT_BITMAP, |
| settings->punct_bitmap)) || |
| - (settings->link_id != NL80211_DRV_LINK_ID_NA && |
| - nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, settings->link_id))) |
| + (settings->freq_params.link_id != NL80211_DRV_LINK_ID_NA && |
| + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, settings->freq_params.link_id))) |
| goto error; |
| |
| /* beacon_after params */ |
| @@ -11528,9 +11534,14 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) |
| if (ret) |
| goto error; |
| |
| - if (nla_put(msg, NL80211_ATTR_CSA_C_OFF_BEACON, |
| - csa_off_len * sizeof(u16), |
| - settings->counter_offset_beacon) || |
| + if ((cs_link_id == settings->freq_params.link_id && |
| + nla_put(msg, NL80211_ATTR_CSA_C_OFF_BEACON, |
| + csa_off_len * sizeof(u16), |
| + settings->counter_offset_beacon)) || |
| + (cs_link_id != settings->freq_params.link_id && |
| + nla_put(msg, NL80211_ATTR_CSA_C_OFF_STA_PROF, |
| + csa_off_len * sizeof(u16), |
| + settings->counter_offset_sta_prof[cs_link_id])) || |
| (settings->beacon_csa.probe_resp && |
| nla_put(msg, NL80211_ATTR_CSA_C_OFF_PRESP, |
| csa_off_len * sizeof(u16), |
| diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h |
| index d425c797c..13837297c 100644 |
| --- a/src/drivers/nl80211_copy.h |
| +++ b/src/drivers/nl80211_copy.h |
| @@ -2868,6 +2868,10 @@ enum nl80211_commands { |
| * nested item, it contains attributes defined in |
| * &enum nl80211_if_combination_attrs. |
| * |
| + * @NL80211_ATTR_CNTDWN_OFFS_STA_PROF: An array of offsets (u16) to the channel |
| + * switch or color change counters in the per-STA profile corresponding to |
| + * the affected AP. |
| + * |
| * @NUM_NL80211_ATTR: total number of nl80211_attrs available |
| * @NL80211_ATTR_MAX: highest attribute number currently defined |
| * @__NL80211_ATTR_AFTER_LAST: internal use |
| @@ -3418,6 +3422,9 @@ enum nl80211_attrs { |
| |
| /* add attributes here, update the policy in nl80211.c */ |
| |
| + /* MTK internal */ |
| + NL80211_ATTR_CNTDWN_OFFS_STA_PROF, |
| + |
| __NL80211_ATTR_AFTER_LAST, |
| NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST, |
| NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 |
| @@ -3430,6 +3437,7 @@ enum nl80211_attrs { |
| #define NL80211_ATTR_SAE_DATA NL80211_ATTR_AUTH_DATA |
| #define NL80211_ATTR_CSA_C_OFF_BEACON NL80211_ATTR_CNTDWN_OFFS_BEACON |
| #define NL80211_ATTR_CSA_C_OFF_PRESP NL80211_ATTR_CNTDWN_OFFS_PRESP |
| +#define NL80211_ATTR_CSA_C_OFF_STA_PROF NL80211_ATTR_CNTDWN_OFFS_STA_PROF |
| |
| /* |
| * Allow user space programs to use #ifdef on new attributes by defining them |
| -- |
| 2.18.0 |
| |