diff options
author | Xin Li <delphij@google.com> | 2023-12-08 13:14:08 -0800 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2023-12-08 13:14:08 -0800 |
commit | b7505b0d3261cd27551d0788f12e0fb713988996 (patch) | |
tree | fb24e508615cdd9f6914bd2311811aa13ca19e37 | |
parent | 6d755ae3182b871a753223d842aeed5e5f1002b8 (diff) | |
parent | cdf2037de91eaa5e8f9b1a119ee4efb55893174e (diff) | |
download | wpa_supplicant_8-b7505b0d3261cd27551d0788f12e0fb713988996.tar.gz |
Merge Android 14 QPR1
Merged-In: I53d14bd9e3f02b5ae467a8607229144614692b7c
Bug: 315507370
Change-Id: I17a39d1e711b7cf5fd6963c54f967c9f205bf923
65 files changed, 1735 insertions, 219 deletions
diff --git a/hostapd/aidl/hostapd.cpp b/hostapd/aidl/hostapd.cpp index b313e549..a0365404 100644 --- a/hostapd/aidl/hostapd.cpp +++ b/hostapd/aidl/hostapd.cpp @@ -373,23 +373,46 @@ std::string CreateHostapdConfig( WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) { return ""; } - encryption_config_as_string = StringPrintf( - "wpa=2\n" - "rsn_pairwise=%s\n" - "wpa_key_mgmt=%s\n" - "ieee80211w=1\n" - "sae_require_mfp=1\n" - "wpa_passphrase=%s\n" - "sae_password=%s", - is_60Ghz_band_only ? "GCMP" : "CCMP", + // WPA3 transition mode or SAE+WPA_PSK key management(AKM) is not allowed in 6GHz. + // Auto-convert any such configurations to SAE. + if ((band & band6Ghz) != 0) { + wpa_printf(MSG_INFO, "WPA3_SAE_TRANSITION configured in 6GHz band." + "Enable only SAE in key_mgmt"); + encryption_config_as_string = StringPrintf( + "wpa=2\n" + "rsn_pairwise=CCMP\n" + "wpa_key_mgmt=%s\n" + "ieee80211w=2\n" + "sae_require_mfp=2\n" + "sae_pwe=%d\n" + "sae_password=%s", #ifdef CONFIG_IEEE80211BE - iface_params.hwModeParams.enable80211BE ? - "WPA-PSK SAE SAE-EXT-KEY" : "WPA-PSK SAE", + iface_params.hwModeParams.enable80211BE ? + "SAE SAE-EXT-KEY" : "SAE", #else - "WPA-PSK SAE", + "SAE", #endif - nw_params.passphrase.c_str(), - nw_params.passphrase.c_str()); + is_6Ghz_band_only ? 1 : 2, + nw_params.passphrase.c_str()); + } else { + encryption_config_as_string = StringPrintf( + "wpa=2\n" + "rsn_pairwise=%s\n" + "wpa_key_mgmt=%s\n" + "ieee80211w=1\n" + "sae_require_mfp=1\n" + "wpa_passphrase=%s\n" + "sae_password=%s", + is_60Ghz_band_only ? "GCMP" : "CCMP", +#ifdef CONFIG_IEEE80211BE + iface_params.hwModeParams.enable80211BE ? + "WPA-PSK SAE SAE-EXT-KEY" : "WPA-PSK SAE", +#else + "WPA-PSK SAE", +#endif + nw_params.passphrase.c_str(), + nw_params.passphrase.c_str()); + } break; case EncryptionType::WPA3_SAE: if (!validatePassphrase(nw_params.passphrase.size(), 1, -1)) { diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 17b1b4a6..580e41c9 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -4738,6 +4738,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, } } else if (os_strcmp(buf, "pasn_comeback_after") == 0) { bss->pasn_comeback_after = atoi(pos); + } else if (os_strcmp(buf, "pasn_noauth") == 0) { + bss->pasn_noauth = atoi(pos); #endif /* CONFIG_PASN */ } else if (os_strcmp(buf, "ext_capa_mask") == 0) { if (get_hex_config(bss->ext_capa_mask, EXT_CAPA_MAX_LEN, diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index ea9c4444..b46d9210 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -2550,6 +2550,36 @@ static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params, return -1; } break; + case 320: + if (!params->center_freq1 || params->center_freq2 || + !params->sec_channel_offset) + return -1; + + switch (params->sec_channel_offset) { + case 1: + if (params->freq + 150 != params->center_freq1 && + params->freq + 110 != params->center_freq1 && + params->freq + 70 != params->center_freq1 && + params->freq + 30 != params->center_freq1 && + params->freq - 10 != params->center_freq1 && + params->freq - 50 != params->center_freq1 && + params->freq - 90 != params->center_freq1 && + params->freq - 130 != params->center_freq1) + return -1; + break; + case -1: + if (params->freq + 130 != params->center_freq1 && + params->freq + 90 != params->center_freq1 && + params->freq + 50 != params->center_freq1 && + params->freq + 10 != params->center_freq1 && + params->freq - 30 != params->center_freq1 && + params->freq - 70 != params->center_freq1 && + params->freq - 110 != params->center_freq1 && + params->freq - 150 != params->center_freq1) + return -1; + break; + } + break; default: return -1; } diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index bc4a0f6e..5868bfde 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -2170,6 +2170,11 @@ own_ip_addr=127.0.0.1 # (default: 10 TUs) #pasn_comeback_after=10 +# Unauthenticated PASN activated (dot11NoAuthPASNActivated) +# This indicates whether PASN without mutual authentication is allowed. +# (default: 1 = activated) +#pasn_noauth=1 + ##### IEEE 802.11r configuration ############################################## # Mobility Domain identifier (dot11FTMobilityDomainID, MDID) diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index 95edea87..646dfc59 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1529,7 +1529,7 @@ static int hostapd_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc, static int hostapd_cli_cmd_dpp_push_button(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - return hostapd_cli_cmd(ctrl, "DPP_PUSH_BUTTON", 1, argc, argv); + return hostapd_cli_cmd(ctrl, "DPP_PUSH_BUTTON", 0, argc, argv); } #endif /* CONFIG_DPP3 */ #endif /* CONFIG_DPP */ diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index b5fcc383..c3ee5067 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -169,6 +169,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) #ifdef CONFIG_PASN /* comeback after 10 TUs */ bss->pasn_comeback_after = 10; + bss->pasn_noauth = 1; #endif /* CONFIG_PASN */ } diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 07ee31c4..def5fd56 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -906,6 +906,9 @@ struct hostapd_bss_config { #endif /* CONFIG_MACSEC */ #ifdef CONFIG_PASN + /* Whether to allow PASN-UNAUTH */ + int pasn_noauth; + #ifdef CONFIG_TESTING_OPTIONS /* * Normally, KDK should be derived if and only if both sides support diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index f77f738e..aa4dbe9e 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -883,10 +883,10 @@ int hostapd_drv_set_qos_map(struct hostapd_data *hapd, } -static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd, - struct hostapd_hw_modes *mode, - int acs_ch_list_all, - int **freq_list) +void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd, + struct hostapd_hw_modes *mode, + int acs_ch_list_all, bool allow_disabled, + int **freq_list) { int i; @@ -912,7 +912,7 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd, (!hapd->iface->conf->ieee80211ax && !hapd->iface->conf->ieee80211be))) continue; - if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && + if ((!(chan->flag & HOSTAPD_CHAN_DISABLED) || allow_disabled) && !(hapd->iface->conf->acs_exclude_dfs && (chan->flag & HOSTAPD_CHAN_RADAR)) && !(chan->max_tx_power < hapd->iface->conf->min_tx_power)) @@ -969,7 +969,7 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd) selected_mode != mode->mode) continue; hostapd_get_hw_mode_any_channels(hapd, mode, acs_ch_list_all, - &freq_list); + false, &freq_list); } params.freq_list = freq_list; diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index 93b22449..023cbf1f 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -156,6 +156,11 @@ int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set, void hostapd_get_ext_capa(struct hostapd_iface *iface); +void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd, + struct hostapd_hw_modes *mode, + int acs_ch_list_all, bool allow_disabled, + int **freq_list); + static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd, int enabled) { diff --git a/src/ap/beacon.c b/src/ap/beacon.c index c25a5bbc..de944fed 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -468,8 +468,9 @@ ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd, { struct hostapd_iface *iface = hapd->iface; struct hostapd_data *tx_bss; - size_t len; + size_t len, rnr_len = 0; u8 elem_count = 0, *elem = NULL, **elem_offset = NULL, *end; + u8 rnr_elem_count = 0, *rnr_elem = NULL, **rnr_elem_offset = NULL; if (!iface->mbssid_max_interfaces || iface->num_bss > iface->mbssid_max_interfaces || @@ -479,7 +480,7 @@ ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd, tx_bss = hostapd_mbssid_get_tx_bss(hapd); len = hostapd_eid_mbssid_len(tx_bss, WLAN_FC_STYPE_BEACON, &elem_count, - NULL, 0); + NULL, 0, &rnr_len); if (!len || (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED && elem_count > iface->ema_max_periodicity)) goto fail; @@ -492,8 +493,19 @@ ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd, if (!elem_offset) goto fail; + if (rnr_len) { + rnr_elem = os_zalloc(rnr_len); + if (!rnr_elem) + goto fail; + + rnr_elem_offset = os_calloc(elem_count + 1, sizeof(u8 *)); + if (!rnr_elem_offset) + goto fail; + } + end = hostapd_eid_mbssid(tx_bss, elem, elem + len, WLAN_FC_STYPE_BEACON, - elem_count, elem_offset, NULL, 0); + elem_count, elem_offset, NULL, 0, rnr_elem, + &rnr_elem_count, rnr_elem_offset, rnr_len); params->mbssid_tx_iface = tx_bss->conf->iface; params->mbssid_index = hostapd_mbssid_get_bss_index(hapd); @@ -501,12 +513,19 @@ ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd, params->mbssid_elem_len = end - elem; params->mbssid_elem_count = elem_count; params->mbssid_elem_offset = elem_offset; + params->rnr_elem = rnr_elem; + params->rnr_elem_len = rnr_len; + params->rnr_elem_count = rnr_elem_count; + params->rnr_elem_offset = rnr_elem_offset; if (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED) params->ema = true; return 0; fail: + os_free(rnr_elem); + os_free(rnr_elem_offset); + os_free(elem_offset); os_free(elem); wpa_printf(MSG_ERROR, "MBSSID: Configuration failed"); return -1; @@ -590,7 +609,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, #endif /* CONFIG_IEEE80211BE */ buflen += hostapd_eid_mbssid_len(hapd, WLAN_FC_STYPE_PROBE_RESP, NULL, - known_bss, known_bss_len); + known_bss, known_bss_len, NULL); buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP); buflen += hostapd_mbo_ie_len(hapd); buflen += hostapd_eid_owe_trans_len(hapd); @@ -658,7 +677,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos = hostapd_get_rsne(hapd, pos, epos - pos); pos = hostapd_eid_bss_load(hapd, pos, epos - pos); pos = hostapd_eid_mbssid(hapd, pos, epos, WLAN_FC_STYPE_PROBE_RESP, 0, - NULL, known_bss, known_bss_len); + NULL, known_bss, known_bss_len, NULL, NULL, + NULL, 0); pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos); pos = hostapd_get_mde(hapd, pos, epos - pos); @@ -2026,6 +2046,10 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params) params->mbssid_elem = NULL; os_free(params->mbssid_elem_offset); params->mbssid_elem_offset = NULL; + os_free(params->rnr_elem); + params->rnr_elem = NULL; + os_free(params->rnr_elem_offset); + params->rnr_elem_offset = NULL; #ifdef CONFIG_FILS os_free(params->fd_frame_tmpl); params->fd_frame_tmpl = NULL; @@ -2034,6 +2058,8 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params) os_free(params->unsol_bcast_probe_resp_tmpl); params->unsol_bcast_probe_resp_tmpl = NULL; #endif /* CONFIG_IEEE80211AX */ + os_free(params->allowed_freqs); + params->allowed_freqs = NULL; } @@ -2045,7 +2071,8 @@ static int __ieee802_11_set_beacon(struct hostapd_data *hapd) struct hostapd_config *iconf = iface->conf; struct hostapd_hw_modes *cmode = iface->current_mode; struct wpabuf *beacon, *proberesp, *assocresp; - int res, ret = -1; + int res, ret = -1, i; + struct hostapd_hw_modes *mode; if (!hapd->drv_priv) { wpa_printf(MSG_ERROR, "Interface is disabled"); @@ -2120,6 +2147,19 @@ static int __ieee802_11_set_beacon(struct hostapd_data *hapd) &cmode->eht_capab[IEEE80211_MODE_AP]) == 0) params.freq = &freq; + for (i = 0; i < hapd->iface->num_hw_features; i++) { + mode = &hapd->iface->hw_features[i]; + + if (iconf->hw_mode != HOSTAPD_MODE_IEEE80211ANY && + iconf->hw_mode != mode->mode) + continue; + + hostapd_get_hw_mode_any_channels(hapd, mode, + !(iconf->acs_freq_list.num || + iconf->acs_ch_list.num), + true, ¶ms.allowed_freqs); + } + res = hostapd_drv_set_ap(hapd, ¶ms); hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); if (res) diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 8fc128e9..510a06c6 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -978,7 +978,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, hapd->iconf->ch_switch_eht_config = 0; if (width == CHAN_WIDTH_40 || width == CHAN_WIDTH_80 || - width == CHAN_WIDTH_80P80 || width == CHAN_WIDTH_160) + width == CHAN_WIDTH_80P80 || width == CHAN_WIDTH_160 || + width == CHAN_WIDTH_320) hapd->iconf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; else if (width == CHAN_WIDTH_20 || width == CHAN_WIDTH_20_NOHT) hapd->iconf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 8b3fb404..112e6fad 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -1476,11 +1476,11 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first, return -1; } - if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0) + if (start_beacon && hostapd_start_beacon(hapd, flush_old_stations) < 0) return -1; - if (start_beacon) - return hostapd_start_beacon(hapd, flush_old_stations); + if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0) + return -1; return 0; } @@ -1756,16 +1756,15 @@ static int configured_fixed_chan_to_freq(struct hostapd_iface *iface) static void hostapd_set_6ghz_sec_chan(struct hostapd_iface *iface) { - int bw, seg0; + int bw; if (!is_6ghz_op_class(iface->conf->op_class)) return; - seg0 = hostapd_get_oper_centr_freq_seg0_idx(iface->conf); - bw = center_idx_to_bw_6ghz(seg0); + bw = op_class_to_bandwidth(iface->conf->op_class); /* Assign the secondary channel if absent in config for * bandwidths > 20 MHz */ - if (bw > 0 && !iface->conf->secondary_channel) { + if (bw >= 40 && !iface->conf->secondary_channel) { if (((iface->conf->channel - 1) / 4) % 2) iface->conf->secondary_channel = -1; else @@ -3340,7 +3339,6 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, return; } - hostapd_prune_associations(hapd, sta->addr); ap_sta_clear_disconnect_timeouts(hapd, sta); sta->post_csa_sa_query = 0; @@ -3602,6 +3600,7 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd, case 40: case 80: case 160: + case 320: conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; break; default: @@ -3674,6 +3673,9 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd, case 160: bandwidth = CONF_OPER_CHWIDTH_160MHZ; break; + case 320: + bandwidth = CONF_OPER_CHWIDTH_320MHZ; + break; default: bandwidth = CONF_OPER_CHWIDTH_USE_HT; break; diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index 842d9f5b..f836be48 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -1001,6 +1001,24 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface) } +static bool skip_mode(struct hostapd_iface *iface, + struct hostapd_hw_modes *mode) +{ + int chan; + + if (iface->freq > 0 && !hw_mode_get_channel(mode, iface->freq, &chan)) + return true; + + if (is_6ghz_op_class(iface->conf->op_class) && iface->freq == 0 && + (mode->mode != HOSTAPD_MODE_IEEE80211A || + mode->num_channels == 0 || + !is_6ghz_freq(mode->channels[0].freq))) + return true; + + return false; +} + + static void hostapd_determine_mode(struct hostapd_iface *iface) { int i; @@ -1022,6 +1040,9 @@ static void hostapd_determine_mode(struct hostapd_iface *iface) mode = &iface->hw_features[i]; if (mode->mode == target_mode) { + if (skip_mode(iface, mode)) + continue; + iface->current_mode = mode; iface->conf->hw_mode = mode->mode; break; @@ -1152,11 +1173,9 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) iface->current_mode = NULL; for (i = 0; i < iface->num_hw_features; i++) { struct hostapd_hw_modes *mode = &iface->hw_features[i]; - int chan; if (mode->mode == iface->conf->hw_mode) { - if (iface->freq > 0 && - !hw_mode_get_channel(mode, iface->freq, &chan)) + if (skip_mode(iface, mode)) continue; iface->current_mode = mode; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 0142ee44..93a6b4f5 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -2527,6 +2527,7 @@ static void hapd_initialize_pasn(struct hostapd_data *hapd, pasn->cb_ctx = hapd; pasn->send_mgmt = hapd_pasn_send_mlme; pasn->pasn_groups = hapd->conf->pasn_groups; + pasn->noauth = hapd->conf->pasn_noauth; pasn->wpa_key_mgmt = hapd->conf->wpa_key_mgmt; pasn->rsn_pairwise = hapd->conf->rsn_pairwise; pasn->derive_kdk = hapd->iface->drv_flags2 & @@ -3696,7 +3697,7 @@ static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, if (resp != WLAN_STATUS_SUCCESS) return resp; - resp = set_sta_vht_opmode(hapd, sta, elems->vht_opmode_notif); + resp = set_sta_vht_opmode(hapd, sta, elems->opmode_notif); if (resp != WLAN_STATUS_SUCCESS) return resp; } @@ -5758,7 +5759,11 @@ static void handle_assoc_cb(struct hostapd_data *hapd, sta->flags |= WLAN_STA_WDS; } - if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) { + /* WPS not supported on backhaul BSS. Disable 4addr mode on fronthaul */ + if ((sta->flags & WLAN_STA_WDS) || + (sta->flags & WLAN_STA_MULTI_AP && + !(hapd->conf->multi_ap & FRONTHAUL_BSS) && + !(sta->flags & WLAN_STA_WPS))) { int ret; char ifname_wds[IFNAMSIZ + 1]; @@ -6347,7 +6352,7 @@ u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid) !hapd->cs_freq_params.eht_enabled)) return eid; - /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */ + /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80, 4: 320 */ switch (hapd->cs_freq_params.bandwidth) { case 40: bw = 0; @@ -6362,6 +6367,9 @@ u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid) case 160: bw = 2; break; + case 320: + bw = 4; + break; default: /* not valid VHT bandwidth or not in CSA */ return eid; @@ -6379,9 +6387,9 @@ u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid) &chan2) != HOSTAPD_MODE_IEEE80211A) return eid; - *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER; + *eid++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER; *eid++ = 5; /* Length of Channel Switch Wrapper */ - *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH; + *eid++ = WLAN_EID_WIDE_BW_CHSWITCH; *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */ *eid++ = bw; /* New Channel Width */ *eid++ = chan1; /* New Channel Center Frequency Segment 0 */ @@ -6421,9 +6429,16 @@ static size_t hostapd_eid_nr_db_len(struct hostapd_data *hapd, } -static size_t hostapd_eid_rnr_iface_len(struct hostapd_data *hapd, - struct hostapd_data *reporting_hapd, - size_t *current_len) +struct mbssid_ie_profiles { + u8 start; + u8 end; +}; + +static size_t +hostapd_eid_rnr_iface_len(struct hostapd_data *hapd, + struct hostapd_data *reporting_hapd, + size_t *current_len, + struct mbssid_ie_profiles *skip_profiles) { size_t total_len = 0, len = *current_len; int tbtt_count = 0; @@ -6449,6 +6464,10 @@ static size_t hostapd_eid_rnr_iface_len(struct hostapd_data *hapd, bss->conf->ignore_broadcast_ssid) continue; + if (skip_profiles && + i >= skip_profiles->start && i < skip_profiles->end) + continue; + if (len + RNR_TBTT_INFO_LEN > 255 || tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) break; @@ -6527,7 +6546,7 @@ static size_t hostapd_eid_rnr_colocation_len(struct hostapd_data *hapd, continue; len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd, - current_len); + current_len, NULL); } return len; @@ -6550,15 +6569,18 @@ size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type) total_len += hostapd_eid_rnr_colocation_len( hapd, ¤t_len); - if (hapd->conf->rnr && hapd->iface->num_bss > 1) + if (hapd->conf->rnr && hapd->iface->num_bss > 1 && + !hapd->iconf->mbssid) total_len += hostapd_eid_rnr_iface_len(hapd, hapd, - ¤t_len); + ¤t_len, + NULL); break; case WLAN_FC_STYPE_ACTION: if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ) total_len += hostapd_eid_rnr_iface_len(hapd, hapd, - ¤t_len); + ¤t_len, + NULL); break; default: @@ -6626,7 +6648,8 @@ static u8 * hostapd_eid_nr_db(struct hostapd_data *hapd, u8 *eid, static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd, struct hostapd_data *reporting_hapd, - u8 *eid, size_t *current_len) + u8 *eid, size_t *current_len, + struct mbssid_ie_profiles *skip_profiles) { struct hostapd_data *bss; struct hostapd_iface *iface = hapd->iface; @@ -6671,6 +6694,10 @@ static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd, bss->conf->ignore_broadcast_ssid) continue; + if (skip_profiles && + i >= skip_profiles->start && i < skip_profiles->end) + continue; + if (len + RNR_TBTT_INFO_LEN > 255 || tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) break; @@ -6687,7 +6714,7 @@ static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd, if (iface->conf->mbssid != MBSSID_DISABLED && iface->num_bss > 1) { bss_param |= RNR_BSS_PARAM_MULTIPLE_BSSID; - if (i == 0) + if (bss == hostapd_mbssid_get_tx_bss(hapd)) bss_param |= RNR_BSS_PARAM_TRANSMITTED_BSSID; } @@ -6735,7 +6762,7 @@ static u8 * hostapd_eid_rnr_colocation(struct hostapd_data *hapd, u8 *eid, continue; eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid, - current_len); + current_len, NULL); } return eid; @@ -6759,15 +6786,16 @@ u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type) eid = hostapd_eid_rnr_colocation(hapd, eid, ¤t_len); - if (hapd->conf->rnr && hapd->iface->num_bss > 1) + if (hapd->conf->rnr && hapd->iface->num_bss > 1 && + !hapd->iconf->mbssid) eid = hostapd_eid_rnr_iface(hapd, hapd, eid, - ¤t_len); + ¤t_len, NULL); break; case WLAN_FC_STYPE_ACTION: if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ) eid = hostapd_eid_rnr_iface(hapd, hapd, eid, - ¤t_len); + ¤t_len, NULL); break; default: @@ -6856,7 +6884,7 @@ static size_t hostapd_eid_mbssid_elem_len(struct hostapd_data *hapd, size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type, u8 *elem_count, const u8 *known_bss, - size_t known_bss_len) + size_t known_bss_len, size_t *rnr_len) { size_t len = 0, bss_index = 1; @@ -6875,13 +6903,29 @@ size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type, } while (bss_index < hapd->iface->num_bss) { + size_t rnr_count = bss_index; + len += hostapd_eid_mbssid_elem_len(hapd, frame_type, &bss_index, known_bss, known_bss_len); if (frame_type == WLAN_FC_STYPE_BEACON) *elem_count += 1; + if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len) { + size_t rnr_cur_len = 0; + struct mbssid_ie_profiles skip_profiles = { + rnr_count, bss_index + }; + + *rnr_len += hostapd_eid_rnr_iface_len( + hapd, hostapd_mbssid_get_tx_bss(hapd), + &rnr_cur_len, &skip_profiles); + } } + + if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len) + *rnr_len += hostapd_eid_rnr_len(hapd, frame_type); + return len; } @@ -6993,10 +7037,12 @@ static u8 * hostapd_eid_mbssid_elem(struct hostapd_data *hapd, u8 *eid, u8 *end, u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end, unsigned int frame_stype, u8 elem_count, u8 **elem_offset, - const u8 *known_bss, size_t known_bss_len) + const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid, + u8 *rnr_count, u8 **rnr_offset, size_t rnr_len) { - size_t bss_index = 1; - u8 elem_index = 0; + size_t bss_index = 1, cur_len = 0; + u8 elem_index = 0, *rnr_start_eid = rnr_eid; + bool add_rnr; if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 || (frame_stype != WLAN_FC_STYPE_BEACON && @@ -7009,7 +7055,13 @@ u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end, return eid; } + add_rnr = hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && + frame_stype == WLAN_FC_STYPE_BEACON && + rnr_eid && rnr_count && rnr_offset && rnr_len; + while (bss_index < hapd->iface->num_bss) { + unsigned int rnr_start_count = bss_index; + if (frame_stype == WLAN_FC_STYPE_BEACON) { if (elem_index == elem_count) { wpa_printf(MSG_WARNING, @@ -7024,6 +7076,31 @@ u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end, hostapd_max_bssid_indicator(hapd), &bss_index, elem_count, known_bss, known_bss_len); + + if (add_rnr) { + struct mbssid_ie_profiles skip_profiles = { + rnr_start_count, bss_index + }; + + rnr_offset[*rnr_count] = rnr_eid; + *rnr_count = *rnr_count + 1; + cur_len = 0; + rnr_eid = hostapd_eid_rnr_iface( + hapd, hostapd_mbssid_get_tx_bss(hapd), + rnr_eid, &cur_len, &skip_profiles); + } + } + + if (add_rnr && (size_t) (rnr_eid - rnr_start_eid) < rnr_len) { + rnr_offset[*rnr_count] = rnr_eid; + *rnr_count = *rnr_count + 1; + cur_len = 0; + + if (hapd->conf->rnr) + rnr_eid = hostapd_eid_nr_db(hapd, rnr_eid, &cur_len); + if (get_colocation_mode(hapd) == COLOCATED_LOWER_BAND) + rnr_eid = hostapd_eid_rnr_colocation(hapd, rnr_eid, + &cur_len); } return eid; diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index 1e4c843f..1190a5ea 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -218,11 +218,12 @@ u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta, const u8 *eht_capab, size_t eht_capab_len); size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type, u8 *elem_count, const u8 *known_bss, - size_t known_bss_len); + size_t known_bss_len, size_t *rnr_len); u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end, unsigned int frame_stype, u8 elem_count, u8 **elem_offset, - const u8 *known_bss, size_t known_bss_len); + const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid, + u8 *rnr_count, u8 **rnr_offset, size_t rnr_len); void punct_update_legacy_bw(u16 bitmap, u8 pri_chan, enum oper_chan_width *width, u8 *seg0, u8 *seg1); diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 46a47d06..8b67669b 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -43,9 +43,9 @@ #ifdef CONFIG_HS20 static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx); #endif /* CONFIG_HS20 */ -static void ieee802_1x_finished(struct hostapd_data *hapd, +static bool ieee802_1x_finished(struct hostapd_data *hapd, struct sta_info *sta, int success, - int remediation); + int remediation, bool logoff); static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, @@ -2287,16 +2287,18 @@ static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx, } -static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success, - int preauth, int remediation) +static bool _ieee802_1x_finished(void *ctx, void *sta_ctx, int success, + int preauth, int remediation, bool logoff) { struct hostapd_data *hapd = ctx; struct sta_info *sta = sta_ctx; - if (preauth) + if (preauth) { rsn_preauth_finished(hapd, sta, success); - else - ieee802_1x_finished(hapd, sta, success, remediation); + return false; + } + + return ieee802_1x_finished(hapd, sta, success, remediation, logoff); } @@ -2977,9 +2979,9 @@ static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx) #endif /* CONFIG_HS20 */ -static void ieee802_1x_finished(struct hostapd_data *hapd, +static bool ieee802_1x_finished(struct hostapd_data *hapd, struct sta_info *sta, int success, - int remediation) + int remediation, bool logoff) { const u8 *key; size_t len; @@ -3039,6 +3041,11 @@ static void ieee802_1x_finished(struct hostapd_data *hapd, * EAP-FAST with anonymous provisioning, may require another * EAPOL authentication to be started to complete connection. */ - ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta); + ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta, + logoff ? 0 : 10); + if (logoff && sta->wpa_sm) + return true; } + + return false; } diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index 63f514c9..2fb6edf0 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -197,7 +197,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) ap_sta_set_authorized(hapd, sta, 0); hostapd_set_sta_flags(hapd, sta); - if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) + if ((sta->flags & WLAN_STA_WDS) || + (sta->flags & WLAN_STA_MULTI_AP && + !(hapd->conf->multi_ap & FRONTHAUL_BSS) && + !(sta->flags & WLAN_STA_WPS))) hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0); if (sta->ipaddr) @@ -1280,10 +1283,12 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED)) return; - if (authorized) + if (authorized) { + hostapd_prune_associations(hapd, sta->addr); sta->flags |= WLAN_STA_AUTHORIZED; - else + } else { sta->flags &= ~WLAN_STA_AUTHORIZED; + } #ifdef CONFIG_P2P if (hapd->p2p_group == NULL) { @@ -1536,11 +1541,12 @@ static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx) void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, - struct sta_info *sta) + struct sta_info *sta, + unsigned timeout) { wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force disconnection of " MACSTR - " after EAP-Failure in 10 ms", MAC2STR(sta->addr)); + " after EAP-Failure in %u ms", MAC2STR(sta->addr), timeout); /* * Add a small sleep to increase likelihood of previously requested @@ -1548,8 +1554,8 @@ void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, * operations. */ eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta); - eloop_register_timeout(0, 10000, ap_sta_delayed_1x_auth_fail_cb, - hapd, sta); + eloop_register_timeout(0, timeout * 1000, + ap_sta_delayed_1x_auth_fail_cb, hapd, sta); } diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index b59b7584..8433ff8d 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -373,7 +373,8 @@ void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd, int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen); void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, - struct sta_info *sta); + struct sta_info *sta, + unsigned timeout); int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, struct sta_info *sta); int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta); diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 35585cd9..2402ad92 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -3085,7 +3085,7 @@ static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, const u8 *r0kh_id, size_t r0kh_id_len, const u8 *req_pmk_r0_name, - const u8 *req_pmk_r1_name, + u8 *out_pmk_r1_name, u8 *out_pmk_r1, int *out_pairwise, struct vlan_description *vlan, const u8 **identity, size_t *identity_len, @@ -3096,7 +3096,6 @@ static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth, { struct wpa_auth_config *conf = &wpa_auth->conf; const struct wpa_ft_pmk_r0_sa *r0; - u8 pmk_r1_name[WPA_PMK_NAME_LEN]; int expires_in = 0; int session_timeout = 0; struct os_reltime now; @@ -3115,7 +3114,7 @@ static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth, if (wpa_derive_pmk_r1(r0->pmk_r0, r0->pmk_r0_len, r0->pmk_r0_name, conf->r1_key_holder, - sm->addr, out_pmk_r1, pmk_r1_name) < 0) + sm->addr, out_pmk_r1, out_pmk_r1_name) < 0) return -1; os_get_reltime(&now); @@ -3126,7 +3125,7 @@ static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth, session_timeout = r0->session_timeout - now.sec; wpa_ft_store_pmk_r1(wpa_auth, sm->addr, out_pmk_r1, r0->pmk_r0_len, - pmk_r1_name, + out_pmk_r1_name, sm->pairwise, r0->vlan, expires_in, session_timeout, r0->identity, r0->identity_len, r0->radius_cui, r0->radius_cui_len); diff --git a/src/common/defs.h b/src/common/defs.h index c0c6dbe8..aa3c5cfe 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -521,6 +521,11 @@ enum frame_encryption { #define MAX_NUM_MLD_LINKS 15 +enum mlo_info_change_reason { + MLO_TID_TO_LINK_MAP = 0, + MLO_LINK_RECONFIG_AP_REMOVAL = 1 +}; + enum sae_pwe { SAE_PWE_HUNT_AND_PECK = 0, SAE_PWE_HASH_TO_ELEMENT = 1, diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index cd1b198f..dcadfbe5 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -550,10 +550,10 @@ static ParseRes __ieee802_11_parse_elems(const u8 *start, size_t len, break; elems->vht_operation = pos; break; - case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION: + case WLAN_EID_OPERATING_MODE_NOTIFICATION: if (elen != 1) break; - elems->vht_opmode_notif = pos; + elems->opmode_notif = pos; break; case WLAN_EID_LINK_ID: if (elen < 18) @@ -777,8 +777,8 @@ void ieee802_11_elems_clear_ids(struct ieee802_11_elems *elems, case WLAN_EID_VHT_OPERATION: elems->vht_operation = NULL; break; - case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION: - elems->vht_opmode_notif = NULL; + case WLAN_EID_OPERATING_MODE_NOTIFICATION: + elems->opmode_notif = NULL; break; case WLAN_EID_LINK_ID: elems->link_id = NULL; @@ -1800,6 +1800,7 @@ static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan) static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan) { + /* Table E-3 in IEEE Std 802.11-2020 - Operating classes in Japan */ switch (op_class) { case 30: /* channels 1..13 */ case 56: /* channels 1..9; 40 MHz */ @@ -1823,14 +1824,14 @@ static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan) if (chan < 34 || chan > 64) return -1; return 5000 + 5 * chan; - case 34: /* channels 100-140 */ - case 35: /* channels 100-140 */ - case 39: /* channels 100-132; 40 MHz */ - case 40: /* channels 100-132; 40 MHz */ - case 44: /* channels 104-136; 40 MHz */ - case 45: /* channels 104-136; 40 MHz */ - case 58: /* channels 100-140 */ - if (chan < 100 || chan > 140) + case 34: /* channels 100-144 */ + case 35: /* reserved */ + case 39: /* channels 100-140; 40 MHz */ + case 40: /* reserved */ + case 44: /* channels 104-144; 40 MHz */ + case 45: /* reserved */ + case 58: /* channels 100-144 */ + if (chan < 100 || chan > 144) return -1; return 5000 + 5 * chan; case 59: /* 60 GHz band, channels 1..6 */ @@ -1884,7 +1885,7 @@ static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan) static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan) { - /* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */ + /* Table E-4 in IEEE Std 802.11-2020 - Global operating classes */ switch (op_class) { case 81: /* channels 1..13 */ @@ -1910,10 +1911,10 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan) if (chan < 36 || chan > 64) return -1; return 5000 + 5 * chan; - case 121: /* channels 100-140 */ - case 122: /* channels 100-142; 40 MHz */ - case 123: /* channels 104-136; 40 MHz */ - if (chan < 100 || chan > 140) + case 121: /* channels 100-144 */ + case 122: /* channels 100-140; 40 MHz */ + case 123: /* channels 104-144; 40 MHz */ + if (chan < 100 || chan > 144) return -1; return 5000 + 5 * chan; case 124: /* channels 149,153,157,161 */ @@ -2015,7 +2016,7 @@ int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes, if (!modes || !num_modes) return (freq >= 5260 && freq <= 5320) || - (freq >= 5500 && freq <= 5700); + (freq >= 5500 && freq <= 5720); for (i = 0; i < num_modes; i++) { for (j = 0; j < modes[i].num_channels; j++) { @@ -2388,9 +2389,9 @@ const struct oper_class_map global_op_class[] = { { HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 121, 100, 140, 4, BW20, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 122, 100, 132, 8, BW40PLUS, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 123, 104, 136, 8, BW40MINUS, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 121, 100, 144, 4, BW20, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 122, 100, 140, 8, BW40PLUS, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 123, 104, 144, 8, BW40MINUS, NO_P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 125, 149, 177, 4, BW20, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 126, 149, 173, 8, BW40PLUS, P2P_SUPP }, @@ -3065,10 +3066,10 @@ int op_class_to_bandwidth(u8 op_class) case 119: /* channels 52,60; 40 MHz; dfs */ case 120: /* channels 56,64; 40 MHz; dfs */ return 40; - case 121: /* channels 100-140 */ + case 121: /* channels 100-144 */ return 20; - case 122: /* channels 100-142; 40 MHz */ - case 123: /* channels 104-136; 40 MHz */ + case 122: /* channels 100-140; 40 MHz */ + case 123: /* channels 104-144; 40 MHz */ return 40; case 124: /* channels 149,153,157,161 */ case 125: /* channels 149,153,157,161,165,169,173,177 */ @@ -3128,10 +3129,10 @@ enum oper_chan_width op_class_to_ch_width(u8 op_class) case 119: /* channels 52,60; 40 MHz; dfs */ case 120: /* channels 56,64; 40 MHz; dfs */ return CONF_OPER_CHWIDTH_USE_HT; - case 121: /* channels 100-140 */ + case 121: /* channels 100-144 */ return CONF_OPER_CHWIDTH_USE_HT; - case 122: /* channels 100-142; 40 MHz */ - case 123: /* channels 104-136; 40 MHz */ + case 122: /* channels 100-140; 40 MHz */ + case 123: /* channels 104-144; 40 MHz */ return CONF_OPER_CHWIDTH_USE_HT; case 124: /* channels 149,153,157,161 */ case 125: /* channels 149,153,157,161,165,169,171 */ diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index d1f72184..c7afd347 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -55,7 +55,7 @@ struct ieee802_11_elems { const u8 *peer_mgmt; const u8 *vht_capabilities; const u8 *vht_operation; - const u8 *vht_opmode_notif; + const u8 *opmode_notif; const u8 *vendor_ht_cap; const u8 *vendor_vht; const u8 *p2p; diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 9846fb48..b9bb2266 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -435,13 +435,13 @@ #define WLAN_EID_ANTENNA_SECTOR_ID_PATTERN 190 #define WLAN_EID_VHT_CAP 191 #define WLAN_EID_VHT_OPERATION 192 -#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193 -#define WLAN_EID_VHT_WIDE_BW_CHSWITCH 194 +#define WLAN_EID_EXTENDED_BSS_LOAD 193 +#define WLAN_EID_WIDE_BW_CHSWITCH 194 #define WLAN_EID_TRANSMIT_POWER_ENVELOPE 195 -#define WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER 196 -#define WLAN_EID_VHT_AID 197 -#define WLAN_EID_VHT_QUIET_CHANNEL 198 -#define WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION 199 +#define WLAN_EID_CHANNEL_SWITCH_WRAPPER 196 +#define WLAN_EID_AID 197 +#define WLAN_EID_QUIET_CHANNEL 198 +#define WLAN_EID_OPERATING_MODE_NOTIFICATION 199 #define WLAN_EID_UPSIM 200 #define WLAN_EID_REDUCED_NEIGHBOR_REPORT 201 #define WLAN_EID_TVHT_OPERATION 202 diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h index 6c25816b..2fcdfbe4 100644 --- a/src/common/qca-vendor.h +++ b/src/common/qca-vendor.h @@ -899,6 +899,61 @@ enum qca_radiotap_vendor_ids { * configure and fetch the state information of the MLO links affiliated * with the STA interface. The attributes used with this command are * defined in enum qca_wlan_vendor_attr_mlo_link_state. + * + * @QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS: Userspace can use this + * vendor subcommand to trigger channel utilization measurement on entire + * channel width of the connected channel(s). For MLO connection, connected + * channel utilization measurement shall be done on all the MLO links. + * The driver may use regular scan or wideband energy detection feature + * based on the hardware capability for connected channel(s) utilization + * measurement. The driver indicates the connected channel(s) utilization + * measurement completion as an asynchronous event with this command ID to + * userspace. Upon receiving this event, userspace can use + * %NL80211_CMD_GET_INTERFACE to determine the channel width of the current + * connected channel(s) and can derive the channel utilization percentage + * (CU) of each 20 MHz sub-channel of the entire connected channel using + * %NL80211_CMD_GET_SURVEY response. + * CU = %NL80211_SURVEY_INFO_TIME_BUSY * 100 / %NL80211_SURVEY_INFO_TIME. + * This command is only used for STA mode. + * + * @QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP: This vendor subcommand is + * used as an event to notify the userspace of TID-to-link map changes + * negotiated by the driver or updated by associated AP MLD with Beacon, + * Probe Response, or Action frames. The attributes used with this command + * are defined in enum qca_wlan_vendor_attr_tid_to_link_map. + * + * Note that the attribute + * %QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR may not correspond to + * the current connected AP MLD address. + * + * @QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG: Notify userspace about the removal + * of STA MLD setup links due to the AP MLD removing the corresponding + * affiliated APs with Multi-Link reconfiguration. If all the STA MLD setup + * links are removed during Multi-Link reconfiguration, the driver shall + * use %NL80211_CMD_DISCONNECT instead of this command since it is a + * connection drop. The attributes used with this command are defined in + * enum qca_wlan_vendor_attr_link_reconfig. + * Note that the attribute + * %QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR may not correspond to + * the current connected AP MLD address. + * + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_DISC_RSP_EXT: Vendor command to configure + * the driver with MLO link id information on which to transmit the TDLS + * discovery response frame on the configured MLO BSS link when the + * local station is connected in MLO mode. This command is sent to the + * driver prior to the TDLS discovery response management transmit + * operation and is followed immediately by the TDLS discovery response + * management frame transmit command. + * + * The driver saves the configured MLO link id information and uses it for + * the following TDLS discovery response frame transmission on the + * configured MLO BSS link and the link id information is cleared in the + * driver after the TDLS discovery response frame is successfully + * transmitted. This behavior is indepent of the TDLS peer STA connection + * mode (MLO or non-MLO). + * + * Uses the attributes defined in + * enum qca_wlan_vendor_attr_tdls_disc_rsp_ext. */ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0, @@ -1110,6 +1165,10 @@ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_GET_MONITOR_MODE = 225, QCA_NL80211_VENDOR_SUBCMD_ROAM_STATS = 226, QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE = 227, + QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS = 228, + QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP = 229, + QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG = 230, + QCA_NL80211_VENDOR_SUBCMD_TDLS_DISC_RSP_EXT = 231, }; /* Compatibility defines for previously used subcmd names. @@ -1787,6 +1846,11 @@ enum qca_wlan_vendor_acs_hw_mode { * measurement management frames. If * NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE is set, then * QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_AP will be ignored. + * @QCA_WLAN_VENDOR_FEATURE_AP_ALLOWED_FREQ_LIST: Flag indicates that the device + * in AP mode supports configuring allowed frequency list for AP operation + * with %QCA_WLAN_VENDOR_ATTR_CONFIG_AP_ALLOWED_FREQ_LIST. + * @QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN: Flag indicates + * that the device supports enhanced audio experience over WLAN feature. * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits */ enum qca_wlan_vendor_features { @@ -1812,6 +1876,8 @@ enum qca_wlan_vendor_features { QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_AP = 19, QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_STA = 20, QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_AP = 21, + QCA_WLAN_VENDOR_FEATURE_AP_ALLOWED_FREQ_LIST = 22, + QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN = 23, NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */ }; @@ -2839,6 +2905,9 @@ enum qca_wlan_vendor_attr_config { * 8-bit unsigned value. This attribute can be used to configure the * data path mode to be followed for audio traffic. Possible values * are defined in enum qca_wlan_audio_data_path. + * + * This attribute is used only when the driver advertises support for + * QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN. */ QCA_WLAN_VENDOR_ATTR_CONFIG_AUDIO_DATA_PATH = 82, @@ -2917,6 +2986,57 @@ enum qca_wlan_vendor_attr_config { */ QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_MODE = 90, + /* Nested attribute with frequencies in u32 attributes to configure a + * list of allowed 20 MHz channel center frequencies in MHz for AP + * operation. Whenever performing a channel selection operation, the + * driver shall generate a new list based on this provided list by + * filtering out channels that cannot be used at that time due to + * regulatory or other constraints. The resulting list is used as the + * list of all allowed channels, i.e., operation on any channel that is + * not included is not allowed, whenever performing operations like ACS + * and DFS. + * + * Userspace shall configure this before starting the AP and the + * configuration is valid only from the next BSS start and until the + * BSS is stopped. The driver shall clear this configuration when the + * AP is stopped and fall back to the default behavior for subsequent + * AP operation. + * + * The default behavior when this configuration is not applicable is the + * driver can choose any of the channels supported by the hardware + * except the channels that cannot be used due to regulatory or other + * constraints. + * + * The driver shall reject this configuration if done after the AP is + * started. This attribute can be used to specify user's choice of + * frequencies and static puncture channel list, etc. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_AP_ALLOWED_FREQ_LIST = 91, + + /* Nested attribute to indicate EHT MLO links to be forced active. + * It contains link MAC address attributes. These nested attributes are + * of the type NL80211_ATTR_MAC and are used to force enabling of the + * MLO links corresponding to the indicated link MAC addresses. + * Subsequently, the links corresponding to the link MAC addresses that + * are not indicated are forced inactive. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_ACTIVE_LINKS = 92, + + /* 8-bit unsigned value to configure EMLSR mode entry or exit. + * Uses enum qca_wlan_emlsr_mode values. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_EMLSR_MODE_SWITCH = 93, + + /* 8-bit unsigned value to configure the channel bandwidth + * for CTS frame transmission during the dymamic bandwidth + * signaling CTS procedure referred in IEEE Std 802.11-2020, + * 10.3.2.9 CTS and DMG CTS procedure. + * This configuration is used for testing purposes. + * + * This uses values defined in enum nl80211_chan_width. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_CTS_CHANNEL_WIDTH = 94, + /* keep last */ QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_CONFIG_MAX = @@ -3999,18 +4119,55 @@ enum qca_wlan_vendor_attr_ll_stats_set { QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_AFTER_LAST - 1, }; +/** + * qca_wlan_ll_stats_clr_req_bitmap - Represents the bitmap to clear LL STATS + * values for %QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO: Clear all radio statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO_CCA: Clear cca_busy_time within + * radio statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO_CHANNEL: Clear all channel + * statistics within radio statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_SCAN: Clear all scan statistics within + * radio statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE: Clear all interface statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_TXRATE: Clear all TX rate statistics + * within interface statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_AC: Clear all AC statistics within + * interface statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_CONTENTION: Clear all contention + * (min, max, avg) statistics within AC statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_ALL_PEER: Clear all peer statistics + * on this interface. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_PER_PEER: Clear particular peer + * statistics depending on the peer_mac. + */ +enum qca_wlan_ll_stats_clr_req_bitmap { + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO = BIT(0), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO_CCA = BIT(1), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO_CHANNELS = BIT(2), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO_SCAN = BIT(3), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE = BIT(4), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_TXRATE = BIT(5), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_AC = BIT(6), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_CONTENTION = BIT(7), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_ALL_PEER = BIT(8), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_PER_PEER = BIT(9), +}; + enum qca_wlan_vendor_attr_ll_stats_clr { QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_INVALID = 0, - /* Unsigned 32bit bitmap for clearing statistics - * All radio statistics 0x00000001 - * cca_busy_time (within radio statistics) 0x00000002 - * All channel stats (within radio statistics) 0x00000004 - * All scan statistics (within radio statistics) 0x00000008 - * All interface statistics 0x00000010 - * All tx rate statistics (within interface statistics) 0x00000020 - * All ac statistics (with in interface statistics) 0x00000040 - * All contention (min, max, avg) statistics (within ac statisctics) - * 0x00000080. + /* Unsigned 32bit bitmap for clearing statistics, specified + * in the enum qca_wlan_ll_stats_clr_req_bitmap. */ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK = 1, /* Unsigned 8 bit value: Request to stop statistics collection */ @@ -4030,6 +4187,25 @@ enum qca_wlan_vendor_attr_ll_stats_clr { QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_AFTER_LAST - 1, }; +/** + * qca_wlan_ll_stats_get_req_bitmap - Represents the bitmap to request LL STATS + * values for %QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK. + * + * @QCA_WLAN_LL_STATS_GET_REQ_BITMAP_RADIO: Request all radio statistics. + * + * @QCA_WLAN_LL_STATS_GET_REQ_BITMAP_IFACE: Request interface statistics. + * + * @QCA_WLAN_LL_STATS_GET_REQ_BITMAP_ALL_PEER: Request all peer statistics. + * + * @QCA_WLAN_LL_STATS_GET_REQ_BITMAP_PER_PEER: Request per peer statistics. + */ +enum qca_wlan_ll_stats_get_req_bitmap { + QCA_WLAN_LL_STATS_GET_REQ_BITMAP_RADIO = BIT(0), + QCA_WLAN_LL_STATS_GET_REQ_BITMAP_IFACE = BIT(1), + QCA_WLAN_LL_STATS_GET_REQ_BITMAP_ALL_PEER = BIT(2), + QCA_WLAN_LL_STATS_GET_REQ_BITMAP_PER_PEER = BIT(3), +}; + enum qca_wlan_vendor_attr_ll_stats_get { QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_INVALID = 0, /* Unsigned 32 bit value provided by the caller issuing the GET stats @@ -4038,11 +4214,8 @@ enum qca_wlan_vendor_attr_ll_stats_get { */ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID = 1, /* Unsigned 32 bit value - bit mask to identify what statistics are - * requested for retrieval. - * Radio Statistics 0x00000001 - * Interface Statistics 0x00000020 - * All Peer Statistics 0x00000040 - * Peer Statistics 0x00000080 + * requested for retrieval specified in the enum + * qca_wlan_ll_stats_get_req_bitmap */ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK = 2, /* keep last */ @@ -4053,24 +4226,65 @@ enum qca_wlan_vendor_attr_ll_stats_get { enum qca_wlan_vendor_attr_ll_stats_results { QCA_WLAN_VENDOR_ATTR_LL_STATS_INVALID = 0, + + /* + * For Multi Link Operation (MLO) connection, per-link statistics will + * be sent inside of %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and + * cumulative statistics will be sent outside of + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK to maintain backward + * compatibility with legacy user space. Attributes which don't have + * explicit documentation for MLO will be sent only outside of + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK, such attributes values + * don't depend on whether the connection is MLO capable or not, e.g., + * radio and channel specific attributes. + */ + /* Unsigned 32bit value. Used by the driver; must match the request id * provided with the QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET command. */ QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_REQ_ID = 1, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX = 2, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX = 3, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX = 4, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX = 5, - /* Signed 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT = 6, - /* Signed 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA = 7, - /* Signed 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK = 8, /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_* are @@ -4094,7 +4308,8 @@ enum qca_wlan_vendor_attr_ll_stats_results { QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES = 13, /* NULL terminated SSID. An array of 33 Unsigned 8bit values */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID = 14, - /* BSSID. An array of 6 unsigned 8 bit values */ + /* For non-MLO connection, BSSID of the AP. For MLO connection, MLD + * address of the AP. An array of 6 unsigned 8 bit values */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID = 15, /* Country string advertised by AP. An array of 3 unsigned 8 bit * values. @@ -4107,6 +4322,15 @@ enum qca_wlan_vendor_attr_ll_stats_results { /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_* could * be nested within the interface stats. + * For an MLO connection, all %QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_* + * attributes except %QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_* + * indicate the aggregate of all links outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_* attributes + * indicate value of the MLO link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + * These attributes indicate the link specific value inside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. */ /* Type = enum wifi_traffic_ac, e.g., V0, VI, BE and BK */ @@ -4209,6 +4433,12 @@ enum qca_wlan_vendor_attr_ll_stats_results { */ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG = 48, + /* Unsigned 32 bit value. This is used to indicate radio ID of the radio + * statistics when %QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE is + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO. This is also used + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK to indicate radio ID + * of the MLO link. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID = 49, /* Unsigned 32 bit value. Total number of msecs the radio is awake * accruing over time. @@ -4255,7 +4485,13 @@ enum qca_wlan_vendor_attr_ll_stats_results { /* Type = enum wifi_channel_width. Channel width, e.g., 20, 40, 80 */ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH = 60, - /* Unsigned 32 bit value. Primary 20 MHz channel. */ + /* Unsigned 32 bit value. Primary 20 MHz channel. This is used to + * indicate the primary frequency of the channel when + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE is + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO. This is also used inside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK to indicate the frequency + * on which the MLO link is operating. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ = 61, /* Unsigned 32 bit value. Center frequency (MHz) first segment. */ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0 = 62, @@ -4285,7 +4521,9 @@ enum qca_wlan_vendor_attr_ll_stats_results { QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO = 67, /* Signifies the nested list of peer info attributes - * QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_* + * QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_*. For MLO connection, + * this also contains %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK_ID to + * indicate on which link the peer is connected. */ QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO = 68, @@ -4306,16 +4544,32 @@ enum qca_wlan_vendor_attr_ll_stats_results { */ QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA = 71, - /* Unsigned 64 bit value */ + /* Unsigned 64 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET = 72, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED = 73, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED = 74, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME = 75, /* Unsigned 32 bit value */ @@ -4328,13 +4582,29 @@ enum qca_wlan_vendor_attr_ll_stats_results { */ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL = 78, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT = 79, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT = 80, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT = 81, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT = 82, /* Unsigned int 32 value. @@ -4358,12 +4628,18 @@ enum qca_wlan_vendor_attr_ll_stats_results { */ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_LOAD_PERCENTAGE = 86, /* u8 value representing the time slicing duty cycle percentage. - * Possible values are 0-100. + * Possible values are 0-100. For an MLO connection, indicates the value + * of the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_TS_DUTY_CYCLE = 87, /* Unsigned 32 bit value. The number of Beacon frames which are received * from the associated AP and indicate buffered unicast frame(s) for us - * in the TIM element. + * in the TIM element. For an MLO connection, indicates the value of the + * link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. */ QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON = 88, /* Unsigned 32 bit value. The total number of Beacon frames received @@ -4374,16 +4650,46 @@ enum qca_wlan_vendor_attr_ll_stats_results { * doesn’t receive any unicast data after this beacon. * 2) The related TIM element is still set in the beacon for STA * after STA has indicated power save exit by QoS Null Data frame. + * For an MLO connection, indicates the value of the link with the best + * RSSI outside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link + * specific value inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. */ QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON_ERR = 89, - /* Attribute used for padding for 64-bit alignment */ - QCA_WLAN_VENDOR_ATTR_LL_STATS_PAD = 90, /* Signed 32 bit value. It represents the noise floor calibration value. - * Possible values are -120~-50 dBm. + * Possible values are -120~-50 dBm. For an MLO connection, indicates + * the value of the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NF_CAL_VAL = 90, + /* Attribute used for padding for 64-bit alignment */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_PAD = 91, + + /* Unsigned u8 value, link ID of an MLO link. Used inside nested + * attribute %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK to represent the + * link ID of the MLO link for which the statistics are embedded in the + * nested attribute. Used inside nested attribute + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO to represent the connected + * link ID of the peer. + */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK_ID = 92, + + /* A nested array of attributes for each MLO link, each containing + * per-link statistics of a multi link connection. The attributes used + * inside this nested attribute are defined in enum + * qca_wlan_vendor_attr_ll_stats_results. + * + * For non-MLO connection, this attribute is not present and the + * statistics will be sent outside this attribute (without nesting). + * + * For MLO connection, this attribute is present and also cumulative + * statistics of all the links will be sent outside of this attribute + * to be compatible with legacy user space. + */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK = 93, + /* keep last */ QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX = @@ -4865,6 +5171,8 @@ enum qca_vendor_roam_triggers { * @QCA_ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT: WPA3-SAE pre-authentication times * out. * @QCA_ROAM_FAIL_REASON_SAE_PREAUTH_FAIL: WPA3-SAE pre-authentication fails. + * @QCA_ROAM_FAIL_REASON_CURR_AP_STILL_OK: Roam scan did not happen since the + * current network conditions are fine. */ enum qca_vendor_roam_fail_reasons { QCA_ROAM_FAIL_REASON_NONE = 0, @@ -4897,6 +5205,7 @@ enum qca_vendor_roam_fail_reasons { QCA_ROAM_FAIL_REASON_SAE_INVALID_PMKID = 27, QCA_ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT = 28, QCA_ROAM_FAIL_REASON_SAE_PREAUTH_FAIL = 29, + QCA_ROAM_FAIL_REASON_CURR_AP_STILL_OK = 30, }; /* @@ -8558,9 +8867,19 @@ enum qca_wlan_eht_mlo_mode { }; /** - * enum qca_wlan_vendor_attr_he_omi_tx: Represents attributes for - * HE operating mode control transmit request. These attributes are - * sent as part of QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX and + * enum qca_wlan_emlsr_mode: Enhanced Multi-link Single Radio mode configuration + * @QCA_WLAN_EMLSR_MODE_ENTER: Enter EMLSR mode + * @QCA_WLAN_EMLSR_MODE_EXIT: Exit EMLSR mode + */ +enum qca_wlan_emlsr_mode { + QCA_WLAN_EMLSR_MODE_ENTER = 0, + QCA_WLAN_EMLSR_MODE_EXIT = 1, +}; + +/** + * enum qca_wlan_vendor_attr_omi_tx: Represents attributes for HE and + * EHT operating mode control transmit request. These attributes are + * sent as part of QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OMI_TX and * QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION. * * @QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS: Mandatory 8-bit unsigned value @@ -8590,21 +8909,48 @@ enum qca_wlan_eht_mlo_mode { * 1 - Determine which HE TB PPDU types are allowed by the STA if UL MU disable * bit is not set, else UL MU Tx is suspended. * + * @QCA_WLAN_VENDOR_ATTR_EHT_OMI_RX_NSS_EXTN: 8-bit unsigned value in the EHT OM + * Control subfield combined with the Rx NSS subfield in the OM Control subfield + * indicates NSS - 1, where NSS is the maximum number of spatial streams that + * STA supports in reception for PPDU bandwidths less than or equal to 80 MHz. + * + * @QCA_WLAN_VENDOR_ATTR_EHT_OMI_CH_BW_EXTN: 8-bit unsigned value indicates + * 320 MHz operating channel width supported by the EHT STA for both reception + * and transmission. + * + * @QCA_WLAN_VENDOR_ATTR_EHT_OMI_TX_NSS_EXTN: 8-bit unsigned value in the EHT OM + * Control subfield combined with the Tx NSTS subfield in OM Control subfield + * indicates NSTS - 1, where NSTS is the maximum number of space-time streams + * that the STA supports in transmission for PPDU bandwidths less than or equal + * to 80 MHz. */ -enum qca_wlan_vendor_attr_he_omi_tx { +enum qca_wlan_vendor_attr_omi_tx { QCA_WLAN_VENDOR_ATTR_HE_OMI_INVALID = 0, QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS = 1, QCA_WLAN_VENDOR_ATTR_HE_OMI_CH_BW = 2, QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DISABLE = 3, QCA_WLAN_VENDOR_ATTR_HE_OMI_TX_NSTS = 4, QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DATA_DISABLE = 5, + QCA_WLAN_VENDOR_ATTR_EHT_OMI_RX_NSS_EXTN = 6, + QCA_WLAN_VENDOR_ATTR_EHT_OMI_CH_BW_EXTN = 7, + QCA_WLAN_VENDOR_ATTR_EHT_OMI_TX_NSS_EXTN = 8, /* keep last */ - QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST, - QCA_WLAN_VENDOR_ATTR_HE_OMI_MAX = - QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST - 1, + QCA_WLAN_VENDOR_ATTR_OMI_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OMI_MAX = + QCA_WLAN_VENDOR_ATTR_OMI_AFTER_LAST - 1, }; +/* deprecated legacy names */ +#define QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX \ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OMI_TX +#define qca_wlan_vendor_attr_he_omi_tx \ + qca_wlan_vendor_attr_omi_tx +#define QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST \ + QCA_WLAN_VENDOR_ATTR_OMI_AFTER_LAST +#define QCA_WLAN_VENDOR_ATTR_HE_OMI_MAX \ + QCA_WLAN_VENDOR_ATTR_OMI_MAX + /** * enum qca_wlan_vendor_phy_mode - Different PHY modes * These values are used with %QCA_WLAN_VENDOR_ATTR_CONFIG_PHY_MODE. @@ -8922,10 +9268,10 @@ enum qca_wlan_vendor_attr_wifi_test_config { * channel bandwidth, Tx Nsts and UL MU disable attributes. * These nested attributes are used to send HE operating mode control * with configured values. - * Uses the enum qca_wlan_vendor_attr_he_omi_tx attributes. + * Uses the enum qca_wlan_vendor_attr_omi_tx attributes. * This attribute is used to configure the testbed device. */ - QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX = 33, + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OMI_TX = 33, /* 8-bit unsigned value to configure +HTC_HE support to indicate the * support for the reception of a frame that carries an HE variant @@ -9207,6 +9553,46 @@ enum qca_wlan_vendor_attr_wifi_test_config { */ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_TB_SOUNDING_FB_RL = 66, + /* 8-bit unsigned value to configure the support for receiving an MPDU + * that contains an EHT operating mode control subfield. + * This attribute is used to configure the testbed device. + * 1-enable, 0-disable. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_OM_CTRL_SUPPORT = 67, + + /* 8-bit unsigned value to configure the driver with EMLSR padding delay + * subfield value. + * + * 0 - 0 us + * 1 - 32 us + * 2 - 64 us + * 3 - 128 us + * 4 - 256 us + * 5-255 - Reserved + * + * This attribute is used for testing purposes. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EMLSR_PADDING_DELAY = 68, + + /* + * 8-bit unsigned value to indicate the firmware to force the active MLO + * links to power save mode for the configured number of beacon periods. + * This allows the firmware to suspend STA links for X beacon periods + * and remain asleep even if the AP advertises TIM as opposed to regular + * power save mode where STA links wake up if the AP indicates that it + * has buffered data to send. + * This attribute is used to configure the testbed device. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FORCE_MLO_POWER_SAVE_BCN_PERIOD = 69, + + /* + * 8-bit unsigned value to indicate the firmware to be in STR MLMR mode + * to enable simultaneous transmission of PPDUs on all active links. + * 0 - Default behavior + * 1 - Enter STR mode for simultaneous data transmission on all links + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_MLO_STR_TX = 70, + /* keep last */ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX = @@ -12194,9 +12580,13 @@ enum qca_wlan_concurrent_sta_policy_config { * * @QCA_WLAN_CONCURRENT_AP_POLICY_GAMING_AUDIO: Select interface concurrencies * to meet gaming audio latency requirements. + * This policy is used only when the driver advertises support for + * QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN. * * @QCA_WLAN_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING: Select interface * concurrencies to meet lossless audio streaming requirements. + * This policy is used only when the driver advertises support for + * QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN. * * @QCA_WLAN_CONCURRENT_AP_POLICY_XR: Select interface concurrencies to meet * XR (eXtended Reality) requirements. @@ -15117,4 +15507,100 @@ enum qca_wlan_vendor_attr_mlo_link_state { QCA_WLAN_VENDOR_ATTR_LINK_STATE_AFTER_LAST - 1, }; +/** + * enum qca_wlan_vendor_attr_tid_link_map_status - Definition of attributes used + * inside nested attribute %QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK: Required u16 attribute + * within nested attribute %QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS. + * Indicates the link mapping bitmap of a TID for uplink traffic. It is a + * bitmask of the link IDs in which a bit set means that the TID is mapped with + * that link ID in uplink traffic. Otherwise, the TID is not mapped to uplink + * traffic for that link. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK: Required u16 attribute + * within nested attribute %QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS. + * Indicates the link mapping bitmap of a TID for downlink traffic. It is a + * bitmask of the link IDs in which a bit set means that the TID is mapped with + * that link ID in downlink traffic. Otherwise, the TID is not mapped to + * downlink traffic for that link. + */ +enum qca_wlan_vendor_attr_tid_link_map_status { + QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK = 1, + QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_MAX = + QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_AFTER_LAST - 1, +}; + +/* + * enum qca_wlan_vendor_attr_tid_to_link_map: Definition of attributes used with + * %QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP event. + * + * @QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR: Required attribute. 6-byte + * AP MLD address with which this TID-to-link negotiation mapping is + * established/updated. + * + * @QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS: Optional attribute. Array of + * nested attributes containing TID-to-links mapping information. This will have + * TID-to-link mapping for TID0 to TID7, each containing the uplink and downlink + * map information. If this attribute is not present the default TID-to-link + * mapping is in use, i.e., all TIDs are mapped to all links for both uplink and + * downlink traffic. + * See enum qca_wlan_vendor_attr_tid_link_map_status for the nested attributes. + */ +enum qca_wlan_vendor_attr_tid_to_link_map { + QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR = 1, + QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_MAX = + QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_link_reconfig: Definition of attributes used + * with %QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG event. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR: Required attribute. + * 6-byte AP MLD address of the AP which indicated the link reconfiguration. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_REMOVED_LINKS: Required u16 attribute. + * A bitmap of the removed setup links link IDs. + */ +enum qca_wlan_vendor_attr_link_reconfig { + + QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR = 1, + QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_REMOVED_LINKS = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_tdls_disc_rsp_ext - Attributes used by + * %QCA_NL80211_VENDOR_SUBCMD_TDLS_DISC_RSP_EXT vendor command. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_TX_LINK: u8 attribute. + * Indicates the MLO link id on which the TDLS discovery response + * frame is to be transmitted. + */ +enum qca_wlan_vendor_attr_tdls_disc_rsp_ext { + QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_TX_LINK = 1, + + /* Keep last */ + QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_AFTER_LAST - 1, +}; + #endif /* QCA_VENDOR_H */ diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index 15ebcabb..367af8f6 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -3567,7 +3567,7 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) } else if (*pos == WLAN_EID_HT_CAP && pos[1] >= sizeof(struct ieee80211_ht_capabilities)) { ie->ht_capabilities = pos + 2; - } else if (*pos == WLAN_EID_VHT_AID) { + } else if (*pos == WLAN_EID_AID) { if (pos[1] >= 2) ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff; } else if (*pos == WLAN_EID_VHT_CAP && diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 4ab2a1b6..06149ecc 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -110,6 +110,10 @@ extern "C" { #define WPA_EVENT_DO_ROAM "CTRL-EVENT-DO-ROAM " /** Decision made to skip a within-ESS roam */ #define WPA_EVENT_SKIP_ROAM "CTRL-EVENT-SKIP-ROAM " +/** TID-to-link mapping response event */ +#define WPA_EVENT_T2LM_UPDATE "CTRL-EVENT-T2LM-UPDATE " +/** MLO link reconfiguration event */ +#define WPA_EVENT_LINK_RECONFIG "CTRL-EVENT-LINK-RECONFIG " /** IP subnet status change notification * diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 1477eccf..3c4de7a2 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -430,6 +430,18 @@ struct wpa_driver_scan_ssid { size_t ssid_len; }; +struct t2lm_mapping { + /** + * downlink - Bitmap of TIDs mapped with a link in downlink direction + */ + u8 downlink; + + /** + * uplink - Bitmap of TIDs mapped with a link in uplink direction + */ + u8 uplink; +}; + /** * struct wpa_driver_scan_params - Scan parameters * Data for struct wpa_driver_ops::scan2(). @@ -1733,6 +1745,38 @@ struct wpa_driver_ap_params { * subchannel is punctured, otherwise active. */ u16 punct_bitmap; + + /** + * rnr_elem - This buffer contains all of reduced neighbor report (RNR) + * elements + */ + u8 *rnr_elem; + + /** + * rnr_elem_len - Length of rnr_elem buffer + */ + size_t rnr_elem_len; + + /** + * rnr_elem_count - Number of RNR elements + */ + unsigned int rnr_elem_count; + + /** + * rnr_elem_offset - The offsets to the elements in rnr_elem. + * The driver will use these to include RNR elements in EMA beacons. + */ + u8 **rnr_elem_offset; + + /** + * allowed_freqs - List of allowed 20 MHz channel center frequencies in + * MHz for AP operation. Drivers which support this parameter will + * generate a new list based on this provided list by filtering out + * channels that cannot be used at that time due to regulatory or other + * constraints. The resulting list is used as the list of all allowed + * channels whenever performing operations like ACS and DFS. + */ + int *allowed_freqs; }; struct wpa_driver_mesh_bss_params { @@ -2889,6 +2933,7 @@ struct weighted_pcl { }; struct driver_sta_mlo_info { + bool default_map; u16 req_links; /* bitmap of requested link IDs */ u16 valid_links; /* bitmap of accepted link IDs */ u8 assoc_link_id; @@ -2897,6 +2942,7 @@ struct driver_sta_mlo_info { u8 addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; unsigned int freq; + struct t2lm_mapping t2lmap; } links[MAX_NUM_MLD_LINKS]; }; @@ -5618,6 +5664,21 @@ enum wpa_event_type { * Described in wpa_event_data.ch_switch. */ EVENT_LINK_CH_SWITCH_STARTED, + + /** + * EVENT_TID_LINK_MAP - MLD event to set TID-to-link mapping + * + * This event is used by the driver to indicate the received TID-to-link + * mapping response from the associated AP MLD. + * + * Described in wpa_event_data.t2l_map_info. + */ + EVENT_TID_LINK_MAP, + + /** + * EVENT_LINK_RECONFIG - Notification that AP links removed + */ + EVENT_LINK_RECONFIG, }; @@ -6542,6 +6603,15 @@ union wpa_event_data { const u8 *td_bitmap; size_t td_bitmap_len; } port_authorized; + + /** + * struct tid_link_map_info - Data for EVENT_TID_LINK_MAP + */ + struct tid_link_map_info { + bool default_map; + u8 valid_links; + struct t2lm_mapping t2lmap[MAX_NUM_MLD_LINKS]; + } t2l_map_info; }; /** diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index bbd1a7ce..f3625e8c 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -98,6 +98,8 @@ const char * event_to_string(enum wpa_event_type event) E2S(PASN_AUTH); E2S(LINK_CH_SWITCH); E2S(LINK_CH_SWITCH_STARTED); + E2S(TID_LINK_MAP); + E2S(LINK_RECONFIG); } return "UNKNOWN"; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index cc87e72d..5f39e804 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -283,6 +283,10 @@ void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv) #ifdef CONFIG_DRIVER_NL80211_QCA os_free(drv->pending_roam_data); drv->pending_roam_data = NULL; + os_free(drv->pending_t2lm_data); + drv->pending_t2lm_data = NULL; + os_free(drv->pending_link_reconfig_data); + drv->pending_link_reconfig_data = NULL; #endif /* CONFIG_DRIVER_NL80211_QCA */ drv->auth_mld = false; @@ -4838,12 +4842,80 @@ static int nl80211_mbssid(struct nl_msg *msg, nla_nest_end(msg, elems); } + if (!params->ema) + return 0; + + if (params->rnr_elem_count && params->rnr_elem_len && + params->rnr_elem_offset && *params->rnr_elem_offset) { + u8 i, **offs = params->rnr_elem_offset; + + elems = nla_nest_start(msg, NL80211_ATTR_EMA_RNR_ELEMS); + if (!elems) + return -1; + + for (i = 0; i < params->rnr_elem_count - 1; i++) { + if (nla_put(msg, i + 1, offs[i + 1] - offs[i], offs[i])) + return -1; + } + + if (nla_put(msg, i + 1, *offs + params->rnr_elem_len - offs[i], + offs[i])) + return -1; + nla_nest_end(msg, elems); + } + return 0; } #endif /* CONFIG_IEEE80211AX */ +#ifdef CONFIG_DRIVER_NL80211_QCA +static void qca_set_allowed_ap_freqs(struct wpa_driver_nl80211_data *drv, + const int *freqs, int num_freqs) +{ + struct nl_msg *msg; + struct nlattr *params, *freqs_list; + int i, ret; + + if (!drv->set_wifi_conf_vendor_cmd_avail || !drv->qca_ap_allowed_freqs) + return; + + wpa_printf(MSG_DEBUG, "nl80211: Set AP allowed frequency list"); + + if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION) || + !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA))) + goto err; + + freqs_list = nla_nest_start( + msg, QCA_WLAN_VENDOR_ATTR_CONFIG_AP_ALLOWED_FREQ_LIST); + if (!freqs_list) + goto err; + + for (i = 0; i < num_freqs; i++) { + if (nla_put_u32(msg, i, freqs[i])) + goto err; + } + + nla_nest_end(msg, freqs_list); + nla_nest_end(msg, params); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + if (ret) + wpa_printf(MSG_ERROR, + "nl80211: Failed set AP alllowed frequency list: %d (%s)", + ret, strerror(-ret)); + + return; +err: + nlmsg_free(msg); +} +#endif /* CONFIG_DRIVER_NL80211_QCA */ + + static int wpa_driver_nl80211_set_ap(void *priv, struct wpa_driver_ap_params *params) { @@ -5166,6 +5238,12 @@ static int wpa_driver_nl80211_set_ap(void *priv, goto fail; } +#ifdef CONFIG_DRIVER_NL80211_QCA + if (cmd == NL80211_CMD_NEW_BEACON && params->allowed_freqs) + qca_set_allowed_ap_freqs(drv, params->allowed_freqs, + int_array_len(params->allowed_freqs)); +#endif /* CONFIG_DRIVER_NL80211_QCA */ + ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)", @@ -9618,6 +9696,11 @@ static int nl80211_set_param(void *priv, const char *param) } } + if (os_strstr(param, "secure_ltf=1")) { + drv->capa.flags2 |= WPA_DRIVER_FLAGS2_SEC_LTF_STA | + WPA_DRIVER_FLAGS2_SEC_LTF_AP; + } + return 0; } @@ -10662,8 +10745,10 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen) struct driver_sta_mlo_info *mlo = &drv->sta_mlo_info; res = os_snprintf(pos, end - pos, - "ap_mld_addr=" MACSTR "\n", - MAC2STR(mlo->ap_mld_addr)); + "ap_mld_addr=" MACSTR "\n" + "default_map=%d\n", + MAC2STR(mlo->ap_mld_addr), + mlo->default_map); if (os_snprintf_error(end - pos, res)) return pos - buf; pos += res; @@ -10682,6 +10767,18 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen) if (os_snprintf_error(end - pos, res)) return pos - buf; pos += res; + + if (!mlo->default_map) { + res = os_snprintf( + pos, end - pos, + "uplink_map[%u]=%x\n" + "downlink_map[%u]=%x\n", + i, mlo->links[i].t2lmap.uplink, + i, mlo->links[i].t2lmap.downlink); + if (os_snprintf_error(end - pos, res)) + return pos - buf; + pos += res; + } } } diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index bd35e52c..c5972956 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -199,6 +199,7 @@ struct wpa_driver_nl80211_data { unsigned int uses_6ghz:1; unsigned int secure_ranging_ctx_vendor_cmd_avail:1; unsigned int puncturing:1; + unsigned int qca_ap_allowed_freqs:1; u64 vendor_scan_cookie; u64 remain_on_chan_cookie; @@ -257,6 +258,10 @@ struct wpa_driver_nl80211_data { bool roam_indication_done; u8 *pending_roam_data; size_t pending_roam_data_len; + u8 *pending_t2lm_data; + size_t pending_t2lm_data_len; + u8 *pending_link_reconfig_data; + size_t pending_link_reconfig_data_len; #endif /* CONFIG_DRIVER_NL80211_QCA */ }; diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index 31525297..09771bba 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -1414,6 +1414,9 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv) QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_AP, &info)) drv->capa.flags2 |= WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP; + if (check_feature(QCA_WLAN_VENDOR_FEATURE_AP_ALLOWED_FREQ_LIST, + &info)) + drv->qca_ap_allowed_freqs = 1; os_free(info.flags); } diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 14d78427..e99afdca 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -421,6 +421,78 @@ convert_connect_fail_reason_codes(enum qca_sta_connect_fail_reason_codes } +static void qca_nl80211_link_reconfig_event(struct wpa_driver_nl80211_data *drv, + u8 *data, size_t len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_MAX + 1]; + u16 removed_links; + u8 *ap_mld; + int i; + + if (!data) + return; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_MAX, + (struct nlattr *) data, len, NULL) || + !tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR]) + return; + + ap_mld = nla_data(tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR]); + wpa_printf(MSG_DEBUG, "nl80211: AP MLD address " MACSTR + " received in link reconfig event", MAC2STR(ap_mld)); + if (!drv->sta_mlo_info.valid_links || + os_memcmp(drv->sta_mlo_info.ap_mld_addr, ap_mld, ETH_ALEN) != 0) { + if (drv->pending_link_reconfig_data == data) { + wpa_printf(MSG_DEBUG, + "nl80211: Drop pending link reconfig event since AP MLD not matched even after new connect/roam event"); + os_free(drv->pending_link_reconfig_data); + drv->pending_link_reconfig_data = NULL; + return; + } + + wpa_printf(MSG_DEBUG, + "nl80211: Cache new link reconfig event till next connect/roam event"); + if (drv->pending_link_reconfig_data) { + wpa_printf(MSG_DEBUG, "nl80211: Override old link reconfig event data"); + os_free(drv->pending_link_reconfig_data); + } + drv->pending_link_reconfig_data = os_memdup(data, len); + if (!drv->pending_link_reconfig_data) + return; + drv->pending_link_reconfig_data_len = len; + return; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_REMOVED_LINKS]) + return; + removed_links = nla_get_u16( + tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_REMOVED_LINKS]); + + drv->sta_mlo_info.valid_links &= ~removed_links; + + /* + * Set default BSSID to the BSSID of the lowest link ID of remaining + * links when the link used for (re)association is removed. + */ + if (removed_links & BIT(drv->sta_mlo_info.assoc_link_id)) { + for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { + if (!(drv->sta_mlo_info.valid_links & BIT(i))) + continue; + + os_memcpy(drv->bssid, drv->sta_mlo_info.links[i].bssid, + ETH_ALEN); + drv->sta_mlo_info.assoc_link_id = i; + break; + } + } + + wpa_printf(MSG_DEBUG, "nl80211: Removed MLO links bitmap: 0x%x", + removed_links); + + wpa_supplicant_event(drv->ctx, EVENT_LINK_RECONFIG, NULL); +} + + static void nl80211_parse_qca_vendor_mlo_link_info(struct driver_sta_mlo_info *mlo, struct nlattr *mlo_links) @@ -713,6 +785,126 @@ static void nl80211_parse_mlo_info(struct wpa_driver_nl80211_data *drv, } +#ifdef CONFIG_DRIVER_NL80211_QCA +static void +qca_nl80211_tid_to_link_map_event(struct wpa_driver_nl80211_data *drv, + u8 *data, size_t len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_MAX + 1]; + struct nlattr *tids; + union wpa_event_data event; + u8 *ap_mld; + int i, rem, tidnum = 0; + + os_memset(&event, 0, sizeof(event)); + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_MAX, + (struct nlattr *) data, len, NULL) || + !tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR]) + return; + + ap_mld = nla_data(tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR]); + + wpa_printf(MSG_DEBUG, "nl80211: AP MLD address " MACSTR + " received in TID to link mapping event", MAC2STR(ap_mld)); + if (!drv->sta_mlo_info.valid_links || + os_memcmp(drv->sta_mlo_info.ap_mld_addr, ap_mld, ETH_ALEN) != 0) { + if (drv->pending_t2lm_data == data) { + wpa_printf(MSG_DEBUG, + "nl80211: Drop pending TID-to-link mapping event since AP MLD not matched even after new connect/roam event"); + os_free(drv->pending_t2lm_data); + drv->pending_t2lm_data = NULL; + return; + } + wpa_printf(MSG_DEBUG, + "nl80211: Cache new TID-to-link map event until the next connect/roam event"); + if (drv->pending_t2lm_data) { + wpa_printf(MSG_DEBUG, + "nl80211: Override old TID-to-link map event data"); + os_free(drv->pending_t2lm_data); + } + drv->pending_t2lm_data = os_memdup(data, len); + if (!drv->pending_t2lm_data) + return; + drv->pending_t2lm_data_len = len; + return; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS]) { + wpa_printf(MSG_DEBUG, "nl80211: Default TID-to-link map"); + event.t2l_map_info.default_map = true; + goto out; + } + + event.t2l_map_info.default_map = false; + + nla_for_each_nested(tids, + tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS], + rem) { + u16 uplink, downlink; + struct nlattr *tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_MAX + 1]; + + if (nla_parse_nested( + tid, QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_MAX, + tids, NULL)) { + wpa_printf(MSG_DEBUG, + "nl80211: TID-to-link: nla_parse_nested() failed"); + return; + } + + if (!tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK]) { + wpa_printf(MSG_DEBUG, + "nl80211: TID-to-link: uplink not present for tid: %d", + tidnum); + return; + } + uplink = nla_get_u16(tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK]); + + if (!tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK]) { + wpa_printf(MSG_DEBUG, + "nl80211: TID-to-link: downlink not present for tid: %d", + tidnum); + return; + } + downlink = nla_get_u16(tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK]); + + wpa_printf(MSG_DEBUG, + "nl80211: TID-to-link: Received uplink %x downlink %x", + uplink, downlink); + for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { + if (!(drv->sta_mlo_info.valid_links & BIT(i))) + continue; + if (uplink & BIT(i)) + event.t2l_map_info.t2lmap[i].uplink |= + BIT(tidnum); + if (downlink & BIT(i)) + event.t2l_map_info.t2lmap[i].downlink |= + BIT(tidnum); + } + + tidnum++; + } + +out: + drv->sta_mlo_info.default_map = event.t2l_map_info.default_map; + + event.t2l_map_info.valid_links = drv->sta_mlo_info.valid_links; + for (i = 0; i < MAX_NUM_MLD_LINKS && !drv->sta_mlo_info.default_map; + i++) { + if (!(drv->sta_mlo_info.valid_links & BIT(i))) + continue; + + drv->sta_mlo_info.links[i].t2lmap.uplink = + event.t2l_map_info.t2lmap[i].uplink; + drv->sta_mlo_info.links[i].t2lmap.downlink = + event.t2l_map_info.t2lmap[i].downlink; + } + + wpa_supplicant_event(drv->ctx, EVENT_TID_LINK_MAP, &event); +} +#endif /* CONFIG_DRIVER_NL80211_QCA */ + + static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, enum nl80211_commands cmd, bool qca_roam_auth, struct nlattr *status, @@ -912,6 +1104,19 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, * operation that happened in parallel with the disconnection request. */ drv->ignore_next_local_disconnect = 0; + +#ifdef CONFIG_DRIVER_NL80211_QCA + if (drv->pending_t2lm_data) + qca_nl80211_tid_to_link_map_event(drv, drv->pending_t2lm_data, + drv->pending_t2lm_data_len); + else + drv->sta_mlo_info.default_map = true; + + if (drv->pending_link_reconfig_data) + qca_nl80211_link_reconfig_event( + drv, drv->pending_link_reconfig_data, + drv->pending_link_reconfig_data_len); +#endif /* CONFIG_DRIVER_NL80211_QCA */ } @@ -2861,6 +3066,12 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, qca_nl80211_pasn_auth(drv, data, len); break; #endif /* CONFIG_PASN */ + case QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP: + qca_nl80211_tid_to_link_map_event(drv, data, len); + break; + case QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG: + qca_nl80211_link_reconfig_event(drv, data, len); + break; #endif /* CONFIG_DRIVER_NL80211_QCA */ default: wpa_printf(MSG_DEBUG, diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c index 7a7890c7..4d33b149 100644 --- a/src/drivers/driver_nl80211_scan.c +++ b/src/drivers/driver_nl80211_scan.c @@ -21,7 +21,7 @@ #include "driver_nl80211.h" -#define MAX_NL80211_NOISE_FREQS 50 +#define MAX_NL80211_NOISE_FREQS 100 struct nl80211_noise_info { u32 freq[MAX_NL80211_NOISE_FREQS]; diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h index 9a0ac036..c59fec40 100644 --- a/src/drivers/nl80211_copy.h +++ b/src/drivers/nl80211_copy.h @@ -2794,6 +2794,17 @@ enum nl80211_commands { * @NL80211_ATTR_HW_TIMESTAMP_ENABLED: Indicates whether HW timestamping should * be enabled or not (flag attribute). * + * @NL80211_ATTR_EMA_RNR_ELEMS: Optional nested attribute for + * reduced neighbor report (RNR) elements. This attribute can be used + * only when NL80211_MBSSID_CONFIG_ATTR_EMA is enabled. + * Userspace is responsible for splitting the RNR into multiple + * elements such that each element excludes the non-transmitting + * profiles already included in the MBSSID element + * (%NL80211_ATTR_MBSSID_ELEMS) at the same index. Each EMA beacon + * will be generated by adding MBSSID and RNR elements at the same + * index. If the userspace includes more RNR elements than number of + * MBSSID elements then these will be added in every EMA beacon. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3328,6 +3339,8 @@ enum nl80211_attrs { NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS, NL80211_ATTR_HW_TIMESTAMP_ENABLED, + NL80211_ATTR_EMA_RNR_ELEMS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -4048,6 +4061,10 @@ enum nl80211_band_iftype_attr { * @NL80211_BAND_ATTR_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes * the allowed channel bandwidth configurations. * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13. + * @NL80211_BAND_ATTR_S1G_MCS_NSS_SET: S1G capabilities, supported S1G-MCS and NSS + * set subfield, as in the S1G information IE, 5 bytes + * @NL80211_BAND_ATTR_S1G_CAPA: S1G capabilities information subfield as in the + * S1G information IE, 10 bytes * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined * @__NL80211_BAND_ATTR_AFTER_LAST: internal use */ @@ -4068,6 +4085,9 @@ enum nl80211_band_attr { NL80211_BAND_ATTR_EDMG_CHANNELS, NL80211_BAND_ATTR_EDMG_BW_CONFIG, + NL80211_BAND_ATTR_S1G_MCS_NSS_SET, + NL80211_BAND_ATTR_S1G_CAPA, + /* keep last */ __NL80211_BAND_ATTR_AFTER_LAST, NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 @@ -6544,7 +6564,9 @@ enum nl80211_timeout_reason { * channels on which APs are expected to be found. Note that when not set, * the scan logic would scan all 6GHz channels, but since transmission of * probe requests on non PSC channels is limited, it is highly likely that - * these channels would passively be scanned. + * these channels would passively be scanned. Also note that when the flag + * is set, in addition to the colocated APs, PSC channels would also be + * scanned if the user space has asked for it. */ enum nl80211_scan_flags { NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h index 59fac905..14544476 100644 --- a/src/eap_peer/eap_config.h +++ b/src/eap_peer/eap_config.h @@ -483,6 +483,14 @@ struct eap_peer_config { * 1 = use cryptobinding if server supports it * 2 = require cryptobinding * + * phase2_auth option can be used to control Phase 2 (i.e., within TLS + * tunnel) behavior for PEAP: + * 0 = do not require Phase 2 authentication + * 1 = require Phase 2 authentication when client certificate + * (private_key/client_cert) is not used and TLS session resumption was + * not used (default) + * 2 = require Phase 2 authentication in all cases + * * EAP-WSC (WPS) uses following options: pin=Device_Password and * uuid=Device_UUID * diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c index 12e30df2..60806971 100644 --- a/src/eap_peer/eap_peap.c +++ b/src/eap_peer/eap_peap.c @@ -67,6 +67,7 @@ struct eap_peap_data { u8 cmk[20]; int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP) * is enabled. */ + enum { NO_AUTH, FOR_INITIAL, ALWAYS } phase2_auth; }; @@ -114,6 +115,19 @@ static void eap_peap_parse_phase1(struct eap_peap_data *data, wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding"); } + if (os_strstr(phase1, "phase2_auth=0")) { + data->phase2_auth = NO_AUTH; + wpa_printf(MSG_DEBUG, + "EAP-PEAP: Do not require Phase 2 authentication"); + } else if (os_strstr(phase1, "phase2_auth=1")) { + data->phase2_auth = FOR_INITIAL; + wpa_printf(MSG_DEBUG, + "EAP-PEAP: Require Phase 2 authentication for initial connection"); + } else if (os_strstr(phase1, "phase2_auth=2")) { + data->phase2_auth = ALWAYS; + wpa_printf(MSG_DEBUG, + "EAP-PEAP: Require Phase 2 authentication for all cases"); + } #ifdef EAP_TNC if (os_strstr(phase1, "tnc=soh2")) { data->soh = 2; @@ -142,6 +156,7 @@ static void * eap_peap_init(struct eap_sm *sm) data->force_peap_version = -1; data->peap_outer_success = 2; data->crypto_binding = OPTIONAL_BINDING; + data->phase2_auth = FOR_INITIAL; if (config && config->phase1) eap_peap_parse_phase1(data, config->phase1); @@ -454,6 +469,20 @@ static int eap_tlv_validate_cryptobinding(struct eap_sm *sm, } +static bool peap_phase2_sufficient(struct eap_sm *sm, + struct eap_peap_data *data) +{ + if ((data->phase2_auth == ALWAYS || + (data->phase2_auth == FOR_INITIAL && + !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn) && + !data->ssl.client_cert_conf) || + data->phase2_eap_started) && + !data->phase2_eap_success) + return false; + return true; +} + + /** * eap_tlv_process - Process a received EAP-TLV message and generate a response * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() @@ -568,6 +597,11 @@ static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data, " - force failed Phase 2"); resp_status = EAP_TLV_RESULT_FAILURE; ret->decision = DECISION_FAIL; + } else if (!peap_phase2_sufficient(sm, data)) { + wpa_printf(MSG_INFO, + "EAP-PEAP: Server indicated Phase 2 success, but sufficient Phase 2 authentication has not been completed"); + resp_status = EAP_TLV_RESULT_FAILURE; + ret->decision = DECISION_FAIL; } else { resp_status = EAP_TLV_RESULT_SUCCESS; ret->decision = DECISION_UNCOND_SUCC; @@ -887,8 +921,7 @@ continue_req: /* EAP-Success within TLS tunnel is used to indicate * shutdown of the TLS channel. The authentication has * been completed. */ - if (data->phase2_eap_started && - !data->phase2_eap_success) { + if (!peap_phase2_sufficient(sm, data)) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 " "Success used to indicate success, " "but Phase 2 EAP was not yet " @@ -1199,8 +1232,9 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv, static bool eap_peap_has_reauth_data(struct eap_sm *sm, void *priv) { struct eap_peap_data *data = priv; + return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && - data->phase2_success; + data->phase2_success && data->phase2_auth != ALWAYS; } diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c index 3050456d..5594216c 100644 --- a/src/eap_peer/eap_tls_common.c +++ b/src/eap_peer/eap_tls_common.c @@ -242,6 +242,12 @@ static int eap_tls_params_from_conf(struct eap_sm *sm, sm->ext_cert_check = !!(params->flags & TLS_CONN_EXT_CERT_CHECK); + if (!phase2) + data->client_cert_conf = params->client_cert || + params->client_cert_blob || + params->private_key || + params->private_key_blob; + return 0; } diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h index 9ac00121..33486341 100644 --- a/src/eap_peer/eap_tls_common.h +++ b/src/eap_peer/eap_tls_common.h @@ -79,6 +79,11 @@ struct eap_ssl_data { * tls_v13 - Whether TLS v1.3 or newer is used */ int tls_v13; + + /** + * client_cert_conf: Whether client certificate has been configured + */ + bool client_cert_conf; }; diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c index c8e2de0a..6adc2227 100644 --- a/src/eap_peer/eap_ttls.c +++ b/src/eap_peer/eap_ttls.c @@ -65,9 +65,30 @@ struct eap_ttls_data { int ready_for_tnc; int tnc_started; #endif /* EAP_TNC */ + + enum { NO_AUTH, FOR_INITIAL, ALWAYS } phase2_auth; }; +static void eap_ttls_parse_phase1(struct eap_ttls_data *data, + const char *phase1) +{ + if (os_strstr(phase1, "phase2_auth=0")) { + data->phase2_auth = NO_AUTH; + wpa_printf(MSG_DEBUG, + "EAP-TTLS: Do not require Phase 2 authentication"); + } else if (os_strstr(phase1, "phase2_auth=1")) { + data->phase2_auth = FOR_INITIAL; + wpa_printf(MSG_DEBUG, + "EAP-TTLS: Require Phase 2 authentication for initial connection"); + } else if (os_strstr(phase1, "phase2_auth=2")) { + data->phase2_auth = ALWAYS; + wpa_printf(MSG_DEBUG, + "EAP-TTLS: Require Phase 2 authentication for all cases"); + } +} + + static void * eap_ttls_init(struct eap_sm *sm) { struct eap_ttls_data *data; @@ -82,6 +103,10 @@ static void * eap_ttls_init(struct eap_sm *sm) selected = "EAP"; selected_non_eap = 0; data->phase2_type = EAP_TTLS_PHASE2_EAP; + data->phase2_auth = FOR_INITIAL; + + if (config && config->phase1) + eap_ttls_parse_phase1(data, config->phase1); /* * Either one auth= type or one or more autheap= methods can be @@ -1703,8 +1728,9 @@ static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv, static bool eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv) { struct eap_ttls_data *data = priv; + return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && - data->phase2_success; + data->phase2_success && data->phase2_auth != ALWAYS; } diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c index 1c11cb61..e1b82ebe 100644 --- a/src/eapol_auth/eapol_auth_sm.c +++ b/src/eapol_auth/eapol_auth_sm.c @@ -217,6 +217,9 @@ SM_STATE(AUTH_PAE, INITIALIZE) SM_STATE(AUTH_PAE, DISCONNECTED) { int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE; + bool pre_auth_logoff = sm->auth_pae_state == AUTH_PAE_ABORTING && + sm->eapolLogoff && !sm->authenticated; + bool logoff = sm->eapolLogoff; if (sm->eapolLogoff) { if (sm->auth_pae_state == AUTH_PAE_CONNECTING) @@ -231,10 +234,14 @@ SM_STATE(AUTH_PAE, DISCONNECTED) setPortUnauthorized(); sm->reAuthCount = 0; sm->eapolLogoff = false; - if (!from_initialize) { - sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0, - sm->flags & EAPOL_SM_PREAUTH, - sm->remediation); + if (!from_initialize && !pre_auth_logoff) { + if (sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0, + sm->flags & EAPOL_SM_PREAUTH, + sm->remediation, logoff)) { + wpa_printf(MSG_DEBUG, + "EAPOL: Do not restart since lower layers will disconnect the port after EAPOL-Logoff"); + sm->stopped = true; + } } } @@ -291,7 +298,8 @@ SM_STATE(AUTH_PAE, HELD) eap_server_get_name(0, sm->eap_type_supp)); } sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0, - sm->flags & EAPOL_SM_PREAUTH, sm->remediation); + sm->flags & EAPOL_SM_PREAUTH, sm->remediation, + false); } @@ -316,8 +324,11 @@ SM_STATE(AUTH_PAE, AUTHENTICATED) sm->eap_type_authsrv, eap_server_get_name(0, sm->eap_type_authsrv), extra); + if (sm->authSuccess) + sm->authenticated++; sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1, - sm->flags & EAPOL_SM_PREAUTH, sm->remediation); + sm->flags & EAPOL_SM_PREAUTH, sm->remediation, + false); } @@ -397,7 +408,8 @@ SM_STEP(AUTH_PAE) SM_ENTER(AUTH_PAE, DISCONNECTED); break; case AUTH_PAE_DISCONNECTED: - SM_ENTER(AUTH_PAE, RESTART); + if (!sm->stopped) + SM_ENTER(AUTH_PAE, RESTART); break; case AUTH_PAE_RESTART: if (!sm->eap_if->eapRestart) diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h index 61b7039d..7296a3ac 100644 --- a/src/eapol_auth/eapol_auth_sm.h +++ b/src/eapol_auth/eapol_auth_sm.h @@ -46,8 +46,8 @@ struct eapol_auth_cb { size_t datalen); void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data, size_t datalen); - void (*finished)(void *ctx, void *sta_ctx, int success, int preauth, - int remediation); + bool (*finished)(void *ctx, void *sta_ctx, int success, int preauth, + int remediation, bool logoff); int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, int phase2, struct eap_user *user); int (*sta_entry_alive)(void *ctx, const u8 *addr); diff --git a/src/eapol_auth/eapol_auth_sm_i.h b/src/eapol_auth/eapol_auth_sm_i.h index 3c689831..a0cef0f8 100644 --- a/src/eapol_auth/eapol_auth_sm_i.h +++ b/src/eapol_auth/eapol_auth_sm_i.h @@ -171,6 +171,10 @@ struct eapol_state_machine { int remediation; u64 acct_multi_session_id; + + unsigned int authenticated; /* The number of times authentication has + * been completed successfully. */ + bool stopped; }; #endif /* EAPOL_AUTH_SM_I_H */ diff --git a/src/pasn/pasn_common.h b/src/pasn/pasn_common.h index 9c2f397e..a4850a28 100644 --- a/src/pasn/pasn_common.h +++ b/src/pasn/pasn_common.h @@ -95,7 +95,8 @@ struct pasn_data { u8 wrapped_data_format; struct wpabuf *secret; - /* Reponder */ + /* Responder */ + bool noauth; /* Whether PASN without mutual authentication is enabled */ int wpa_key_mgmt; int rsn_pairwise; bool derive_kdk; diff --git a/src/pasn/pasn_responder.c b/src/pasn/pasn_responder.c index 3b1912df..78a9dd7d 100644 --- a/src/pasn/pasn_responder.c +++ b/src/pasn/pasn_responder.c @@ -743,6 +743,12 @@ int handle_auth_pasn_1(struct pasn_data *pasn, goto send_resp; } + if (!pasn->noauth && pasn->akmp == WPA_KEY_MGMT_PASN) { + wpa_printf(MSG_DEBUG, "PASN: Refuse PASN-UNAUTH"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + derive_keys = true; if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) { wrapped_data = ieee802_11_defrag(&elems, diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 3a398862..5a28ef57 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -4561,6 +4561,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, sm->dpp_pfs = value; break; #endif /* CONFIG_DPP2 */ + case WPA_PARAM_WMM_ENABLED: + sm->wmm_enabled = value; + break; default: break; } diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index cd3ef3e7..47d2344e 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -123,6 +123,7 @@ enum wpa_sm_conf_params { WPA_PARAM_USE_EXT_KEY_ID, WPA_PARAM_FT_RSNXE_USED, WPA_PARAM_DPP_PFS, + WPA_PARAM_WMM_ENABLED, WPA_PARAM_OCI_FREQ_EAPOL, WPA_PARAM_OCI_FREQ_EAPOL_G2, WPA_PARAM_OCI_FREQ_FT_ASSOC, diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index a3c13b11..300ef547 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -220,6 +220,8 @@ struct wpa_sm { int dpp_pfs; #endif /* CONFIG_DPP2 */ struct wpa_sm_mlo mlo; + + bool wmm_enabled; }; diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index 50bd2b27..2a6c79b2 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -109,6 +109,10 @@ u16 rsn_supp_capab(struct wpa_sm *sm) { u16 capab = 0; + if (sm->wmm_enabled) { + /* Advertise 16 PTKSA replay counters when using WMM */ + capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; + } if (sm->mfp) capab |= WPA_CAPABILITY_MFPC; if (sm->mfp == 2) diff --git a/wpa_supplicant/README b/wpa_supplicant/README index c643b268..f8da7818 100644 --- a/wpa_supplicant/README +++ b/wpa_supplicant/README @@ -442,7 +442,9 @@ drivers: nl80211 = Linux nl80211/cfg80211 wext = Linux wireless extensions (generic) wired = wpa_supplicant wired Ethernet driver + macsec_linux = MACsec Ethernet driver for Linux roboswitch = wpa_supplicant Broadcom switch driver + none = no driver (RADIUS server/WPS ER only) bsd = BSD 802.11 support (Atheros, etc.) ndis = Windows NDIS driver diff --git a/wpa_supplicant/aidl/aidl.cpp b/wpa_supplicant/aidl/aidl.cpp index 6a22a2a6..f221862a 100644 --- a/wpa_supplicant/aidl/aidl.cpp +++ b/wpa_supplicant/aidl/aidl.cpp @@ -312,6 +312,22 @@ void wpas_aidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s) aidl_manager->notifyDisconnectReason(wpa_s); } +void wpas_aidl_notify_mlo_info_change_reason(struct wpa_supplicant *wpa_s, + enum mlo_info_change_reason reason) +{ + if (!wpa_s) + return; + + wpa_printf(MSG_DEBUG, "Notifying MLO info change reason to aidl control: %d", + reason); + + AidlManager *aidl_manager = AidlManager::getInstance(); + if (!aidl_manager) + return; + + aidl_manager->notifyMloLinksInfoChanged(wpa_s, reason); +} + void wpas_aidl_notify_assoc_reject(struct wpa_supplicant *wpa_s, const u8 *bssid, u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len) { diff --git a/wpa_supplicant/aidl/aidl.h b/wpa_supplicant/aidl/aidl.h index f9b374ea..dfe5c745 100644 --- a/wpa_supplicant/aidl/aidl.h +++ b/wpa_supplicant/aidl/aidl.h @@ -52,6 +52,10 @@ extern "C" void wpas_aidl_notify_hs20_rx_terms_and_conditions_acceptance( struct wpa_supplicant *wpa_s, const char *url); void wpas_aidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s); + void wpas_aidl_notify_mlo_info_change_reason( + struct wpa_supplicant *wpa_s, + enum mlo_info_change_reason reason); + void wpas_aidl_notify_assoc_reject(struct wpa_supplicant *wpa_s, const u8 *bssid, u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len); void wpas_aidl_notify_auth_timeout(struct wpa_supplicant *wpa_s); @@ -198,6 +202,9 @@ static void wpas_aidl_notify_hs20_rx_terms_and_conditions_acceptance( struct wpa_supplicant *wpa_s, const char *url) {} static void wpas_aidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s) {} +static void wpas_aidl_notify_mlo_info_change_reason( + struct wpa_supplicant *wpa_s, enum mlo_info_change_reason reason) +{} static void wpas_aidl_notify_assoc_reject(struct wpa_supplicant *wpa_s, const u8 *bssid, u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len) {} static void wpas_aidl_notify_auth_timeout(struct wpa_supplicant *wpa_s) {} diff --git a/wpa_supplicant/aidl/aidl_manager.cpp b/wpa_supplicant/aidl/aidl_manager.cpp index db566ab2..b3baf5b4 100644 --- a/wpa_supplicant/aidl/aidl_manager.cpp +++ b/wpa_supplicant/aidl/aidl_manager.cpp @@ -2666,6 +2666,23 @@ void AidlManager::notifyQosPolicyRequest(struct wpa_supplicant *wpa_s, std::placeholders::_1, wpa_s->dscp_req_dialog_token, qosPolicyData)); } +void AidlManager::notifyMloLinksInfoChanged(struct wpa_supplicant *wpa_s, + enum mlo_info_change_reason reason) +{ + if (!wpa_s) + return; + + if (sta_iface_object_map_.find(wpa_s->ifname) == + sta_iface_object_map_.end()) + return; + + callWithEachStaIfaceCallback( + misc_utils::charBufToString(wpa_s->ifname), + std::bind(&ISupplicantStaIfaceCallback::onMloLinksInfoChanged, + std::placeholders::_1, + static_cast<ISupplicantStaIfaceCallback::MloLinkInfoChangeReason>(reason))); +} + ssize_t AidlManager::getCertificate(const char* alias, uint8_t** value) { if (alias == nullptr || value == nullptr) { wpa_printf(MSG_ERROR, "Null pointer argument was passed to getCertificate"); diff --git a/wpa_supplicant/aidl/aidl_manager.h b/wpa_supplicant/aidl/aidl_manager.h index fcea1f72..8f1f1770 100644 --- a/wpa_supplicant/aidl/aidl_manager.h +++ b/wpa_supplicant/aidl/aidl_manager.h @@ -167,6 +167,8 @@ public: ssize_t listAliases(const char *prefix, char ***aliases); void notifyQosPolicyScsResponse(struct wpa_supplicant *wpa_s, unsigned int count, int **scs_resp); + void notifyMloLinksInfoChanged(struct wpa_supplicant *wpa_s, + enum mlo_info_change_reason reason); // Methods called from aidl objects. void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id); diff --git a/wpa_supplicant/aidl/sta_iface.cpp b/wpa_supplicant/aidl/sta_iface.cpp index afcd4b51..fb3ebcd5 100644 --- a/wpa_supplicant/aidl/sta_iface.cpp +++ b/wpa_supplicant/aidl/sta_iface.cpp @@ -2021,6 +2021,7 @@ ndk::ScopedAStatus StaIface::removeAllQosPoliciesInternal() std::pair<MloLinksInfo, ndk::ScopedAStatus> StaIface::getConnectionMloLinksInfoInternal() { struct wpa_supplicant *wpa_s = retrieveIfacePtr(); + struct driver_sta_mlo_info mlo; MloLinksInfo linksInfo; MloLink link; @@ -2028,6 +2029,7 @@ std::pair<MloLinksInfo, ndk::ScopedAStatus> StaIface::getConnectionMloLinksInfoI if (!wpa_s->valid_links) return {linksInfo, ndk::ScopedAStatus::ok()}; + wpas_drv_get_sta_mlo_info(wpa_s, &mlo); for (int i = 0; i < MAX_NUM_MLD_LINKS; i++) { if (!(wpa_s->valid_links & BIT(i))) continue; @@ -2055,8 +2057,13 @@ std::pair<MloLinksInfo, ndk::ScopedAStatus> StaIface::getConnectionMloLinksInfoI // mapping by the AP, a default TID-to-link mapping is assumed // unless an individual TID-to-link mapping is successfully // negotiated. - link.tidsUplinkMap = 0xFF; - link.tidsDownlinkMap = 0xFF; + if (!mlo.default_map) { + link.tidsUplinkMap = mlo.links[i].t2lmap.uplink; + link.tidsDownlinkMap = mlo.links[i].t2lmap.downlink; + } else { + link.tidsUplinkMap = 0xFF; + link.tidsDownlinkMap = 0xFF; + } linksInfo.links.push_back(link); } diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index a5d4d815..c843cb00 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2501,6 +2501,7 @@ static const struct parse_data ssid_fields[] = { { FUNC(freq_list) }, { INT_RANGE(ht, 0, 1) }, { INT_RANGE(vht, 0, 1) }, + { INT_RANGE(he, 0, 1) }, { INT_RANGE(ht40, -1, 1) }, { INT_RANGE(max_oper_chwidth, CONF_OPER_CHWIDTH_USE_HT, CONF_OPER_CHWIDTH_80P80MHZ) }, diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml index 898765c9..df538e33 100644 --- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml +++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml @@ -274,6 +274,13 @@ </varlistentry> <varlistentry> + <term>macsec_linux</term> + <listitem> + <para>MACsec Ethernet driver for Linux</para> + </listitem> + </varlistentry> + + <varlistentry> <term>roboswitch</term> <listitem> <para>wpa_supplicant Broadcom switch driver</para> @@ -281,6 +288,13 @@ </varlistentry> <varlistentry> + <term>none</term> + <listitem> + <para>no driver (RADIUS server/WPS ER only)</para> + </listitem> + </varlistentry> + + <varlistentry> <term>bsd</term> <listitem> <para>BSD 802.11 support (Atheros, etc.).</para> diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 253f87de..b09d51d4 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -60,6 +60,10 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, int new_scan, int own_request); #endif /* CONFIG_NO_SCAN_PROCESSING */ +#ifdef CONFIG_OWE +static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, + const u8 **ret_ssid, size_t *ret_ssid_len); +#endif /* CONFIG_OWE */ int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) @@ -187,6 +191,7 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { struct wpa_ssid *ssid, *old_ssid; + struct wpa_bss *bss; u8 drv_ssid[SSID_MAX_LEN]; size_t drv_ssid_len; int res; @@ -210,6 +215,14 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s, return 0; /* current profile still in use */ #ifdef CONFIG_OWE + if (wpa_s->current_bss && + !(wpa_s->current_bss->flags & WPA_BSS_OWE_TRANSITION)) { + const u8 *match_ssid; + size_t match_ssid_len; + + owe_trans_ssid(wpa_s, wpa_s->current_bss, + &match_ssid, &match_ssid_len); + } if ((wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_OWE) && wpa_s->current_bss && (wpa_s->current_bss->flags & WPA_BSS_OWE_TRANSITION) && @@ -254,6 +267,7 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "Network configuration found for the " "current AP"); + bss = wpa_supplicant_update_current_bss(wpa_s, wpa_s->bssid); if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) { u8 wpa_ie[80]; size_t wpa_ie_len = sizeof(wpa_ie); @@ -263,7 +277,7 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s, * driver indicated the actual values used in the * (Re)Association Request frame. */ skip_default_rsne = data && data->assoc_info.req_ies; - if (wpa_supplicant_set_suites(wpa_s, NULL, ssid, + if (wpa_supplicant_set_suites(wpa_s, bss, ssid, wpa_ie, &wpa_ie_len, skip_default_rsne) < 0) wpa_dbg(wpa_s, MSG_DEBUG, "Could not set WPA suites"); @@ -276,8 +290,6 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s, old_ssid = wpa_s->current_ssid; wpa_s->current_ssid = ssid; - wpa_supplicant_update_current_bss(wpa_s, wpa_s->bssid); - wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); wpa_supplicant_initiate_eapol(wpa_s); if (old_ssid != wpa_s->current_ssid) @@ -611,8 +623,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, #ifdef CONFIG_WEP int wep_ok; #endif /* CONFIG_WEP */ - bool is_6ghz_bss_or_mld = is_6ghz_freq(bss->freq) || - !is_zero_ether_addr(bss->mld_addr); + bool is_6ghz_bss = is_6ghz_freq(bss->freq); ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss); if (ret >= 0) @@ -627,10 +638,10 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, #endif /* CONFIG_WEP */ rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); - if (is_6ghz_bss_or_mld && !rsn_ie) { + if (is_6ghz_bss && !rsn_ie) { if (debug_print) wpa_dbg(wpa_s, MSG_DEBUG, - " skip - 6 GHz/MLD BSS without RSNE"); + " skip - 6 GHz BSS without RSNE"); return 0; } @@ -648,8 +659,8 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, if (!ie.has_group) ie.group_cipher = wpa_default_rsn_cipher(bss->freq); - if (is_6ghz_bss_or_mld) { - /* WEP and TKIP are not allowed on 6 GHz */ + if (is_6ghz_bss || !is_zero_ether_addr(bss->mld_addr)) { + /* WEP and TKIP are not allowed on 6 GHz/MLD */ ie.pairwise_cipher &= ~(WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104 | WPA_CIPHER_TKIP); @@ -699,12 +710,12 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, break; } - if (is_6ghz_bss_or_mld) { + if (is_6ghz_bss) { /* MFPC must be supported on 6 GHz */ if (!(ie.capabilities & WPA_CAPABILITY_MFPC)) { if (debug_print) wpa_dbg(wpa_s, MSG_DEBUG, - " skip RSNE - 6 GHz/MLD without MFPC"); + " skip RSNE - 6 GHz without MFPC"); break; } @@ -744,10 +755,10 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, return 1; } - if (is_6ghz_bss_or_mld) { + if (is_6ghz_bss) { if (debug_print) wpa_dbg(wpa_s, MSG_DEBUG, - " skip - 6 GHz/MLD BSS without matching RSNE"); + " skip - 6 GHz BSS without matching RSNE"); return 0; } @@ -1828,6 +1839,7 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *selected, struct wpa_ssid *ssid) { +#ifdef IEEE8021X_EAPOL if ((eap_is_wps_pbc_enrollee(&ssid->eap) && wpas_wps_partner_link_overlap_detect(wpa_s)) || wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) { @@ -1850,6 +1862,7 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s, #endif /* CONFIG_WPS */ return -1; } +#endif /* IEEE8021X_EAPOL */ wpa_msg(wpa_s, MSG_DEBUG, "Considering connect request: reassociate: %d selected: " @@ -3793,7 +3806,13 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, wpas_fst_update_mb_assoc(wpa_s, data); #ifdef CONFIG_SME - os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN); + /* + * Cache the current AP's BSSID (for non-MLO connection) or MLD address + * (for MLO connection) as the previous BSSID for subsequent + * reassociation requests handled by SME-in-wpa_supplicant. + */ + os_memcpy(wpa_s->sme.prev_bssid, + wpa_s->valid_links ? wpa_s->ap_mld_addr : bssid, ETH_ALEN); wpa_s->sme.prev_bssid_set = 1; wpa_s->sme.last_unprot_disconnect.sec = 0; #endif /* CONFIG_SME */ @@ -3889,6 +3908,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, * EVENT_PORT_AUTHORIZED handler when the driver is done * with the 4-way handshake. */ + wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE); wpa_msg(wpa_s, MSG_INFO, "ASSOC INFO: wait for driver port authorized indication"); } @@ -5020,7 +5040,7 @@ static void wpa_supplicant_notify_avoid_freq(struct wpa_supplicant *wpa_s, static void wpa_supplicant_event_port_authorized(struct wpa_supplicant *wpa_s) { - if (wpa_s->wpa_state == WPA_ASSOCIATED) { + if (wpa_s->wpa_state >= WPA_ASSOCIATED) { wpa_supplicant_cancel_auth_timeout(wpa_s); wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); eapol_sm_notify_portValid(wpa_s->eapol, true); @@ -5382,6 +5402,99 @@ static void wpas_event_unprot_beacon(struct wpa_supplicant *wpa_s, } +static const char * bitmap_to_str(u8 value, char *buf) +{ + char *pos = buf; + int i, k = 0; + + for (i = 7; i >= 0; i--) + pos[k++] = (value & BIT(i)) ? '1' : '0'; + + pos[8] = '\0'; + return pos; +} + + +static void wpas_tid_link_map(struct wpa_supplicant *wpa_s, + struct tid_link_map_info *info) +{ + char map_info[1000], *pos, *end; + int res, i; + + pos = map_info; + end = pos + sizeof(map_info); + res = os_snprintf(map_info, sizeof(map_info), "default=%d", + info->default_map); + if (os_snprintf_error(end - pos, res)) + return; + pos += res; + + if (!info->default_map) { + for (i = 0; i < MAX_NUM_MLD_LINKS && end > pos; i++) { + char uplink_map_str[9]; + char downlink_map_str[9]; + + if (!(info->valid_links & BIT(i))) + continue; + + bitmap_to_str(info->t2lmap[i].uplink, uplink_map_str); + bitmap_to_str(info->t2lmap[i].downlink, + downlink_map_str); + + res = os_snprintf(pos, end - pos, + " link_id=%d up_link=%s down_link=%s", + i, uplink_map_str, + downlink_map_str); + if (os_snprintf_error(end - pos, res)) + return; + pos += res; + } + } + + wpas_notify_mlo_info_change_reason(wpa_s, MLO_TID_TO_LINK_MAP); + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_T2LM_UPDATE "%s", map_info); +} + + +static void wpas_link_reconfig(struct wpa_supplicant *wpa_s) +{ + u8 bssid[ETH_ALEN]; + + if (wpa_drv_get_bssid(wpa_s, bssid) < 0) { + wpa_printf(MSG_ERROR, "LINK_RECONFIG: Failed to get BSSID"); + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + return; + } + + if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) { + os_memcpy(wpa_s->bssid, bssid, ETH_ALEN); + wpa_supplicant_update_current_bss(wpa_s, wpa_s->bssid); + wpas_notify_bssid_changed(wpa_s); + } + + if (wpa_drv_get_mlo_info(wpa_s) < 0) { + wpa_printf(MSG_ERROR, + "LINK_RECONFIG: Failed to get MLO connection info"); + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + return; + } + + if (wpa_sm_set_ml_info(wpa_s)) { + wpa_printf(MSG_ERROR, + "LINK_RECONFIG: Failed to set MLO connection info to wpa_sm"); + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + return; + } + + wpas_notify_mlo_info_change_reason(wpa_s, MLO_LINK_RECONFIG_AP_REMOVAL); + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_LINK_RECONFIG "valid_links=0x%x", + wpa_s->valid_links); +} + + void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { @@ -5481,6 +5594,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpas_event_deauth(wpa_s, data ? &data->deauth_info : NULL); break; + case EVENT_LINK_RECONFIG: + wpas_link_reconfig(wpa_s); + break; case EVENT_MICHAEL_MIC_FAILURE: wpa_supplicant_event_michael_mic_failure(wpa_s, data); break; @@ -6291,6 +6407,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpas_dpp_tx_wait_expire(wpa_s); #endif /* CONFIG_DPP */ break; + case EVENT_TID_LINK_MAP: + if (data) + wpas_tid_link_map(wpa_s, &data->t2l_map_info); + break; default: wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event); break; diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c index da6d9db0..c9e14d5c 100644 --- a/wpa_supplicant/mesh_mpm.c +++ b/wpa_supplicant/mesh_mpm.c @@ -771,7 +771,7 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s, #ifdef CONFIG_IEEE80211AC copy_sta_vht_capab(data, sta, elems->vht_capabilities); copy_sta_vht_oper(data, sta, elems->vht_operation); - set_sta_vht_opmode(data, sta, elems->vht_opmode_notif); + set_sta_vht_opmode(data, sta, elems->opmode_notif); #endif /* CONFIG_IEEE80211AC */ #ifdef CONFIG_IEEE80211AX diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index 89a0389e..c6e2dbe2 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -154,6 +154,16 @@ void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s) } +void wpas_notify_mlo_info_change_reason(struct wpa_supplicant *wpa_s, + enum mlo_info_change_reason reason) +{ + if (wpa_s->p2p_mgmt) + return; + + wpas_aidl_notify_mlo_info_change_reason(wpa_s, reason); +} + + void wpas_notify_auth_status_code(struct wpa_supplicant *wpa_s) { if (wpa_s->p2p_mgmt) diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h index bc2bd64a..c41aa6e1 100644 --- a/wpa_supplicant/notify.h +++ b/wpa_supplicant/notify.h @@ -229,5 +229,7 @@ void wpas_notify_pmk_cache_added(struct wpa_supplicant *wpa_s, void wpas_notify_signal_change(struct wpa_supplicant *wpa_s); void wpas_notify_qos_policy_scs_response(struct wpa_supplicant *wpa_s, unsigned int num_scs_resp, int **scs_resp); +void wpas_notify_mlo_info_change_reason(struct wpa_supplicant *wpa_s, + enum mlo_info_change_reason reason); #endif /* NOTIFY_H */ diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index ea4023c8..8068f1ef 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -378,10 +378,12 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s, } -static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) +static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, + struct wpa_ssid *ssid) { struct wpabuf *mlbuf; - const u8 *rnr_ie, *pos; + const u8 *rnr_ie, *pos, *rsn_ie; + struct wpa_ie_data ie; u8 ml_ie_len, rnr_ie_len; const struct ieee80211_eht_ml *eht_ml; const struct eht_ml_basic_common_info *ml_basic_common_info; @@ -402,6 +404,26 @@ static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) return false; } + rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); + if (!rsn_ie || wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) { + wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RSN element"); + goto out; + } + + if (!(ie.capabilities & WPA_CAPABILITY_MFPC) || + wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION) { + wpa_dbg(wpa_s, MSG_DEBUG, + "MLD: No management frame protection"); + goto out; + } + + ie.key_mgmt &= ~(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_PSK_SHA256); + if (!(ie.key_mgmt & ssid->key_mgmt)) { + wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No valid key management"); + goto out; + } + ml_ie_len = wpabuf_len(mlbuf); /* control + common info len + MLD address + MLD link information */ @@ -525,20 +547,28 @@ static void wpas_sme_ml_auth(struct wpa_supplicant *wpa_s, { struct ieee802_11_elems elems; const u8 *mld_addr; + u16 status_code = data->auth.status_code; if (!wpa_s->valid_links) return; if (ieee802_11_parse_elems(data->auth.ies + ie_offset, data->auth.ies_len - ie_offset, - &elems, 0) != ParseOK) { + &elems, 0) == ParseFailed) { wpa_printf(MSG_DEBUG, "MLD: Failed parsing elements"); goto out; } if (!elems.basic_mle || !elems.basic_mle_len) { wpa_printf(MSG_DEBUG, "MLD: No ML element in authentication"); - goto out; + if (status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ || + status_code == WLAN_STATUS_SUCCESS || + status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT || + status_code == WLAN_STATUS_SAE_PK) + goto out; + /* Accept missing Multi-Link element in failed authentication + * cases. */ + return; } mld_addr = get_basic_mle_mld_addr(elems.basic_mle, elems.basic_mle_len); @@ -604,7 +634,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, params.ssid_len = bss->ssid_len; params.p2p = ssid->p2p_group; - if (wpas_ml_element(wpa_s, bss)) { + if (wpas_ml_element(wpa_s, bss, ssid)) { wpa_printf(MSG_DEBUG, "MLD: In authentication"); params.mld = true; params.mld_link_id = wpa_s->mlo_assoc_link_id; @@ -1596,20 +1626,28 @@ static int sme_check_sae_rejected_groups(struct wpa_supplicant *wpa_s, static int sme_external_ml_auth(struct wpa_supplicant *wpa_s, - const u8 *data, size_t len, int ie_offset) + const u8 *data, size_t len, int ie_offset, + u16 status_code) { struct ieee802_11_elems elems; const u8 *mld_addr; if (ieee802_11_parse_elems(data + ie_offset, len - ie_offset, - &elems, 0) != ParseOK) { + &elems, 0) == ParseFailed) { wpa_printf(MSG_DEBUG, "MLD: Failed parsing elements"); return -1; } if (!elems.basic_mle || !elems.basic_mle_len) { wpa_printf(MSG_DEBUG, "MLD: No ML element in authentication"); - return -1; + if (status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ || + status_code == WLAN_STATUS_SUCCESS || + status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT || + status_code == WLAN_STATUS_SAE_PK) + return -1; + /* Accept missing Multi-Link element in failed authentication + * cases. */ + return 0; } mld_addr = get_basic_mle_mld_addr(elems.basic_mle, elems.basic_mle_len); @@ -1623,7 +1661,8 @@ static int sme_external_ml_auth(struct wpa_supplicant *wpa_s, if (os_memcmp(wpa_s->sme.ext_auth_ap_mld_addr, mld_addr, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "MLD: Unexpected MLD address (expected " - MACSTR ")", MAC2STR(wpa_s->ap_mld_addr)); + MACSTR ")", + MAC2STR(wpa_s->sme.ext_auth_ap_mld_addr)); return -1; } @@ -1714,7 +1753,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, wpa_s->current_ssid, 2); } else { if (wpa_s->sme.ext_ml_auth && - sme_external_ml_auth(wpa_s, data, len, *ie_offset)) + sme_external_ml_auth(wpa_s, data, len, *ie_offset, + status_code)) return -1; sme_external_auth_send_sae_commit( @@ -1741,7 +1781,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, wpa_s->current_ssid, 1); } else { if (wpa_s->sme.ext_ml_auth && - sme_external_ml_auth(wpa_s, data, len, *ie_offset)) + sme_external_ml_auth(wpa_s, data, len, *ie_offset, + status_code)) return -1; sme_external_auth_send_sae_commit( @@ -1840,7 +1881,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, wpa_s->current_ssid, 0); } else { if (wpa_s->sme.ext_ml_auth && - sme_external_ml_auth(wpa_s, data, len, *ie_offset)) + sme_external_ml_auth(wpa_s, data, len, *ie_offset, + status_code)) return -1; sme_external_auth_send_sae_confirm(wpa_s, sa); @@ -1856,7 +1898,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, ie_offset) < 0) return -1; if (external && wpa_s->sme.ext_ml_auth && - sme_external_ml_auth(wpa_s, data, len, *ie_offset)) + sme_external_ml_auth(wpa_s, data, len, *ie_offset, + status_code)) return -1; wpa_s->sme.sae.state = SAE_ACCEPTED; diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index f808ac42..effc7b3b 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -1427,7 +1427,7 @@ static const char *network_fields[] = { "bssid_accept", "psk", "proto", "key_mgmt", "bg_scan_period", "pairwise", "group", "auth_alg", "scan_freq", "freq_list", "max_oper_chwidth", "ht40", "vht", "vht_center_freq1", - "vht_center_freq2", "ht", "edmg", + "vht_center_freq2", "ht", "edmg", "he", #ifdef IEEE8021X_EAPOL "eap", "identity", "anonymous_identity", "password", "ca_cert", "ca_path", "client_cert", "private_key", "private_key_passwd", diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 1344ef6a..a3645d1c 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1587,6 +1587,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, int sel, proto; enum sae_pwe sae_pwe; const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen; + bool wmm; if (bss) { bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); @@ -1983,6 +1984,22 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID, 0); } + /* Mark WMM enabled for any HT/VHT/HE/EHT association to get more + * appropriate advertisement of the supported number of PTKSA receive + * counters. In theory, this could be based on a driver capability, but + * in practice all cases using WMM support at least eight replay + * counters, so use a hardcoded value for now since there is no explicit + * driver capability indication for this. + * + * In addition, claim WMM to be enabled if the AP supports it since it + * is far more likely for any current device to support WMM. */ + wmm = wpa_s->connection_set && + (wpa_s->connection_ht || wpa_s->connection_vht || + wpa_s->connection_he || wpa_s->connection_eht); + if (!wmm && bss) + wmm = wpa_bss_get_vendor_ie(bss, WMM_IE_VENDOR_TYPE); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_WMM_ENABLED, wmm); + if (!skip_default_rsne) { if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) { @@ -3975,7 +3992,16 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) return; } - os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN); + /* + * Set the current AP's BSSID (for non-MLO connection) or MLD address + * (for MLO connection) as the previous BSSID for reassociation requests + * handled by SME-in-driver. If wpa_supplicant is in disconnected state, + * prev_bssid will be zero as both wpa_s->valid_links and wpa_s->bssid + * will be zero. + */ + os_memcpy(prev_bssid, + wpa_s->valid_links ? wpa_s->ap_mld_addr : wpa_s->bssid, + ETH_ALEN); os_memset(¶ms, 0, sizeof(params)); wpa_s->reassociate = 0; wpa_s->eap_expected_failure = 0; @@ -4829,7 +4855,8 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, wpa_s->current_ssid = ssid; eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); wpa_s->connect_without_scan = - (ssid->mode == WPAS_MODE_MESH) ? ssid : NULL; + (ssid->mode == WPAS_MODE_MESH || + ssid->mode == WPAS_MODE_AP) ? ssid : NULL; /* * Don't optimize next scan freqs since a new ESS has been diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 8753fbaa..a8abf9ae 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -1378,6 +1378,13 @@ fast_reauth=1 # * 0 = do not use cryptobinding (default) # * 1 = use cryptobinding if server supports it # * 2 = require cryptobinding +# 'phase2_auth' option can be used to control Phase 2 (i.e., within TLS +# tunnel) behavior for PEAP: +# * 0 = do not require Phase 2 authentication +# * 1 = require Phase 2 authentication when client certificate +# (private_key/client_cert) is not used and TLS session resumption was +# not used (default) +# * 2 = require Phase 2 authentication in all cases # EAP-WSC (WPS) uses following options: pin=<Device Password> or # pbc=1. # diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf index cec26c48..6a2fbd37 100644 --- a/wpa_supplicant/wpa_supplicant_template.conf +++ b/wpa_supplicant/wpa_supplicant_template.conf @@ -9,3 +9,4 @@ oce=1 sae_pwe=2 p2p_optimize_listen_chan=1 wowlan_disconnect_on_deinit=1 +sae_pmkid_in_assoc=1 |