]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/wpa_supplicant.c
FT: Support addition of RIC elements into Reassociation Request frame
[thirdparty/hostap.git] / wpa_supplicant / wpa_supplicant.c
index 247943245f0c47cf36adcaa8264c43bd0ac5e9cd..926b80752dbca58c95aef79fbb3058dcd818cbcb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -62,7 +62,7 @@
 
 const char *const wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi> and contributors";
 
 const char *const wpa_supplicant_license =
 "This software may be distributed under the terms of the BSD license.\n"
@@ -329,7 +329,12 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
 
        eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
 
-       ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#ifdef CONFIG_MACSEC
+       if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE && ssid->mka_psk_set)
+               ieee802_1x_create_preshared_mka(wpa_s, ssid);
+       else
+               ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#endif /* CONFIG_MACSEC */
 #endif /* IEEE8021X_EAPOL */
 }
 
@@ -415,6 +420,19 @@ static void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
 }
 
 
+void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s)
+{
+       struct fils_hlp_req *req;
+
+       while ((req = dl_list_first(&wpa_s->fils_hlp_req, struct fils_hlp_req,
+                                   list)) != NULL) {
+               dl_list_del(&req->list);
+               wpabuf_free(req->pkt);
+               os_free(req);
+       }
+}
+
+
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
        int i;
@@ -434,6 +452,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 #ifdef CONFIG_TESTING_OPTIONS
        l2_packet_deinit(wpa_s->l2_test);
        wpa_s->l2_test = NULL;
+       os_free(wpa_s->get_pref_freq_list_override);
+       wpa_s->get_pref_freq_list_override = NULL;
 #endif /* CONFIG_TESTING_OPTIONS */
 
        if (wpa_s->conf != NULL) {
@@ -580,6 +600,28 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 
        wpabuf_free(wpa_s->lci);
        wpa_s->lci = NULL;
+       wpas_clear_beacon_rep_data(wpa_s);
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+       {
+               struct external_pmksa_cache *entry;
+
+               while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache,
+                                            struct external_pmksa_cache,
+                                            list)) != NULL) {
+                       dl_list_del(&entry->list);
+                       os_free(entry->pmksa_cache);
+                       os_free(entry);
+               }
+       }
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+       wpas_flush_fils_hlp_req(wpa_s);
+
+       wpabuf_free(wpa_s->ric_ies);
+       wpa_s->ric_ies = NULL;
 }
 
 
@@ -1691,11 +1733,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                        wmm_ac_save_tspecs(wpa_s);
                        wpa_s->reassoc_same_bss = 1;
                }
-       } else if (rand_style > 0) {
+       }
+
+       if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
                if (wpas_update_random_addr(wpa_s, rand_style) < 0)
                        return;
                wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
-       } else if (wpa_s->mac_addr_changed) {
+       } else if (rand_style == 0 && wpa_s->mac_addr_changed) {
                if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
                        wpa_msg(wpa_s, MSG_INFO,
                                "Could not restore permanent MAC address");
@@ -1714,6 +1758,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_IBSS_RSN
        ibss_rsn_deinit(wpa_s->ibss_rsn);
        wpa_s->ibss_rsn = NULL;
+#else /* CONFIG_IBSS_RSN */
+       if (ssid->mode == WPAS_MODE_IBSS &&
+           !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       "IBSS RSN not supported in the build");
+               return;
+       }
 #endif /* CONFIG_IBSS_RSN */
 
        if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
@@ -1784,6 +1835,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                return;
        }
 
+#ifdef CONFIG_SME
+       if (ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) {
+               /* Clear possibly set auth_alg, if any, from last attempt. */
+               wpa_s->sme.auth_alg = WPA_AUTH_ALG_OPEN;
+       }
+#endif /* CONFIG_SME */
+
        wpas_abort_ongoing_scan(wpa_s);
 
        cwork = os_zalloc(sizeof(*cwork));
@@ -2018,6 +2076,13 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
 
        vht_freq = *freq;
 
+#ifdef CONFIG_VHT_OVERRIDES
+       if (ssid->disable_vht) {
+               freq->vht_enabled = 0;
+               return;
+       }
+#endif /* CONFIG_VHT_OVERRIDES */
+
        vht_freq.vht_enabled = vht_supported(mode);
        if (!vht_freq.vht_enabled)
                return;
@@ -2126,9 +2191,6 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        struct ieee80211_vht_capabilities vhtcaps;
        struct ieee80211_vht_capabilities vhtcaps_mask;
 #endif /* CONFIG_VHT_OVERRIDES */
-#ifdef CONFIG_MBO
-       const u8 *mbo = NULL;
-#endif /* CONFIG_MBO */
 
        if (deinit) {
                if (work->started) {
@@ -2317,21 +2379,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
 #endif /* CONFIG_P2P */
 
-#ifdef CONFIG_MBO
        if (bss) {
-               mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
-               if (mbo) {
-                       int len;
-
-                       len = wpas_mbo_supp_op_class_ie(wpa_s, bss->freq,
-                                                       wpa_ie + wpa_ie_len,
-                                                       sizeof(wpa_ie) -
-                                                       wpa_ie_len);
-                       if (len > 0)
-                               wpa_ie_len += len;
-               }
+               wpa_ie_len += wpas_supp_op_class_ie(wpa_s, bss->freq,
+                                                   wpa_ie + wpa_ie_len,
+                                                   sizeof(wpa_ie) -
+                                                   wpa_ie_len);
        }
-#endif /* CONFIG_MBO */
 
        /*
         * Workaround: Add Extended Capabilities element only if the AP
@@ -2410,7 +2463,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 #endif /* CONFIG_FST */
 
 #ifdef CONFIG_MBO
-       if (mbo) {
+       if (bss && wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
                int len;
 
                len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
@@ -3693,6 +3746,7 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
        wpa_s->sched_scanning = 0;
 
        dl_list_init(&wpa_s->bss_tmp_disallowed);
+       dl_list_init(&wpa_s->fils_hlp_req);
 
        return wpa_s;
 }
@@ -3720,8 +3774,11 @@ static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
        wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
 
        for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+               long v;
+
                errno = 0;
-               long v = strtol(tmp, &end, 16);
+               v = strtol(tmp, &end, 16);
+
                if (errno == 0) {
                        wpa_msg(wpa_s, MSG_DEBUG,
                                "htcap value[%i]: %ld end: %p  tmp: %p",
@@ -3831,18 +3888,10 @@ static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
                                struct ieee80211_ht_capabilities *htcaps_mask,
                                int disabled)
 {
-       /* Masking these out disables HT40 */
-       le16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
-                               HT_CAP_INFO_SHORT_GI40MHZ);
-
        wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
 
-       if (disabled)
-               htcaps->ht_capabilities_info &= ~msk;
-       else
-               htcaps->ht_capabilities_info |= msk;
-
-       htcaps_mask->ht_capabilities_info |= msk;
+       set_disable_ht40(htcaps, disabled);
+       set_disable_ht40(htcaps_mask, 0);
 
        return 0;
 }
@@ -4118,10 +4167,14 @@ static int wpas_fst_send_action_cb(void *ctx, const u8 *da, struct wpabuf *data)
 {
        struct wpa_supplicant *wpa_s = ctx;
 
-       WPA_ASSERT(os_memcmp(wpa_s->bssid, da, ETH_ALEN) == 0);
+       if (os_memcmp(wpa_s->bssid, da, ETH_ALEN) != 0) {
+               wpa_printf(MSG_INFO, "FST:%s:bssid=" MACSTR " != da=" MACSTR,
+                          __func__, MAC2STR(wpa_s->bssid), MAC2STR(da));
+               return -1;
+       }
        return wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
-                                         wpa_s->own_addr, wpa_s->bssid,
-                                         wpabuf_head(data), wpabuf_len(data),
+                                  wpa_s->own_addr, wpa_s->bssid,
+                                  wpabuf_head(data), wpabuf_len(data),
                                   0);
 }
 
@@ -4319,6 +4372,20 @@ static void radio_work_free(struct wpa_radio_work *work)
 }
 
 
+static int radio_work_is_connect(struct wpa_radio_work *work)
+{
+       return os_strcmp(work->type, "sme-connect") == 0 ||
+               os_strcmp(work->type, "connect") == 0;
+}
+
+
+static int radio_work_is_scan(struct wpa_radio_work *work)
+{
+       return os_strcmp(work->type, "scan") == 0 ||
+               os_strcmp(work->type, "p2p-scan") == 0;
+}
+
+
 static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
 {
        struct wpa_radio_work *active_work = NULL;
@@ -4348,8 +4415,7 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
                return NULL;
        }
 
-       if (os_strcmp(active_work->type, "sme-connect") == 0 ||
-           os_strcmp(active_work->type, "connect") == 0) {
+       if (radio_work_is_connect(active_work)) {
                /*
                 * If the active work is either connect or sme-connect,
                 * do not parallelize them with other radio works.
@@ -4368,10 +4434,20 @@ static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
                 * If connect or sme-connect are enqueued, parallelize only
                 * those operations ahead of them in the queue.
                 */
-               if (os_strcmp(tmp->type, "connect") == 0 ||
-                   os_strcmp(tmp->type, "sme-connect") == 0)
+               if (radio_work_is_connect(tmp))
                        break;
 
+               /* Serialize parallel scan and p2p_scan operations on the same
+                * interface since the driver_nl80211 mechanism for tracking
+                * scan cookies does not yet have support for this. */
+               if (active_work->wpa_s == tmp->wpa_s &&
+                   radio_work_is_scan(active_work) &&
+                   radio_work_is_scan(tmp)) {
+                       wpa_dbg(active_work->wpa_s, MSG_DEBUG,
+                               "Do not start work '%s' when another work '%s' is already scheduled",
+                               tmp->type, active_work->type);
+                       continue;
+               }
                /*
                 * Check that the radio works are distinct and
                 * on different bands.
@@ -4967,6 +5043,12 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
        if (wpa_bss_init(wpa_s) < 0)
                return -1;
 
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+       dl_list_init(&wpa_s->mesh_external_pmksa_cache);
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
        /*
         * Set Wake-on-WLAN triggers, if configured.
         * Note: We don't restore/remove the triggers on shutdown (it doesn't
@@ -5268,6 +5350,7 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
 #ifdef CONFIG_MESH
        unsigned int mesh_if_created = wpa_s->mesh_if_created;
        char *ifname = NULL;
+       struct wpa_supplicant *parent = wpa_s->parent;
 #endif /* CONFIG_MESH */
 
        /* Remove interface from the global list of interfaces */
@@ -5303,7 +5386,7 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
 
 #ifdef CONFIG_MESH
        if (mesh_if_created) {
-               wpa_drv_if_remove(global->ifaces, WPA_IF_MESH, ifname);
+               wpa_drv_if_remove(parent, WPA_IF_MESH, ifname);
                os_free(ifname);
        }
 #endif /* CONFIG_MESH */
@@ -5896,6 +5979,7 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
        case WPA_CTRL_REQ_SIM:
                str_clear_free(eap->external_sim_resp);
                eap->external_sim_resp = os_strdup(value);
+               eap->pending_req_sim = 0;
                break;
        case WPA_CTRL_REQ_PSK_PASSPHRASE:
                if (wpa_config_set(ssid, "psk", value, 0) < 0)
@@ -6274,489 +6358,6 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
 }
 
 
-static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx)
-{
-       struct rrm_data *rrm = data;
-
-       if (!rrm->notify_neighbor_rep) {
-               wpa_printf(MSG_ERROR,
-                          "RRM: Unexpected neighbor report timeout");
-               return;
-       }
-
-       wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE");
-       rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL);
-
-       rrm->notify_neighbor_rep = NULL;
-       rrm->neighbor_rep_cb_ctx = NULL;
-}
-
-
-/*
- * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant
- * @wpa_s: Pointer to wpa_supplicant
- */
-void wpas_rrm_reset(struct wpa_supplicant *wpa_s)
-{
-       wpa_s->rrm.rrm_used = 0;
-
-       eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
-                            NULL);
-       if (wpa_s->rrm.notify_neighbor_rep)
-               wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
-       wpa_s->rrm.next_neighbor_rep_token = 1;
-}
-
-
-/*
- * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report
- * @wpa_s: Pointer to wpa_supplicant
- * @report: Neighbor report buffer, prefixed by a 1-byte dialog token
- * @report_len: Length of neighbor report buffer
- */
-void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
-                                  const u8 *report, size_t report_len)
-{
-       struct wpabuf *neighbor_rep;
-
-       wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len);
-       if (report_len < 1)
-               return;
-
-       if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: Discarding neighbor report with token %d (expected %d)",
-                          report[0], wpa_s->rrm.next_neighbor_rep_token - 1);
-               return;
-       }
-
-       eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
-                            NULL);
-
-       if (!wpa_s->rrm.notify_neighbor_rep) {
-               wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
-               return;
-       }
-
-       /* skipping the first byte, which is only an id (dialog token) */
-       neighbor_rep = wpabuf_alloc(report_len - 1);
-       if (neighbor_rep == NULL)
-               return;
-       wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
-       wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
-                  report[0]);
-       wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
-                                      neighbor_rep);
-       wpa_s->rrm.notify_neighbor_rep = NULL;
-       wpa_s->rrm.neighbor_rep_cb_ctx = NULL;
-}
-
-
-#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
-/* Workaround different, undefined for Windows, error codes used here */
-#define ENOTCONN -1
-#define EOPNOTSUPP -1
-#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
- *     the requester's responsibility to free it.
- *     In the latter case NULL will be sent in 'neighbor_rep'.
- * @cb_ctx: Context value to send the callback function
- * Returns: 0 in case of success, negative error code otherwise
- *
- * In case there is a previous request which has not been answered yet, the
- * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT.
- * Request must contain a callback function.
- */
-int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
-                                      const struct wpa_ssid_value *ssid,
-                                      int lci, int civic,
-                                      void (*cb)(void *ctx,
-                                                 struct wpabuf *neighbor_rep),
-                                      void *cb_ctx)
-{
-       struct wpabuf *buf;
-       const u8 *rrm_ie;
-
-       if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
-               wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
-               return -ENOTCONN;
-       }
-
-       if (!wpa_s->rrm.rrm_used) {
-               wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
-               return -EOPNOTSUPP;
-       }
-
-       rrm_ie = wpa_bss_get_ie(wpa_s->current_bss,
-                               WLAN_EID_RRM_ENABLED_CAPABILITIES);
-       if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
-           !(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: No network support for Neighbor Report.");
-               return -EOPNOTSUPP;
-       }
-
-       if (!cb) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: Neighbor Report request must provide a callback.");
-               return -EINVAL;
-       }
-
-       /* Refuse if there's a live request */
-       if (wpa_s->rrm.notify_neighbor_rep) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: Currently handling previous Neighbor Report.");
-               return -EBUSY;
-       }
-
-       /* 3 = action category + action code + dialog token */
-       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");
-               return -ENOMEM;
-       }
-
-       wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
-                  (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
-                  wpa_s->rrm.next_neighbor_rep_token);
-
-       wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
-       wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
-       wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token);
-       if (ssid) {
-               wpabuf_put_u8(buf, WLAN_EID_SSID);
-               wpabuf_put_u8(buf, ssid->ssid_len);
-               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,
-                               wpa_s->own_addr, wpa_s->bssid,
-                               wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
-               wpa_printf(MSG_DEBUG,
-                          "RRM: Failed to send Neighbor Report Request");
-               wpabuf_free(buf);
-               return -ECANCELED;
-       }
-
-       wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx;
-       wpa_s->rrm.notify_neighbor_rep = cb;
-       eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0,
-                              wpas_rrm_neighbor_rep_timeout_handler,
-                              &wpa_s->rrm, NULL);
-
-       wpabuf_free(buf);
-       return 0;
-}
-
-
-static struct wpabuf * wpas_rrm_build_lci_report(struct wpa_supplicant *wpa_s,
-                                                const u8 *request, size_t len,
-                                                struct wpabuf *report)
-{
-       u8 token, type, subject;
-       u16 max_age = 0;
-       struct os_reltime t, diff;
-       unsigned long diff_l;
-       u8 *ptoken;
-       const u8 *subelem;
-
-       if (!wpa_s->lci || len < 3 + 4)
-               return report;
-
-       token = *request++;
-       /* Measurement request mode isn't used */
-       request++;
-       type = *request++;
-       subject = *request++;
-
-       wpa_printf(MSG_DEBUG,
-                  "Measurement request token %u type %u location subject %u",
-                  token, type, subject);
-
-       if (type != MEASURE_TYPE_LCI || subject != LOCATION_SUBJECT_REMOTE) {
-               wpa_printf(MSG_INFO,
-                          "Not building LCI report - bad type or location subject");
-               return report;
-       }
-
-       /* Subelements are formatted exactly like elements */
-       subelem = get_ie(request, len, LCI_REQ_SUBELEM_MAX_AGE);
-       if (subelem && subelem[1] == 2)
-               max_age = WPA_GET_LE16(subelem + 2);
-
-       if (os_get_reltime(&t))
-               return report;
-
-       os_reltime_sub(&t, &wpa_s->lci_time, &diff);
-       /* LCI age is calculated in 10th of a second units. */
-       diff_l = diff.sec * 10 + diff.usec / 100000;
-
-       if (max_age != 0xffff && max_age < diff_l)
-               return report;
-
-       if (wpabuf_resize(&report, 2 + wpabuf_len(wpa_s->lci)))
-               return report;
-
-       wpabuf_put_u8(report, WLAN_EID_MEASURE_REPORT);
-       wpabuf_put_u8(report, wpabuf_len(wpa_s->lci));
-       /* We'll override user's measurement token */
-       ptoken = wpabuf_put(report, 0);
-       wpabuf_put_buf(report, wpa_s->lci);
-       *ptoken = token;
-
-       return report;
-}
-
-
-void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
-                                              const u8 *src,
-                                              const u8 *frame, size_t len)
-{
-       struct wpabuf *buf, *report;
-       u8 token;
-       const u8 *ie, *end;
-
-       if (wpa_s->wpa_state != WPA_COMPLETED) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Ignoring radio measurement request: Not associated");
-               return;
-       }
-
-       if (!wpa_s->rrm.rrm_used) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Ignoring radio measurement request: Not RRM network");
-               return;
-       }
-
-       if (len < 3) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Ignoring too short radio measurement request");
-               return;
-       }
-
-       end = frame + len;
-
-       token = *frame++;
-
-       /* Ignore number of repetitions because it's not used in LCI request */
-       frame += 2;
-
-       report = NULL;
-       while ((ie = get_ie(frame, end - frame, WLAN_EID_MEASURE_REQUEST)) &&
-              ie[1] >= 3) {
-               u8 msmt_type;
-
-               msmt_type = ie[4];
-               wpa_printf(MSG_DEBUG, "RRM request %d", msmt_type);
-
-               switch (msmt_type) {
-               case MEASURE_TYPE_LCI:
-                       report = wpas_rrm_build_lci_report(wpa_s, ie + 2, ie[1],
-                                                          report);
-                       break;
-               default:
-                       wpa_printf(MSG_INFO,
-                                  "RRM: Unsupported radio measurement request %d",
-                                  msmt_type);
-                       break;
-               }
-
-               frame = ie + ie[1] + 2;
-       }
-
-       if (!report)
-               return;
-
-       buf = wpabuf_alloc(3 + wpabuf_len(report));
-       if (!buf) {
-               wpabuf_free(report);
-               return;
-       }
-
-       wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
-       wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REPORT);
-       wpabuf_put_u8(buf, token);
-
-       wpabuf_put_buf(buf, report);
-       wpabuf_free(report);
-
-       if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
-                               wpa_s->own_addr, wpa_s->bssid,
-                               wpabuf_head(buf), wpabuf_len(buf), 0)) {
-               wpa_printf(MSG_ERROR,
-                          "RRM: Radio measurement report failed: Sending Action frame failed");
-       }
-       wpabuf_free(buf);
-}
-
-
-void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
-                                             const u8 *src,
-                                             const u8 *frame, size_t len,
-                                             int rssi)
-{
-       struct wpabuf *buf;
-       const struct rrm_link_measurement_request *req;
-       struct rrm_link_measurement_report report;
-
-       if (wpa_s->wpa_state != WPA_COMPLETED) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Ignoring link measurement request. Not associated");
-               return;
-       }
-
-       if (!wpa_s->rrm.rrm_used) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Ignoring link measurement request. Not RRM network");
-               return;
-       }
-
-       if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Measurement report failed. TX power insertion not supported");
-               return;
-       }
-
-       req = (const struct rrm_link_measurement_request *) frame;
-       if (len < sizeof(*req)) {
-               wpa_printf(MSG_INFO,
-                          "RRM: Link measurement report failed. Request too short");
-               return;
-       }
-
-       os_memset(&report, 0, sizeof(report));
-       report.tpc.eid = WLAN_EID_TPC_REPORT;
-       report.tpc.len = 2;
-       report.rsni = 255; /* 255 indicates that RSNI is not available */
-       report.dialog_token = req->dialog_token;
-
-       /*
-        * It's possible to estimate RCPI based on RSSI in dBm. This
-        * calculation will not reflect the correct value for high rates,
-        * but it's good enough for Action frames which are transmitted
-        * with up to 24 Mbps rates.
-        */
-       if (!rssi)
-               report.rcpi = 255; /* not available */
-       else if (rssi < -110)
-               report.rcpi = 0;
-       else if (rssi > 0)
-               report.rcpi = 220;
-       else
-               report.rcpi = (rssi + 110) * 2;
-
-       /* action_category + action_code */
-       buf = wpabuf_alloc(2 + sizeof(report));
-       if (buf == NULL) {
-               wpa_printf(MSG_ERROR,
-                          "RRM: Link measurement report failed. Buffer allocation failed");
-               return;
-       }
-
-       wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
-       wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT);
-       wpabuf_put_data(buf, &report, sizeof(report));
-       wpa_hexdump(MSG_DEBUG, "RRM: Link measurement report:",
-                   wpabuf_head(buf), wpabuf_len(buf));
-
-       if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
-                               wpa_s->own_addr, wpa_s->bssid,
-                               wpabuf_head(buf), wpabuf_len(buf), 0)) {
-               wpa_printf(MSG_ERROR,
-                          "RRM: Link measurement report failed. Send action failed");
-       }
-       wpabuf_free(buf);
-}
-
-
 struct wpa_supplicant *
 wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame)
 {