blob: c9b8ea943fb8e852fe1f3c41b92d4ad3c533914b [file] [log] [blame]
From bed7e913c79fcd0f2d7d686b7d1da0ec8bf4d23f Mon Sep 17 00:00:00 2001
From: mtk20656 <chank.chen@mediatek.com>
Date: Thu, 2 Mar 2023 10:51:43 +0800
Subject: [PATCH 21/29] hostapd: mtk: add 11v_mbss and ema support for hostapd
Signed-off-by: mtk20656 <chank.chen@mediatek.com>
---
hostapd/config_file.c | 9 +
hostapd/hostapd.conf | 58 +++++++
hostapd/main.c | 3 +
src/ap/ap_config.c | 12 ++
src/ap/ap_config.h | 6 +
src/ap/beacon.c | 124 ++++++++++++--
src/ap/hostapd.c | 72 +++++++-
src/ap/hostapd.h | 7 +
src/ap/ieee802_11.c | 276 +++++++++++++++++++++++++++++-
src/ap/ieee802_11.h | 7 +-
src/ap/ieee802_11_shared.c | 11 ++
src/common/ieee802_11_common.c | 4 +
src/common/ieee802_11_common.h | 3 +
src/common/ieee802_11_defs.h | 5 +
src/drivers/driver.h | 42 +++++
src/drivers/driver_nl80211.c | 52 ++++++
src/drivers/driver_nl80211_capa.c | 27 +++
17 files changed, 698 insertions(+), 20 deletions(-)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 649618b..3f26191 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3663,6 +3663,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
return 1;
}
bss->unsol_bcast_probe_resp_interval = val;
+ } else if (os_strcmp(buf, "mbssid") == 0) {
+ int mbssid = atoi(pos);
+ if (mbssid < 0 || mbssid > ENHANCED_MBSSID_ENABLED) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid mbssid (%d): '%s'.",
+ line, mbssid, pos);
+ return 1;
+ }
+ conf->mbssid = mbssid;
} else if (os_strcmp(buf, "mu_onoff") == 0) {
int val = atoi(pos);
if (val < 0 || val > 15) {
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index e3a5eb3..f926029 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -3123,3 +3123,61 @@ own_ip_addr=127.0.0.1
#bss=wlan0_1
#bssid=00:13:10:95:fe:0b
# ...
+#
+# Multiple BSSID Advertisement in 802.11ax
+# IEEE Std 802.11ax-2021 added a feature where instead of multiple interfaces
+# on a common radio transmitting individual beacons, those can form a set with
+# a common beacon is transmitted for all. The interface which is brought up
+# first is called as the transmitting profile of the MBSSID set which transmits
+# the beacons. The remaining interfaces are called as the non-transmitting
+# profiles and these are advertised inside the multiple BSSID element in the
+# beacons and probe response frames.
+# The transmitting interface is visible to all clients in the vicinity, however
+# the clients which do not support parsing of the multiple BSSID element will
+# not be able to connect to the non-transmitting interfaces.
+#
+# Enhanced Multiple BSSID Advertisements (EMA)
+# When enabled, the non-transmitting interfaces are split into multiple
+# beacons. The number of beacons required to cover all the non-transmitting
+# profiles is called as the profile periodicity.
+#
+# Refer to IEEE Std 802.11-2020 for details regarding the procedure and
+# required MAC address assignment.
+#
+# Following configuration is per radio.
+# 0 = Disabled (Default)
+# 1 = Multiple BSSID advertisements enabled.
+# 2 = Enhanced multiple BSSID advertisements enabled.
+#mbssid=0
+#
+# The transmitting interface should be added with 'interface' option while
+# the non-transmitting interfaces should be added using 'bss' option.
+# Security configuration should be added separately per interface, if required.
+#
+# Example:
+#mbssid=2
+#interface=wlan2
+#ctrl_interface=/var/run/hostapd
+#wpa_passphrase=0123456789
+#ieee80211w=2
+#sae_pwe=1
+#auth_algs=1
+#wpa=2
+#wpa_pairwise=CCMP
+#ssid=<SSID-0>
+#bridge=br-lan
+#wpa_key_mgmt=SAE
+#bssid=00:03:7f:12:84:84
+#
+#bss=wlan2-1
+#ctrl_interface=/var/run/hostapd
+#wpa_passphrase=0123456789
+#ieee80211w=2
+#sae_pwe=1
+#auth_algs=1
+#wpa=2
+#wpa_pairwise=CCMP
+#ssid=<SSID-1>
+#bridge=br-lan
+#wpa_key_mgmt=SAE
+#bssid=00:03:7f:12:84:85
diff --git a/hostapd/main.c b/hostapd/main.c
index 70a4b32..1b6474a 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -253,6 +253,9 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
wpa_printf(MSG_ERROR, "set_wowlan failed");
}
os_free(triggs);
+
+ iface->mbssid_max_interfaces = capa.mbssid_max_interfaces;
+ iface->ema_max_periodicity = capa.ema_max_periodicity;
}
return 0;
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 4e46a62..7d9d5cb 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -1462,6 +1462,12 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
#endif /* CONFIG_IEEE80211BE */
+ if (full_config && bss->ignore_broadcast_ssid && conf->mbssid) {
+ wpa_printf(MSG_ERROR,
+ "Hidden SSID is not suppored when MBSSID is enabled");
+ return -1;
+ }
+
return 0;
}
@@ -1545,6 +1551,12 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
}
#endif /* CONFIG_IEEE80211BE */
+ if (full_config && conf->mbssid && !conf->ieee80211ax) {
+ wpa_printf(MSG_ERROR,
+ "Cannot enable multiple BSSID support without ieee80211ax");
+ return -1;
+ }
+
for (i = 0; i < conf->num_bss; i++) {
if (hostapd_config_check_bss(conf->bss[i], conf, full_config))
return -1;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 7aeb176..51476b8 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -923,6 +923,8 @@ struct hostapd_bss_config {
u8 ext_capa[EXT_CAPA_MAX_LEN];
u8 rnr;
+
+ bool xrates_supported;
};
/**
@@ -1163,6 +1165,10 @@ struct hostapd_config {
u8 ibf_enable;
u8 dfs_detect_mode;
u8 amsdu;
+
+#define MBSSID_ENABLED 1
+#define ENHANCED_MBSSID_ENABLED 2
+ u8 mbssid;
};
enum three_wire_mode {
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index f3ea5c2..ad56046 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -462,15 +462,77 @@ static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
}
+static int ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd,
+ struct wpa_driver_ap_params *params,
+ u8 **eid)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ struct hostapd_data *tx_bss;
+ size_t len;
+ u8 elem_count = 0, *elem = NULL, **elem_offset = NULL, *end;
+ u8 *tailpos = *eid;
+
+ if (!iface->mbssid_max_interfaces ||
+ iface->num_bss > iface->mbssid_max_interfaces ||
+ (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED &&
+ !iface->ema_max_periodicity))
+ goto fail;
+
+ tx_bss = hostapd_mbssid_get_tx_bss(hapd);
+ len = hostapd_eid_mbssid_len(tx_bss, WLAN_FC_STYPE_BEACON, &elem_count,
+ NULL, 0);
+ if (!len || (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED &&
+ elem_count > iface->ema_max_periodicity))
+ goto fail;
+
+ elem = os_zalloc(len);
+ if (!elem)
+ goto fail;
+
+ elem_offset = os_zalloc(elem_count * sizeof(u8 *));
+ if (!elem_offset)
+ goto fail;
+
+ end = hostapd_eid_mbssid(tx_bss, elem, elem + len, WLAN_FC_STYPE_BEACON,
+ elem_count, elem_offset, NULL, 0);
+
+ params->mbssid_tx_iface = tx_bss->conf->iface;
+ params->mbssid_index = hostapd_mbssid_get_bss_index(hapd);
+ params->mbssid_elem = elem;
+ params->mbssid_elem_len = end - elem;
+ params->mbssid_elem_count = elem_count;
+ params->mbssid_elem_offset = elem_offset;
+ if (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED) {
+ params->ema = true;
+ *tailpos++ = WLAN_EID_EXTENSION;
+ *tailpos++ = 3;
+ *tailpos++ = WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION;
+ *tailpos++ = iface->num_bss;
+ *tailpos++ = params->mbssid_elem_count;
+ *eid = tailpos;
+ }
+
+ return 0;
+
+fail:
+ os_free(elem);
+ wpa_printf(MSG_ERROR, "MBSSID: Configuration failed");
+ return -1;
+}
+
+
static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
const struct ieee80211_mgmt *req,
int is_p2p, size_t *resp_len,
- bool bcast_probe_resp)
+ bool bcast_probe_resp, const u8 *known_bss,
+ u8 known_bss_len)
{
struct ieee80211_mgmt *resp;
- u8 *pos, *epos, *csa_pos;
+ u8 *pos, *epos, *csa_pos, *ext_cap_pos;
size_t buflen;
+ hapd = hostapd_mbssid_get_tx_bss(hapd);
+
#define MAX_PROBERESP_LEN 768
buflen = MAX_PROBERESP_LEN;
#ifdef CONFIG_WPS
@@ -517,6 +579,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211BE */
+ buflen += hostapd_eid_mbssid_len(hapd, WLAN_FC_STYPE_PROBE_RESP, NULL,
+ known_bss, known_bss_len);
buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP);
buflen += hostapd_mbo_ie_len(hapd);
buflen += hostapd_eid_owe_trans_len(hapd);
@@ -588,8 +652,16 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_eid_supported_op_classes(hapd, pos);
pos = hostapd_eid_ht_capabilities(hapd, pos);
pos = hostapd_eid_ht_operation(hapd, pos);
+ pos = hostapd_eid_mbssid(hapd, pos, epos, WLAN_FC_STYPE_PROBE_RESP, 0,
+ NULL, known_bss, known_bss_len);
+ ext_cap_pos = pos;
pos = hostapd_eid_ext_capab(hapd, pos);
+ if (hapd->iconf->mbssid >= MBSSID_ENABLED && !known_bss_len)
+ ext_cap_pos[12] |= 0x01; /* Probe responses always include all
+ * non-tx profiles except when a list
+ * of known BSSes is included in the
+ * probe request. */
pos = hostapd_eid_time_adv(hapd, pos);
pos = hostapd_eid_time_zone(hapd, pos);
@@ -1153,16 +1225,23 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#endif /* CONFIG_TESTING_OPTIONS */
+ /* Do not send probe response from a non-transmitting multiple BSSID
+ * profile unless the probe request is directed at that paticular BSS */
+ if (hapd != hostapd_mbssid_get_tx_bss(hapd) && res != EXACT_SSID_MATCH)
+ return;
+
wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, RX_PROBE_REQUEST "sa=" MACSTR
" signal=%d", MAC2STR(mgmt->sa), ssi_signal);
if (is_6ghz_op_class(hapd->iconf->op_class) &&
is_broadcast_ether_addr(mgmt->da))
resp = hostapd_gen_probe_resp(hapd, NULL, elems.p2p != NULL,
- &resp_len, true);
+ &resp_len, true, elems.mbssid_known_bss,
+ elems.mbssid_known_bss_len);
else
resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
- &resp_len, false);
+ &resp_len, false, elems.mbssid_known_bss,
+ elems.mbssid_known_bss_len);
if (resp == NULL)
return;
@@ -1184,7 +1263,8 @@ void handle_probe_req(struct hostapd_data *hapd,
hapd->cs_c_off_ecsa_proberesp;
}
- ret = hostapd_drv_send_mlme(hapd, resp, resp_len, noack,
+ ret = hostapd_drv_send_mlme(hostapd_mbssid_get_tx_bss(hapd), resp,
+ resp_len, noack,
csa_offs_len ? csa_offs : NULL,
csa_offs_len, 0);
@@ -1231,7 +1311,7 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
"this");
/* Generate a Probe Response template for the non-P2P case */
- return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len, false);
+ return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len, false, NULL, 0);
}
#endif /* NEED_AP_MLME */
@@ -1250,7 +1330,7 @@ static u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
return hostapd_gen_probe_resp(hapd, NULL, 0,
&params->unsol_bcast_probe_resp_tmpl_len,
- true);
+ true, NULL, 0);
}
#endif /* CONFIG_IEEE80211AX */
@@ -1533,8 +1613,12 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
size_t resp_len = 0;
#ifdef NEED_AP_MLME
u16 capab_info;
- u8 *pos, *tailpos, *tailend, *csa_pos;
+ u8 *pos, *tailpos, *tailend, *csa_pos, *ext_cap_pos;
+#endif /* NEED_AP_MLME */
+ os_memset(params, 0, sizeof(*params));
+
+#ifdef NEED_AP_MLME
#define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512
head = os_zalloc(BEACON_HEAD_BUF_SIZE);
@@ -1586,6 +1670,9 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211BE */
+ 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_mbo_ie_len(hapd);
tail_len += hostapd_eid_owe_trans_len(hapd);
@@ -1671,9 +1758,23 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_supported_op_classes(hapd, tailpos);
tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
tailpos = hostapd_eid_ht_operation(hapd, tailpos);
-
+ ext_cap_pos = tailpos;
tailpos = hostapd_eid_ext_capab(hapd, tailpos);
+ if (hapd->iconf->mbssid && hapd->iconf->num_bss > 1) {
+ if (ieee802_11_build_ap_params_mbssid(hapd, params, &tailpos)) {
+ os_free(head);
+ os_free(tail);
+ wpa_printf(MSG_ERROR, "Failed to set beacon data");
+ return -1;
+ } else if (hapd->iconf->mbssid == MBSSID_ENABLED ||
+ (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
+ params->mbssid_elem_count == 1)) {
+ /* Set the extended capability bit for "complete list
+ * of non-tx profiles" */
+ ext_cap_pos[12] |= 0x01;
+ }
+ }
/*
* TODO: Time Advertisement element should only be included in some
* DTIM Beacon frames.
@@ -1794,7 +1895,6 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
resp = hostapd_probe_resp_offloads(hapd, &resp_len);
#endif /* NEED_AP_MLME */
- os_memset(params, 0, sizeof(*params));
params->head = (u8 *) head;
params->head_len = head_len;
params->tail = tail;
@@ -1897,6 +1997,10 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
params->head = NULL;
os_free(params->proberesp);
params->proberesp = NULL;
+ os_free(params->mbssid_elem);
+ params->mbssid_elem = NULL;
+ os_free(params->mbssid_elem_offset);
+ params->mbssid_elem_offset = NULL;
#ifdef CONFIG_FILS
os_free(params->fd_frame_tmpl);
params->fd_frame_tmpl = NULL;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 42e8ed7..ef0d6db 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -91,6 +91,29 @@ int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
}
+struct hostapd_data * hostapd_mbssid_get_tx_bss(struct hostapd_data *hapd)
+{
+ if (hapd->iconf->mbssid)
+ return hapd->iface->bss[0];
+
+ return hapd;
+}
+
+
+int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd)
+{
+ if (hapd->iconf->mbssid) {
+ size_t i;
+
+ for (i = 1; i < hapd->iface->num_bss; i++)
+ if (hapd->iface->bss[i] == hapd)
+ return i;
+ }
+
+ return 0;
+}
+
+
void hostapd_reconfig_encryption(struct hostapd_data *hapd)
{
if (hapd->wpa_auth)
@@ -1179,19 +1202,37 @@ static int db_table_create_radius_attributes(sqlite3 *db)
#endif /* CONFIG_NO_RADIUS */
+static int hostapd_start_beacon(struct hostapd_data *hapd)
+{
+ struct hostapd_bss_config *conf = hapd->conf;
+
+ if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
+ return -1;
+
+ if (hapd->driver && hapd->driver->set_operstate)
+ hapd->driver->set_operstate(hapd->drv_priv, 1);
+
+ return 0;
+}
/**
* hostapd_setup_bss - Per-BSS setup (initialization)
* @hapd: Pointer to BSS data
* @first: Whether this BSS is the first BSS of an interface; -1 = not first,
* but interface may exist
+ * @start_beacon: Whether beacons should be configured and transmission started
+ * at this time. This is used when MBSSID IE is enabled where the
+ * information regarding all BSSes should be retrieved before configuring
+ * the beacons. The calling functions are responsible to configure the
+ * beacon explicitly if this is set to 'false'.
*
* This function is used to initialize all per-BSS data structures and
* resources. This gets called in a loop for each BSS when an interface is
* initialized. Most of the modules that are initialized here will be
* deinitialized in hostapd_cleanup().
*/
-static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
+static int hostapd_setup_bss(struct hostapd_data *hapd, int first,
+ bool start_beacon)
{
struct hostapd_bss_config *conf = hapd->conf;
u8 ssid[SSID_MAX_LEN + 1];
@@ -1464,9 +1505,6 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
return -1;
}
- if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0)
- return -1;
-
if (flush_old_stations && !conf->start_disabled &&
conf->broadcast_deauth) {
u8 addr[ETH_ALEN];
@@ -1485,8 +1523,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
return -1;
- if (hapd->driver && hapd->driver->set_operstate)
- hapd->driver->set_operstate(hapd->drv_priv, 1);
+ if (start_beacon && hostapd_start_beacon(hapd) < 0)
+ return -1;
hostapd_ubus_add_bss(hapd);
@@ -2214,7 +2252,7 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
hapd = iface->bss[j];
if (j)
os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
- if (hostapd_setup_bss(hapd, j == 0)) {
+ if (hostapd_setup_bss(hapd, j == 0, !iface->conf->mbssid)) {
for (;;) {
hapd = iface->bss[j];
hostapd_bss_deinit_no_free(hapd);
@@ -2228,6 +2266,24 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
if (is_zero_ether_addr(hapd->conf->bssid))
prev_addr = hapd->own_addr;
}
+
+ if (hapd->iconf->mbssid) {
+ for (j = 0; j < iface->num_bss; j++) {
+ hapd = iface->bss[j];
+ if (hostapd_start_beacon(hapd)) {
+ for (;;) {
+ hapd = iface->bss[j];
+ hostapd_bss_deinit_no_free(hapd);
+ hostapd_free_hapd_data(hapd);
+ if (j == 0)
+ break;
+ j--;
+ }
+ goto fail;
+ }
+ }
+ }
+
hapd = iface->bss[0];
hostapd_tx_queue_params(iface);
@@ -3130,7 +3186,7 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
if (start_ctrl_iface_bss(hapd) < 0 ||
(hapd_iface->state == HAPD_IFACE_ENABLED &&
- hostapd_setup_bss(hapd, -1))) {
+ hostapd_setup_bss(hapd, -1, true))) {
hostapd_cleanup(hapd);
hapd_iface->bss[hapd_iface->num_bss - 1] = NULL;
hapd_iface->conf->num_bss--;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 56d96a5..093c28a 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -660,6 +660,11 @@ struct hostapd_iface {
/* Previous WMM element information */
struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM];
+ /* Maximum number of interfaces supported for MBSSID advertisements */
+ u8 mbssid_max_interfaces;
+ /* Maximum profile periodicity for enhanced MBSSID advertisements */
+ u8 ema_max_periodicity;
+
int (*enable_iface_cb)(struct hostapd_iface *iface);
int (*disable_iface_cb)(struct hostapd_iface *iface);
};
@@ -762,5 +767,7 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
#endif /* CONFIG_FST */
int hostapd_set_acl(struct hostapd_data *hapd);
+struct hostapd_data * hostapd_mbssid_get_tx_bss(struct hostapd_data *hapd);
+int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd);
#endif /* HOSTAPD_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 098793e..30bfa30 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -165,6 +165,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
int i, num, count;
int h2e_required;
+ hapd->conf->xrates_supported = 0;
if (hapd->iface->current_rates == NULL)
return eid;
@@ -214,6 +215,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
}
+ hapd->conf->xrates_supported = 1;
return pos;
}
@@ -3979,6 +3981,23 @@ static void handle_auth(struct hostapd_data *hapd,
}
+static u8 hostapd_max_bssid_indicator(struct hostapd_data *hapd)
+{
+ size_t num_bss_nontx;
+ u8 max_bssid_ind = 0;
+
+ if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1)
+ return 0;
+
+ num_bss_nontx = hapd->iface->num_bss - 1;
+ while (num_bss_nontx > 0) {
+ max_bssid_ind++;
+ num_bss_nontx >>= 1;
+ }
+ return max_bssid_ind;
+}
+
+
int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
{
int i, j = 32, aid;
@@ -4004,7 +4023,10 @@ int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
}
if (j == 32)
return -1;
- aid = i * 32 + j + 1;
+ aid = i * 32 + j;
+
+ aid += (1 << hostapd_max_bssid_indicator(hapd));
+
if (aid > 2007)
return -1;
@@ -7579,4 +7601,256 @@ u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type)
return eid;
}
+
+static size_t hostapd_eid_mbssid_elem_len(struct hostapd_data *hapd,
+ u32 frame_type, size_t *bss_index,
+ const u8 *known_bss,
+ size_t known_bss_len)
+{
+ struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
+ size_t len = 3, i;
+
+ for (i = *bss_index; i < hapd->iface->num_bss; i++) {
+ struct hostapd_data *bss = hapd->iface->bss[i];
+ const u8 *auth, *rsn = NULL, *rsnx = NULL;
+ size_t nontx_profile_len, auth_len;
+ u8 ie_count = 0;
+
+ if (known_bss && (known_bss_len > (i / 8))) {
+ known_bss = &known_bss[i / 8];
+ if (*known_bss & (u8)(BIT(i % 8)))
+ continue;
+ }
+
+ if (!bss || !bss->conf || !bss->started)
+ continue;
+
+ /*
+ * Sublement ID: 1 byte
+ * Length: 1 byte
+ * Nontransmitted capabilities: 4 bytes
+ * SSID element: 2 + variable
+ * Multiple BSSID Index Element: 3 bytes (+2 bytes in beacons)
+ * Fixed length = 1 + 1 + 4 + 2 + 3 = 11
+ */
+ nontx_profile_len = 11 + bss->conf->ssid.ssid_len;
+
+ if (frame_type == WLAN_FC_STYPE_BEACON)
+ nontx_profile_len += 2;
+
+ auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
+ if (auth) {
+ rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
+ if (rsn)
+ nontx_profile_len += (2 + rsn[1]);
+
+ rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
+ if (rsnx)
+ nontx_profile_len += (2 + rsnx[1]);
+ }
+ if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN))
+ ie_count++;
+ if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX))
+ ie_count++;
+ if (bss->conf->xrates_supported)
+ nontx_profile_len += 8;
+ else if (hapd->conf->xrates_supported)
+ ie_count++;
+ if (ie_count)
+ nontx_profile_len += (4 + ie_count);
+
+ if ((len + nontx_profile_len) > 255)
+ goto mbssid_too_big;
+
+ len += nontx_profile_len;
+ }
+
+mbssid_too_big:
+ *bss_index = i;
+ return len;
+}
+
+
+size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
+ u8 *elem_count, const u8 *known_bss,
+ size_t known_bss_len)
+{
+ size_t len = 0, bss_index = 1;
+
+ if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
+ (frame_type != WLAN_FC_STYPE_BEACON &&
+ frame_type != WLAN_FC_STYPE_PROBE_RESP))
+ return 0;
+
+ if (frame_type == WLAN_FC_STYPE_BEACON) {
+ if (!elem_count) {
+ wpa_printf(MSG_ERROR,
+ "MBSSID: Insufficient data for beacons");
+ return 0;
+ }
+ *elem_count = 0;
+ }
+
+ while (bss_index < hapd->iface->num_bss) {
+ len += hostapd_eid_mbssid_elem_len(hapd, frame_type,
+ &bss_index, known_bss,
+ known_bss_len);
+
+ if (frame_type == WLAN_FC_STYPE_BEACON)
+ *elem_count += 1;
+ }
+ return len;
+}
+
+
+static u8 * hostapd_eid_mbssid_elem(struct hostapd_data *hapd, u8 *eid, u8 *end,
+ u32 frame_type, u8 max_bssid_indicator,
+ size_t *bss_index, u8 elem_count,
+ const u8 *known_bss, size_t known_bss_len)
+{
+ struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
+ size_t i;
+ u8 *eid_len_offset, *max_bssid_indicator_offset;
+
+ *eid++ = WLAN_EID_MULTIPLE_BSSID;
+ eid_len_offset = eid++;
+ max_bssid_indicator_offset = eid++;
+
+ for (i = *bss_index; i < hapd->iface->num_bss; i++) {
+ struct hostapd_data *bss = hapd->iface->bss[i];
+ struct hostapd_bss_config *conf;
+ u8 *eid_len_pos, *nontx_bss_start = eid;
+ const u8 *auth, *rsn = NULL, *rsnx = NULL;
+ u8 ie_count = 0, non_inherit_ie[3];
+ size_t auth_len = 0;
+ u16 capab_info;
+
+ if (known_bss && (known_bss_len > (i / 8))) {
+ known_bss = &known_bss[i / 8];
+ if (*known_bss & (u8)(BIT(i % 8)))
+ continue;
+ }
+
+ if (!bss || !bss->conf || !bss->started)
+ continue;
+ conf = bss->conf;
+
+ *eid++ = WLAN_EID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE;
+ eid_len_pos = eid++;
+
+ *eid++ = WLAN_EID_NONTRANSMITTED_BSSID_CAPA;
+ *eid++ = sizeof(capab_info);
+ capab_info = host_to_le16(hostapd_own_capab_info(bss));
+ os_memcpy(eid, (const void *)&capab_info, sizeof(capab_info));
+ eid += sizeof(capab_info);
+
+ *eid++ = WLAN_EID_SSID;
+ *eid++ = conf->ssid.ssid_len;
+ os_memcpy(eid, conf->ssid.ssid, conf->ssid.ssid_len);
+ eid += conf->ssid.ssid_len;
+
+ *eid++ = WLAN_EID_MULTIPLE_BSSID_INDEX;
+ if (frame_type == WLAN_FC_STYPE_BEACON) {
+ *eid++ = 3;
+ *eid++ = i;
+ if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
+ (conf->dtim_period % elem_count))
+ conf->dtim_period = elem_count;
+ *eid++ = conf->dtim_period;
+ *eid++ = 0xFF;
+ } else {
+ *eid++ = 1;
+ *eid++ = i;
+ }
+
+ auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
+ if (auth) {
+ rsn = get_ie(auth, auth_len, WLAN_EID_RSN);
+ if (rsn) {
+ os_memcpy(eid, rsn, 2 + rsn[1]);
+ eid += (2 + rsn[1]);
+ }
+
+ rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX);
+ if (rsnx) {
+ os_memcpy(eid, rsnx, 2 + rsnx[1]);
+ eid += (2 + rsnx[1]);
+ }
+ }
+ if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN)) {
+ non_inherit_ie[ie_count] = WLAN_EID_RSN;
+ ie_count++;
+ }
+ if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX)) {
+ non_inherit_ie[ie_count] = WLAN_EID_RSNX;
+ ie_count++;
+ }
+ if (hapd->conf->xrates_supported &&
+ !bss->conf->xrates_supported) {
+ non_inherit_ie[ie_count] = WLAN_EID_EXT_SUPP_RATES;
+ ie_count++;
+ }
+ if (ie_count) {
+ *eid++ = WLAN_EID_EXTENSION;
+ *eid++ = 2 + ie_count;
+ *eid++ = WLAN_EID_EXT_NON_INHERITANCE;
+ *eid++ = ie_count;
+ os_memcpy(eid, non_inherit_ie, ie_count);
+ eid += ie_count;
+ }
+
+ *eid_len_pos = (eid - eid_len_pos) - 1;
+
+ if (((eid - eid_len_offset) - 1) > 255) {
+ eid = nontx_bss_start;
+ goto mbssid_too_big;
+ }
+ }
+
+mbssid_too_big:
+ *bss_index = i;
+ *max_bssid_indicator_offset = max_bssid_indicator;
+ if (*max_bssid_indicator_offset < 1)
+ *max_bssid_indicator_offset = 1;
+ *eid_len_offset = (eid - eid_len_offset) - 1;
+ return eid;
+}
+
+
+u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
+ u32 frame_type, u8 elem_count, u8 **elem_offset,
+ const u8 *known_bss, size_t known_bss_len)
+{
+ size_t bss_index = 1;
+ u8 elem_index = 0;
+
+ if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
+ (frame_type != WLAN_FC_STYPE_BEACON &&
+ frame_type != WLAN_FC_STYPE_PROBE_RESP))
+ return eid;
+
+ if (frame_type == WLAN_FC_STYPE_BEACON && !elem_offset) {
+ wpa_printf(MSG_ERROR, "MBSSID: Insufficient data for beacons");
+ return eid;
+ }
+
+ while (bss_index < hapd->iface->num_bss) {
+ if (frame_type == WLAN_FC_STYPE_BEACON) {
+ if (elem_index == elem_count) {
+ wpa_printf(MSG_WARNING,
+ "MBSSID: More number of elements than provided array");
+ break;
+ }
+
+ elem_offset[elem_index] = eid;
+ elem_index = elem_index + 1;
+ }
+ eid = hostapd_eid_mbssid_elem(hapd, eid, end, frame_type,
+ hostapd_max_bssid_indicator(hapd),
+ &bss_index, elem_count,
+ known_bss, known_bss_len);
+ }
+ return eid;
+}
+
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index fa1f47b..bb454bb 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -214,5 +214,10 @@ u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta,
enum ieee80211_op_mode opmode,
const u8 *he_capab, size_t he_capab_len,
const u8 *eht_capab, size_t eht_capab_len);
-
+size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
+ u8 *elem_count, const u8 *known_bss,
+ size_t known_bss_len);
+u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
+ u32 frame_type, u8 elem_count, u8 **elem_offset,
+ const u8 *known_bss, size_t known_bss_len);
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 4f85d78..7f5b475 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -364,6 +364,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
if (hapd->conf->bss_transition)
*pos |= 0x08; /* Bit 19 - BSS Transition */
+ if (hapd->iconf->mbssid)
+ *pos |= 0x40; /* Bit 22 - Multiple BSSID */
break;
case 3: /* Bits 24-31 */
#ifdef CONFIG_WNM_AP
@@ -436,6 +438,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
(hapd->iface->drv_flags &
WPA_DRIVER_FLAGS_BEACON_PROTECTION))
*pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */
+ if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED)
+ *pos |= 0x08; /* Bit 83 - Enhanced multiple BSSID */
break;
case 11: /* Bits 88-95 */
#ifdef CONFIG_SAE_PK
@@ -471,6 +475,13 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
*pos &= ~hapd->conf->ext_capa_mask[i];
*pos |= hapd->conf->ext_capa[i];
}
+
+ /* Clear bits 83 and 22 if EMA and MBSSID are not enabled
+ * otherwise association fails with some clients */
+ if (i == 10 && hapd->iconf->mbssid < ENHANCED_MBSSID_ENABLED)
+ *pos &= ~0x08;
+ if (i == 2 && !hapd->iconf->mbssid)
+ *pos &= ~0x40;
}
while (len > 0 && eid[1 + len] == 0) {
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index c8ee90c..2fab7c3 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -315,6 +315,10 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
elems->eht_operation = pos;
elems->eht_operation_len = elen;
break;
+ case WLAN_EID_EXT_KNOWN_BSSID:
+ elems->mbssid_known_bss = pos;
+ elems->mbssid_known_bss_len = elen;
+ break;
default:
if (show_errors) {
wpa_printf(MSG_MSGDUMP,
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 94e1d7b..1e4e27d 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -119,6 +119,7 @@ struct ieee802_11_elems {
const u8 *pasn_params;
const u8 *eht_capabilities;
const u8 *eht_operation;
+ const u8 *mbssid_known_bss;
u8 ssid_len;
u8 supp_rates_len;
@@ -176,6 +177,8 @@ struct ieee802_11_elems {
u8 eht_capabilities_len;
u8 eht_operation_len;
+ u8 mbssid_known_bss_len;
+
struct mb_ies_info mb_ies;
struct frag_ies_info frag_ies;
};
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 62088bd..0bbbca9 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -481,6 +481,9 @@
#define WLAN_EID_EXT_SPATIAL_REUSE 39
#define WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT 42
#define WLAN_EID_EXT_OCV_OCI 54
+#define WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION 55
+#define WLAN_EID_EXT_NON_INHERITANCE 56
+#define WLAN_EID_EXT_KNOWN_BSSID 57
#define WLAN_EID_EXT_SHORT_SSID_LIST 58
#define WLAN_EID_EXT_HE_6GHZ_BAND_CAP 59
#define WLAN_EID_EXT_EDMG_CAPABILITIES 61
@@ -497,6 +500,8 @@
#define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110
#define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114
+#define WLAN_EID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE 0
+
/* Extended Capabilities field */
#define WLAN_EXT_CAPAB_20_40_COEX 0
#define WLAN_EXT_CAPAB_GLK 1
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 82daef0..36f465c 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1633,6 +1633,43 @@ struct wpa_driver_ap_params {
* ibf_enable=<val>
*/
u8 ibf_enable;
+
+ /**
+ * mbssid_tx_iface - Transmitting interface of the MBSSID set
+ */
+ const char *mbssid_tx_iface;
+
+ /**
+ * mbssid_index - The index of this BSS in the MBSSID set
+ */
+ unsigned int mbssid_index;
+
+ /**
+ * mbssid_elem - Buffer containing all MBSSID elements
+ */
+ u8 *mbssid_elem;
+
+ /**
+ * mbssid_elem_len - Total length of all MBSSID elements
+ */
+ size_t mbssid_elem_len;
+
+ /**
+ * mbssid_elem_count - The number of MBSSID elements
+ */
+ u8 mbssid_elem_count;
+
+ /**
+ * mbssid_elem_offset - Offsets to elements in mbssid_elem.
+ * Kernel will use these offsets to generate multiple BSSID beacons.
+ */
+ u8 **mbssid_elem_offset;
+
+ /**
+ * ema - Enhanced MBSSID advertisements support.
+ */
+ bool ema;
+
};
struct wpa_driver_mesh_bss_params {
@@ -2197,6 +2234,11 @@ struct wpa_driver_capa {
/* Maximum number of supported CSA counters */
u16 max_csa_counters;
+
+ /* Maximum number of interfaces supported for MBSSID advertisements */
+ u8 mbssid_max_interfaces;
+ /* Maximum profile periodicity for enhanced MBSSID advertisements */
+ u8 ema_max_periodicity;
};
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 6c65901..3753409 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -4540,6 +4540,55 @@ static int nl80211_unsol_bcast_probe_resp(struct i802_bss *bss,
nla_nest_end(msg, attr);
return 0;
}
+
+
+static int nl80211_mbssid(struct nl_msg *msg,
+ struct wpa_driver_ap_params *params)
+{
+ struct nlattr *config, *elems;
+ int ifidx;
+
+ if (!params->mbssid_tx_iface)
+ return 0;
+
+ config = nla_nest_start(msg, NL80211_ATTR_MBSSID_CONFIG);
+ if (!config)
+ return -1;
+
+ nla_put_u8(msg, NL80211_MBSSID_CONFIG_ATTR_INDEX, params->mbssid_index);
+ if (params->mbssid_tx_iface) {
+ ifidx = if_nametoindex(params->mbssid_tx_iface);
+ if (ifidx <= 0)
+ return -1;
+ nla_put_u32(msg,
+ NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX,
+ ifidx);
+ }
+
+ if (params->ema)
+ nla_put_flag(msg, NL80211_MBSSID_CONFIG_ATTR_EMA);
+
+ nla_nest_end(msg, config);
+
+ if (params->mbssid_elem_count && params->mbssid_elem_len &&
+ params->mbssid_elem_offset && *params->mbssid_elem_offset) {
+ u8 i, **offs = params->mbssid_elem_offset;
+
+ elems = nla_nest_start(msg, NL80211_ATTR_MBSSID_ELEMS);
+ if (!elems)
+ return -1;
+
+ for (i = 0; i < params->mbssid_elem_count - 1; i++)
+ nla_put(msg, i + 1, offs[i + 1] - offs[i], offs[i]);
+
+ nla_put(msg, i + 1,
+ *offs + params->mbssid_elem_len - offs[i],
+ offs[i]);
+
+ nla_nest_end(msg, elems);
+ }
+ return 0;
+}
#endif /* CONFIG_IEEE80211AX */
@@ -4838,6 +4887,9 @@ static int wpa_driver_nl80211_set_ap(void *priv,
if (params->unsol_bcast_probe_resp_interval &&
nl80211_unsol_bcast_probe_resp(bss, msg, params) < 0)
goto fail;
+
+ if (nl80211_mbssid(msg, params) < 0)
+ goto fail;
#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_SAE
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 06a52db..d8078bc 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -857,6 +857,30 @@ err:
}
+static void wiphy_info_mbssid(struct wpa_driver_capa *cap, struct nlattr *attr)
+{
+ struct nlattr *config[NL80211_MBSSID_CONFIG_ATTR_MAX + 1];
+
+ if (nla_parse_nested(config, NL80211_MBSSID_CONFIG_ATTR_MAX, attr,
+ NULL))
+ return;
+
+ if (!config[NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES])
+ return;
+
+ cap->mbssid_max_interfaces =
+ nla_get_u8(config[NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES]);
+
+ if (config[NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY])
+ cap->ema_max_periodicity =
+ nla_get_u8(config[NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY]);
+
+ wpa_printf(MSG_DEBUG,
+ "multiple_bssid: max interfaces %u, max profile periodicity %u\n",
+ cap->mbssid_max_interfaces, cap->ema_max_periodicity);
+}
+
+
static int wiphy_info_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -1106,6 +1130,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
if (tb[NL80211_ATTR_WIPHY_SELF_MANAGED_REG])
capa->flags |= WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY;
+ if (tb[NL80211_ATTR_MBSSID_CONFIG])
+ wiphy_info_mbssid(capa, tb[NL80211_ATTR_MBSSID_CONFIG]);
+
return NL_SKIP;
}
--
2.18.0