]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
RRM: Support for Last Beacon Report Indication subelement
authorAvraham Stern <avraham.stern@intel.com>
Wed, 22 Aug 2018 13:46:19 +0000 (16:46 +0300)
committerJouni Malinen <j@w1.fi>
Wed, 2 Jan 2019 14:26:11 +0000 (16:26 +0200)
IEEE P802.11-REVmd/D2.0, 9.4.2.20.7 (Beacon request) and 9.4.2.21.7
(Beacon report) add the Last Beacon Report Indication subelement to
Beacon Request and Beacon Report elements.

Add the Last Beacon Report Indication subelement to all Beacon Report
elements if the Beacon Request indicated that this subelement is
requested.

Signed-off-by: Avraham Stern <avraham.stern@intel.com>
src/common/ieee802_11_defs.h
wpa_supplicant/rrm.c
wpa_supplicant/wpa_supplicant_i.h

index ee6a9db0905b7f150fb24fff7a9793dc826ed105..ee750fa45d8d9d34e0b4f037ac60a97586415ce3 100644 (file)
@@ -1851,11 +1851,14 @@ enum beacon_report_mode {
 };
 
 /* IEEE Std 802.11-2016, Table 9-88 - Beacon Request subelement IDs */
+/* IEEE P802.11-REVmd/D2.0, Table 9-106 - Optional subelement IDs for
+ * Beacon request */
 #define WLAN_BEACON_REQUEST_SUBELEM_SSID       0
 #define WLAN_BEACON_REQUEST_SUBELEM_INFO       1 /* Beacon Reporting */
 #define WLAN_BEACON_REQUEST_SUBELEM_DETAIL     2 /* Reporting Detail */
 #define WLAN_BEACON_REQUEST_SUBELEM_REQUEST    10
 #define WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL 51 /* AP Channel Report */
+#define WLAN_BEACON_REQUEST_SUBELEM_LAST_INDICATION    164
 #define WLAN_BEACON_REQUEST_SUBELEM_VENDOR     221
 
 /*
@@ -1909,6 +1912,7 @@ struct rrm_measurement_beacon_report {
  * Beacon report */
 #define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY  1
 #define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY_FRAGMENT_ID      2
+#define WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION     164
 #define WLAN_BEACON_REPORT_SUBELEM_VENDOR      221
 
 /* IEEE P802.11-REVmd/D2.0, Table 9-232 - Data field format of the
@@ -1916,6 +1920,9 @@ struct rrm_measurement_beacon_report {
 #define REPORTED_FRAME_BODY_SUBELEM_LEN                4
 #define REPORTED_FRAME_BODY_MORE_FRAGMENTS     BIT(7)
 
+/* IEEE P802.11-REVmd/D2.0, 9.4.2.21.7 - Beacon report  */
+#define BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN      3
+
 /* IEEE Std 802.11ad-2012 - Multi-band element */
 struct multi_band_ie {
        u8 eid; /* WLAN_EID_MULTI_BAND */
index 3ba10c5b5bdd8d6ec9c0a15aaeadfc70bbf9d631..ab5e6dbdb6bc57a09d9c237f4a0b5cc51301f0c9 100644 (file)
@@ -392,17 +392,66 @@ static void wpas_rrm_send_msr_report_mpdu(struct wpa_supplicant *wpa_s,
 }
 
 
+static int wpas_rrm_beacon_rep_update_last_frame(u8 *pos, size_t len)
+{
+       struct rrm_measurement_report_element *msr_rep;
+       u8 *end = pos + len;
+       u8 *msr_rep_end;
+
+       while (end - pos >= (int) sizeof(*msr_rep)) {
+               msr_rep = (struct rrm_measurement_report_element *) pos;
+               msr_rep_end = pos + msr_rep->len + 2;
+
+               if (msr_rep->eid != WLAN_EID_MEASURE_REPORT ||
+                   msr_rep_end > end) {
+                       /* Should not happen. This indicates a bug. */
+                       wpa_printf(MSG_ERROR,
+                                  "RRM: non-measurement report element in measurement report frame");
+                       return -1;
+               }
+
+               if (msr_rep->type == MEASURE_TYPE_BEACON) {
+                       struct rrm_measurement_beacon_report *rep;
+                       u8 *subelem;
+
+                       rep = (struct rrm_measurement_beacon_report *)
+                               msr_rep->variable;
+                       subelem = rep->variable;
+                       while (subelem + 2 < msr_rep_end &&
+                              subelem[0] !=
+                              WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION)
+                               subelem += 2 + subelem[1];
+
+                       if (subelem + 2 < msr_rep_end &&
+                           subelem[0] ==
+                           WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION &&
+                           subelem[1] == 1 &&
+                           subelem +
+                           BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN <= end)
+                               subelem[2] = 1;
+               }
+
+               pos += pos[1] + 2;
+       }
+
+       return 0;
+}
+
+
 static void wpas_rrm_send_msr_report(struct wpa_supplicant *wpa_s,
                                     struct wpabuf *buf)
 {
        int len = wpabuf_len(buf);
-       const u8 *pos = wpabuf_head_u8(buf), *next = pos;
+       u8 *pos = wpabuf_mhead_u8(buf), *next = pos;
 
 #define MPDU_REPORT_LEN (int) (IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN - 3)
 
        while (len) {
                int send_len = (len > MPDU_REPORT_LEN) ? next - pos : len;
 
+               if (send_len == len)
+                       wpas_rrm_beacon_rep_update_last_frame(pos, len);
+
                if (send_len == len ||
                    (send_len + next[1] + 2) > MPDU_REPORT_LEN) {
                        wpas_rrm_send_msr_report_mpdu(wpa_s, pos, send_len);
@@ -796,12 +845,14 @@ static int wpas_add_beacon_rep_elem(struct beacon_rep_data *data,
 {
        int ret;
        u8 *buf, *pos;
+       u32 subelems_len = REPORTED_FRAME_BODY_SUBELEM_LEN +
+               (data->last_indication ?
+                BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN : 0);
 
        /* Maximum element length: Beacon Report element + Reported Frame Body
         * subelement + all IEs of the reported Beacon frame + Reported Frame
         * Body Fragment ID subelement */
-       buf = os_malloc(sizeof(*rep) + 14 + *ie_len +
-                       REPORTED_FRAME_BODY_SUBELEM_LEN);
+       buf = os_malloc(sizeof(*rep) + 14 + *ie_len + subelems_len);
        if (!buf)
                return -1;
 
@@ -832,11 +883,20 @@ static int wpas_add_beacon_rep_elem(struct beacon_rep_data *data,
        else
                pos[3] &= ~REPORTED_FRAME_BODY_MORE_FRAGMENTS;
 
+       pos += REPORTED_FRAME_BODY_SUBELEM_LEN;
+
+       if (data->last_indication) {
+               pos[0] = WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION;
+               pos[1] = 1;
+
+               /* This field will be updated later if this is the last frame */
+               pos[2] = 0;
+       }
+
        ret = wpas_rrm_report_elem(wpa_buf, data->token,
                                   MEASUREMENT_REPORT_MODE_ACCEPT,
                                   MEASURE_TYPE_BEACON, buf,
-                                  ret + sizeof(*rep) +
-                                  REPORTED_FRAME_BODY_SUBELEM_LEN);
+                                  ret + sizeof(*rep) + subelems_len);
 out:
        os_free(buf);
        return ret;
@@ -1051,6 +1111,16 @@ static int wpas_rm_handle_beacon_req_subelem(struct wpa_supplicant *wpa_s,
        case WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL:
                /* Skip - it will be processed when freqs are added */
                break;
+       case WLAN_BEACON_REQUEST_SUBELEM_LAST_INDICATION:
+               if (slen != 1) {
+                       wpa_printf(MSG_DEBUG,
+                                  "Beacon request: Invalid last indication request subelement length: %u",
+                                  slen);
+                       return -1;
+               }
+
+               data->last_indication = subelem[0];
+               break;
        default:
                wpa_printf(MSG_DEBUG,
                           "Beacon request: Unknown subelement id %u", sid);
index a2f78e685afac9dd5816a2d0c2f1a9539acb160f..c2298a216eb881fc24e0894b13c300de014d8afc 100644 (file)
@@ -456,6 +456,7 @@ struct wpa_bss_tmp_disallowed {
 
 struct beacon_rep_data {
        u8 token;
+       u8 last_indication;
        struct wpa_driver_scan_params scan_params;
        u8 ssid[SSID_MAX_LEN];
        size_t ssid_len;