developer | 2fd555a | 2023-07-25 05:48:15 +0800 | [diff] [blame] | 1 | From 6bcb8ed50638aeecd32cc43287a49e3caecd4b3e Mon Sep 17 00:00:00 2001 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 2 | From: mtk20656 <chank.chen@mediatek.com> |
| 3 | Date: Thu, 2 Mar 2023 10:51:43 +0800 |
developer | 2fd555a | 2023-07-25 05:48:15 +0800 | [diff] [blame] | 4 | Subject: [PATCH 21/35] hostapd: mtk: add 11v_mbss and ema support for hostapd |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 5 | |
| 6 | Signed-off-by: mtk20656 <chank.chen@mediatek.com> |
| 7 | --- |
| 8 | hostapd/config_file.c | 9 + |
| 9 | hostapd/hostapd.conf | 58 +++++++ |
| 10 | hostapd/main.c | 3 + |
| 11 | src/ap/ap_config.c | 12 ++ |
| 12 | src/ap/ap_config.h | 6 + |
| 13 | src/ap/beacon.c | 124 ++++++++++++-- |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 14 | src/ap/hostapd.c | 72 +++++++- |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 15 | src/ap/hostapd.h | 7 + |
| 16 | src/ap/ieee802_11.c | 276 +++++++++++++++++++++++++++++- |
| 17 | src/ap/ieee802_11.h | 7 +- |
| 18 | src/ap/ieee802_11_shared.c | 11 ++ |
| 19 | src/common/ieee802_11_common.c | 4 + |
| 20 | src/common/ieee802_11_common.h | 3 + |
| 21 | src/common/ieee802_11_defs.h | 5 + |
| 22 | src/drivers/driver.h | 42 +++++ |
| 23 | src/drivers/driver_nl80211.c | 52 ++++++ |
| 24 | src/drivers/driver_nl80211_capa.c | 27 +++ |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 25 | 17 files changed, 698 insertions(+), 20 deletions(-) |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 26 | |
| 27 | diff --git a/hostapd/config_file.c b/hostapd/config_file.c |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 28 | index 649618b..3f26191 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 29 | --- a/hostapd/config_file.c |
| 30 | +++ b/hostapd/config_file.c |
| 31 | @@ -3663,6 +3663,15 @@ static int hostapd_config_fill(struct hostapd_config *conf, |
| 32 | return 1; |
| 33 | } |
| 34 | bss->unsol_bcast_probe_resp_interval = val; |
| 35 | + } else if (os_strcmp(buf, "mbssid") == 0) { |
| 36 | + int mbssid = atoi(pos); |
| 37 | + if (mbssid < 0 || mbssid > ENHANCED_MBSSID_ENABLED) { |
| 38 | + wpa_printf(MSG_ERROR, |
| 39 | + "Line %d: invalid mbssid (%d): '%s'.", |
| 40 | + line, mbssid, pos); |
| 41 | + return 1; |
| 42 | + } |
| 43 | + conf->mbssid = mbssid; |
| 44 | } else if (os_strcmp(buf, "mu_onoff") == 0) { |
| 45 | int val = atoi(pos); |
| 46 | if (val < 0 || val > 15) { |
| 47 | diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 48 | index e3a5eb3..f926029 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 49 | --- a/hostapd/hostapd.conf |
| 50 | +++ b/hostapd/hostapd.conf |
| 51 | @@ -3123,3 +3123,61 @@ own_ip_addr=127.0.0.1 |
| 52 | #bss=wlan0_1 |
| 53 | #bssid=00:13:10:95:fe:0b |
| 54 | # ... |
| 55 | +# |
| 56 | +# Multiple BSSID Advertisement in 802.11ax |
| 57 | +# IEEE Std 802.11ax-2021 added a feature where instead of multiple interfaces |
| 58 | +# on a common radio transmitting individual beacons, those can form a set with |
| 59 | +# a common beacon is transmitted for all. The interface which is brought up |
| 60 | +# first is called as the transmitting profile of the MBSSID set which transmits |
| 61 | +# the beacons. The remaining interfaces are called as the non-transmitting |
| 62 | +# profiles and these are advertised inside the multiple BSSID element in the |
| 63 | +# beacons and probe response frames. |
| 64 | +# The transmitting interface is visible to all clients in the vicinity, however |
| 65 | +# the clients which do not support parsing of the multiple BSSID element will |
| 66 | +# not be able to connect to the non-transmitting interfaces. |
| 67 | +# |
| 68 | +# Enhanced Multiple BSSID Advertisements (EMA) |
| 69 | +# When enabled, the non-transmitting interfaces are split into multiple |
| 70 | +# beacons. The number of beacons required to cover all the non-transmitting |
| 71 | +# profiles is called as the profile periodicity. |
| 72 | +# |
| 73 | +# Refer to IEEE Std 802.11-2020 for details regarding the procedure and |
| 74 | +# required MAC address assignment. |
| 75 | +# |
| 76 | +# Following configuration is per radio. |
| 77 | +# 0 = Disabled (Default) |
| 78 | +# 1 = Multiple BSSID advertisements enabled. |
| 79 | +# 2 = Enhanced multiple BSSID advertisements enabled. |
| 80 | +#mbssid=0 |
| 81 | +# |
| 82 | +# The transmitting interface should be added with 'interface' option while |
| 83 | +# the non-transmitting interfaces should be added using 'bss' option. |
| 84 | +# Security configuration should be added separately per interface, if required. |
| 85 | +# |
| 86 | +# Example: |
| 87 | +#mbssid=2 |
| 88 | +#interface=wlan2 |
| 89 | +#ctrl_interface=/var/run/hostapd |
| 90 | +#wpa_passphrase=0123456789 |
| 91 | +#ieee80211w=2 |
| 92 | +#sae_pwe=1 |
| 93 | +#auth_algs=1 |
| 94 | +#wpa=2 |
| 95 | +#wpa_pairwise=CCMP |
| 96 | +#ssid=<SSID-0> |
| 97 | +#bridge=br-lan |
| 98 | +#wpa_key_mgmt=SAE |
| 99 | +#bssid=00:03:7f:12:84:84 |
| 100 | +# |
| 101 | +#bss=wlan2-1 |
| 102 | +#ctrl_interface=/var/run/hostapd |
| 103 | +#wpa_passphrase=0123456789 |
| 104 | +#ieee80211w=2 |
| 105 | +#sae_pwe=1 |
| 106 | +#auth_algs=1 |
| 107 | +#wpa=2 |
| 108 | +#wpa_pairwise=CCMP |
| 109 | +#ssid=<SSID-1> |
| 110 | +#bridge=br-lan |
| 111 | +#wpa_key_mgmt=SAE |
| 112 | +#bssid=00:03:7f:12:84:85 |
| 113 | diff --git a/hostapd/main.c b/hostapd/main.c |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 114 | index 70a4b32..1b6474a 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 115 | --- a/hostapd/main.c |
| 116 | +++ b/hostapd/main.c |
| 117 | @@ -253,6 +253,9 @@ static int hostapd_driver_init(struct hostapd_iface *iface) |
| 118 | wpa_printf(MSG_ERROR, "set_wowlan failed"); |
| 119 | } |
| 120 | os_free(triggs); |
| 121 | + |
| 122 | + iface->mbssid_max_interfaces = capa.mbssid_max_interfaces; |
| 123 | + iface->ema_max_periodicity = capa.ema_max_periodicity; |
| 124 | } |
| 125 | |
| 126 | return 0; |
| 127 | diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 128 | index 4e46a62..7d9d5cb 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 129 | --- a/src/ap/ap_config.c |
| 130 | +++ b/src/ap/ap_config.c |
| 131 | @@ -1462,6 +1462,12 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, |
| 132 | } |
| 133 | #endif /* CONFIG_IEEE80211BE */ |
| 134 | |
| 135 | + if (full_config && bss->ignore_broadcast_ssid && conf->mbssid) { |
| 136 | + wpa_printf(MSG_ERROR, |
| 137 | + "Hidden SSID is not suppored when MBSSID is enabled"); |
| 138 | + return -1; |
| 139 | + } |
| 140 | + |
| 141 | return 0; |
| 142 | } |
| 143 | |
| 144 | @@ -1545,6 +1551,12 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config) |
| 145 | } |
| 146 | #endif /* CONFIG_IEEE80211BE */ |
| 147 | |
| 148 | + if (full_config && conf->mbssid && !conf->ieee80211ax) { |
| 149 | + wpa_printf(MSG_ERROR, |
| 150 | + "Cannot enable multiple BSSID support without ieee80211ax"); |
| 151 | + return -1; |
| 152 | + } |
| 153 | + |
| 154 | for (i = 0; i < conf->num_bss; i++) { |
| 155 | if (hostapd_config_check_bss(conf->bss[i], conf, full_config)) |
| 156 | return -1; |
| 157 | diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 158 | index 7aeb176..51476b8 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 159 | --- a/src/ap/ap_config.h |
| 160 | +++ b/src/ap/ap_config.h |
| 161 | @@ -923,6 +923,8 @@ struct hostapd_bss_config { |
| 162 | u8 ext_capa[EXT_CAPA_MAX_LEN]; |
| 163 | |
| 164 | u8 rnr; |
| 165 | + |
| 166 | + bool xrates_supported; |
| 167 | }; |
| 168 | |
| 169 | /** |
| 170 | @@ -1163,6 +1165,10 @@ struct hostapd_config { |
| 171 | u8 ibf_enable; |
| 172 | u8 dfs_detect_mode; |
| 173 | u8 amsdu; |
| 174 | + |
| 175 | +#define MBSSID_ENABLED 1 |
| 176 | +#define ENHANCED_MBSSID_ENABLED 2 |
| 177 | + u8 mbssid; |
| 178 | }; |
| 179 | |
| 180 | enum three_wire_mode { |
| 181 | diff --git a/src/ap/beacon.c b/src/ap/beacon.c |
developer | 8eb72a3 | 2023-03-30 08:32:07 +0800 | [diff] [blame] | 182 | index f3ea5c2..ad56046 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 183 | --- a/src/ap/beacon.c |
| 184 | +++ b/src/ap/beacon.c |
| 185 | @@ -462,15 +462,77 @@ static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid) |
| 186 | } |
| 187 | |
| 188 | |
| 189 | +static int ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd, |
| 190 | + struct wpa_driver_ap_params *params, |
| 191 | + u8 **eid) |
| 192 | +{ |
| 193 | + struct hostapd_iface *iface = hapd->iface; |
| 194 | + struct hostapd_data *tx_bss; |
| 195 | + size_t len; |
| 196 | + u8 elem_count = 0, *elem = NULL, **elem_offset = NULL, *end; |
| 197 | + u8 *tailpos = *eid; |
| 198 | + |
| 199 | + if (!iface->mbssid_max_interfaces || |
| 200 | + iface->num_bss > iface->mbssid_max_interfaces || |
| 201 | + (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED && |
| 202 | + !iface->ema_max_periodicity)) |
| 203 | + goto fail; |
| 204 | + |
| 205 | + tx_bss = hostapd_mbssid_get_tx_bss(hapd); |
| 206 | + len = hostapd_eid_mbssid_len(tx_bss, WLAN_FC_STYPE_BEACON, &elem_count, |
| 207 | + NULL, 0); |
| 208 | + if (!len || (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED && |
| 209 | + elem_count > iface->ema_max_periodicity)) |
| 210 | + goto fail; |
| 211 | + |
| 212 | + elem = os_zalloc(len); |
| 213 | + if (!elem) |
| 214 | + goto fail; |
| 215 | + |
| 216 | + elem_offset = os_zalloc(elem_count * sizeof(u8 *)); |
| 217 | + if (!elem_offset) |
| 218 | + goto fail; |
| 219 | + |
| 220 | + end = hostapd_eid_mbssid(tx_bss, elem, elem + len, WLAN_FC_STYPE_BEACON, |
| 221 | + elem_count, elem_offset, NULL, 0); |
| 222 | + |
| 223 | + params->mbssid_tx_iface = tx_bss->conf->iface; |
| 224 | + params->mbssid_index = hostapd_mbssid_get_bss_index(hapd); |
| 225 | + params->mbssid_elem = elem; |
| 226 | + params->mbssid_elem_len = end - elem; |
| 227 | + params->mbssid_elem_count = elem_count; |
| 228 | + params->mbssid_elem_offset = elem_offset; |
| 229 | + if (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED) { |
| 230 | + params->ema = true; |
| 231 | + *tailpos++ = WLAN_EID_EXTENSION; |
| 232 | + *tailpos++ = 3; |
| 233 | + *tailpos++ = WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION; |
| 234 | + *tailpos++ = iface->num_bss; |
| 235 | + *tailpos++ = params->mbssid_elem_count; |
| 236 | + *eid = tailpos; |
| 237 | + } |
| 238 | + |
| 239 | + return 0; |
| 240 | + |
| 241 | +fail: |
| 242 | + os_free(elem); |
| 243 | + wpa_printf(MSG_ERROR, "MBSSID: Configuration failed"); |
| 244 | + return -1; |
| 245 | +} |
| 246 | + |
| 247 | + |
| 248 | static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, |
| 249 | const struct ieee80211_mgmt *req, |
| 250 | int is_p2p, size_t *resp_len, |
| 251 | - bool bcast_probe_resp) |
| 252 | + bool bcast_probe_resp, const u8 *known_bss, |
| 253 | + u8 known_bss_len) |
| 254 | { |
| 255 | struct ieee80211_mgmt *resp; |
| 256 | - u8 *pos, *epos, *csa_pos; |
| 257 | + u8 *pos, *epos, *csa_pos, *ext_cap_pos; |
| 258 | size_t buflen; |
| 259 | |
| 260 | + hapd = hostapd_mbssid_get_tx_bss(hapd); |
| 261 | + |
| 262 | #define MAX_PROBERESP_LEN 768 |
| 263 | buflen = MAX_PROBERESP_LEN; |
| 264 | #ifdef CONFIG_WPS |
| 265 | @@ -517,6 +579,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, |
| 266 | } |
| 267 | #endif /* CONFIG_IEEE80211BE */ |
| 268 | |
| 269 | + buflen += hostapd_eid_mbssid_len(hapd, WLAN_FC_STYPE_PROBE_RESP, NULL, |
| 270 | + known_bss, known_bss_len); |
| 271 | buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP); |
| 272 | buflen += hostapd_mbo_ie_len(hapd); |
| 273 | buflen += hostapd_eid_owe_trans_len(hapd); |
| 274 | @@ -588,8 +652,16 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, |
| 275 | pos = hostapd_eid_supported_op_classes(hapd, pos); |
| 276 | pos = hostapd_eid_ht_capabilities(hapd, pos); |
| 277 | pos = hostapd_eid_ht_operation(hapd, pos); |
| 278 | + pos = hostapd_eid_mbssid(hapd, pos, epos, WLAN_FC_STYPE_PROBE_RESP, 0, |
| 279 | + NULL, known_bss, known_bss_len); |
| 280 | |
| 281 | + ext_cap_pos = pos; |
| 282 | pos = hostapd_eid_ext_capab(hapd, pos); |
| 283 | + if (hapd->iconf->mbssid >= MBSSID_ENABLED && !known_bss_len) |
| 284 | + ext_cap_pos[12] |= 0x01; /* Probe responses always include all |
| 285 | + * non-tx profiles except when a list |
| 286 | + * of known BSSes is included in the |
| 287 | + * probe request. */ |
| 288 | |
| 289 | pos = hostapd_eid_time_adv(hapd, pos); |
| 290 | pos = hostapd_eid_time_zone(hapd, pos); |
| 291 | @@ -1153,16 +1225,23 @@ void handle_probe_req(struct hostapd_data *hapd, |
| 292 | } |
| 293 | #endif /* CONFIG_TESTING_OPTIONS */ |
| 294 | |
| 295 | + /* Do not send probe response from a non-transmitting multiple BSSID |
| 296 | + * profile unless the probe request is directed at that paticular BSS */ |
| 297 | + if (hapd != hostapd_mbssid_get_tx_bss(hapd) && res != EXACT_SSID_MATCH) |
| 298 | + return; |
| 299 | + |
| 300 | wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, RX_PROBE_REQUEST "sa=" MACSTR |
| 301 | " signal=%d", MAC2STR(mgmt->sa), ssi_signal); |
| 302 | |
| 303 | if (is_6ghz_op_class(hapd->iconf->op_class) && |
| 304 | is_broadcast_ether_addr(mgmt->da)) |
| 305 | resp = hostapd_gen_probe_resp(hapd, NULL, elems.p2p != NULL, |
| 306 | - &resp_len, true); |
developer | f8c237a | 2023-03-28 16:08:27 +0800 | [diff] [blame] | 307 | + &resp_len, true, elems.mbssid_known_bss, |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 308 | + elems.mbssid_known_bss_len); |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 309 | else |
| 310 | resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL, |
| 311 | - &resp_len, false); |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 312 | + &resp_len, false, elems.mbssid_known_bss, |
| 313 | + elems.mbssid_known_bss_len); |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 314 | if (resp == NULL) |
| 315 | return; |
| 316 | |
| 317 | @@ -1184,7 +1263,8 @@ void handle_probe_req(struct hostapd_data *hapd, |
| 318 | hapd->cs_c_off_ecsa_proberesp; |
| 319 | } |
| 320 | |
| 321 | - ret = hostapd_drv_send_mlme(hapd, resp, resp_len, noack, |
| 322 | + ret = hostapd_drv_send_mlme(hostapd_mbssid_get_tx_bss(hapd), resp, |
| 323 | + resp_len, noack, |
| 324 | csa_offs_len ? csa_offs : NULL, |
| 325 | csa_offs_len, 0); |
| 326 | |
| 327 | @@ -1231,7 +1311,7 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd, |
| 328 | "this"); |
| 329 | |
| 330 | /* Generate a Probe Response template for the non-P2P case */ |
| 331 | - return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len, false); |
| 332 | + return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len, false, NULL, 0); |
| 333 | } |
| 334 | |
| 335 | #endif /* NEED_AP_MLME */ |
| 336 | @@ -1250,7 +1330,7 @@ static u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd, |
| 337 | |
| 338 | return hostapd_gen_probe_resp(hapd, NULL, 0, |
| 339 | ¶ms->unsol_bcast_probe_resp_tmpl_len, |
| 340 | - true); |
| 341 | + true, NULL, 0); |
| 342 | } |
| 343 | #endif /* CONFIG_IEEE80211AX */ |
| 344 | |
| 345 | @@ -1533,8 +1613,12 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, |
| 346 | size_t resp_len = 0; |
| 347 | #ifdef NEED_AP_MLME |
| 348 | u16 capab_info; |
| 349 | - u8 *pos, *tailpos, *tailend, *csa_pos; |
| 350 | + u8 *pos, *tailpos, *tailend, *csa_pos, *ext_cap_pos; |
| 351 | +#endif /* NEED_AP_MLME */ |
| 352 | |
| 353 | + os_memset(params, 0, sizeof(*params)); |
| 354 | + |
| 355 | +#ifdef NEED_AP_MLME |
| 356 | #define BEACON_HEAD_BUF_SIZE 256 |
| 357 | #define BEACON_TAIL_BUF_SIZE 512 |
| 358 | head = os_zalloc(BEACON_HEAD_BUF_SIZE); |
| 359 | @@ -1586,6 +1670,9 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, |
| 360 | } |
| 361 | #endif /* CONFIG_IEEE80211BE */ |
| 362 | |
| 363 | + if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && |
| 364 | + hapd == hostapd_mbssid_get_tx_bss(hapd)) |
| 365 | + tail_len += 5; /* Multiple BSSID Configuration element */ |
| 366 | tail_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_BEACON); |
| 367 | tail_len += hostapd_mbo_ie_len(hapd); |
| 368 | tail_len += hostapd_eid_owe_trans_len(hapd); |
| 369 | @@ -1671,9 +1758,23 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, |
| 370 | tailpos = hostapd_eid_supported_op_classes(hapd, tailpos); |
| 371 | tailpos = hostapd_eid_ht_capabilities(hapd, tailpos); |
| 372 | tailpos = hostapd_eid_ht_operation(hapd, tailpos); |
| 373 | - |
| 374 | + ext_cap_pos = tailpos; |
| 375 | tailpos = hostapd_eid_ext_capab(hapd, tailpos); |
| 376 | |
| 377 | + if (hapd->iconf->mbssid && hapd->iconf->num_bss > 1) { |
| 378 | + if (ieee802_11_build_ap_params_mbssid(hapd, params, &tailpos)) { |
| 379 | + os_free(head); |
| 380 | + os_free(tail); |
| 381 | + wpa_printf(MSG_ERROR, "Failed to set beacon data"); |
| 382 | + return -1; |
| 383 | + } else if (hapd->iconf->mbssid == MBSSID_ENABLED || |
| 384 | + (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && |
| 385 | + params->mbssid_elem_count == 1)) { |
| 386 | + /* Set the extended capability bit for "complete list |
| 387 | + * of non-tx profiles" */ |
| 388 | + ext_cap_pos[12] |= 0x01; |
| 389 | + } |
| 390 | + } |
| 391 | /* |
| 392 | * TODO: Time Advertisement element should only be included in some |
| 393 | * DTIM Beacon frames. |
| 394 | @@ -1794,7 +1895,6 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, |
| 395 | resp = hostapd_probe_resp_offloads(hapd, &resp_len); |
| 396 | #endif /* NEED_AP_MLME */ |
| 397 | |
| 398 | - os_memset(params, 0, sizeof(*params)); |
| 399 | params->head = (u8 *) head; |
| 400 | params->head_len = head_len; |
| 401 | params->tail = tail; |
| 402 | @@ -1897,6 +1997,10 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params) |
| 403 | params->head = NULL; |
| 404 | os_free(params->proberesp); |
| 405 | params->proberesp = NULL; |
| 406 | + os_free(params->mbssid_elem); |
| 407 | + params->mbssid_elem = NULL; |
| 408 | + os_free(params->mbssid_elem_offset); |
| 409 | + params->mbssid_elem_offset = NULL; |
| 410 | #ifdef CONFIG_FILS |
| 411 | os_free(params->fd_frame_tmpl); |
| 412 | params->fd_frame_tmpl = NULL; |
| 413 | diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c |
developer | 8eb72a3 | 2023-03-30 08:32:07 +0800 | [diff] [blame] | 414 | index 42e8ed7..ef0d6db 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 415 | --- a/src/ap/hostapd.c |
| 416 | +++ b/src/ap/hostapd.c |
| 417 | @@ -91,6 +91,29 @@ int hostapd_for_each_interface(struct hapd_interfaces *interfaces, |
| 418 | } |
| 419 | |
| 420 | |
| 421 | +struct hostapd_data * hostapd_mbssid_get_tx_bss(struct hostapd_data *hapd) |
| 422 | +{ |
| 423 | + if (hapd->iconf->mbssid) |
| 424 | + return hapd->iface->bss[0]; |
| 425 | + |
| 426 | + return hapd; |
| 427 | +} |
| 428 | + |
| 429 | + |
| 430 | +int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd) |
| 431 | +{ |
| 432 | + if (hapd->iconf->mbssid) { |
| 433 | + size_t i; |
| 434 | + |
| 435 | + for (i = 1; i < hapd->iface->num_bss; i++) |
| 436 | + if (hapd->iface->bss[i] == hapd) |
| 437 | + return i; |
| 438 | + } |
| 439 | + |
| 440 | + return 0; |
| 441 | +} |
| 442 | + |
| 443 | + |
| 444 | void hostapd_reconfig_encryption(struct hostapd_data *hapd) |
| 445 | { |
| 446 | if (hapd->wpa_auth) |
| 447 | @@ -1179,19 +1202,37 @@ static int db_table_create_radius_attributes(sqlite3 *db) |
| 448 | |
| 449 | #endif /* CONFIG_NO_RADIUS */ |
| 450 | |
| 451 | +static int hostapd_start_beacon(struct hostapd_data *hapd) |
| 452 | +{ |
| 453 | + struct hostapd_bss_config *conf = hapd->conf; |
| 454 | + |
| 455 | + if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0) |
| 456 | + return -1; |
| 457 | + |
| 458 | + if (hapd->driver && hapd->driver->set_operstate) |
| 459 | + hapd->driver->set_operstate(hapd->drv_priv, 1); |
| 460 | + |
| 461 | + return 0; |
| 462 | +} |
| 463 | |
| 464 | /** |
| 465 | * hostapd_setup_bss - Per-BSS setup (initialization) |
| 466 | * @hapd: Pointer to BSS data |
| 467 | * @first: Whether this BSS is the first BSS of an interface; -1 = not first, |
| 468 | * but interface may exist |
| 469 | + * @start_beacon: Whether beacons should be configured and transmission started |
| 470 | + * at this time. This is used when MBSSID IE is enabled where the |
| 471 | + * information regarding all BSSes should be retrieved before configuring |
| 472 | + * the beacons. The calling functions are responsible to configure the |
| 473 | + * beacon explicitly if this is set to 'false'. |
| 474 | * |
| 475 | * This function is used to initialize all per-BSS data structures and |
| 476 | * resources. This gets called in a loop for each BSS when an interface is |
| 477 | * initialized. Most of the modules that are initialized here will be |
| 478 | * deinitialized in hostapd_cleanup(). |
| 479 | */ |
| 480 | -static int hostapd_setup_bss(struct hostapd_data *hapd, int first) |
| 481 | +static int hostapd_setup_bss(struct hostapd_data *hapd, int first, |
| 482 | + bool start_beacon) |
| 483 | { |
| 484 | struct hostapd_bss_config *conf = hapd->conf; |
| 485 | u8 ssid[SSID_MAX_LEN + 1]; |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 486 | @@ -1464,9 +1505,6 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 487 | return -1; |
| 488 | } |
| 489 | |
| 490 | - if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0) |
| 491 | - return -1; |
| 492 | - |
| 493 | if (flush_old_stations && !conf->start_disabled && |
| 494 | conf->broadcast_deauth) { |
| 495 | u8 addr[ETH_ALEN]; |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 496 | @@ -1485,8 +1523,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 497 | if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0) |
| 498 | return -1; |
| 499 | |
| 500 | - if (hapd->driver && hapd->driver->set_operstate) |
| 501 | - hapd->driver->set_operstate(hapd->drv_priv, 1); |
developer | e2a629e | 2023-03-27 09:50:19 +0800 | [diff] [blame] | 502 | + if (start_beacon && hostapd_start_beacon(hapd) < 0) |
| 503 | + return -1; |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 504 | |
| 505 | hostapd_ubus_add_bss(hapd); |
| 506 | |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 507 | @@ -2214,7 +2252,7 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface, |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 508 | hapd = iface->bss[j]; |
| 509 | if (j) |
| 510 | os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN); |
| 511 | - if (hostapd_setup_bss(hapd, j == 0)) { |
| 512 | + if (hostapd_setup_bss(hapd, j == 0, !iface->conf->mbssid)) { |
| 513 | for (;;) { |
| 514 | hapd = iface->bss[j]; |
| 515 | hostapd_bss_deinit_no_free(hapd); |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 516 | @@ -2228,6 +2266,24 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface, |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 517 | if (is_zero_ether_addr(hapd->conf->bssid)) |
| 518 | prev_addr = hapd->own_addr; |
| 519 | } |
| 520 | + |
| 521 | + if (hapd->iconf->mbssid) { |
| 522 | + for (j = 0; j < iface->num_bss; j++) { |
| 523 | + hapd = iface->bss[j]; |
| 524 | + if (hostapd_start_beacon(hapd)) { |
| 525 | + for (;;) { |
| 526 | + hapd = iface->bss[j]; |
| 527 | + hostapd_bss_deinit_no_free(hapd); |
| 528 | + hostapd_free_hapd_data(hapd); |
| 529 | + if (j == 0) |
| 530 | + break; |
| 531 | + j--; |
| 532 | + } |
| 533 | + goto fail; |
| 534 | + } |
| 535 | + } |
| 536 | + } |
| 537 | + |
| 538 | hapd = iface->bss[0]; |
| 539 | |
| 540 | hostapd_tx_queue_params(iface); |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 541 | @@ -3130,7 +3186,7 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf) |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 542 | |
| 543 | if (start_ctrl_iface_bss(hapd) < 0 || |
| 544 | (hapd_iface->state == HAPD_IFACE_ENABLED && |
| 545 | - hostapd_setup_bss(hapd, -1))) { |
| 546 | + hostapd_setup_bss(hapd, -1, true))) { |
| 547 | hostapd_cleanup(hapd); |
| 548 | hapd_iface->bss[hapd_iface->num_bss - 1] = NULL; |
| 549 | hapd_iface->conf->num_bss--; |
| 550 | diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 551 | index 56d96a5..093c28a 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 552 | --- a/src/ap/hostapd.h |
| 553 | +++ b/src/ap/hostapd.h |
| 554 | @@ -660,6 +660,11 @@ struct hostapd_iface { |
| 555 | /* Previous WMM element information */ |
| 556 | struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM]; |
| 557 | |
| 558 | + /* Maximum number of interfaces supported for MBSSID advertisements */ |
| 559 | + u8 mbssid_max_interfaces; |
| 560 | + /* Maximum profile periodicity for enhanced MBSSID advertisements */ |
| 561 | + u8 ema_max_periodicity; |
| 562 | + |
| 563 | int (*enable_iface_cb)(struct hostapd_iface *iface); |
| 564 | int (*disable_iface_cb)(struct hostapd_iface *iface); |
| 565 | }; |
| 566 | @@ -762,5 +767,7 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd, |
| 567 | #endif /* CONFIG_FST */ |
| 568 | |
| 569 | int hostapd_set_acl(struct hostapd_data *hapd); |
| 570 | +struct hostapd_data * hostapd_mbssid_get_tx_bss(struct hostapd_data *hapd); |
| 571 | +int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd); |
| 572 | |
| 573 | #endif /* HOSTAPD_H */ |
| 574 | diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 575 | index 098793e..30bfa30 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 576 | --- a/src/ap/ieee802_11.c |
| 577 | +++ b/src/ap/ieee802_11.c |
| 578 | @@ -165,6 +165,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) |
| 579 | int i, num, count; |
| 580 | int h2e_required; |
| 581 | |
| 582 | + hapd->conf->xrates_supported = 0; |
| 583 | if (hapd->iface->current_rates == NULL) |
| 584 | return eid; |
| 585 | |
| 586 | @@ -214,6 +215,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) |
| 587 | *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY; |
| 588 | } |
| 589 | |
| 590 | + hapd->conf->xrates_supported = 1; |
| 591 | return pos; |
| 592 | } |
| 593 | |
| 594 | @@ -3979,6 +3981,23 @@ static void handle_auth(struct hostapd_data *hapd, |
| 595 | } |
| 596 | |
| 597 | |
| 598 | +static u8 hostapd_max_bssid_indicator(struct hostapd_data *hapd) |
| 599 | +{ |
| 600 | + size_t num_bss_nontx; |
| 601 | + u8 max_bssid_ind = 0; |
| 602 | + |
| 603 | + if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1) |
| 604 | + return 0; |
| 605 | + |
| 606 | + num_bss_nontx = hapd->iface->num_bss - 1; |
| 607 | + while (num_bss_nontx > 0) { |
| 608 | + max_bssid_ind++; |
| 609 | + num_bss_nontx >>= 1; |
| 610 | + } |
| 611 | + return max_bssid_ind; |
| 612 | +} |
| 613 | + |
| 614 | + |
| 615 | int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta) |
| 616 | { |
| 617 | int i, j = 32, aid; |
| 618 | @@ -4004,7 +4023,10 @@ int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta) |
| 619 | } |
| 620 | if (j == 32) |
| 621 | return -1; |
| 622 | - aid = i * 32 + j + 1; |
| 623 | + aid = i * 32 + j; |
| 624 | + |
| 625 | + aid += (1 << hostapd_max_bssid_indicator(hapd)); |
| 626 | + |
| 627 | if (aid > 2007) |
| 628 | return -1; |
| 629 | |
| 630 | @@ -7579,4 +7601,256 @@ u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type) |
| 631 | return eid; |
| 632 | } |
| 633 | |
| 634 | + |
| 635 | +static size_t hostapd_eid_mbssid_elem_len(struct hostapd_data *hapd, |
| 636 | + u32 frame_type, size_t *bss_index, |
| 637 | + const u8 *known_bss, |
| 638 | + size_t known_bss_len) |
| 639 | +{ |
| 640 | + struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd); |
| 641 | + size_t len = 3, i; |
| 642 | + |
| 643 | + for (i = *bss_index; i < hapd->iface->num_bss; i++) { |
| 644 | + struct hostapd_data *bss = hapd->iface->bss[i]; |
| 645 | + const u8 *auth, *rsn = NULL, *rsnx = NULL; |
| 646 | + size_t nontx_profile_len, auth_len; |
| 647 | + u8 ie_count = 0; |
| 648 | + |
| 649 | + if (known_bss && (known_bss_len > (i / 8))) { |
| 650 | + known_bss = &known_bss[i / 8]; |
| 651 | + if (*known_bss & (u8)(BIT(i % 8))) |
| 652 | + continue; |
| 653 | + } |
| 654 | + |
| 655 | + if (!bss || !bss->conf || !bss->started) |
| 656 | + continue; |
| 657 | + |
| 658 | + /* |
| 659 | + * Sublement ID: 1 byte |
| 660 | + * Length: 1 byte |
| 661 | + * Nontransmitted capabilities: 4 bytes |
| 662 | + * SSID element: 2 + variable |
| 663 | + * Multiple BSSID Index Element: 3 bytes (+2 bytes in beacons) |
| 664 | + * Fixed length = 1 + 1 + 4 + 2 + 3 = 11 |
| 665 | + */ |
| 666 | + nontx_profile_len = 11 + bss->conf->ssid.ssid_len; |
| 667 | + |
| 668 | + if (frame_type == WLAN_FC_STYPE_BEACON) |
| 669 | + nontx_profile_len += 2; |
| 670 | + |
| 671 | + auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len); |
| 672 | + if (auth) { |
| 673 | + rsn = get_ie(auth, auth_len, WLAN_EID_RSN); |
| 674 | + if (rsn) |
| 675 | + nontx_profile_len += (2 + rsn[1]); |
| 676 | + |
| 677 | + rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX); |
| 678 | + if (rsnx) |
| 679 | + nontx_profile_len += (2 + rsnx[1]); |
| 680 | + } |
| 681 | + if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN)) |
| 682 | + ie_count++; |
| 683 | + if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX)) |
| 684 | + ie_count++; |
| 685 | + if (bss->conf->xrates_supported) |
| 686 | + nontx_profile_len += 8; |
| 687 | + else if (hapd->conf->xrates_supported) |
| 688 | + ie_count++; |
| 689 | + if (ie_count) |
| 690 | + nontx_profile_len += (4 + ie_count); |
| 691 | + |
| 692 | + if ((len + nontx_profile_len) > 255) |
| 693 | + goto mbssid_too_big; |
| 694 | + |
| 695 | + len += nontx_profile_len; |
| 696 | + } |
| 697 | + |
| 698 | +mbssid_too_big: |
| 699 | + *bss_index = i; |
| 700 | + return len; |
| 701 | +} |
| 702 | + |
| 703 | + |
| 704 | +size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type, |
| 705 | + u8 *elem_count, const u8 *known_bss, |
| 706 | + size_t known_bss_len) |
| 707 | +{ |
| 708 | + size_t len = 0, bss_index = 1; |
| 709 | + |
| 710 | + if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 || |
| 711 | + (frame_type != WLAN_FC_STYPE_BEACON && |
| 712 | + frame_type != WLAN_FC_STYPE_PROBE_RESP)) |
| 713 | + return 0; |
| 714 | + |
| 715 | + if (frame_type == WLAN_FC_STYPE_BEACON) { |
| 716 | + if (!elem_count) { |
| 717 | + wpa_printf(MSG_ERROR, |
| 718 | + "MBSSID: Insufficient data for beacons"); |
| 719 | + return 0; |
| 720 | + } |
| 721 | + *elem_count = 0; |
| 722 | + } |
| 723 | + |
| 724 | + while (bss_index < hapd->iface->num_bss) { |
| 725 | + len += hostapd_eid_mbssid_elem_len(hapd, frame_type, |
| 726 | + &bss_index, known_bss, |
| 727 | + known_bss_len); |
| 728 | + |
| 729 | + if (frame_type == WLAN_FC_STYPE_BEACON) |
| 730 | + *elem_count += 1; |
| 731 | + } |
| 732 | + return len; |
| 733 | +} |
| 734 | + |
| 735 | + |
| 736 | +static u8 * hostapd_eid_mbssid_elem(struct hostapd_data *hapd, u8 *eid, u8 *end, |
| 737 | + u32 frame_type, u8 max_bssid_indicator, |
| 738 | + size_t *bss_index, u8 elem_count, |
| 739 | + const u8 *known_bss, size_t known_bss_len) |
| 740 | +{ |
| 741 | + struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd); |
| 742 | + size_t i; |
| 743 | + u8 *eid_len_offset, *max_bssid_indicator_offset; |
| 744 | + |
| 745 | + *eid++ = WLAN_EID_MULTIPLE_BSSID; |
| 746 | + eid_len_offset = eid++; |
| 747 | + max_bssid_indicator_offset = eid++; |
| 748 | + |
| 749 | + for (i = *bss_index; i < hapd->iface->num_bss; i++) { |
| 750 | + struct hostapd_data *bss = hapd->iface->bss[i]; |
| 751 | + struct hostapd_bss_config *conf; |
| 752 | + u8 *eid_len_pos, *nontx_bss_start = eid; |
| 753 | + const u8 *auth, *rsn = NULL, *rsnx = NULL; |
| 754 | + u8 ie_count = 0, non_inherit_ie[3]; |
| 755 | + size_t auth_len = 0; |
| 756 | + u16 capab_info; |
| 757 | + |
| 758 | + if (known_bss && (known_bss_len > (i / 8))) { |
| 759 | + known_bss = &known_bss[i / 8]; |
| 760 | + if (*known_bss & (u8)(BIT(i % 8))) |
| 761 | + continue; |
| 762 | + } |
| 763 | + |
| 764 | + if (!bss || !bss->conf || !bss->started) |
| 765 | + continue; |
| 766 | + conf = bss->conf; |
| 767 | + |
| 768 | + *eid++ = WLAN_EID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE; |
| 769 | + eid_len_pos = eid++; |
| 770 | + |
| 771 | + *eid++ = WLAN_EID_NONTRANSMITTED_BSSID_CAPA; |
| 772 | + *eid++ = sizeof(capab_info); |
| 773 | + capab_info = host_to_le16(hostapd_own_capab_info(bss)); |
| 774 | + os_memcpy(eid, (const void *)&capab_info, sizeof(capab_info)); |
| 775 | + eid += sizeof(capab_info); |
| 776 | + |
| 777 | + *eid++ = WLAN_EID_SSID; |
| 778 | + *eid++ = conf->ssid.ssid_len; |
| 779 | + os_memcpy(eid, conf->ssid.ssid, conf->ssid.ssid_len); |
| 780 | + eid += conf->ssid.ssid_len; |
| 781 | + |
| 782 | + *eid++ = WLAN_EID_MULTIPLE_BSSID_INDEX; |
| 783 | + if (frame_type == WLAN_FC_STYPE_BEACON) { |
| 784 | + *eid++ = 3; |
| 785 | + *eid++ = i; |
| 786 | + if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && |
| 787 | + (conf->dtim_period % elem_count)) |
| 788 | + conf->dtim_period = elem_count; |
| 789 | + *eid++ = conf->dtim_period; |
| 790 | + *eid++ = 0xFF; |
| 791 | + } else { |
| 792 | + *eid++ = 1; |
| 793 | + *eid++ = i; |
| 794 | + } |
| 795 | + |
| 796 | + auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len); |
| 797 | + if (auth) { |
| 798 | + rsn = get_ie(auth, auth_len, WLAN_EID_RSN); |
| 799 | + if (rsn) { |
| 800 | + os_memcpy(eid, rsn, 2 + rsn[1]); |
| 801 | + eid += (2 + rsn[1]); |
| 802 | + } |
| 803 | + |
| 804 | + rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX); |
| 805 | + if (rsnx) { |
| 806 | + os_memcpy(eid, rsnx, 2 + rsnx[1]); |
| 807 | + eid += (2 + rsnx[1]); |
| 808 | + } |
| 809 | + } |
| 810 | + if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN)) { |
| 811 | + non_inherit_ie[ie_count] = WLAN_EID_RSN; |
| 812 | + ie_count++; |
| 813 | + } |
| 814 | + if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX)) { |
| 815 | + non_inherit_ie[ie_count] = WLAN_EID_RSNX; |
| 816 | + ie_count++; |
| 817 | + } |
| 818 | + if (hapd->conf->xrates_supported && |
| 819 | + !bss->conf->xrates_supported) { |
| 820 | + non_inherit_ie[ie_count] = WLAN_EID_EXT_SUPP_RATES; |
| 821 | + ie_count++; |
| 822 | + } |
| 823 | + if (ie_count) { |
| 824 | + *eid++ = WLAN_EID_EXTENSION; |
| 825 | + *eid++ = 2 + ie_count; |
| 826 | + *eid++ = WLAN_EID_EXT_NON_INHERITANCE; |
| 827 | + *eid++ = ie_count; |
| 828 | + os_memcpy(eid, non_inherit_ie, ie_count); |
| 829 | + eid += ie_count; |
| 830 | + } |
| 831 | + |
| 832 | + *eid_len_pos = (eid - eid_len_pos) - 1; |
| 833 | + |
| 834 | + if (((eid - eid_len_offset) - 1) > 255) { |
| 835 | + eid = nontx_bss_start; |
| 836 | + goto mbssid_too_big; |
| 837 | + } |
| 838 | + } |
| 839 | + |
| 840 | +mbssid_too_big: |
| 841 | + *bss_index = i; |
| 842 | + *max_bssid_indicator_offset = max_bssid_indicator; |
| 843 | + if (*max_bssid_indicator_offset < 1) |
| 844 | + *max_bssid_indicator_offset = 1; |
| 845 | + *eid_len_offset = (eid - eid_len_offset) - 1; |
| 846 | + return eid; |
| 847 | +} |
| 848 | + |
| 849 | + |
| 850 | +u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end, |
| 851 | + u32 frame_type, u8 elem_count, u8 **elem_offset, |
| 852 | + const u8 *known_bss, size_t known_bss_len) |
| 853 | +{ |
| 854 | + size_t bss_index = 1; |
| 855 | + u8 elem_index = 0; |
| 856 | + |
| 857 | + if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 || |
| 858 | + (frame_type != WLAN_FC_STYPE_BEACON && |
| 859 | + frame_type != WLAN_FC_STYPE_PROBE_RESP)) |
| 860 | + return eid; |
| 861 | + |
| 862 | + if (frame_type == WLAN_FC_STYPE_BEACON && !elem_offset) { |
| 863 | + wpa_printf(MSG_ERROR, "MBSSID: Insufficient data for beacons"); |
| 864 | + return eid; |
| 865 | + } |
| 866 | + |
| 867 | + while (bss_index < hapd->iface->num_bss) { |
| 868 | + if (frame_type == WLAN_FC_STYPE_BEACON) { |
| 869 | + if (elem_index == elem_count) { |
| 870 | + wpa_printf(MSG_WARNING, |
| 871 | + "MBSSID: More number of elements than provided array"); |
| 872 | + break; |
| 873 | + } |
| 874 | + |
| 875 | + elem_offset[elem_index] = eid; |
| 876 | + elem_index = elem_index + 1; |
| 877 | + } |
| 878 | + eid = hostapd_eid_mbssid_elem(hapd, eid, end, frame_type, |
| 879 | + hostapd_max_bssid_indicator(hapd), |
| 880 | + &bss_index, elem_count, |
| 881 | + known_bss, known_bss_len); |
| 882 | + } |
| 883 | + return eid; |
| 884 | +} |
| 885 | + |
| 886 | #endif /* CONFIG_NATIVE_WINDOWS */ |
| 887 | diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 888 | index fa1f47b..bb454bb 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 889 | --- a/src/ap/ieee802_11.h |
| 890 | +++ b/src/ap/ieee802_11.h |
| 891 | @@ -214,5 +214,10 @@ u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta, |
| 892 | enum ieee80211_op_mode opmode, |
| 893 | const u8 *he_capab, size_t he_capab_len, |
| 894 | const u8 *eht_capab, size_t eht_capab_len); |
| 895 | - |
| 896 | +size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type, |
| 897 | + u8 *elem_count, const u8 *known_bss, |
| 898 | + size_t known_bss_len); |
| 899 | +u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end, |
| 900 | + u32 frame_type, u8 elem_count, u8 **elem_offset, |
| 901 | + const u8 *known_bss, size_t known_bss_len); |
| 902 | #endif /* IEEE802_11_H */ |
| 903 | diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 904 | index 4f85d78..7f5b475 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 905 | --- a/src/ap/ieee802_11_shared.c |
| 906 | +++ b/src/ap/ieee802_11_shared.c |
| 907 | @@ -364,6 +364,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) |
| 908 | *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */ |
| 909 | if (hapd->conf->bss_transition) |
| 910 | *pos |= 0x08; /* Bit 19 - BSS Transition */ |
| 911 | + if (hapd->iconf->mbssid) |
| 912 | + *pos |= 0x40; /* Bit 22 - Multiple BSSID */ |
| 913 | break; |
| 914 | case 3: /* Bits 24-31 */ |
| 915 | #ifdef CONFIG_WNM_AP |
| 916 | @@ -436,6 +438,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) |
| 917 | (hapd->iface->drv_flags & |
| 918 | WPA_DRIVER_FLAGS_BEACON_PROTECTION)) |
| 919 | *pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */ |
| 920 | + if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED) |
| 921 | + *pos |= 0x08; /* Bit 83 - Enhanced multiple BSSID */ |
| 922 | break; |
| 923 | case 11: /* Bits 88-95 */ |
| 924 | #ifdef CONFIG_SAE_PK |
| 925 | @@ -471,6 +475,13 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) |
| 926 | *pos &= ~hapd->conf->ext_capa_mask[i]; |
| 927 | *pos |= hapd->conf->ext_capa[i]; |
| 928 | } |
| 929 | + |
| 930 | + /* Clear bits 83 and 22 if EMA and MBSSID are not enabled |
| 931 | + * otherwise association fails with some clients */ |
| 932 | + if (i == 10 && hapd->iconf->mbssid < ENHANCED_MBSSID_ENABLED) |
| 933 | + *pos &= ~0x08; |
| 934 | + if (i == 2 && !hapd->iconf->mbssid) |
| 935 | + *pos &= ~0x40; |
| 936 | } |
| 937 | |
| 938 | while (len > 0 && eid[1 + len] == 0) { |
| 939 | diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 940 | index c8ee90c..2fab7c3 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 941 | --- a/src/common/ieee802_11_common.c |
| 942 | +++ b/src/common/ieee802_11_common.c |
| 943 | @@ -315,6 +315,10 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen, |
| 944 | elems->eht_operation = pos; |
| 945 | elems->eht_operation_len = elen; |
| 946 | break; |
| 947 | + case WLAN_EID_EXT_KNOWN_BSSID: |
| 948 | + elems->mbssid_known_bss = pos; |
| 949 | + elems->mbssid_known_bss_len = elen; |
| 950 | + break; |
| 951 | default: |
| 952 | if (show_errors) { |
| 953 | wpa_printf(MSG_MSGDUMP, |
| 954 | diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 955 | index 94e1d7b..1e4e27d 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 956 | --- a/src/common/ieee802_11_common.h |
| 957 | +++ b/src/common/ieee802_11_common.h |
| 958 | @@ -119,6 +119,7 @@ struct ieee802_11_elems { |
| 959 | const u8 *pasn_params; |
| 960 | const u8 *eht_capabilities; |
| 961 | const u8 *eht_operation; |
| 962 | + const u8 *mbssid_known_bss; |
| 963 | |
| 964 | u8 ssid_len; |
| 965 | u8 supp_rates_len; |
| 966 | @@ -176,6 +177,8 @@ struct ieee802_11_elems { |
| 967 | u8 eht_capabilities_len; |
| 968 | u8 eht_operation_len; |
| 969 | |
| 970 | + u8 mbssid_known_bss_len; |
| 971 | + |
| 972 | struct mb_ies_info mb_ies; |
| 973 | struct frag_ies_info frag_ies; |
| 974 | }; |
| 975 | diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 976 | index 62088bd..0bbbca9 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 977 | --- a/src/common/ieee802_11_defs.h |
| 978 | +++ b/src/common/ieee802_11_defs.h |
| 979 | @@ -481,6 +481,9 @@ |
| 980 | #define WLAN_EID_EXT_SPATIAL_REUSE 39 |
| 981 | #define WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT 42 |
| 982 | #define WLAN_EID_EXT_OCV_OCI 54 |
| 983 | +#define WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION 55 |
| 984 | +#define WLAN_EID_EXT_NON_INHERITANCE 56 |
| 985 | +#define WLAN_EID_EXT_KNOWN_BSSID 57 |
| 986 | #define WLAN_EID_EXT_SHORT_SSID_LIST 58 |
| 987 | #define WLAN_EID_EXT_HE_6GHZ_BAND_CAP 59 |
| 988 | #define WLAN_EID_EXT_EDMG_CAPABILITIES 61 |
| 989 | @@ -497,6 +500,8 @@ |
| 990 | #define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110 |
| 991 | #define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114 |
| 992 | |
| 993 | +#define WLAN_EID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE 0 |
| 994 | + |
| 995 | /* Extended Capabilities field */ |
| 996 | #define WLAN_EXT_CAPAB_20_40_COEX 0 |
| 997 | #define WLAN_EXT_CAPAB_GLK 1 |
| 998 | diff --git a/src/drivers/driver.h b/src/drivers/driver.h |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 999 | index 82daef0..36f465c 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 1000 | --- a/src/drivers/driver.h |
| 1001 | +++ b/src/drivers/driver.h |
| 1002 | @@ -1633,6 +1633,43 @@ struct wpa_driver_ap_params { |
| 1003 | * ibf_enable=<val> |
| 1004 | */ |
| 1005 | u8 ibf_enable; |
| 1006 | + |
| 1007 | + /** |
| 1008 | + * mbssid_tx_iface - Transmitting interface of the MBSSID set |
| 1009 | + */ |
| 1010 | + const char *mbssid_tx_iface; |
| 1011 | + |
| 1012 | + /** |
| 1013 | + * mbssid_index - The index of this BSS in the MBSSID set |
| 1014 | + */ |
| 1015 | + unsigned int mbssid_index; |
| 1016 | + |
| 1017 | + /** |
| 1018 | + * mbssid_elem - Buffer containing all MBSSID elements |
| 1019 | + */ |
| 1020 | + u8 *mbssid_elem; |
| 1021 | + |
| 1022 | + /** |
| 1023 | + * mbssid_elem_len - Total length of all MBSSID elements |
| 1024 | + */ |
| 1025 | + size_t mbssid_elem_len; |
| 1026 | + |
| 1027 | + /** |
| 1028 | + * mbssid_elem_count - The number of MBSSID elements |
| 1029 | + */ |
| 1030 | + u8 mbssid_elem_count; |
| 1031 | + |
| 1032 | + /** |
| 1033 | + * mbssid_elem_offset - Offsets to elements in mbssid_elem. |
| 1034 | + * Kernel will use these offsets to generate multiple BSSID beacons. |
| 1035 | + */ |
| 1036 | + u8 **mbssid_elem_offset; |
| 1037 | + |
| 1038 | + /** |
| 1039 | + * ema - Enhanced MBSSID advertisements support. |
| 1040 | + */ |
| 1041 | + bool ema; |
| 1042 | + |
| 1043 | }; |
| 1044 | |
| 1045 | struct wpa_driver_mesh_bss_params { |
| 1046 | @@ -2197,6 +2234,11 @@ struct wpa_driver_capa { |
| 1047 | |
| 1048 | /* Maximum number of supported CSA counters */ |
| 1049 | u16 max_csa_counters; |
| 1050 | + |
| 1051 | + /* Maximum number of interfaces supported for MBSSID advertisements */ |
| 1052 | + u8 mbssid_max_interfaces; |
| 1053 | + /* Maximum profile periodicity for enhanced MBSSID advertisements */ |
| 1054 | + u8 ema_max_periodicity; |
| 1055 | }; |
| 1056 | |
| 1057 | |
| 1058 | diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 1059 | index 6c65901..3753409 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 1060 | --- a/src/drivers/driver_nl80211.c |
| 1061 | +++ b/src/drivers/driver_nl80211.c |
| 1062 | @@ -4540,6 +4540,55 @@ static int nl80211_unsol_bcast_probe_resp(struct i802_bss *bss, |
| 1063 | nla_nest_end(msg, attr); |
| 1064 | return 0; |
| 1065 | } |
| 1066 | + |
| 1067 | + |
| 1068 | +static int nl80211_mbssid(struct nl_msg *msg, |
| 1069 | + struct wpa_driver_ap_params *params) |
| 1070 | +{ |
| 1071 | + struct nlattr *config, *elems; |
| 1072 | + int ifidx; |
| 1073 | + |
| 1074 | + if (!params->mbssid_tx_iface) |
| 1075 | + return 0; |
| 1076 | + |
| 1077 | + config = nla_nest_start(msg, NL80211_ATTR_MBSSID_CONFIG); |
| 1078 | + if (!config) |
| 1079 | + return -1; |
| 1080 | + |
| 1081 | + nla_put_u8(msg, NL80211_MBSSID_CONFIG_ATTR_INDEX, params->mbssid_index); |
| 1082 | + if (params->mbssid_tx_iface) { |
| 1083 | + ifidx = if_nametoindex(params->mbssid_tx_iface); |
| 1084 | + if (ifidx <= 0) |
| 1085 | + return -1; |
| 1086 | + nla_put_u32(msg, |
| 1087 | + NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX, |
| 1088 | + ifidx); |
| 1089 | + } |
| 1090 | + |
| 1091 | + if (params->ema) |
| 1092 | + nla_put_flag(msg, NL80211_MBSSID_CONFIG_ATTR_EMA); |
| 1093 | + |
| 1094 | + nla_nest_end(msg, config); |
| 1095 | + |
| 1096 | + if (params->mbssid_elem_count && params->mbssid_elem_len && |
| 1097 | + params->mbssid_elem_offset && *params->mbssid_elem_offset) { |
| 1098 | + u8 i, **offs = params->mbssid_elem_offset; |
| 1099 | + |
| 1100 | + elems = nla_nest_start(msg, NL80211_ATTR_MBSSID_ELEMS); |
| 1101 | + if (!elems) |
| 1102 | + return -1; |
| 1103 | + |
| 1104 | + for (i = 0; i < params->mbssid_elem_count - 1; i++) |
| 1105 | + nla_put(msg, i + 1, offs[i + 1] - offs[i], offs[i]); |
| 1106 | + |
| 1107 | + nla_put(msg, i + 1, |
| 1108 | + *offs + params->mbssid_elem_len - offs[i], |
| 1109 | + offs[i]); |
| 1110 | + |
| 1111 | + nla_nest_end(msg, elems); |
| 1112 | + } |
| 1113 | + return 0; |
| 1114 | +} |
| 1115 | #endif /* CONFIG_IEEE80211AX */ |
| 1116 | |
| 1117 | |
| 1118 | @@ -4838,6 +4887,9 @@ static int wpa_driver_nl80211_set_ap(void *priv, |
| 1119 | if (params->unsol_bcast_probe_resp_interval && |
| 1120 | nl80211_unsol_bcast_probe_resp(bss, msg, params) < 0) |
| 1121 | goto fail; |
| 1122 | + |
| 1123 | + if (nl80211_mbssid(msg, params) < 0) |
| 1124 | + goto fail; |
| 1125 | #endif /* CONFIG_IEEE80211AX */ |
| 1126 | |
| 1127 | #ifdef CONFIG_SAE |
| 1128 | diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c |
developer | a5e13c9 | 2023-03-03 15:51:12 +0800 | [diff] [blame] | 1129 | index 06a52db..d8078bc 100644 |
developer | 0b9a639 | 2023-03-02 17:16:47 +0800 | [diff] [blame] | 1130 | --- a/src/drivers/driver_nl80211_capa.c |
| 1131 | +++ b/src/drivers/driver_nl80211_capa.c |
| 1132 | @@ -857,6 +857,30 @@ err: |
| 1133 | } |
| 1134 | |
| 1135 | |
| 1136 | +static void wiphy_info_mbssid(struct wpa_driver_capa *cap, struct nlattr *attr) |
| 1137 | +{ |
| 1138 | + struct nlattr *config[NL80211_MBSSID_CONFIG_ATTR_MAX + 1]; |
| 1139 | + |
| 1140 | + if (nla_parse_nested(config, NL80211_MBSSID_CONFIG_ATTR_MAX, attr, |
| 1141 | + NULL)) |
| 1142 | + return; |
| 1143 | + |
| 1144 | + if (!config[NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES]) |
| 1145 | + return; |
| 1146 | + |
| 1147 | + cap->mbssid_max_interfaces = |
| 1148 | + nla_get_u8(config[NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES]); |
| 1149 | + |
| 1150 | + if (config[NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY]) |
| 1151 | + cap->ema_max_periodicity = |
| 1152 | + nla_get_u8(config[NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY]); |
| 1153 | + |
| 1154 | + wpa_printf(MSG_DEBUG, |
| 1155 | + "multiple_bssid: max interfaces %u, max profile periodicity %u\n", |
| 1156 | + cap->mbssid_max_interfaces, cap->ema_max_periodicity); |
| 1157 | +} |
| 1158 | + |
| 1159 | + |
| 1160 | static int wiphy_info_handler(struct nl_msg *msg, void *arg) |
| 1161 | { |
| 1162 | struct nlattr *tb[NL80211_ATTR_MAX + 1]; |
| 1163 | @@ -1106,6 +1130,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) |
| 1164 | if (tb[NL80211_ATTR_WIPHY_SELF_MANAGED_REG]) |
| 1165 | capa->flags |= WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY; |
| 1166 | |
| 1167 | + if (tb[NL80211_ATTR_MBSSID_CONFIG]) |
| 1168 | + wiphy_info_mbssid(capa, tb[NL80211_ATTR_MBSSID_CONFIG]); |
| 1169 | + |
| 1170 | return NL_SKIP; |
| 1171 | } |
| 1172 | |
| 1173 | -- |
| 1174 | 2.18.0 |
| 1175 | |