summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAloka Dixit <quic_alokad@quicinc.com>2023-04-04 10:58:59 -0700
committerJouni Malinen <j@w1.fi>2023-04-18 11:35:06 +0300
commit5d06acefdd4c0a4cc7bdb0f8df3c6f446f296ac6 (patch)
treeea4dec2be461b7f384a08b8c7fd031a1cc227288
parent8f1d3841979f47cbe05846e132e1006c0e10034e (diff)
downloadhostap-5d06acefdd4c0a4cc7bdb0f8df3c6f446f296ac6.tar.gz
RNR: Add elements by default for EMA AP
As per IEEE Std 802.11ax-2021, 11.1.3.8.3 Discovery of a nontransmitted BSSID profile, an EMA AP that transmits a Beacon frame carrying a partial list of nontransmitted BSSID profiles should include in the frame a Reduced Neighbor Report element carrying information for at least the nontransmitted BSSIDs that are not present in the Multiple BSSID element carried in that frame. Add this support by splitting the reduced neighbor report (RNR) in as many elements as the number of multiple BSSID elements. Each RNR element excludes the non-transmitting profiles already included in the MBSSID element at the same index. If present, the last additional group will have the data common for all EMA beacons such as neighbor AP information gathered through neighbor reports. The hwsim test case he_ap_ema demonstrates this support. Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com>
-rw-r--r--src/ap/beacon.c34
-rw-r--r--src/ap/ieee802_11.c97
-rw-r--r--src/ap/ieee802_11.h5
-rw-r--r--src/drivers/driver.h22
4 files changed, 136 insertions, 22 deletions
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index c25a5bbc3..d66d83173 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -468,8 +468,9 @@ ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd,
{
struct hostapd_iface *iface = hapd->iface;
struct hostapd_data *tx_bss;
- size_t len;
+ size_t len, rnr_len = 0;
u8 elem_count = 0, *elem = NULL, **elem_offset = NULL, *end;
+ u8 rnr_elem_count = 0, *rnr_elem = NULL, **rnr_elem_offset = NULL;
if (!iface->mbssid_max_interfaces ||
iface->num_bss > iface->mbssid_max_interfaces ||
@@ -479,7 +480,7 @@ ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd,
tx_bss = hostapd_mbssid_get_tx_bss(hapd);
len = hostapd_eid_mbssid_len(tx_bss, WLAN_FC_STYPE_BEACON, &elem_count,
- NULL, 0);
+ NULL, 0, &rnr_len);
if (!len || (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED &&
elem_count > iface->ema_max_periodicity))
goto fail;
@@ -492,8 +493,19 @@ ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd,
if (!elem_offset)
goto fail;
+ if (rnr_len) {
+ rnr_elem = os_zalloc(rnr_len);
+ if (!rnr_elem)
+ goto fail;
+
+ rnr_elem_offset = os_calloc(elem_count + 1, sizeof(u8 *));
+ if (!rnr_elem_offset)
+ goto fail;
+ }
+
end = hostapd_eid_mbssid(tx_bss, elem, elem + len, WLAN_FC_STYPE_BEACON,
- elem_count, elem_offset, NULL, 0);
+ elem_count, elem_offset, NULL, 0, rnr_elem,
+ &rnr_elem_count, rnr_elem_offset, rnr_len);
params->mbssid_tx_iface = tx_bss->conf->iface;
params->mbssid_index = hostapd_mbssid_get_bss_index(hapd);
@@ -501,12 +513,19 @@ ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd,
params->mbssid_elem_len = end - elem;
params->mbssid_elem_count = elem_count;
params->mbssid_elem_offset = elem_offset;
+ params->rnr_elem = rnr_elem;
+ params->rnr_elem_len = rnr_len;
+ params->rnr_elem_count = rnr_elem_count;
+ params->rnr_elem_offset = rnr_elem_offset;
if (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED)
params->ema = true;
return 0;
fail:
+ os_free(rnr_elem);
+ os_free(rnr_elem_offset);
+ os_free(elem_offset);
os_free(elem);
wpa_printf(MSG_ERROR, "MBSSID: Configuration failed");
return -1;
@@ -590,7 +609,7 @@ 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);
+ known_bss, known_bss_len, 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);
@@ -658,7 +677,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_get_rsne(hapd, pos, epos - pos);
pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
pos = hostapd_eid_mbssid(hapd, pos, epos, WLAN_FC_STYPE_PROBE_RESP, 0,
- NULL, known_bss, known_bss_len);
+ NULL, known_bss, known_bss_len, NULL, NULL,
+ NULL, 0);
pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
pos = hostapd_get_mde(hapd, pos, epos - pos);
@@ -2026,6 +2046,10 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
params->mbssid_elem = NULL;
os_free(params->mbssid_elem_offset);
params->mbssid_elem_offset = NULL;
+ os_free(params->rnr_elem);
+ params->rnr_elem = NULL;
+ os_free(params->rnr_elem_offset);
+ params->rnr_elem_offset = NULL;
#ifdef CONFIG_FILS
os_free(params->fd_frame_tmpl);
params->fd_frame_tmpl = NULL;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index c5962abb0..0fa19debf 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -6421,9 +6421,16 @@ static size_t hostapd_eid_nr_db_len(struct hostapd_data *hapd,
}
-static size_t hostapd_eid_rnr_iface_len(struct hostapd_data *hapd,
- struct hostapd_data *reporting_hapd,
- size_t *current_len)
+struct mbssid_ie_profiles {
+ u8 start;
+ u8 end;
+};
+
+static size_t
+hostapd_eid_rnr_iface_len(struct hostapd_data *hapd,
+ struct hostapd_data *reporting_hapd,
+ size_t *current_len,
+ struct mbssid_ie_profiles *skip_profiles)
{
size_t total_len = 0, len = *current_len;
int tbtt_count = 0;
@@ -6449,6 +6456,10 @@ static size_t hostapd_eid_rnr_iface_len(struct hostapd_data *hapd,
bss->conf->ignore_broadcast_ssid)
continue;
+ if (skip_profiles &&
+ i >= skip_profiles->start && i < skip_profiles->end)
+ continue;
+
if (len + RNR_TBTT_INFO_LEN > 255 ||
tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
break;
@@ -6527,7 +6538,7 @@ static size_t hostapd_eid_rnr_colocation_len(struct hostapd_data *hapd,
continue;
len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd,
- current_len);
+ current_len, NULL);
}
return len;
@@ -6553,13 +6564,15 @@ size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type)
if (hapd->conf->rnr && hapd->iface->num_bss > 1 &&
!hapd->iconf->mbssid)
total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
- &current_len);
+ &current_len,
+ NULL);
break;
case WLAN_FC_STYPE_ACTION:
if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
- &current_len);
+ &current_len,
+ NULL);
break;
default:
@@ -6627,7 +6640,8 @@ static u8 * hostapd_eid_nr_db(struct hostapd_data *hapd, u8 *eid,
static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
struct hostapd_data *reporting_hapd,
- u8 *eid, size_t *current_len)
+ u8 *eid, size_t *current_len,
+ struct mbssid_ie_profiles *skip_profiles)
{
struct hostapd_data *bss;
struct hostapd_iface *iface = hapd->iface;
@@ -6672,6 +6686,10 @@ static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
bss->conf->ignore_broadcast_ssid)
continue;
+ if (skip_profiles &&
+ i >= skip_profiles->start && i < skip_profiles->end)
+ continue;
+
if (len + RNR_TBTT_INFO_LEN > 255 ||
tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
break;
@@ -6688,7 +6706,7 @@ static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
if (iface->conf->mbssid != MBSSID_DISABLED &&
iface->num_bss > 1) {
bss_param |= RNR_BSS_PARAM_MULTIPLE_BSSID;
- if (i == 0)
+ if (bss == hostapd_mbssid_get_tx_bss(hapd))
bss_param |=
RNR_BSS_PARAM_TRANSMITTED_BSSID;
}
@@ -6736,7 +6754,7 @@ static u8 * hostapd_eid_rnr_colocation(struct hostapd_data *hapd, u8 *eid,
continue;
eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid,
- current_len);
+ current_len, NULL);
}
return eid;
@@ -6763,13 +6781,13 @@ u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type)
if (hapd->conf->rnr && hapd->iface->num_bss > 1 &&
!hapd->iconf->mbssid)
eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
- &current_len);
+ &current_len, NULL);
break;
case WLAN_FC_STYPE_ACTION:
if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
- &current_len);
+ &current_len, NULL);
break;
default:
@@ -6858,7 +6876,7 @@ static size_t hostapd_eid_mbssid_elem_len(struct hostapd_data *hapd,
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 known_bss_len, size_t *rnr_len)
{
size_t len = 0, bss_index = 1;
@@ -6877,13 +6895,29 @@ size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type,
}
while (bss_index < hapd->iface->num_bss) {
+ size_t rnr_count = bss_index;
+
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;
+ if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len) {
+ size_t rnr_cur_len = 0;
+ struct mbssid_ie_profiles skip_profiles = {
+ rnr_count, bss_index
+ };
+
+ *rnr_len += hostapd_eid_rnr_iface_len(
+ hapd, hostapd_mbssid_get_tx_bss(hapd),
+ &rnr_cur_len, &skip_profiles);
+ }
}
+
+ if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len)
+ *rnr_len += hostapd_eid_rnr_len(hapd, frame_type);
+
return len;
}
@@ -6995,10 +7029,12 @@ static u8 * hostapd_eid_mbssid_elem(struct hostapd_data *hapd, u8 *eid, u8 *end,
u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
unsigned int frame_stype, u8 elem_count,
u8 **elem_offset,
- const u8 *known_bss, size_t known_bss_len)
+ const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid,
+ u8 *rnr_count, u8 **rnr_offset, size_t rnr_len)
{
- size_t bss_index = 1;
- u8 elem_index = 0;
+ size_t bss_index = 1, cur_len = 0;
+ u8 elem_index = 0, *rnr_start_eid = rnr_eid;
+ bool add_rnr;
if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 ||
(frame_stype != WLAN_FC_STYPE_BEACON &&
@@ -7011,7 +7047,13 @@ u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
return eid;
}
+ add_rnr = hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
+ frame_stype == WLAN_FC_STYPE_BEACON &&
+ rnr_eid && rnr_count && rnr_offset && rnr_len;
+
while (bss_index < hapd->iface->num_bss) {
+ unsigned int rnr_start_count = bss_index;
+
if (frame_stype == WLAN_FC_STYPE_BEACON) {
if (elem_index == elem_count) {
wpa_printf(MSG_WARNING,
@@ -7026,6 +7068,31 @@ u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
hostapd_max_bssid_indicator(hapd),
&bss_index, elem_count,
known_bss, known_bss_len);
+
+ if (add_rnr) {
+ struct mbssid_ie_profiles skip_profiles = {
+ rnr_start_count, bss_index
+ };
+
+ rnr_offset[*rnr_count] = rnr_eid;
+ *rnr_count = *rnr_count + 1;
+ cur_len = 0;
+ rnr_eid = hostapd_eid_rnr_iface(
+ hapd, hostapd_mbssid_get_tx_bss(hapd),
+ rnr_eid, &cur_len, &skip_profiles);
+ }
+ }
+
+ if (add_rnr && (size_t) (rnr_eid - rnr_start_eid) < rnr_len) {
+ rnr_offset[*rnr_count] = rnr_eid;
+ *rnr_count = *rnr_count + 1;
+ cur_len = 0;
+
+ if (hapd->conf->rnr)
+ rnr_eid = hostapd_eid_nr_db(hapd, rnr_eid, &cur_len);
+ if (get_colocation_mode(hapd) == COLOCATED_LOWER_BAND)
+ rnr_eid = hostapd_eid_rnr_colocation(hapd, rnr_eid,
+ &cur_len);
}
return eid;
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 1e4c843f6..1190a5ea8 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -218,11 +218,12 @@ u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta,
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);
+ size_t known_bss_len, size_t *rnr_len);
u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
unsigned int frame_stype, u8 elem_count,
u8 **elem_offset,
- const u8 *known_bss, size_t known_bss_len);
+ const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid,
+ u8 *rnr_count, u8 **rnr_offset, size_t rnr_len);
void punct_update_legacy_bw(u16 bitmap, u8 pri_chan,
enum oper_chan_width *width, u8 *seg0, u8 *seg1);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 7c0e949b9..bcb0c92d6 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1726,6 +1726,28 @@ struct wpa_driver_ap_params {
* subchannel is punctured, otherwise active.
*/
u16 punct_bitmap;
+
+ /**
+ * rnr_elem - This buffer contains all of reduced neighbor report (RNR)
+ * elements
+ */
+ u8 *rnr_elem;
+
+ /**
+ * rnr_elem_len - Length of rnr_elem buffer
+ */
+ size_t rnr_elem_len;
+
+ /**
+ * rnr_elem_count - Number of RNR elements
+ */
+ unsigned int rnr_elem_count;
+
+ /**
+ * rnr_elem_offset - The offsets to the elements in rnr_elem.
+ * The driver will use these to include RNR elements in EMA beacons.
+ */
+ u8 **rnr_elem_offset;
};
struct wpa_driver_mesh_bss_params {