Revert "Revert "[wpa_supplicant] cumilative patch from commit 4b..."
Revert submission 28102966-revert-26533062-Supplicant_merge_June24-CUATTSRBBR
Fixed the regression issue (ag/28389573)
Bug: 329004037
Reverted changes: /q/submissionid:28102966-revert-26533062-Supplicant_merge_June24-CUATTSRBBR
Test: Turn ON/OFF SoftAp
Change-Id: Ie7ea1ee7f8b1311fce280907d37a2e321542f547
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 445d963..9aa61fa 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -163,6 +163,8 @@
/* Default to strict CRL checking. */
bss->check_crl_strict = 1;
+ bss->multi_ap_profile = MULTI_AP_PROFILE_2;
+
#ifdef CONFIG_TESTING_OPTIONS
bss->sae_commit_status = -1;
bss->test_assoc_comeback_type = -1;
@@ -557,6 +559,10 @@
for (i = 0; i < num_servers; i++) {
os_free(servers[i].shared_secret);
+ os_free(servers[i].ca_cert);
+ os_free(servers[i].client_cert);
+ os_free(servers[i].private_key);
+ os_free(servers[i].private_key_passwd);
}
os_free(servers);
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 69db16d..4f2164d 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -800,6 +800,14 @@
#define BACKHAUL_BSS 1
#define FRONTHAUL_BSS 2
int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
+ int multi_ap_profile;
+ /* Multi-AP Profile-1 clients not allowed to connect */
+#define PROFILE1_CLIENT_ASSOC_DISALLOW BIT(0)
+ /* Multi-AP Profile-2 clients not allowed to connect */
+#define PROFILE2_CLIENT_ASSOC_DISALLOW BIT(1)
+ unsigned int multi_ap_client_disallow;
+ /* Primary VLAN ID to use in Multi-AP */
+ int multi_ap_vlanid;
#ifdef CONFIG_AIRTIME_POLICY
unsigned int airtime_weight;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 60d66e4..11fe39c 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -265,8 +265,8 @@
}
-static bool hostapd_sta_is_link_sta(struct hostapd_data *hapd,
- struct sta_info *sta)
+bool hostapd_sta_is_link_sta(struct hostapd_data *hapd,
+ struct sta_info *sta)
{
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta) &&
@@ -572,12 +572,33 @@
}
+#ifdef CONFIG_IEEE80211BE
+int hostapd_if_link_remove(struct hostapd_data *hapd,
+ enum wpa_driver_if_type type,
+ const char *ifname, u8 link_id)
+{
+ if (!hapd->driver || !hapd->drv_priv || !hapd->driver->link_remove)
+ return -1;
+
+ return hapd->driver->link_remove(hapd->drv_priv, type, ifname,
+ hapd->mld_link_id);
+}
+#endif /* CONFIG_IEEE80211BE */
+
+
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname)
{
if (hapd->driver == NULL || hapd->drv_priv == NULL ||
hapd->driver->if_remove == NULL)
return -1;
+
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap)
+ return hostapd_if_link_remove(hapd, type, ifname,
+ hapd->mld_link_id);
+#endif /* CONFIG_IEEE80211BE */
+
return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
}
@@ -629,7 +650,7 @@
&cmode->he_capab[IEEE80211_MODE_AP] : NULL,
cmode ?
&cmode->eht_capab[IEEE80211_MODE_AP] :
- NULL))
+ NULL, hostapd_get_punct_bitmap(hapd)))
return -1;
if (hapd->driver == NULL)
@@ -758,6 +779,8 @@
struct wpa_scan_results * hostapd_driver_get_scan_results(
struct hostapd_data *hapd)
{
+ if (hapd->driver && hapd->driver->get_scan_results)
+ return hapd->driver->get_scan_results(hapd->drv_priv, NULL);
if (hapd->driver && hapd->driver->get_scan_results2)
return hapd->driver->get_scan_results2(hapd->drv_priv);
return NULL;
@@ -840,7 +863,7 @@
link_id = hapd->mld_link_id;
if (ap_sta_is_mld(hapd, sta))
- own_addr = hapd->mld_addr;
+ own_addr = hapd->mld->mld_addr;
}
#endif /* CONFIG_IEEE80211BE */
@@ -861,7 +884,7 @@
struct sta_info *sta = ap_get_sta(hapd, addr);
if (ap_sta_is_mld(hapd, sta))
- own_addr = hapd->mld_addr;
+ own_addr = hapd->mld->mld_addr;
}
#endif /* CONFIG_IEEE80211BE */
@@ -919,7 +942,7 @@
sta = ap_get_sta(hapd, dst);
if (ap_sta_is_mld(hapd, sta)) {
- own_addr = hapd->mld_addr;
+ own_addr = hapd->mld->mld_addr;
bssid = own_addr;
}
#endif /* CONFIG_IEEE80211BE */
@@ -977,7 +1000,8 @@
center_segment1,
cmode->vht_capab,
&cmode->he_capab[IEEE80211_MODE_AP],
- &cmode->eht_capab[IEEE80211_MODE_AP])) {
+ &cmode->eht_capab[IEEE80211_MODE_AP],
+ hostapd_get_punct_bitmap(hapd))) {
wpa_printf(MSG_ERROR, "Can't set freq params");
return -1;
}
@@ -999,7 +1023,8 @@
int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
const u8 *qos_map_set, u8 qos_map_set_len)
{
- if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv)
+ if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv ||
+ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_QOS_MAPPING))
return 0;
return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
qos_map_set_len);
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 331b0ea..d7e79c8 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -26,6 +26,8 @@
struct wpabuf *assocresp);
int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd);
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
+bool hostapd_sta_is_link_sta(struct hostapd_data *hapd,
+ struct sta_info *sta);
int hostapd_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta);
@@ -59,6 +61,9 @@
const char *bridge, int use_existing);
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname);
+int hostapd_if_link_remove(struct hostapd_data *hapd,
+ enum wpa_driver_if_type type,
+ const char *ifname, u8 link_id);
int hostapd_set_ieee8021x(struct hostapd_data *hapd,
struct wpa_bss_params *params);
int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
@@ -388,9 +393,15 @@
static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
{
+ int link_id = -1;
+
if (!hapd->driver || !hapd->driver->stop_ap || !hapd->drv_priv)
return 0;
- return hapd->driver->stop_ap(hapd->drv_priv);
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap)
+ link_id = hapd->mld_link_id;
+#endif /* CONFIG_IEEE80211BE */
+ return hapd->driver->stop_ap(hapd->drv_priv, link_id);
}
static inline int hostapd_drv_channel_info(struct hostapd_data *hapd,
@@ -443,15 +454,28 @@
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_IEEE80211BE
+
static inline int hostapd_drv_link_add(struct hostapd_data *hapd,
u8 link_id, const u8 *addr)
{
if (!hapd->driver || !hapd->drv_priv || !hapd->driver->link_add)
return -1;
- return hapd->driver->link_add(hapd->drv_priv, link_id, addr);
+ return hapd->driver->link_add(hapd->drv_priv, link_id, addr, hapd);
}
+
+static inline int hostapd_drv_link_sta_remove(struct hostapd_data *hapd,
+ const u8 *addr)
+{
+ if (!hapd->conf->mld_ap || !hapd->driver || !hapd->drv_priv ||
+ !hapd->driver->link_sta_remove)
+ return -1;
+
+ return hapd->driver->link_sta_remove(hapd->drv_priv, hapd->mld_link_id,
+ addr);
+}
+
#endif /* CONFIG_IEEE80211BE */
#endif /* AP_DRV_OPS */
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 1488dcc..6ed4d06 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -107,13 +107,20 @@
struct radius_server_conf srv;
struct hostapd_bss_config *conf = hapd->conf;
- if (hapd->mld_first_bss) {
+#ifdef CONFIG_IEEE80211BE
+ if (!hostapd_mld_is_first_bss(hapd)) {
+ struct hostapd_data *first;
+
wpa_printf(MSG_DEBUG,
"MLD: Using RADIUS server of the first BSS");
- hapd->radius_srv = hapd->mld_first_bss->radius_srv;
+ first = hostapd_mld_get_first_bss(hapd);
+ if (!first)
+ return -1;
+ hapd->radius_srv = first->radius_srv;
return 0;
}
+#endif /* CONFIG_IEEE80211BE */
os_memset(&srv, 0, sizeof(srv));
srv.client_file = conf->radius_server_clients;
@@ -249,18 +256,25 @@
int authsrv_init(struct hostapd_data *hapd)
{
- if (hapd->mld_first_bss) {
+#ifdef CONFIG_IEEE80211BE
+ 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;
#ifdef EAP_TLS_FUNCS
- hapd->ssl_ctx = hapd->mld_first_bss->ssl_ctx;
+ hapd->ssl_ctx = first->ssl_ctx;
#endif /* EAP_TLS_FUNCS */
- hapd->eap_cfg = hapd->mld_first_bss->eap_cfg;
+ hapd->eap_cfg = first->eap_cfg;
#ifdef EAP_SIM_DB
- hapd->eap_sim_db_priv = hapd->mld_first_bss->eap_sim_db_priv;
+ hapd->eap_sim_db_priv = first->eap_sim_db_priv;
#endif /* EAP_SIM_DB */
return 0;
}
+#endif /* CONFIG_IEEE80211BE */
#ifdef EAP_TLS_FUNCS
if (hapd->conf->eap_server &&
@@ -376,7 +390,8 @@
void authsrv_deinit(struct hostapd_data *hapd)
{
- if (hapd->mld_first_bss) {
+#ifdef CONFIG_IEEE80211BE
+ if (!hostapd_mld_is_first_bss(hapd)) {
wpa_printf(MSG_DEBUG,
"MLD: Deinit auth_serv of a non-first BSS");
@@ -390,6 +405,7 @@
#endif /* EAP_TLS_FUNCS */
return;
}
+#endif /* CONFIG_IEEE80211BE */
#ifdef RADIUS_SERVER
radius_server_deinit(hapd->radius_srv);
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index e50f0a0..32865f6 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -960,7 +960,7 @@
* 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 : hapd->conf->mld_id;
+ 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) {
@@ -2616,7 +2616,8 @@
hostapd_get_oper_centr_freq_seg1_idx(iconf),
cmode->vht_capab,
&cmode->he_capab[IEEE80211_MODE_AP],
- &cmode->eht_capab[IEEE80211_MODE_AP]) == 0)
+ &cmode->eht_capab[IEEE80211_MODE_AP],
+ hostapd_get_punct_bitmap(hapd)) == 0)
params.freq = &freq;
for (i = 0; i < hapd->iface->num_hw_features; i++) {
@@ -2675,8 +2676,7 @@
continue;
#ifdef CONFIG_IEEE80211BE
- if (hapd->conf->mld_ap && other->bss[0]->conf->mld_ap &&
- hapd->conf->mld_id == other->bss[0]->conf->mld_id)
+ if (hostapd_is_ml_partner(hapd, other->bss[0]))
mld_ap = true;
#endif /* CONFIG_IEEE80211BE */
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 5378671..eac0606 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -348,11 +348,15 @@
if (sta->supp_op_classes &&
buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
- len += os_snprintf(buf + len, buflen - len, "supp_op_classes=");
+ res = os_snprintf(buf + len, buflen - len, "supp_op_classes=");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
len += wpa_snprintf_hex(buf + len, buflen - len,
sta->supp_op_classes + 1,
sta->supp_op_classes[0]);
- len += os_snprintf(buf + len, buflen - len, "\n");
+ res = os_snprintf(buf + len, buflen - len, "\n");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
}
if (sta->power_capab) {
@@ -364,6 +368,34 @@
len += ret;
}
+#ifdef CONFIG_IEEE80211AX
+ if ((sta->flags & WLAN_STA_HE) && sta->he_capab) {
+ res = os_snprintf(buf + len, buflen - len, "he_capab=");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ len += wpa_snprintf_hex(buf + len, buflen - len,
+ (const u8 *) sta->he_capab,
+ sta->he_capab_len);
+ res = os_snprintf(buf + len, buflen - len, "\n");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ }
+#endif /* CONFIG_IEEE80211AX */
+
+#ifdef CONFIG_IEEE80211BE
+ if ((sta->flags & WLAN_STA_EHT) && sta->eht_capab) {
+ res = os_snprintf(buf + len, buflen - len, "eht_capab=");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ len += wpa_snprintf_hex(buf + len, buflen - len,
+ (const u8 *) sta->eht_capab,
+ sta->eht_capab_len);
+ res = os_snprintf(buf + len, buflen - len, "\n");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ }
+#endif /* CONFIG_IEEE80211BE */
+
#ifdef CONFIG_IEEE80211AC
if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
res = os_snprintf(buf + len, buflen - len,
@@ -372,6 +404,16 @@
vht_capabilities_info));
if (!os_snprintf_error(buflen - len, res))
len += res;
+
+ res = os_snprintf(buf + len, buflen - len, "vht_capab=");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ len += wpa_snprintf_hex(buf + len, buflen - len,
+ (const u8 *) sta->vht_capabilities,
+ sizeof(*sta->vht_capabilities));
+ res = os_snprintf(buf + len, buflen - len, "\n");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
}
#endif /* CONFIG_IEEE80211AC */
@@ -386,11 +428,15 @@
if (sta->ext_capability &&
buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
- len += os_snprintf(buf + len, buflen - len, "ext_capab=");
+ res = os_snprintf(buf + len, buflen - len, "ext_capab=");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
len += wpa_snprintf_hex(buf + len, buflen - len,
sta->ext_capability + 1,
sta->ext_capability[0]);
- len += os_snprintf(buf + len, buflen - len, "\n");
+ res = os_snprintf(buf + len, buflen - len, "\n");
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
}
if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) {
@@ -419,6 +465,21 @@
len += ret;
}
+#ifdef CONFIG_IEEE80211BE
+ if (sta->mld_info.mld_sta) {
+ for (i = 0; i < MAX_NUM_MLD_LINKS; ++i) {
+ if (!sta->mld_info.links[i].valid)
+ continue;
+ ret = os_snprintf(
+ buf + len, buflen - len,
+ "peer_addr[%d]=" MACSTR "\n",
+ i, MAC2STR(sta->mld_info.links[i].peer_addr));
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+ }
+#endif /* CONFIG_IEEE80211BE */
+
return len;
}
@@ -966,8 +1027,8 @@
"mld_addr[%d]=" MACSTR "\n"
"mld_id[%d]=%d\n"
"mld_link_id[%d]=%d\n",
- (int) i, MAC2STR(bss->mld_addr),
- (int) i, bss->conf->mld_id,
+ (int) i, MAC2STR(bss->mld->mld_addr),
+ (int) i, hostapd_get_mld_id(bss),
(int) i, bss->mld_link_id);
if (os_snprintf_error(buflen - len, ret))
return len;
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 5e4c810..af9dc16 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -14,6 +14,7 @@
#include "common/hw_features_common.h"
#include "common/wpa_ctrl.h"
#include "hostapd.h"
+#include "beacon.h"
#include "ap_drv_ops.h"
#include "drivers/driver.h"
#include "dfs.h"
@@ -972,6 +973,7 @@
struct csa_settings csa_settings;
u8 new_vht_oper_chwidth;
unsigned int i;
+ unsigned int num_err = 0;
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", channel);
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
@@ -1009,7 +1011,8 @@
oper_centr_freq_seg1_idx,
cmode->vht_capab,
&cmode->he_capab[ieee80211_mode],
- &cmode->eht_capab[ieee80211_mode]);
+ &cmode->eht_capab[ieee80211_mode],
+ hostapd_get_punct_bitmap(iface->bss[0]));
if (err) {
wpa_printf(MSG_ERROR,
@@ -1021,10 +1024,10 @@
for (i = 0; i < iface->num_bss; i++) {
err = hostapd_switch_channel(iface->bss[i], &csa_settings);
if (err)
- break;
+ num_err++;
}
- if (err) {
+ if (num_err == iface->num_bss) {
wpa_printf(MSG_WARNING,
"DFS failed to schedule CSA (%d) - trying fallback",
err);
@@ -1141,14 +1144,23 @@
int cf1, int cf2)
{
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
- "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
- success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+ "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d radar_detected=%d",
+ success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2,
+ iface->radar_detected);
if (success) {
/* Complete iface/ap configuration */
if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
- /* Complete AP configuration for the first bring up. */
- if (iface->state != HAPD_IFACE_ENABLED)
+ /* Complete AP configuration for the first bring up. If
+ * a radar was detected in this channel, interface setup
+ * will be handled in
+ * 1. hostapd_event_ch_switch() if switching to a
+ * non-DFS channel
+ * 2. on next CAC complete event if switching to another
+ * DFS channel.
+ */
+ if (iface->state != HAPD_IFACE_ENABLED &&
+ !iface->radar_detected)
hostapd_setup_interface_complete(iface, 0);
else
iface->cac_started = 0;
@@ -1193,6 +1205,7 @@
hostapd_dfs_update_background_chain(iface);
}
+ iface->radar_detected = false;
return 0;
}
@@ -1436,6 +1449,8 @@
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+ iface->radar_detected = true;
+
/* Proceed only if DFS is not offloaded to the driver */
if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
return 0;
@@ -1529,9 +1544,17 @@
iface->radar_background.cac_started = 1;
} else {
/* This is called when the driver indicates that an offloaded
- * DFS has started CAC. */
+ * DFS has started CAC. radar_detected might be set for previous
+ * DFS channel. Clear it for this new CAC process. */
hostapd_set_state(iface, HAPD_IFACE_DFS);
iface->cac_started = 1;
+
+ /* Clear radar_detected in case it is for the previous
+ * frequency. Also remove disabled link's information in RNR
+ * element from other links. */
+ iface->radar_detected = false;
+ if (iface->interfaces && iface->interfaces->count > 1)
+ ieee802_11_set_beacons(iface);
}
/* TODO: How to check CAC time for ETSI weather channels? */
iface->dfs_cac_ms = 60000;
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 3f89bc2..d1bffa8 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -3941,6 +3941,7 @@
eloop_register_timeout(100, 0, hostapd_dpp_push_button_expire,
hapd, NULL);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PB_STATUS "started");
return 0;
}
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 533cc54..b0fcd1c 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -517,7 +517,7 @@
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_addr,
+ wpa_auth_set_ml_info(sta->wpa_sm, hapd->mld->mld_addr,
sta->mld_assoc_link_id,
&sta->mld_info);
}
@@ -910,6 +910,54 @@
}
+static void hostapd_remove_sta(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ ap_sta_set_authorized(hapd, sta, 0);
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ hostapd_set_sta_flags(hapd, sta);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
+ sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+ ap_free_sta(hapd, sta);
+}
+
+
+#ifdef CONFIG_IEEE80211BE
+static void hostapd_notif_disassoc_mld(struct hostapd_data *assoc_hapd,
+ struct sta_info *sta,
+ const u8 *addr)
+{
+ unsigned int link_id, i;
+ struct hostapd_data *tmp_hapd;
+ struct hapd_interfaces *interfaces = assoc_hapd->iface->interfaces;
+
+ /* Remove STA entry in non-assoc links */
+ for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
+ if (!sta->mld_info.links[link_id].valid)
+ continue;
+
+ for (i = 0; i < interfaces->count; i++) {
+ struct sta_info *tmp_sta;
+
+ tmp_hapd = interfaces->iface[i]->bss[0];
+
+ if (!tmp_hapd->conf->mld_ap ||
+ assoc_hapd == tmp_hapd ||
+ assoc_hapd->conf->mld_id != tmp_hapd->conf->mld_id)
+ continue;
+
+ tmp_sta = ap_get_sta(tmp_hapd, addr);
+ if (tmp_sta)
+ ap_free_sta(tmp_hapd, tmp_sta);
+ }
+ }
+
+ /* Remove STA in assoc link */
+ hostapd_remove_sta(assoc_hapd, sta);
+}
+#endif /* CONFIG_IEEE80211BE */
+
+
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta;
@@ -931,6 +979,50 @@
HOSTAPD_LEVEL_INFO, "disassociated");
sta = ap_get_sta(hapd, addr);
+#ifdef CONFIG_IEEE80211BE
+ if (hostapd_is_mld_ap(hapd)) {
+ struct hostapd_data *assoc_hapd;
+ unsigned int i;
+
+ if (!sta) {
+ /* Find non-MLO cases from any of the affiliated AP
+ * links. */
+ 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];
+ struct hostapd_bss_config *hconf = h_hapd->conf;
+
+ if (!hconf->mld_ap ||
+ hconf->mld_id != hapd->conf->mld_id)
+ continue;
+
+ sta = ap_get_sta(h_hapd, addr);
+ if (sta) {
+ if (!sta->mld_info.mld_sta) {
+ hapd = h_hapd;
+ goto legacy;
+ }
+ break;
+ }
+ }
+ } else if (!sta->mld_info.mld_sta) {
+ goto legacy;
+ }
+ if (!sta) {
+ wpa_printf(MSG_DEBUG,
+ "Disassociation notification for unknown STA "
+ MACSTR, MAC2STR(addr));
+ return;
+ }
+ sta = hostapd_ml_get_assoc_sta(hapd, sta, &assoc_hapd);
+ if (sta)
+ hostapd_notif_disassoc_mld(assoc_hapd, sta, addr);
+ return;
+ }
+
+legacy:
+#endif /* CONFIG_IEEE80211BE */
if (sta == NULL) {
wpa_printf(MSG_DEBUG,
"Disassociation notification for unknown STA "
@@ -938,13 +1030,7 @@
return;
}
- ap_sta_set_authorized(hapd, sta, 0);
- sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
- hostapd_set_sta_flags(hapd, sta);
- wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
- sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
- ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
- ap_free_sta(hapd, sta);
+ hostapd_remove_sta(hapd, sta);
}
@@ -1663,6 +1749,34 @@
}
+static struct hostapd_data *
+switch_link_scan(struct hostapd_data *hapd, u64 scan_cookie)
+{
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap && scan_cookie != 0) {
+ unsigned int i;
+
+ for (i = 0; i < hapd->iface->interfaces->count; i++) {
+ struct hostapd_iface *h;
+ struct hostapd_data *h_hapd;
+
+ h = hapd->iface->interfaces->iface[i];
+ h_hapd = h->bss[0];
+ if (!hostapd_is_ml_partner(hapd, h_hapd))
+ continue;
+
+ if (h_hapd->scan_cookie == scan_cookie) {
+ h_hapd->scan_cookie = 0;
+ return h_hapd;
+ }
+ }
+ }
+#endif /* CONFIG_IEEE80211BE */
+
+ return hapd;
+}
+
+
#define HAPD_BROADCAST ((struct hostapd_data *) -1)
static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
@@ -1731,7 +1845,7 @@
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap &&
- ether_addr_equal(hapd->mld_addr, bssid))
+ ether_addr_equal(hapd->mld->mld_addr, bssid))
is_mld = true;
#endif /* CONFIG_IEEE80211BE */
@@ -1803,7 +1917,8 @@
hapd = tmp_hapd;
#ifdef CONFIG_IEEE80211BE
} else if (hapd->conf->mld_ap &&
- ether_addr_equal(hapd->mld_addr, get_hdr_bssid(hdr, len))) {
+ ether_addr_equal(hapd->mld->mld_addr,
+ get_hdr_bssid(hdr, len))) {
/* AP MLD address match - use hapd pointer as-is */
#endif /* CONFIG_IEEE80211BE */
} else {
@@ -1878,10 +1993,8 @@
struct hostapd_iface *h =
hapd->iface->interfaces->iface[i];
struct hostapd_data *h_hapd = h->bss[0];
- struct hostapd_bss_config *hconf = h_hapd->conf;
- if (!hconf->mld_ap ||
- hconf->mld_id != hapd->conf->mld_id)
+ if (!hostapd_is_ml_partner(h_hapd, hapd))
continue;
h_hapd = hostapd_find_by_sta(h, src, false);
@@ -2292,8 +2405,29 @@
michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
break;
case EVENT_SCAN_RESULTS:
+#ifdef NEED_AP_MLME
+ if (data)
+ hapd = switch_link_scan(hapd,
+ data->scan_info.scan_cookie);
+#endif /* NEED_AP_MLME */
if (hapd->iface->scan_cb)
hapd->iface->scan_cb(hapd->iface);
+#ifdef CONFIG_IEEE80211BE
+ if (!hapd->iface->scan_cb && hapd->conf->mld_ap) {
+ /* Other links may be waiting for HT scan result */
+ unsigned int i;
+
+ 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) &&
+ h_hapd->iface->scan_cb)
+ h_hapd->iface->scan_cb(h_hapd->iface);
+ }
+ }
+#endif /* CONFIG_IEEE80211BE */
break;
case EVENT_WPS_BUTTON_PUSHED:
hostapd_wps_button_pushed(hapd, NULL);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index ddbcabc..56bac45 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -184,6 +184,8 @@
hostapd_set_generic_elem(hapd, (u8 *) "", 0);
}
+ hostapd_neighbor_sync_own_report(hapd);
+
ieee802_11_set_beacon(hapd);
hostapd_update_wps(hapd);
@@ -395,25 +397,6 @@
#endif /* CONFIG_WEP */
-static void hostapd_clear_drv_priv(struct hostapd_data *hapd)
-{
- unsigned int i;
-
- for (i = 0; i < hapd->iface->interfaces->count; i++) {
- struct hostapd_iface *iface = hapd->iface->interfaces->iface[i];
-
- if (hapd->iface == iface || !iface)
- continue;
-
- if (iface->bss && iface->bss[0] &&
- iface->bss[0]->mld_first_bss == hapd)
- iface->bss[0]->drv_priv = NULL;
- }
-
- hapd->drv_priv = NULL;
-}
-
-
#ifdef CONFIG_IEEE80211BE
#ifdef CONFIG_TESTING_OPTIONS
@@ -435,6 +418,7 @@
ieee802_11_set_beacon(hapd);
if (!hapd->eht_mld_link_removal_count) {
+ hostapd_free_link_stas(hapd);
hostapd_disable_iface(hapd->iface);
return;
}
@@ -496,7 +480,8 @@
vlan_deinit(hapd);
hostapd_acl_deinit(hapd);
#ifndef CONFIG_NO_RADIUS
- if (!hapd->mld_first_bss) {
+ if (hostapd_mld_is_first_bss(hapd)) {
+#ifdef CONFIG_IEEE80211BE
struct hapd_interfaces *ifaces = hapd->iface->interfaces;
size_t i;
@@ -515,6 +500,7 @@
h->radius_das = NULL;
}
}
+#endif /* CONFIG_IEEE80211BE */
radius_client_deinit(hapd->radius);
radius_das_deinit(hapd->radius_das);
}
@@ -548,10 +534,20 @@
* driver wrapper may have removed its internal instance
* and hapd->drv_priv is not valid anymore.
*/
- hostapd_clear_drv_priv(hapd);
+ hapd->drv_priv = NULL;
}
}
+#ifdef CONFIG_IEEE80211BE
+ /* If the interface was not added as well as it is not the first BSS,
+ * at least the link should be removed here since deinit will take care
+ * of only the first BSS. */
+ if (hapd->conf->mld_ap && !hapd->interface_added &&
+ hapd->iface->bss[0] != hapd)
+ hostapd_if_link_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface,
+ hapd->mld_link_id);
+#endif /* CONFIG_IEEE80211BE */
+
wpabuf_free(hapd->time_adv);
hapd->time_adv = NULL;
@@ -614,6 +610,41 @@
}
+/* hostapd_bss_link_deinit - Per-BSS ML cleanup (deinitialization)
+ * @hapd: Pointer to BSS data
+ *
+ * This function is used to unlink the BSS from the AP MLD.
+ * If the BSS being removed is the first link, the next link becomes the first
+ * link.
+ */
+static void hostapd_bss_link_deinit(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_IEEE80211BE
+ if (!hapd->conf || !hapd->conf->mld_ap)
+ return;
+
+ if (!hapd->mld->num_links)
+ return;
+
+ /* If not started, not yet linked to the MLD. However, the first
+ * BSS is always linked since it is linked during driver_init(), and
+ * hence, need to remove it from the AP MLD.
+ */
+ if (!hapd->started && hapd->iface->bss[0] != hapd)
+ return;
+
+ /* The first BSS can also be only linked when at least driver_init() is
+ * executed. But if previous interface fails, it is not, and hence,
+ * safe to skip.
+ */
+ if (hapd->iface->bss[0] == hapd && !hapd->drv_priv)
+ return;
+
+ hostapd_mld_remove_link(hapd);
+#endif /* CONFIG_IEEE80211BE */
+}
+
+
/**
* hostapd_cleanup - Per-BSS cleanup (deinitialization)
* @hapd: Pointer to BSS data
@@ -654,6 +685,7 @@
void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
+ eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
#ifdef NEED_AP_MLME
hostapd_stop_setup_timers(iface);
#endif /* NEED_AP_MLME */
@@ -683,7 +715,6 @@
static void hostapd_cleanup_iface(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
- eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface,
NULL);
@@ -1303,7 +1334,7 @@
u8 if_addr[ETH_ALEN];
int flush_old_stations = 1;
- if (hapd->mld_first_bss)
+ if (!hostapd_mld_is_first_bss(hapd))
wpa_printf(MSG_DEBUG,
"MLD: %s: Setting non-first BSS", __func__);
@@ -1465,7 +1496,7 @@
}
#endif /* CONFIG_SQLITE */
- if (!hapd->mld_first_bss) {
+ if (hostapd_mld_is_first_bss(hapd)) {
hapd->radius = radius_client_init(hapd, conf->radius);
if (!hapd->radius) {
wpa_printf(MSG_ERROR,
@@ -1498,10 +1529,17 @@
}
}
} else {
+#ifdef CONFIG_IEEE80211BE
+ struct hostapd_data *f_bss;
+
wpa_printf(MSG_DEBUG,
"MLD: Using RADIUS client of the first BSS");
- hapd->radius = hapd->mld_first_bss->radius;
- hapd->radius_das = hapd->mld_first_bss->radius_das;
+ f_bss = hostapd_mld_get_first_bss(hapd);
+ if (!f_bss)
+ return -1;
+ hapd->radius = f_bss->radius;
+ hapd->radius_das = f_bss->radius_das;
+#endif /* CONFIG_IEEE80211BE */
}
#endif /* CONFIG_NO_RADIUS */
@@ -1546,6 +1584,7 @@
wpa_printf(MSG_ERROR, "GAS server initialization failed");
return -1;
}
+#endif /* CONFIG_INTERWORKING */
if (conf->qos_map_set_len &&
hostapd_drv_set_qos_map(hapd, conf->qos_map_set,
@@ -1553,7 +1592,6 @@
wpa_printf(MSG_ERROR, "Failed to initialize QoS Map");
return -1;
}
-#endif /* CONFIG_INTERWORKING */
if (conf->bss_load_update_period && bss_load_update_init(hapd)) {
wpa_printf(MSG_ERROR, "BSS Load initialization failed");
@@ -1739,6 +1777,7 @@
static void hostapd_no_ir_cleanup(struct hostapd_data *bss)
{
hostapd_bss_deinit_no_free(bss);
+ hostapd_bss_link_deinit(bss);
hostapd_free_hapd_data(bss);
hostapd_cleanup_iface_partial(bss->iface);
}
@@ -2035,10 +2074,11 @@
} else {
int ret;
- if (iface->conf->acs) {
+ if (iface->conf->acs && !iface->is_ch_switch_dfs) {
iface->freq = 0;
iface->conf->channel = 0;
}
+ iface->is_ch_switch_dfs = false;
ret = configured_fixed_chan_to_freq(iface);
if (ret < 0)
@@ -2797,6 +2837,8 @@
hapd->rad_attr_db = NULL;
}
#endif /* CONFIG_SQLITE */
+
+ hostapd_bss_link_deinit(hapd);
hostapd_cleanup(hapd);
}
@@ -2835,6 +2877,40 @@
}
+#ifdef CONFIG_IEEE80211BE
+
+static void hostapd_mld_ref_inc(struct hostapd_mld *mld)
+{
+ if (!mld)
+ return;
+
+ if (mld->refcount == HOSTAPD_MLD_MAX_REF_COUNT) {
+ wpa_printf(MSG_ERROR, "AP MLD %s: Ref count overflow",
+ mld->name);
+ return;
+ }
+
+ mld->refcount++;
+}
+
+
+static void hostapd_mld_ref_dec(struct hostapd_mld *mld)
+{
+ if (!mld)
+ return;
+
+ if (!mld->refcount) {
+ wpa_printf(MSG_ERROR, "AP MLD %s: Ref count underflow",
+ mld->name);
+ return;
+ }
+
+ mld->refcount--;
+}
+
+#endif /* CONFIG_IEEE80211BE */
+
+
void hostapd_interface_free(struct hostapd_iface *iface)
{
size_t j;
@@ -2842,6 +2918,10 @@
for (j = 0; j < iface->num_bss; j++) {
if (!iface->bss)
break;
+#ifdef CONFIG_IEEE80211BE
+ if (iface->bss[j])
+ hostapd_mld_ref_dec(iface->bss[j]->mld);
+#endif /* CONFIG_IEEE80211BE */
wpa_printf(MSG_DEBUG, "%s: free hapd %p",
__func__, iface->bss[j]);
os_free(iface->bss[j]);
@@ -2864,6 +2944,157 @@
}
+#ifdef CONFIG_IEEE80211BE
+static void hostapd_bss_alloc_link_id(struct hostapd_data *hapd)
+{
+ hapd->mld_link_id = hapd->mld->next_link_id++;
+ wpa_printf(MSG_DEBUG, "AP MLD: %s: Link ID %d assigned.",
+ hapd->mld->name, hapd->mld_link_id);
+}
+#endif /* CONFIG_IEEE80211BE */
+
+
+static void hostapd_bss_setup_multi_link(struct hostapd_data *hapd,
+ struct hapd_interfaces *interfaces)
+{
+#ifdef CONFIG_IEEE80211BE
+ struct hostapd_mld *mld, **all_mld;
+ struct hostapd_bss_config *conf;
+ size_t i;
+
+ conf = hapd->conf;
+
+ if (!hapd->iconf || !hapd->iconf->ieee80211be || !conf->mld_ap ||
+ conf->disable_11be)
+ return;
+
+ for (i = 0; i < interfaces->mld_count; i++) {
+ mld = interfaces->mld[i];
+
+ if (!mld || os_strcmp(conf->iface, mld->name) != 0)
+ continue;
+
+ hapd->mld = mld;
+ hostapd_mld_ref_inc(mld);
+ hostapd_bss_alloc_link_id(hapd);
+ break;
+ }
+
+ if (hapd->mld)
+ return;
+
+ mld = os_zalloc(sizeof(struct hostapd_mld));
+ if (!mld)
+ goto fail;
+
+ os_strlcpy(mld->name, conf->iface, sizeof(conf->iface));
+ dl_list_init(&mld->links);
+
+ wpa_printf(MSG_DEBUG, "AP MLD %s created", mld->name);
+
+ hapd->mld = mld;
+ hostapd_mld_ref_inc(mld);
+ hostapd_bss_alloc_link_id(hapd);
+
+ all_mld = os_realloc_array(interfaces->mld, interfaces->mld_count + 1,
+ sizeof(struct hostapd_mld *));
+ if (!all_mld)
+ goto fail;
+
+ interfaces->mld = all_mld;
+ interfaces->mld[interfaces->mld_count] = mld;
+ interfaces->mld_count++;
+
+ return;
+fail:
+ if (!mld)
+ return;
+
+ wpa_printf(MSG_DEBUG, "AP MLD %s: free mld %p", mld->name, mld);
+ os_free(mld);
+ hapd->mld = NULL;
+#endif /* CONFIG_IEEE80211BE */
+}
+
+
+static void hostapd_cleanup_unused_mlds(struct hapd_interfaces *interfaces)
+{
+#ifdef CONFIG_IEEE80211BE
+ struct hostapd_mld *mld, **all_mld;
+ size_t i, j, num_mlds;
+ bool forced_remove, remove;
+
+ if (!interfaces->mld)
+ return;
+
+ num_mlds = interfaces->mld_count;
+
+ for (i = 0; i < interfaces->mld_count; i++) {
+ mld = interfaces->mld[i];
+ if (!mld)
+ continue;
+
+ remove = false;
+ forced_remove = false;
+
+ if (!mld->refcount)
+ remove = true;
+
+ /* If MLD is still being referenced but the number of interfaces
+ * is zero, it is safe to force its deletion. Normally, this
+ * should not happen but even if it does, let us free the
+ * memory.
+ */
+ if (!remove && !interfaces->count)
+ forced_remove = true;
+
+ if (!remove && !forced_remove)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "AP MLD %s: Freed%s", mld->name,
+ forced_remove ? " (forced)" : "");
+ os_free(mld);
+ interfaces->mld[i] = NULL;
+ num_mlds--;
+ }
+
+ if (!num_mlds) {
+ interfaces->mld_count = 0;
+ os_free(interfaces->mld);
+ interfaces->mld = NULL;
+ return;
+ }
+
+ all_mld = os_zalloc(num_mlds * sizeof(struct hostapd_mld *));
+ if (!all_mld) {
+ wpa_printf(MSG_ERROR,
+ "AP MLD: Failed to re-allocate the MLDs. Expect issues");
+ return;
+ }
+
+ for (i = 0, j = 0; i < interfaces->mld_count; i++) {
+ mld = interfaces->mld[i];
+ if (!mld)
+ continue;
+
+ all_mld[j++] = mld;
+ }
+
+ /* This should not happen */
+ if (j != num_mlds) {
+ wpa_printf(MSG_DEBUG,
+ "AP MLD: Some error occurred while reallocating MLDs. Expect issues.");
+ os_free(all_mld);
+ return;
+ }
+
+ os_free(interfaces->mld);
+ interfaces->mld = all_mld;
+ interfaces->mld_count = num_mlds;
+#endif /* CONFIG_IEEE80211BE */
+}
+
+
/**
* hostapd_init - Allocate and initialize per-interface data
* @config_file: Path to the configuration file
@@ -2907,8 +3138,10 @@
if (hapd == NULL)
goto fail;
hapd->msg_ctx = hapd;
+ hostapd_bss_setup_multi_link(hapd, interfaces);
}
+ hapd_iface->is_ch_switch_dfs = false;
return hapd_iface;
fail:
@@ -3028,6 +3261,8 @@
iface->conf->last_bss = bss;
iface->bss[iface->num_bss] = hapd;
hapd->msg_ctx = hapd;
+ hostapd_bss_setup_multi_link(hapd, interfaces);
+
bss_idx = iface->num_bss++;
conf->num_bss--;
@@ -3061,6 +3296,37 @@
}
+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;
+
+ /* 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
+ * still being used by some other BSS before de-initiallizing. */
+ if (!iface->bss[0]->conf->mld_ap) {
+ driver->hapd_deinit(drv_priv);
+ } else if (hostapd_mld_is_first_bss(iface->bss[0]) &&
+ driver->is_drv_shared &&
+ !driver->is_drv_shared(drv_priv, iface->bss[0])) {
+ driver->hapd_deinit(drv_priv);
+ } else if (hostapd_if_link_remove(iface->bss[0],
+ WPA_IF_AP_BSS,
+ iface->bss[0]->conf->iface,
+ iface->bss[0]->mld_link_id)) {
+ wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s",
+ iface->bss[0]->conf->iface);
+ }
+#else /* CONFIG_IEEE80211BE */
+ driver->hapd_deinit(drv_priv);
+#endif /* CONFIG_IEEE80211BE */
+ iface->bss[0]->drv_priv = NULL;
+}
+
+
void hostapd_interface_deinit_free(struct hostapd_iface *iface)
{
const struct wpa_driver_ops *driver;
@@ -3077,11 +3343,7 @@
hostapd_interface_deinit(iface);
wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
__func__, driver, drv_priv);
- if (driver && driver->hapd_deinit && drv_priv) {
- if (!iface->bss[0]->mld_first_bss)
- driver->hapd_deinit(drv_priv);
- hostapd_clear_drv_priv(iface->bss[0]);
- }
+ hostapd_cleanup_driver(driver, drv_priv, iface);
hostapd_interface_free(iface);
}
@@ -3094,15 +3356,16 @@
wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
__func__, driver, drv_priv);
+
+ hostapd_cleanup_driver(driver, drv_priv, hapd_iface);
+
if (driver && driver->hapd_deinit && drv_priv) {
- if (!hapd_iface->bss[0]->mld_first_bss)
- driver->hapd_deinit(drv_priv);
for (j = 0; j < hapd_iface->num_bss; j++) {
wpa_printf(MSG_DEBUG, "%s:bss[%d]->drv_priv=%p",
__func__, (int) j,
hapd_iface->bss[j]->drv_priv);
if (hapd_iface->bss[j]->drv_priv == drv_priv) {
- hostapd_clear_drv_priv(hapd_iface->bss[j]);
+ hapd_iface->bss[j]->drv_priv = NULL;
hapd_iface->extended_capa = NULL;
hapd_iface->extended_capa_mask = NULL;
hapd_iface->extended_capa_len = 0;
@@ -3112,6 +3375,22 @@
}
+static void hostapd_refresh_all_iface_beacons(struct hostapd_iface *hapd_iface)
+{
+ size_t j;
+
+ if (!hapd_iface->interfaces || hapd_iface->interfaces->count <= 1)
+ return;
+
+ for (j = 0; j < hapd_iface->interfaces->count; j++) {
+ if (hapd_iface->interfaces->iface[j] == hapd_iface)
+ continue;
+
+ ieee802_11_update_beacons(hapd_iface->interfaces->iface[j]);
+ }
+}
+
+
int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
{
size_t j;
@@ -3150,6 +3429,8 @@
return -1;
}
+ hostapd_refresh_all_iface_beacons(hapd_iface);
+
return 0;
}
@@ -3207,31 +3488,6 @@
return -1;
}
-#ifdef CONFIG_IEEE80211BE
- if (hapd_iface->bss[0]->conf->mld_ap &&
- !hapd_iface->bss[0]->mld_first_bss) {
- /* Do not allow mld_first_bss disabling before other BSSs */
- for (j = 0; j < hapd_iface->interfaces->count; ++j) {
- struct hostapd_iface *h_iface =
- hapd_iface->interfaces->iface[j];
- struct hostapd_data *h_hapd = h_iface->bss[0];
- struct hostapd_bss_config *h_conf = h_hapd->conf;
-
- if (!h_conf->mld_ap ||
- h_conf->mld_id !=
- hapd_iface->bss[0]->conf->mld_id ||
- h_iface == hapd_iface)
- continue;
-
- if (h_iface->state != HAPD_IFACE_DISABLED) {
- wpa_printf(MSG_INFO,
- "Do not allow disable mld_first_bss first");
- return -1;
- }
- }
- }
-#endif /* CONFIG_IEEE80211BE */
-
wpa_msg(hapd_iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
driver = hapd_iface->bss[0]->driver;
drv_priv = hapd_iface->bss[0]->drv_priv;
@@ -3249,6 +3505,7 @@
for (j = 0; j < hapd_iface->num_bss; j++) {
struct hostapd_data *hapd = hapd_iface->bss[j];
hostapd_bss_deinit_no_free(hapd);
+ hostapd_bss_link_deinit(hapd);
hostapd_free_hapd_data(hapd);
}
@@ -3262,6 +3519,7 @@
wpa_printf(MSG_DEBUG, "Interface %s disabled",
hapd_iface->bss[0]->conf->iface);
hostapd_set_state(hapd_iface, HAPD_IFACE_DISABLED);
+ hostapd_refresh_all_iface_beacons(hapd_iface);
return 0;
}
@@ -3370,6 +3628,7 @@
return -1;
}
hapd->msg_ctx = hapd;
+ hostapd_bss_setup_multi_link(hapd, hapd_iface->interfaces);
}
hapd_iface->conf = conf;
@@ -3443,6 +3702,7 @@
if (start_ctrl_iface_bss(hapd) < 0 ||
(hapd_iface->state == HAPD_IFACE_ENABLED &&
hostapd_setup_bss(hapd, -1, true))) {
+ hostapd_bss_link_deinit(hapd);
hostapd_cleanup(hapd);
hapd_iface->bss[hapd_iface->num_bss - 1] = NULL;
hapd_iface->conf->num_bss--;
@@ -3451,6 +3711,9 @@
__func__, hapd, hapd->conf->iface);
hostapd_config_free_bss(hapd->conf);
hapd->conf = NULL;
+#ifdef CONFIG_IEEE80211BE
+ hostapd_mld_ref_dec(hapd->mld);
+#endif /* CONFIG_IEEE80211BE */
os_free(hapd);
return -1;
}
@@ -3540,7 +3803,11 @@
wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
__func__, hapd_iface->bss[i],
hapd->conf->iface);
+ hostapd_bss_link_deinit(hapd);
hostapd_cleanup(hapd);
+#ifdef CONFIG_IEEE80211BE
+ hostapd_mld_ref_dec(hapd->mld);
+#endif /* CONFIG_IEEE80211BE */
os_free(hapd);
hapd_iface->bss[i] = NULL;
}
@@ -3550,6 +3817,7 @@
if (new_iface) {
interfaces->count--;
interfaces->iface[interfaces->count] = NULL;
+ hostapd_cleanup_unused_mlds(interfaces);
}
hostapd_cleanup_iface(hapd_iface);
}
@@ -3572,6 +3840,9 @@
__func__, hapd, hapd->conf->iface);
hostapd_config_free_bss(hapd->conf);
hapd->conf = NULL;
+#ifdef CONFIG_IEEE80211BE
+ hostapd_mld_ref_dec(hapd->mld);
+#endif /* CONFIG_IEEE80211BE */
os_free(hapd);
iface->num_bss--;
@@ -3614,6 +3885,8 @@
k++;
}
interfaces->count--;
+ hostapd_cleanup_unused_mlds(interfaces);
+
return 0;
}
@@ -3913,7 +4186,8 @@
mode ? &mode->he_capab[IEEE80211_MODE_AP] :
NULL,
mode ? &mode->eht_capab[IEEE80211_MODE_AP] :
- NULL))
+ NULL,
+ hostapd_get_punct_bitmap(hapd)))
return -1;
switch (params->bandwidth) {
@@ -4403,6 +4677,7 @@
#ifdef CONFIG_IEEE80211BE
+
struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd,
u8 link_id)
{
@@ -4411,9 +4686,8 @@
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];
- struct hostapd_bss_config *hconf = h_hapd->conf;
- if (!hconf->mld_ap || hconf->mld_id != hapd->conf->mld_id)
+ if (!hostapd_is_ml_partner(hapd, h_hapd))
continue;
if (h_hapd->mld_link_id == link_id)
@@ -4422,4 +4696,141 @@
return NULL;
}
+
+
+bool hostapd_is_ml_partner(struct hostapd_data *hapd1,
+ struct hostapd_data *hapd2)
+{
+ if (!hapd1->conf->mld_ap || !hapd2->conf->mld_ap)
+ return false;
+
+ return !os_strcmp(hapd1->conf->iface, hapd2->conf->iface);
+}
+
+
+u8 hostapd_get_mld_id(struct hostapd_data *hapd)
+{
+ if (!hapd->conf->mld_ap)
+ return 255;
+
+ /* MLD ID 0 represents self */
+ return 0;
+
+ /* TODO: MLD ID for Multiple BSS cases */
+}
+
+
+int hostapd_mld_add_link(struct hostapd_data *hapd)
+{
+ struct hostapd_mld *mld = hapd->mld;
+
+ if (!hapd->conf->mld_ap)
+ return 0;
+
+ /* Should not happen */
+ if (!mld)
+ return -1;
+
+ dl_list_add_tail(&mld->links, &hapd->link);
+ mld->num_links++;
+
+ wpa_printf(MSG_DEBUG, "AP MLD %s: Link ID %d added. num_links: %d",
+ mld->name, hapd->mld_link_id, mld->num_links);
+
+ if (mld->fbss)
+ return 0;
+
+ mld->fbss = hapd;
+ wpa_printf(MSG_DEBUG, "AP MLD %s: First link BSS set to %p",
+ mld->name, mld->fbss);
+ return 0;
+}
+
+
+int hostapd_mld_remove_link(struct hostapd_data *hapd)
+{
+ struct hostapd_mld *mld = hapd->mld;
+ struct hostapd_data *next_fbss;
+
+ if (!hapd->conf->mld_ap)
+ return 0;
+
+ /* Should not happen */
+ if (!mld)
+ return -1;
+
+ dl_list_del(&hapd->link);
+ mld->num_links--;
+
+ wpa_printf(MSG_DEBUG, "AP MLD %s: Link ID %d removed. num_links: %d",
+ mld->name, hapd->mld_link_id, mld->num_links);
+
+ if (mld->fbss != hapd)
+ return 0;
+
+ /* If the list is empty, all links are removed */
+ if (dl_list_empty(&mld->links)) {
+ mld->fbss = NULL;
+ } else {
+ next_fbss = dl_list_entry(mld->links.next, struct hostapd_data,
+ link);
+ mld->fbss = next_fbss;
+ }
+
+ wpa_printf(MSG_DEBUG, "AP MLD %s: First link BSS set to %p",
+ mld->name, mld->fbss);
+ return 0;
+}
+
+
+bool hostapd_mld_is_first_bss(struct hostapd_data *hapd)
+{
+ struct hostapd_mld *mld = hapd->mld;
+
+ if (!hapd->conf->mld_ap)
+ return true;
+
+ /* Should not happen */
+ if (!mld)
+ return false;
+
+ /* If fbss is not set, it is safe to assume the caller is the first BSS.
+ */
+ if (!mld->fbss)
+ return true;
+
+ return hapd == mld->fbss;
+}
+
+
+struct hostapd_data * hostapd_mld_get_first_bss(struct hostapd_data *hapd)
+{
+ struct hostapd_mld *mld = hapd->mld;
+
+ if (!hapd->conf->mld_ap)
+ return NULL;
+
+ /* Should not happen */
+ if (!mld)
+ return NULL;
+
+ return mld->fbss;
+}
+
#endif /* CONFIG_IEEE80211BE */
+
+
+u16 hostapd_get_punct_bitmap(struct hostapd_data *hapd)
+{
+ u16 punct_bitmap = 0;
+
+#ifdef CONFIG_IEEE80211BE
+ punct_bitmap = hapd->iconf->punct_bitmap;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (!punct_bitmap)
+ punct_bitmap = hapd->conf->eht_oper_puncturing_override;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_IEEE80211BE */
+
+ return punct_bitmap;
+}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index bcf980f..ff29726 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -44,6 +44,7 @@
#endif /* CONFIG_CTRL_IFACE_UDP */
struct hostapd_iface;
+struct hostapd_mld;
struct hapd_interfaces {
int (*reload_config)(struct hostapd_iface *iface);
@@ -93,6 +94,10 @@
unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN];
#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_IEEE80211BE
+ struct hostapd_mld **mld;
+ size_t mld_count;
+#endif /* CONFIG_IEEE80211BE */
};
enum hostapd_chan_status {
@@ -175,12 +180,6 @@
unsigned int reenable_beacon:1;
u8 own_addr[ETH_ALEN];
- u8 mld_addr[ETH_ALEN];
- u8 mld_link_id;
- /* Used for mld_link_id assignment - valid on the first MLD BSS only */
- u8 mld_next_link_id;
-
- struct hostapd_data *mld_first_bss;
int num_sta; /* number of entries in sta_list */
struct sta_info *sta_list; /* STA info list head */
@@ -406,8 +405,10 @@
u8 beacon_req_token;
u8 lci_req_token;
u8 range_req_token;
+ u8 link_measurement_req_token;
unsigned int lci_req_active:1;
unsigned int range_req_active:1;
+ unsigned int link_mesr_req_active:1;
int dhcp_sock; /* UDP socket used with the DHCP server */
@@ -472,6 +473,9 @@
#ifdef CONFIG_IEEE80211BE
u8 eht_mld_bss_param_change;
+ struct hostapd_mld *mld;
+ struct dl_list link;
+ u8 mld_link_id;
#ifdef CONFIG_TESTING_OPTIONS
u8 eht_mld_link_removal_count;
#endif /* CONFIG_TESTING_OPTIONS */
@@ -480,6 +484,9 @@
#ifdef CONFIG_NAN_USD
struct nan_de *nan_de;
#endif /* CONFIG_NAN_USD */
+
+ u64 scan_cookie; /* Scan instance identifier for the ongoing HT40 scan
+ */
};
@@ -504,6 +511,29 @@
HAPD_IFACE_ENABLED
};
+#ifdef CONFIG_IEEE80211BE
+/**
+ * struct hostapd_mld - hostapd per-mld data structure
+ */
+struct hostapd_mld {
+ char name[IFNAMSIZ + 1];
+ u8 mld_addr[ETH_ALEN];
+ u8 next_link_id;
+ u8 num_links;
+ /* Number of hostapd_data (hapd) referencing this. num_links cannot be
+ * used since num_links can go to 0 even when a BSS is disabled and
+ * when it is re-enabled, the MLD should exist and hence it cannot be
+ * freed when num_links is 0.
+ */
+ u8 refcount;
+
+ struct hostapd_data *fbss;
+ struct dl_list links; /* List head of all affiliated links */
+};
+
+#define HOSTAPD_MLD_MAX_REF_COUNT 0xFF
+#endif /* CONFIG_IEEE80211BE */
+
/**
* struct hostapd_iface - hostapd per-interface data structure
*/
@@ -551,6 +581,7 @@
u64 drv_flags;
u64 drv_flags2;
+ unsigned int drv_rrm_flags;
/*
* A bitmap of supported protocols for probe response offload. See
@@ -576,6 +607,8 @@
int *basic_rates;
int freq;
+ bool radar_detected;
+
/* Background radar configuration */
struct {
int channel;
@@ -677,6 +710,8 @@
/* Configured freq of interface is NO_IR */
bool is_no_ir;
+
+ bool is_ch_switch_dfs; /* Channel switch from ACS to DFS */
};
/* hostapd.c */
@@ -783,8 +818,17 @@
struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd,
u8 link_id);
int hostapd_link_remove(struct hostapd_data *hapd, u32 count);
+bool hostapd_is_ml_partner(struct hostapd_data *hapd1,
+ struct hostapd_data *hapd2);
+u8 hostapd_get_mld_id(struct hostapd_data *hapd);
+int hostapd_mld_add_link(struct hostapd_data *hapd);
+int hostapd_mld_remove_link(struct hostapd_data *hapd);
+struct hostapd_data * hostapd_mld_get_first_bss(struct hostapd_data *hapd);
#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; \
@@ -796,11 +840,21 @@
for (_link = \
(_ifaces)->iface[_iface_idx]->bss[_bss_idx]; \
_link && _link->conf->mld_ap && \
- _link->conf->mld_id == _mld_id; \
+ hostapd_get_mld_id(_link) == _mld_id; \
_link = NULL)
+
#else /* CONFIG_IEEE80211BE */
+
+static inline bool hostapd_mld_is_first_bss(struct hostapd_data *hapd)
+{
+ return true;
+}
+
#define for_each_mld_link(_link, _bss_idx, _iface_idx, _ifaces, _mld_id) \
if (false)
+
#endif /* CONFIG_IEEE80211BE */
+u16 hostapd_get_punct_bitmap(struct hostapd_data *hapd);
+
#endif /* HOSTAPD_H */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 596f2f0..c455660 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -107,9 +107,7 @@
*/
orig_mode_valid = true;
mode = iface->current_mode->mode;
- is_6ghz = mode == HOSTAPD_MODE_IEEE80211A &&
- iface->current_mode->num_channels > 0 &&
- is_6ghz_freq(iface->current_mode->channels[0].freq);
+ is_6ghz = iface->current_mode->is_6ghz;
iface->current_mode = NULL;
}
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
@@ -508,6 +506,12 @@
else
ieee80211n_scan_channels_5g(iface, ¶ms);
+ params.link_id = -1;
+#ifdef CONFIG_IEEE80211BE
+ if (iface->bss[0]->conf->mld_ap)
+ params.link_id = iface->bss[0]->mld_link_id;
+#endif /* CONFIG_IEEE80211BE */
+
ret = hostapd_driver_scan(iface->bss[0], ¶ms);
iface->num_ht40_scan_tries++;
os_free(params.freqs);
@@ -523,6 +527,7 @@
if (ret == 0) {
iface->scan_cb = ieee80211n_check_scan;
+ iface->bss[0]->scan_cookie = params.scan_cookie;
return;
}
@@ -558,6 +563,11 @@
else
ieee80211n_scan_channels_5g(iface, ¶ms);
+ params.link_id = -1;
+#ifdef CONFIG_IEEE80211BE
+ if (iface->bss[0]->conf->mld_ap)
+ params.link_id = iface->bss[0]->mld_link_id;
+#endif /* CONFIG_IEEE80211BE */
ret = hostapd_driver_scan(iface->bss[0], ¶ms);
os_free(params.freqs);
@@ -579,6 +589,7 @@
}
iface->scan_cb = ieee80211n_check_scan;
+ iface->bss[0]->scan_cookie = params.scan_cookie;
return 1;
}
@@ -1070,9 +1081,7 @@
return true;
if (is_6ghz_op_class(iface->conf->op_class) && iface->freq == 0 &&
- (mode->mode != HOSTAPD_MODE_IEEE80211A ||
- mode->num_channels == 0 ||
- !is_6ghz_freq(mode->channels[0].freq)))
+ !mode->is_6ghz)
return true;
return false;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 8b8c1f0..85a39d5 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -88,18 +88,31 @@
struct sta_info *sta, int reassoc);
-u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid)
+static u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid, size_t len)
{
- u8 multi_ap_val = 0;
+ struct multi_ap_params multi_ap = { 0 };
if (!hapd->conf->multi_ap)
return eid;
- if (hapd->conf->multi_ap & BACKHAUL_BSS)
- multi_ap_val |= MULTI_AP_BACKHAUL_BSS;
- if (hapd->conf->multi_ap & FRONTHAUL_BSS)
- multi_ap_val |= MULTI_AP_FRONTHAUL_BSS;
- return eid + add_multi_ap_ie(eid, 9, multi_ap_val);
+ if (hapd->conf->multi_ap & BACKHAUL_BSS)
+ multi_ap.capability |= MULTI_AP_BACKHAUL_BSS;
+ if (hapd->conf->multi_ap & FRONTHAUL_BSS)
+ multi_ap.capability |= MULTI_AP_FRONTHAUL_BSS;
+
+ if (hapd->conf->multi_ap_client_disallow &
+ PROFILE1_CLIENT_ASSOC_DISALLOW)
+ multi_ap.capability |=
+ MULTI_AP_PROFILE1_BACKHAUL_STA_DISALLOWED;
+ if (hapd->conf->multi_ap_client_disallow &
+ PROFILE2_CLIENT_ASSOC_DISALLOW)
+ multi_ap.capability |=
+ MULTI_AP_PROFILE2_BACKHAUL_STA_DISALLOWED;
+
+ multi_ap.profile = hapd->conf->multi_ap_profile;
+ multi_ap.vlanid = hapd->conf->multi_ap_vlanid;
+
+ return eid + add_multi_ap_ie(eid, len, &multi_ap);
}
@@ -409,7 +422,7 @@
* the addresses.
*/
if (ap_sta_is_mld(hapd, sta)) {
- sa = hapd->mld_addr;
+ sa = hapd->mld->mld_addr;
ml_resp = hostapd_ml_auth_resp(hapd);
if (!ml_resp)
@@ -610,7 +623,7 @@
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta))
- own_addr = hapd->mld_addr;
+ own_addr = hapd->mld->mld_addr;
#endif /* CONFIG_IEEE80211BE */
if (sta->sae->tmp) {
@@ -2390,7 +2403,7 @@
wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS ANonce",
fils->anonce, FILS_NONCE_LEN);
- ret = fils_rmsk_to_pmk(pasn->akmp, msk, msk_len, fils->nonce,
+ ret = fils_rmsk_to_pmk(pasn_get_akmp(pasn), msk, msk_len, fils->nonce,
fils->anonce, NULL, 0, pmk, &pmk_len);
if (ret) {
wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
@@ -2400,15 +2413,16 @@
ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
wpabuf_head(pasn->secret),
wpabuf_len(pasn->secret),
- &sta->pasn->ptk, sta->pasn->akmp,
- sta->pasn->cipher, sta->pasn->kdk_len);
+ pasn_get_ptk(sta->pasn), pasn_get_akmp(sta->pasn),
+ pasn_get_cipher(sta->pasn), sta->pasn->kdk_len);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
goto fail;
}
if (pasn->secure_ltf) {
- ret = wpa_ltf_keyseed(&pasn->ptk, pasn->akmp, pasn->cipher);
+ ret = wpa_ltf_keyseed(pasn_get_ptk(pasn), pasn_get_akmp(pasn),
+ pasn_get_cipher(pasn));
if (ret) {
wpa_printf(MSG_DEBUG,
"PASN: FILS: Failed to derive LTF keyseed");
@@ -2554,7 +2568,8 @@
* Calculate pending PMKID here so that we do not need to maintain a
* copy of the EAP-Initiate/Reautt message.
*/
- fils_pmkid_erp(pasn->akmp, wpabuf_head(fils_wd), wpabuf_len(fils_wd),
+ fils_pmkid_erp(pasn_get_akmp(pasn),
+ wpabuf_head(fils_wd), wpabuf_len(fils_wd),
fils->erp_pmkid);
wpabuf_free(fils_wd);
@@ -2579,32 +2594,35 @@
{
struct pasn_data *pasn = sta->pasn;
- pasn->cb_ctx = hapd;
- pasn->send_mgmt = hapd_pasn_send_mlme;
+ pasn_register_callbacks(pasn, hapd, hapd_pasn_send_mlme, NULL);
+ pasn_set_bssid(pasn, hapd->own_addr);
+ pasn_set_own_addr(pasn, hapd->own_addr);
+ pasn_set_peer_addr(pasn, sta->addr);
+ pasn_set_wpa_key_mgmt(pasn, hapd->conf->wpa_key_mgmt);
+ pasn_set_rsn_pairwise(pasn, hapd->conf->rsn_pairwise);
pasn->pasn_groups = hapd->conf->pasn_groups;
pasn->noauth = hapd->conf->pasn_noauth;
- pasn->wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
- pasn->rsn_pairwise = hapd->conf->rsn_pairwise;
- pasn->derive_kdk = hapd->iface->drv_flags2 &
- WPA_DRIVER_FLAGS2_SEC_LTF_AP;
+ if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_AP)
+ pasn_enable_kdk_derivation(pasn);
+
#ifdef CONFIG_TESTING_OPTIONS
pasn->corrupt_mic = hapd->conf->pasn_corrupt_mic;
if (hapd->conf->force_kdk_derivation)
- pasn->derive_kdk = true;
+ pasn_enable_kdk_derivation(pasn);
#endif /* CONFIG_TESTING_OPTIONS */
pasn->use_anti_clogging = use_anti_clogging(hapd);
- pasn->password = sae_get_password(hapd, sta, NULL, NULL, &pasn->pt,
- NULL);
+ pasn_set_password(pasn, sae_get_password(hapd, sta, NULL, NULL,
+ &pasn->pt, NULL));
pasn->rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &pasn->rsn_ie_len);
- pasn->rsnxe_ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
+ pasn_set_rsnxe_ie(pasn, hostapd_wpa_ie(hapd, WLAN_EID_RSNX));
pasn->disable_pmksa_caching = hapd->conf->disable_pmksa_caching;
- pasn->pmksa = wpa_auth_get_pmksa_cache(hapd->wpa_auth);
+ pasn_set_responder_pmksa(pasn,
+ wpa_auth_get_pmksa_cache(hapd->wpa_auth));
pasn->comeback_after = hapd->conf->pasn_comeback_after;
pasn->comeback_idx = hapd->comeback_idx;
pasn->comeback_key = hapd->comeback_key;
pasn->comeback_pending_idx = hapd->comeback_pending_idx;
- os_memcpy(pasn->bssid, hapd->own_addr, ETH_ALEN);
}
@@ -2652,6 +2670,7 @@
struct wpa_pasn_params_data pasn_params;
struct wpabuf *wrapped_data = NULL;
#endif /* CONFIG_FILS */
+ int akmp;
if (ieee802_11_parse_elems(mgmt->u.auth.variable,
len - offsetof(struct ieee80211_mgmt,
@@ -2675,10 +2694,12 @@
return;
}
- pasn->akmp = rsn_data.key_mgmt;
- pasn->cipher = rsn_data.pairwise_cipher;
+ pasn_set_akmp(pasn, rsn_data.key_mgmt);
+ pasn_set_cipher(pasn, rsn_data.pairwise_cipher);
- if (wpa_key_mgmt_ft(pasn->akmp) && rsn_data.num_pmkid) {
+ akmp = pasn_get_akmp(pasn);
+
+ if (wpa_key_mgmt_ft(akmp) && rsn_data.num_pmkid) {
#ifdef CONFIG_IEEE80211R_AP
pasn->pmk_r1_len = 0;
wpa_ft_fetch_pmk_r1(hapd->wpa_auth, sta->addr,
@@ -2689,8 +2710,8 @@
#endif /* CONFIG_IEEE80211R_AP */
}
#ifdef CONFIG_FILS
- if (pasn->akmp != WPA_KEY_MGMT_FILS_SHA256 &&
- pasn->akmp != WPA_KEY_MGMT_FILS_SHA384)
+ if (akmp != WPA_KEY_MGMT_FILS_SHA256 &&
+ akmp != WPA_KEY_MGMT_FILS_SHA384)
return;
if (!elems.pasn_params ||
wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
@@ -2743,7 +2764,7 @@
return;
}
- sta->pasn = os_zalloc(sizeof(*sta->pasn));
+ sta->pasn = pasn_data_init();
if (!sta->pasn) {
wpa_printf(MSG_DEBUG,
"PASN: Failed to allocate PASN context");
@@ -2773,13 +2794,14 @@
if (handle_auth_pasn_3(sta->pasn, hapd->own_addr,
sta->addr, mgmt, len) == 0) {
ptksa_cache_add(hapd->ptksa, hapd->own_addr, sta->addr,
- sta->pasn->cipher, 43200,
- &sta->pasn->ptk, NULL, NULL,
- sta->pasn->akmp);
+ pasn_get_cipher(sta->pasn), 43200,
+ pasn_get_ptk(sta->pasn), NULL, NULL,
+ pasn_get_akmp(sta->pasn));
pasn_set_keys_from_cache(hapd, hapd->own_addr,
- sta->addr, sta->pasn->cipher,
- sta->pasn->akmp);
+ sta->addr,
+ pasn_get_cipher(sta->pasn),
+ pasn_get_akmp(sta->pasn));
}
ap_free_sta(hapd, sta);
} else {
@@ -2806,7 +2828,9 @@
u16 seq_ctrl;
struct radius_sta rad_info;
const u8 *dst, *sa, *bssid;
+#ifdef CONFIG_IEEE80211BE
bool mld_sta = false;
+#endif /* CONFIG_IEEE80211BE */
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
@@ -2924,15 +2948,17 @@
goto fail;
}
+#ifdef CONFIG_IEEE80211BE
if (mld_sta &&
(ether_addr_equal(sa, hapd->own_addr) ||
- ether_addr_equal(sa, hapd->mld_addr))) {
+ ether_addr_equal(sa, hapd->mld->mld_addr))) {
wpa_printf(MSG_INFO,
"Station " MACSTR " not allowed to authenticate",
MAC2STR(sa));
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
+#endif /* CONFIG_IEEE80211BE */
if (hapd->conf->no_auth_if_seen_on) {
struct hostapd_data *other;
@@ -3032,15 +3058,6 @@
seq_ctrl);
return;
}
-#ifdef CONFIG_MESH
- if ((hapd->conf->mesh & MESH_ENABLED) &&
- sta->plink_state == PLINK_BLOCKED) {
- wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
- " is blocked - drop Authentication frame",
- MAC2STR(sa));
- return;
- }
-#endif /* CONFIG_MESH */
#ifdef CONFIG_PASN
if (auth_alg == WLAN_AUTH_PASN &&
(sta->flags & WLAN_STA_ASSOC)) {
@@ -3078,7 +3095,12 @@
}
#ifdef CONFIG_IEEE80211BE
- if (auth_transaction == 1) {
+ /* Set the non-AP MLD information based on the initial Authentication
+ * frame. Once the STA entry has been added to the driver, the driver
+ * will translate addresses in the frame and we need to avoid overriding
+ * peer_addr based on mgmt->sa which would have been translated to the
+ * MLD MAC address. */
+ if (!sta->added_unassoc && auth_transaction == 1) {
ap_sta_free_sta_profile(&sta->mld_info);
os_memset(&sta->mld_info, 0, sizeof(sta->mld_info));
@@ -3250,7 +3272,7 @@
*/
if (ap_sta_is_mld(hapd, sta)) {
dst = sta->addr;
- bssid = hapd->mld_addr;
+ bssid = hapd->mld->mld_addr;
}
#endif /* CONFIG_IEEE80211BE */
@@ -3410,37 +3432,58 @@
static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *multi_ap_ie, size_t multi_ap_len)
{
- u8 multi_ap_value = 0;
+ struct multi_ap_params multi_ap;
+ u16 status;
sta->flags &= ~WLAN_STA_MULTI_AP;
if (!hapd->conf->multi_ap)
return WLAN_STATUS_SUCCESS;
- if (multi_ap_ie) {
- const u8 *multi_ap_subelem;
-
- multi_ap_subelem = get_ie(multi_ap_ie + 4,
- multi_ap_len - 4,
- MULTI_AP_SUB_ELEM_TYPE);
- if (multi_ap_subelem && multi_ap_subelem[1] == 1) {
- multi_ap_value = multi_ap_subelem[2];
- } else {
+ if (!multi_ap_ie) {
+ if (!(hapd->conf->multi_ap & FRONTHAUL_BSS)) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
- "Multi-AP IE has missing or invalid Multi-AP subelement");
- return WLAN_STATUS_INVALID_IE;
+ "Non-Multi-AP STA tries to associate with backhaul-only BSS");
+ return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
}
+
+ return WLAN_STATUS_SUCCESS;
}
- if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA)
+ status = check_multi_ap_ie(multi_ap_ie + 4, multi_ap_len - 4,
+ &multi_ap);
+ if (status != WLAN_STATUS_SUCCESS)
+ return status;
+
+ if (multi_ap.capability && multi_ap.capability != MULTI_AP_BACKHAUL_STA)
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
"Multi-AP IE with unexpected value 0x%02x",
- multi_ap_value);
+ multi_ap.capability);
- if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) {
+ if (multi_ap.profile == MULTI_AP_PROFILE_1 &&
+ (hapd->conf->multi_ap_client_disallow &
+ PROFILE1_CLIENT_ASSOC_DISALLOW)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Multi-AP Profile-1 clients not allowed");
+ return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+ }
+
+ if (multi_ap.profile >= MULTI_AP_PROFILE_2 &&
+ (hapd->conf->multi_ap_client_disallow &
+ PROFILE2_CLIENT_ASSOC_DISALLOW)) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Multi-AP Profile-2 clients not allowed");
+ return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+ }
+
+ if (!(multi_ap.capability & MULTI_AP_BACKHAUL_STA)) {
if (hapd->conf->multi_ap & FRONTHAUL_BSS)
return WLAN_STATUS_SUCCESS;
@@ -3740,7 +3783,7 @@
}
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta))
- wpa_auth_set_ml_info(sta->wpa_sm, hapd->mld_addr,
+ wpa_auth_set_ml_info(sta->wpa_sm, hapd->mld->mld_addr,
sta->mld_assoc_link_id, &sta->mld_info);
#endif /* CONFIG_IEEE80211BE */
rsn_ie -= 2;
@@ -4025,7 +4068,7 @@
wpa_printf(MSG_DEBUG,
"MLD: Set ML info in RSN Authenticator");
wpa_auth_set_ml_info(sta->wpa_sm,
- hapd->mld_addr,
+ hapd->mld->mld_addr,
sta->mld_assoc_link_id,
info);
}
@@ -4559,8 +4602,7 @@
if (hapd->iface == iface)
continue;
- if (iface->bss[0]->conf->mld_ap &&
- hapd->conf->mld_id == iface->bss[0]->conf->mld_id &&
+ if (hostapd_is_ml_partner(hapd, iface->bss[0]) &&
i == iface->bss[0]->mld_link_id)
break;
}
@@ -4787,7 +4829,7 @@
* MLD MAC address.
*/
if (ap_sta_is_mld(hapd, sta) && allow_mld_addr_trans)
- sa = hapd->mld_addr;
+ sa = hapd->mld->mld_addr;
#endif /* CONFIG_IEEE80211BE */
os_memcpy(reply->da, addr, ETH_ALEN);
@@ -4991,7 +5033,7 @@
#endif /* CONFIG_WPS */
if (sta && (sta->flags & WLAN_STA_MULTI_AP))
- p = hostapd_eid_multi_ap(hapd, p);
+ p = hostapd_eid_multi_ap(hapd, p, buf + buflen - p);
#ifdef CONFIG_P2P
if (sta && sta->p2p_ie && hapd->p2p_group) {
@@ -5775,8 +5817,7 @@
tmp_hapd =
assoc_hapd->iface->interfaces->iface[i]->bss[0];
- if (!tmp_hapd->conf->mld_ap ||
- assoc_hapd->conf->mld_id != tmp_hapd->conf->mld_id)
+ if (!hostapd_is_ml_partner(assoc_hapd, tmp_hapd))
continue;
for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
@@ -6206,7 +6247,7 @@
#endif /* CONFIG_MESH */
#ifdef CONFIG_IEEE80211BE
!(hapd->conf->mld_ap &&
- ether_addr_equal(hapd->mld_addr, mgmt->bssid)) &&
+ ether_addr_equal(hapd->mld->mld_addr, mgmt->bssid)) &&
#endif /* CONFIG_IEEE80211BE */
!ether_addr_equal(mgmt->bssid, hapd->own_addr)) {
wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
@@ -6229,7 +6270,7 @@
stype != WLAN_FC_STYPE_ACTION) &&
#ifdef CONFIG_IEEE80211BE
!(hapd->conf->mld_ap &&
- ether_addr_equal(hapd->mld_addr, mgmt->bssid)) &&
+ ether_addr_equal(hapd->mld->mld_addr, mgmt->bssid)) &&
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_NAN_USD
!ether_addr_equal(mgmt->da, nan_network_id) &&
@@ -6443,8 +6484,7 @@
struct hostapd_data *tmp_hapd =
hapd->iface->interfaces->iface[i]->bss[0];
- if (!tmp_hapd->conf->mld_ap ||
- hapd->conf->mld_id != tmp_hapd->conf->mld_id)
+ if (!hostapd_is_ml_partner(tmp_hapd, hapd))
continue;
for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
@@ -7407,12 +7447,12 @@
bool ap_mld = false;
#ifdef CONFIG_IEEE80211BE
- if (hapd->conf->mld_ap && iface->bss[0]->conf->mld_ap &&
- hapd->conf->mld_id == iface->bss[0]->conf->mld_id)
+ if (hostapd_is_ml_partner(hapd, iface->bss[0]))
ap_mld = true;
#endif /* CONFIG_IEEE80211BE */
if (iface == hapd->iface ||
+ iface->state != HAPD_IFACE_ENABLED ||
!(is_6ghz_op_class(iface->conf->op_class) || ap_mld))
continue;
@@ -7580,11 +7620,10 @@
#ifdef CONFIG_IEEE80211BE
u8 param_ch = hapd->eht_mld_bss_param_change;
- if (reporting_hapd->conf->mld_ap &&
- bss->conf->mld_id == reporting_hapd->conf->mld_id)
+ if (hostapd_is_ml_partner(bss, reporting_hapd))
*eid++ = 0;
else
- *eid++ = hapd->conf->mld_id;
+ *eid++ = hostapd_get_mld_id(hapd);
*eid++ = hapd->mld_link_id | ((param_ch & 0xF) << 4);
*eid = (param_ch >> 4) & 0xF;
@@ -7682,12 +7721,12 @@
bool ap_mld = false;
#ifdef CONFIG_IEEE80211BE
- if (hapd->conf->mld_ap && iface->bss[0]->conf->mld_ap &&
- hapd->conf->mld_id == iface->bss[0]->conf->mld_id)
+ if (hostapd_is_ml_partner(hapd, iface->bss[0]))
ap_mld = true;
#endif /* CONFIG_IEEE80211BE */
if (iface == hapd->iface ||
+ iface->state != HAPD_IFACE_ENABLED ||
!(is_6ghz_op_class(iface->conf->op_class) || ap_mld))
continue;
@@ -7754,6 +7793,27 @@
}
+static size_t hostapd_mbssid_ext_capa(struct hostapd_data *bss,
+ struct hostapd_data *tx_bss, u8 *buf)
+{
+ u8 ext_capa_tx[20], *ext_capa_tx_end, ext_capa[20], *ext_capa_end;
+ size_t ext_capa_len, ext_capa_tx_len;
+
+ ext_capa_tx_end = hostapd_eid_ext_capab(tx_bss, ext_capa_tx,
+ true);
+ ext_capa_tx_len = ext_capa_tx_end - ext_capa_tx;
+ ext_capa_end = hostapd_eid_ext_capab(bss, ext_capa, true);
+ ext_capa_len = ext_capa_end - ext_capa;
+ if (ext_capa_tx_len != ext_capa_len ||
+ os_memcmp(ext_capa_tx, ext_capa, ext_capa_len) != 0) {
+ os_memcpy(buf, ext_capa, ext_capa_len);
+ return ext_capa_len;
+ }
+
+ return 0;
+}
+
+
static size_t hostapd_eid_mbssid_elem_len(struct hostapd_data *hapd,
u32 frame_type, size_t *bss_index,
const u8 *known_bss,
@@ -7761,6 +7821,7 @@
{
struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
size_t len, i;
+ u8 ext_capa[20];
/* Element ID: 1 octet
* Length: 1 octet
@@ -7806,6 +7867,10 @@
if (rsnx)
nontx_profile_len += 2 + rsnx[1];
}
+
+ nontx_profile_len += hostapd_mbssid_ext_capa(bss, tx_bss,
+ ext_capa);
+
if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN))
ie_count++;
if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX))
@@ -7955,6 +8020,9 @@
eid += 2 + rsnx[1];
}
}
+
+ eid += hostapd_mbssid_ext_capa(bss, tx_bss, eid);
+
/* List of Element ID values in increasing order */
if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN))
non_inherit_ie[ie_count++] = WLAN_EID_RSN;
@@ -8062,73 +8130,4 @@
return eid;
}
-
-static void punct_update_legacy_bw_80(u8 bitmap, u8 pri_chan, u8 *seg0)
-{
- u8 first_chan = *seg0 - 6, sec_chan;
-
- switch (bitmap) {
- case 0x6:
- *seg0 = 0;
- return;
- case 0x8:
- case 0x4:
- case 0x2:
- case 0x1:
- case 0xC:
- case 0x3:
- if (pri_chan < *seg0)
- *seg0 -= 4;
- else
- *seg0 += 4;
- break;
- }
-
- if (pri_chan < *seg0)
- sec_chan = pri_chan + 4;
- else
- sec_chan = pri_chan - 4;
-
- if (bitmap & BIT((sec_chan - first_chan) / 4))
- *seg0 = 0;
-}
-
-
-static void punct_update_legacy_bw_160(u8 bitmap, u8 pri,
- enum oper_chan_width *width, u8 *seg0)
-{
- if (pri < *seg0) {
- *seg0 -= 8;
- if (bitmap & 0x0F) {
- *width = 0;
- punct_update_legacy_bw_80(bitmap & 0xF, pri, seg0);
- }
- } else {
- *seg0 += 8;
- if (bitmap & 0xF0) {
- *width = 0;
- punct_update_legacy_bw_80((bitmap & 0xF0) >> 4, pri,
- seg0);
- }
- }
-}
-
-
-void punct_update_legacy_bw(u16 bitmap, u8 pri, enum oper_chan_width *width,
- u8 *seg0, u8 *seg1)
-{
- if (*width == CONF_OPER_CHWIDTH_80MHZ && (bitmap & 0xF)) {
- *width = CONF_OPER_CHWIDTH_USE_HT;
- punct_update_legacy_bw_80(bitmap & 0xF, pri, seg0);
- }
-
- if (*width == CONF_OPER_CHWIDTH_160MHZ && (bitmap & 0xFF)) {
- *width = CONF_OPER_CHWIDTH_80MHZ;
- *seg1 = 0;
- punct_update_legacy_bw_160(bitmap & 0xFF, pri, width, seg0);
- }
-
- /* TODO: 320 MHz */
-}
-
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 5fd380a..a35486d 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -248,8 +248,6 @@
u8 **elem_offset,
const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid,
u8 *rnr_count, u8 **rnr_offset, size_t rnr_len);
-void punct_update_legacy_bw(u16 bitmap, u8 pri_chan,
- enum oper_chan_width *width, u8 *seg0, u8 *seg1);
bool hostapd_is_mld_ap(struct hostapd_data *hapd);
const char * sae_get_password(struct hostapd_data *hapd,
struct sta_info *sta, const char *rx_id,
diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c
index 840fc20..638546e 100644
--- a/src/ap/ieee802_11_eht.c
+++ b/src/ap/ieee802_11_eht.c
@@ -206,19 +206,11 @@
enum oper_chan_width chwidth;
size_t elen = 1 + 4;
bool eht_oper_info_present;
- u16 punct_bitmap = conf->punct_bitmap;
+ u16 punct_bitmap = hostapd_get_punct_bitmap(hapd);
if (!hapd->iface->current_mode)
return eid;
-#ifdef CONFIG_TESTING_OPTIONS
- if (!punct_bitmap && hapd->conf->eht_oper_puncturing_override) {
- wpa_printf(MSG_DEBUG, "EHT: Puncturing mask override=0x%x",
- hapd->conf->eht_oper_puncturing_override);
- punct_bitmap = hapd->conf->eht_oper_puncturing_override;
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
if (is_6ghz_op_class(conf->op_class))
chwidth = op_class_to_ch_width(conf->op_class);
else
@@ -458,6 +450,8 @@
size_t len, slice_len;
u8 link_id;
u8 common_info_len;
+ u16 mld_cap;
+ u8 max_simul_links, active_links;
/*
* As the Multi-Link element can exceed the size of 255 bytes need to
@@ -495,7 +489,7 @@
wpabuf_put_u8(buf, common_info_len);
/* Own MLD MAC Address */
- wpabuf_put_data(buf, hapd->mld_addr, ETH_ALEN);
+ wpabuf_put_data(buf, hapd->mld->mld_addr, ETH_ALEN);
/* Own Link ID */
wpabuf_put_u8(buf, hapd->mld_link_id);
@@ -507,14 +501,31 @@
hapd->iface->mld_eml_capa);
wpabuf_put_le16(buf, hapd->iface->mld_eml_capa);
+ mld_cap = hapd->iface->mld_mld_capa;
+ max_simul_links = mld_cap & EHT_ML_MLD_CAPA_MAX_NUM_SIM_LINKS_MASK;
+ active_links = hapd->mld->num_links - 1;
+
+ if (active_links > max_simul_links) {
+ wpa_printf(MSG_ERROR,
+ "MLD: Error in max simultaneous links, advertised: 0x%x current: 0x%x",
+ max_simul_links, active_links);
+ active_links = max_simul_links;
+ }
+
+ mld_cap &= ~EHT_ML_MLD_CAPA_MAX_NUM_SIM_LINKS_MASK;
+ mld_cap |= active_links & EHT_ML_MLD_CAPA_MAX_NUM_SIM_LINKS_MASK;
+
+ /* TODO: Advertise T2LM based on driver support as well */
+ mld_cap &= ~EHT_ML_MLD_CAPA_TID_TO_LINK_MAP_NEG_SUPP_MSK;
+
wpa_printf(MSG_DEBUG, "MLD: MLD Capabilities and Operations=0x%x",
- hapd->iface->mld_mld_capa);
- wpabuf_put_le16(buf, hapd->iface->mld_mld_capa);
+ mld_cap);
+ wpabuf_put_le16(buf, mld_cap);
if (include_mld_id) {
wpa_printf(MSG_DEBUG, "MLD: AP MLD ID=0x%x",
- hapd->conf->mld_id);
- wpabuf_put_u8(buf, hapd->conf->mld_id);
+ hostapd_get_mld_id(hapd));
+ wpabuf_put_u8(buf, hostapd_get_mld_id(hapd));
}
if (!mld_info)
@@ -578,7 +589,8 @@
wpabuf_put_le64(buf, 0);
/* DTIM Info */
- wpabuf_put_le16(buf, link_bss->conf->dtim_period);
+ wpabuf_put_u8(buf, 0); /* DTIM Count */
+ wpabuf_put_u8(buf, link_bss->conf->dtim_period);
/* BSS Parameters Change Count */
wpabuf_put_u8(buf, hapd->eht_mld_bss_param_change);
@@ -812,7 +824,7 @@
wpabuf_put_u8(buf, WLAN_EID_EXT_MULTI_LINK);
wpabuf_put_le16(buf, MULTI_LINK_CONTROL_TYPE_BASIC);
wpabuf_put_u8(buf, ETH_ALEN + 1);
- wpabuf_put_data(buf, hapd->mld_addr, ETH_ALEN);
+ wpabuf_put_data(buf, hapd->mld->mld_addr, ETH_ALEN);
return buf;
}
@@ -1047,8 +1059,7 @@
if (hapd == other_hapd)
continue;
- if (other_hapd->conf->mld_ap &&
- other_hapd->conf->mld_id == hapd->conf->mld_id &&
+ if (hostapd_is_ml_partner(hapd, other_hapd) &&
link_id == other_hapd->mld_link_id)
break;
}
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index 4b693a7..a2deda6 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -12,6 +12,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/hw_features_common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "beacon.h"
@@ -224,10 +225,11 @@
u8 seg0 = hapd->iconf->he_oper_centr_freq_seg0_idx;
u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
u8 control;
-
#ifdef CONFIG_IEEE80211BE
- if (hapd->iconf->punct_bitmap) {
- punct_update_legacy_bw(hapd->iconf->punct_bitmap,
+ u16 punct_bitmap = hostapd_get_punct_bitmap(hapd);
+
+ if (punct_bitmap) {
+ punct_update_legacy_bw(punct_bitmap,
hapd->iconf->channel,
&oper_chwidth, &seg0, &seg1);
}
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 0c38483..85790c7 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -121,7 +121,7 @@
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta))
- own_addr = hapd->mld_addr;
+ own_addr = hapd->mld->mld_addr;
#endif /* CONFIG_IEEE80211BE */
mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -219,7 +219,7 @@
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta))
- own_addr = hapd->mld_addr;
+ own_addr = hapd->mld->mld_addr;
#endif /* CONFIG_IEEE80211BE */
resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -1138,13 +1138,11 @@
u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ext_capab_ie, size_t ext_capab_ie_len)
{
-#ifdef CONFIG_INTERWORKING
/* check for QoS Map support */
if (ext_capab_ie_len >= 5) {
if (ext_capab_ie[4] & 0x01)
sta->qos_map_enabled = 1;
}
-#endif /* CONFIG_INTERWORKING */
if (ext_capab_ie_len > 0) {
sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2));
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index db615a3..4dc325c 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -12,6 +12,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "sta_info.h"
@@ -79,6 +80,9 @@
hostapd_get_oper_chwidth(hapd->iconf);
u8 seg0 = hapd->iconf->vht_oper_centr_freq_seg0_idx;
u8 seg1 = hapd->iconf->vht_oper_centr_freq_seg1_idx;
+#ifdef CONFIG_IEEE80211BE
+ u16 punct_bitmap = hostapd_get_punct_bitmap(hapd);
+#endif /* CONFIG_IEEE80211BE */
if (is_6ghz_op_class(hapd->iconf->op_class))
return eid;
@@ -90,8 +94,8 @@
os_memset(oper, 0, sizeof(*oper));
#ifdef CONFIG_IEEE80211BE
- if (hapd->iconf->punct_bitmap) {
- punct_update_legacy_bw(hapd->iconf->punct_bitmap,
+ if (punct_bitmap) {
+ punct_update_legacy_bw(punct_bitmap,
hapd->iconf->channel,
&oper_chwidth, &seg0, &seg1);
}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index f13c60a..8e98b65 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -172,8 +172,7 @@
struct hostapd_data *tmp_hapd =
hapd->iface->interfaces->iface[i]->bss[0];
- if (!tmp_hapd->conf->mld_ap ||
- hapd->conf->mld_id != tmp_hapd->conf->mld_id)
+ if (!hostapd_is_ml_partner(hapd, tmp_hapd))
continue;
for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
@@ -2540,13 +2539,20 @@
struct eapol_auth_config conf;
struct eapol_auth_cb cb;
- if (hapd->mld_first_bss) {
+#ifdef CONFIG_IEEE80211BE
+ 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");
- hapd->eapol_auth = hapd->mld_first_bss->eapol_auth;
+ first = hostapd_mld_get_first_bss(hapd);
+ if (!first)
+ return -1;
+ hapd->eapol_auth = first->eapol_auth;
return 0;
}
+#endif /* CONFIG_IEEE80211BE */
dl_list_init(&hapd->erp_keys);
@@ -2632,13 +2638,15 @@
void ieee802_1x_deinit(struct hostapd_data *hapd)
{
- if (hapd->mld_first_bss) {
+#ifdef CONFIG_IEEE80211BE
+ if (!hostapd_mld_is_first_bss(hapd)) {
wpa_printf(MSG_DEBUG,
"MLD: Deinit IEEE 802.1X state machine of a non-first BSS");
hapd->eapol_auth = NULL;
return;
}
+#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_WEP
eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
diff --git a/src/ap/ndisc_snoop.c b/src/ap/ndisc_snoop.c
index 788c12f..bc1eb62 100644
--- a/src/ap/ndisc_snoop.c
+++ b/src/ap/ndisc_snoop.c
@@ -61,6 +61,7 @@
dl_list_for_each_safe(ip6addr, prev, &sta->ip6addr, struct ip6addr,
list) {
hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &ip6addr->addr);
+ dl_list_del(&ip6addr->list);
os_free(ip6addr);
}
}
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index 2a25ae2..f7a7d83 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -99,7 +99,10 @@
nr->civic = NULL;
os_memset(nr->bssid, 0, sizeof(nr->bssid));
os_memset(&nr->ssid, 0, sizeof(nr->ssid));
+ os_memset(&nr->lci_date, 0, sizeof(nr->lci_date));
nr->stationary = 0;
+ nr->short_ssid = 0;
+ nr->bss_parameters = 0;
}
@@ -165,6 +168,14 @@
}
+static void hostapd_neighbor_free(struct hostapd_neighbor_entry *nr)
+{
+ hostapd_neighbor_clear_entry(nr);
+ dl_list_del(&nr->list);
+ os_free(nr);
+}
+
+
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid)
{
@@ -174,9 +185,7 @@
if (!nr)
return -1;
- hostapd_neighbor_clear_entry(nr);
- dl_list_del(&nr->list);
- os_free(nr);
+ hostapd_neighbor_free(nr);
return 0;
}
@@ -188,9 +197,7 @@
dl_list_for_each_safe(nr, prev, &hapd->nr_db,
struct hostapd_neighbor_entry, list) {
- hostapd_neighbor_clear_entry(nr);
- dl_list_del(&nr->list);
- os_free(nr);
+ hostapd_neighbor_free(nr);
}
}
@@ -325,3 +332,35 @@
wpabuf_free(nr);
#endif /* NEED_AP_MLME */
}
+
+
+static struct hostapd_neighbor_entry *
+hostapd_neighbor_get_diff_short_ssid(struct hostapd_data *hapd, const u8 *bssid)
+{
+ struct hostapd_neighbor_entry *nr;
+
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+ list) {
+ if (ether_addr_equal(bssid, nr->bssid) &&
+ nr->short_ssid != hapd->conf->ssid.short_ssid)
+ return nr;
+ }
+ return NULL;
+}
+
+
+int hostapd_neighbor_sync_own_report(struct hostapd_data *hapd)
+{
+ struct hostapd_neighbor_entry *nr;
+
+ nr = hostapd_neighbor_get_diff_short_ssid(hapd, hapd->own_addr);
+ if (!nr)
+ return -1;
+
+ /* Clear old entry due to SSID change */
+ hostapd_neighbor_free(nr);
+
+ hostapd_neighbor_set_own_report(hapd);
+
+ return 0;
+}
diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
index 992671b..53f7142 100644
--- a/src/ap/neighbor_db.h
+++ b/src/ap/neighbor_db.h
@@ -20,6 +20,7 @@
const struct wpabuf *civic, int stationary,
u8 bss_parameters);
void hostapd_neighbor_set_own_report(struct hostapd_data *hapd);
+int hostapd_neighbor_sync_own_report(struct hostapd_data *hapd);
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid);
void hostapd_free_neighbor_db(struct hostapd_data *hapd);
diff --git a/src/ap/rrm.c b/src/ap/rrm.c
index f2d5cd1..fbcddf3 100644
--- a/src/ap/rrm.c
+++ b/src/ap/rrm.c
@@ -334,6 +334,53 @@
}
+static void hostapd_link_mesr_rep_timeout_handler(void *eloop_data,
+ void *user_ctx)
+{
+ struct hostapd_data *hapd = eloop_data;
+
+ wpa_printf(MSG_DEBUG,
+ "RRM: Link measurement request (token %u) timed out",
+ hapd->link_measurement_req_token);
+ hapd->link_mesr_req_active = 0;
+}
+
+
+static void hostapd_handle_link_mesr_report(struct hostapd_data *hapd,
+ const u8 *buf, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
+ const struct rrm_link_measurement_report *report;
+ const u8 *pos, *end;
+ char report_msg[2 * 8 + 1];
+
+ end = buf + len;
+ pos = mgmt->u.action.u.rrm.variable;
+ report = (const struct rrm_link_measurement_report *) (pos - 1);
+ if (end - (const u8 *) report < (int) sizeof(*report))
+ return;
+
+ if (!hapd->link_mesr_req_active ||
+ (hapd->link_measurement_req_token != report->dialog_token)) {
+ wpa_printf(MSG_INFO,
+ "Unexpected Link measurement report, token %u",
+ report->dialog_token);
+ return;
+ }
+
+ hapd->link_mesr_req_active = 0;
+ eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, hapd, NULL);
+
+ report_msg[0] = '\0';
+ if (wpa_snprintf_hex(report_msg, sizeof(report_msg),
+ pos, end - pos) < 0)
+ return;
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, LINK_MSR_RESP_RX MACSTR " %u %s",
+ MAC2STR(mgmt->sa), report->dialog_token, report_msg);
+}
+
+
void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
const u8 *buf, size_t len)
{
@@ -356,6 +403,9 @@
case WLAN_RRM_NEIGHBOR_REPORT_REQUEST:
hostapd_handle_nei_report_req(hapd, buf, len);
break;
+ case WLAN_RRM_LINK_MEASUREMENT_REPORT:
+ hostapd_handle_link_mesr_report(hapd, buf, len);
+ break;
default:
wpa_printf(MSG_DEBUG, "RRM action %u is not supported",
mgmt->u.action.u.rrm.action);
@@ -563,6 +613,7 @@
hapd->lci_req_active = 0;
eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
hapd->range_req_active = 0;
+ eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, hapd, NULL);
}
@@ -672,3 +723,73 @@
" %u ack=%d", MAC2STR(mgmt->da),
mgmt->u.action.u.rrm.dialog_token, ok);
}
+
+
+int hostapd_send_link_measurement_req(struct hostapd_data *hapd, const u8 *addr)
+{
+ struct wpabuf *buf;
+ struct sta_info *sta;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "Request Link Measurement: dest addr " MACSTR,
+ MAC2STR(addr));
+
+ if (!(hapd->iface->drv_rrm_flags &
+ WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
+ wpa_printf(MSG_INFO,
+ "Request Link Measurement: the driver does not support TX power insertion");
+ return -1;
+ }
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
+ wpa_printf(MSG_INFO,
+ "Request Link Measurement: specied STA is not connected");
+ return -1;
+ }
+
+ if (!(sta->rrm_enabled_capa[0] & WLAN_RRM_CAPS_LINK_MEASUREMENT)) {
+ wpa_printf(MSG_INFO,
+ "Request Link Measurement: destination STA does not support link measurement");
+ return -1;
+ }
+
+ if (hapd->link_mesr_req_active) {
+ wpa_printf(MSG_DEBUG,
+ "Request Link Measurement: request already in process - overriding");
+ hapd->link_mesr_req_active = 0;
+ eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler,
+ hapd, NULL);
+ }
+
+ /* Action + Action type + token + Tx Power used + Max Tx Power = 5 */
+ buf = wpabuf_alloc(5);
+ if (!buf)
+ return -1;
+
+ hapd->link_measurement_req_token++;
+ if (!hapd->link_measurement_req_token)
+ hapd->link_measurement_req_token++;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REQUEST);
+ wpabuf_put_u8(buf, hapd->link_measurement_req_token);
+ /* NOTE: The driver is expected to fill the Tx Power Used and Max Tx
+ * Power */
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_u8(buf, 0);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+ if (ret < 0)
+ return ret;
+
+ hapd->link_mesr_req_active = 1;
+
+ eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
+ hostapd_link_mesr_rep_timeout_handler, hapd,
+ NULL);
+
+ return hapd->link_measurement_req_token;
+}
diff --git a/src/ap/rrm.h b/src/ap/rrm.h
index 02cd522..17751e0 100644
--- a/src/ap/rrm.h
+++ b/src/ap/rrm.h
@@ -29,5 +29,7 @@
void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt,
size_t len, int ok);
+int hostapd_send_link_measurement_req(struct hostapd_data *hapd,
+ const u8 *addr);
#endif /* RRM_H */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 2178d65..32944ed 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -180,13 +180,26 @@
sta->pasn->fils.erp_resp = NULL;
#endif /* CONFIG_FILS */
- bin_clear_free(sta->pasn, sizeof(*sta->pasn));
+ pasn_data_deinit(sta->pasn);
sta->pasn = NULL;
}
}
#endif /* CONFIG_PASN */
+
+static void __ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
+{
+#ifdef CONFIG_IEEE80211BE
+ if (hostapd_sta_is_link_sta(hapd, sta) &&
+ !hostapd_drv_link_sta_remove(hapd, sta->addr))
+ return;
+#endif /* CONFIG_IEEE80211BE */
+
+ hostapd_drv_sta_remove(hapd, sta->addr);
+}
+
+
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_beacon = 0;
@@ -209,7 +222,7 @@
if (!hapd->iface->driver_ap_teardown &&
!(sta->flags & WLAN_STA_PREAUTH)) {
- hostapd_drv_sta_remove(hapd, sta->addr);
+ __ap_free_sta(hapd, sta);
sta->added_unassoc = 0;
}
@@ -454,6 +467,27 @@
}
+#ifdef CONFIG_IEEE80211BE
+void hostapd_free_link_stas(struct hostapd_data *hapd)
+{
+ struct sta_info *sta, *prev;
+
+ sta = hapd->sta_list;
+ while (sta) {
+ prev = sta;
+ sta = sta->next;
+
+ if (!hostapd_sta_is_link_sta(hapd, prev))
+ continue;
+
+ wpa_printf(MSG_DEBUG, "Removing link station from MLD " MACSTR,
+ MAC2STR(prev->addr));
+ ap_free_sta(hapd, prev);
+ }
+}
+#endif /* CONFIG_IEEE80211BE */
+
+
/**
* ap_handle_timer - Per STA timer handler
* @eloop_ctx: struct hostapd_data *
@@ -970,16 +1004,15 @@
interfaces = assoc_hapd->iface->interfaces;
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
+ if (!assoc_sta->mld_info.links[link_id].valid)
+ continue;
+
for (i = 0; i < interfaces->count; i++) {
struct sta_info *tmp_sta;
- if (!assoc_sta->mld_info.links[link_id].valid)
- continue;
-
tmp_hapd = interfaces->iface[i]->bss[0];
- if (!tmp_hapd->conf->mld_ap ||
- assoc_hapd->conf->mld_id != tmp_hapd->conf->mld_id)
+ if (!hostapd_is_ml_partner(tmp_hapd, assoc_hapd))
continue;
for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
@@ -1433,7 +1466,7 @@
u8 addr[ETH_ALEN];
u8 ip_addr_buf[4];
#endif /* CONFIG_P2P */
- u8 *ip_ptr = NULL;
+ const u8 *ip_ptr = NULL;
#ifdef CONFIG_P2P
if (hapd->p2p_group == NULL) {
@@ -1731,7 +1764,7 @@
unsigned int i, j;
for_each_mld_link(tmp_hapd, i, j, hapd->iface->interfaces,
- hapd->conf->mld_id) {
+ hostapd_get_mld_id(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 b136ff7..153e4a0 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -440,4 +440,6 @@
void ap_sta_free_sta_profile(struct mld_info *info);
+void hostapd_free_link_stas(struct hostapd_data *hapd);
+
#endif /* STA_INFO_H */
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index b77e21b..af8ccca 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -51,7 +51,7 @@
#ifdef CONFIG_IEEE80211BE
if (hapd->conf->mld_ap && (!sta || ap_sta_is_mld(hapd, sta)))
- own_addr = hapd->mld_addr;
+ own_addr = hapd->mld->mld_addr;
#endif /* CONFIG_IEEE80211BE */
return own_addr;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 3002d91..4bf8d79 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -3345,10 +3345,7 @@
}
/* Find matching link ID and the MAC address for each link */
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(kde->valid_mlo_links & BIT(i)))
- continue;
-
+ for_each_link(kde->valid_mlo_links, i) {
/*
* Each entry should contain the link information and the MAC
* address.
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index b286a77..34de45c 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -1559,8 +1559,7 @@
struct hostapd_iface *iface =
hapd->iface->interfaces->iface[j];
- if (!iface->bss[0]->conf->mld_ap ||
- hapd->conf->mld_id != iface->bss[0]->conf->mld_id ||
+ if (!hostapd_is_ml_partner(hapd, iface->bss[0]) ||
link_id != iface->bss[0]->mld_link_id ||
!iface->bss[0]->wpa_auth)
continue;
@@ -1602,8 +1601,7 @@
struct hostapd_iface *iface =
hapd->iface->interfaces->iface[j];
- if (!iface->bss[0]->conf->mld_ap ||
- hapd->conf->mld_id != iface->bss[0]->conf->mld_id ||
+ if (!hostapd_is_ml_partner(hapd, iface->bss[0]) ||
link_id != iface->bss[0]->mld_link_id ||
!iface->bss[0]->wpa_auth)
continue;