]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
RNR: Add elements by default for EMA AP
authorAloka Dixit <quic_alokad@quicinc.com>
Tue, 4 Apr 2023 17:58:59 +0000 (10:58 -0700)
committerJouni Malinen <j@w1.fi>
Tue, 18 Apr 2023 08:35:06 +0000 (11:35 +0300)
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>
src/ap/beacon.c
src/ap/ieee802_11.c
src/ap/ieee802_11.h
src/drivers/driver.h

index c25a5bbc38512d0280a40d8b77f6655c33fb5573..d66d831735ecf6edae81cbf585412964102613f6 100644 (file)
@@ -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;
index c5962abb04afb48169fba107c055bcc8586911af..0fa19debf0394644002249bc9b432c64eeca7e7d 100644 (file)
@@ -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;
index 1e4c843f6695369a99819b37ba4128d2a9078ba0..1190a5ea86a26a31d435770166d9ee5fda838df8 100644 (file)
@@ -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);
 
index 7c0e949b9ad06ead4b1d7c0aeeab89f9798c0c4f..bcb0c92d6d0ea79c70e1f3fb66e20b891c25b34d 100644 (file)
@@ -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 {