@@ -432,6 +432,9 @@ static void hostapd_set_mbssid_beacon(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
struct hostapd_iface *iface = hapd->iface;
+ struct hostapd_data *tx_bss;
+ size_t len;
+ u8 num_mbssid = 0, *end;
if (!iface->conf->mbssid || iface->num_bss == 1)
return;
@@ -447,9 +450,54 @@ static void hostapd_set_mbssid_beacon(struct hostapd_data *hapd,
return;
}
- params->mbssid_tx_iface = hostapd_mbssid_get_tx_bss(hapd)->conf->iface;
+ tx_bss = hostapd_mbssid_get_tx_bss(hapd);
+ params->mbssid_tx_iface = tx_bss->conf->iface;
params->mbssid_index = hostapd_mbssid_get_bss_index(hapd);
params->mbssid_count = iface->num_bss;
+
+ len = hostapd_eid_mbssid_len(tx_bss, WLAN_FC_STYPE_BEACON, &num_mbssid);
+ if (hapd->iconf->ema) {
+ if (!iface->ema_max_periodicity) {
+ wpa_printf(MSG_DEBUG,
+ "MBSSID: Driver doesn't support enhanced multiple BSSID advertisements");
+ return;
+ }
+ if (num_mbssid > iface->ema_max_periodicity) {
+ wpa_printf(MSG_DEBUG,
+ "MBSSID: Driver supports maximum %u EMA profile periodicity",
+ iface->ema_max_periodicity);
+ return;
+ }
+ params->ema = 1;
+ }
+
+ if (hapd != tx_bss || !num_mbssid)
+ return;
+
+ params->mbssid_elem_count = num_mbssid;
+ params->mbssid_elem = os_zalloc(len);
+ if (!params->mbssid_elem) {
+ wpa_printf(MSG_ERROR,
+ "Memory allocation failed for multiple BSSID elements");
+ return;
+ }
+
+ params->mbssid_elem_offset = os_zalloc(params->mbssid_elem_count *
+ sizeof(u8 *));
+ if (!params->mbssid_elem_offset) {
+ wpa_printf(MSG_ERROR,
+ "MBSSID: Memory allocation failed for multiple BSSID element offsets");
+ os_free(params->mbssid_elem);
+ params->mbssid_elem = NULL;
+ return;
+ }
+
+ end = hostapd_eid_mbssid(tx_bss, params->mbssid_elem,
+ params->mbssid_elem + len,
+ WLAN_FC_STYPE_BEACON,
+ params->mbssid_elem_count,
+ params->mbssid_elem_offset);
+ params->mbssid_elem_len = end - params->mbssid_elem;
return;
}
@@ -462,8 +510,11 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
u8 *pos, *epos, *csa_pos;
size_t buflen;
+ hapd = hostapd_mbssid_get_tx_bss(hapd);
+
#define MAX_PROBERESP_LEN 768
buflen = MAX_PROBERESP_LEN;
+
#ifdef CONFIG_WPS
if (hapd->wps_probe_resp_ie)
buflen += wpabuf_len(hapd->wps_probe_resp_ie);
@@ -495,6 +546,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211AX */
+ buflen += hostapd_eid_mbssid_len(hapd, WLAN_FC_STYPE_PROBE_RESP, NULL);
buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP);
buflen += hostapd_mbo_ie_len(hapd);
buflen += hostapd_eid_owe_trans_len(hapd);
@@ -563,6 +615,8 @@ 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);
pos = hostapd_eid_ext_capab(hapd, pos);
@@ -1100,6 +1154,9 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#endif /* CONFIG_TESTING_OPTIONS */
+ 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);
@@ -1126,7 +1183,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);
@@ -1794,6 +1852,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;
@@ -3956,6 +3956,23 @@ static void handle_auth(struct hostapd_data *hapd,
}
+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;
@@ -7450,4 +7467,199 @@ 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)
+{
+ 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, *rsnx;
+ size_t nontx_profile_len, auth_len;
+
+ 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 ((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)
+{
+ 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);
+
+ 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)
+{
+ 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, *rsnx;
+ size_t auth_len = 0;
+ u16 capab_info;
+
+ 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;
+ *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]);
+ }
+ }
+
+ *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)
+{
+ 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);
+ }
+ return eid;
+}
+
#endif /* CONFIG_NATIVE_WINDOWS */
@@ -119,8 +119,11 @@ u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
int hostapd_update_time_adv(struct hostapd_data *hapd);
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
-
int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
+size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
+ u8 *elem_count);
+u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
+ u32 frame_type, u8 elem_count, u8 **elem_offset);
#ifdef CONFIG_SAE
void sae_clear_retransmit_timer(struct hostapd_data *hapd,
struct sta_info *sta);
@@ -490,6 +490,8 @@
#define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93
#define WLAN_EID_EXT_PASN_PARAMS 100
+#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
@@ -1597,6 +1597,33 @@ struct wpa_driver_ap_params {
* mbssid_count - Total number of BSSs in the group
*/
unsigned int mbssid_count;
+
+ /**
+ * mbssid_elem - Buffer containing all multiple BSSID elements
+ */
+ u8 *mbssid_elem;
+
+ /**
+ * mbssid_elem_len - Total length of all multiple BSSID elements
+ */
+ size_t mbssid_elem_len;
+
+ /**
+ * mbssid_elem_count - The number of multiple bssid 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 multi-bssid advertisements support.
+ */
+ u8 ema;
+
};
struct wpa_driver_mesh_bss_params {