wpa_supplicant: Add LCI and civic request to Neighbor Report Request
[mech_eap.git] / wpa_supplicant / wpa_supplicant.c
index 047ca10..1f0fcd0 100644 (file)
@@ -552,6 +552,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        wpa_s->last_scan_res = NULL;
 
 #ifdef CONFIG_HS20
+       if (wpa_s->drv_priv)
+               wpa_drv_configure_frame_filters(wpa_s, 0);
        hs20_deinit(wpa_s);
 #endif /* CONFIG_HS20 */
 
@@ -1646,9 +1648,11 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 
        wmm_ac_clear_saved_tspecs(wpa_s);
        wpa_s->reassoc_same_bss = 0;
+       wpa_s->reassoc_same_ess = 0;
 
        if (wpa_s->last_ssid == ssid) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
+               wpa_s->reassoc_same_ess = 1;
                if (wpa_s->current_bss && wpa_s->current_bss == bss) {
                        wmm_ac_save_tspecs(wpa_s);
                        wpa_s->reassoc_same_bss = 1;
@@ -2063,6 +2067,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        int wep_keys_set = 0;
        int assoc_failed = 0;
        struct wpa_ssid *old_ssid;
+       u8 prev_bssid[ETH_ALEN];
 #ifdef CONFIG_HT_OVERRIDES
        struct ieee80211_ht_capabilities htcaps;
        struct ieee80211_ht_capabilities htcaps_mask;
@@ -2096,6 +2101,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                return;
        }
 
+       os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN);
        os_memset(&params, 0, sizeof(params));
        wpa_s->reassociate = 0;
        wpa_s->eap_expected_failure = 0;
@@ -2315,6 +2321,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                                wpa_ie_len += wpabuf_len(hs20);
                        }
                        wpabuf_free(hs20);
+
+                       hs20_configure_frame_filters(wpa_s);
                }
        }
 #endif /* CONFIG_HS20 */
@@ -2410,7 +2418,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        } else {
                params.ssid = ssid->ssid;
                params.ssid_len = ssid->ssid_len;
-               params.pbss = ssid->pbss;
+               params.pbss = (ssid->pbss != 2) ? ssid->pbss : 0;
        }
 
        if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
@@ -2536,6 +2544,10 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        }
 #endif /* CONFIG_P2P */
 
+       if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) &&
+           wpa_s->current_ssid)
+               params.prev_bssid = prev_bssid;
+
        ret = wpa_drv_associate(wpa_s, &params);
        if (ret < 0) {
                wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
@@ -2603,8 +2615,14 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        }
        old_ssid = wpa_s->current_ssid;
        wpa_s->current_ssid = ssid;
-       if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set)
+
+       if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
                wpa_s->current_bss = bss;
+#ifdef CONFIG_HS20
+               hs20_configure_frame_filters(wpa_s);
+#endif /* CONFIG_HS20 */
+       }
+
        wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
        wpa_supplicant_initiate_eapol(wpa_s);
        if (old_ssid != wpa_s->current_ssid)
@@ -6144,11 +6162,19 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
 #define ECANCELED -1
 #endif
 
+/* Measurement Request element + Location Subject + Maximum Age subelement */
+#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4)
+/* Measurement Request element + Location Civic Request */
+#define MEASURE_REQUEST_CIVIC_LEN (3 + 5)
+
+
 /**
  * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
  * @wpa_s: Pointer to wpa_supplicant
  * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE
  *       is sent in the request.
+ * @lci: if set, neighbor request will include LCI request
+ * @civic: if set, neighbor request will include civic location request
  * @cb: Callback function to be called once the requested report arrives, or
  *     timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds.
  *     In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's
@@ -6162,7 +6188,8 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
  * Request must contain a callback function.
  */
 int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
-                                      const struct wpa_ssid *ssid,
+                                      const struct wpa_ssid_value *ssid,
+                                      int lci, int civic,
                                       void (*cb)(void *ctx,
                                                  struct wpabuf *neighbor_rep),
                                       void *cb_ctx)
@@ -6203,7 +6230,9 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
        }
 
        /* 3 = action category + action code + dialog token */
-       buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0));
+       buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0) +
+                          (lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) +
+                          (civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0));
        if (buf == NULL) {
                wpa_printf(MSG_DEBUG,
                           "RRM: Failed to allocate Neighbor Report Request");
@@ -6223,6 +6252,72 @@ int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
                wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len);
        }
 
+       if (lci) {
+               /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
+               wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+               wpabuf_put_u8(buf, MEASURE_REQUEST_LCI_LEN);
+
+               /*
+                * Measurement token; nonzero number that is unique among the
+                * Measurement Request elements in a particular frame.
+                */
+               wpabuf_put_u8(buf, 1); /* Measurement Token */
+
+               /*
+                * Parallel, Enable, Request, and Report bits are 0, Duration is
+                * reserved.
+                */
+               wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+               wpabuf_put_u8(buf, MEASURE_TYPE_LCI); /* Measurement Type */
+
+               /* IEEE P802.11-REVmc/D5.0 9.4.2.21.10 - LCI request */
+               /* Location Subject */
+               wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+
+               /* Optional Subelements */
+               /*
+                * IEEE P802.11-REVmc/D5.0 Figure 9-170
+                * The Maximum Age subelement is required, otherwise the AP can
+                * send only data that was determined after receiving the
+                * request. Setting it here to unlimited age.
+                */
+               wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
+               wpabuf_put_u8(buf, 2);
+               wpabuf_put_le16(buf, 0xffff);
+       }
+
+       if (civic) {
+               /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
+               wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+               wpabuf_put_u8(buf, MEASURE_REQUEST_CIVIC_LEN);
+
+               /*
+                * Measurement token; nonzero number that is unique among the
+                * Measurement Request elements in a particular frame.
+                */
+               wpabuf_put_u8(buf, 2); /* Measurement Token */
+
+               /*
+                * Parallel, Enable, Request, and Report bits are 0, Duration is
+                * reserved.
+                */
+               wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+               /* Measurement Type */
+               wpabuf_put_u8(buf, MEASURE_TYPE_LOCATION_CIVIC);
+
+               /* IEEE P802.11-REVmc/D5.0 9.4.2.21.14:
+                * Location Civic request */
+               /* Location Subject */
+               wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+               wpabuf_put_u8(buf, 0); /* Civic Location Type: IETF RFC 4776 */
+               /* Location Service Interval Units: Seconds */
+               wpabuf_put_u8(buf, 0);
+               /* Location Service Interval: 0 - Only one report is requested
+                */
+               wpabuf_put_le16(buf, 0);
+               /* No optional subelements */
+       }
+
        wpa_s->rrm.next_neighbor_rep_token++;
 
        if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,