[wpa_supplicant] cumilative patch from commit 92374d59d
This merge is done mainly to support RSNE overriding for STA.
Bug: 348669010
Bug: 355076858
Test: Connect to open, WPA2, WPA3 and OWE
Test: Establish P2P connection
Test: Basic SoftAp tests
Test: Ran above tests on Pixel6
Test: Regression test (b/355078233)
BYPASS_INCLUSIVE_LANGUAGE_REASON=Merged from open source
92374d59d Enhance select_network() to trigger new scans in some cases
ff99012d8 RSNO: Use correct MLO capability while fetching RSNE/RSNXE
526ea193c Fallback to RSNXE when AP is not using valid RSN Overrding
4417b5ba8 Add QCA vendor interface to support Unsynchronized Service Discovery
765c48d5a RSNE/RSNXE overriding for STA
d0b55eb36 Make driver capabilities for AKM suites available within wpa_supplicant
5488e120d Use helper functions to access RSNE/RSNXE from BSS entries
341bcb2b5 nl80211: Add a capability flag for RSN overriding
6fad7224b Add QCA vendor feature flags to indicate RSN override elements support
157b01638 RSNE/RSNXE overriding for AP
b8a2d11ae Allow RSNXE Override element to override RSNXE contents during parsing
48ca68f6f Allow RSNE Override element to override RSNE contents during parsing
c16ac89be Add RSN overriding elements into IE parsing
6b0ce29d2 Define WFA vendor specific element types for RSNE/RSNXE overriding
e99cdfae4 The main branch is now used for v2.12 development
d945ddd36 Preparations for v2.11 release
aa2dfae5e dbus: Fix memory leak with Bonjour params for a P2P UPnP service
70e5bad56 dbus: Fix SignalChange property
ed5887a8c Move NULL check for driver private data (drv_priv)
c3d305d93 FT: Fix FTE MIC calculation with fragmented FTE
e7172e26d MLD STA: Find partner links by BSSID and SSID
816e22bba hostapd: Fix opclass during CSA with DFS channels
93a3c59ad Multi-AP: Honor wds_sta even with multi_ap
7d51bf2ab SAE: Drop default dot11RSNASAESync value from 5 to 3
5da59ff1c SAE: Disable protocol instance temporarily on sync error in mesh
7b8517d19 nl80211: Fix AP scan with STA fallback error path
6ad59779c nl80211: NAN: Register multicast action frames if possible
92829d8be NAN: Reject undefined publish type
44f20382c NAN: Fix a typo in USD doc
7c935eef3 nl80211: AP MLD: Reassign drv->ctx correctly to prevent hostapd crash
102365453 Make Beacon frame checks less frequent for SSID verification
fcf799c0d wpa_supplicant: Do not select a rejected SAE group
5f83f4db0 Add int_array_includes()
094e188f8 wpa_supplicant: Always clear SAE rejected groups on roaming to another BSS
627b67f29 ACS: Fix primary channel puncturing in ACS
be2ac9291 ACS: Fix ACS behavior for channel selection
83cfeb890 ACS: Update ACS documentation
cb91ef256 MLO: Swap Tx/Rx keys for GTK TKIP Michael MIC in MLO GTK KDE
7d314d6bd Fix channel switch without 'ht' for HE and EHT modes in 2.4 GHz band
99e82880e Fix mesh 6 GHz incorrect channel bandwidth
5452a4a30 SSID verification based on beacon protection
89b164138 BSS: Add wpa_bss_get_ie_beacon()
7436b5b01 Indicate if BIGTK has been set in STATUS output
c6f394b88 Indicate if SSID has been verified in STATUS output
b745cd33e PASN: Derive KDK on AP only when both ends support SecureLTF
e5f76b915 dbus: Fix error path in scan request handling
58b275955 trace: Only permit explicit prefix matching for functions
49344db09 trace: Use strncmp() to match function names
ac15b79fe PMKSA: Guard against NULL KCK for memcpy()
7bcede06e MLD: Ensure link_bssid array has space for sentinel
cf3883f3d MLD: Ensure link BSSIDs remain on stack for ignore
9f0429c9e dbus: Make sure ServiceDiscoveryRequest/Result does not override pointers
d22401d89 dbus: Fix memory leak in case dbus provides 'tlvs' in invalid P2P SD response
0c2d8417c dbus: Fix memory leak in case dbus provides tlv in P2P UPnP SD request
3b4f12708 nl80211: Use actual number of supported AKMs for AP setup
8f69e538a SecureLTF: Work around misbehaving STAs for PTK derivation without KDK
438a27b36 Do not derive SAE PT if the network profile does not include SAE
61eb89d5f nl80211: AP MLD: Parse link ID to determine the BSS for color event
5d16ad9ab nl80211: Refactor color collision related nl80211 commands handling
22a592d11 hostapd: Fix updating Beacon frames during association handling
9716bf116 SAE: Reject invalid Rejected Groups element in the parser
593a7c2f8 SAE: Check for invalid Rejected Groups element length explicitly on STA
5f98c853e nl80211: Send link ID with NL80211_CMD_TDLS_MGMT to enable TDLS with MLO
f302d9f96 RADIUS: Check Message-Authenticator if it is present even if not required
58097123e RADIUS: Require Message-Authenticator attribute in MAC ACL cases
934b0c3a4 Require Message-Authenticator in Access-Reject even without EAP-Message
f54157077 RADIUS DAS: Move Message-Authenticator attribute to be the first one
37fe8e48a hostapd: Move Message-Authenticator attribute to be the first one in req
689a24826 eapol_test: Move Message-Authenticator attribute to be the first one
54abb0d3c RADIUS server: Place Message-Authenticator attribute as the first one
adac846bd RADIUS: Allow Message-Authenticator attribute as the first attribute
d944ef1c0 SAE: Clear rejected groups list on completing authentication
0ab009db3 SAE: Clear rejected groups list on continuous failures
21fe04281 SAE: Clear peer_rejected_groups when no element is included
364c2da87 SAE: Check for invalid Rejected Groups element length explicitly
c9db4925f Vendor attribute to configure STA to follow AP preference for candidates
0cb42655f Vendor command extension for Responder PM Mode bit in TWT SET Request
9832f1324 Add vendor flag to indicate unavailability mode in TWT responder mode
761041b18 SAE: Free password identifier if SAE commit is rejected due to it
d97b5c649 Define Link Id attribute for secure ranging context vendor command
2097de2a6 Define Link Id attribute for QCA_NL80211_VENDOR_SUBCMD_PASN
c6e55fb96 Add Link ID for External ACS vendor command
37a289f8b SSID protection in 4-way handshake on AP
dab7549d6 SSID protection in 4-way handshake on STA
9a022cdc7 STA: Update scan results when BSS entry with current SSID is not found
320c4c8f8 AP MLD: Send link id to the driver during color change
ecfe2aa61 Update Beacon frames after color change
5913d1a18 Remove double "on" from debug prints in CCA event callbacks
d8e1a353a hostapd: Add support to change BSS color from the control interface
3e52a90d3 ACS: Handle scan start request failure with error code -EBUSY
3cf7bf68f AP MLD: Fix deferred first link BSS's authentication server init
2829f1c43 wlantest: Initial support for Multiple BSSID procedure
1b96745f1 Add a new QCA vendor attribute to set interface offload type
ffcb7392f Add vendor attributes to detect data stall for consecutive TX no ack
a5ee11e02 Add new traffic type values for flow report vendor attribute
2c89b56d6 WNM: Include BSS max idle period in STATUS command output
58ac46baf WNM: AP configuration to allow BSS max idle period requests
6594ea9ef WNM: Allow a specific BSS max idle period to be requested
6cd023111 WNM: Group rekeying skipping with BSS max idle period management
846b1d618 WNM: Configurable BSS Max Idle Period management on AP
7566370a9 Add QCA vendor attribute to get number of TX/RX packets for each NSS
4c0ea8270 Add vendor attributes to configure TX/RX NSS and chains per band
c484a0fca Add kernel documentation for nss and chain configuration vendor command
cb40986a7 Add QCA vendor attribute for uplink delay jitter
ed56dfc33 P2P: Fix fast IP address allocation for invitation of a persistent group
0ae087994 Add a new QCA vendor attribute to set reduced power scan mode
bd36dc90f AP MLD: Remove unused get_ml_rsn_info callback definition
51b5b9512 Update Probe Response template on BSS color change
6f1fbebeb Update Probe Response template on channel switch
7d0c08910 More generic unsolicited broadcast Probe Response template setup
195cc3d91 Make selection of current opclass more generic for 20 MHz UNI-III channels
b9113105a FILS: Add Operating Class and Primary Channel in FD for non-PSC chan
5929b4eb1 Define QCA vendor commands for flow stats/classification
5308029f8 nl80211: Update link bandwidth when receiving channel switch event
11dfdf64c AP MLD: Set link_id field in hostapd_freq_params when setting up AP
df14f1e2b Add QCA vendor subcommand to suspend/resume AP interface
df5988004 AP MLD: Add MLO Link KDE for each affiliated link in EAPOL-Key 3/4
b26971774 AP MLD: Do not store per-supplicant AP RSNE/RSNXE information
20872d525 AP MLD: Do not store per-supplicant AP link MAC address information
3b68eef7d AP MLD: Do not store per-supplicant AP MLD MAC address information
ed78f56dc Add a vendor attribute value to set aggressive roaming mode
e6ec62aa2 Allow Session-Timeout with PSK RADIUS during 4-way handshake
f44a07d5c wpa_cli: Make WPA_EVENT_CHANNEL_SWITCH events accessible to action scripts
2e1f7d091 Fix center segment indexes in channel switch fallback to non-5 GHz cases
7cf3ceada P2P: Call normal SD query callback on RX/TX race
9b1e0ab4e dbus: Use correct values for persistent group
cf36ffd43 wpa_supplicant: Do not allow fast associate before scanning 6 GHz
ff798fbb8 ctrl_iface: Allow sending ML probe without AP MLD ID
4d2f76fab MLD: Use AP MLD MAC address with deauthenticate
5d9b4a1a1 SME: MLD: Clear MLD state only after the deauthentication
39fefeada SME: MLD: Deauthenticate when failing to parse ML element
6f3e7c5d3 wpa_supplicant: Do not roam to an associated link
2bbe4822a Clear connect_without_scan on network profile removal
b3ad54e46 Check whether to skip a BSS in RNR with a shared helper
de1bfda64 Fix RNR building for co-location and MLO
8d434bf65 AP MLD: Add link details in STATUS command
b1e463374 AP MLD: Link-specific flushing of stations
5e3c2b489 AP MLD: Run authenticator state machine for all links
12acda633 AP MLD: Support group rekeying for MLO
62a8f96e5 AP MLD: Calculate ML KDE length separately for each link
78adbf2c0 AP MLD: Mark GKeyDone completed for STAs in a helper function
e5b49876a AP MLD: Debug print of MLO KDE lengths
84d2a36da AP MLD: Require same AKM and pairwise cipher for all links
8891ebdc1 Use defined values for RSN PN length
3ea7cf11d AP MLD: Enhance authenticator state machine
19fdcf511 AP MLD: Skip association link processing in ML info
4a1197acd AP MLD: Update all partner links' beacons
a51881032 AP MLD: Handle link_id in EAPOL RX handler
eea52c4b5 AP MLD: Handle link_id in EAPOL TX status handler
636530bc2 hostapd: Make hostapd_eapol_tx_status() function static
93d204b1e nl80211: Move control port TX status to per BSS handling
efb484bbc nl80211: Move Management frame TX status to per BSS handling
80864d011 AP MLD/nl80211: Pass ctx in mlme_event_mgmt()
c36ad1150 AP MLD: Use link_id in the get_hapd_bssid() helper function
d9c5d601f AP NLD: Extend support for cohosted ML BSS
3d0cc612f AP MLD: Support cohosted ML BSS
9098535ef AP MLD: Reset authenticator state machine's ML info
866ed6324 Remove the bssid argument from send_auth_reply()
fd1a35e14 AP MLD: Handle authentication and association on link address
e4e772456 AP MLD: Use if/else/endif comments more consistently
9fcc636da nl80211: Restore libnl3-route inclusion for full VLAN support with netlink
61c8cc94f Add a vendor attribute to configure custom keep-alive interval for STA
47d1307d2 Add QCA vendor interface for reporting station info in unicast event
3c79173c3 Add TWT responder support for AP in HT and VHT modes
54b1df85c Add QCA vendor feature flag for TWT responder support in HT and VHT modes
85ea5f349 nl80211: Send link_id on sta_deauth()
62e0c1019 nl80211: Print the interface name in debug during link add
e8764518b nl80211: Generate link add command on per-BSS basis for AP MLD
16aea07e5 AP MLD: Simplify for_each_mld_link() macro
d43eb71da hostapd: Add support for testing Probe Response frame elements
Change-Id: I445ef0fed93ec7d4443ed33751318a46899e61e7
Signed-off-by: Sunil Ravi <sunilravi@google.com>
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 28b0ba7..f5b36d3 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -12,6 +12,7 @@
#include "utils/common.h"
#include "utils/list.h"
+#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/hw_features_common.h"
#include "common/wpa_ctrl.h"
@@ -75,7 +76,7 @@
*
* This corresponds to:
* ---
- * (busy time - tx time) / (active time - tx time) * 2^(chan_nf + band_min_nf)
+ * (busy time - tx time) / (active time - tx time) * 2^(chan_nf - band_min_nf)
* ---
*
* The coefficient of 2 reflects the way power in "far-field"
@@ -92,7 +93,7 @@
* calculated easily.
* ---
* (busy time - tx time) / (active time - tx time) *
- * 2^(10^(chan_nf/10) + 10^(band_min_nf/10))
+ * 2^(10^(chan_nf/10) - 10^(band_min_nf/10))
* ---
*
* However to account for cases where busy/rx time is 0 (channel load is then
@@ -100,7 +101,7 @@
* channel with lower noise floor is preferred. The equation becomes:
* ---
* 10^(chan_nf/5) + (busy time - tx time) / (active time - tx time) *
- * 2^(10^(chan_nf/10) + 10^(band_min_nf/10))
+ * 2^(10^(chan_nf/10) - 10^(band_min_nf/10))
* ---
*
* All this "interference factor" is purely subjective and only time
@@ -307,6 +308,7 @@
static int acs_request_scan(struct hostapd_iface *iface);
static int acs_survey_is_sufficient(struct freq_survey *survey);
+static void acs_scan_retry(void *eloop_data, void *user_data);
static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
@@ -352,6 +354,8 @@
iface->chans_surveyed = 0;
iface->acs_num_completed_scans = 0;
+ iface->acs_num_retries = 0;
+ eloop_cancel_timeout(acs_scan_retry, iface, NULL);
}
@@ -507,7 +511,7 @@
}
if (ret == -1)
- ret = 1; /* no survey list entries */
+ ret = 0; /* no survey list entries */
if (!ret) {
wpa_printf(MSG_INFO,
@@ -830,6 +834,9 @@
int bw320_offset = 0, ideal_bw320_offset = 0;
unsigned int k;
int secondary_channel = 1, freq_offset;
+#ifdef CONFIG_IEEE80211BE
+ int index_primary = 0;
+#endif /* CONFIG_IEEE80211BE */
if (is_24ghz_mode(mode->mode))
secondary_channel = iface->conf->secondary_channel;
@@ -969,6 +976,9 @@
best->chan, chan->chan,
chan->interference_factor,
best->interference_factor);
+#ifdef CONFIG_IEEE80211BE
+ index_primary = (chan->freq - best->freq) / 20;
+#endif /* CONFIG_IEEE80211BE */
chan = best;
}
@@ -1057,7 +1067,8 @@
if (iface->conf->ieee80211be)
acs_update_puncturing_bitmap(iface, mode, bw,
n_chans, chan,
- factor, 0);
+ factor,
+ index_primary);
#endif /* CONFIG_IEEE80211BE */
}
@@ -1317,6 +1328,7 @@
int err;
iface->scan_cb = NULL;
+ iface->acs_num_retries = 0;
wpa_printf(MSG_DEBUG, "ACS: Using survey based algorithm (acs_num_scans=%d)",
iface->conf->acs_num_scans);
@@ -1329,7 +1341,7 @@
if (++iface->acs_num_completed_scans < iface->conf->acs_num_scans) {
err = acs_request_scan(iface);
- if (err) {
+ if (err && err != -EBUSY) {
wpa_printf(MSG_ERROR, "ACS: Failed to request scan");
goto fail;
}
@@ -1382,7 +1394,7 @@
static int acs_request_scan(struct hostapd_iface *iface)
{
struct wpa_driver_scan_params params;
- int i, *freq;
+ int i, *freq, ret;
int num_channels;
struct hostapd_hw_modes *mode;
@@ -1415,24 +1427,62 @@
return -1;
}
- iface->scan_cb = acs_scan_complete;
+ if (!iface->acs_num_retries)
+ wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d",
+ iface->acs_num_completed_scans + 1,
+ iface->conf->acs_num_scans);
+ else
+ wpa_printf(MSG_DEBUG,
+ "ACS: Re-try scanning attempt %d (%d / %d)",
+ iface->acs_num_retries,
+ iface->acs_num_completed_scans + 1,
+ iface->conf->acs_num_scans);
- wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d",
- iface->acs_num_completed_scans + 1,
- iface->conf->acs_num_scans);
+ ret = hostapd_driver_scan(iface->bss[0], ¶ms);
+ os_free(params.freqs);
- if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) {
+ if (ret == -EBUSY) {
+ iface->acs_num_retries++;
+ if (iface->acs_num_retries >= ACS_SCAN_RETRY_MAX_COUNT) {
+ wpa_printf(MSG_ERROR,
+ "ACS: Failed to request initial scan (all re-attempts failed)");
+ acs_fail(iface);
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO,
+ "Failed to request acs scan ret=%d (%s) - try to scan after %d seconds",
+ ret, strerror(-ret), ACS_SCAN_RETRY_INTERVAL);
+ eloop_cancel_timeout(acs_scan_retry, iface, NULL);
+ eloop_register_timeout(ACS_SCAN_RETRY_INTERVAL, 0,
+ acs_scan_retry, iface, NULL);
+ return 0;
+ }
+
+ if (ret < 0) {
wpa_printf(MSG_ERROR, "ACS: Failed to request initial scan");
acs_cleanup(iface);
- os_free(params.freqs);
return -1;
}
- os_free(params.freqs);
+ iface->scan_cb = acs_scan_complete;
+
return 0;
}
+static void acs_scan_retry(void *eloop_data, void *user_data)
+{
+ struct hostapd_iface *iface = eloop_data;
+
+ if (acs_request_scan(iface)) {
+ wpa_printf(MSG_ERROR,
+ "ACS: Failed to request re-try of initial scan");
+ acs_fail(iface);
+ }
+}
+
+
enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
{
int err;
diff --git a/src/ap/acs.h b/src/ap/acs.h
index ec84f0e..8be3de5 100644
--- a/src/ap/acs.h
+++ b/src/ap/acs.h
@@ -15,6 +15,9 @@
enum hostapd_chan_status acs_init(struct hostapd_iface *iface);
void acs_cleanup(struct hostapd_iface *iface);
+#define ACS_SCAN_RETRY_MAX_COUNT 15
+#define ACS_SCAN_RETRY_INTERVAL 5
+
#else /* CONFIG_ACS */
static inline enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 9aa61fa..a5a821b 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -92,6 +92,7 @@
bss->eap_sim_id = 3;
bss->eap_sim_aka_fast_reauth_limit = 1000;
bss->ap_max_inactivity = AP_MAX_INACTIVITY;
+ bss->bss_max_idle = 1;
bss->eapol_version = EAPOL_VERSION;
bss->max_listen_interval = 65535;
@@ -121,9 +122,10 @@
#endif /* CONFIG_IEEE80211R_AP */
bss->radius_das_time_window = 300;
+ bss->radius_require_message_authenticator = 1;
bss->anti_clogging_threshold = 5;
- bss->sae_sync = 5;
+ bss->sae_sync = 3;
bss->gas_frag_limit = 1400;
@@ -494,10 +496,14 @@
if ((conf->sae_pwe == SAE_PWE_HUNT_AND_PECK &&
!hostapd_sae_pw_id_in_use(conf) &&
- !wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt) &&
+ !wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt |
+ conf->rsn_override_key_mgmt |
+ conf->rsn_override_key_mgmt_2) &&
!hostapd_sae_pk_in_use(conf)) ||
conf->sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK ||
- !wpa_key_mgmt_sae(conf->wpa_key_mgmt))
+ !wpa_key_mgmt_sae(conf->wpa_key_mgmt |
+ conf->rsn_override_key_mgmt |
+ conf->rsn_override_key_mgmt_2))
return 0; /* PT not needed */
sae_deinit_pt(ssid->pt);
@@ -969,6 +975,7 @@
wpabuf_free(conf->igtk_rsc_override);
wpabuf_free(conf->eapol_m1_elements);
wpabuf_free(conf->eapol_m3_elements);
+ wpabuf_free(conf->presp_elements);
#endif /* CONFIG_TESTING_OPTIONS */
os_free(conf->no_probe_resp_if_seen_on);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 4f2164d..1a4c912 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -309,6 +309,7 @@
struct hostapd_ip_addr own_ip_addr;
char *nas_identifier;
struct hostapd_radius_servers *radius;
+ int radius_require_message_authenticator;
int acct_interim_interval;
int radius_request_cui;
struct hostapd_radius_attr *radius_auth_req_attr;
@@ -357,7 +358,11 @@
int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
int extended_key_id;
int wpa_key_mgmt;
+ int rsn_override_key_mgmt;
+ int rsn_override_key_mgmt_2;
enum mfp_options ieee80211w;
+ enum mfp_options rsn_override_mfp;
+ enum mfp_options rsn_override_mfp_2;
int group_mgmt_cipher;
int beacon_prot;
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
@@ -386,6 +391,8 @@
u32 wpa_pairwise_update_count;
int wpa_disable_eapol_key_retries;
int rsn_pairwise;
+ int rsn_override_pairwise;
+ int rsn_override_pairwise_2;
int rsn_preauth;
char *rsn_preauth_interfaces;
@@ -465,6 +472,9 @@
*/
int ap_max_inactivity;
+ int bss_max_idle;
+ int max_acceptable_idle_period;
+ bool no_disconnect_on_group_keyerror;
int ignore_broadcast_ssid;
int no_probe_resp_if_max_sta;
@@ -709,6 +719,7 @@
struct wpabuf *eapol_m3_elements;
bool eapol_m3_no_encrypt;
int test_assoc_comeback_type;
+ struct wpabuf *presp_elements;
#ifdef CONFIG_IEEE80211BE
u16 eht_oper_puncturing_override;
@@ -956,6 +967,8 @@
char *config_id;
bool xrates_supported;
+ bool ssid_protection;
+
#ifdef CONFIG_IEEE80211BE
/* The AP is part of an AP MLD */
u8 mld_ap;
@@ -1227,6 +1240,9 @@
MBSSID_ENABLED = 1,
ENHANCED_MBSSID_ENABLED = 2,
} mbssid;
+
+ /* Whether to enable TWT responder in HT and VHT modes */
+ bool ht_vht_twt_responder;
};
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 11fe39c..c473491 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -208,6 +208,9 @@
add_buf(&beacon, hapd->conf->vendor_elements);
add_buf(&proberesp, hapd->conf->vendor_elements);
+#ifdef CONFIG_TESTING_OPTIONS
+ add_buf(&proberesp, hapd->conf->presp_elements);
+#endif /* CONFIG_TESTING_OPTIONS */
add_buf(&assocresp, hapd->conf->assocresp_elements);
*beacon_ret = beacon;
@@ -624,9 +627,17 @@
int hostapd_flush(struct hostapd_data *hapd)
{
+ int link_id = -1;
+
if (hapd->driver == NULL || hapd->driver->flush == NULL)
return 0;
- return hapd->driver->flush(hapd->drv_priv);
+
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf && hapd->conf->mld_ap)
+ link_id = hapd->mld_link_id;
+#endif /* CONFIG_IEEE80211BE */
+
+ return hapd->driver->flush(hapd->drv_priv, link_id);
}
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 6ed4d06..837b690 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -260,11 +260,20 @@
if (!hostapd_mld_is_first_bss(hapd)) {
struct hostapd_data *first;
- wpa_printf(MSG_DEBUG, "MLD: Using auth_serv of the first BSS");
-
first = hostapd_mld_get_first_bss(hapd);
if (!first)
return -1;
+
+ if (!first->eap_cfg) {
+ wpa_printf(MSG_DEBUG,
+ "MLD: First BSS auth_serv does not exist. Init on its behalf");
+
+ if (authsrv_init(first))
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "MLD: Using auth_serv of the first BSS");
+
#ifdef EAP_TLS_FUNCS
hapd->ssl_ctx = first->ssl_ctx;
#endif /* EAP_TLS_FUNCS */
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 32865f6..f8ce810 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -403,6 +403,81 @@
}
+static u8 * hostapd_get_rsne_override(struct hostapd_data *hapd, u8 *pos,
+ size_t len)
+{
+ const u8 *ie;
+
+ ie = hostapd_vendor_wpa_ie(hapd, RSNE_OVERRIDE_IE_VENDOR_TYPE);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_rsne_override_2(struct hostapd_data *hapd, u8 *pos,
+ size_t len)
+{
+ const u8 *ie;
+
+ ie = hostapd_vendor_wpa_ie(hapd, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static u8 * hostapd_get_rsnxe_override(struct hostapd_data *hapd, u8 *pos,
+ size_t len)
+{
+ const u8 *ie;
+
+ ie = hostapd_vendor_wpa_ie(hapd, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
+ if (!ie || 2U + ie[1] > len)
+ return pos;
+
+ os_memcpy(pos, ie, 2 + ie[1]);
+ return pos + 2 + ie[1];
+}
+
+
+static size_t hostapd_get_rsne_override_len(struct hostapd_data *hapd)
+{
+ const u8 *ie;
+
+ ie = hostapd_vendor_wpa_ie(hapd, RSNE_OVERRIDE_IE_VENDOR_TYPE);
+ if (!ie)
+ return 0;
+ return 2 + ie[1];
+}
+
+
+static size_t hostapd_get_rsne_override_2_len(struct hostapd_data *hapd)
+{
+ const u8 *ie;
+
+ ie = hostapd_vendor_wpa_ie(hapd, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
+ if (!ie)
+ return 0;
+ return 2 + ie[1];
+}
+
+
+static size_t hostapd_get_rsnxe_override_len(struct hostapd_data *hapd)
+{
+ const u8 *ie;
+
+ ie = hostapd_vendor_wpa_ie(hapd, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
+ if (!ie)
+ return 0;
+ return 2 + ie[1];
+}
+
+
static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
{
#ifdef CONFIG_TESTING_OPTIONS
@@ -649,6 +724,10 @@
#endif /* CONFIG_FST */
if (hapd->conf->vendor_elements)
buflen += wpabuf_len(hapd->conf->vendor_elements);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->presp_elements)
+ buflen += wpabuf_len(hapd->conf->presp_elements);
+#endif /* CONFIG_TESTING_OPTIONS */
if (hapd->conf->vendor_vht) {
buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
2 + sizeof(struct ieee80211_vht_operation);
@@ -677,10 +756,14 @@
params->known_bss,
params->known_bss_len, NULL);
if (!params->is_ml_sta_info)
- buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP);
+ buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP,
+ true);
buflen += hostapd_mbo_ie_len(hapd);
buflen += hostapd_eid_owe_trans_len(hapd);
buflen += hostapd_eid_dpp_cc_len(hapd);
+ buflen += hostapd_get_rsne_override_len(hapd);
+ buflen += hostapd_get_rsne_override_2_len(hapd);
+ buflen += hostapd_get_rsnxe_override_len(hapd);
return buflen;
}
@@ -797,7 +880,8 @@
pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
if (!params->is_ml_sta_info)
- pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP);
+ pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP,
+ true);
pos = hostapd_eid_fils_indic(hapd, pos, 0);
pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
@@ -879,12 +963,24 @@
pos = hostapd_eid_owe_trans(hapd, pos, epos - pos);
pos = hostapd_eid_dpp_cc(hapd, pos, epos - pos);
+ pos = hostapd_get_rsne_override(hapd, pos, epos - pos);
+ pos = hostapd_get_rsne_override_2(hapd, pos, epos - pos);
+ pos = hostapd_get_rsnxe_override(hapd, pos, epos - pos);
+
if (hapd->conf->vendor_elements) {
os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
wpabuf_len(hapd->conf->vendor_elements));
pos += wpabuf_len(hapd->conf->vendor_elements);
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->presp_elements) {
+ os_memcpy(pos, wpabuf_head(hapd->conf->presp_elements),
+ wpabuf_len(hapd->conf->presp_elements));
+ pos += wpabuf_len(hapd->conf->presp_elements);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
return pos;
}
@@ -945,7 +1041,6 @@
{
struct probe_resp_params sta_info_params;
struct hostapd_data *link;
- unsigned int probed_mld_id, i, j;
params->mld_ap = NULL;
params->mld_info = os_zalloc(sizeof(*params->mld_info));
@@ -956,14 +1051,7 @@
"MLD: Got ML probe request with AP MLD ID %d for links %04x",
mld_id, links);
- /*
- * We want to include the AP MLD ID in the response if it was
- * included in the request.
- */
- probed_mld_id = mld_id != -1 ? mld_id : hostapd_get_mld_id(hapd);
-
- for_each_mld_link(link, i, j, hapd->iface->interfaces,
- probed_mld_id) {
+ for_each_mld_link(link, hapd) {
struct mld_link_info *link_info;
size_t buflen;
u8 mld_link_id = link->mld_link_id;
@@ -1706,15 +1794,15 @@
#ifdef CONFIG_IEEE80211AX
/* Unsolicited broadcast Probe Response transmission, 6 GHz only */
-static u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
- struct wpa_driver_ap_params *params)
+u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
+ struct unsol_bcast_probe_resp *ubpr)
{
struct probe_resp_params probe_params;
if (!is_6ghz_op_class(hapd->iconf->op_class))
return NULL;
- params->unsol_bcast_probe_resp_interval =
+ ubpr->unsol_bcast_probe_resp_interval =
hapd->conf->unsol_bcast_probe_resp_interval;
os_memset(&probe_params, 0, sizeof(probe_params));
@@ -1727,7 +1815,7 @@
probe_params.mld_info = NULL;
hostapd_gen_probe_resp(hapd, &probe_params);
- params->unsol_bcast_probe_resp_tmpl_len = probe_params.resp_len;
+ ubpr->unsol_bcast_probe_resp_tmpl_len = probe_params.resp_len;
return (u8 *) probe_params.resp;
}
#endif /* CONFIG_IEEE80211AX */
@@ -1942,6 +2030,17 @@
FD_FRAME_CTL_CAP_PRESENT;
total_len += 4 + 1 + 2;
+ /* Fill primary channel information for 6 GHz channels with over 20 MHz
+ * bandwidth, if the primary channel is not a PSC */
+ if (is_6ghz_op_class(hapd->iconf->op_class) &&
+ !is_6ghz_psc_frequency(ieee80211_chan_to_freq(
+ NULL, hapd->iconf->op_class,
+ hapd->iconf->channel)) &&
+ op_class_to_bandwidth(hapd->iconf->op_class) > 20) {
+ ctl |= FD_FRAME_CTL_PRI_CHAN_PRESENT;
+ total_len += 2;
+ }
+
/* Check for optional subfields and calculate length */
if (wpa_auth_write_fd_rsn_info(hapd->wpa_auth, fd_rsn_info)) {
ctl |= FD_FRAME_CTL_RSN_INFO_PRESENT;
@@ -1954,7 +2053,7 @@
total_len += 3;
}
- total_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_ACTION);
+ total_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_ACTION, true);
pos = hostapd_eid_fils_indic(hapd, buf, 0);
buf_len = pos - buf;
@@ -2003,9 +2102,11 @@
WPA_PUT_LE16(pos, hostapd_fils_discovery_cap(hapd));
pos += 2;
- /* Operating Class - not present */
-
- /* Primary Channel - not present */
+ /* Operating Class and Primary Channel - if a 6 GHz chan is non PSC */
+ if (ctl & FD_FRAME_CTL_PRI_CHAN_PRESENT) {
+ *pos++ = hapd->iconf->op_class;
+ *pos++ = hapd->iconf->channel;
+ }
/* AP Configuration Sequence Number - not present */
@@ -2028,7 +2129,7 @@
/* Fill in the Length field value */
*length_pos = pos - (length_pos + 1);
- pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_ACTION);
+ pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_ACTION, true);
/* FILS Indication element */
if (buf_len) {
@@ -2134,10 +2235,13 @@
if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
hapd == hostapd_mbssid_get_tx_bss(hapd))
tail_len += 5; /* Multiple BSSID Configuration element */
- tail_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_BEACON);
+ tail_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_BEACON, true);
tail_len += hostapd_mbo_ie_len(hapd);
tail_len += hostapd_eid_owe_trans_len(hapd);
tail_len += hostapd_eid_dpp_cc_len(hapd);
+ tail_len += hostapd_get_rsne_override_len(hapd);
+ tail_len += hostapd_get_rsne_override_2_len(hapd);
+ tail_len += hostapd_get_rsnxe_override_len(hapd);
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
@@ -2270,7 +2374,7 @@
tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
- tailpos = hostapd_eid_rnr(hapd, tailpos, WLAN_FC_STYPE_BEACON);
+ tailpos = hostapd_eid_rnr(hapd, tailpos, WLAN_FC_STYPE_BEACON, true);
tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
tailpos = hostapd_eid_mbssid_config(hapd, tailpos,
@@ -2349,6 +2453,13 @@
tail + tail_len - tailpos);
tailpos = hostapd_eid_dpp_cc(hapd, tailpos, tail + tail_len - tailpos);
+ tailpos = hostapd_get_rsne_override(hapd, tailpos,
+ tail + tail_len - tailpos);
+ tailpos = hostapd_get_rsne_override_2(hapd, tailpos,
+ tail + tail_len - tailpos);
+ tailpos = hostapd_get_rsnxe_override(hapd, tailpos,
+ tail + tail_len - tailpos);
+
if (hapd->conf->vendor_elements) {
os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
wpabuf_len(hapd->conf->vendor_elements));
@@ -2381,7 +2492,9 @@
/* If SAE offload is enabled, provide password to lower layer for
* SAE authentication and PMK generation.
*/
- if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt |
+ hapd->conf->rsn_override_key_mgmt |
+ hapd->conf->rsn_override_key_mgmt_2) &&
(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP)) {
if (hostapd_sae_pk_in_use(hapd->conf)) {
wpa_printf(MSG_ERROR,
@@ -2426,7 +2539,9 @@
else if (hapd->conf->wpa & WPA_PROTO_WPA)
params->pairwise_ciphers = hapd->conf->wpa_pairwise;
params->group_cipher = hapd->conf->wpa_group;
- params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
+ params->key_mgmt_suites = hapd->conf->wpa_key_mgmt |
+ hapd->conf->rsn_override_key_mgmt |
+ hapd->conf->rsn_override_key_mgmt_2;
params->auth_algs = hapd->conf->auth_algs;
params->wpa_version = hapd->conf->wpa;
params->privacy = hapd->conf->wpa;
@@ -2527,8 +2642,8 @@
params->fd_frame_tmpl = NULL;
#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211AX
- os_free(params->unsol_bcast_probe_resp_tmpl);
- params->unsol_bcast_probe_resp_tmpl = NULL;
+ os_free(params->ubpr.unsol_bcast_probe_resp_tmpl);
+ params->ubpr.unsol_bcast_probe_resp_tmpl = NULL;
#endif /* CONFIG_IEEE80211AX */
os_free(params->allowed_freqs);
params->allowed_freqs = NULL;
@@ -2543,6 +2658,7 @@
struct hostapd_config *iconf = iface->conf;
struct hostapd_hw_modes *cmode = iface->current_mode;
struct wpabuf *beacon, *proberesp, *assocresp;
+ bool twt_he_responder = false;
int res, ret = -1, i;
struct hostapd_hw_modes *mode;
@@ -2586,11 +2702,13 @@
params.he_bss_color_partial =
hapd->iface->conf->he_op.he_bss_color_partial;
params.he_bss_color = hapd->iface->conf->he_op.he_bss_color;
- params.twt_responder = hostapd_get_he_twt_responder(hapd,
- IEEE80211_MODE_AP);
- params.unsol_bcast_probe_resp_tmpl =
- hostapd_unsol_bcast_probe_resp(hapd, ¶ms);
+ twt_he_responder = hostapd_get_he_twt_responder(hapd,
+ IEEE80211_MODE_AP);
+ params.ubpr.unsol_bcast_probe_resp_tmpl =
+ hostapd_unsol_bcast_probe_resp(hapd, ¶ms.ubpr);
#endif /* CONFIG_IEEE80211AX */
+ params.twt_responder =
+ twt_he_responder || hostapd_get_ht_vht_twt_responder(hapd);
hapd->reenable_beacon = 0;
#ifdef CONFIG_SAE
params.sae_pwe = hapd->conf->sae_pwe;
@@ -2617,8 +2735,14 @@
cmode->vht_capab,
&cmode->he_capab[IEEE80211_MODE_AP],
&cmode->eht_capab[IEEE80211_MODE_AP],
- hostapd_get_punct_bitmap(hapd)) == 0)
+ hostapd_get_punct_bitmap(hapd)) == 0) {
+ freq.link_id = -1;
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap)
+ freq.link_id = hapd->mld_link_id;
+#endif /* CONFIG_IEEE80211BE */
params.freq = &freq;
+ }
for (i = 0; i < hapd->iface->num_hw_features; i++) {
mode = &hapd->iface->hw_features[i];
@@ -2656,7 +2780,7 @@
struct hostapd_iface *iface = hapd->iface;
int ret;
size_t i, j;
- bool is_6g;
+ bool is_6g, hapd_mld = false;
ret = __ieee802_11_set_beacon(hapd);
if (ret != 0)
@@ -2665,26 +2789,33 @@
if (!iface->interfaces || iface->interfaces->count <= 1)
return 0;
+#ifdef CONFIG_IEEE80211BE
+ hapd_mld = hapd->conf->mld_ap;
+#endif /* CONFIG_IEEE80211BE */
+
/* Update Beacon frames in case of 6 GHz colocation or AP MLD */
is_6g = is_6ghz_op_class(iface->conf->op_class);
for (j = 0; j < iface->interfaces->count; j++) {
struct hostapd_iface *other;
- bool mld_ap = false;
+ bool other_iface_6g;
other = iface->interfaces->iface[j];
if (other == iface || !other || !other->conf)
continue;
-#ifdef CONFIG_IEEE80211BE
- if (hostapd_is_ml_partner(hapd, other->bss[0]))
- mld_ap = true;
-#endif /* CONFIG_IEEE80211BE */
+ other_iface_6g = is_6ghz_op_class(other->conf->op_class);
- if (is_6g == is_6ghz_op_class(other->conf->op_class) &&
- !mld_ap)
+ if (is_6g == other_iface_6g && !hapd_mld)
continue;
for (i = 0; i < other->num_bss; i++) {
+#ifdef CONFIG_IEEE80211BE
+ if (is_6g == other_iface_6g &&
+ !(hapd_mld && other->bss[i]->conf->mld_ap &&
+ hostapd_is_ml_partner(hapd, other->bss[i])))
+ continue;
+#endif /* CONFIG_IEEE80211BE */
+
if (other->bss[i] && other->bss[i]->started)
__ieee802_11_set_beacon(other->bss[i]);
}
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index b32b2a7..e381542 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -33,4 +33,7 @@
const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid);
+u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
+ struct unsol_bcast_probe_resp *ubpr);
+
#endif /* BEACON_H */
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index eac0606..d4d73de 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -277,6 +277,14 @@
return len;
len += ret;
+ if (sta->max_idle_period) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "max_idle_period=%d\n", sta->max_idle_period);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
if (res >= 0)
len += res;
@@ -902,6 +910,42 @@
return len;
len += ret;
}
+
+ if (hapd->conf->mld_ap) {
+ struct hostapd_data *link_bss;
+
+ ret = os_snprintf(buf + len, buflen - len,
+ "num_links=%d\n",
+ hapd->mld->num_links);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+
+ /* Self BSS */
+ ret = os_snprintf(buf + len, buflen - len,
+ "link_id=%d\n"
+ "link_addr=" MACSTR "\n",
+ hapd->mld_link_id,
+ MAC2STR(hapd->own_addr));
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+
+ /* Partner BSSs */
+ for_each_mld_link(link_bss, hapd) {
+ if (link_bss == hapd)
+ continue;
+
+ ret = os_snprintf(buf + len, buflen - len,
+ "partner_link[%d]=" MACSTR
+ "\n",
+ link_bss->mld_link_id,
+ MAC2STR(link_bss->own_addr));
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+ }
}
#endif /* CONFIG_IEEE80211BE */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index b0fcd1c..233984f 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -513,11 +513,15 @@
"Failed to initialize WPA state machine");
return -1;
}
+ wpa_auth_set_rsn_override(sta->wpa_sm,
+ elems.rsne_override != NULL);
+ wpa_auth_set_rsn_override_2(sta->wpa_sm,
+ elems.rsne_override_2 != NULL);
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta)) {
wpa_printf(MSG_DEBUG,
"MLD: Set ML info in RSN Authenticator");
- wpa_auth_set_ml_info(sta->wpa_sm, hapd->mld->mld_addr,
+ wpa_auth_set_ml_info(sta->wpa_sm,
sta->mld_assoc_link_id,
&sta->mld_info);
}
@@ -528,7 +532,7 @@
elems.rsnxe ? elems.rsnxe - 2 : NULL,
elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len,
- elems.owe_dh, elems.owe_dh_len);
+ elems.owe_dh, elems.owe_dh_len, NULL);
reason = WLAN_REASON_INVALID_IE;
status = WLAN_STATUS_INVALID_IE;
switch (res) {
@@ -1537,7 +1541,6 @@
#ifdef CONFIG_IEEE80211R_AP
static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
- const u8 *bssid,
u16 auth_transaction, u16 status,
const u8 *ies, size_t ies_len)
{
@@ -1613,7 +1616,7 @@
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
- wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid,
+ wpa_ft_process_auth(sta->wpa_sm,
rx_auth->auth_transaction, rx_auth->ies,
rx_auth->ies_len,
hostapd_notify_auth_ft_finish, hapd);
@@ -1780,7 +1783,7 @@
#define HAPD_BROADCAST ((struct hostapd_data *) -1)
static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
- const u8 *bssid)
+ const u8 *bssid, int link_id)
{
size_t i;
@@ -1791,8 +1794,35 @@
return HAPD_BROADCAST;
for (i = 0; i < iface->num_bss; i++) {
- if (ether_addr_equal(bssid, iface->bss[i]->own_addr))
- return iface->bss[i];
+ struct hostapd_data *hapd;
+#ifdef CONFIG_IEEE80211BE
+ struct hostapd_data *p_hapd;
+#endif /* CONFIG_IEEE80211BE */
+
+ hapd = iface->bss[i];
+ if (ether_addr_equal(bssid, hapd->own_addr))
+ return hapd;
+
+#ifdef CONFIG_IEEE80211BE
+ if (ether_addr_equal(bssid, hapd->own_addr) ||
+ (hapd->conf->mld_ap &&
+ ether_addr_equal(bssid, hapd->mld->mld_addr) &&
+ link_id == hapd->mld_link_id))
+ return hapd;
+
+ if (!hapd->conf->mld_ap)
+ continue;
+
+ for_each_mld_link(p_hapd, hapd) {
+ if (p_hapd == hapd)
+ continue;
+
+ if (ether_addr_equal(bssid, p_hapd->own_addr) ||
+ (ether_addr_equal(bssid, p_hapd->mld->mld_addr) &&
+ link_id == p_hapd->mld_link_id))
+ return p_hapd;
+ }
+#endif /* CONFIG_IEEE80211BE */
}
return NULL;
@@ -1803,7 +1833,7 @@
const u8 *bssid, const u8 *addr,
int wds)
{
- hapd = get_hapd_bssid(hapd->iface, bssid);
+ hapd = get_hapd_bssid(hapd->iface, bssid, -1);
if (hapd == NULL || hapd == HAPD_BROADCAST)
return;
@@ -1818,8 +1848,9 @@
const u8 *bssid;
struct hostapd_frame_info fi;
int ret;
- bool is_mld = false;
+ if (rx_mgmt->ctx)
+ hapd = rx_mgmt->ctx;
hapd = switch_link_hapd(hapd, rx_mgmt->link_id);
iface = hapd->iface;
@@ -1843,14 +1874,7 @@
if (bssid == NULL)
return 0;
-#ifdef CONFIG_IEEE80211BE
- if (hapd->conf->mld_ap &&
- ether_addr_equal(hapd->mld->mld_addr, bssid))
- is_mld = true;
-#endif /* CONFIG_IEEE80211BE */
-
- if (!is_mld)
- hapd = get_hapd_bssid(iface, bssid);
+ hapd = get_hapd_bssid(iface, bssid, rx_mgmt->link_id);
if (!hapd) {
u16 fc = le_to_host16(hdr->frame_control);
@@ -1902,17 +1926,11 @@
struct ieee80211_hdr *hdr;
struct hostapd_data *orig_hapd, *tmp_hapd;
-#ifdef CONFIG_IEEE80211BE
- if (hapd->conf->mld_ap && link_id != -1) {
- tmp_hapd = hostapd_mld_get_link_bss(hapd, link_id);
- if (tmp_hapd)
- hapd = tmp_hapd;
- }
-#endif /* CONFIG_IEEE80211BE */
orig_hapd = hapd;
hdr = (struct ieee80211_hdr *) buf;
- tmp_hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
+ hapd = switch_link_hapd(hapd, link_id);
+ tmp_hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len), link_id);
if (tmp_hapd) {
hapd = tmp_hapd;
#ifdef CONFIG_IEEE80211BE
@@ -1929,7 +1947,7 @@
if (stype != WLAN_FC_STYPE_ACTION || len <= 25 ||
buf[24] != WLAN_ACTION_PUBLIC)
return;
- hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2);
+ hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2, link_id);
if (!hapd || hapd == HAPD_BROADCAST)
return;
/*
@@ -1966,54 +1984,49 @@
static struct hostapd_data * hostapd_find_by_sta(struct hostapd_iface *iface,
- const u8 *src, bool rsn)
+ const u8 *src, bool rsn,
+ struct sta_info **sta_ret)
{
+ struct hostapd_data *hapd;
struct sta_info *sta;
unsigned int j;
+ if (sta_ret)
+ *sta_ret = NULL;
+
for (j = 0; j < iface->num_bss; j++) {
- sta = ap_get_sta(iface->bss[j], src);
+ hapd = iface->bss[j];
+ sta = ap_get_sta(hapd, src);
if (sta && (sta->flags & WLAN_STA_ASSOC) &&
- (!rsn || sta->wpa_sm))
- return iface->bss[j];
+ (!rsn || sta->wpa_sm)) {
+ if (sta_ret)
+ *sta_ret = sta;
+ return hapd;
+ }
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap) {
+ struct hostapd_data *p_hapd;
+
+ for_each_mld_link(p_hapd, hapd) {
+ if (p_hapd == hapd)
+ continue;
+
+ sta = ap_get_sta(p_hapd, src);
+ if (sta && (sta->flags & WLAN_STA_ASSOC) &&
+ (!rsn || sta->wpa_sm)) {
+ if (sta_ret)
+ *sta_ret = sta;
+ return p_hapd;
+ }
+ }
+ }
+#endif /* CONFIG_IEEE80211BE */
}
return NULL;
}
-#ifdef CONFIG_IEEE80211BE
-static bool search_mld_sta(struct hostapd_data **p_hapd, const u8 *src)
-{
- struct hostapd_data *hapd = *p_hapd;
- unsigned int i;
-
- /* Search for STA on other MLO BSSs */
- for (i = 0; i < hapd->iface->interfaces->count; i++) {
- struct hostapd_iface *h =
- hapd->iface->interfaces->iface[i];
- struct hostapd_data *h_hapd = h->bss[0];
-
- if (!hostapd_is_ml_partner(h_hapd, hapd))
- continue;
-
- h_hapd = hostapd_find_by_sta(h, src, false);
- if (h_hapd) {
- struct sta_info *sta = ap_get_sta(h_hapd, src);
-
- if (sta && sta->mld_info.mld_sta &&
- sta->mld_assoc_link_id != h_hapd->mld_link_id)
- continue;
- *p_hapd = h_hapd;
- return true;
- }
- }
-
- return false;
-}
-#endif /* CONFIG_IEEE80211BE */
-
-
static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
const u8 *data, size_t data_len,
enum frame_encryption encrypted,
@@ -2022,28 +2035,10 @@
struct hostapd_data *orig_hapd = hapd;
#ifdef CONFIG_IEEE80211BE
- if (link_id != -1) {
- struct hostapd_data *h_hapd;
-
- hapd = switch_link_hapd(hapd, link_id);
- h_hapd = hostapd_find_by_sta(hapd->iface, src, true);
- if (!h_hapd)
- h_hapd = hostapd_find_by_sta(orig_hapd->iface, src,
- true);
- if (!h_hapd)
- h_hapd = hostapd_find_by_sta(hapd->iface, src, false);
- if (!h_hapd)
- h_hapd = hostapd_find_by_sta(orig_hapd->iface, src,
- false);
- if (h_hapd)
- hapd = h_hapd;
- } else if (hapd->conf->mld_ap) {
- search_mld_sta(&hapd, src);
- } else {
- hapd = hostapd_find_by_sta(hapd->iface, src, false);
- }
+ hapd = switch_link_hapd(hapd, link_id);
+ hapd = hostapd_find_by_sta(hapd->iface, src, true, NULL);
#else /* CONFIG_IEEE80211BE */
- hapd = hostapd_find_by_sta(hapd->iface, src, false);
+ hapd = hostapd_find_by_sta(hapd->iface, src, false, NULL);
#endif /* CONFIG_IEEE80211BE */
if (!hapd) {
@@ -2373,6 +2368,54 @@
#endif /* CONFIG_OWE */
+#ifdef NEED_AP_MLME
+static void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
+ const u8 *data, size_t len, int ack,
+ int link_id)
+{
+ struct sta_info *sta;
+
+ hapd = switch_link_hapd(hapd, link_id);
+ hapd = hostapd_find_by_sta(hapd->iface, dst, false, &sta);
+
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA "
+ MACSTR " that is not currently associated",
+ MAC2STR(dst));
+ return;
+ }
+
+ ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
+}
+#endif /* NEED_AP_MLME */
+
+
+#ifdef CONFIG_IEEE80211AX
+static void hostapd_event_color_change(struct hostapd_data *hapd, bool success)
+{
+ struct hostapd_data *bss;
+ size_t i;
+
+ for (i = 0; i < hapd->iface->num_bss; i++) {
+ bss = hapd->iface->bss[i];
+ if (bss->cca_color == 0)
+ continue;
+
+ if (success)
+ hapd->iface->conf->he_op.he_bss_color = bss->cca_color;
+
+ bss->cca_in_progress = 0;
+ if (ieee802_11_set_beacon(bss)) {
+ wpa_printf(MSG_ERROR, "Failed to remove BCCA element");
+ bss->cca_in_progress = 1;
+ } else {
+ hostapd_cleanup_cca_params(bss);
+ }
+ }
+}
+#endif /* CONFIG_IEEE80211AX */
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@@ -2451,11 +2494,11 @@
}
break;
case EVENT_EAPOL_TX_STATUS:
- hapd = switch_link_hapd(hapd, data->eapol_tx_status.link_id);
hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst,
data->eapol_tx_status.data,
data->eapol_tx_status.data_len,
- data->eapol_tx_status.ack);
+ data->eapol_tx_status.ack,
+ data->eapol_tx_status.link_id);
break;
case EVENT_DRIVER_CLIENT_POLL_OK:
hostapd_client_poll_ok(hapd, data->client_poll.addr);
@@ -2698,26 +2741,32 @@
/* The BSS color is shared amongst all BBSs on a specific phy.
* Therefore we always start the color change on the primary
* BSS. */
+ hapd = switch_link_hapd(hapd,
+ data->bss_color_collision.link_id);
wpa_printf(MSG_DEBUG, "BSS color collision on %s",
hapd->conf->iface);
hostapd_switch_color(hapd->iface->bss[0],
data->bss_color_collision.bitmap);
break;
case EVENT_CCA_STARTED_NOTIFY:
- wpa_printf(MSG_DEBUG, "CCA started on on %s",
+ hapd = switch_link_hapd(hapd,
+ data->bss_color_collision.link_id);
+ wpa_printf(MSG_DEBUG, "CCA started on %s",
hapd->conf->iface);
break;
case EVENT_CCA_ABORTED_NOTIFY:
- wpa_printf(MSG_DEBUG, "CCA aborted on on %s",
+ hapd = switch_link_hapd(hapd,
+ data->bss_color_collision.link_id);
+ wpa_printf(MSG_DEBUG, "CCA aborted on %s",
hapd->conf->iface);
- hostapd_cleanup_cca_params(hapd);
+ hostapd_event_color_change(hapd, false);
break;
case EVENT_CCA_NOTIFY:
- wpa_printf(MSG_DEBUG, "CCA finished on on %s",
+ hapd = switch_link_hapd(hapd,
+ data->bss_color_collision.link_id);
+ wpa_printf(MSG_DEBUG, "CCA finished on %s",
hapd->conf->iface);
- if (hapd->cca_color)
- hapd->iface->conf->he_op.he_bss_color = hapd->cca_color;
- hostapd_cleanup_cca_params(hapd);
+ hostapd_event_color_change(hapd, true);
break;
#endif /* CONFIG_IEEE80211AX */
default:
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 56bac45..a05de03 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1307,6 +1307,59 @@
}
+#ifndef CONFIG_NO_RADIUS
+static int hostapd_bss_radius_init(struct hostapd_data *hapd)
+{
+ struct hostapd_bss_config *conf;
+
+ if (!hapd)
+ return -1;
+
+ conf = hapd->conf;
+
+ if (hapd->radius) {
+ wpa_printf(MSG_DEBUG,
+ "Skipping RADIUS client init (already done)");
+ return 0;
+ }
+
+ hapd->radius = radius_client_init(hapd, conf->radius);
+ if (!hapd->radius) {
+ wpa_printf(MSG_ERROR,
+ "RADIUS client initialization failed.");
+ return -1;
+ }
+
+ if (conf->radius_das_port) {
+ struct radius_das_conf das_conf;
+
+ os_memset(&das_conf, 0, sizeof(das_conf));
+ das_conf.port = conf->radius_das_port;
+ das_conf.shared_secret = conf->radius_das_shared_secret;
+ das_conf.shared_secret_len =
+ conf->radius_das_shared_secret_len;
+ das_conf.client_addr = &conf->radius_das_client_addr;
+ das_conf.time_window = conf->radius_das_time_window;
+ das_conf.require_event_timestamp =
+ conf->radius_das_require_event_timestamp;
+ das_conf.require_message_authenticator =
+ conf->radius_das_require_message_authenticator;
+ das_conf.ctx = hapd;
+ das_conf.disconnect = hostapd_das_disconnect;
+ das_conf.coa = hostapd_das_coa;
+ hapd->radius_das = radius_das_init(&das_conf);
+ if (!hapd->radius_das) {
+ wpa_printf(MSG_ERROR,
+ "RADIUS DAS initialization failed.");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
/**
* hostapd_setup_bss - Per-BSS setup (initialization)
* @hapd: Pointer to BSS data
@@ -1379,6 +1432,23 @@
} while (mac_in_conf(hapd->iconf, hapd->own_addr));
}
+#ifdef CONFIG_IEEE80211BE
+ if (conf->mld_ap) {
+ struct hostapd_data *h_hapd;
+
+ h_hapd = hostapd_mld_get_first_bss(hapd);
+ if (h_hapd) {
+ hapd->drv_priv = h_hapd->drv_priv;
+ hapd->interface_added = h_hapd->interface_added;
+ hostapd_mld_add_link(hapd);
+ wpa_printf(MSG_DEBUG,
+ "Setup of non first link (%d) BSS of MLD %s",
+ hapd->mld_link_id, hapd->conf->iface);
+ goto setup_mld;
+ }
+ }
+#endif /* CONFIG_IEEE80211BE */
+
hapd->interface_added = 1;
if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
conf->iface, addr, hapd,
@@ -1393,8 +1463,34 @@
if (!addr)
os_memcpy(hapd->own_addr, if_addr, ETH_ALEN);
+
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap) {
+ wpa_printf(MSG_DEBUG,
+ "Setup of first link (%d) BSS of MLD %s",
+ hapd->mld_link_id, hapd->conf->iface);
+ os_memcpy(hapd->mld->mld_addr, hapd->own_addr,
+ ETH_ALEN);
+ hostapd_mld_add_link(hapd);
+ }
+#endif /* CONFIG_IEEE80211BE */
}
+#ifdef CONFIG_IEEE80211BE
+setup_mld:
+ if (hapd->conf->mld_ap && !first) {
+ wpa_printf(MSG_DEBUG,
+ "MLD: Set link_id=%u, mld_addr=" MACSTR
+ ", own_addr=" MACSTR,
+ hapd->mld_link_id, MAC2STR(hapd->mld->mld_addr),
+ MAC2STR(hapd->own_addr));
+
+ if (hostapd_drv_link_add(hapd, hapd->mld_link_id,
+ hapd->own_addr))
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211BE */
+
if (conf->wmm_enabled < 0)
conf->wmm_enabled = hapd->iconf->ieee80211n |
hapd->iconf->ieee80211ax;
@@ -1497,46 +1593,26 @@
#endif /* CONFIG_SQLITE */
if (hostapd_mld_is_first_bss(hapd)) {
- hapd->radius = radius_client_init(hapd, conf->radius);
- if (!hapd->radius) {
- wpa_printf(MSG_ERROR,
- "RADIUS client initialization failed.");
+ if (hostapd_bss_radius_init(hapd))
return -1;
- }
-
- if (conf->radius_das_port) {
- struct radius_das_conf das_conf;
-
- os_memset(&das_conf, 0, sizeof(das_conf));
- das_conf.port = conf->radius_das_port;
- das_conf.shared_secret = conf->radius_das_shared_secret;
- das_conf.shared_secret_len =
- conf->radius_das_shared_secret_len;
- das_conf.client_addr = &conf->radius_das_client_addr;
- das_conf.time_window = conf->radius_das_time_window;
- das_conf.require_event_timestamp =
- conf->radius_das_require_event_timestamp;
- das_conf.require_message_authenticator =
- conf->radius_das_require_message_authenticator;
- das_conf.ctx = hapd;
- das_conf.disconnect = hostapd_das_disconnect;
- das_conf.coa = hostapd_das_coa;
- hapd->radius_das = radius_das_init(&das_conf);
- if (!hapd->radius_das) {
- wpa_printf(MSG_ERROR,
- "RADIUS DAS initialization failed.");
- return -1;
- }
- }
} else {
#ifdef CONFIG_IEEE80211BE
struct hostapd_data *f_bss;
- wpa_printf(MSG_DEBUG,
- "MLD: Using RADIUS client of the first BSS");
f_bss = hostapd_mld_get_first_bss(hapd);
if (!f_bss)
return -1;
+
+ if (!f_bss->radius) {
+ wpa_printf(MSG_DEBUG,
+ "MLD: First BSS RADIUS client does not exist. Init on its behalf");
+
+ if (hostapd_bss_radius_init(f_bss))
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "MLD: Using RADIUS client of the first BSS");
hapd->radius = f_bss->radius;
hapd->radius_das = f_bss->radius_das;
#endif /* CONFIG_IEEE80211BE */
@@ -3299,10 +3375,10 @@
static void hostapd_cleanup_driver(const struct wpa_driver_ops *driver,
void *drv_priv, struct hostapd_iface *iface)
{
-#ifdef CONFIG_IEEE80211BE
if (!driver || !driver->hapd_deinit || !drv_priv)
return;
+#ifdef CONFIG_IEEE80211BE
/* In case of non-ML operation, de-init. But if ML operation exist,
* even if that's the last BSS in the interface, the driver (drv) could
* be in use for a different AP MLD. Hence, need to check if drv is
@@ -4045,7 +4121,7 @@
#ifdef NEED_AP_MLME
-static void free_beacon_data(struct beacon_data *beacon)
+void free_beacon_data(struct beacon_data *beacon)
{
os_free(beacon->head);
beacon->head = NULL;
@@ -4344,6 +4420,11 @@
settings->link_id = hapd->mld_link_id;
#endif /* CONFIG_IEEE80211BE */
+#ifdef CONFIG_IEEE80211AX
+ settings->ubpr.unsol_bcast_probe_resp_tmpl =
+ hostapd_unsol_bcast_probe_resp(hapd, &settings->ubpr);
+#endif /* CONFIG_IEEE80211AX */
+
return 0;
}
@@ -4405,6 +4486,9 @@
ret = hostapd_drv_switch_channel(hapd, settings);
free_beacon_data(&settings->beacon_csa);
free_beacon_data(&settings->beacon_after);
+#ifdef CONFIG_IEEE80211AX
+ os_free(settings->ubpr.unsol_bcast_probe_resp_tmpl);
+#endif /* CONFIG_IEEE80211AX */
if (ret) {
/* if we failed, clean cs parameters */
@@ -4421,15 +4505,16 @@
hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params)
{
- int seg0_idx = 0, seg1_idx = 0;
+ u8 seg0_idx = 0, seg1_idx = 0;
enum oper_chan_width bw = CONF_OPER_CHWIDTH_USE_HT;
+ u8 op_class, chan = 0;
wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
if (freq_params->center_freq1)
- seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
+ ieee80211_freq_to_chan(freq_params->center_freq1, &seg0_idx);
if (freq_params->center_freq2)
- seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
+ ieee80211_freq_to_chan(freq_params->center_freq2, &seg1_idx);
switch (freq_params->bandwidth) {
case 0:
@@ -4462,6 +4547,15 @@
iface->freq = freq_params->freq;
iface->conf->channel = freq_params->channel;
iface->conf->secondary_channel = freq_params->sec_channel_offset;
+ if (ieee80211_freq_to_channel_ext(freq_params->freq,
+ freq_params->sec_channel_offset, bw,
+ &op_class, &chan) ==
+ NUM_HOSTAPD_MODES ||
+ chan != freq_params->channel)
+ wpa_printf(MSG_INFO, "CSA: Channel mismatch: %d -> %d",
+ freq_params->channel, chan);
+
+ iface->conf->op_class = op_class;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, seg1_idx);
hostapd_set_oper_chwidth(iface->conf, bw);
@@ -4492,8 +4586,8 @@
}
-static int hostapd_fill_cca_settings(struct hostapd_data *hapd,
- struct cca_settings *settings)
+int hostapd_fill_cca_settings(struct hostapd_data *hapd,
+ struct cca_settings *settings)
{
struct hostapd_iface *iface = hapd->iface;
u8 old_color;
@@ -4502,6 +4596,12 @@
if (!iface || iface->conf->he_op.he_bss_color_disabled)
return -1;
+ settings->link_id = -1;
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap)
+ settings->link_id = hapd->mld_link_id;
+#endif /* CONFIG_IEEE80211BE */
+
old_color = iface->conf->he_op.he_bss_color;
iface->conf->he_op.he_bss_color = hapd->cca_color;
ret = hostapd_build_beacon_data(hapd, &settings->beacon_after);
@@ -4520,6 +4620,9 @@
return ret;
}
+ settings->ubpr.unsol_bcast_probe_resp_tmpl =
+ hostapd_unsol_bcast_probe_resp(hapd, &settings->ubpr);
+
settings->counter_offset_beacon = hapd->cca_c_off_beacon;
settings->counter_offset_presp = hapd->cca_c_off_proberesp;
@@ -4582,6 +4685,7 @@
free_beacon_data(&settings.beacon_cca);
free_beacon_data(&settings.beacon_after);
+ os_free(settings.ubpr.unsol_bcast_probe_resp_tmpl);
}
}
@@ -4681,17 +4785,28 @@
struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd,
u8 link_id)
{
- unsigned int i;
+ struct hostapd_iface *iface;
+ struct hostapd_data *bss;
+ unsigned int i, j;
for (i = 0; i < hapd->iface->interfaces->count; i++) {
- struct hostapd_iface *h = hapd->iface->interfaces->iface[i];
- struct hostapd_data *h_hapd = h->bss[0];
-
- if (!hostapd_is_ml_partner(hapd, h_hapd))
+ iface = hapd->iface->interfaces->iface[i];
+ if (!iface)
continue;
- if (h_hapd->mld_link_id == link_id)
- return h_hapd;
+ for (j = 0; j < iface->num_bss; j++) {
+ bss = iface->bss[j];
+
+ if (!bss->conf->mld_ap ||
+ !hostapd_is_ml_partner(hapd, bss))
+ continue;
+
+ if (!bss->drv_priv)
+ continue;
+
+ if (bss->mld_link_id == link_id)
+ return bss;
+ }
}
return NULL;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index ff29726..85122d4 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -684,6 +684,7 @@
#ifdef CONFIG_ACS
unsigned int acs_num_completed_scans;
+ unsigned int acs_num_retries;
#endif /* CONFIG_ACS */
void (*scan_cb)(struct hostapd_iface *iface);
@@ -825,23 +826,16 @@
int hostapd_mld_remove_link(struct hostapd_data *hapd);
struct hostapd_data * hostapd_mld_get_first_bss(struct hostapd_data *hapd);
+void free_beacon_data(struct beacon_data *beacon);
+int hostapd_fill_cca_settings(struct hostapd_data *hapd,
+ struct cca_settings *settings);
+
#ifdef CONFIG_IEEE80211BE
bool hostapd_mld_is_first_bss(struct hostapd_data *hapd);
-#define for_each_mld_link(_link, _bss_idx, _iface_idx, _ifaces, _mld_id) \
- for (_iface_idx = 0; \
- _iface_idx < (_ifaces)->count; \
- _iface_idx++) \
- for (_bss_idx = 0; \
- _bss_idx < \
- (_ifaces)->iface[_iface_idx]->num_bss; \
- _bss_idx++) \
- for (_link = \
- (_ifaces)->iface[_iface_idx]->bss[_bss_idx]; \
- _link && _link->conf->mld_ap && \
- hostapd_get_mld_id(_link) == _mld_id; \
- _link = NULL)
+#define for_each_mld_link(partner, self) \
+ dl_list_for_each(partner, &self->mld->links, struct hostapd_data, link)
#else /* CONFIG_IEEE80211BE */
@@ -850,7 +844,7 @@
return true;
}
-#define for_each_mld_link(_link, _bss_idx, _iface_idx, _ifaces, _mld_id) \
+#define for_each_mld_link(partner, self) \
if (false)
#endif /* CONFIG_IEEE80211BE */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 85a39d5..1cd76ca 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -404,7 +404,7 @@
static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *dst, const u8 *bssid,
+ const u8 *dst,
u16 auth_alg, u16 auth_transaction, u16 resp,
const u8 *ies, size_t ies_len, const char *dbg)
{
@@ -416,14 +416,7 @@
struct wpabuf *ml_resp = NULL;
#ifdef CONFIG_IEEE80211BE
- /*
- * Once a non-AP MLD is added to the driver, the addressing should use
- * the MLD MAC address. Thus, use the MLD address instead of translating
- * the addresses.
- */
if (ap_sta_is_mld(hapd, sta)) {
- sa = hapd->mld->mld_addr;
-
ml_resp = hostapd_ml_auth_resp(hapd);
if (!ml_resp)
return -1;
@@ -444,7 +437,7 @@
WLAN_FC_STYPE_AUTH);
os_memcpy(reply->da, dst, ETH_ALEN);
os_memcpy(reply->sa, sa, ETH_ALEN);
- os_memcpy(reply->bssid, bssid, ETH_ALEN);
+ os_memcpy(reply->bssid, sa, ETH_ALEN);
reply->u.auth.auth_alg = host_to_le16(auth_alg);
reply->u.auth.auth_transaction = host_to_le16(auth_transaction);
@@ -508,7 +501,7 @@
#ifdef CONFIG_IEEE80211R_AP
-static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
+static void handle_auth_ft_finish(void *ctx, const u8 *dst,
u16 auth_transaction, u16 status,
const u8 *ies, size_t ies_len)
{
@@ -516,7 +509,7 @@
struct sta_info *sta;
int reply_res;
- reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT,
+ reply_res = send_auth_reply(hapd, NULL, dst, WLAN_AUTH_FT,
auth_transaction, status, ies, ies_len,
"auth-ft-finish");
@@ -712,7 +705,7 @@
static int auth_sae_send_commit(struct hostapd_data *hapd,
struct sta_info *sta,
- const u8 *bssid, int update, int status_code)
+ int update, int status_code)
{
struct wpabuf *data;
int reply_res;
@@ -739,7 +732,7 @@
status = hapd->conf->sae_commit_status;
}
#endif /* CONFIG_TESTING_OPTIONS */
- reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
+ reply_res = send_auth_reply(hapd, sta, sta->addr,
WLAN_AUTH_SAE, 1,
status, wpabuf_head(data),
wpabuf_len(data), "sae-send-commit");
@@ -751,8 +744,7 @@
static int auth_sae_send_confirm(struct hostapd_data *hapd,
- struct sta_info *sta,
- const u8 *bssid)
+ struct sta_info *sta)
{
struct wpabuf *data;
int reply_res;
@@ -761,7 +753,7 @@
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- reply_res = send_auth_reply(hapd, sta, sta->addr, bssid,
+ reply_res = send_auth_reply(hapd, sta, sta->addr,
WLAN_AUTH_SAE, 2,
WLAN_STATUS_SUCCESS, wpabuf_head(data),
wpabuf_len(data), "sae-send-confirm");
@@ -821,12 +813,41 @@
if (sta->sae->sync > hapd->conf->sae_sync) {
sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync");
sta->sae->sync = 0;
+ if (sta->sae->tmp) {
+ /* Disable this SAE instance for 10 seconds to avoid
+ * unnecessary flood of multiple SAE commits in
+ * unexpected mesh cases. */
+ if (os_get_reltime(&sta->sae->tmp->disabled_until) == 0)
+ sta->sae->tmp->disabled_until.sec += 10;
+ }
return -1;
}
return 0;
}
+static bool sae_proto_instance_disabled(struct sta_info *sta)
+{
+ struct sae_temporary_data *tmp;
+
+ if (!sta->sae)
+ return false;
+ tmp = sta->sae->tmp;
+ if (!tmp)
+ return false;
+
+ if (os_reltime_initialized(&tmp->disabled_until)) {
+ struct os_reltime now;
+
+ os_get_reltime(&now);
+ if (os_reltime_before(&now, &tmp->disabled_until))
+ return true;
+ }
+
+ return false;
+}
+
+
static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
{
struct hostapd_data *hapd = eloop_ctx;
@@ -843,13 +864,13 @@
switch (sta->sae->state) {
case SAE_COMMITTED:
- ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
+ ret = auth_sae_send_commit(hapd, sta, 0, -1);
eloop_register_timeout(0,
hapd->dot11RSNASAERetransPeriod * 1000,
auth_sae_retransmit_timer, hapd, sta);
break;
case SAE_CONFIRMED:
- ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
+ ret = auth_sae_send_confirm(hapd, sta);
eloop_register_timeout(0,
hapd->dot11RSNASAERetransPeriod * 1000,
auth_sae_retransmit_timer, hapd, sta);
@@ -957,7 +978,7 @@
static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *bssid, u16 auth_transaction, u16 status_code,
+ u16 auth_transaction, u16 status_code,
int allow_reuse, int *sta_removed)
{
int ret;
@@ -970,6 +991,13 @@
wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u",
MAC2STR(sta->addr), sae_state_txt(sta->sae->state),
auth_transaction);
+
+ if (auth_transaction == 1 && sae_proto_instance_disabled(sta)) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Protocol instance temporarily disabled - discard received SAE commit");
+ return WLAN_STATUS_SUCCESS;
+ }
+
switch (sta->sae->state) {
case SAE_NOTHING:
if (auth_transaction == 1) {
@@ -981,7 +1009,7 @@
sta->sae->pk =
status_code == WLAN_STATUS_SAE_PK;
}
- ret = auth_sae_send_commit(hapd, sta, bssid,
+ ret = auth_sae_send_commit(hapd, sta,
!allow_reuse, status_code);
if (ret)
return ret;
@@ -1007,7 +1035,7 @@
* based on SAE finite state machine
* Nothing -> Confirm transition.
*/
- ret = auth_sae_send_confirm(hapd, sta, bssid);
+ ret = auth_sae_send_confirm(hapd, sta);
if (ret)
return ret;
sae_set_state(sta, SAE_CONFIRMED,
@@ -1037,7 +1065,7 @@
if (sae_process_commit(sta->sae) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- ret = auth_sae_send_confirm(hapd, sta, bssid);
+ ret = auth_sae_send_confirm(hapd, sta);
if (ret)
return ret;
sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm");
@@ -1052,8 +1080,7 @@
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
- ret = auth_sae_send_commit(hapd, sta, bssid, 0,
- status_code);
+ ret = auth_sae_send_commit(hapd, sta, 0, status_code);
if (ret)
return ret;
@@ -1064,7 +1091,7 @@
* Nothing -> Confirmed transition that was reduced to
* Nothing -> Committed above.
*/
- ret = auth_sae_send_confirm(hapd, sta, bssid);
+ ret = auth_sae_send_confirm(hapd, sta);
if (ret)
return ret;
@@ -1075,7 +1102,7 @@
* step to get to Accepted without waiting for
* additional events.
*/
- return sae_sm_step(hapd, sta, bssid, auth_transaction,
+ return sae_sm_step(hapd, sta, auth_transaction,
WLAN_STATUS_SUCCESS, 0, sta_removed);
}
break;
@@ -1086,15 +1113,14 @@
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
- ret = auth_sae_send_commit(hapd, sta, bssid, 1,
- status_code);
+ ret = auth_sae_send_commit(hapd, sta, 1, status_code);
if (ret)
return ret;
if (sae_process_commit(sta->sae) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- ret = auth_sae_send_confirm(hapd, sta, bssid);
+ ret = auth_sae_send_confirm(hapd, sta);
if (ret)
return ret;
@@ -1115,8 +1141,7 @@
*sta_removed = 1;
} else if (auth_transaction == 1) {
wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
- ret = auth_sae_send_commit(hapd, sta, bssid, 1,
- status_code);
+ ret = auth_sae_send_commit(hapd, sta, 1, status_code);
if (ret)
return ret;
sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
@@ -1130,7 +1155,7 @@
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
- ret = auth_sae_send_confirm(hapd, sta, bssid);
+ ret = auth_sae_send_confirm(hapd, sta);
sae_clear_temp_data(sta->sae);
if (ret)
return ret;
@@ -1242,7 +1267,7 @@
struct sae_data *sae)
{
const struct wpabuf *groups;
- size_t i, count;
+ size_t i, count, len;
const u8 *pos;
if (!sae->tmp)
@@ -1252,7 +1277,15 @@
return 0;
pos = wpabuf_head(groups);
- count = wpabuf_len(groups) / 2;
+ len = wpabuf_len(groups);
+ if (len & 1) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Invalid length of the Rejected Groups element payload: %zu",
+ len);
+ return 1;
+ }
+
+ count = len / 2;
for (i = 0; i < count; i++) {
int enabled;
u16 group;
@@ -1291,7 +1324,7 @@
pos = mgmt->u.auth.variable;
end = ((const u8 *) mgmt) + len;
resp = status_code;
- send_auth_reply(hapd, sta, sta->addr, mgmt->bssid,
+ send_auth_reply(hapd, sta, sta->addr,
WLAN_AUTH_SAE,
auth_transaction, resp, pos, end - pos,
"auth-sae-reflection-attack");
@@ -1300,7 +1333,7 @@
if (hapd->conf->sae_commit_override && auth_transaction == 1) {
wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
- send_auth_reply(hapd, sta, sta->addr, mgmt->bssid,
+ send_auth_reply(hapd, sta, sta->addr,
WLAN_AUTH_SAE,
auth_transaction, resp,
wpabuf_head(hapd->conf->sae_commit_override),
@@ -1380,8 +1413,7 @@
* Authentication frame, and the commit-scalar and
* COMMIT-ELEMENT previously sent.
*/
- resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0,
- status_code);
+ resp = auth_sae_send_commit(hapd, sta, 0, status_code);
if (resp != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_ERROR,
"SAE: Failed to send commit message");
@@ -1407,6 +1439,12 @@
if (!sae_status_success(hapd, status_code))
goto remove_sta;
+ if (sae_proto_instance_disabled(sta)) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Protocol instance temporarily disabled - discard received SAE commit");
+ return;
+ }
+
if (!(hapd->conf->mesh & MESH_ENABLED) &&
sta->sae->state == SAE_COMMITTED) {
/* This is needed in the infrastructure BSS case to
@@ -1504,7 +1542,7 @@
goto reply;
}
- resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
+ resp = sae_sm_step(hapd, sta, auth_transaction,
status_code, allow_reuse, &sta_removed);
} else if (auth_transaction == 2) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -1547,7 +1585,7 @@
}
sta->sae->rc = peer_send_confirm;
}
- resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
+ resp = sae_sm_step(hapd, sta, auth_transaction,
status_code, 0, &sta_removed);
} else {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -1572,11 +1610,19 @@
data = wpabuf_alloc_copy(pos, 2);
sae_sme_send_external_auth_status(hapd, sta, resp);
- send_auth_reply(hapd, sta, sta->addr, mgmt->bssid,
+ send_auth_reply(hapd, sta, sta->addr,
WLAN_AUTH_SAE,
auth_transaction, resp,
data ? wpabuf_head(data) : (u8 *) "",
data ? wpabuf_len(data) : 0, "auth-sae");
+ if (sta->sae && sta->sae->tmp && sta->sae->tmp->pw_id &&
+ resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER &&
+ auth_transaction == 1) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Clear stored password identifier since this SAE commit was not accepted");
+ os_free(sta->sae->tmp->pw_id);
+ sta->sae->tmp->pw_id = NULL;
+ }
}
remove_sta:
@@ -1613,7 +1659,7 @@
if (sta->sae->state != SAE_NOTHING)
return -1;
- ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
+ ret = auth_sae_send_commit(hapd, sta, 0, -1);
if (ret)
return -1;
@@ -1894,11 +1940,14 @@
elems.rsn_ie - 2, elems.rsn_ie_len + 2,
elems.rsnxe ? elems.rsnxe - 2 : NULL,
elems.rsnxe ? elems.rsnxe_len + 2 : 0,
- elems.mdie, elems.mdie_len, NULL, 0);
+ elems.mdie, elems.mdie_len, NULL, 0, NULL);
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
goto fail;
+ wpa_auth_set_rsn_override(sta->wpa_sm, elems.rsne_override != NULL);
+ wpa_auth_set_rsn_override_2(sta->wpa_sm, elems.rsne_override_2 != NULL);
+
if (!elems.fils_nonce) {
wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -2226,7 +2275,7 @@
auth_alg = (pub ||
resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
- send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp,
+ send_auth_reply(hapd, sta, sta->addr, auth_alg, 2, resp,
data ? wpabuf_head(data) : (u8 *) "",
data ? wpabuf_len(data) : 0, "auth-fils-finish");
wpabuf_free(data);
@@ -2697,6 +2746,14 @@
pasn_set_akmp(pasn, rsn_data.key_mgmt);
pasn_set_cipher(pasn, rsn_data.pairwise_cipher);
+ if (pasn->derive_kdk &&
+ !ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
+ WLAN_RSNX_CAPAB_SECURE_LTF))
+ pasn_disable_kdk_derivation(pasn);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->conf->force_kdk_derivation)
+ pasn_enable_kdk_derivation(pasn);
+#endif /* CONFIG_TESTING_OPTIONS */
akmp = pasn_get_akmp(pasn);
if (wpa_key_mgmt_ft(akmp) && rsn_data.num_pmkid) {
@@ -2827,7 +2884,7 @@
size_t resp_ies_len = 0;
u16 seq_ctrl;
struct radius_sta rad_info;
- const u8 *dst, *sa, *bssid;
+ const u8 *dst, *sa;
#ifdef CONFIG_IEEE80211BE
bool mld_sta = false;
#endif /* CONFIG_IEEE80211BE */
@@ -2907,7 +2964,10 @@
auth_alg == WLAN_AUTH_FT) ||
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
- (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ (hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt |
+ hapd->conf->rsn_override_key_mgmt |
+ hapd->conf->rsn_override_key_mgmt_2) &&
auth_alg == WLAN_AUTH_SAE) ||
#endif /* CONFIG_SAE */
#ifdef CONFIG_FILS
@@ -3214,7 +3274,7 @@
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
- wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid,
+ wpa_ft_process_auth(sta->wpa_sm,
auth_transaction, mgmt->u.auth.variable,
len - IEEE80211_HDRLEN -
sizeof(mgmt->u.auth),
@@ -3262,21 +3322,13 @@
fail:
dst = mgmt->sa;
- bssid = mgmt->bssid;
#ifdef CONFIG_IEEE80211BE
- /*
- * Once a non-AP MLD is added to the driver, the addressing should use
- * the MLD MAC address. It is the responsibility of the driver to
- * handle the translations.
- */
- if (ap_sta_is_mld(hapd, sta)) {
+ if (ap_sta_is_mld(hapd, sta))
dst = sta->addr;
- bssid = hapd->mld->mld_addr;
- }
#endif /* CONFIG_IEEE80211BE */
- reply_res = send_auth_reply(hapd, sta, dst, bssid, auth_alg,
+ reply_res = send_auth_reply(hapd, sta, dst, auth_alg,
auth_alg == WLAN_AUTH_SAE ?
auth_transaction : auth_transaction + 1,
resp, resp_ies, resp_ies_len,
@@ -3783,14 +3835,14 @@
}
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta))
- wpa_auth_set_ml_info(sta->wpa_sm, hapd->mld->mld_addr,
+ wpa_auth_set_ml_info(sta->wpa_sm,
sta->mld_assoc_link_id, &sta->mld_info);
#endif /* CONFIG_IEEE80211BE */
rsn_ie -= 2;
rsn_ie_len += 2;
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq, rsn_ie, rsn_ie_len,
- NULL, 0, NULL, 0, owe_dh, owe_dh_len);
+ NULL, 0, NULL, 0, owe_dh, owe_dh_len, NULL);
status = wpa_res_to_status_code(res);
if (status != WLAN_STATUS_SUCCESS)
goto end;
@@ -3879,6 +3931,8 @@
const u8 *wpa_ie;
size_t wpa_ie_len;
const u8 *p2p_dev_addr = NULL;
+ struct hostapd_data *assoc_hapd;
+ struct sta_info *assoc_sta = NULL;
resp = check_ssid(hapd, sta, elems->ssid, elems->ssid_len);
if (resp != WLAN_STATUS_SUCCESS)
@@ -4044,14 +4098,18 @@
if (hapd->conf->wpa && wpa_ie) {
enum wpa_validate_result res;
+#ifdef CONFIG_IEEE80211BE
+ struct mld_info *info = &sta->mld_info;
+ bool init = !sta->wpa_sm;
+#endif /* CONFIG_IEEE80211BE */
wpa_ie -= 2;
wpa_ie_len += 2;
if (!sta->wpa_sm) {
-#ifdef CONFIG_IEEE80211BE
- struct mld_info *info = &sta->mld_info;
-#endif /* CONFIG_IEEE80211BE */
+ if (!link)
+ assoc_sta = hostapd_ml_get_assoc_sta(
+ hapd, sta, &assoc_hapd);
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
sta->addr,
@@ -4062,20 +4120,24 @@
"Failed to initialize RSN state machine");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
-
-#ifdef CONFIG_IEEE80211BE
- if (ap_sta_is_mld(hapd, sta)) {
- wpa_printf(MSG_DEBUG,
- "MLD: Set ML info in RSN Authenticator");
- wpa_auth_set_ml_info(sta->wpa_sm,
- hapd->mld->mld_addr,
- sta->mld_assoc_link_id,
- info);
- }
-#endif /* CONFIG_IEEE80211BE */
}
+#ifdef CONFIG_IEEE80211BE
+ if (ap_sta_is_mld(hapd, sta)) {
+ wpa_printf(MSG_DEBUG,
+ "MLD: %s ML info in RSN Authenticator",
+ init ? "Set" : "Reset");
+ wpa_auth_set_ml_info(sta->wpa_sm,
+ sta->mld_assoc_link_id,
+ info);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
+ wpa_auth_set_rsn_override(sta->wpa_sm,
+ elems->rsne_override != NULL);
+ wpa_auth_set_rsn_override_2(sta->wpa_sm,
+ elems->rsne_override_2 != NULL);
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
wpa_ie, wpa_ie_len,
@@ -4084,7 +4146,8 @@
elems->rsnxe ? elems->rsnxe_len + 2 :
0,
elems->mdie, elems->mdie_len,
- elems->owe_dh, elems->owe_dh_len);
+ elems->owe_dh, elems->owe_dh_len,
+ assoc_sta ? assoc_sta->wpa_sm : NULL);
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
@@ -4205,6 +4268,13 @@
"association");
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
}
+
+ wpa_auth_set_ssid_protection(
+ sta->wpa_sm,
+ hapd->conf->ssid_protection &&
+ ieee802_11_rsnx_capab_len(
+ elems->rsnxe, elems->rsnxe_len,
+ WLAN_RSNX_CAPAB_SSID_PROTECTION));
#ifdef CONFIG_HS20
} else if (hapd->conf->osen) {
if (!elems->osen) {
@@ -4341,6 +4411,19 @@
sta->power_capab = 0;
}
+ if (elems->bss_max_idle_period &&
+ hapd->conf->max_acceptable_idle_period) {
+ u16 req;
+
+ req = WPA_GET_LE16(elems->bss_max_idle_period);
+ if (req <= hapd->conf->max_acceptable_idle_period)
+ sta->max_idle_period = req;
+ else if (hapd->conf->max_acceptable_idle_period >
+ hapd->conf->ap_max_inactivity)
+ sta->max_idle_period =
+ hapd->conf->max_acceptable_idle_period;
+ }
+
return WLAN_STATUS_SUCCESS;
}
@@ -4475,6 +4558,8 @@
}
sta->flags |= origin_sta->flags | WLAN_STA_ASSOC_REQ_OK;
+ sta->mld_assoc_link_id = origin_sta->mld_assoc_link_id;
+
status = __check_assoc_ies(hapd, sta, NULL, 0, &elems, reassoc, true);
if (status != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG, "MLD: link: Element check failed");
@@ -4482,7 +4567,6 @@
}
ap_sta_set_mld(sta, true);
- sta->mld_assoc_link_id = origin_sta->mld_assoc_link_id;
os_memcpy(&sta->mld_info, &origin_sta->mld_info, sizeof(sta->mld_info));
for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
@@ -4509,9 +4593,11 @@
ieee802_11_update_beacons(hapd->iface);
}
- /* RSN Authenticator should always be the one on the original station */
+ /* Maintain state machine reference on all link STAs, this is needed
+ * during group rekey handling.
+ */
wpa_auth_sta_deinit(sta->wpa_sm);
- sta->wpa_sm = NULL;
+ sta->wpa_sm = origin_sta->wpa_sm;
/*
* Do not initialize the EAPOL state machine.
@@ -4522,13 +4608,6 @@
wpa_printf(MSG_DEBUG, "MLD: link=%u, association OK (aid=%u)",
hapd->mld_link_id, sta->aid);
- /*
- * Get RSNE and RSNXE for the current BSS as they are required by the
- * Authenticator.
- */
- link->rsne = hostapd_wpa_ie(hapd, WLAN_EID_RSN);
- link->rsnxe = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
-
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC_REQ_OK;
/* TODO: What other processing is required? */
@@ -4575,40 +4654,31 @@
bool offload)
{
#ifdef CONFIG_IEEE80211BE
- unsigned int i, j;
+ unsigned int i;
if (!hostapd_is_mld_ap(hapd))
return 0;
- /*
- * This is not really needed, but make the interaction with the RSN
- * Authenticator more consistent
- */
- sta->mld_info.links[hapd->mld_link_id].rsne =
- hostapd_wpa_ie(hapd, WLAN_EID_RSN);
- sta->mld_info.links[hapd->mld_link_id].rsnxe =
- hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
-
for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- struct hostapd_iface *iface = NULL;
+ struct hostapd_data *bss = NULL;
struct mld_link_info *link = &sta->mld_info.links[i];
+ bool link_bss_found = false;
- if (!link->valid)
+ if (!link->valid || i == sta->mld_assoc_link_id)
continue;
- for (j = 0; j < hapd->iface->interfaces->count; j++) {
- iface = hapd->iface->interfaces->iface[j];
-
- if (hapd->iface == iface)
+ for_each_mld_link(bss, hapd) {
+ if (bss == hapd)
continue;
- if (hostapd_is_ml_partner(hapd, iface->bss[0]) &&
- i == iface->bss[0]->mld_link_id)
- break;
+ if (bss->mld_link_id != i)
+ continue;
+
+ link_bss_found = true;
+ break;
}
- if (!iface || j == hapd->iface->interfaces->count ||
- TEST_FAIL()) {
+ if (!link_bss_found || TEST_FAIL()) {
wpa_printf(MSG_DEBUG,
"MLD: No link match for link_id=%u", i);
@@ -4621,7 +4691,7 @@
if (!offload)
ieee80211_ml_build_assoc_resp(hapd, link);
} else {
- if (ieee80211_ml_process_link(iface->bss[0], sta, link,
+ if (ieee80211_ml_process_link(bss, sta, link,
ies, ies_len, reassoc,
offload))
return -1;
@@ -4786,7 +4856,6 @@
struct ieee80211_mgmt *reply;
u8 *p;
u16 res = WLAN_STATUS_SUCCESS;
- const u8 *sa = hapd->own_addr;
buflen = sizeof(struct ieee80211_mgmt) + 1024;
#ifdef CONFIG_FILS
@@ -4823,18 +4892,9 @@
(reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
WLAN_FC_STYPE_ASSOC_RESP));
-#ifdef CONFIG_IEEE80211BE
- /*
- * Once a non-AP MLD is added to the driver, the addressing should use
- * MLD MAC address.
- */
- if (ap_sta_is_mld(hapd, sta) && allow_mld_addr_trans)
- sa = hapd->mld->mld_addr;
-#endif /* CONFIG_IEEE80211BE */
-
os_memcpy(reply->da, addr, ETH_ALEN);
- os_memcpy(reply->sa, sa, ETH_ALEN);
- os_memcpy(reply->bssid, sa, ETH_ALEN);
+ os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
send_len = IEEE80211_HDRLEN;
send_len += sizeof(reply->u.assoc_resp);
@@ -4938,7 +4998,7 @@
#endif /* CONFIG_IEEE80211AX */
p = hostapd_eid_ext_capab(hapd, p, false);
- p = hostapd_eid_bss_max_idle_period(hapd, p);
+ p = hostapd_eid_bss_max_idle_period(hapd, p, sta->max_idle_period);
if (sta && sta->qos_map_enabled)
p = hostapd_eid_qos_map_set(hapd, p);
@@ -5622,7 +5682,7 @@
#endif /* CONFIG_FILS */
if (set_beacon)
- ieee802_11_set_beacons(hapd->iface);
+ ieee802_11_update_beacons(hapd->iface);
fail:
@@ -5794,7 +5854,7 @@
#ifdef CONFIG_IEEE80211BE
struct hostapd_data *assoc_hapd, *tmp_hapd;
struct sta_info *assoc_sta;
- unsigned int i, link_id;
+ struct sta_info *tmp_sta;
if (!hostapd_is_mld_ap(hapd))
return false;
@@ -5807,45 +5867,25 @@
if (!assoc_sta)
return false;
- for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
- for (i = 0; i < assoc_hapd->iface->interfaces->count; i++) {
- struct sta_info *tmp_sta;
+ for_each_mld_link(tmp_hapd, assoc_hapd) {
+ if (tmp_hapd == assoc_hapd)
+ continue;
- if (!assoc_sta->mld_info.links[link_id].valid)
+ if (!assoc_sta->mld_info.links[tmp_hapd->mld_link_id].valid)
+ continue;
+
+ for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
+ tmp_sta = tmp_sta->next) {
+ if (tmp_sta->mld_assoc_link_id !=
+ assoc_sta->mld_assoc_link_id ||
+ tmp_sta->aid != assoc_sta->aid)
continue;
- tmp_hapd =
- assoc_hapd->iface->interfaces->iface[i]->bss[0];
-
- if (!hostapd_is_ml_partner(assoc_hapd, tmp_hapd))
- continue;
-
- for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
- tmp_sta = tmp_sta->next) {
- /*
- * Remove the station on which the association
- * was done only after all other link stations
- * are removed. Since there is only a single
- * station per struct hostapd_hapd with the
- * same association link simply break out from
- * the loop.
- */
- if (tmp_sta == assoc_sta)
- break;
-
- if (tmp_sta->mld_assoc_link_id !=
- assoc_sta->mld_assoc_link_id ||
- tmp_sta->aid != assoc_sta->aid)
- continue;
-
- if (!disassoc)
- hostapd_deauth_sta(tmp_hapd, tmp_sta,
- mgmt);
- else
- hostapd_disassoc_sta(tmp_hapd, tmp_sta,
- mgmt);
- break;
- }
+ if (!disassoc)
+ hostapd_deauth_sta(tmp_hapd, tmp_sta, mgmt);
+ else
+ hostapd_disassoc_sta(tmp_hapd, tmp_sta, mgmt);
+ break;
}
}
@@ -6468,38 +6508,33 @@
struct sta_info *sta, bool ok)
{
#ifdef CONFIG_IEEE80211BE
- unsigned int i, link_id;
+ struct hostapd_data *tmp_hapd;
if (!hostapd_is_mld_ap(hapd))
return;
- for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
- struct mld_link_info *link = &sta->mld_info.links[link_id];
+ for_each_mld_link(tmp_hapd, hapd) {
+ struct mld_link_info *link;
+ struct sta_info *tmp_sta;
+ if (tmp_hapd == hapd)
+ continue;
+
+ link = &sta->mld_info.links[tmp_hapd->mld_link_id];
if (!link->valid)
continue;
- for (i = 0; i < hapd->iface->interfaces->count; i++) {
- struct sta_info *tmp_sta;
- struct hostapd_data *tmp_hapd =
- hapd->iface->interfaces->iface[i]->bss[0];
-
- if (!hostapd_is_ml_partner(tmp_hapd, hapd))
+ for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
+ tmp_sta = tmp_sta->next) {
+ if (tmp_sta == sta ||
+ tmp_sta->mld_assoc_link_id !=
+ sta->mld_assoc_link_id ||
+ tmp_sta->aid != sta->aid)
continue;
- for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
- tmp_sta = tmp_sta->next) {
- if (tmp_sta == sta ||
- tmp_sta->mld_assoc_link_id !=
- sta->mld_assoc_link_id ||
- tmp_sta->aid != sta->aid)
- continue;
-
- ieee80211_ml_link_sta_assoc_cb(tmp_hapd,
- tmp_sta, link,
- ok);
- break;
- }
+ ieee80211_ml_link_sta_assoc_cb(tmp_hapd, tmp_sta, link,
+ ok);
+ break;
}
}
#endif /* CONFIG_IEEE80211BE */
@@ -6622,6 +6657,7 @@
if ((sta->flags & WLAN_STA_WDS) ||
(sta->flags & WLAN_STA_MULTI_AP &&
(hapd->conf->multi_ap & BACKHAUL_BSS) &&
+ hapd->conf->wds_sta &&
!(sta->flags & WLAN_STA_WPS))) {
int ret;
char ifname_wds[IFNAMSIZ + 1];
@@ -6914,33 +6950,6 @@
}
-void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
- const u8 *data, size_t len, int ack)
-{
- struct sta_info *sta;
- struct hostapd_iface *iface = hapd->iface;
-
- sta = ap_get_sta(hapd, dst);
- if (sta == NULL && iface->num_bss > 1) {
- size_t j;
- for (j = 0; j < iface->num_bss; j++) {
- hapd = iface->bss[j];
- sta = ap_get_sta(hapd, dst);
- if (sta)
- break;
- }
- }
- if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
- wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA "
- MACSTR " that is not currently associated",
- MAC2STR(dst));
- return;
- }
-
- ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
-}
-
-
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta;
@@ -7326,24 +7335,61 @@
u8 end;
};
+static bool hostapd_skip_rnr(size_t i, struct mbssid_ie_profiles *skip_profiles,
+ bool ap_mld, u8 tbtt_info_len, bool mld_update,
+ struct hostapd_data *reporting_hapd,
+ struct hostapd_data *bss)
+{
+ if (skip_profiles &&
+ i >= skip_profiles->start && i < skip_profiles->end)
+ return true;
+
+ /* No need to report if length is for normal TBTT and the BSS is
+ * affiliated with an AP MLD. MLD TBTT will include this. */
+ if (tbtt_info_len == RNR_TBTT_INFO_LEN && ap_mld)
+ return true;
+
+ /* No need to report if length is for MLD TBTT and the BSS is not
+ * affiliated with an aP MLD. Normal TBTT will include this. */
+ if (tbtt_info_len == RNR_TBTT_INFO_MLD_LEN && !ap_mld)
+ return true;
+
+#ifdef CONFIG_IEEE80211BE
+ /* If building for co-location and they are ML partners, no need to
+ * include since the ML RNR will carry this. */
+ if (!mld_update && hostapd_is_ml_partner(reporting_hapd, bss))
+ return true;
+
+ /* If building for ML RNR and they are not ML partners, don't include.
+ */
+ if (mld_update && !hostapd_is_ml_partner(reporting_hapd, bss))
+ return true;
+#endif /* CONFIG_IEEE80211BE */
+
+ return false;
+}
+
+
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)
+ struct mbssid_ie_profiles *skip_profiles,
+ bool mld_update)
{
size_t total_len = 0, len = *current_len;
- int tbtt_count = 0;
- size_t i, start = 0;
- bool ap_mld = false;
+ int tbtt_count, total_tbtt_count = 0;
+ size_t i, start;
+ u8 tbtt_info_len = mld_update ? RNR_TBTT_INFO_MLD_LEN :
+ RNR_TBTT_INFO_LEN;
-#ifdef CONFIG_IEEE80211BE
- ap_mld = !!hapd->conf->mld_ap;
-#endif /* CONFIG_IEEE80211BE */
+repeat_rnr_len:
+ start = 0;
+ tbtt_count = 0;
while (start < hapd->iface->num_bss) {
if (!len ||
- len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255 ||
+ len + RNR_TBTT_HEADER_LEN + tbtt_info_len > 255 ||
tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) {
len = RNR_HEADER_LEN;
total_len += RNR_HEADER_LEN;
@@ -7355,35 +7401,61 @@
for (i = start; i < hapd->iface->num_bss; i++) {
struct hostapd_data *bss = hapd->iface->bss[i];
+ bool ap_mld = false;
if (!bss || !bss->conf || !bss->started)
continue;
+#ifdef CONFIG_IEEE80211BE
+ ap_mld = bss->conf->mld_ap;
+#endif /* CONFIG_IEEE80211BE */
+
if (bss == reporting_hapd ||
bss->conf->ignore_broadcast_ssid)
continue;
- if (skip_profiles &&
- i >= skip_profiles->start && i < skip_profiles->end)
+ if (hostapd_skip_rnr(i, skip_profiles, ap_mld,
+ tbtt_info_len, mld_update,
+ reporting_hapd, bss))
continue;
- if (len + RNR_TBTT_INFO_LEN > 255 ||
+ if (len + tbtt_info_len > 255 ||
tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
break;
- if (!ap_mld) {
- len += RNR_TBTT_INFO_LEN;
- total_len += RNR_TBTT_INFO_LEN;
- } else {
- len += RNR_TBTT_INFO_MLD_LEN;
- total_len += RNR_TBTT_INFO_MLD_LEN;
- }
+ len += tbtt_info_len;
+ total_len += tbtt_info_len;
tbtt_count++;
}
start = i;
}
- if (!tbtt_count)
+ total_tbtt_count += tbtt_count;
+
+ /* If building for co-location, re-build again but this time include
+ * ML TBTTs.
+ */
+ if (!mld_update && tbtt_info_len == RNR_TBTT_INFO_LEN) {
+ tbtt_info_len = RNR_TBTT_INFO_MLD_LEN;
+
+ /* If no TBTT was found, adjust the len and total_len since it
+ * would have incremented before we checked all BSSs. */
+ if (!tbtt_count) {
+ len -= RNR_TBTT_HEADER_LEN;
+ total_len -= RNR_TBTT_HEADER_LEN;
+ }
+
+ goto repeat_rnr_len;
+ }
+
+ /* This is possible when in the re-built case and no suitable TBTT was
+ * found. Adjust the length accordingly. */
+ if (!tbtt_count && total_tbtt_count) {
+ len -= RNR_TBTT_HEADER_LEN;
+ total_len -= RNR_TBTT_HEADER_LEN;
+ }
+
+ if (!total_tbtt_count)
total_len = 0;
else
*current_len = len;
@@ -7432,8 +7504,8 @@
}
-static size_t hostapd_eid_rnr_multi_iface_len(struct hostapd_data *hapd,
- size_t *current_len)
+static size_t hostapd_eid_rnr_colocation_len(struct hostapd_data *hapd,
+ size_t *current_len)
{
struct hostapd_iface *iface;
size_t len = 0;
@@ -7444,66 +7516,89 @@
for (i = 0; i < hapd->iface->interfaces->count; i++) {
iface = hapd->iface->interfaces->iface[i];
- bool ap_mld = false;
-#ifdef CONFIG_IEEE80211BE
- if (hostapd_is_ml_partner(hapd, iface->bss[0]))
- ap_mld = true;
-#endif /* CONFIG_IEEE80211BE */
-
- if (iface == hapd->iface ||
+ if (!iface || iface == hapd->iface ||
iface->state != HAPD_IFACE_ENABLED ||
- !(is_6ghz_op_class(iface->conf->op_class) || ap_mld))
+ !is_6ghz_op_class(iface->conf->op_class))
continue;
len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd,
- current_len, NULL);
+ current_len, NULL, false);
}
return len;
}
-size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type)
+static size_t hostapd_eid_rnr_mlo_len(struct hostapd_data *hapd, u32 type,
+ size_t *current_len)
+{
+ size_t len = 0;
+#ifdef CONFIG_IEEE80211BE
+ struct hostapd_iface *iface;
+ size_t i;
+
+ if (!hapd->iface || !hapd->iface->interfaces || !hapd->conf->mld_ap)
+ return 0;
+
+ /* TODO: Allow for FILS/Action as well */
+ if (type != WLAN_FC_STYPE_BEACON && type != WLAN_FC_STYPE_PROBE_RESP)
+ return 0;
+
+ for (i = 0; i < hapd->iface->interfaces->count; i++) {
+ iface = hapd->iface->interfaces->iface[i];
+
+ if (!iface || iface == hapd->iface ||
+ hapd->iface->freq == iface->freq)
+ continue;
+
+ len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd,
+ current_len, NULL, true);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
+ return len;
+}
+
+
+size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type,
+ bool include_mld_params)
{
size_t total_len = 0, current_len = 0;
enum colocation_mode mode = get_colocation_mode(hapd);
- bool ap_mld = false;
-
-#ifdef CONFIG_IEEE80211BE
- ap_mld = !!hapd->conf->mld_ap;
-#endif /* CONFIG_IEEE80211BE */
switch (type) {
case WLAN_FC_STYPE_BEACON:
if (hapd->conf->rnr)
total_len += hostapd_eid_nr_db_len(hapd, ¤t_len);
/* fallthrough */
-
case WLAN_FC_STYPE_PROBE_RESP:
- if (mode == COLOCATED_LOWER_BAND || ap_mld)
+ if (mode == COLOCATED_LOWER_BAND)
total_len +=
- hostapd_eid_rnr_multi_iface_len(hapd,
- ¤t_len);
+ hostapd_eid_rnr_colocation_len(hapd,
+ ¤t_len);
if (hapd->conf->rnr && hapd->iface->num_bss > 1 &&
!hapd->iconf->mbssid)
total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
¤t_len,
- NULL);
+ NULL, false);
break;
-
case WLAN_FC_STYPE_ACTION:
if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
¤t_len,
- NULL);
- break;
-
- default:
+ NULL, false);
break;
}
+ /* For EMA Beacons, MLD neighbor repoting is added as part of
+ * MBSSID RNR. */
+ if (include_mld_params &&
+ (type != WLAN_FC_STYPE_BEACON ||
+ hapd->iconf->mbssid != ENHANCED_MBSSID_ENABLED))
+ total_len += hostapd_eid_rnr_mlo_len(hapd, type, ¤t_len);
+
return total_len;
}
@@ -7567,7 +7662,8 @@
struct hostapd_data *reporting_hapd,
struct mbssid_ie_profiles *skip_profiles,
size_t i, u8 *tbtt_count, size_t *len,
- u8 **pos)
+ u8 **pos, u8 **tbtt_count_pos, u8 tbtt_info_len,
+ u8 op_class, bool mld_update)
{
struct hostapd_iface *iface = hapd->iface;
struct hostapd_data *bss = iface->bss[i];
@@ -7583,14 +7679,24 @@
bss == reporting_hapd || bss->conf->ignore_broadcast_ssid)
return false;
- if (skip_profiles
- && i >= skip_profiles->start && i < skip_profiles->end)
- return false;
+ if (hostapd_skip_rnr(i, skip_profiles, ap_mld, tbtt_info_len,
+ mld_update, reporting_hapd, bss))
+ return false;
if (*len + RNR_TBTT_INFO_LEN > 255 ||
*tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
return true;
+ if (!(*tbtt_count)) {
+ /* Add neighbor report header info only if there is at least
+ * one TBTT info available. */
+ *tbtt_count_pos = eid++;
+ *eid++ = tbtt_info_len;
+ *eid++ = op_class;
+ *eid++ = bss->iconf->channel;
+ *len += RNR_TBTT_HEADER_LEN;
+ }
+
*eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
os_memcpy(eid, bss->own_addr, ETH_ALEN);
eid += ETH_ALEN;
@@ -7614,29 +7720,34 @@
*eid++ = bss_param;
*eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER;
- if (!ap_mld) {
- *len += RNR_TBTT_INFO_LEN;
- } else {
#ifdef CONFIG_IEEE80211BE
- u8 param_ch = hapd->eht_mld_bss_param_change;
+ if (ap_mld) {
+ u8 param_ch = bss->eht_mld_bss_param_change;
+ bool is_partner;
- if (hostapd_is_ml_partner(bss, reporting_hapd))
- *eid++ = 0;
- else
- *eid++ = hostapd_get_mld_id(hapd);
-
- *eid++ = hapd->mld_link_id | ((param_ch & 0xF) << 4);
- *eid = (param_ch >> 4) & 0xF;
+ /* If BSS is not a partner of the reporting_hapd
+ * a) MLD ID advertised shall be 255.
+ * b) Link ID advertised shall be 15.
+ * c) BPCC advertised shall be 255 */
+ is_partner = hostapd_is_ml_partner(bss, reporting_hapd);
+ /* MLD ID */
+ *eid++ = is_partner ? hostapd_get_mld_id(bss) : 0xFF;
+ /* Link ID (Bit 3 to Bit 0)
+ * BPCC (Bit 4 to Bit 7) */
+ *eid++ = is_partner ?
+ bss->mld_link_id | ((param_ch & 0xF) << 4) :
+ (MAX_NUM_MLD_LINKS | 0xF0);
+ /* BPCC (Bit 3 to Bit 0) */
+ *eid = is_partner ? ((param_ch & 0xF0) >> 4) : 0x0F;
#ifdef CONFIG_TESTING_OPTIONS
- if (hapd->conf->mld_indicate_disabled)
+ if (bss->conf->mld_indicate_disabled)
*eid |= RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED;
#endif /* CONFIG_TESTING_OPTIONS */
eid++;
-
- *len += RNR_TBTT_INFO_MLD_LEN;
-#endif /* CONFIG_IEEE80211BE */
}
+#endif /* CONFIG_IEEE80211BE */
+ *len += tbtt_info_len;
(*tbtt_count)++;
*pos = eid;
@@ -7647,18 +7758,17 @@
static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
struct hostapd_data *reporting_hapd,
u8 *eid, size_t *current_len,
- struct mbssid_ie_profiles *skip_profiles)
+ struct mbssid_ie_profiles *skip_profiles,
+ bool mld_update)
{
struct hostapd_iface *iface = hapd->iface;
- size_t i, start = 0;
+ size_t i, start;
size_t len = *current_len;
- u8 *tbtt_count_pos, *eid_start = eid, *size_offset = (eid - len) + 1;
- u8 tbtt_count = 0, op_class, channel;
- bool ap_mld = false;
-
-#ifdef CONFIG_IEEE80211BE
- ap_mld = !!hapd->conf->mld_ap;
-#endif /* CONFIG_IEEE80211BE */
+ u8 *eid_start = eid, *size_offset = (eid - len) + 1;
+ u8 *tbtt_count_pos = size_offset + 1;
+ u8 tbtt_count, total_tbtt_count = 0, op_class, channel;
+ u8 tbtt_info_len = mld_update ? RNR_TBTT_INFO_MLD_LEN :
+ RNR_TBTT_INFO_LEN;
if (!(iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) || !iface->freq)
return eid;
@@ -7670,9 +7780,12 @@
NUM_HOSTAPD_MODES)
return eid;
+repeat_rnr:
+ start = 0;
+ tbtt_count = 0;
while (start < iface->num_bss) {
if (!len ||
- len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255 ||
+ len + RNR_TBTT_HEADER_LEN + tbtt_info_len > 255 ||
tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) {
eid_start = eid;
*eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
@@ -7681,25 +7794,34 @@
tbtt_count = 0;
}
- tbtt_count_pos = eid++;
- *eid++ = ap_mld ? RNR_TBTT_INFO_MLD_LEN : RNR_TBTT_INFO_LEN;
- *eid++ = op_class;
- *eid++ = hapd->iconf->channel;
- len += RNR_TBTT_HEADER_LEN;
-
for (i = start; i < iface->num_bss; i++) {
if (hostapd_eid_rnr_bss(hapd, reporting_hapd,
skip_profiles, i,
- &tbtt_count, &len, &eid))
+ &tbtt_count, &len, &eid,
+ &tbtt_count_pos, tbtt_info_len,
+ op_class, mld_update))
break;
}
start = i;
- *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
- *size_offset = (eid - size_offset) - 1;
+
+ if (tbtt_count) {
+ *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
+ *size_offset = (eid - size_offset) - 1;
+ }
}
- if (tbtt_count == 0)
+ total_tbtt_count += tbtt_count;
+
+ /* If building for co-location, re-build again but this time include
+ * ML TBTTs.
+ */
+ if (!mld_update && tbtt_info_len == RNR_TBTT_INFO_LEN) {
+ tbtt_info_len = RNR_TBTT_INFO_MLD_LEN;
+ goto repeat_rnr;
+ }
+
+ if (!total_tbtt_count)
return eid_start;
*current_len = len;
@@ -7707,8 +7829,8 @@
}
-static u8 * hostapd_eid_rnr_multi_iface(struct hostapd_data *hapd, u8 *eid,
- size_t *current_len)
+u8 * hostapd_eid_rnr_colocation(struct hostapd_data *hapd, u8 *eid,
+ size_t *current_len)
{
struct hostapd_iface *iface;
size_t i;
@@ -7718,64 +7840,88 @@
for (i = 0; i < hapd->iface->interfaces->count; i++) {
iface = hapd->iface->interfaces->iface[i];
- bool ap_mld = false;
-#ifdef CONFIG_IEEE80211BE
- if (hostapd_is_ml_partner(hapd, iface->bss[0]))
- ap_mld = true;
-#endif /* CONFIG_IEEE80211BE */
-
- if (iface == hapd->iface ||
+ if (!iface || iface == hapd->iface ||
iface->state != HAPD_IFACE_ENABLED ||
- !(is_6ghz_op_class(iface->conf->op_class) || ap_mld))
+ !is_6ghz_op_class(iface->conf->op_class))
continue;
eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid,
- current_len, NULL);
+ current_len, NULL, false);
}
return eid;
}
-u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type)
+u8 * hostapd_eid_rnr_mlo(struct hostapd_data *hapd, u32 type,
+ u8 *eid, size_t *current_len)
+{
+#ifdef CONFIG_IEEE80211BE
+ struct hostapd_iface *iface;
+ size_t i;
+
+ if (!hapd->iface || !hapd->iface->interfaces || !hapd->conf->mld_ap)
+ return eid;
+
+ /* TODO: Allow for FILS/Action as well */
+ if (type != WLAN_FC_STYPE_BEACON && type != WLAN_FC_STYPE_PROBE_RESP)
+ return eid;
+
+ for (i = 0; i < hapd->iface->interfaces->count; i++) {
+ iface = hapd->iface->interfaces->iface[i];
+
+ if (!iface || iface == hapd->iface ||
+ hapd->iface->freq == iface->freq)
+ continue;
+
+ eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid,
+ current_len, NULL, true);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
+ return eid;
+}
+
+
+u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type,
+ bool include_mld_params)
{
u8 *eid_start = eid;
size_t current_len = 0;
enum colocation_mode mode = get_colocation_mode(hapd);
- bool ap_mld = false;
-
-#ifdef CONFIG_IEEE80211BE
- ap_mld = !!hapd->conf->mld_ap;
-#endif /* CONFIG_IEEE80211BE */
switch (type) {
case WLAN_FC_STYPE_BEACON:
if (hapd->conf->rnr)
eid = hostapd_eid_nr_db(hapd, eid, ¤t_len);
/* fallthrough */
-
case WLAN_FC_STYPE_PROBE_RESP:
- if (mode == COLOCATED_LOWER_BAND || ap_mld)
- eid = hostapd_eid_rnr_multi_iface(hapd, eid,
- ¤t_len);
+ if (mode == COLOCATED_LOWER_BAND)
+ eid = hostapd_eid_rnr_colocation(hapd, eid,
+ ¤t_len);
if (hapd->conf->rnr && hapd->iface->num_bss > 1 &&
!hapd->iconf->mbssid)
eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
- ¤t_len, NULL);
+ ¤t_len, NULL, false);
break;
-
case WLAN_FC_STYPE_ACTION:
if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
- ¤t_len, NULL);
+ ¤t_len, NULL, false);
break;
-
default:
return eid_start;
}
+ /* For EMA Beacons, MLD neighbor repoting is added as part of
+ * MBSSID RNR. */
+ if (include_mld_params &&
+ (type != WLAN_FC_STYPE_BEACON ||
+ hapd->iconf->mbssid != ENHANCED_MBSSID_ENABLED))
+ eid = hostapd_eid_rnr_mlo(hapd, type, eid, ¤t_len);
+
if (eid == eid_start + 2)
return eid_start;
@@ -7900,6 +8046,11 @@
size_t known_bss_len, size_t *rnr_len)
{
size_t len = 0, bss_index = 1;
+ bool ap_mld = false;
+
+#ifdef CONFIG_IEEE80211BE
+ ap_mld = hapd->conf->mld_ap;
+#endif /* CONFIG_IEEE80211BE */
if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
(frame_type != WLAN_FC_STYPE_BEACON &&
@@ -7932,12 +8083,12 @@
*rnr_len += hostapd_eid_rnr_iface_len(
hapd, hostapd_mbssid_get_tx_bss(hapd),
- &rnr_cur_len, &skip_profiles);
+ &rnr_cur_len, &skip_profiles, ap_mld);
}
}
if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len)
- *rnr_len += hostapd_eid_rnr_len(hapd, frame_type);
+ *rnr_len += hostapd_eid_rnr_len(hapd, frame_type, false);
return len;
}
@@ -8066,7 +8217,11 @@
{
size_t bss_index = 1, cur_len = 0;
u8 elem_index = 0, *rnr_start_eid = rnr_eid;
- bool add_rnr;
+ bool add_rnr, ap_mld = false;
+
+#ifdef CONFIG_IEEE80211BE
+ ap_mld = hapd->conf->mld_ap;
+#endif /* CONFIG_IEEE80211BE */
if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
(frame_stype != WLAN_FC_STYPE_BEACON &&
@@ -8111,7 +8266,7 @@
cur_len = 0;
rnr_eid = hostapd_eid_rnr_iface(
hapd, hostapd_mbssid_get_tx_bss(hapd),
- rnr_eid, &cur_len, &skip_profiles);
+ rnr_eid, &cur_len, &skip_profiles, ap_mld);
}
}
@@ -8123,8 +8278,8 @@
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_multi_iface(hapd, rnr_eid,
- &cur_len);
+ 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 a35486d..dd4995f 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -129,11 +129,10 @@
const u8 *he_6ghz_capab);
int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
enum ieee80211_op_mode mode);
+bool hostapd_get_ht_vht_twt_responder(struct hostapd_data *hapd);
u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
-void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
- const u8 *data, size_t len, int ack);
void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
int wds);
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
@@ -148,7 +147,8 @@
u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
int hostapd_update_time_adv(struct hostapd_data *hapd);
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
-u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid,
+ u16 value);
int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
#ifdef CONFIG_SAE
@@ -227,8 +227,10 @@
u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len);
u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ext_capab_ie, size_t ext_capab_ie_len);
-size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type);
-u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type);
+size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type,
+ bool include_mld_params);
+u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type,
+ bool include_mld_params);
int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
int res, struct radius_sta *info);
size_t hostapd_eid_eht_capab_len(struct hostapd_data *hapd,
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index e723ae7..913a995 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -128,6 +128,9 @@
goto fail;
}
+ if (!radius_msg_add_msg_auth(msg))
+ goto fail;
+
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
os_strlen(buf))) {
@@ -505,7 +508,9 @@
"Found matching Access-Request for RADIUS message (id=%d)",
query->radius_id);
- if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
+ if (radius_msg_verify(
+ msg, shared_secret, shared_secret_len, req,
+ hapd->conf->radius_require_message_authenticator)) {
wpa_printf(MSG_INFO,
"Incoming RADIUS packet did not have correct authenticator - dropped");
return RADIUS_RX_INVALID_AUTHENTICATOR;
@@ -596,7 +601,8 @@
if (query->radius_psk) {
struct sta_info *sta;
- bool success = cache->accepted == HOSTAPD_ACL_ACCEPT;
+ bool success = cache->accepted == HOSTAPD_ACL_ACCEPT ||
+ cache->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT;
sta = ap_get_sta(hapd, query->addr);
if (!sta || !sta->wpa_sm) {
diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c
index 638546e..afb2e16 100644
--- a/src/ap/ieee802_11_eht.c
+++ b/src/ap/ieee802_11_eht.c
@@ -1030,7 +1030,7 @@
static int hostapd_mld_validate_assoc_info(struct hostapd_data *hapd,
struct sta_info *sta)
{
- u8 i, link_id;
+ u8 link_id;
struct mld_info *info = &sta->mld_info;
if (!ap_sta_is_mld(hapd, sta)) {
@@ -1050,31 +1050,18 @@
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
struct hostapd_data *other_hapd;
- if (!info->links[link_id].valid)
+ if (!info->links[link_id].valid || link_id == hapd->mld_link_id)
continue;
- for (i = 0; i < hapd->iface->interfaces->count; i++) {
- other_hapd = hapd->iface->interfaces->iface[i]->bss[0];
-
- if (hapd == other_hapd)
- continue;
-
- if (hostapd_is_ml_partner(hapd, other_hapd) &&
- link_id == other_hapd->mld_link_id)
- break;
- }
-
- if (i == hapd->iface->interfaces->count &&
- link_id != hapd->mld_link_id) {
+ other_hapd = hostapd_mld_get_link_bss(hapd, link_id);
+ if (!other_hapd) {
wpa_printf(MSG_DEBUG, "MLD: Invalid link ID=%u",
link_id);
return -1;
}
- if (i < hapd->iface->interfaces->count)
- os_memcpy(info->links[link_id].local_addr,
- other_hapd->own_addr,
- ETH_ALEN);
+ os_memcpy(info->links[link_id].local_addr, other_hapd->own_addr,
+ ETH_ALEN);
}
return 0;
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 85790c7..3dd3a6a 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -441,6 +441,8 @@
if (hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
*pos |= 0x40; /* Bit 78 - TWT responder */
#endif /* CONFIG_IEEE80211AX */
+ if (hostapd_get_ht_vht_twt_responder(hapd))
+ *pos |= 0x40; /* Bit 78 - TWT responder */
break;
case 10: /* Bits 80-87 */
#ifdef CONFIG_SAE
@@ -735,12 +737,14 @@
}
-u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
+u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid,
+ u16 value)
{
u8 *pos = eid;
#ifdef CONFIG_WNM_AP
- if (hapd->conf->ap_max_inactivity > 0) {
+ if (hapd->conf->ap_max_inactivity > 0 &&
+ hapd->conf->bss_max_idle) {
unsigned int val;
*pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
*pos++ = 3;
@@ -753,9 +757,13 @@
val = 1;
if (val > 65535)
val = 65535;
+ if (value)
+ val = value;
WPA_PUT_LE16(pos, val);
pos += 2;
- *pos++ = 0x00; /* TODO: Protected Keep-Alive Required */
+ /* Set the Protected Keep-Alive Required bit based on
+ * configuration */
+ *pos++ = hapd->conf->bss_max_idle == 2 ? BIT(0) : 0x00;
}
#endif /* CONFIG_WNM_AP */
@@ -1089,7 +1097,7 @@
{
u8 *pos = eid;
bool sae_pk = false;
- u16 capab = 0;
+ u32 capab = 0, tmp;
size_t flen;
if (!(hapd->conf->wpa & WPA_PROTO_RSN))
@@ -1118,18 +1126,28 @@
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP)
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
+ if (hapd->conf->ssid_protection)
+ capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION);
- flen = (capab & 0xff00) ? 2 : 1;
- if (len < 2 + flen || !capab)
+ if (!capab)
+ return eid; /* no supported extended RSN capabilities */
+ tmp = capab;
+ flen = 0;
+ while (tmp) {
+ flen++;
+ tmp >>= 8;
+ }
+
+ if (len < 2 + flen)
return eid; /* no supported extended RSN capabilities */
capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
*pos++ = WLAN_EID_RSNX;
*pos++ = flen;
- *pos++ = capab & 0x00ff;
- capab >>= 8;
- if (capab)
- *pos++ = capab;
+ while (capab) {
+ *pos++ = capab & 0xff;
+ capab >>= 8;
+ }
return pos;
}
@@ -1198,3 +1216,13 @@
return sta;
}
+
+
+bool hostapd_get_ht_vht_twt_responder(struct hostapd_data *hapd)
+{
+ return hapd->iconf->ht_vht_twt_responder &&
+ ((hapd->iconf->ieee80211n && !hapd->conf->disable_11n) ||
+ (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac)) &&
+ (hapd->iface->drv_flags2 &
+ WPA_DRIVER_FLAGS2_HT_VHT_TWT_RESPONDER);
+}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 8e98b65..f4103ac 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -767,6 +767,9 @@
goto fail;
}
+ if (!radius_msg_add_msg_auth(msg))
+ goto fail;
+
if (sm->identity &&
!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
sm->identity, sm->identity_len)) {
@@ -2039,16 +2042,7 @@
}
sta = sm->sta;
- /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
- * present when packet contains an EAP-Message attribute */
- if (hdr->code == RADIUS_CODE_ACCESS_REJECT &&
- radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
- 0) < 0 &&
- radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
- wpa_printf(MSG_DEBUG,
- "Allowing RADIUS Access-Reject without Message-Authenticator since it does not include EAP-Message");
- } else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
- req, 1)) {
+ if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 1)) {
wpa_printf(MSG_INFO,
"Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
return RADIUS_RX_INVALID_AUTHENTICATOR;
@@ -2543,12 +2537,21 @@
if (!hostapd_mld_is_first_bss(hapd)) {
struct hostapd_data *first;
- wpa_printf(MSG_DEBUG,
- "MLD: Using IEEE 802.1X state machine of the first BSS");
-
first = hostapd_mld_get_first_bss(hapd);
if (!first)
return -1;
+
+ if (!first->eapol_auth) {
+ wpa_printf(MSG_DEBUG,
+ "MLD: First BSS IEEE 802.1X state machine does not exist. Init on its behalf");
+
+ if (ieee802_1x_init(first))
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "MLD: Using IEEE 802.1X state machine of the first BSS");
+
hapd->eapol_auth = first->eapol_auth;
return 0;
}
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 32944ed..13613db 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -200,6 +200,28 @@
}
+#ifdef CONFIG_IEEE80211BE
+static void clear_wpa_sm_for_each_partner_link(struct hostapd_data *hapd,
+ struct sta_info *psta)
+{
+ struct sta_info *lsta;
+ struct hostapd_data *lhapd;
+
+ if (!ap_sta_is_mld(hapd, psta))
+ return;
+
+ for_each_mld_link(lhapd, hapd) {
+ if (lhapd == hapd)
+ continue;
+
+ lsta = ap_get_sta(lhapd, psta->addr);
+ if (lsta)
+ lsta->wpa_sm = NULL;
+ }
+}
+#endif /* CONFIG_IEEE80211BE */
+
+
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_beacon = 0;
@@ -213,6 +235,7 @@
if ((sta->flags & WLAN_STA_WDS) ||
(sta->flags & WLAN_STA_MULTI_AP &&
(hapd->conf->multi_ap & BACKHAUL_BSS) &&
+ hapd->conf->wds_sta &&
!(sta->flags & WLAN_STA_WPS)))
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
@@ -317,9 +340,17 @@
#ifdef CONFIG_IEEE80211BE
if (!ap_sta_is_mld(hapd, sta) ||
- hapd->mld_link_id == sta->mld_assoc_link_id)
+ hapd->mld_link_id == sta->mld_assoc_link_id) {
wpa_auth_sta_deinit(sta->wpa_sm);
-#else
+ /* Remove references from partner links. */
+ clear_wpa_sm_for_each_partner_link(hapd, sta);
+ }
+
+ /* Release group references in case non-association link STA is removed
+ * before association link STA */
+ if (hostapd_sta_is_link_sta(hapd, sta))
+ wpa_release_link_auth_ref(sta->wpa_sm, hapd->mld_link_id);
+#else /* CONFIG_IEEE80211BE */
wpa_auth_sta_deinit(sta->wpa_sm);
#endif /* CONFIG_IEEE80211BE */
@@ -502,6 +533,7 @@
struct sta_info *sta = timeout_ctx;
unsigned long next_time = 0;
int reason;
+ int max_inactivity = hapd->conf->ap_max_inactivity;
wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
@@ -514,6 +546,9 @@
return;
}
+ if (sta->max_idle_period)
+ max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000;
+
if ((sta->flags & WLAN_STA_ASSOC) &&
(sta->timeout_next == STA_NULLFUNC ||
sta->timeout_next == STA_DISASSOC)) {
@@ -535,7 +570,7 @@
* Anyway, try again after the next inactivity timeout,
* but do not disconnect the station now.
*/
- next_time = hapd->conf->ap_max_inactivity + fuzz;
+ next_time = max_inactivity + fuzz;
} else if (inactive_sec == -ENOENT) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Station " MACSTR " has lost its driver entry",
@@ -544,20 +579,19 @@
/* Avoid sending client probe on removed client */
sta->timeout_next = STA_DISASSOC;
goto skip_poll;
- } else if (inactive_sec < hapd->conf->ap_max_inactivity) {
+ } else if (inactive_sec < max_inactivity) {
/* station activity detected; reset timeout state */
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Station " MACSTR " has been active %is ago",
MAC2STR(sta->addr), inactive_sec);
sta->timeout_next = STA_NULLFUNC;
- next_time = hapd->conf->ap_max_inactivity + fuzz -
- inactive_sec;
+ next_time = max_inactivity + fuzz - inactive_sec;
} else {
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Station " MACSTR " has been "
"inactive too long: %d sec, max allowed: %d",
MAC2STR(sta->addr), inactive_sec,
- hapd->conf->ap_max_inactivity);
+ max_inactivity);
if (hapd->conf->skip_inactivity_poll)
sta->timeout_next = STA_DISASSOC;
@@ -573,7 +607,7 @@
/* data nullfunc frame poll did not produce TX errors; assume
* station ACKed it */
sta->timeout_next = STA_NULLFUNC;
- next_time = hapd->conf->ap_max_inactivity;
+ next_time = max_inactivity;
}
skip_poll:
@@ -761,6 +795,7 @@
{
struct sta_info *sta;
int i;
+ int max_inactivity = hapd->conf->ap_max_inactivity;
sta = ap_get_sta(hapd, addr);
if (sta)
@@ -794,12 +829,15 @@
}
sta->supported_rates_len = i;
+ if (sta->max_idle_period)
+ max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000;
+
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%d seconds - ap_max_inactivity)",
__func__, MAC2STR(addr),
- hapd->conf->ap_max_inactivity);
- eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
+ max_inactivity);
+ eloop_register_timeout(max_inactivity, 0,
ap_handle_timer, hapd, sta);
}
@@ -903,9 +941,11 @@
ieee802_1x_free_station(hapd, sta);
#ifdef CONFIG_IEEE80211BE
if (!hapd->conf->mld_ap ||
- hapd->mld_link_id == sta->mld_assoc_link_id)
+ hapd->mld_link_id == sta->mld_assoc_link_id) {
wpa_auth_sta_deinit(sta->wpa_sm);
-#else
+ clear_wpa_sm_for_each_partner_link(hapd, sta);
+ }
+#else /* CONFIG_IEEE80211BE */
wpa_auth_sta_deinit(sta->wpa_sm);
#endif /* CONFIG_IEEE80211BE */
@@ -1761,10 +1801,8 @@
struct sta_info *sta)
{
struct hostapd_data *tmp_hapd;
- unsigned int i, j;
- for_each_mld_link(tmp_hapd, i, j, hapd->iface->interfaces,
- hostapd_get_mld_id(hapd)) {
+ for_each_mld_link(tmp_hapd, hapd) {
struct sta_info *tmp_sta;
if (hapd == tmp_hapd)
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 153e4a0..8462935 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -94,8 +94,6 @@
u16 status;
u16 resp_sta_profile_len;
u8 *resp_sta_profile;
-
- const u8 *rsne, *rsnxe;
} links[MAX_NUM_MLD_LINKS];
};
@@ -334,6 +332,9 @@
struct mld_info mld_info;
u8 mld_assoc_link_id;
#endif /* CONFIG_IEEE80211BE */
+
+ u16 max_idle_period; /* if nonzero, the granted BSS max idle period in
+ * units of 1000 TUs */
};
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 4bf8d79..bbf41d3 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -62,7 +62,7 @@
const u8 *pmk, unsigned int pmk_len,
struct wpa_ptk *ptk, int force_sha256,
u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
- size_t *key_len);
+ size_t *key_len, bool no_kdk);
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
@@ -71,6 +71,9 @@
struct wpa_group *group);
static int ieee80211w_kde_len(struct wpa_state_machine *sm);
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
+static void wpa_group_update_gtk(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group);
+
static const u32 eapol_key_timeout_first = 100; /* ms */
static const u32 eapol_key_timeout_subseq = 1000; /* ms */
@@ -87,7 +90,7 @@
{
#ifdef CONFIG_IEEE80211BE
if (sm->mld_assoc_link_id >= 0)
- return sm->own_mld_addr;
+ return sm->wpa_auth->mld_addr;
#endif /* CONFIG_IEEE80211BE */
return sm->wpa_auth->addr;
}
@@ -103,6 +106,125 @@
}
+static void wpa_gkeydone_sta(struct wpa_state_machine *sm)
+{
+#ifdef CONFIG_IEEE80211BE
+ int link_id;
+#endif /* CONFIG_IEEE80211BE */
+
+ if (!sm->wpa_auth)
+ return;
+
+ sm->wpa_auth->group->GKeyDoneStations--;
+ sm->GUpdateStationKeys = false;
+
+#ifdef CONFIG_IEEE80211BE
+ for_each_sm_auth(sm, link_id)
+ sm->mld_links[link_id].wpa_auth->group->GKeyDoneStations--;
+#endif /* CONFIG_IEEE80211BE */
+}
+
+
+#ifdef CONFIG_IEEE80211BE
+
+void wpa_release_link_auth_ref(struct wpa_state_machine *sm,
+ int release_link_id)
+{
+ int link_id;
+
+ if (!sm || release_link_id >= MAX_NUM_MLD_LINKS)
+ return;
+
+ for_each_sm_auth(sm, link_id) {
+ if (link_id == release_link_id) {
+ wpa_group_put(sm->mld_links[link_id].wpa_auth,
+ sm->mld_links[link_id].wpa_auth->group);
+ sm->mld_links[link_id].wpa_auth = NULL;
+ }
+ }
+}
+
+
+struct wpa_get_link_auth_ctx {
+ const u8 *addr;
+ const u8 *mld_addr;
+ int link_id;
+ struct wpa_authenticator *wpa_auth;
+};
+
+static int wpa_get_link_sta_auth(struct wpa_authenticator *wpa_auth, void *data)
+{
+ struct wpa_get_link_auth_ctx *ctx = data;
+
+ if (!wpa_auth->is_ml)
+ return 0;
+
+ if (ctx->mld_addr &&
+ !ether_addr_equal(wpa_auth->mld_addr, ctx->mld_addr))
+ return 0;
+
+ if ((ctx->addr && ether_addr_equal(wpa_auth->addr, ctx->addr)) ||
+ (ctx->link_id > -1 && wpa_auth->is_ml &&
+ wpa_auth->link_id == ctx->link_id)) {
+ ctx->wpa_auth = wpa_auth;
+ return 1;
+
+ }
+ return 0;
+}
+
+
+static struct wpa_authenticator *
+wpa_get_link_auth(struct wpa_authenticator *wpa_auth, int link_id)
+{
+ struct wpa_get_link_auth_ctx ctx;
+
+ ctx.addr = NULL;
+ ctx.mld_addr = wpa_auth->mld_addr;
+ ctx.link_id = link_id;
+ ctx.wpa_auth = NULL;
+ wpa_auth_for_each_auth(wpa_auth, wpa_get_link_sta_auth, &ctx);
+ return ctx.wpa_auth;
+}
+
+
+static int wpa_get_primary_auth_cb(struct wpa_authenticator *wpa_auth,
+ void *data)
+{
+ struct wpa_get_link_auth_ctx *ctx = data;
+
+ if (!wpa_auth->is_ml ||
+ !ether_addr_equal(wpa_auth->mld_addr, ctx->addr) ||
+ !wpa_auth->primary_auth)
+ return 0;
+
+ ctx->wpa_auth = wpa_auth;
+ return 1;
+}
+
+#endif /* CONFIG_IEEE80211BE */
+
+
+static struct wpa_authenticator *
+wpa_get_primary_auth(struct wpa_authenticator *wpa_auth)
+{
+#ifdef CONFIG_IEEE80211BE
+ struct wpa_get_link_auth_ctx ctx;
+
+ if (!wpa_auth || !wpa_auth->is_ml || wpa_auth->primary_auth)
+ return wpa_auth;
+
+ ctx.addr = wpa_auth->mld_addr;
+ ctx.wpa_auth = NULL;
+ wpa_auth_for_each_auth(wpa_auth, wpa_get_primary_auth_cb, &ctx);
+
+ return ctx.wpa_auth;
+#else /* CONFIG_IEEE80211BE */
+ return wpa_auth;
+#endif /* CONFIG_IEEE80211BE */
+}
+
+
static inline int wpa_auth_mic_failure_report(
struct wpa_authenticator *wpa_auth, const u8 *addr)
{
@@ -372,14 +494,16 @@
}
-static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
+static void wpa_rekey_all_groups(struct wpa_authenticator *wpa_auth)
{
- struct wpa_authenticator *wpa_auth = eloop_ctx;
struct wpa_group *group, *next;
wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
group = wpa_auth->group;
while (group) {
+ wpa_printf(MSG_DEBUG, "GTK rekey start for authenticator ("
+ MACSTR "), group vlan %d",
+ MAC2STR(wpa_auth->addr), group->vlan_id);
wpa_group_get(wpa_auth, group);
group->GTKReKey = true;
@@ -392,6 +516,83 @@
wpa_group_put(wpa_auth, group);
group = next;
}
+}
+
+
+#ifdef CONFIG_IEEE80211BE
+
+static void wpa_update_all_gtks(struct wpa_authenticator *wpa_auth)
+{
+ struct wpa_group *group, *next;
+
+ group = wpa_auth->group;
+ while (group) {
+ wpa_group_get(wpa_auth, group);
+
+ wpa_group_update_gtk(wpa_auth, group);
+ next = group->next;
+ wpa_group_put(wpa_auth, group);
+ group = next;
+ }
+}
+
+
+static int wpa_update_all_gtks_cb(struct wpa_authenticator *wpa_auth, void *ctx)
+{
+ const u8 *mld_addr = ctx;
+
+ if (!ether_addr_equal(wpa_auth->mld_addr, mld_addr))
+ return 0;
+
+ wpa_update_all_gtks(wpa_auth);
+ return 0;
+}
+
+
+static int wpa_rekey_all_groups_cb(struct wpa_authenticator *wpa_auth,
+ void *ctx)
+{
+ const u8 *mld_addr = ctx;
+
+ if (!ether_addr_equal(wpa_auth->mld_addr, mld_addr))
+ return 0;
+
+ wpa_rekey_all_groups(wpa_auth);
+ return 0;
+}
+
+#endif /* CONFIG_IEEE80211BE */
+
+
+static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_authenticator *wpa_auth = eloop_ctx;
+
+#ifdef CONFIG_IEEE80211BE
+ if (wpa_auth->is_ml) {
+ /* Non-primary ML authenticator eloop timer for group rekey is
+ * never started and shouldn't fire. Check and warn just in
+ * case. */
+ if (!wpa_auth->primary_auth) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Cannot start GTK rekey on non-primary ML authenticator");
+ return;
+ }
+
+ /* Generate all the new group keys */
+ wpa_auth_for_each_auth(wpa_auth, wpa_update_all_gtks_cb,
+ wpa_auth->mld_addr);
+
+ /* Send all the generated group keys to the respective stations
+ * with group key handshake. */
+ wpa_auth_for_each_auth(wpa_auth, wpa_rekey_all_groups_cb,
+ wpa_auth->mld_addr);
+ } else {
+ wpa_rekey_all_groups(wpa_auth);
+ }
+#else /* CONFIG_IEEE80211BE */
+ wpa_rekey_all_groups(wpa_auth);
+#endif /* CONFIG_IEEE80211BE */
if (wpa_auth->conf.wpa_group_rekey) {
eloop_register_timeout(wpa_auth->conf.wpa_group_rekey,
@@ -541,8 +742,19 @@
wpa_auth = os_zalloc(sizeof(struct wpa_authenticator));
if (!wpa_auth)
return NULL;
+
os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
+
+#ifdef CONFIG_IEEE80211BE
+ if (conf->mld_addr) {
+ wpa_auth->is_ml = true;
+ wpa_auth->link_id = conf->link_id;
+ wpa_auth->primary_auth = !conf->first_link_auth;
+ os_memcpy(wpa_auth->mld_addr, conf->mld_addr, ETH_ALEN);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
wpa_auth->cb = cb;
wpa_auth->cb_ctx = cb_ctx;
@@ -586,7 +798,15 @@
wpa_rekey_gmk, wpa_auth, NULL);
}
+#ifdef CONFIG_IEEE80211BE
+ /* For AP MLD, run group rekey timer only on one link (first) and
+ * whenever it fires do rekey on all associated ML links in one shot.
+ */
+ if ((!wpa_auth->is_ml || !conf->first_link_auth) &&
+ wpa_auth->conf.wpa_group_rekey) {
+#else /* CONFIG_IEEE80211BE */
if (wpa_auth->conf.wpa_group_rekey) {
+#endif /* CONFIG_IEEE80211BE */
eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, 0,
wpa_rekey_gtk, wpa_auth, NULL);
}
@@ -650,6 +870,9 @@
struct wpa_group *group, *prev;
eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL);
+
+ /* TODO: Assign ML primary authenticator to next link authenticator and
+ * start rekey timer. */
eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
pmksa_cache_auth_deinit(wpa_auth->pmksa);
@@ -666,6 +889,9 @@
os_free(wpa_auth->wpa_ie);
+ os_free(wpa_auth->rsne_override);
+ os_free(wpa_auth->rsne_override_2);
+ os_free(wpa_auth->rsnxe_override);
group = wpa_auth->group;
while (group) {
@@ -802,6 +1028,10 @@
static void wpa_free_sta_sm(struct wpa_state_machine *sm)
{
+#ifdef CONFIG_IEEE80211BE
+ int link_id;
+#endif /* CONFIG_IEEE80211BE */
+
#ifdef CONFIG_P2P
if (WPA_GET_BE32(sm->ip_addr)) {
wpa_printf(MSG_DEBUG,
@@ -814,10 +1044,8 @@
bitfield_clear(sm->wpa_auth->ip_pool, sm->ip_addr_bit);
}
#endif /* CONFIG_P2P */
- if (sm->GUpdateStationKeys) {
- sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = false;
- }
+ if (sm->GUpdateStationKeys)
+ wpa_gkeydone_sta(sm);
#ifdef CONFIG_IEEE80211R_AP
os_free(sm->assoc_resp_ftie);
wpabuf_free(sm->ft_pending_req_ies);
@@ -825,6 +1053,13 @@
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
os_free(sm->rsnxe);
+#ifdef CONFIG_IEEE80211BE
+ for_each_sm_auth(sm, link_id) {
+ wpa_group_put(sm->mld_links[link_id].wpa_auth,
+ sm->mld_links[link_id].wpa_auth->group);
+ sm->mld_links[link_id].wpa_auth = NULL;
+ }
+#endif /* CONFIG_IEEE80211BE */
wpa_group_put(sm->wpa_auth, sm->group);
#ifdef CONFIG_DPP2
wpabuf_clear_free(sm->dpp_z);
@@ -842,12 +1077,20 @@
wpa_auth = sm->wpa_auth;
if (wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
+ struct wpa_authenticator *primary_auth = wpa_auth;
+
wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"strict rekeying - force GTK rekey since STA is leaving");
+
+#ifdef CONFIG_IEEE80211BE
+ if (wpa_auth->is_ml && !wpa_auth->primary_auth)
+ primary_auth = wpa_get_primary_auth(wpa_auth);
+#endif /* CONFIG_IEEE80211BE */
+
if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk,
- wpa_auth, NULL) == -1)
+ primary_auth, NULL) == -1)
eloop_register_timeout(0, 500000, wpa_rekey_gtk,
- wpa_auth, NULL);
+ primary_auth, NULL);
}
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
@@ -1087,7 +1330,8 @@
}
if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0,
- pmk_r0, pmk_r1, pmk_r0_name, &key_len) < 0)
+ pmk_r0, pmk_r1, pmk_r0_name, &key_len,
+ false) < 0)
break;
if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
@@ -1601,12 +1845,16 @@
wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
LOGGER_INFO,
"received EAPOL-Key Request for GTK rekeying");
- eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
+
+ eloop_cancel_timeout(wpa_rekey_gtk,
+ wpa_get_primary_auth(wpa_auth),
+ NULL);
if (wpa_auth_gtk_rekey_in_process(wpa_auth))
wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG,
"skip new GTK rekey - already in process");
else
- wpa_rekey_gtk(wpa_auth, NULL);
+ wpa_rekey_gtk(wpa_get_primary_auth(wpa_auth),
+ NULL);
}
} else {
/* Do not allow the same key replay counter to be reused. */
@@ -2144,8 +2392,7 @@
* Reauthentication cancels the pending group key
* update for this STA.
*/
- sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = false;
+ wpa_gkeydone_sta(sm);
sm->PtkGroupInit = true;
}
sm->ReAuthenticationRequest = true;
@@ -2221,8 +2468,7 @@
sm->keycount = 0;
if (sm->GUpdateStationKeys)
- sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = false;
+ wpa_gkeydone_sta(sm);
if (sm->wpa == WPA_VERSION_WPA)
sm->PInitAKeys = false;
if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and
@@ -2600,7 +2846,7 @@
"RSN: MLD: Add MAC Address KDE: kde_len=%zu",
kde_len);
wpa_add_kde(buf + kde_len, RSN_KEY_DATA_MAC_ADDR,
- sm->own_mld_addr, ETH_ALEN, NULL, 0);
+ sm->wpa_auth->mld_addr, ETH_ALEN, NULL, 0);
kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN;
}
#endif /* CONFIG_IEEE80211BE */
@@ -2626,7 +2872,7 @@
const u8 *pmk, unsigned int pmk_len,
struct wpa_ptk *ptk, int force_sha256,
u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
- size_t *key_len)
+ size_t *key_len, bool no_kdk)
{
const u8 *z = NULL;
size_t z_len = 0, kdk_len;
@@ -2634,7 +2880,7 @@
int ret;
if (sm->wpa_auth->conf.force_kdk_derivation ||
- (sm->wpa_auth->conf.secure_ltf &&
+ (!no_kdk && sm->wpa_auth->conf.secure_ltf &&
ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)))
kdk_len = WPA_KDK_MAX_LEN;
else
@@ -2663,7 +2909,7 @@
}
#ifdef CONFIG_PASN
- if (sm->wpa_auth->conf.secure_ltf &&
+ if (!no_kdk && sm->wpa_auth->conf.secure_ltf &&
ieee802_11_rsnx_capab(sm->rsnxe,
WLAN_RSNX_CAPAB_SECURE_LTF)) {
ret = wpa_ltf_keyseed(ptk, sm->wpa_key_mgmt,
@@ -2699,7 +2945,7 @@
}
#ifdef CONFIG_PASN
- if (sm->wpa_auth->conf.secure_ltf &&
+ if (!no_kdk && sm->wpa_auth->conf.secure_ltf &&
ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)) {
ret = wpa_ltf_keyseed(ptk, sm->wpa_key_mgmt, sm->pairwise);
if (ret) {
@@ -3410,6 +3656,7 @@
size_t key_len;
u8 *key_data_buf = NULL;
size_t key_data_buf_len = 0;
+ bool derive_kdk, no_kdk = false;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
sm->EAPOLKeyReceived = false;
@@ -3418,6 +3665,9 @@
mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
+ derive_kdk = sm->wpa_auth->conf.secure_ltf &&
+ ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF);
+
/* WPA with IEEE 802.1X: use the derived PMK from EAP
* WPA-PSK: iterate through possible PSKs and select the one matching
* the packet */
@@ -3447,9 +3697,11 @@
pmk_len = sm->pmksa->pmk_len;
}
+ no_kdk = false;
+ try_without_kdk:
if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK,
owe_ptk_workaround == 2, pmk_r0, pmk_r1,
- pmk_r0_name, &key_len) < 0)
+ pmk_r0_name, &key_len, no_kdk) < 0)
break;
if (mic_len &&
@@ -3483,11 +3735,31 @@
}
#endif /* CONFIG_OWE */
+ /* Some deployed STAs that advertise SecureLTF support in the
+ * RSNXE in (Re)Association Request frames, do not derive KDK
+ * during PTK generation. Try to work around this by checking if
+ * a PTK derived without KDK would result in a matching MIC. */
+ if (!sm->wpa_auth->conf.force_kdk_derivation &&
+ derive_kdk && !no_kdk) {
+ wpa_printf(MSG_DEBUG,
+ "Try new PTK derivation without KDK as a workaround");
+ no_kdk = true;
+ goto try_without_kdk;
+ }
+
if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
wpa_key_mgmt_sae(sm->wpa_key_mgmt))
break;
}
+ if (no_kdk && ok) {
+ /* The workaround worked, so allow the 4-way handshake to be
+ * completed with the PTK that was derived without the KDK. */
+ wpa_printf(MSG_DEBUG,
+ "PTK without KDK worked - misbehaving STA "
+ MACSTR, MAC2STR(sm->addr));
+ }
+
if (!ok && wpa_key_mgmt_wpa_psk_no_sae(sm->wpa_key_mgmt) &&
wpa_auth->conf.radius_psk && wpa_auth->cb->request_radius_psk &&
!sm->waiting_radius_psk) {
@@ -3915,27 +4187,6 @@
#ifdef CONFIG_IEEE80211BE
-void wpa_auth_ml_get_rsn_info(struct wpa_authenticator *a,
- struct wpa_auth_ml_link_rsn_info *info)
-{
- info->rsn_ies = a->wpa_ie;
- info->rsn_ies_len = a->wpa_ie_len;
-
- wpa_printf(MSG_DEBUG, "RSN: MLD: link_id=%u, rsn_ies_len=%zu",
- info->link_id, info->rsn_ies_len);
-}
-
-
-static void wpa_auth_get_ml_rsn_info(struct wpa_authenticator *wpa_auth,
- struct wpa_auth_ml_rsn_info *info)
-{
- if (!wpa_auth->cb->get_ml_rsn_info)
- return;
-
- wpa_auth->cb->get_ml_rsn_info(wpa_auth->cb_ctx, info);
-}
-
-
void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
struct wpa_auth_ml_link_key_info *info,
bool mgmt_frame_prot, bool beacon_prot)
@@ -3998,38 +4249,47 @@
static size_t wpa_auth_ml_group_kdes_len(struct wpa_state_machine *sm)
{
- struct wpa_authenticator *wpa_auth = sm->wpa_auth;
- struct wpa_group *gsm = sm->group;
- size_t gtk_len = gsm->GTK_len;
- size_t igtk_len;
- size_t kde_len;
- unsigned int n_links;
+ struct wpa_authenticator *wpa_auth;
+ size_t kde_len = 0;
+ int link_id;
if (sm->mld_assoc_link_id < 0)
return 0;
- n_links = sm->n_mld_affiliated_links + 1;
+ for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
+ if (!sm->mld_links[link_id].valid)
+ continue;
- /* MLO GTK KDE for each link */
- kde_len = n_links * (2 + RSN_SELECTOR_LEN + 1 + 6 + gtk_len);
+ wpa_auth = sm->mld_links[link_id].wpa_auth;
+ if (!wpa_auth || !wpa_auth->group)
+ continue;
- if (!sm->mgmt_frame_prot)
- return kde_len;
+ /* MLO GTK KDE
+ * Header + Key ID + Tx + LinkID + PN + GTK */
+ kde_len += KDE_HDR_LEN + 1 + RSN_PN_LEN;
+ kde_len += wpa_auth->group->GTK_len;
- /* MLO IGTK KDE for each link */
- igtk_len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
- kde_len += n_links * (2 + RSN_SELECTOR_LEN + 2 + 6 + 1 + igtk_len);
+ if (!sm->mgmt_frame_prot)
+ continue;
- if (wpa_auth->conf.tx_bss_auth) {
- wpa_auth = wpa_auth->conf.tx_bss_auth;
- igtk_len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+ if (wpa_auth->conf.tx_bss_auth)
+ wpa_auth = wpa_auth->conf.tx_bss_auth;
+
+ /* MLO IGTK KDE
+ * Header + Key ID + IPN + LinkID + IGTK */
+ kde_len += KDE_HDR_LEN + WPA_IGTK_KDE_PREFIX_LEN + 1;
+ kde_len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+
+ if (!wpa_auth->conf.beacon_prot)
+ continue;
+
+ /* MLO BIGTK KDE
+ * Header + Key ID + BIPN + LinkID + BIGTK */
+ kde_len += KDE_HDR_LEN + WPA_BIGTK_KDE_PREFIX_LEN + 1;
+ kde_len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
}
- if (!wpa_auth->conf.beacon_prot)
- return kde_len;
-
- /* MLO BIGTK KDE for each link */
- kde_len += n_links * (2 + RSN_SELECTOR_LEN + 2 + 6 + 1 + igtk_len);
+ wpa_printf(MSG_DEBUG, "MLO Group KDEs len = %zu", kde_len);
return kde_len;
}
@@ -4039,6 +4299,7 @@
{
struct wpa_auth_ml_key_info ml_key_info;
unsigned int i, link_id;
+ u8 *start = pos;
/* First fetch the key information from all the authenticators */
os_memset(&ml_key_info, 0, sizeof(ml_key_info));
@@ -4090,8 +4351,11 @@
i++;
}
- if (!sm->mgmt_frame_prot)
+ if (!sm->mgmt_frame_prot) {
+ wpa_printf(MSG_DEBUG, "RSN: MLO Group KDE len = %ld",
+ pos - start);
return pos;
+ }
/* Add MLO IGTK KDEs */
for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
@@ -4130,8 +4394,11 @@
i++;
}
- if (!sm->wpa_auth->conf.beacon_prot)
+ if (!sm->wpa_auth->conf.beacon_prot) {
+ wpa_printf(MSG_DEBUG, "RSN: MLO Group KDE len = %ld",
+ pos - start);
return pos;
+ }
/* Add MLO BIGTK KDEs */
for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
@@ -4171,6 +4438,7 @@
i++;
}
+ wpa_printf(MSG_DEBUG, "RSN: MLO Group KDE len = %ld", pos - start);
return pos;
}
@@ -4192,12 +4460,33 @@
/* MLO Link KDE for each link */
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
- if (!sm->mld_links[link_id].valid)
+ struct wpa_authenticator *wpa_auth;
+ const u8 *ie, *ieo;
+
+ wpa_auth = wpa_get_link_auth(sm->wpa_auth, link_id);
+ if (!wpa_auth)
continue;
- kde_len += 2 + RSN_SELECTOR_LEN + 1 + ETH_ALEN +
- sm->mld_links[link_id].rsne_len +
- sm->mld_links[link_id].rsnxe_len;
+ kde_len += 2 + RSN_SELECTOR_LEN + 1 + ETH_ALEN;
+ ie = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
+ WLAN_EID_RSN);
+ ieo = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
+ sm->rsn_override_2 ?
+ RSNE_OVERRIDE_2_IE_VENDOR_TYPE :
+ RSNE_OVERRIDE_IE_VENDOR_TYPE);
+ if ((sm->rsn_override || sm->rsn_override_2) && ieo)
+ kde_len += 2 + ieo[1 - 4];
+ else
+ kde_len += 2 + ie[1];
+
+ ie = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
+ WLAN_EID_RSNX);
+ ieo = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
+ RSNXE_OVERRIDE_IE_VENDOR_TYPE);
+ if ((sm->rsn_override || sm->rsn_override_2) && ieo)
+ kde_len += 2 + ieo[1] - 4;
+ else if (ie)
+ kde_len += 2 + ie[1];
}
kde_len += wpa_auth_ml_group_kdes_len(sm);
@@ -4211,56 +4500,95 @@
{
#ifdef CONFIG_IEEE80211BE
u8 link_id;
+ u8 *start = pos;
if (sm->mld_assoc_link_id < 0)
return pos;
wpa_printf(MSG_DEBUG, "RSN: MLD: Adding MAC Address KDE");
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR,
- sm->own_mld_addr, ETH_ALEN, NULL, 0);
+ sm->wpa_auth->mld_addr, ETH_ALEN, NULL, 0);
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
- if (!sm->mld_links[link_id].valid)
+ struct wpa_authenticator *wpa_auth;
+ const u8 *rsne, *rsnxe, *rsneo, *rsnxeo;
+ size_t rsne_len, rsnxe_len;
+
+ wpa_auth = wpa_get_link_auth(sm->wpa_auth, link_id);
+ if (!wpa_auth)
continue;
+ rsne = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
+ WLAN_EID_RSN);
+ rsne_len = rsne ? 2 + rsne[1] : 0;
+ rsneo = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
+ sm->rsn_override_2 ?
+ RSNE_OVERRIDE_2_IE_VENDOR_TYPE :
+ RSNE_OVERRIDE_IE_VENDOR_TYPE);
+ if ((sm->rsn_override || sm->rsn_override_2) && rsneo)
+ rsne_len = 2 + rsneo[1] - 4;
+ else
+ rsneo = NULL;
+
+ rsnxe = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
+ WLAN_EID_RSNX);
+ rsnxe_len = rsnxe ? 2 + rsnxe[1] : 0;
+ rsnxeo = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
+ RSNXE_OVERRIDE_IE_VENDOR_TYPE);
+ if ((sm->rsn_override || sm->rsn_override_2) && rsnxeo)
+ rsnxe_len = 2 + rsnxeo[1] - 4;
+ else
+ rsnxeo = NULL;
+
wpa_printf(MSG_DEBUG,
"RSN: MLO Link: link=%u, len=%zu", link_id,
RSN_SELECTOR_LEN + 1 + ETH_ALEN +
- sm->mld_links[link_id].rsne_len +
- sm->mld_links[link_id].rsnxe_len);
+ rsne_len + rsnxe_len);
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
*pos++ = RSN_SELECTOR_LEN + 1 + ETH_ALEN +
- sm->mld_links[link_id].rsne_len +
- sm->mld_links[link_id].rsnxe_len;
+ rsne_len + rsnxe_len;
RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_MLO_LINK);
pos += RSN_SELECTOR_LEN;
/* Add the Link Information */
*pos = link_id;
- if (sm->mld_links[link_id].rsne_len)
+ if (rsne_len)
*pos |= RSN_MLO_LINK_KDE_LI_RSNE_INFO;
- if (sm->mld_links[link_id].rsnxe_len)
+ if (rsnxe_len)
*pos |= RSN_MLO_LINK_KDE_LI_RSNXE_INFO;
pos++;
- os_memcpy(pos, sm->mld_links[link_id].own_addr, ETH_ALEN);
+ os_memcpy(pos, wpa_auth->addr, ETH_ALEN);
pos += ETH_ALEN;
- if (sm->mld_links[link_id].rsne_len) {
- os_memcpy(pos, sm->mld_links[link_id].rsne,
- sm->mld_links[link_id].rsne_len);
- pos += sm->mld_links[link_id].rsne_len;
+ if (rsne_len) {
+ if (rsneo) {
+ *pos++ = WLAN_EID_RSN;
+ *pos++ = rsneo[1] - 4;
+ os_memcpy(pos, &rsneo[2 + 4], rsneo[1] - 4);
+ pos += rsneo[1] - 4;
+ } else {
+ os_memcpy(pos, rsne, rsne_len);
+ pos += rsne_len;
+ }
}
- if (sm->mld_links[link_id].rsnxe_len) {
- os_memcpy(pos, sm->mld_links[link_id].rsnxe,
- sm->mld_links[link_id].rsnxe_len);
- pos += sm->mld_links[link_id].rsnxe_len;
+ if (rsnxe_len) {
+ if (rsnxeo) {
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = rsnxeo[1] - 4;
+ os_memcpy(pos, &rsnxeo[2 + 4], rsnxeo[1] - 4);
+ pos += rsnxeo[1] - 4;
+ } else {
+ os_memcpy(pos, rsnxe, rsnxe_len);
+ pos += rsnxe_len;
+ }
}
}
+ wpa_printf(MSG_DEBUG, "RSN: MLO Link KDE len = %ld", pos - start);
pos = wpa_auth_ml_group_kdes(sm, pos);
#endif /* CONFIG_IEEE80211BE */
@@ -4275,7 +4603,7 @@
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
int secure, gtkidx, encr = 0;
- u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL;
+ u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL, *wpa_ie_buf3 = NULL;
u8 hdr[2];
struct wpa_auth_config *conf = &sm->wpa_auth->conf;
#ifdef CONFIG_IEEE80211BE
@@ -4316,6 +4644,80 @@
wpa_ie = wpa_ie + wpa_ie[1] + 2;
wpa_ie_len = wpa_ie[1] + 2;
}
+ if ((sm->rsn_override &&
+ get_vendor_ie(wpa_ie, wpa_ie_len, RSNE_OVERRIDE_IE_VENDOR_TYPE)) ||
+ (sm->rsn_override_2 &&
+ get_vendor_ie(wpa_ie, wpa_ie_len,
+ RSNE_OVERRIDE_2_IE_VENDOR_TYPE))) {
+ const u8 *mde, *fte, *tie, *tie2 = NULL;
+ const u8 *override_rsne = NULL, *override_rsnxe = NULL;
+ const struct element *elem;
+
+ wpa_printf(MSG_DEBUG,
+ "RSN: Use RSNE/RSNXE override element contents");
+ mde = get_ie(wpa_ie, wpa_ie_len, WLAN_EID_MOBILITY_DOMAIN);
+ fte = get_ie(wpa_ie, wpa_ie_len, WLAN_EID_FAST_BSS_TRANSITION);
+ tie = get_ie(wpa_ie, wpa_ie_len, WLAN_EID_TIMEOUT_INTERVAL);
+ if (tie) {
+ const u8 *next = tie + 2 + tie[1];
+
+ tie2 = get_ie(next, wpa_ie + wpa_ie_len - next,
+ WLAN_EID_TIMEOUT_INTERVAL);
+ }
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC,
+ wpa_ie, wpa_ie_len) {
+ if (elem->datalen >= 4) {
+ if (WPA_GET_BE32(elem->data) ==
+ (sm->rsn_override_2 ?
+ RSNE_OVERRIDE_2_IE_VENDOR_TYPE :
+ RSNE_OVERRIDE_IE_VENDOR_TYPE))
+ override_rsne = &elem->id;
+ if (WPA_GET_BE32(elem->data) ==
+ RSNXE_OVERRIDE_IE_VENDOR_TYPE)
+ override_rsnxe = &elem->id;
+ }
+ }
+ wpa_hexdump(MSG_DEBUG, "EAPOL-Key msg 3/4 IEs before edits",
+ wpa_ie, wpa_ie_len);
+ wpa_ie_buf3 = os_malloc(wpa_ie_len);
+ if (!wpa_ie_buf3)
+ goto done;
+ pos = wpa_ie_buf3;
+ if (override_rsne) {
+ *pos++ = WLAN_EID_RSN;
+ *pos++ = override_rsne[1] - 4;
+ os_memcpy(pos, &override_rsne[2 + 4],
+ override_rsne[1] - 4);
+ pos += override_rsne[1] - 4;
+ }
+ if (mde) {
+ os_memcpy(pos, mde, 2 + mde[1]);
+ pos += 2 + mde[1];
+ }
+ if (fte) {
+ os_memcpy(pos, fte, 2 + fte[1]);
+ pos += 2 + fte[1];
+ }
+ if (tie) {
+ os_memcpy(pos, tie, 2 + tie[1]);
+ pos += 2 + tie[1];
+ }
+ if (tie2) {
+ os_memcpy(pos, tie2, 2 + tie2[1]);
+ pos += 2 + tie2[1];
+ }
+ if (override_rsnxe) {
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = override_rsnxe[1] - 4;
+ os_memcpy(pos, &override_rsnxe[2 + 4],
+ override_rsnxe[1] - 4);
+ pos += override_rsnxe[1] - 4;
+ }
+ wpa_ie = wpa_ie_buf3;
+ wpa_ie_len = pos - wpa_ie_buf3;
+ wpa_hexdump(MSG_DEBUG, "EAPOL-Key msg 3/4 IEs after edits",
+ wpa_ie, wpa_ie_len);
+ }
#ifdef CONFIG_TESTING_OPTIONS
if (conf->rsne_override_eapol_set) {
wpa_ie_buf2 = replace_ie(
@@ -4434,6 +4836,9 @@
kde_len += wpa_auth_ml_kdes_len(sm);
+ if (sm->ssid_protection)
+ kde_len += 2 + conf->ssid_len;
+
#ifdef CONFIG_TESTING_OPTIONS
if (conf->eapol_m3_elements)
kde_len += wpabuf_len(conf->eapol_m3_elements);
@@ -4553,6 +4958,13 @@
pos = wpa_auth_ml_kdes(sm, pos);
+ if (sm->ssid_protection) {
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = conf->ssid_len;
+ os_memcpy(pos, conf->ssid, conf->ssid_len);
+ pos += conf->ssid_len;
+ }
+
#ifdef CONFIG_TESTING_OPTIONS
if (conf->eapol_m3_elements) {
os_memcpy(pos, wpabuf_head(conf->eapol_m3_elements),
@@ -4575,6 +4987,7 @@
bin_clear_free(kde, kde_len);
os_free(wpa_ie_buf);
os_free(wpa_ie_buf2);
+ os_free(wpa_ie_buf3);
}
@@ -5043,8 +5456,7 @@
#endif /* CONFIG_OCV */
if (sm->GUpdateStationKeys)
- sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = false;
+ wpa_gkeydone_sta(sm);
sm->GTimeoutCtr = 0;
/* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */
wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
@@ -5058,8 +5470,15 @@
{
SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group);
if (sm->GUpdateStationKeys)
- sm->group->GKeyDoneStations--;
- sm->GUpdateStationKeys = false;
+ wpa_gkeydone_sta(sm);
+ if (sm->wpa_auth->conf.no_disconnect_on_group_keyerror &&
+ sm->wpa == WPA_VERSION_WPA2) {
+ wpa_auth_vlogger(sm->wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_DEBUG,
+ "group key handshake failed after %u tries - allow STA to remain connected",
+ sm->wpa_auth->conf.wpa_group_update_count);
+ return;
+ }
sm->Disconnect = true;
sm->disconnect_reason = WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT;
wpa_auth_vlogger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
@@ -5353,17 +5772,11 @@
#endif /* CONFIG_WNM_AP */
-static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
- struct wpa_group *group)
+static void wpa_group_update_gtk(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group)
{
int tmp;
- wpa_printf(MSG_DEBUG,
- "WPA: group state machine entering state SETKEYS (VLAN-ID %d)",
- group->vlan_id);
- group->changed = true;
- group->wpa_group_state = WPA_GROUP_SETKEYS;
- group->GTKReKey = false;
tmp = group->GM;
group->GM = group->GN;
group->GN = tmp;
@@ -5377,6 +5790,25 @@
* counting the STAs that are marked with GUpdateStationKeys instead of
* including all STAs that could be in not-yet-completed state. */
wpa_gtk_update(wpa_auth, group);
+}
+
+
+static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group)
+{
+ wpa_printf(MSG_DEBUG,
+ "WPA: group state machine entering state SETKEYS (VLAN-ID %d)",
+ group->vlan_id);
+ group->changed = true;
+ group->wpa_group_state = WPA_GROUP_SETKEYS;
+ group->GTKReKey = false;
+
+#ifdef CONFIG_IEEE80211BE
+ if (wpa_auth->is_ml)
+ goto skip_update;
+#endif /* CONFIG_IEEE80211BE */
+
+ wpa_group_update_gtk(wpa_auth, group);
if (group->GKeyDoneStations) {
wpa_printf(MSG_DEBUG,
@@ -5384,6 +5816,10 @@
group->GKeyDoneStations);
group->GKeyDoneStations = 0;
}
+
+#ifdef CONFIG_IEEE80211BE
+skip_update:
+#endif /* CONFIG_IEEE80211BE */
wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, group);
wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d",
group->GKeyDoneStations);
@@ -5502,6 +5938,61 @@
}
+static void wpa_clear_changed(struct wpa_state_machine *sm)
+{
+#ifdef CONFIG_IEEE80211BE
+ int link_id;
+#endif /* CONFIG_IEEE80211BE */
+
+ sm->changed = false;
+ sm->wpa_auth->group->changed = false;
+
+#ifdef CONFIG_IEEE80211BE
+ for_each_sm_auth(sm, link_id)
+ sm->mld_links[link_id].wpa_auth->group->changed = false;
+#endif /* CONFIG_IEEE80211BE */
+}
+
+
+static void wpa_group_sm_step_links(struct wpa_state_machine *sm)
+{
+#ifdef CONFIG_IEEE80211BE
+ int link_id;
+#endif /* CONFIG_IEEE80211BE */
+
+ if (!sm || !sm->wpa_auth)
+ return;
+ wpa_group_sm_step(sm->wpa_auth, sm->wpa_auth->group);
+
+#ifdef CONFIG_IEEE80211BE
+ for_each_sm_auth(sm, link_id) {
+ wpa_group_sm_step(sm->mld_links[link_id].wpa_auth,
+ sm->mld_links[link_id].wpa_auth->group);
+ }
+#endif /* CONFIG_IEEE80211BE */
+}
+
+
+static bool wpa_group_sm_changed(struct wpa_state_machine *sm)
+{
+#ifdef CONFIG_IEEE80211BE
+ int link_id;
+#endif /* CONFIG_IEEE80211BE */
+ bool changed;
+
+ if (!sm || !sm->wpa_auth)
+ return false;
+ changed = sm->wpa_auth->group->changed;
+
+#ifdef CONFIG_IEEE80211BE
+ for_each_sm_auth(sm, link_id)
+ changed |= sm->mld_links[link_id].wpa_auth->group->changed;
+#endif /* CONFIG_IEEE80211BE */
+
+ return changed;
+}
+
+
static int wpa_sm_step(struct wpa_state_machine *sm)
{
if (!sm)
@@ -5520,8 +6011,7 @@
if (sm->pending_deinit)
break;
- sm->changed = false;
- sm->wpa_auth->group->changed = false;
+ wpa_clear_changed(sm);
SM_STEP_RUN(WPA_PTK);
if (sm->pending_deinit)
@@ -5529,8 +6019,8 @@
SM_STEP_RUN(WPA_PTK_GROUP);
if (sm->pending_deinit)
break;
- wpa_group_sm_step(sm->wpa_auth, sm->group);
- } while (sm->changed || sm->wpa_auth->group->changed);
+ wpa_group_sm_step_links(sm);
+ } while (sm->changed || wpa_group_sm_changed(sm));
sm->in_step_loop = 0;
if (sm->pending_deinit) {
@@ -6449,6 +6939,20 @@
}
+void wpa_auth_set_rsn_override(struct wpa_state_machine *sm, bool val)
+{
+ if (sm)
+ sm->rsn_override = val;
+}
+
+
+void wpa_auth_set_rsn_override_2(struct wpa_state_machine *sm, bool val)
+{
+ if (sm)
+ sm->rsn_override_2 = val;
+}
+
+
#ifdef CONFIG_DPP2
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
{
@@ -6460,6 +6964,13 @@
#endif /* CONFIG_DPP2 */
+void wpa_auth_set_ssid_protection(struct wpa_state_machine *sm, bool val)
+{
+ if (sm)
+ sm->ssid_protection = val;
+}
+
+
void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
u8 val)
{
@@ -6744,8 +7255,10 @@
{
if (!wpa_auth)
return -1;
- eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
- return eloop_register_timeout(0, 0, wpa_rekey_gtk, wpa_auth, NULL);
+ eloop_cancel_timeout(wpa_rekey_gtk,
+ wpa_get_primary_auth(wpa_auth), NULL);
+ return eloop_register_timeout(0, 0, wpa_rekey_gtk,
+ wpa_get_primary_auth(wpa_auth), NULL);
}
@@ -6833,79 +7346,64 @@
}
-void wpa_auth_set_ml_info(struct wpa_state_machine *sm, const u8 *mld_addr,
+void wpa_auth_set_ml_info(struct wpa_state_machine *sm,
u8 mld_assoc_link_id, struct mld_info *info)
{
#ifdef CONFIG_IEEE80211BE
- struct wpa_auth_ml_rsn_info ml_rsn_info;
- unsigned int link_id, i;
+ unsigned int link_id;
if (!info)
return;
os_memset(sm->mld_links, 0, sizeof(sm->mld_links));
+ sm->n_mld_affiliated_links = 0;
wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"MLD: Initialization");
- os_memcpy(sm->own_mld_addr, mld_addr, ETH_ALEN);
os_memcpy(sm->peer_mld_addr, info->common_info.mld_addr, ETH_ALEN);
sm->mld_assoc_link_id = mld_assoc_link_id;
- os_memset(&ml_rsn_info, 0, sizeof(ml_rsn_info));
-
- for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
+ for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
struct mld_link_info *link = &info->links[link_id];
struct mld_link *sm_link = &sm->mld_links[link_id];
+ struct wpa_get_link_auth_ctx ctx;
sm_link->valid = link->valid;
if (!link->valid)
continue;
os_memcpy(sm_link->peer_addr, link->peer_addr, ETH_ALEN);
- os_memcpy(sm_link->own_addr, link->local_addr, ETH_ALEN);
wpa_printf(MSG_DEBUG,
- "WPA_AUTH: MLD: id=%u, addr=" MACSTR " peer=" MACSTR,
+ "WPA_AUTH: MLD: id=%u, peer=" MACSTR,
link_id,
- MAC2STR(sm_link->own_addr),
MAC2STR(sm_link->peer_addr));
- if (link_id != mld_assoc_link_id)
+ if (link_id != mld_assoc_link_id) {
sm->n_mld_affiliated_links++;
-
- ml_rsn_info.links[i++].link_id = link_id;
- }
-
- ml_rsn_info.n_mld_links = i;
-
- wpa_auth_get_ml_rsn_info(sm->wpa_auth, &ml_rsn_info);
-
- for (i = 0; i < ml_rsn_info.n_mld_links; i++) {
- struct mld_link *sm_link;
- const u8 *rsn_ies;
- u8 rsn_ies_len;
-
- sm_link = &sm->mld_links[ml_rsn_info.links[i].link_id];
- rsn_ies = ml_rsn_info.links[i].rsn_ies;
- rsn_ies_len = ml_rsn_info.links[i].rsn_ies_len;
-
- /* This should not really happen */
- if (!rsn_ies || rsn_ies_len < 2 || rsn_ies[0] != WLAN_EID_RSN ||
- rsn_ies[1] + 2 > rsn_ies_len) {
- wpa_printf(MSG_INFO, "WPA_AUTH: MLD: Invalid RSNE");
- continue;
+ ctx.addr = link->local_addr;
+ ctx.mld_addr = NULL;
+ ctx.link_id = -1;
+ ctx.wpa_auth = NULL;
+ wpa_auth_for_each_auth(sm->wpa_auth,
+ wpa_get_link_sta_auth, &ctx);
+ if (ctx.wpa_auth) {
+ sm_link->wpa_auth = ctx.wpa_auth;
+ wpa_group_get(sm_link->wpa_auth,
+ sm_link->wpa_auth->group);
+ }
+ } else {
+ sm_link->wpa_auth = sm->wpa_auth;
}
- sm_link->rsne = rsn_ies;
- sm_link->rsne_len = rsn_ies[1] + 2;
-
- if (rsn_ies[1] + 2UL + 2UL < rsn_ies_len &&
- rsn_ies[rsn_ies[1] + 2] == WLAN_EID_RSNX) {
- sm_link->rsnxe = rsn_ies + 2 + rsn_ies[1];
- sm_link->rsnxe_len = sm_link->rsnxe[1] + 2;
- }
+ if (!sm_link->wpa_auth)
+ wpa_printf(MSG_ERROR,
+ "Unable to find authenticator object for ML STA "
+ MACSTR " on link id %d",
+ MAC2STR(sm->wpa_auth->mld_addr),
+ link_id);
}
#endif /* CONFIG_IEEE80211BE */
}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 4f6bb76..86cb4e8 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -173,6 +173,8 @@
int wpa;
int extended_key_id;
int wpa_key_mgmt;
+ int rsn_override_key_mgmt;
+ int rsn_override_key_mgmt_2;
int wpa_pairwise;
int wpa_group;
int wpa_group_rekey;
@@ -184,6 +186,8 @@
u32 wpa_pairwise_update_count;
int wpa_disable_eapol_key_retries;
int rsn_pairwise;
+ int rsn_override_pairwise;
+ int rsn_override_pairwise_2;
int rsn_preauth;
int eapol_version;
int wmm_enabled;
@@ -192,15 +196,17 @@
int okc;
int tx_status;
enum mfp_options ieee80211w;
+ enum mfp_options rsn_override_mfp;
+ enum mfp_options rsn_override_mfp_2;
int beacon_prot;
int group_mgmt_cipher;
int sae_require_mfp;
#ifdef CONFIG_OCV
int ocv; /* Operating Channel Validation */
#endif /* CONFIG_OCV */
-#ifdef CONFIG_IEEE80211R_AP
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
+#ifdef CONFIG_IEEE80211R_AP
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
size_t r0_key_holder_len;
@@ -283,10 +289,20 @@
bool radius_psk;
+ bool no_disconnect_on_group_keyerror;
+
/* Pointer to Multi-BSSID transmitted BSS authenticator instance.
* Set only in nontransmitted BSSs, i.e., is NULL for transmitted BSS
* and in BSSs that are not part of a Multi-BSSID set. */
struct wpa_authenticator *tx_bss_auth;
+
+#ifdef CONFIG_IEEE80211BE
+ const u8 *mld_addr;
+ int link_id;
+ struct wpa_authenticator *first_link_auth;
+#endif /* CONFIG_IEEE80211BE */
+
+ bool ssid_protection;
};
typedef enum {
@@ -299,16 +315,6 @@
WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx
} wpa_eapol_variable;
-struct wpa_auth_ml_rsn_info {
- unsigned int n_mld_links;
-
- struct wpa_auth_ml_link_rsn_info {
- unsigned int link_id;
- const u8 *rsn_ies;
- size_t rsn_ies_len;
- } links[MAX_NUM_MLD_LINKS];
-};
-
struct wpa_auth_ml_key_info {
unsigned int n_mld_links;
bool mgmt_frame_prot;
@@ -402,7 +408,6 @@
size_t ltf_keyseed_len);
#endif /* CONFIG_PASN */
#ifdef CONFIG_IEEE80211BE
- int (*get_ml_rsn_info)(void *ctx, struct wpa_auth_ml_rsn_info *info);
int (*get_ml_key_info)(void *ctx, struct wpa_auth_ml_key_info *info);
#endif /* CONFIG_IEEE80211BE */
int (*get_drv_flags)(void *ctx, u64 *drv_flags, u64 *drv_flags2);
@@ -431,7 +436,8 @@
const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *rsnxe, size_t rsnxe_len,
const u8 *mdie, size_t mdie_len,
- const u8 *owe_dh, size_t owe_dh_len);
+ const u8 *owe_dh, size_t owe_dh_len,
+ struct wpa_state_machine *assoc_sm);
int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *osen_ie, size_t osen_ie_len);
@@ -522,9 +528,9 @@
size_t max_len, int auth_alg,
const u8 *req_ies, size_t req_ies_len,
int omit_rsnxe);
-void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
+void wpa_ft_process_auth(struct wpa_state_machine *sm,
u16 auth_transaction, const u8 *ies, size_t ies_len,
- void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
+ void (*cb)(void *ctx, const u8 *dst,
u16 auth_transaction, u16 resp,
const u8 *ies, size_t ies_len),
void *ctx);
@@ -607,7 +613,10 @@
bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
u8 *fd_rsn_info);
void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
+void wpa_auth_set_rsn_override(struct wpa_state_machine *sm, bool val);
+void wpa_auth_set_rsn_override_2(struct wpa_state_machine *sm, bool val);
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
+void wpa_auth_set_ssid_protection(struct wpa_state_machine *sm, bool val);
void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
u8 val);
@@ -645,12 +654,19 @@
void wpa_auth_sta_radius_psk_resp(struct wpa_state_machine *sm, bool success);
-void wpa_auth_set_ml_info(struct wpa_state_machine *sm, const u8 *mld_addr,
+void wpa_auth_set_ml_info(struct wpa_state_machine *sm,
u8 mld_assoc_link_id, struct mld_info *info);
-void wpa_auth_ml_get_rsn_info(struct wpa_authenticator *a,
- struct wpa_auth_ml_link_rsn_info *info);
void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
struct wpa_auth_ml_link_key_info *info,
bool mgmt_frame_prot, bool beacon_prot);
+void wpa_release_link_auth_ref(struct wpa_state_machine *sm,
+ int release_link_id);
+
+#define for_each_sm_auth(sm, link_id) \
+ for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) \
+ if (sm->mld_links[link_id].valid && \
+ sm->mld_links[link_id].wpa_auth && \
+ sm->wpa_auth != sm->mld_links[link_id].wpa_auth)
+
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 7744ed6..de16c31 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -3442,9 +3442,9 @@
}
-void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
+void wpa_ft_process_auth(struct wpa_state_machine *sm,
u16 auth_transaction, const u8 *ies, size_t ies_len,
- void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
+ void (*cb)(void *ctx, const u8 *dst,
u16 auth_transaction, u16 status,
const u8 *ies, size_t ies_len),
void *ctx)
@@ -3462,7 +3462,8 @@
wpa_printf(MSG_DEBUG, "FT: Received authentication frame: STA=" MACSTR
" BSSID=" MACSTR " transaction=%d",
- MAC2STR(sm->addr), MAC2STR(bssid), auth_transaction);
+ MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr),
+ auth_transaction);
sm->ft_pending_cb = cb;
sm->ft_pending_cb_ctx = ctx;
sm->ft_pending_auth_transaction = auth_transaction;
@@ -3480,8 +3481,7 @@
MAC2STR(sm->addr), auth_transaction + 1, status,
status2str(status));
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
- cb(ctx, sm->addr, bssid, auth_transaction + 1, status,
- resp_ies, resp_ies_len);
+ cb(ctx, sm->addr, auth_transaction + 1, status, resp_ies, resp_ies_len);
os_free(resp_ies);
}
@@ -3810,7 +3810,7 @@
}
-static void wpa_ft_rrb_rx_request_cb(void *ctx, const u8 *dst, const u8 *bssid,
+static void wpa_ft_rrb_rx_request_cb(void *ctx, const u8 *dst,
u16 auth_transaction, u16 resp,
const u8 *ies, size_t ies_len)
{
@@ -4339,7 +4339,7 @@
wpa_printf(MSG_DEBUG, "FT: Postponed auth callback result for " MACSTR
" - status %u", MAC2STR(sm->addr), status);
- sm->ft_pending_cb(sm->ft_pending_cb_ctx, sm->addr, sm->wpa_auth->addr,
+ sm->ft_pending_cb(sm->ft_pending_cb_ctx, sm->addr,
sm->ft_pending_auth_transaction + 1, status,
resp_ies, resp_ies_len);
os_free(resp_ies);
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 34de45c..e88644f 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -45,6 +45,8 @@
wconf->wpa = conf->wpa;
wconf->extended_key_id = conf->extended_key_id;
wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
+ wconf->rsn_override_key_mgmt = conf->rsn_override_key_mgmt;
+ wconf->rsn_override_key_mgmt_2 = conf->rsn_override_key_mgmt_2;
wconf->wpa_pairwise = conf->wpa_pairwise;
wconf->wpa_group = conf->wpa_group;
wconf->wpa_group_rekey = conf->wpa_group_rekey;
@@ -56,6 +58,8 @@
conf->wpa_disable_eapol_key_retries;
wconf->wpa_pairwise_update_count = conf->wpa_pairwise_update_count;
wconf->rsn_pairwise = conf->rsn_pairwise;
+ wconf->rsn_override_pairwise = conf->rsn_override_pairwise;
+ wconf->rsn_override_pairwise_2 = conf->rsn_override_pairwise_2;
wconf->rsn_preauth = conf->rsn_preauth;
wconf->eapol_version = conf->eapol_version;
#ifdef CONFIG_MACSEC
@@ -70,14 +74,17 @@
#endif /* CONFIG_OCV */
wconf->okc = conf->okc;
wconf->ieee80211w = conf->ieee80211w;
+ wconf->rsn_override_mfp = conf->rsn_override_mfp;
+ wconf->rsn_override_mfp_2 = conf->rsn_override_mfp_2;
wconf->beacon_prot = conf->beacon_prot;
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
wconf->sae_require_mfp = conf->sae_require_mfp;
-#ifdef CONFIG_IEEE80211R_AP
+ wconf->ssid_protection = conf->ssid_protection;
wconf->ssid_len = conf->ssid.ssid_len;
if (wconf->ssid_len > SSID_MAX_LEN)
wconf->ssid_len = SSID_MAX_LEN;
os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
+#ifdef CONFIG_IEEE80211R_AP
os_memcpy(wconf->mobility_domain, conf->mobility_domain,
MOBILITY_DOMAIN_ID_LEN);
if (conf->nas_identifier &&
@@ -227,6 +234,9 @@
#endif /* CONFIG_PASN */
wconf->radius_psk = conf->wpa_psk_radius == PSK_RADIUS_DURING_4WAY_HS;
+ wconf->no_disconnect_on_group_keyerror =
+ conf->bss_max_idle && conf->ap_max_inactivity &&
+ conf->no_disconnect_on_group_keyerror;
}
@@ -1536,53 +1546,11 @@
#ifdef CONFIG_IEEE80211BE
-static int hostapd_wpa_auth_get_ml_rsn_info(void *ctx,
- struct wpa_auth_ml_rsn_info *info)
-{
- struct hostapd_data *hapd = ctx;
- unsigned int i, j;
-
- wpa_printf(MSG_DEBUG, "WPA_AUTH: MLD: Get RSN info CB: n_mld_links=%u",
- info->n_mld_links);
-
- if (!hapd->conf->mld_ap || !hapd->iface || !hapd->iface->interfaces)
- return -1;
-
- for (i = 0; i < info->n_mld_links; i++) {
- unsigned int link_id = info->links[i].link_id;
-
- wpa_printf(MSG_DEBUG,
- "WPA_AUTH: MLD: Get link RSN CB: link_id=%u",
- link_id);
-
- for (j = 0; j < hapd->iface->interfaces->count; j++) {
- struct hostapd_iface *iface =
- hapd->iface->interfaces->iface[j];
-
- if (!hostapd_is_ml_partner(hapd, iface->bss[0]) ||
- link_id != iface->bss[0]->mld_link_id ||
- !iface->bss[0]->wpa_auth)
- continue;
-
- wpa_auth_ml_get_rsn_info(iface->bss[0]->wpa_auth,
- &info->links[i]);
- break;
- }
-
- if (j == hapd->iface->interfaces->count)
- wpa_printf(MSG_DEBUG,
- "WPA_AUTH: MLD: link=%u not found", link_id);
- }
-
- return 0;
-}
-
-
static int hostapd_wpa_auth_get_ml_key_info(void *ctx,
struct wpa_auth_ml_key_info *info)
{
struct hostapd_data *hapd = ctx;
- unsigned int i, j;
+ unsigned int i;
wpa_printf(MSG_DEBUG, "WPA_AUTH: MLD: Get key info CB: n_mld_links=%u",
info->n_mld_links);
@@ -1591,29 +1559,35 @@
return -1;
for (i = 0; i < info->n_mld_links; i++) {
+ struct hostapd_data *bss;
u8 link_id = info->links[i].link_id;
+ bool link_bss_found = false;
wpa_printf(MSG_DEBUG,
"WPA_AUTH: MLD: Get link info CB: link_id=%u",
link_id);
- for (j = 0; j < hapd->iface->interfaces->count; j++) {
- struct hostapd_iface *iface =
- hapd->iface->interfaces->iface[j];
-
- if (!hostapd_is_ml_partner(hapd, iface->bss[0]) ||
- link_id != iface->bss[0]->mld_link_id ||
- !iface->bss[0]->wpa_auth)
- continue;
-
- wpa_auth_ml_get_key_info(iface->bss[0]->wpa_auth,
+ if (hapd->mld_link_id == link_id) {
+ wpa_auth_ml_get_key_info(hapd->wpa_auth,
&info->links[i],
info->mgmt_frame_prot,
info->beacon_prot);
+ continue;
+ }
+
+ for_each_mld_link(bss, hapd) {
+ if (bss == hapd || bss->mld_link_id != link_id)
+ continue;
+
+ wpa_auth_ml_get_key_info(bss->wpa_auth,
+ &info->links[i],
+ info->mgmt_frame_prot,
+ info->beacon_prot);
+ link_bss_found = true;
break;
}
- if (j == hapd->iface->interfaces->count)
+ if (!link_bss_found)
wpa_printf(MSG_DEBUG,
"WPA_AUTH: MLD: link=%u not found", link_id);
}
@@ -1689,7 +1663,6 @@
.set_ltf_keyseed = hostapd_set_ltf_keyseed,
#endif /* CONFIG_PASN */
#ifdef CONFIG_IEEE80211BE
- .get_ml_rsn_info = hostapd_wpa_auth_get_ml_rsn_info,
.get_ml_key_info = hostapd_wpa_auth_get_ml_key_info,
#endif /* CONFIG_IEEE80211BE */
.get_drv_flags = hostapd_wpa_auth_get_drv_flags,
@@ -1740,6 +1713,27 @@
!!(hapd->iface->drv_flags2 &
WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP);
+#ifdef CONFIG_IEEE80211BE
+ _conf.mld_addr = NULL;
+ _conf.link_id = -1;
+ _conf.first_link_auth = NULL;
+
+ if (hapd->conf->mld_ap) {
+ struct hostapd_data *lhapd;
+
+ _conf.mld_addr = hapd->mld->mld_addr;
+ _conf.link_id = hapd->mld_link_id;
+
+ for_each_mld_link(lhapd, hapd) {
+ if (lhapd == hapd)
+ continue;
+
+ if (lhapd->wpa_auth)
+ _conf.first_link_auth = lhapd->wpa_auth;
+ }
+ }
+#endif /* CONFIG_IEEE80211BE */
+
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
if (hapd->wpa_auth == NULL) {
wpa_printf(MSG_ERROR, "WPA initialization failed.");
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 9ba8304..29988c2 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -124,6 +124,9 @@
u32 dot11RSNAStatsTKIPLocalMICFailures;
u32 dot11RSNAStatsTKIPRemoteMICFailures;
+ bool rsn_override;
+ bool rsn_override_2;
+
#ifdef CONFIG_IEEE80211R_AP
u8 xxkey[PMK_LEN_MAX]; /* PSK or the second 256 bits of MSK, or the
* first 384 bits of MSK */
@@ -136,7 +139,7 @@
size_t r0kh_id_len;
u8 *assoc_resp_ftie;
- void (*ft_pending_cb)(void *ctx, const u8 *dst, const u8 *bssid,
+ void (*ft_pending_cb)(void *ctx, const u8 *dst,
u16 auth_transaction, u16 status,
const u8 *ies, size_t ies_len);
void *ft_pending_cb_ctx;
@@ -172,7 +175,6 @@
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_IEEE80211BE
- u8 own_mld_addr[ETH_ALEN];
u8 peer_mld_addr[ETH_ALEN];
s8 mld_assoc_link_id;
u8 n_mld_affiliated_links;
@@ -180,14 +182,12 @@
struct mld_link {
bool valid;
u8 peer_addr[ETH_ALEN];
- u8 own_addr[ETH_ALEN];
- const u8 *rsne;
- size_t rsne_len;
- const u8 *rsnxe;
- size_t rsnxe_len;
+ struct wpa_authenticator *wpa_auth;
} mld_links[MAX_NUM_MLD_LINKS];
#endif /* CONFIG_IEEE80211BE */
+
+ bool ssid_protection;
};
@@ -251,6 +251,9 @@
u8 *wpa_ie;
size_t wpa_ie_len;
+ u8 *rsne_override; /* RSNE with overridden payload */
+ u8 *rsne_override_2; /* RSNE with overridden (2) payload */
+ u8 *rsnxe_override; /* RSNXE with overridden payload */
u8 addr[ETH_ALEN];
@@ -262,6 +265,13 @@
#ifdef CONFIG_P2P
struct bitfield *ip_pool;
#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_IEEE80211BE
+ bool is_ml;
+ u8 mld_addr[ETH_ALEN];
+ u8 link_id;
+ bool primary_auth;
+#endif /* CONFIG_IEEE80211BE */
};
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index a5f2861..f4f9cc8 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -89,7 +89,8 @@
}
-static u16 wpa_own_rsn_capab(struct wpa_auth_config *conf)
+static u16 wpa_own_rsn_capab(struct wpa_auth_config *conf,
+ enum mfp_options mfp)
{
u16 capab = 0;
@@ -99,9 +100,9 @@
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
- if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ if (mfp != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
- if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
+ if (mfp == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
#ifdef CONFIG_OCV
@@ -119,24 +120,19 @@
}
-int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
- const u8 *pmkid)
+static u8 * rsne_write_data(u8 *buf, size_t len, u8 *pos, int group,
+ int pairwise, int key_mgmt, u16 rsn_capab,
+ const u8 *pmkid, enum mfp_options mfp,
+ int group_mgmt_cipher)
{
- struct rsn_ie_hdr *hdr;
int num_suites, res;
- u8 *pos, *count;
+ u8 *count;
u32 suite;
- hdr = (struct rsn_ie_hdr *) buf;
- hdr->elem_id = WLAN_EID_RSN;
- WPA_PUT_LE16(hdr->version, RSN_VERSION);
- pos = (u8 *) (hdr + 1);
-
- suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group);
if (suite == 0) {
- wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
- conf->wpa_group);
- return -1;
+ wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", group);
+ return NULL;
}
RSN_SELECTOR_PUT(pos, suite);
pos += RSN_SELECTOR_LEN;
@@ -153,7 +149,7 @@
}
#endif /* CONFIG_RSN_TESTING */
- res = rsn_cipher_put_suites(pos, conf->rsn_pairwise);
+ res = rsn_cipher_put_suites(pos, pairwise);
num_suites += res;
pos += res * RSN_SELECTOR_LEN;
@@ -167,8 +163,8 @@
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
- conf->rsn_pairwise);
- return -1;
+ pairwise);
+ return NULL;
}
WPA_PUT_LE16(count, num_suites);
@@ -184,102 +180,102 @@
}
#endif /* CONFIG_RSN_TESTING */
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+ if (key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
+ if (key_mgmt & WPA_KEY_MGMT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#ifdef CONFIG_IEEE80211R_AP
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
+ if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#ifdef CONFIG_SHA384
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
+ if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_SHA384 */
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
+ if (key_mgmt & WPA_KEY_MGMT_FT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SHA384
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) {
+ if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA384);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_SHA384 */
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+ if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+ if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#ifdef CONFIG_SAE
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
+ if (key_mgmt & WPA_KEY_MGMT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ if (key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+ if (key_mgmt & WPA_KEY_MGMT_FT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
+ if (key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_SAE */
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#ifdef CONFIG_FILS
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
+ if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
+ if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#ifdef CONFIG_IEEE80211R_AP
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
+ if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
+ if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384);
pos += RSN_SELECTOR_LEN;
num_suites++;
@@ -287,28 +283,28 @@
#endif /* CONFIG_IEEE80211R_AP */
#endif /* CONFIG_FILS */
#ifdef CONFIG_OWE
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) {
+ if (key_mgmt & WPA_KEY_MGMT_OWE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OWE);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_OWE */
#ifdef CONFIG_DPP
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) {
+ if (key_mgmt & WPA_KEY_MGMT_DPP) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_DPP */
#ifdef CONFIG_HS20
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_OSEN) {
+ if (key_mgmt & WPA_KEY_MGMT_OSEN) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_HS20 */
#ifdef CONFIG_PASN
- if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) {
+ if (key_mgmt & WPA_KEY_MGMT_PASN) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PASN);
pos += RSN_SELECTOR_LEN;
num_suites++;
@@ -325,18 +321,18 @@
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
- conf->wpa_key_mgmt);
- return -1;
+ key_mgmt);
+ return NULL;
}
WPA_PUT_LE16(count, num_suites);
/* RSN Capabilities */
- WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf));
+ WPA_PUT_LE16(pos, rsn_capab);
pos += 2;
if (pmkid) {
if (2 + PMKID_LEN > buf + len - pos)
- return -1;
+ return NULL;
/* PMKID Count */
WPA_PUT_LE16(pos, 1);
pos += 2;
@@ -344,18 +340,19 @@
pos += PMKID_LEN;
}
- if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
- conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
+
+ if (mfp != NO_MGMT_FRAME_PROTECTION &&
+ group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
if (2 + 4 > buf + len - pos)
- return -1;
- if (pmkid == NULL) {
+ return NULL;
+ if (!pmkid) {
/* PMKID Count */
WPA_PUT_LE16(pos, 0);
pos += 2;
}
/* Management Group Cipher Suite */
- switch (conf->group_mgmt_cipher) {
+ switch (group_mgmt_cipher) {
case WPA_CIPHER_AES_128_CMAC:
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
break;
@@ -371,8 +368,8 @@
default:
wpa_printf(MSG_DEBUG,
"Invalid group management cipher (0x%x)",
- conf->group_mgmt_cipher);
- return -1;
+ group_mgmt_cipher);
+ return NULL;
}
pos += RSN_SELECTOR_LEN;
}
@@ -384,12 +381,12 @@
* the element.
*/
int pmkid_count_set = pmkid != NULL;
- if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
+ if (mfp != NO_MGMT_FRAME_PROTECTION)
pmkid_count_set = 1;
/* PMKID Count */
WPA_PUT_LE16(pos, 0);
pos += 2;
- if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
+ if (mfp == NO_MGMT_FRAME_PROTECTION) {
/* Management Group Cipher Suite */
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
pos += RSN_SELECTOR_LEN;
@@ -399,6 +396,27 @@
pos += 17;
}
#endif /* CONFIG_RSN_TESTING */
+ return pos;
+}
+
+
+int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
+ const u8 *pmkid)
+{
+ struct rsn_ie_hdr *hdr;
+ u8 *pos;
+
+ hdr = (struct rsn_ie_hdr *) buf;
+ hdr->elem_id = WLAN_EID_RSN;
+ WPA_PUT_LE16(hdr->version, RSN_VERSION);
+ pos = (u8 *) (hdr + 1);
+
+ pos = rsne_write_data(buf, len, pos, conf->wpa_group,
+ conf->rsn_pairwise, conf->wpa_key_mgmt,
+ wpa_own_rsn_capab(conf, conf->ieee80211w), pmkid,
+ conf->ieee80211w, conf->group_mgmt_cipher);
+ if (!pos)
+ return -1;
hdr->len = (pos - buf) - 2;
@@ -406,16 +424,74 @@
}
-int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
+static int wpa_write_rsne_override(struct wpa_auth_config *conf, u8 *buf,
+ size_t len)
{
- u8 *pos = buf;
- u16 capab = 0;
- size_t flen;
+ u8 *pos, *len_pos;
- if (wpa_key_mgmt_sae(conf->wpa_key_mgmt) &&
+ pos = buf;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ len_pos = pos++;
+
+ WPA_PUT_BE32(pos, RSNE_OVERRIDE_IE_VENDOR_TYPE);
+ pos += 4;
+
+ WPA_PUT_LE16(pos, RSN_VERSION);
+ pos += 2;
+
+ pos = rsne_write_data(buf, len, pos, conf->wpa_group,
+ conf->rsn_override_pairwise,
+ conf->rsn_override_key_mgmt,
+ wpa_own_rsn_capab(conf, conf->rsn_override_mfp),
+ NULL, conf->rsn_override_mfp,
+ conf->group_mgmt_cipher);
+ if (!pos)
+ return -1;
+
+ *len_pos = (pos - buf) - 2;
+
+ return pos - buf;
+}
+
+
+static int wpa_write_rsne_override_2(struct wpa_auth_config *conf, u8 *buf,
+ size_t len)
+{
+ u8 *pos, *len_pos;
+
+ pos = buf;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ len_pos = pos++;
+
+ WPA_PUT_BE32(pos, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
+ pos += 4;
+
+ WPA_PUT_LE16(pos, RSN_VERSION);
+ pos += 2;
+
+ pos = rsne_write_data(buf, len, pos, conf->wpa_group,
+ conf->rsn_override_pairwise_2,
+ conf->rsn_override_key_mgmt_2,
+ wpa_own_rsn_capab(conf, conf->rsn_override_mfp_2),
+ NULL, conf->rsn_override_mfp_2,
+ conf->group_mgmt_cipher);
+ if (!pos)
+ return -1;
+
+ *len_pos = (pos - buf) - 2;
+
+ return pos - buf;
+}
+
+
+static u32 rsnxe_capab(struct wpa_auth_config *conf, int key_mgmt)
+{
+ u32 capab = 0;
+
+ if (wpa_key_mgmt_sae(key_mgmt) &&
(conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
conf->sae_pwe == SAE_PWE_BOTH || conf->sae_pk ||
- wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt))) {
+ wpa_key_mgmt_sae_ext_key(key_mgmt))) {
capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
#ifdef CONFIG_SAE_PK
if (conf->sae_pk)
@@ -429,6 +505,53 @@
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
if (conf->prot_range_neg)
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
+ if (conf->ssid_protection)
+ capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION);
+
+ return capab;
+}
+
+
+int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
+{
+ u8 *pos = buf;
+ u32 capab = 0, tmp;
+ size_t flen;
+
+ capab = rsnxe_capab(conf, conf->wpa_key_mgmt);
+
+ if (!capab)
+ return 0; /* no supported extended RSN capabilities */
+ tmp = capab;
+ flen = 0;
+ while (tmp) {
+ flen++;
+ tmp >>= 8;
+ }
+ if (len < 2 + flen)
+ return -1;
+ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
+
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = flen;
+ while (capab) {
+ *pos++ = capab & 0xff;
+ capab >>= 8;
+ }
+
+ return pos - buf;
+}
+
+
+static int wpa_write_rsnxe_override(struct wpa_auth_config *conf, u8 *buf,
+ size_t len)
+{
+ u8 *pos = buf;
+ u16 capab;
+ size_t flen;
+
+ capab = rsnxe_capab(conf, conf->rsn_override_key_mgmt |
+ conf->rsn_override_key_mgmt_2);
flen = (capab & 0xff00) ? 2 : 1;
if (!capab)
@@ -437,8 +560,11 @@
return -1;
capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
- *pos++ = WLAN_EID_RSNX;
- *pos++ = flen;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4 + flen;
+ WPA_PUT_BE32(pos, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
+ pos += 4;
+
*pos++ = capab & 0x00ff;
capab >>= 8;
if (capab)
@@ -501,7 +627,7 @@
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
{
- u8 *pos, buf[128];
+ u8 *pos, buf[256];
int res;
#ifdef CONFIG_TESTING_OPTIONS
@@ -554,6 +680,31 @@
return res;
pos += res;
}
+ if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
+ wpa_auth->conf.rsn_override_key_mgmt) {
+ res = wpa_write_rsne_override(&wpa_auth->conf,
+ pos, buf + sizeof(buf) - pos);
+ if (res < 0)
+ return res;
+ pos += res;
+ }
+ if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
+ wpa_auth->conf.rsn_override_key_mgmt_2) {
+ res = wpa_write_rsne_override_2(&wpa_auth->conf, pos,
+ buf + sizeof(buf) - pos);
+ if (res < 0)
+ return res;
+ pos += res;
+ }
+ if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
+ (wpa_auth->conf.rsn_override_key_mgmt ||
+ wpa_auth->conf.rsn_override_key_mgmt_2)) {
+ res = wpa_write_rsnxe_override(&wpa_auth->conf, pos,
+ buf + sizeof(buf) - pos);
+ if (res < 0)
+ return res;
+ pos += res;
+ }
os_free(wpa_auth->wpa_ie);
wpa_auth->wpa_ie = os_malloc(pos - buf);
@@ -562,6 +713,59 @@
os_memcpy(wpa_auth->wpa_ie, buf, pos - buf);
wpa_auth->wpa_ie_len = pos - buf;
+ if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
+ wpa_auth->conf.rsn_override_key_mgmt) {
+ res = wpa_write_rsne_override(&wpa_auth->conf, buf,
+ sizeof(buf));
+ if (res < 0)
+ return res;
+ os_free(wpa_auth->rsne_override);
+ wpa_auth->rsne_override = os_malloc(res - 4);
+ if (!wpa_auth->rsne_override)
+ return -1;
+ pos = wpa_auth->rsne_override;
+ *pos++ = WLAN_EID_RSN;
+ *pos++ = res - 2 - 4;
+ os_memcpy(pos, &buf[2 + 4], res - 2 - 4);
+ }
+
+ if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
+ wpa_auth->conf.rsn_override_key_mgmt_2) {
+ res = wpa_write_rsne_override_2(&wpa_auth->conf, buf,
+ sizeof(buf));
+ if (res < 0)
+ return res;
+ os_free(wpa_auth->rsne_override_2);
+ wpa_auth->rsne_override_2 = os_malloc(res - 4);
+ if (!wpa_auth->rsne_override_2)
+ return -1;
+ pos = wpa_auth->rsne_override_2;
+ *pos++ = WLAN_EID_RSN;
+ *pos++ = res - 2 - 4;
+ os_memcpy(pos, &buf[2 + 4], res - 2 - 4);
+ }
+
+ if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
+ (wpa_auth->conf.rsn_override_key_mgmt ||
+ wpa_auth->conf.rsn_override_key_mgmt_2)) {
+ res = wpa_write_rsnxe_override(&wpa_auth->conf, buf,
+ sizeof(buf));
+ if (res < 0)
+ return res;
+ os_free(wpa_auth->rsnxe_override);
+ if (res == 0) {
+ wpa_auth->rsnxe_override = NULL;
+ return 0;
+ }
+ wpa_auth->rsnxe_override = os_malloc(res - 4);
+ if (!wpa_auth->rsnxe_override)
+ return -1;
+ pos = wpa_auth->rsnxe_override;
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = res - 2 - 4;
+ os_memcpy(pos, &buf[2 + 4], res - 2 - 4);
+ }
+
return 0;
}
@@ -608,7 +812,8 @@
const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *rsnxe, size_t rsnxe_len,
const u8 *mdie, size_t mdie_len,
- const u8 *owe_dh, size_t owe_dh_len)
+ const u8 *owe_dh, size_t owe_dh_len,
+ struct wpa_state_machine *assoc_sm)
{
struct wpa_auth_config *conf = &wpa_auth->conf;
struct wpa_ie_data data;
@@ -765,7 +970,9 @@
return WPA_INVALID_GROUP;
}
- key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
+ key_mgmt = data.key_mgmt & (wpa_auth->conf.wpa_key_mgmt |
+ wpa_auth->conf.rsn_override_key_mgmt |
+ wpa_auth->conf.rsn_override_key_mgmt_2);
if (!key_mgmt) {
wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
MACSTR, data.key_mgmt, MAC2STR(sm->addr));
@@ -835,7 +1042,10 @@
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
if (version == WPA_PROTO_RSN)
- ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise;
+ ciphers = data.pairwise_cipher &
+ (wpa_auth->conf.rsn_pairwise |
+ wpa_auth->conf.rsn_override_pairwise |
+ wpa_auth->conf.rsn_override_pairwise_2);
else
ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
if (!ciphers) {
@@ -956,6 +1166,15 @@
else
sm->wpa = WPA_VERSION_WPA;
+ if (assoc_sm) {
+ /* For ML association link STA cannot choose a different
+ * AKM or pairwise cipher from association STA */
+ if (sm->wpa_key_mgmt != assoc_sm->wpa_key_mgmt)
+ return WPA_INVALID_AKMP;
+ if (sm->pairwise != assoc_sm->pairwise)
+ return WPA_INVALID_PAIRWISE;
+ }
+
#if defined(CONFIG_IEEE80211R_AP) && defined(CONFIG_FILS)
if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256 ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA384) &&
@@ -1212,7 +1431,7 @@
return false;
/* RSN Capability (B0..B15) */
- WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf));
+ WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf, conf->ieee80211w));
pos += 2;
/* Group Data Cipher Suite Selector (B16..B21) */