aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2023-12-09 00:11:48 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2023-12-09 00:11:48 +0000
commit90fff35dcbb48a55de1aca139aff4312c6eb007f (patch)
treefb24e508615cdd9f6914bd2311811aa13ca19e37
parent6d755ae3182b871a753223d842aeed5e5f1002b8 (diff)
parentb7505b0d3261cd27551d0788f12e0fb713988996 (diff)
downloadwpa_supplicant_8-90fff35dcbb48a55de1aca139aff4312c6eb007f.tar.gz
Merge "Merge Android 14 QPR1" into main
-rw-r--r--hostapd/aidl/hostapd.cpp51
-rw-r--r--hostapd/config_file.c2
-rw-r--r--hostapd/ctrl_iface.c30
-rw-r--r--hostapd/hostapd.conf5
-rw-r--r--hostapd/hostapd_cli.c2
-rw-r--r--src/ap/ap_config.c1
-rw-r--r--src/ap/ap_config.h3
-rw-r--r--src/ap/ap_drv_ops.c12
-rw-r--r--src/ap/ap_drv_ops.h5
-rw-r--r--src/ap/beacon.c52
-rw-r--r--src/ap/drv_callbacks.c3
-rw-r--r--src/ap/hostapd.c18
-rw-r--r--src/ap/hw_features.c25
-rw-r--r--src/ap/ieee802_11.c121
-rw-r--r--src/ap/ieee802_11.h5
-rw-r--r--src/ap/ieee802_1x.c27
-rw-r--r--src/ap/sta_info.c20
-rw-r--r--src/ap/sta_info.h3
-rw-r--r--src/ap/wpa_auth_ft.c7
-rw-r--r--src/common/defs.h5
-rw-r--r--src/common/ieee802_11_common.c55
-rw-r--r--src/common/ieee802_11_common.h2
-rw-r--r--src/common/ieee802_11_defs.h12
-rw-r--r--src/common/qca-vendor.h580
-rw-r--r--src/common/wpa_common.c2
-rw-r--r--src/common/wpa_ctrl.h4
-rw-r--r--src/drivers/driver.h70
-rw-r--r--src/drivers/driver_common.c2
-rw-r--r--src/drivers/driver_nl80211.c101
-rw-r--r--src/drivers/driver_nl80211.h5
-rw-r--r--src/drivers/driver_nl80211_capa.c3
-rw-r--r--src/drivers/driver_nl80211_event.c211
-rw-r--r--src/drivers/driver_nl80211_scan.c2
-rw-r--r--src/drivers/nl80211_copy.h24
-rw-r--r--src/eap_peer/eap_config.h8
-rw-r--r--src/eap_peer/eap_peap.c40
-rw-r--r--src/eap_peer/eap_tls_common.c6
-rw-r--r--src/eap_peer/eap_tls_common.h5
-rw-r--r--src/eap_peer/eap_ttls.c28
-rw-r--r--src/eapol_auth/eapol_auth_sm.c26
-rw-r--r--src/eapol_auth/eapol_auth_sm.h4
-rw-r--r--src/eapol_auth/eapol_auth_sm_i.h4
-rw-r--r--src/pasn/pasn_common.h3
-rw-r--r--src/pasn/pasn_responder.c6
-rw-r--r--src/rsn_supp/wpa.c3
-rw-r--r--src/rsn_supp/wpa.h1
-rw-r--r--src/rsn_supp/wpa_i.h2
-rw-r--r--src/rsn_supp/wpa_ie.c4
-rw-r--r--wpa_supplicant/README2
-rw-r--r--wpa_supplicant/aidl/aidl.cpp16
-rw-r--r--wpa_supplicant/aidl/aidl.h7
-rw-r--r--wpa_supplicant/aidl/aidl_manager.cpp17
-rw-r--r--wpa_supplicant/aidl/aidl_manager.h2
-rw-r--r--wpa_supplicant/aidl/sta_iface.cpp11
-rw-r--r--wpa_supplicant/config.c1
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.sgml14
-rw-r--r--wpa_supplicant/events.c150
-rw-r--r--wpa_supplicant/mesh_mpm.c2
-rw-r--r--wpa_supplicant/notify.c10
-rw-r--r--wpa_supplicant/notify.h2
-rw-r--r--wpa_supplicant/sme.c69
-rw-r--r--wpa_supplicant/wpa_cli.c2
-rw-r--r--wpa_supplicant/wpa_supplicant.c31
-rw-r--r--wpa_supplicant/wpa_supplicant.conf7
-rw-r--r--wpa_supplicant/wpa_supplicant_template.conf1
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, &params.allowed_freqs);
+ }
+
res = hostapd_drv_set_ap(hapd, &params);
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, &current_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,
- &current_len);
+ &current_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,
- &current_len);
+ &current_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,
&current_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,
- &current_len);
+ &current_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,
- &current_len);
+ &current_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(&params, 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