| From 6bcb8ed50638aeecd32cc43287a49e3caecd4b3e 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/35] 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, |
| ¶ms->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 |
| |