diff --git a/components/esp8266/include/esp_wifi.h b/components/esp8266/include/esp_wifi.h
index 54592fd3..0aaaf49c 100644
--- a/components/esp8266/include/esp_wifi.h
+++ b/components/esp8266/include/esp_wifi.h
@@ -992,6 +992,33 @@ esp_err_t esp_wifi_80211_tx(wifi_interface_t ifx, const void *buffer, int len, b
  */
 wifi_state_t esp_wifi_get_state(void);
 
+/**
+ * @brief      Set RSSI threshold below which APP will get an event
+ *
+ * @attention  This API needs to be called every time after WIFI_EVENT_STA_BSS_RSSI_LOW event is received.
+ *
+ * @param      rssi threshold value in dbm between -100 to 0
+ *
+ * @return
+ *    - ESP_OK: succeed
+ *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init
+ *    - ESP_ERR_WIFI_ARG: invalid argument
+ */
+esp_err_t esp_wifi_set_rssi_threshold(int32_t rssi);
+
+/**
+ * @brief      Get the TSF time
+ *             In Station mode or SoftAP+Station mode if station is not connected or station doesn't receive at least
+ *             one beacon after connected, will return 0
+ *
+ * @attention  Enabling power save may cause the return value inaccurate, except WiFi modem sleep
+ *
+ * @param      interface The interface whose tsf_time is to be retrieved.
+ *
+ * @return     0 or the TSF time
+ */
+int64_t esp_wifi_get_tsf_time(wifi_interface_t interface);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/components/esp8266/include/esp_wifi_types.h b/components/esp8266/include/esp_wifi_types.h
index 9b7c413e..69b44532 100755
--- a/components/esp8266/include/esp_wifi_types.h
+++ b/components/esp8266/include/esp_wifi_types.h
@@ -272,6 +272,9 @@ typedef struct {
     wifi_sort_method_t sort_method;    /**< sort the connect AP in the list by rssi or security mode */
     wifi_fast_scan_threshold_t  threshold;     /**< When scan_method is set to WIFI_FAST_SCAN, only APs which have an auth mode that is more secure than the selected auth mode and a signal stronger than the minimum RSSI will be used. */
     wifi_pmf_config_t pmf_cfg;    /**< Configuration for Protected Management Frame. Will be advertized in RSN Capabilities in RSN IE. */
+    uint32_t rm_enabled:1;        /**< Whether radio measurements are enabled for the connection */
+    uint32_t btm_enabled:1;       /**< Whether BTM is enabled for the connection */
+    uint32_t reserved:30;         /**< Reserved for future feature set */
 } wifi_sta_config_t;
 
 /** @brief Configuration data for ESP8266 AP or STA.
@@ -481,6 +484,7 @@ typedef enum {
     WIFI_EVENT_STA_CONNECTED,            /**< station connected to AP */
     WIFI_EVENT_STA_DISCONNECTED,         /**< station disconnected from AP */
     WIFI_EVENT_STA_AUTHMODE_CHANGE,      /**< the auth mode of AP connected by station changed */
+    WIFI_EVENT_STA_BSS_RSSI_LOW,         /**< AP's RSSI crossed configured threshold */
     WIFI_EVENT_STA_WPS_ER_SUCCESS,       /**< station wps succeeds in enrollee mode */
     WIFI_EVENT_STA_WPS_ER_FAILED,        /**< station wps fails in enrollee mode */
     WIFI_EVENT_STA_WPS_ER_TIMEOUT,       /**< station wps timeout in enrollee mode */
@@ -556,6 +560,11 @@ typedef struct {
     uint8_t reason;           /**< reason of disconnection */
 } wifi_event_sta_disconnected_t;
 
+/** Argument structure for WIFI_EVENT_STA_BSS_RSSI_LOW event */
+typedef struct {
+    int32_t rssi;                 /**< RSSI value of bss */
+} wifi_event_bss_rssi_low_t;
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/components/esp_event/event_send_compat.inc b/components/esp_event/event_send_compat.inc
index 4a954112..a920eee2 100644
--- a/components/esp_event/event_send_compat.inc
+++ b/components/esp_event/event_send_compat.inc
@@ -79,6 +79,7 @@ esp_err_t esp_event_send_to_default_loop(system_event_t *event)
         HANDLE_SYS_EVENT(WIFI, STA_WPS_ER_TIMEOUT);
         HANDLE_SYS_EVENT_ARG(WIFI, STA_WPS_ER_FAILED, sta_er_fail_reason);
         HANDLE_SYS_EVENT_ARG(WIFI, STA_WPS_ER_PIN, sta_er_pin);
+        HANDLE_SYS_EVENT_ARG(WIFI, STA_BSS_RSSI_LOW, bss_rssi_low);
 
         /* AP events */
         HANDLE_SYS_EVENT(WIFI, AP_START);
@@ -250,6 +251,11 @@ static void esp_system_event_debug(const system_event_t* event)
                        MAC2STR(ap_probereqrecved->mac));
             break;
         }
+        case SYSTEM_EVENT_STA_BSS_RSSI_LOW: {
+            const system_event_bss_rssi_low_t *bss_rssi_low = &event->event_info.bss_rssi_low;
+            ESP_LOGD(TAG, "SYSTEM_EVENT_STA_BSS_RSSI_LOW, rssi:%d", bss_rssi_low->rssi);
+            break;
+        }
 #if LWIP_IPV6
         case SYSTEM_EVENT_GOT_IP6: {
             const ip6_addr_t *addr = &event->event_info.got_ip6.ip6_info.ip;
diff --git a/components/esp_event/include/esp_event_legacy.h b/components/esp_event/include/esp_event_legacy.h
index 671696af..a54ad0e5 100644
--- a/components/esp_event/include/esp_event_legacy.h
+++ b/components/esp_event/include/esp_event_legacy.h
@@ -34,6 +34,7 @@ typedef enum {
     SYSTEM_EVENT_STA_CONNECTED,            /*!< station connected to AP */
     SYSTEM_EVENT_STA_DISCONNECTED,         /*!< station disconnected from AP */
     SYSTEM_EVENT_STA_AUTHMODE_CHANGE,      /*!< the auth mode of AP connected by station changed */
+    SYSTEM_EVENT_STA_BSS_RSSI_LOW,         /*!< Connected BSS rssi goes below threshold */
     SYSTEM_EVENT_STA_GOT_IP,               /*!< station got IP from connected AP */
     SYSTEM_EVENT_STA_LOST_IP,              /*!< station lost IP and the IP is reset to 0 */
     SYSTEM_EVENT_STA_WPS_ER_SUCCESS,       /*!< station wps succeeds in enrollee mode */
@@ -88,6 +89,9 @@ typedef wifi_event_ap_stadisconnected_t system_event_ap_stadisconnected_t;
 /** Argument structure of  event */
 typedef wifi_event_ap_probe_req_rx_t system_event_ap_probe_req_rx_t;
 
+/** Argument structure of  event */
+typedef wifi_event_bss_rssi_low_t system_event_bss_rssi_low_t;
+
 /** Argument structure of  event */
 typedef ip_event_ap_staipassigned_t system_event_ap_staipassigned_t;
 
@@ -109,6 +113,7 @@ typedef union {
     system_event_ap_staconnected_t             sta_connected;      /*!< a station connected to soft-AP */
     system_event_ap_stadisconnected_t          sta_disconnected;   /*!< a station disconnected to soft-AP */
     system_event_ap_probe_req_rx_t             ap_probereqrecved;  /*!< soft-AP receive probe request packet */
+    system_event_bss_rssi_low_t                bss_rssi_low;       /*!< Connected BSS rssi goes below threshold */
     system_event_ap_staipassigned_t            ap_staipassigned;   /**< soft-AP assign an IP to the station*/
     system_event_got_ip6_t                     got_ip6;            /*!< station or ap or ethernet ipv6 addr state change to preferred */
 } system_event_info_t;
diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt
index c635717e..1b9651cb 100644
--- a/components/wpa_supplicant/CMakeLists.txt
+++ b/components/wpa_supplicant/CMakeLists.txt
@@ -6,6 +6,7 @@ set(srcs "port/os_xtensa.c"
     "src/common/sae.c"
     "src/common/wpa_common.c"
     "src/common/dpp.c"
+    "src/utils/bitfield.c"
     "src/crypto/aes-ctr.c"
     "src/crypto/aes-siv.c"
     "src/crypto/sha256-kdf.c"
@@ -106,7 +107,21 @@ else()
     )
 endif()
 
-idf_component_register(SRCS "${srcs}" "${tls_src}"
+if (CONFIG_WPA_11KV_SUPPORT)
+    set(roaming_src
+    "src/common/rrm.c"
+    "src/common/wnm_sta.c"
+    "src/common/bss.c"
+    "src/common/scan.c"
+    "src/common/ieee802_11_common.c"
+    "src/esp_supplicant/esp_common.c"
+    "src/esp_supplicant/esp_scan.c"
+    )
+else()
+    set(roaming_src "")
+endif()
+
+idf_component_register(SRCS "${srcs}" "${tls_src}" "${roaming_src}"
                     INCLUDE_DIRS include port/include include/esp_supplicant
                     PRIV_INCLUDE_DIRS src
                     PRIV_REQUIRES mbedtls freertos heap newlib)
@@ -132,4 +147,5 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE
     CONFIG_WPA3_SAE
     #CONFIG_SHA256
     CONFIG_DPP
+    CONFIG_WNM
     )
diff --git a/components/wpa_supplicant/Kconfig b/components/wpa_supplicant/Kconfig
index 0057d40c..e21d696d 100644
--- a/components/wpa_supplicant/Kconfig
+++ b/components/wpa_supplicant/Kconfig
@@ -50,4 +50,22 @@ config LTM_FAST
             button bit without setting virtual/phycial display/button bit which
             will cause M2 validation fail, bypassing WPS-Config method validation.
 
+    menuconfig WPA_11KV_SUPPORT
+        bool "Enable 802.11k, 802.11v APIs handling in supplicant"
+        default n
+        help
+            Select this option to enable 802.11k 802.11v APIs.
+            Only APIs which are helpful for network assisted roaming
+            are supported for now.
+            Enable this option with btm and rrm enabled in sta config
+            to make device ready for network assisted roaming.
+
+    if WPA_11KV_SUPPORT
+        config WPA_SCAN_CACHE
+            bool "Keep scan results in cache"
+            default n
+            help
+                Keep scan results in cache, if not enabled, those
+                will be flushed immediately.
+    endif
 endmenu
diff --git a/components/wpa_supplicant/component.mk b/components/wpa_supplicant/component.mk
index 73f48a52..e89325d9 100644
--- a/components/wpa_supplicant/component.mk
+++ b/components/wpa_supplicant/component.mk
@@ -5,7 +5,7 @@ COMPONENT_SRCDIRS := port src/ap src/common src/crypto src/eap_peer src/rsn_supp
 COMPONENT_ADD_INCLUDEDIRS := include port/include include/esp_supplicant
 
 ifeq ($(CONFIG_WPA_MBEDTLS_CRYPTO), y)
-    COMPONENT_OBJEXCLUDE := src/tls/asn1.o \
+    COMPONENT_OBJEXCLUDE += src/tls/asn1.o \
     src/tls/bignum.o \
     src/tls/pkcs1.o \
     src/tls/pkcs5.o \
@@ -25,5 +25,14 @@ ifeq ($(CONFIG_WPA_MBEDTLS_CRYPTO), y)
 else
     COMPONENT_OBJEXCLUDE := src/crypto/tls_mbedtls.o
 endif
+ifneq ($(CONFIG_WPA_11KV_SUPPORT), y)
+    COMPONENT_OBJEXCLUDE += src/common/rrm.o \
+    src/common/wnm_sta.o \
+    src/common/bss.o \
+    src/common/scan.o \
+    src/common/ieee802_11_common.o \
+    src/esp_supplicant/esp_common.o \
+    src/esp_supplicant/esp_scan.o
+endif
 
-CFLAGS += -DCONFIG_DPP -DCONFIG_WPA3_SAE -DCONFIG_IEEE80211W -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_TLS -DEAP_TTLS -DEAP_PEAP -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP8266_WORKAROUND -DCONFIG_ECC -D__ets__ -Wno-strict-aliasing
+CFLAGS += -DCONFIG_DPP -DCONFIG_WPA3_SAE -DCONFIG_IEEE80211W -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_TLS -DEAP_TTLS -DEAP_PEAP -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP8266_WORKAROUND -DCONFIG_ECC -DCONFIG_WNM -D__ets__ -Wno-strict-aliasing
diff --git a/components/wpa_supplicant/include/esp_supplicant/esp_rrm.h b/components/wpa_supplicant/include/esp_supplicant/esp_rrm.h
new file mode 100755
index 00000000..7e2ccb51
--- /dev/null
+++ b/components/wpa_supplicant/include/esp_supplicant/esp_rrm.h
@@ -0,0 +1,54 @@
+/**
+ * Copyright 2020 Espressif Systems (Shanghai) PTE LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ESP_RRM_H
+#define _ESP_RRM_H
+
+#include <stdbool.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+  * @brief  Callback function type to get neighbor report
+  *
+  * @param  ctx: neighbor report context
+  * @param  report: neighbor report
+  * @param  report_len: neighbor report length
+  *
+  * @return
+  *    - void
+  */
+typedef void (*neighbor_rep_request_cb)(void *ctx, const uint8_t *report, size_t report_len);
+
+/**
+  * @brief  Send Radio measurement neighbor report request to connect AP
+  *
+  * @param  cb: callback function for neighbor report
+  * @param  cb_ctx: callback context
+  *
+  * @return
+  *    - 0: success else failure
+  */
+int esp_rrm_send_neighbor_rep_request(neighbor_rep_request_cb cb,
+				      void *cb_ctx);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
diff --git a/components/wpa_supplicant/include/esp_supplicant/esp_wnm.h b/components/wpa_supplicant/include/esp_supplicant/esp_wnm.h
new file mode 100755
index 00000000..d3e5ccc4
--- /dev/null
+++ b/components/wpa_supplicant/include/esp_supplicant/esp_wnm.h
@@ -0,0 +1,58 @@
+/**
+ * Copyright 2020 Espressif Systems (Shanghai) PTE LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ESP_WNM_H
+#define _ESP_WNM_H
+
+#include <stdbool.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+  * enum btm_query_reason: Reason code for sending btm query
+  */
+enum btm_query_reason {
+	REASON_UNSPECIFIED = 0,
+	REASON_FRAME_LOSS = 1,
+	REASON_DELAY = 2,
+	REASON_QOS_CAPACITY = 3,
+	REASON_FIRST_ASSOC = 4,
+	REASON_LOAD_BALALNCE = 5,
+	REASON_BETTER_AP = 6,
+	REASON_CURRENT_DEAUTH = 7,
+};
+
+/**
+  * @brief  Send bss transition query to connected AP
+  *
+  * @param  query_reason: reason for sending query
+  * @param  btm_candidates: btm candidates list if available
+  * @param  cand_list: whether candidate list to be included or not
+  *
+  * @return
+  *    - 0: success else failure
+  */
+int esp_wnm_send_bss_transition_mgmt_query(enum btm_query_reason query_reason,
+					   const char *btm_candidates,
+					   int cand_list);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
diff --git a/components/wpa_supplicant/include/utils/wpa_debug.h b/components/wpa_supplicant/include/utils/wpa_debug.h
index e32c697f..918af2ab 100644
--- a/components/wpa_supplicant/include/utils/wpa_debug.h
+++ b/components/wpa_supplicant/include/utils/wpa_debug.h
@@ -17,6 +17,7 @@
 
 #include "wpabuf.h"
 #include "esp_log.h"
+#include "supplicant_opt.h"
 
 #ifdef ESPRESSIF_USE
 
@@ -60,6 +61,7 @@ void wpa_debug_print_timestamp(void);
  * Note: New line '\n' is added to the end of the text when printing to stdout.
  */
 #define wpa_printf(level,fmt, args...) ESP_LOG_LEVEL_LOCAL(level, TAG, fmt, ##args)
+#define wpa_dbg(ctx, level, fmt, args...) wpa_printf(level, fmt, ##args)
 
 void wpa_dump_mem(char* desc, uint8_t *addr, uint16_t len);
 static inline void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
@@ -153,6 +155,7 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
 #define wpa_hexdump_buf_key(...) do {} while(0)
 #define wpa_hexdump_ascii(...) do {} while(0)
 #define wpa_hexdump_ascii_key(...) do {} while(0)
+#define wpa_dbg(...) do {} while(0)
 #endif
 
 #define wpa_auth_logger
diff --git a/components/wpa_supplicant/port/include/os.h b/components/wpa_supplicant/port/include/os.h
index a7c8eadc..33d85873 100644
--- a/components/wpa_supplicant/port/include/os.h
+++ b/components/wpa_supplicant/port/include/os.h
@@ -40,6 +40,8 @@ struct os_time {
 	suseconds_t usec;
 };
 
+#define os_reltime os_time
+
 struct os_tm {
     int sec; /* 0..59 or 60 for leap seconds */
     int min; /* 0..59 */
@@ -55,7 +57,7 @@ struct os_tm {
  * Returns: 0 on success, -1 on failure
  */
 int os_get_time(struct os_time *t);
-
+#define os_get_reltime os_get_time
 
 /* Helper macros for handling struct os_time */
 
@@ -63,6 +65,7 @@ int os_get_time(struct os_time *t);
 	((a)->sec < (b)->sec || \
 	 ((a)->sec == (b)->sec && (a)->usec < (b)->usec))
 
+#define os_reltime_before os_time_before
 #define os_time_sub(a, b, res) do { \
 	(res)->sec = (a)->sec - (b)->sec; \
 	(res)->usec = (a)->usec - (b)->usec; \
@@ -71,6 +74,7 @@ int os_get_time(struct os_time *t);
 		(res)->usec += 1000000; \
 	} \
 } while (0)
+#define os_reltime_sub os_time_sub
 
 /**
  * os_mktime - Convert broken-down time into seconds since 1970-01-01
@@ -213,6 +217,10 @@ char * os_readfile(const char *name, size_t *len);
 #ifndef os_zalloc
 #define os_zalloc(s) calloc(1, (s))
 #endif
+#ifndef os_calloc
+#define os_calloc(p, s) calloc((p), (s))
+#endif
+
 #ifndef os_free
 #define os_free(p) free((p))
 #endif
@@ -299,4 +307,11 @@ static inline int os_snprintf_error(size_t size, int res)
 {
         return res < 0 || (unsigned int) res >= size;
 }
+
+static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
+{
+	if (size && nmemb > (~(size_t) 0) / size)
+		return NULL;
+	return os_realloc(ptr, nmemb * size);
+}
 #endif /* OS_H */
diff --git a/components/wpa_supplicant/port/include/supplicant_opt.h b/components/wpa_supplicant/port/include/supplicant_opt.h
index a3d4c666..b70ffd4c 100644
--- a/components/wpa_supplicant/port/include/supplicant_opt.h
+++ b/components/wpa_supplicant/port/include/supplicant_opt.h
@@ -28,4 +28,12 @@
 #define DEBUG_PRINT
 #endif
 
+#if CONFIG_WPA_11KV_SUPPORT
+#define ROAMING_SUPPORT 1
+#endif
+
+#if CONFIG_WPA_SCAN_CACHE
+#define SCAN_CACHE_SUPPORTED
+#endif
+
 #endif /* _SUPPLICANT_OPT_H */
diff --git a/components/wpa_supplicant/port/os_xtensa.c b/components/wpa_supplicant/port/os_xtensa.c
index 9a4ed9d9..94f5c0f6 100644
--- a/components/wpa_supplicant/port/os_xtensa.c
+++ b/components/wpa_supplicant/port/os_xtensa.c
@@ -25,6 +25,7 @@
 #include "os.h"
 #include <stdlib.h>
 #include <time.h>
+#include <unistd.h>
 #include <sys/time.h>
 #include "esp_system.h"
 #include "utils/common.h"
@@ -49,3 +50,10 @@ int os_get_random(unsigned char *buf, size_t len)
     return 0;
 }
 
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+        if (sec)
+                sleep(sec);
+        if (usec)
+                usleep(usec);
+}
diff --git a/components/wpa_supplicant/src/ap/wpa_auth.c b/components/wpa_supplicant/src/ap/wpa_auth.c
index 8b430987..56b41212 100644
--- a/components/wpa_supplicant/src/ap/wpa_auth.c
+++ b/components/wpa_supplicant/src/ap/wpa_auth.c
@@ -2177,7 +2177,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
 }
 
 
-#ifdef CONFIG_WNM
+#ifdef CONFIG_WNM_AP
 /* update GTK when exiting WNM-Sleep Mode */
 void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
 {
@@ -2254,7 +2254,7 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
     return pos - start;
 }
 #endif /* CONFIG_IEEE80211W */
-#endif /* CONFIG_WNM */
+#endif /* CONFIG_WNM_AP */
 
 
 static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
diff --git a/components/wpa_supplicant/src/common/bss.c b/components/wpa_supplicant/src/common/bss.c
new file mode 100755
index 00000000..32c628f6
--- /dev/null
+++ b/components/wpa_supplicant/src/common/bss.c
@@ -0,0 +1,478 @@
+/*
+ * BSS table
+ * Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "drivers/driver.h"
+#include "eap_peer/eap.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#include "scan.h"
+#include "bss.h"
+#ifdef ESP_SUPPLICANT
+#include "esp_supplicant/esp_wifi_driver.h"
+#endif
+
+#define MAX_BSS_COUNT 20
+
+void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+		    const char *reason)
+{
+	if (wpa_s->last_scan_res) {
+		unsigned int i;
+		for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+			if (wpa_s->last_scan_res[i] == bss) {
+				os_memmove(&wpa_s->last_scan_res[i],
+					   &wpa_s->last_scan_res[i + 1],
+					   (wpa_s->last_scan_res_used - i - 1)
+					   * sizeof(struct wpa_bss *));
+				wpa_s->last_scan_res_used--;
+				break;
+			}
+		}
+	}
+	dl_list_del(&bss->list);
+	dl_list_del(&bss->list_id);
+	wpa_s->num_bss--;
+	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
+		" SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
+		wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
+	os_free(bss);
+}
+
+
+/**
+ * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * @ssid: SSID
+ * @ssid_len: Length of @ssid
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
+struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			     const u8 *ssid, size_t ssid_len)
+{
+	struct wpa_bss *bss;
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
+		    bss->ssid_len == ssid_len &&
+		    os_memcmp(bss->ssid, ssid, ssid_len) == 0)
+			return bss;
+	}
+	return NULL;
+}
+
+
+void calculate_update_time(const struct os_reltime *fetch_time,
+			   unsigned int age_ms,
+			   struct os_reltime *update_time)
+{
+	os_time_t usec;
+
+	update_time->sec = fetch_time->sec;
+	update_time->usec = fetch_time->usec;
+	update_time->sec -= age_ms / 1000;
+	usec = (age_ms % 1000) * 1000;
+	if (update_time->usec < usec) {
+		update_time->sec--;
+		update_time->usec += 1000000;
+	}
+	update_time->usec -= usec;
+}
+
+
+static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
+			     struct os_reltime *fetch_time)
+{
+	dst->flags = src->flags;
+	os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
+	dst->channel = src->chan;
+	dst->beacon_int = src->beacon_int;
+	dst->caps = src->caps;
+	dst->noise = src->noise;
+	dst->level = src->level;
+	dst->tsf = src->tsf;
+	dst->parent_tsf = src->parent_tsf;
+
+	calculate_update_time(fetch_time, src->age, &dst->last_update);
+}
+
+#ifdef ESP_SUPPLICANT
+static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	struct wifi_ssid *ssid = esp_wifi_sta_get_prof_ssid_internal();
+
+	if (ssid->ssid == NULL || ssid->len == 0)
+		return 0;
+	if (ssid->len == bss->ssid_len &&
+	    os_memcmp(ssid->ssid, bss->ssid, ssid->len) == 0)
+		return 1;
+	return 0;
+}
+#endif
+
+static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	if (bss == wpa_s->current_bss)
+		return 1;
+
+	if (wpa_s->current_bss &&
+	    (bss->ssid_len != wpa_s->current_bss->ssid_len ||
+	     os_memcmp(bss->ssid, wpa_s->current_bss->ssid,
+		       bss->ssid_len) != 0))
+		return 0; /* SSID has changed */
+
+	return !is_zero_ether_addr(bss->bssid) && wpa_s->current_bss->bssid &&
+		(os_memcmp(bss->bssid, wpa_s->current_bss->bssid, ETH_ALEN) == 0);
+
+	return 0;
+}
+
+static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (!wpa_bss_known(wpa_s, bss)) {
+			wpa_bss_remove(wpa_s, bss, __func__);
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+
+	/*
+	 * Remove the oldest entry that does not match with any configured
+	 * network.
+	 */
+	if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
+		return 0;
+
+	/*
+	 * Remove the oldest entry that isn't currently in use.
+	 */
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (!wpa_bss_in_use(wpa_s, bss)) {
+			wpa_bss_remove(wpa_s, bss, __func__);
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
+				    const u8 *ssid, size_t ssid_len,
+				    struct wpa_scan_res *res,
+				    struct os_reltime *fetch_time)
+{
+	struct wpa_bss *bss;
+
+	if ((wpa_s->num_bss + 1 > MAX_BSS_COUNT) &&
+	    (wpa_bss_remove_oldest(wpa_s) < 0)) {
+		wpa_printf(MSG_ERROR,
+			   "Failed to clean older entries, rejecting scan result");
+		return NULL;
+	}
+
+	bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
+	if (bss == NULL)
+		return NULL;
+	bss->id = wpa_s->bss_next_id++;
+	bss->last_update_idx = wpa_s->bss_update_idx;
+	wpa_bss_copy_res(bss, res, fetch_time);
+	os_memcpy(bss->ssid, ssid, ssid_len);
+	bss->ssid_len = ssid_len;
+	bss->ie_len = res->ie_len;
+	bss->beacon_ie_len = res->beacon_ie_len;
+	os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
+
+	dl_list_add_tail(&wpa_s->bss, &bss->list);
+	dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
+	wpa_s->num_bss++;
+	wpa_dbg(wpa_s, MSG_INFO, "BSS: Add new id %u BSSID " MACSTR
+		" SSID '%s' chan %d",
+		bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len),
+		bss->channel);
+	return bss;
+}
+
+static struct wpa_bss *
+wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+	       struct wpa_scan_res *res, struct os_reltime *fetch_time)
+{
+	if (bss->last_update_idx == wpa_s->bss_update_idx) {
+		struct os_reltime update_time;
+
+		/*
+		 * Some drivers (e.g., cfg80211) include multiple BSS entries
+		 * for the same BSS if that BSS's channel changes. The BSS list
+		 * implementation in wpa_supplicant does not do that and we need
+		 * to filter out the obsolete results here to make sure only the
+		 * most current BSS information remains in the table.
+		 */
+		wpa_printf(MSG_DEBUG, "BSS: " MACSTR
+			   " has multiple entries in the scan results - select the most current one",
+			   MAC2STR(bss->bssid));
+		calculate_update_time(fetch_time, res->age, &update_time);
+		wpa_printf(MSG_DEBUG,
+			   "Accept this BSS entry since it looks more current than the previous update");
+	}
+
+	bss->last_update_idx = wpa_s->bss_update_idx;
+	wpa_bss_copy_res(bss, res, fetch_time);
+	/* Move the entry to the end of the list */
+	dl_list_del(&bss->list);
+	if (bss->ie_len + bss->beacon_ie_len >=
+	    res->ie_len + res->beacon_ie_len) {
+		os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
+		bss->ie_len = res->ie_len;
+		bss->beacon_ie_len = res->beacon_ie_len;
+	} else {
+		struct wpa_bss *nbss;
+		struct dl_list *prev = bss->list_id.prev;
+		dl_list_del(&bss->list_id);
+		nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
+				  res->beacon_ie_len);
+		if (nbss) {
+			unsigned int i;
+			for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+				if (wpa_s->last_scan_res[i] == bss) {
+					wpa_s->last_scan_res[i] = nbss;
+					break;
+				}
+			}
+			if (wpa_s->current_bss == bss)
+				wpa_s->current_bss = nbss;
+			bss = nbss;
+			os_memcpy(bss + 1, res + 1,
+				  res->ie_len + res->beacon_ie_len);
+			bss->ie_len = res->ie_len;
+			bss->beacon_ie_len = res->beacon_ie_len;
+		}
+		dl_list_add(prev, &bss->list_id);
+	}
+	dl_list_add_tail(&wpa_s->bss, &bss->list);
+
+	return bss;
+}
+
+
+/**
+ * wpa_bss_update_start - Start a BSS table update from scan results
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is called at the start of each BSS table update round for new
+ * scan results. The actual scan result entries are indicated with calls to
+ * wpa_bss_update_scan_res() and the update round is finished with a call to
+ * wpa_bss_update_end().
+ */
+void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
+{
+	wpa_s->bss_update_idx++;
+	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
+		wpa_s->bss_update_idx);
+	wpa_s->last_scan_res_used = 0;
+}
+
+
+/**
+ * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @res: Scan result
+ * @fetch_time: Time when the result was fetched from the driver
+ *
+ * This function updates a BSS table entry (or adds one) based on a scan result.
+ * This is called separately for each scan result between the calls to
+ * wpa_bss_update_start() and wpa_bss_update_end().
+ */
+void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
+			     struct wpa_scan_res *res,
+			     struct os_reltime *fetch_time)
+{
+	const u8 *ssid;
+	struct wpa_bss *bss;
+
+	ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
+	if (ssid == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
+			MACSTR, MAC2STR(res->bssid));
+		return;
+	}
+	if (ssid[1] > SSID_MAX_LEN) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
+			MACSTR, MAC2STR(res->bssid));
+		return;
+	}
+
+	/* TODO: add option for ignoring BSSes we are not interested in
+	 * (to save memory) */
+
+	bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
+	if (bss == NULL)
+		bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
+	else {
+		bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
+		if (wpa_s->last_scan_res) {
+			unsigned int i;
+			for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+				if (bss == wpa_s->last_scan_res[i]) {
+					/* Already in the list */
+					return;
+				}
+			}
+		}
+	}
+
+	if (bss == NULL)
+		return;
+	if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
+		struct wpa_bss **n;
+		unsigned int siz;
+		if (wpa_s->last_scan_res_size == 0)
+			siz = 32;
+		else
+			siz = wpa_s->last_scan_res_size * 2;
+		n = os_realloc_array(wpa_s->last_scan_res, siz,
+				     sizeof(struct wpa_bss *));
+		if (n == NULL)
+			return;
+		wpa_s->last_scan_res = n;
+		wpa_s->last_scan_res_size = siz;
+	}
+
+	if (wpa_s->last_scan_res)
+		wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
+}
+
+
+/**
+ * wpa_bss_update_end - End a BSS table update from scan results
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @info: Information about scan parameters
+ * @new_scan: Whether this update round was based on a new scan
+ *
+ * This function is called at the end of each BSS table update round for new
+ * scan results. The start of the update was indicated with a call to
+ * wpa_bss_update_start().
+ */
+void wpa_bss_update_end(struct wpa_supplicant *wpa_s)
+{
+	os_get_reltime(&wpa_s->last_scan);
+}
+
+/**
+ * wpa_bss_init - Initialize BSS table
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This prepares BSS table lists and timer for periodic updates. The BSS table
+ * is deinitialized with wpa_bss_deinit() once not needed anymore.
+ */
+int wpa_bss_init(struct wpa_supplicant *wpa_s)
+{
+	dl_list_init(&wpa_s->bss);
+	dl_list_init(&wpa_s->bss_id);
+	return 0;
+}
+
+
+/**
+ * wpa_bss_flush - Flush all unused BSS entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_bss_flush(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss, *n;
+
+	if (wpa_s->bss.next == NULL)
+		return; /* BSS table not yet initialized */
+
+	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
+		if (wpa_bss_in_use(wpa_s, bss))
+			continue;
+		wpa_bss_remove(wpa_s, bss, __func__);
+	}
+}
+
+
+/**
+ * wpa_bss_deinit - Deinitialize BSS table
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
+{
+	wpa_bss_flush(wpa_s);
+}
+
+
+/**
+ * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
+struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
+				   const u8 *bssid)
+{
+	struct wpa_bss *bss;
+	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+			return bss;
+	}
+	return NULL;
+}
+
+
+/**
+ * wpa_bss_get_next_bss - Fetch a next BSS table entry from the list
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bss: BSS
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
+struct wpa_bss * wpa_bss_get_next_bss(struct wpa_supplicant *wpa_s,
+				   struct wpa_bss *prev_bss)
+{
+	struct wpa_bss *bss;
+
+	if (!prev_bss)
+		return dl_list_first(&wpa_s->bss, struct wpa_bss, list);
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (os_memcmp(bss->bssid, prev_bss->bssid, ETH_ALEN) == 0)
+			return dl_list_entry(bss->list.next, struct wpa_bss, list);
+	}
+	return NULL;
+}
+
+/**
+ * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
+ * @bss: BSS table entry
+ * @ie: Information element identitifier (WLAN_EID_*)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ */
+const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
+{
+	return get_ie((const u8 *) (bss + 1), bss->ie_len, ie);
+}
+
+int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab)
+{
+	return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB),
+				    capab);
+}
diff --git a/components/wpa_supplicant/src/common/bss.h b/components/wpa_supplicant/src/common/bss.h
new file mode 100755
index 00000000..c34941a7
--- /dev/null
+++ b/components/wpa_supplicant/src/common/bss.h
@@ -0,0 +1,86 @@
+/*
+ * BSS table
+ * Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BSS_H
+#define BSS_H
+
+struct wpa_scan_res;
+
+/**
+ * struct wpa_bss - BSS table
+ *
+ * This structure is used to store information about neighboring BSSes in
+ * generic format. It is mainly updated based on scan results from the driver.
+ */
+struct wpa_bss {
+	/** List entry for struct wpa_supplicant::bss */
+	struct dl_list list;
+	/** List entry for struct wpa_supplicant::bss_id */
+	struct dl_list list_id;
+	/** Unique identifier for this BSS entry */
+	unsigned int id;
+	/** Index of the last scan update */
+	unsigned int last_update_idx;
+	/** Information flags about the BSS/IBSS (WPA_BSS_*) */
+	unsigned int flags;
+	/** BSSID */
+	u8 bssid[ETH_ALEN];
+	/** SSID */
+	u8 ssid[SSID_MAX_LEN];
+	/** Length of SSID */
+	size_t ssid_len;
+	/** Frequency of the channel in MHz (e.g., 2412 = channel 1) */
+	int channel;
+	/** Beacon interval in TUs (host byte order) */
+	u16 beacon_int;
+	/** Capability information field in host byte order */
+	u16 caps;
+	/** Signal quality */
+	int qual;
+	/** Noise level */
+	int noise;
+	/** Signal level */
+	int level;
+	/** Timestamp of last Beacon/Probe Response frame */
+	u64 tsf;
+	/** Timestamp of parent aganist which it was taken */
+	u64 parent_tsf;
+	/** Time of the last update (i.e., Beacon or Probe Response RX) */
+	struct os_reltime last_update;
+	/** Length of the following IE field in octets (from Probe Response) */
+	size_t ie_len;
+	/** Length of the following Beacon IE field in octets */
+	size_t beacon_ie_len;
+	/* followed by ie_len octets of IEs */
+	/* followed by beacon_ie_len octets of IEs */
+};
+
+void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
+void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
+			     struct wpa_scan_res *res,
+			     struct os_reltime *fetch_time);
+void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+		    const char *reason);
+void wpa_bss_update_end(struct wpa_supplicant *wpa_s);
+int wpa_bss_init(struct wpa_supplicant *wpa_s);
+void wpa_bss_deinit(struct wpa_supplicant *wpa_s);
+void wpa_bss_flush(struct wpa_supplicant *wpa_s);
+struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			     const u8 *ssid, size_t ssid_len);
+struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
+				   const u8 *bssid);
+const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
+int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab);
+struct wpa_bss * wpa_bss_get_next_bss(struct wpa_supplicant *wpa_s,
+				   struct wpa_bss *prev_bss);
+
+void calculate_update_time(const struct os_reltime *fetch_time,
+			   unsigned int age_ms,
+			   struct os_reltime *update_time);
+
+#endif /* BSS_H */
diff --git a/components/wpa_supplicant/src/common/ieee802_11_common.c b/components/wpa_supplicant/src/common/ieee802_11_common.c
new file mode 100755
index 00000000..ca159c1b
--- /dev/null
+++ b/components/wpa_supplicant/src/common/ieee802_11_common.c
@@ -0,0 +1,198 @@
+/*
+ * IEEE 802.11 Common routines
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "defs.h"
+#include "ieee802_11_defs.h"
+#include "ieee802_11_common.h"
+#include "common/wpa_supplicant_i.h"
+
+/**
+ * get_ie - Fetch a specified information element from IEs buffer
+ * @ies: Information elements buffer
+ * @len: Information elements buffer length
+ * @eid: Information element identifier (WLAN_EID_*)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the IEs
+ * buffer or %NULL in case the element is not found.
+ */
+const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
+{
+	const struct element *elem;
+
+	if (!ies)
+		return NULL;
+
+	for_each_element_id(elem, eid, ies, len)
+		return &elem->id;
+
+	return NULL;
+}
+
+int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
+				    size_t nei_rep_len)
+{
+	u8 *nei_pos = nei_rep;
+	const char *end;
+
+	/*
+	 * BSS Transition Candidate List Entries - Neighbor Report elements
+	 * neighbor=<BSSID>,<BSSID Information>,<Operating Class>,
+	 * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>]
+	 */
+	while (pos) {
+		u8 *nei_start;
+		long int val;
+		char *endptr, *tmp;
+
+		pos = os_strstr(pos, " neighbor=");
+		if (!pos)
+			break;
+		if (nei_pos + 15 > nei_rep + nei_rep_len) {
+			wpa_printf(MSG_DEBUG,
+				   "Not enough room for additional neighbor");
+			return -1;
+		}
+		pos += 10;
+
+		nei_start = nei_pos;
+		*nei_pos++ = WLAN_EID_NEIGHBOR_REPORT;
+		nei_pos++; /* length to be filled in */
+
+		if (hwaddr_aton2(pos, nei_pos) < 0) {
+			wpa_printf(MSG_DEBUG, "Invalid BSSID");
+			return -1;
+		}
+		nei_pos += ETH_ALEN;
+		pos += 17;
+		if (*pos != ',') {
+			wpa_printf(MSG_DEBUG, "Missing BSSID Information");
+			return -1;
+		}
+		pos++;
+
+		val = strtol(pos, &endptr, 0);
+		WPA_PUT_LE32(nei_pos, val);
+		nei_pos += 4;
+		if (*endptr != ',') {
+			wpa_printf(MSG_DEBUG, "Missing Operating Class");
+			return -1;
+		}
+		pos = endptr + 1;
+
+		*nei_pos++ = atoi(pos); /* Operating Class */
+		pos = os_strchr(pos, ',');
+		if (pos == NULL) {
+			wpa_printf(MSG_DEBUG, "Missing Channel Number");
+			return -1;
+		}
+		pos++;
+
+		*nei_pos++ = atoi(pos); /* Channel Number */
+		pos = os_strchr(pos, ',');
+		if (pos == NULL) {
+			wpa_printf(MSG_DEBUG, "Missing PHY Type");
+			return -1;
+		}
+		pos++;
+
+		*nei_pos++ = atoi(pos); /* PHY Type */
+		end = os_strchr(pos, ' ');
+		tmp = os_strchr(pos, ',');
+		if (tmp && (!end || tmp < end)) {
+			/* Optional Subelements (hexdump) */
+			size_t len;
+
+			pos = tmp + 1;
+			end = os_strchr(pos, ' ');
+			if (end)
+				len = end - pos;
+			else
+				len = os_strlen(pos);
+			if (nei_pos + len / 2 > nei_rep + nei_rep_len) {
+				wpa_printf(MSG_DEBUG,
+					   "Not enough room for neighbor subelements");
+				return -1;
+			}
+			if (len & 0x01 ||
+			    hexstr2bin(pos, nei_pos, len / 2) < 0) {
+				wpa_printf(MSG_DEBUG,
+					   "Invalid neighbor subelement info");
+				return -1;
+			}
+			nei_pos += len / 2;
+			pos = end;
+		}
+
+		nei_start[1] = nei_pos - nei_start - 2;
+	}
+
+	return nei_pos - nei_rep;
+}
+
+/**
+ * ieee802_11_parse_elems - Parse information elements in management frames
+ * @start: Pointer to the start of IEs
+ * @len: Length of IE buffer in octets
+ * @elems: Data structure for parsed elements
+ * @show_errors: Whether to show parsing errors in debug log
+ * Returns: Parsing result
+ */
+int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t len)
+{
+	const struct element *elem;
+
+	if (!start)
+		return 0;
+
+	for_each_element(elem, start, len) {
+		u8 id = elem->id;
+		const u8 *pos = elem->data;
+
+		switch (id) {
+		case WLAN_EID_RRM_ENABLED_CAPABILITIES:
+			os_memcpy(wpa_s->rrm_ie, pos, 5);
+			wpa_s->rrm.rrm_used = true;
+			break;
+		case WLAN_EID_EXT_CAPAB:
+			/* extended caps can go beyond 8 octacts but we aren't using them now */
+			os_memcpy(wpa_s->extend_caps, pos, 5);
+			break;
+		default:
+			break;
+
+		}
+	}
+	return 0;
+}
+
+int ieee802_11_ext_capab(const u8 *ie, unsigned int capab)
+{
+	if (!ie || ie[1] <= capab / 8)
+		return 0;
+	return !!(ie[2 + capab / 8] & BIT(capab % 8));
+}
+
+u8 get_operating_class(u8 chan, int sec_channel)
+{
+	u8 op_class;
+
+	if (chan < 1 || chan > 14)
+		return 0;
+	if (sec_channel == 1)
+		op_class = 83;
+	else if (sec_channel == -1)
+		op_class = 84;
+	else
+		op_class = 81;
+
+	return op_class;
+}
diff --git a/components/wpa_supplicant/src/common/ieee802_11_common.h b/components/wpa_supplicant/src/common/ieee802_11_common.h
new file mode 100755
index 00000000..80dd04cb
--- /dev/null
+++ b/components/wpa_supplicant/src/common/ieee802_11_common.h
@@ -0,0 +1,42 @@
+/*
+ * IEEE 802.11 Common routines
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_11_COMMON_H
+#define IEEE802_11_COMMON_H
+
+#include "defs.h"
+#include "ieee802_11_defs.h"
+
+struct element {
+	u8 id;
+	u8 datalen;
+	u8 data[];
+} STRUCT_PACKED;
+
+/* element iteration helpers */
+#define for_each_element(_elem, _data, _datalen)                        \
+	for (_elem = (const struct element *) (_data);                  \
+			(const u8 *) (_data) + (_datalen) - (const u8 *) _elem >=  \
+			(int) sizeof(*_elem) &&                                 \
+			(const u8 *) (_data) + (_datalen) - (const u8 *) _elem >=  \
+			(int) sizeof(*_elem) + _elem->datalen;                  \
+			_elem = (const struct element *) (_elem->data + _elem->datalen))
+
+#define for_each_element_id(element, _id, data, datalen)                \
+	for_each_element(element, data, datalen)                        \
+	if (element->id == (_id))
+
+struct wpa_supplicant;
+
+int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
+				    size_t nei_rep_len);
+const u8 * get_ie(const u8 *ies, size_t len, u8 eid);
+int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t len);
+int ieee802_11_ext_capab(const u8 *ie, unsigned int capab);
+u8 get_operating_class(u8 chan, int sec_channel);
+#endif /* IEEE802_11_COMMON_H */
diff --git a/components/wpa_supplicant/src/common/ieee802_11_defs.h b/components/wpa_supplicant/src/common/ieee802_11_defs.h
index 9260d22f..32e2ca92 100755
--- a/components/wpa_supplicant/src/common/ieee802_11_defs.h
+++ b/components/wpa_supplicant/src/common/ieee802_11_defs.h
@@ -1,21 +1,17 @@
 /*
  * IEEE 802.11 Frame type definitions
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2007-2008 Intel Corporation
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #ifndef IEEE802_11_DEFS_H
 #define IEEE802_11_DEFS_H
 
+#include <utils/common.h>
+
 /* IEEE 802.11 defines */
 
 #define WLAN_FC_PVER		0x0003
@@ -89,10 +85,15 @@
 #define WLAN_CAPABILITY_PBCC BIT(6)
 #define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7)
 #define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8)
+#define WLAN_CAPABILITY_QOS BIT(9)
 #define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10)
+#define WLAN_CAPABILITY_APSD BIT(11)
+#define WLAN_CAPABILITY_RADIO_MEASUREMENT BIT(12)
 #define WLAN_CAPABILITY_DSSS_OFDM BIT(13)
+#define WLAN_CAPABILITY_DELAYED_BLOCK_ACK BIT(14)
+#define WLAN_CAPABILITY_IMM_BLOCK_ACK BIT(15)
 
-/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
+/* Status codes (IEEE Std 802.11-2016, 9.4.1.9, Table 9-46) */
 #define WLAN_STATUS_SUCCESS 0
 #define WLAN_STATUS_UNSPECIFIED_FAILURE 1
 #define WLAN_STATUS_CAPS_UNSUPPORTED 10
@@ -104,26 +105,23 @@
 #define WLAN_STATUS_AUTH_TIMEOUT 16
 #define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
 #define WLAN_STATUS_ASSOC_DENIED_RATES 18
-/* IEEE 802.11b */
 #define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
-#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
-#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
-/* IEEE 802.11h */
 #define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
 #define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
 #define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
-/* IEEE 802.11g */
 #define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
-#define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26
-#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27
+#define WLAN_STATUS_ASSOC_DENIED_NO_HT 27
 #define WLAN_STATUS_R0KH_UNREACHABLE 28
-/* IEEE 802.11w */
+#define WLAN_STATUS_ASSOC_DENIED_NO_PCO 29
 #define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
 #define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
 #define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32
+#define WLAN_STATUS_DENIED_INSUFFICIENT_BANDWIDTH 33
+#define WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS 34
+#define WLAN_STATUS_DENIED_QOS_NOT_SUPPORTED 35
 #define WLAN_STATUS_REQUEST_DECLINED 37
 #define WLAN_STATUS_INVALID_PARAMETERS 38
-/* IEEE 802.11i */
+#define WLAN_STATUS_REJECTED_WITH_SUGGESTED_CHANGES 39
 #define WLAN_STATUS_INVALID_IE 40
 #define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
 #define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
@@ -136,7 +134,6 @@
 #define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
 #define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
 #define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
-/* IEEE 802.11r */
 #define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
 #define WLAN_STATUS_INVALID_PMKID 53
 #define WLAN_STATUS_INVALID_MDIE 54
@@ -161,7 +158,7 @@
 #define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104
 #define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123
 
-/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
+/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
 #define WLAN_REASON_UNSPECIFIED 1
 #define WLAN_REASON_PREV_AUTH_NOT_VALID 2
 #define WLAN_REASON_DEAUTH_LEAVING 3
@@ -171,10 +168,9 @@
 #define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
 #define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
 #define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
-/* IEEE 802.11h */
 #define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10
 #define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11
-/* IEEE 802.11i */
+#define WLAN_REASON_BSS_TRANSITION_DISASSOC 12
 #define WLAN_REASON_INVALID_IE 13
 #define WLAN_REASON_MICHAEL_MIC_FAILURE 14
 #define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
@@ -188,18 +184,15 @@
 #define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
 #define WLAN_REASON_CIPHER_SUITE_REJECTED 24
 
-
-/* Information Element IDs */
+/* Information Element IDs (IEEE Std 802.11-2016, 9.4.2.1, Table 9-77) */
 #define WLAN_EID_SSID 0
 #define WLAN_EID_SUPP_RATES 1
-#define WLAN_EID_FH_PARAMS 2
 #define WLAN_EID_DS_PARAMS 3
 #define WLAN_EID_CF_PARAMS 4
 #define WLAN_EID_TIM 5
 #define WLAN_EID_IBSS_PARAMS 6
 #define WLAN_EID_COUNTRY 7
 #define WLAN_EID_CHALLENGE 16
-/* EIDs defined by IEEE 802.11h - START */
 #define WLAN_EID_PWR_CONSTRAINT 32
 #define WLAN_EID_PWR_CAPABILITY 33
 #define WLAN_EID_TPC_REQUEST 34
@@ -208,23 +201,25 @@
 #define WLAN_EID_CHANNEL_SWITCH 37
 #define WLAN_EID_MEASURE_REQUEST 38
 #define WLAN_EID_MEASURE_REPORT 39
-#define WLAN_EID_QUITE 40
+#define WLAN_EID_QUIET 40
 #define WLAN_EID_IBSS_DFS 41
-/* EIDs defined by IEEE 802.11h - END */
 #define WLAN_EID_ERP_INFO 42
 #define WLAN_EID_HT_CAP 45
 #define WLAN_EID_RSN 48
 #define WLAN_EID_EXT_SUPP_RATES 50
+#define WLAN_EID_NEIGHBOR_REPORT 52
 #define WLAN_EID_MOBILITY_DOMAIN 54
 #define WLAN_EID_FAST_BSS_TRANSITION 55
 #define WLAN_EID_TIMEOUT_INTERVAL 56
 #define WLAN_EID_RIC_DATA 57
 #define WLAN_EID_HT_OPERATION 61
 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
+#define WLAN_EID_RRM_ENABLED_CAPABILITIES 70
 #define WLAN_EID_20_40_BSS_COEXISTENCE 72
 #define WLAN_EID_20_40_BSS_INTOLERANT 73
 #define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
 #define WLAN_EID_MMIE 76
+#define WLAN_EID_EXT_CAPAB 127
 #define WLAN_EID_VENDOR_SPECIFIC 221
 #define WLAN_EID_CAG_NUMBER 237
 #define WLAN_EID_AP_CSN 239
@@ -241,7 +236,7 @@
 #define WLAN_EID_EXT_FILS_HLP_CONTAINER 5
 #define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6
 #define WLAN_EID_EXT_KEY_DELIVERY 7
-#define WLAN_EID_EXT_FILS_WRAPPED_DATA 8
+#define WLAN_EID_EXT_WRAPPED_DATA 8
 #define WLAN_EID_EXT_FTM_SYNC_INFO 9
 #define WLAN_EID_EXT_EXTENDED_REQUEST 10
 #define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11
@@ -253,8 +248,7 @@
 #define WLAN_EID_EXT_HE_CAPABILITIES 35
 #define WLAN_EID_EXT_HE_OPERATION 36
 
-
-/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */
+/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
 #define WLAN_ACTION_SPECTRUM_MGMT 0
 #define WLAN_ACTION_QOS 1
 #define WLAN_ACTION_DLS 2
@@ -264,6 +258,8 @@
 #define WLAN_ACTION_FT 6
 #define WLAN_ACTION_HT 7
 #define WLAN_ACTION_SA_QUERY 8
+#define WLAN_ACTION_WNM 10
+#define WLAN_ACTION_UNPROTECTED_WNM 11
 #define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
 
 /* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
@@ -300,6 +296,51 @@ struct ieee80211_hdr {
 #define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr))
 
 #define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
+/* Radio Measurement Action codes */
+#define WLAN_RRM_RADIO_MEASUREMENT_REQUEST 0
+#define WLAN_RRM_RADIO_MEASUREMENT_REPORT 1
+#define WLAN_RRM_LINK_MEASUREMENT_REQUEST 2
+#define WLAN_RRM_LINK_MEASUREMENT_REPORT 3
+#define WLAN_RRM_NEIGHBOR_REPORT_REQUEST 4
+#define WLAN_RRM_NEIGHBOR_REPORT_RESPONSE 5
+
+/* Radio Measurement capabilities (from RM Enabled Capabilities element)
+ * IEEE Std 802.11-2016, 9.4.2.45, Table 9-157 */
+/* byte 1 (out of 5) */
+#define WLAN_RRM_CAPS_LINK_MEASUREMENT BIT(0)
+#define WLAN_RRM_CAPS_NEIGHBOR_REPORT BIT(1)
+#define WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE BIT(4)
+#define WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE BIT(5)
+#define WLAN_RRM_CAPS_BEACON_REPORT_TABLE BIT(6)
+
+/*
+ * IEEE P802.11-REVmc/D5.0 Table 9-81 - Measurement type definitions for
+ * measurement requests
+ */
+enum measure_type {
+	MEASURE_TYPE_RPI_HIST = 2,
+	MEASURE_TYPE_BEACON = 5,
+	MEASURE_TYPE_LCI = 8,
+	MEASURE_TYPE_LOCATION_CIVIC = 11,
+	MEASURE_TYPE_MEASURE_PAUSE = 255,
+};
+
+/* IEEE Std 802.11-2012 Table 8-71 - Location subject definition */
+enum location_subject {
+	LOCATION_SUBJECT_LOCAL = 0,
+	LOCATION_SUBJECT_REMOTE = 1,
+	LOCATION_SUBJECT_3RD_PARTY = 2,
+};
+
+/*
+ * IEEE P802.11-REVmc/D5.0 Table 9-94 - Optional subelement IDs for LCI request
+ */
+enum lci_req_subelem {
+	LCI_REQ_SUBELEM_AZIMUTH_REQ = 1,
+	LCI_REQ_SUBELEM_ORIGINATOR_MAC_ADDR = 2,
+	LCI_REQ_SUBELEM_TARGET_MAC_ADDR = 3,
+	LCI_REQ_SUBELEM_MAX_AGE = 4,
+};
 
 struct ieee80211_mgmt {
 	le16 frame_control;
@@ -406,6 +447,7 @@ struct ieee80211_mgmt {
 } STRUCT_PACKED;
 
 
+#define IEEE80211_MAX_MMPDU_SIZE 2304
 struct ieee80211_ht_capabilities {
 	le16 ht_capabilities_info;
 	u8 a_mpdu_params;
@@ -416,12 +458,14 @@ struct ieee80211_ht_capabilities {
 } STRUCT_PACKED;
 
 
+/* HT Operation element */
 struct ieee80211_ht_operation {
-	u8 control_chan;
-	u8 ht_param;
-	le16 operation_mode;
-	le16 stbc_param;
-	u8 basic_set[16];
+	u8 primary_chan;
+	/* Five octets of HT Operation Information */
+	u8 ht_param; /* B0..B7 */
+	le16 operation_mode; /* B8..B23 */
+	le16 param; /* B24..B39 */
+	u8 basic_mcs_set[16];
 } STRUCT_PACKED;
 
 #ifdef _MSC_VER
@@ -432,7 +476,9 @@ struct ieee80211_ht_operation {
 #define ERP_INFO_USE_PROTECTION BIT(1)
 #define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2)
 
+#define OVERLAPPING_BSS_TRANS_DELAY_FACTOR 5
 
+/* HT Capabilities Info field within HT Capabilities element */
 #define HT_CAP_INFO_LDPC_CODING_CAP		((u16) BIT(0))
 #define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET	((u16) BIT(1))
 #define HT_CAP_INFO_SMPS_MASK			((u16) (BIT(2) | BIT(3)))
@@ -450,79 +496,86 @@ struct ieee80211_ht_operation {
 #define HT_CAP_INFO_DELAYED_BA			((u16) BIT(10))
 #define HT_CAP_INFO_MAX_AMSDU_SIZE		((u16) BIT(11))
 #define HT_CAP_INFO_DSSS_CCK40MHZ		((u16) BIT(12))
-#define HT_CAP_INFO_PSMP_SUPP			((u16) BIT(13))
+/* B13 - Reserved (was PSMP support during P802.11n development) */
 #define HT_CAP_INFO_40MHZ_INTOLERANT		((u16) BIT(14))
 #define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT	((u16) BIT(15))
 
-
+/* HT Extended Capabilities field within HT Capabilities element */
 #define EXT_HT_CAP_INFO_PCO			((u16) BIT(0))
+#define EXT_HT_CAP_INFO_PCO_TRANS_TIME_MASK	((u16) (BIT(1) | BIT(2)))
 #define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET	1
+/* B3..B7 - Reserved */
+#define EXT_HT_CAP_INFO_MCS_FEEDBACK_MASK	((u16) (BIT(8) | BIT(9)))
 #define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET	8
-#define EXT_HT_CAP_INFO_HTC_SUPPORTED		((u16) BIT(10))
+#define EXT_HT_CAP_INFO_HTC_SUPPORT		((u16) BIT(10))
 #define EXT_HT_CAP_INFO_RD_RESPONDER		((u16) BIT(11))
+/* B12..B15 - Reserved */
 
+/* Transmit Beanforming Capabilities within HT Capabilities element */
+#define TX_BF_CAP_IMPLICIT_TXBF_RX_CAP ((u32) BIT(0))
+#define TX_BF_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1))
+#define TX_BF_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2))
+#define TX_BF_CAP_RX_NDP_CAP ((u32) BIT(3))
+#define TX_BF_CAP_TX_NDP_CAP ((u32) BIT(4))
+#define TX_BF_CAP_IMPLICIT_TX_BF_CAP ((u32) BIT(5))
+#define TX_BF_CAP_CALIBRATION_MASK ((u32) (BIT(6) | BIT(7))
+#define TX_BF_CAP_CALIB_OFFSET 6
+#define TX_BF_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8))
+#define TX_BF_CAP_EXPLICIT_NONCOMPR_STEERING_CAP ((u32) BIT(9))
+#define TX_BF_CAP_EXPLICIT_COMPR_STEERING_CAP ((u32) BIT(10))
+#define TX_BF_CAP_EXPLICIT_TX_BF_CSI_FEEDBACK_MASK ((u32) (BIT(10) | BIT(11)))
+#define TX_BF_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11
+#define TX_BF_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13
+#define TX_BF_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15
+#define TX_BF_CAP_MINIMAL_GROUPING_OFFSET 17
+#define TX_BF_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19
+#define TX_BF_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21
+#define TX_BF_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23
+#define TX_BF_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25
+#define TX_BF_CAP_CHANNEL_ESTIMATION_CAP_MASK ((u32) (BIT(27) | BIT(28)))
+#define TX_BF_CAP_CHANNEL_ESTIMATION_CAP_OFFSET 27
+/* B29..B31 - Reserved */
 
-#define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0))
-#define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1))
-#define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2))
-#define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3))
-#define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4))
-#define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5))
-#define TX_BEAMFORM_CAP_CALIB_OFFSET 6
-#define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8))
-#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9))
-#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10))
-#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11
-#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13
-#define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15
-#define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17
-#define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19
-#define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21
-#define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23
-#define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25
-
-
-#define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0))
-#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1))
-#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2))
-#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3))
-#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4))
-#define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5))
-#define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6))
+/* ASEL Capability field within HT Capabilities element */
+#define ASEL_CAP_ASEL_CAPABLE ((u8) BIT(0))
+#define ASEL_CAP_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1))
+#define ASEL_CAP_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2))
+#define ASEL_CAP_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3))
+#define ASEL_CAP_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4))
+#define ASEL_CAP_RX_AS_CAP ((u8) BIT(5))
+#define ASEL_CAP_TX_SOUNDING_PPDUS_CAP ((u8) BIT(6))
+/* B7 - Reserved */
 
+/* First octet of HT Operation Information within HT Operation element */
 #define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK	((u8) BIT(0) | BIT(1))
 #define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE		((u8) BIT(0))
 #define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW		((u8) BIT(0) | BIT(1))
-#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH		((u8) BIT(2))
+#define HT_INFO_HT_PARAM_STA_CHNL_WIDTH			((u8) BIT(2))
 #define HT_INFO_HT_PARAM_RIFS_MODE			((u8) BIT(3))
-#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY		((u8) BIT(4))
-#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY	((u8) BIT(5))
+/* B4..B7 - Reserved */
 
+/* HT Protection (B8..B9 of HT Operation Information) */
+#define HT_PROT_NO_PROTECTION           0
+#define HT_PROT_NONMEMBER_PROTECTION    1
+#define HT_PROT_20MHZ_PROTECTION        2
+#define HT_PROT_NON_HT_MIXED            3
+/* Bits within ieee80211_ht_operation::operation_mode (BIT(0) maps to B8 in
+ * HT Operation Information) */
+#define HT_OPER_OP_MODE_HT_PROT_MASK ((u16) (BIT(0) | BIT(1))) /* B8..B9 */
+#define HT_OPER_OP_MODE_NON_GF_HT_STAS_PRESENT	((u16) BIT(2)) /* B10 */
+/* BIT(3), i.e., B11 in HT Operation Information field - Reserved */
+#define HT_OPER_OP_MODE_OBSS_NON_HT_STAS_PRESENT	((u16) BIT(4)) /* B12 */
+/* BIT(5)..BIT(15), i.e., B13..B23 - Reserved */
 
-#define OP_MODE_PURE                    0
-#define OP_MODE_MAY_BE_LEGACY_STAS      1
-#define OP_MODE_20MHZ_HT_STA_ASSOCED    2
-#define OP_MODE_MIXED                   3
-
-#define HT_INFO_OPERATION_MODE_OP_MODE_MASK	\
-		((le16) (0x0001 | 0x0002))
-#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET		0
-#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT	((u8) BIT(2))
-#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT	((u8) BIT(3))
-#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT	((u8) BIT(4))
-
-#define HT_INFO_STBC_PARAM_DUAL_BEACON			((u16) BIT(6))
-#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT		((u16) BIT(7))
-#define HT_INFO_STBC_PARAM_SECONDARY_BCN		((u16) BIT(8))
-#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED	((u16) BIT(9))
-#define HT_INFO_STBC_PARAM_PCO_ACTIVE			((u16) BIT(10))
-#define HT_INFO_STBC_PARAM_PCO_PHASE			((u16) BIT(11))
-
-
-#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
-				* 00:50:F2 */
-#define WPA_IE_VENDOR_TYPE 0x0050f201
-#define WPS_IE_VENDOR_TYPE 0x0050f204
+/* Last two octets of HT Operation Information (BIT(0) = B24) */
+/* B24..B29 - Reserved */
+#define HT_OPER_PARAM_DUAL_BEACON			((u16) BIT(6))
+#define HT_OPER_PARAM_DUAL_CTS_PROTECTION		((u16) BIT(7))
+#define HT_OPER_PARAM_STBC_BEACON			((u16) BIT(8))
+#define HT_OPER_PARAM_LSIG_TXOP_PROT_FULL_SUPP		((u16) BIT(9))
+#define HT_OPER_PARAM_PCO_ACTIVE			((u16) BIT(10))
+#define HT_OPER_PARAM_PCO_PHASE				((u16) BIT(11))
+/* B36..B39 - Reserved */
 
 #define WMM_OUI_TYPE 2
 #define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
@@ -589,7 +642,7 @@ struct wmm_parameter_element {
 	u8 oui_type; /* 2 */
 	u8 oui_subtype; /* 1 */
 	u8 version; /* 1 for WMM version 1.0 */
-	u8 qos_info; /* AP/STA specif QoS info */
+	u8 qos_info; /* AP/STA specific QoS info */
 	u8 reserved; /* 0 */
 	struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
 
@@ -624,29 +677,260 @@ struct wmm_tspec_element {
 
 
 /* Access Categories / ACI to AC coding */
-enum {
+enum wmm_ac {
 	WMM_AC_BE = 0 /* Best Effort */,
 	WMM_AC_BK = 1 /* Background */,
 	WMM_AC_VI = 2 /* Video */,
-	WMM_AC_VO = 3 /* Voice */
+	WMM_AC_VO = 3 /* Voice */,
+	WMM_AC_NUM = 4
 };
 
+/* MBO v0.0_r19, 4.2.7: Transition Rejection Reason Code Attribute */
+/* Table 4-21: Transition Rejection Reason Code Field Values */
+enum mbo_transition_reject_reason {
+	MBO_TRANSITION_REJECT_REASON_UNSPECIFIED = 0,
+	MBO_TRANSITION_REJECT_REASON_FRAME_LOSS = 1,
+	MBO_TRANSITION_REJECT_REASON_DELAY = 2,
+	MBO_TRANSITION_REJECT_REASON_QOS_CAPACITY = 3,
+	MBO_TRANSITION_REJECT_REASON_RSSI = 4,
+	MBO_TRANSITION_REJECT_REASON_INTERFERENCE = 5,
+	MBO_TRANSITION_REJECT_REASON_SERVICES = 6,
+};
 
-#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
+/* IEEE 802.11v - WNM Action field values */
+enum wnm_action {
+	WNM_EVENT_REQ = 0,
+	WNM_EVENT_REPORT = 1,
+	WNM_DIAGNOSTIC_REQ = 2,
+	WNM_DIAGNOSTIC_REPORT = 3,
+	WNM_LOCATION_CFG_REQ = 4,
+	WNM_LOCATION_CFG_RESP = 5,
+	WNM_BSS_TRANS_MGMT_QUERY = 6,
+	WNM_BSS_TRANS_MGMT_REQ = 7,
+	WNM_BSS_TRANS_MGMT_RESP = 8,
+	WNM_FMS_REQ = 9,
+	WNM_FMS_RESP = 10,
+	WNM_COLLOCATED_INTERFERENCE_REQ = 11,
+	WNM_COLLOCATED_INTERFERENCE_REPORT = 12,
+	WNM_TFS_REQ = 13,
+	WNM_TFS_RESP = 14,
+	WNM_TFS_NOTIFY = 15,
+	WNM_SLEEP_MODE_REQ = 16,
+	WNM_SLEEP_MODE_RESP = 17,
+	WNM_TIM_BROADCAST_REQ = 18,
+	WNM_TIM_BROADCAST_RESP = 19,
+	WNM_QOS_TRAFFIC_CAPAB_UPDATE = 20,
+	WNM_CHANNEL_USAGE_REQ = 21,
+	WNM_CHANNEL_USAGE_RESP = 22,
+	WNM_DMS_REQ = 23,
+	WNM_DMS_RESP = 24,
+	WNM_TIMING_MEASUREMENT_REQ = 25,
+	WNM_NOTIFICATION_REQ = 26,
+	WNM_NOTIFICATION_RESP = 27
+};
 
-#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
+/* IEEE 802.11v - BSS Transition Management Request - Request Mode */
+#define WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED BIT(0)
+#define WNM_BSS_TM_REQ_ABRIDGED BIT(1)
+#define WNM_BSS_TM_REQ_DISASSOC_IMMINENT BIT(2)
+#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
+#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
 
-/* cipher suite selectors */
-#define WLAN_CIPHER_SUITE_USE_GROUP	0x000FAC00
-#define WLAN_CIPHER_SUITE_WEP40		0x000FAC01
-#define WLAN_CIPHER_SUITE_TKIP		0x000FAC02
-/* reserved: 				0x000FAC03 */
-#define WLAN_CIPHER_SUITE_CCMP		0x000FAC04
-#define WLAN_CIPHER_SUITE_WEP104	0x000FAC05
-#define WLAN_CIPHER_SUITE_AES_CMAC	0x000FAC06
+/* IEEE Std 802.11-2012 - Table 8-253 */
+enum bss_trans_mgmt_status_code {
+	WNM_BSS_TM_ACCEPT = 0,
+	WNM_BSS_TM_REJECT_UNSPECIFIED = 1,
+	WNM_BSS_TM_REJECT_INSUFFICIENT_BEACON = 2,
+	WNM_BSS_TM_REJECT_INSUFFICIENT_CAPABITY = 3,
+	WNM_BSS_TM_REJECT_UNDESIRED = 4,
+	WNM_BSS_TM_REJECT_DELAY_REQUEST = 5,
+	WNM_BSS_TM_REJECT_STA_CANDIDATE_LIST_PROVIDED = 6,
+	WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES = 7,
+	WNM_BSS_TM_REJECT_LEAVING_ESS = 8
+};
 
-/* AKM suite selectors */
-#define WLAN_AKM_SUITE_8021X		0x000FAC01
-#define WLAN_AKM_SUITE_PSK		0x000FAC02
+/*
+ * IEEE P802.11-REVmc/D5.0 Table 9-150 - Optional subelement IDs for
+ * neighbor report
+ */
+#define WNM_NEIGHBOR_TSF                         1
+#define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING    2
+#define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE    3
+#define WNM_NEIGHBOR_BSS_TERMINATION_DURATION    4
+#define WNM_NEIGHBOR_BEARING                     5
+#define WNM_NEIGHBOR_MEASUREMENT_REPORT         39
+#define WNM_NEIGHBOR_MEASUREMENT_PILOT          66
+#define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES   70
+#define WNM_NEIGHBOR_MULTIPLE_BSSID             71
+
+struct tpc_report {
+	u8 eid;
+	u8 len;
+	u8 tx_power;
+	u8 link_margin;
+} STRUCT_PACKED;
+
+#define RRM_CAPABILITIES_IE_LEN 5
+
+/* IEEE Std 802.11-2012, 8.5.7.4 - Link Measurement Request frame format */
+struct rrm_link_measurement_request {
+	u8 dialog_token;
+	s8 tx_power;
+	s8 max_tp;
+	u8 variable[0];
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2012, 8.5.7.5 - Link Measurement Report frame format */
+struct rrm_link_measurement_report {
+	u8 dialog_token;
+	struct tpc_report tpc;
+	u8 rx_ant_id;
+	u8 tx_ant_id;
+	u8 rcpi;
+	u8 rsni;
+	u8 variable[0];
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2016, 9.4.2.21 - Measurement Request element */
+struct rrm_measurement_request_element {
+	u8 eid; /* Element ID */
+	u8 len; /* Length */
+	u8 token; /* Measurement Token */
+	u8 mode; /* Measurement Request Mode */
+	u8 type; /* Measurement Type */
+	u8 variable[0]; /* Measurement Request */
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2016, Figure 9-148 - Measurement Request Mode field */
+#define MEASUREMENT_REQUEST_MODE_PARALLEL BIT(0)
+#define MEASUREMENT_REQUEST_MODE_ENABLE BIT(1)
+#define MEASUREMENT_REQUEST_MODE_REQUEST BIT(2)
+#define MEASUREMENT_REQUEST_MODE_REPORT BIT(3)
+#define MEASUREMENT_REQUEST_MODE_DURATION_MANDATORY BIT(4)
+
+/* IEEE Std 802.11-2016, 9.4.2.21.7 - Beacon request */
+struct rrm_measurement_beacon_request {
+	u8 oper_class; /* Operating Class */
+	u8 channel; /* Channel Number */
+	le16 rand_interval; /* Randomization Interval (in TUs) */
+	le16 duration; /* Measurement Duration (in TUs) */
+	u8 mode; /* Measurement Mode */
+	u8 bssid[ETH_ALEN]; /* BSSID */
+	u8 variable[0]; /* Optional Subelements */
+} STRUCT_PACKED;
+
+/*
+ * IEEE Std 802.11-2016, Table 9-87 - Measurement Mode definitions for Beacon
+ * request
+ */
+enum beacon_report_mode {
+	BEACON_REPORT_MODE_PASSIVE = 0,
+	BEACON_REPORT_MODE_ACTIVE = 1,
+	BEACON_REPORT_MODE_TABLE = 2,
+};
+
+/* 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
+
+/*
+ * IEEE Std 802.11-2016, Table 9-90 - Reporting Detail values
+ */
+enum beacon_report_detail {
+	/* No fixed-length fields or elements */
+	BEACON_REPORT_DETAIL_NONE = 0,
+	/* All fixed-length fields and any requested elements in the Request
+	 * element if present */
+	BEACON_REPORT_DETAIL_REQUESTED_ONLY = 1,
+	/* All fixed-length fields and elements (default, used when Reporting
+	 * Detail subelement is not included in a Beacon request) */
+	BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS = 2,
+};
+
+/* IEEE Std 802.11-2016, 9.4.2.22 - Measurement Report element */
+struct rrm_measurement_report_element {
+	u8 eid; /* Element ID */
+	u8 len; /* Length */
+	u8 token; /* Measurement Token */
+	u8 mode; /* Measurement Report Mode */
+	u8 type; /* Measurement Type */
+	u8 variable[0]; /* Measurement Report */
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2016, Figure 9-192 - Measurement Report Mode field */
+#define MEASUREMENT_REPORT_MODE_ACCEPT 0
+#define MEASUREMENT_REPORT_MODE_REJECT_LATE BIT(0)
+#define MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE BIT(1)
+#define MEASUREMENT_REPORT_MODE_REJECT_REFUSED BIT(2)
+
+/* IEEE Std 802.11-2016, 9.4.2.22.7 - Beacon report */
+struct rrm_measurement_beacon_report {
+	u8 op_class; /* Operating Class */
+	u8 channel; /* Channel Number */
+	le64 start_time; /* Actual Measurement Start Time
+			  * (in TSF of the BSS requesting the measurement) */
+	le16 duration; /* in TUs */
+	u8 report_info; /* Reported Frame Information */
+	u8 rcpi; /* RCPI */
+	u8 rsni; /* RSNI */
+	u8 bssid[ETH_ALEN]; /* BSSID */
+	u8 antenna_id; /* Antenna ID */
+	le32 parent_tsf; /* Parent TSF */
+	u8 variable[0]; /* Optional Subelements */
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2016, Table 9-112 - Beacon report Subelement IDs */
+/* IEEE P802.11-REVmd/D2.0, Table 9-130 - Optional subelement IDs for
+ * 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
+
+/* IEEE P802.11-REVmd/D2.0, Table 9-232 - Data field format of the
+ * Reported Frame Body Fragment ID subelement */
+#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.11ac-2013, Annex C - dot11PHYType */
+enum phy_type {
+	PHY_TYPE_UNSPECIFIED = 0,
+	PHY_TYPE_FHSS = 1,
+	PHY_TYPE_DSSS = 2,
+	PHY_TYPE_IRBASEBAND = 3,
+	PHY_TYPE_OFDM = 4,
+	PHY_TYPE_HRDSSS = 5,
+	PHY_TYPE_ERP = 6,
+	PHY_TYPE_HT = 7,
+	PHY_TYPE_DMG = 8,
+	PHY_TYPE_VHT = 9,
+};
+
+/* IEEE P802.11-REVmc/D5.0, 9.4.2.37 - Neighbor Report element */
+/* BSSID Information Field */
+#define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0)
+#define NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH BIT(1)
+#define NEI_REP_BSSID_INFO_AP_REACHABLE (BIT(0) | BIT(1))
+#define NEI_REP_BSSID_INFO_SECURITY BIT(2)
+#define NEI_REP_BSSID_INFO_KEY_SCOPE BIT(3)
+#define NEI_REP_BSSID_INFO_SPECTRUM_MGMT BIT(4)
+#define NEI_REP_BSSID_INFO_QOS BIT(5)
+#define NEI_REP_BSSID_INFO_APSD BIT(6)
+#define NEI_REP_BSSID_INFO_RM BIT(7)
+#define NEI_REP_BSSID_INFO_DELAYED_BA BIT(8)
+#define NEI_REP_BSSID_INFO_IMM_BA BIT(9)
+#define NEI_REP_BSSID_INFO_MOBILITY_DOMAIN BIT(10)
+#define NEI_REP_BSSID_INFO_HT BIT(11)
+#define NEI_REP_BSSID_INFO_VHT BIT(12)
+#define NEI_REP_BSSID_INFO_FTM BIT(13)
 
 #endif /* IEEE802_11_DEFS_H */
diff --git a/components/wpa_supplicant/src/common/rrm.c b/components/wpa_supplicant/src/common/rrm.c
new file mode 100755
index 00000000..4dc49f47
--- /dev/null
+++ b/components/wpa_supplicant/src/common/rrm.c
@@ -0,0 +1,1162 @@
+/*
+ * wpa_supplicant - Radio Measurements
+ * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/bitfield.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+#include "bss.h"
+#include "rrm.h"
+#include "scan.h"
+#include <sys/errno.h>
+#include "esp_supplicant/esp_common_i.h"
+
+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, 0);
+
+	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_clear_beacon_rep_data(wpa_s);
+}
+
+
+/*
+ * 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)
+{
+
+	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_msg(wpa_s, MSG_INFO, "RRM: Unexpected neighbor report");
+		return;
+	}
+
+	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,
+				       report, report_len);
+	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 */
+#ifndef ENOTCONN
+#define ENOTCONN -1
+#endif
+#ifndef EOPNOTSUPP
+#define EOPNOTSUPP -1
+#endif
+#ifndef ECANCELED
+#define ECANCELED -1
+#endif
+#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,
+						  const u8 *neighbor_rep, size_t len),
+				       void *cb_ctx)
+{
+	struct wpabuf *buf;
+
+	if (!(wpa_s->rrm_ie[0] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
+		wpa_printf(MSG_ERROR,
+			"RRM: No network support for Neighbor Report.");
+		return -EOPNOTSUPP;
+	}
+
+	/* Refuse if there's a live request */
+	if (wpa_s->rrm.notify_neighbor_rep) {
+		wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
+#if 0
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"RRM: Currently handling previous Neighbor Report.");
+		return -EBUSY;
+#endif
+	}
+
+	/* 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_dbg(wpa_s, MSG_DEBUG,
+			"RRM: Failed to allocate Neighbor Report Request");
+		return -ENOMEM;
+	}
+
+	wpa_dbg(wpa_s, 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, 0, 0,
+				wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+		wpa_dbg(wpa_s, 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 int wpas_rrm_report_elem(struct wpabuf **buf, u8 token, u8 mode, u8 type,
+				const u8 *data, size_t data_len)
+{
+	if (wpabuf_resize(buf, 5 + data_len))
+		return -1;
+
+	wpabuf_put_u8(*buf, WLAN_EID_MEASURE_REPORT);
+	wpabuf_put_u8(*buf, 3 + data_len);
+	wpabuf_put_u8(*buf, token);
+	wpabuf_put_u8(*buf, mode);
+	wpabuf_put_u8(*buf, type);
+
+	if (data_len)
+		wpabuf_put_data(*buf, data, data_len);
+
+	return 0;
+}
+
+static void wpas_rrm_send_msr_report_mpdu(struct wpa_supplicant *wpa_s,
+					  const u8 *data, size_t len)
+{
+	struct wpabuf *report = wpabuf_alloc(len + 3);
+
+	if (!report)
+		return;
+
+	wpabuf_put_u8(report, WLAN_ACTION_RADIO_MEASUREMENT);
+	wpabuf_put_u8(report, WLAN_RRM_RADIO_MEASUREMENT_REPORT);
+	wpabuf_put_u8(report, wpa_s->rrm.token);
+
+	wpabuf_put_data(report, data, len);
+
+	if (wpa_drv_send_action(wpa_s, 0, 0,
+				wpabuf_head(report), wpabuf_len(report), 0)) {
+		wpa_printf(MSG_ERROR,
+			   "RRM: Radio measurement report failed: Sending Action frame failed");
+	}
+
+	wpabuf_free(report);
+}
+
+
+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;
+	struct rrm_measurement_beacon_report *rep = NULL;
+	u8 *subelem;
+
+	/* Find the last beacon report element */
+	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)
+			rep = (struct rrm_measurement_beacon_report *)
+				msr_rep->variable;
+
+		pos += pos[1] + 2;
+	}
+
+	if (!rep)
+		return 0;
+
+	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;
+
+	return 0;
+}
+
+
+static void wpas_rrm_send_msr_report(struct wpa_supplicant *wpa_s,
+				     struct wpabuf *buf)
+{
+	int len = wpabuf_len(buf);
+	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);
+			len -= send_len;
+			pos = next;
+		}
+
+		if (len)
+			next += next[1] + 2;
+	}
+#undef MPDU_REPORT_LEN
+}
+
+static int wpas_get_op_chan_phy(int channel, const u8 *ies, size_t ies_len,
+				u8 *op_class, u8 *chan, u8 *phy_type)
+{
+	const u8 *ie;
+	int sec_chan = 0;
+	struct ieee80211_ht_operation *ht_oper = NULL;
+
+	ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
+	if (ie && ie[1] >= 2) {
+		ht_oper = (struct ieee80211_ht_operation *) (ie + 2);
+
+		if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+			sec_chan = 1;
+		else if (ht_oper->ht_param &
+			 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+			sec_chan = -1;
+	}
+
+	*op_class = get_operating_class(channel, sec_chan);
+
+	*phy_type = (sec_chan != 0) ? PHY_TYPE_HT : PHY_TYPE_ERP;
+
+	return 0;
+}
+
+
+static int wpas_beacon_rep_add_frame_body(struct bitfield *eids,
+					  enum beacon_report_detail detail,
+					  struct wpa_bss *bss, u8 *buf,
+					  size_t buf_len, u8 **ies_buf,
+					  size_t *ie_len, int add_fixed)
+{
+	u8 *ies = *ies_buf;
+	size_t ies_len = *ie_len;
+	u8 *pos = buf;
+	int rem_len;
+
+	rem_len = 255 - sizeof(struct rrm_measurement_beacon_report) -
+		sizeof(struct rrm_measurement_report_element) - 2 -
+		REPORTED_FRAME_BODY_SUBELEM_LEN;
+
+	if (detail > BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) {
+		wpa_printf(MSG_DEBUG,
+			   "Beacon Request: Invalid reporting detail: %d",
+			   detail);
+		return -1;
+	}
+
+	if (detail == BEACON_REPORT_DETAIL_NONE)
+		return 0;
+
+	/*
+	 * Minimal frame body subelement size: EID(1) + length(1) + TSF(8) +
+	 * beacon interval(2) + capabilities(2) = 14 bytes
+	 */
+	if (add_fixed && buf_len < 14)
+		return -1;
+
+	*pos++ = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY;
+	/* The length will be filled later */
+	pos++;
+
+	if (add_fixed) {
+		WPA_PUT_LE64(pos, bss->tsf);
+		pos += sizeof(bss->tsf);
+		WPA_PUT_LE16(pos, bss->beacon_int);
+		pos += 2;
+		WPA_PUT_LE16(pos, bss->caps);
+		pos += 2;
+	}
+
+	rem_len -= pos - buf;
+
+	/*
+	 * According to IEEE Std 802.11-2016, 9.4.2.22.7, if the reported frame
+	 * body subelement causes the element to exceed the maximum element
+	 * size, the subelement is truncated so that the last IE is a complete
+	 * IE. So even when required to report all IEs, add elements one after
+	 * the other and stop once there is no more room in the measurement
+	 * element.
+	 */
+	while (ies_len > 2 && 2U + ies[1] <= ies_len && rem_len > 0) {
+		if (detail == BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS ||
+		    (eids && bitfield_is_set(eids, ies[0]))) {
+			u8 elen = ies[1];
+
+			if (2 + elen > buf + buf_len - pos ||
+			    2 + elen > rem_len)
+				break;
+
+			*pos++ = ies[0];
+			*pos++ = elen;
+			os_memcpy(pos, ies + 2, elen);
+			pos += elen;
+			rem_len -= 2 + elen;
+		}
+
+		ies_len -= 2 + ies[1];
+		ies += 2 + ies[1];
+	}
+
+	*ie_len = ies_len;
+	*ies_buf = ies;
+
+	/* Now the length is known */
+	buf[1] = pos - buf - 2;
+	return pos - buf;
+}
+
+
+static int wpas_add_beacon_rep_elem(struct beacon_rep_data *data,
+				    struct wpa_bss *bss,
+				    struct wpabuf **wpa_buf,
+				    struct rrm_measurement_beacon_report *rep,
+				    u8 **ie, size_t *ie_len, u8 idx)
+{
+	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 + subelems_len);
+	if (!buf)
+		return -1;
+
+	os_memcpy(buf, rep, sizeof(*rep));
+
+	ret = wpas_beacon_rep_add_frame_body(data->eids, data->report_detail,
+					     bss, buf + sizeof(*rep),
+					     14 + *ie_len, ie, ie_len,
+					     idx == 0);
+	if (ret < 0)
+		goto out;
+
+	pos = buf + ret + sizeof(*rep);
+	pos[0] = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY_FRAGMENT_ID;
+	pos[1] = 2;
+
+	/*
+	 * Only one Beacon Report Measurement is supported at a time, so
+	 * the Beacon Report ID can always be set to 1.
+	 */
+	pos[2] = 1;
+
+	/* Fragment ID Number (bits 0..6) and More Frame Body Fragments (bit 7)
+ */
+	pos[3] = idx;
+	if (data->report_detail != BEACON_REPORT_DETAIL_NONE && *ie_len)
+		pos[3] |= REPORTED_FRAME_BODY_MORE_FRAGMENTS;
+	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) + subelems_len);
+out:
+	os_free(buf);
+	return ret;
+}
+
+
+static int wpas_add_beacon_rep(struct wpa_supplicant *wpa_s,
+			       struct wpabuf **wpa_buf, struct wpa_bss *bss,
+			       u64 start, u64 parent_tsf)
+{
+	struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
+	u8 *ies = (u8 *) (bss + 1);
+	u8 *pos = ies;
+	size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+	struct rrm_measurement_beacon_report rep;
+	u8 idx = 0;
+
+	if (os_memcmp(data->bssid, broadcast_ether_addr, ETH_ALEN) != 0 &&
+	    os_memcmp(data->bssid, bss->bssid, ETH_ALEN) != 0)
+		return 0;
+
+	if (data->ssid_len &&
+	    (data->ssid_len != bss->ssid_len ||
+	     os_memcmp(data->ssid, bss->ssid, bss->ssid_len) != 0))
+		return 0;
+
+	if (wpas_get_op_chan_phy(bss->channel, ies, ies_len, &rep.op_class,
+				 &rep.channel, &rep.report_info) < 0)
+		return 0;
+
+	rep.channel = bss->channel;
+	rep.start_time = host_to_le64(start);
+	rep.duration = host_to_le16(data->scan_params.duration);
+	rep.rcpi = rssi_to_rcpi(bss->level);
+	rep.rsni = 255; /* 255 indicates that RSNI is not available */
+	os_memcpy(rep.bssid, bss->bssid, ETH_ALEN);
+	rep.antenna_id = 0; /* unknown */
+	rep.parent_tsf = host_to_le32(parent_tsf);
+
+	do {
+		int ret;
+
+		ret = wpas_add_beacon_rep_elem(data, bss, wpa_buf, &rep,
+					       &pos, &ies_len, idx++);
+		if (ret)
+			return ret;
+	} while (data->report_detail != BEACON_REPORT_DETAIL_NONE &&
+		 ies_len >= 2);
+
+	return 0;
+}
+
+
+static int wpas_beacon_rep_no_results(struct wpa_supplicant *wpa_s,
+				      struct wpabuf **buf)
+{
+	return wpas_rrm_report_elem(buf, wpa_s->beacon_rep_data.token,
+				    MEASUREMENT_REPORT_MODE_ACCEPT,
+				    MEASURE_TYPE_BEACON, NULL, 0);
+}
+
+
+static void wpas_beacon_rep_table(struct wpa_supplicant *wpa_s,
+				  struct wpabuf **buf)
+{
+	size_t i;
+
+	for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+		if (wpas_add_beacon_rep(wpa_s, buf, wpa_s->last_scan_res[i],
+					0, 0) < 0)
+			break;
+	}
+
+	if (!(*buf))
+		wpas_beacon_rep_no_results(wpa_s, buf);
+
+	wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", *buf);
+}
+
+
+static void wpas_rrm_refuse_request(struct wpa_supplicant *wpa_s)
+{
+	if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr)) {
+		struct wpabuf *buf = NULL;
+
+		if (wpas_rrm_report_elem(&buf, wpa_s->beacon_rep_data.token,
+					 MEASUREMENT_REPORT_MODE_REJECT_REFUSED,
+					 MEASURE_TYPE_BEACON, NULL, 0)) {
+			wpa_printf(MSG_ERROR, "RRM: Memory allocation failed");
+			wpabuf_free(buf);
+			return;
+		}
+
+		wpas_rrm_send_msr_report(wpa_s, buf);
+		wpabuf_free(buf);
+	}
+
+	wpas_clear_beacon_rep_data(wpa_s);
+}
+
+
+static void wpas_rrm_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct wpa_driver_scan_params *params =
+		&wpa_s->beacon_rep_data.scan_params;
+	u16 prev_duration = params->duration;
+
+	if (!wpa_s->current_bss)
+		return;
+
+	os_get_reltime(&wpa_s->beacon_rep_scan);
+	wpa_s->scan_reason = REASON_RRM_BEACON_REPORT;
+	if (wpa_supplicant_trigger_scan(wpa_s, params) < 0)
+		wpas_rrm_refuse_request(wpa_s);
+	params->duration = prev_duration;
+}
+
+
+static int wpas_rm_handle_beacon_req_subelem(struct wpa_supplicant *wpa_s,
+					     struct beacon_rep_data *data,
+					     u8 sid, u8 slen, const u8 *subelem)
+{
+	u8 report_info, i;
+
+	switch (sid) {
+	case WLAN_BEACON_REQUEST_SUBELEM_SSID:
+		if (!slen) {
+			wpa_printf(MSG_DEBUG,
+				   "SSID subelement with zero length - wildcard SSID");
+			break;
+		}
+
+		if (slen > SSID_MAX_LEN) {
+			wpa_printf(MSG_DEBUG,
+				   "Invalid SSID subelement length: %u", slen);
+			return -1;
+		}
+
+		data->ssid_len = slen;
+		os_memcpy(data->ssid, subelem, data->ssid_len);
+		break;
+	case WLAN_BEACON_REQUEST_SUBELEM_INFO:
+		if (slen != 2) {
+			wpa_printf(MSG_DEBUG,
+				   "Invalid reporting information subelement length: %u",
+				   slen);
+			return -1;
+		}
+
+		report_info = subelem[0];
+		if (report_info != 0) {
+			wpa_printf(MSG_DEBUG,
+				   "reporting information=%u is not supported",
+				   report_info);
+			return 0;
+		}
+		break;
+	case WLAN_BEACON_REQUEST_SUBELEM_DETAIL:
+		if (slen != 1) {
+			wpa_printf(MSG_DEBUG,
+				   "Invalid reporting detail subelement length: %u",
+				   slen);
+			return -1;
+		}
+
+		data->report_detail = subelem[0];
+		if (data->report_detail >
+		    BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) {
+			wpa_printf(MSG_DEBUG, "Invalid reporting detail: %u",
+				   subelem[0]);
+			return -1;
+		}
+
+		break;
+	case WLAN_BEACON_REQUEST_SUBELEM_REQUEST:
+		if (data->report_detail !=
+		    BEACON_REPORT_DETAIL_REQUESTED_ONLY) {
+			wpa_printf(MSG_DEBUG,
+				   "Beacon request: request subelement is present but report detail is %u",
+				   data->report_detail);
+			return -1;
+		}
+
+		if (!slen) {
+			wpa_printf(MSG_DEBUG,
+				   "Invalid request subelement length: %u",
+				   slen);
+			return -1;
+		}
+
+		if (data->eids) {
+			wpa_printf(MSG_DEBUG,
+				   "Beacon Request: Request subelement appears more than once");
+			return -1;
+		}
+
+		data->eids = bitfield_alloc(255);
+		if (!data->eids) {
+			wpa_printf(MSG_DEBUG, "Failed to allocate EIDs bitmap");
+			return -1;
+		}
+
+		for (i = 0; i < slen; i++)
+			bitfield_set(data->eids, subelem[i]);
+		break;
+	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);
+		break;
+	}
+
+	return 1;
+}
+
+
+/**
+ * Returns 0 if the next element can be processed, 1 if some operation was
+ * triggered, and -1 if processing failed (i.e., the element is in invalid
+ * format or an internal error occurred).
+ */
+static int
+wpas_rm_handle_beacon_req(struct wpa_supplicant *wpa_s,
+			  u8 elem_token, int duration_mandatory,
+			  const struct rrm_measurement_beacon_request *req,
+			  size_t len, struct wpabuf **buf)
+{
+	struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
+	struct wpa_driver_scan_params *params = &data->scan_params;
+	const u8 *subelems;
+	size_t elems_len;
+	u16 rand_interval;
+	u32 interval_usec;
+	u32 _rand;
+	int ret = 0, res;
+	u8 reject_mode;
+
+	if (len < sizeof(*req))
+		return -1;
+
+	if (req->mode != BEACON_REPORT_MODE_PASSIVE &&
+	    req->mode != BEACON_REPORT_MODE_ACTIVE &&
+	    req->mode != BEACON_REPORT_MODE_TABLE)
+		return 0;
+
+	subelems = req->variable;
+	elems_len = len - sizeof(*req);
+	rand_interval = le_to_host16(req->rand_interval);
+
+	os_memset(data, 0, sizeof(*data));
+
+	data->token = elem_token;
+
+	/* default reporting detail is all fixed length fields and all
+	 * elements */
+	data->report_detail = BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS;
+	os_memcpy(data->bssid, req->bssid, ETH_ALEN);
+
+	while (elems_len >= 2) {
+		if (subelems[1] > elems_len - 2) {
+			wpa_printf(MSG_DEBUG,
+				   "Beacon Request: Truncated subelement");
+			ret = -1;
+			goto out;
+		}
+
+		res = wpas_rm_handle_beacon_req_subelem(
+			wpa_s, data, subelems[0], subelems[1], &subelems[2]);
+		if (res < 0) {
+			ret = res;
+			goto out;
+		} else if (!res) {
+			reject_mode = MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE;
+			goto out_reject;
+		}
+
+		elems_len -= 2 + subelems[1];
+		subelems += 2 + subelems[1];
+	}
+
+	if (req->mode == BEACON_REPORT_MODE_TABLE) {
+		wpas_beacon_rep_table(wpa_s, buf);
+		goto out;
+	}
+	params->channel = req->channel;
+	params->duration = le_to_host16(req->duration);
+	params->duration_mandatory = duration_mandatory;
+	if (!params->duration) {
+		wpa_printf(MSG_DEBUG, "Beacon request: Duration is 0");
+		ret = -1;
+		goto out;
+	}
+
+	if (data->ssid_len) {
+		params->ssids[params->num_ssids].ssid = data->ssid;
+		params->ssids[params->num_ssids++].ssid_len = data->ssid_len;
+	}
+
+	if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
+		_rand = os_random();
+	interval_usec = (_rand % (rand_interval + 1)) * 1024;
+	os_sleep(0, interval_usec);
+	wpas_rrm_scan_timeout(wpa_s, NULL);
+	return 1;
+out_reject:
+	if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) &&
+	    wpas_rrm_report_elem(buf, elem_token, reject_mode,
+				 MEASURE_TYPE_BEACON, NULL, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
+		ret = -1;
+	}
+out:
+	wpas_clear_beacon_rep_data(wpa_s);
+	return ret;
+}
+
+
+static int
+wpas_rrm_handle_msr_req_element(
+	struct wpa_supplicant *wpa_s,
+	const struct rrm_measurement_request_element *req,
+	struct wpabuf **buf)
+{
+	int duration_mandatory;
+
+	wpa_printf(MSG_DEBUG, "Measurement request type %d token %d",
+		   req->type, req->token);
+
+	if (req->mode & MEASUREMENT_REQUEST_MODE_ENABLE) {
+		/* Enable bit is not supported for now */
+		wpa_printf(MSG_DEBUG, "RRM: Enable bit not supported, ignore");
+		return 0;
+	}
+
+	if ((req->mode & MEASUREMENT_REQUEST_MODE_PARALLEL) &&
+	    req->type > MEASURE_TYPE_RPI_HIST) {
+		/* Parallel measurements are not supported for now */
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Parallel measurements are not supported, reject");
+		goto reject;
+	}
+
+	duration_mandatory =
+		!!(req->mode & MEASUREMENT_REQUEST_MODE_DURATION_MANDATORY);
+
+	switch (req->type) {
+	case MEASURE_TYPE_BEACON:
+		return wpas_rm_handle_beacon_req(wpa_s, req->token,
+						 duration_mandatory,
+						 (const void *) req->variable,
+						 req->len - 3, buf);
+	default:
+		wpa_printf(MSG_INFO,
+			   "RRM: Unsupported radio measurement type %u",
+			   req->type);
+		break;
+	}
+
+reject:
+	if (!is_multicast_ether_addr(wpa_s->rrm.dst_addr) &&
+	    wpas_rrm_report_elem(buf, req->token,
+				 MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE,
+				 req->type, NULL, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf *
+wpas_rrm_process_msr_req_elems(struct wpa_supplicant *wpa_s, const u8 *pos,
+			       size_t len)
+{
+	struct wpabuf *buf = NULL;
+
+	while (len) {
+		const struct rrm_measurement_request_element *req;
+		int res;
+
+		if (len < 2) {
+			wpa_printf(MSG_DEBUG, "RRM: Truncated element");
+			goto out;
+		}
+
+		req = (const struct rrm_measurement_request_element *) pos;
+		if (req->eid != WLAN_EID_MEASURE_REQUEST) {
+			wpa_printf(MSG_DEBUG,
+				   "RRM: Expected Measurement Request element, but EID is %u",
+				   req->eid);
+			printf("len is %d", len);
+			goto out;
+		}
+
+		if (req->len < 3) {
+			wpa_printf(MSG_DEBUG, "RRM: Element length too short");
+			goto out;
+		}
+
+		if (req->len > len - 2) {
+			wpa_printf(MSG_DEBUG, "RRM: Element length too long");
+			goto out;
+		}
+
+		res = wpas_rrm_handle_msr_req_element(wpa_s, req, &buf);
+		if (res < 0)
+			goto out;
+
+		pos += req->len + 2;
+		len -= req->len + 2;
+	}
+
+	return buf;
+
+out:
+	wpabuf_free(buf);
+	return NULL;
+}
+
+
+void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
+					       const u8 *src, const u8 *dst,
+					       const u8 *frame, size_t len)
+{
+	struct wpabuf *report;
+
+	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;
+	}
+
+	wpa_s->rrm.token = *frame;
+	os_memcpy(wpa_s->rrm.dst_addr, dst, ETH_ALEN);
+
+	/* Number of repetitions is not supported */
+
+	report = wpas_rrm_process_msr_req_elems(wpa_s, frame + 3, len - 3);
+	if (!report)
+		return;
+
+	wpas_rrm_send_msr_report(wpa_s, report);
+	wpabuf_free(report);
+}
+
+
+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;
+
+	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.dialog_token = req->dialog_token;
+	report.tpc.eid = WLAN_EID_TPC_REPORT;
+	report.tpc.len = 2;
+	/* Note: The driver is expected to update report.tpc.tx_power and
+	 * report.tpc.link_margin subfields when sending out this frame.
+	 * Similarly, the driver would need to update report.rx_ant_id and
+	 * report.tx_ant_id subfields. */
+
+#ifdef ESPRESSIF_USE
+	esp_get_tx_power(&report.tpc.tx_power);
+	/* Minimum RSSI = -96 dbm */
+	report.tpc.link_margin = rssi + 96;
+#endif
+	report.rsni = 255; /* 255 indicates that RSNI is not available */
+	report.rcpi = rssi_to_rcpi(rssi);
+
+	/* 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_buf(MSG_DEBUG, "RRM: Link measurement report", buf);
+
+	if (wpa_drv_send_action(wpa_s, 0, 0,
+				wpabuf_head(buf), wpabuf_len(buf), 0)) {
+		wpa_printf(MSG_ERROR,
+			   "RRM: Link measurement report failed. Send action failed");
+	}
+	wpabuf_free(buf);
+}
+
+
+int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s,
+				 u64 scan_start_tsf)
+{
+	size_t i = 0;
+	struct wpabuf *buf = NULL;
+	struct wpa_bss *bss = NULL;
+
+	if (!wpa_s->beacon_rep_data.token)
+		return 0;
+
+	if (!wpa_s->current_bss)
+		goto out;
+
+	wpa_printf(MSG_DEBUG, "RRM: TSF  current BSS: " MACSTR,
+		   MAC2STR(wpa_s->current_bss->bssid));
+
+	for (i = 0; i < wpa_s->num_bss; i++) {
+		bss = wpa_bss_get_next_bss(wpa_s, bss);
+
+		if (!bss)
+			continue;
+
+		if (wpa_s->beacon_rep_data.scan_params.channel &&
+				bss->channel != wpa_s->beacon_rep_data.scan_params.channel)
+			continue;
+		/* We flush scan results before issuing scan again */
+#ifndef ESPRESSIF_USE
+		/*
+		 * Don't report results that were not received during the
+		 * current measurement.
+		 */
+		if (scan_start_tsf <
+			   scan_res->res[i]->parent_tsf) {
+			struct os_reltime update_time, diff;
+
+			/* For now, allow 7 ms older results due to some
+			 * unknown issue with cfg80211 BSS table updates during
+			 * a scan with the current BSS.
+			 * TODO: Fix this more properly to avoid having to have
+			 * this type of hacks in place. */
+			calculate_update_time(&scan_res->fetch_time,
+					      scan_res->res[i]->age,
+					      &update_time);
+			os_reltime_sub(&wpa_s->beacon_rep_scan,
+				       &update_time, &diff);
+			if (os_reltime_before(&update_time,
+					      &wpa_s->beacon_rep_scan) &&
+			    (diff.sec || diff.usec >= 8000)) {
+				wpa_printf(MSG_ERROR,
+					   "RRM: Ignore scan result for " MACSTR
+					   " due to old update (age(ms) %u, calculated age %u.%06u seconds)",
+					   MAC2STR(scan_res->res[i]->bssid),
+					   scan_res->res[i]->age,
+					   (unsigned int) diff.sec,
+					   (unsigned int) diff.usec);
+				continue;
+			}
+		} else {
+			continue;
+		}
+#endif
+		if (wpas_add_beacon_rep(wpa_s, &buf, bss, scan_start_tsf,
+					bss->parent_tsf) < 0)
+			break;
+	}
+
+	if (!buf && wpas_beacon_rep_no_results(wpa_s, &buf))
+		goto out;
+
+	wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", buf);
+
+	wpas_rrm_send_msr_report(wpa_s, buf);
+	wpabuf_free(buf);
+
+out:
+	wpas_clear_beacon_rep_data(wpa_s);
+	return 1;
+}
+
+
+void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s)
+{
+	struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
+
+	eloop_cancel_timeout(wpas_rrm_scan_timeout, wpa_s, NULL);
+	bitfield_free(data->eids);
+	os_memset(data, 0, sizeof(*data));
+}
diff --git a/components/wpa_supplicant/src/common/rrm.h b/components/wpa_supplicant/src/common/rrm.h
new file mode 100755
index 00000000..a981d7c0
--- /dev/null
+++ b/components/wpa_supplicant/src/common/rrm.h
@@ -0,0 +1,30 @@
+
+#ifndef RRM_H
+#define RRM_H
+
+#include "common/defs.h"
+#include "utils/list.h"
+#include "esp_wifi_types.h"
+#define RRM_NEIGHBOR_REPORT_TIMEOUT 1 /* 1 second for AP to send a report */
+
+void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
+void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
+				   const u8 *report, size_t report_len);
+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,
+						  const u8 *neighbor_rep, size_t len),
+				       void *cb_ctx);
+void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
+					       const u8 *src, const u8 *dst,
+					       const u8 *frame, size_t len);
+void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
+					      const u8 *src,
+					      const u8 *frame, size_t len,
+					      int rssi);
+int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s,
+				 u64 scan_start_tsf);
+void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s);
+
+#endif
diff --git a/components/wpa_supplicant/src/common/scan.c b/components/wpa_supplicant/src/common/scan.c
new file mode 100755
index 00000000..3e417494
--- /dev/null
+++ b/components/wpa_supplicant/src/common/scan.c
@@ -0,0 +1,95 @@
+/*
+ * WPA Supplicant - Scanning
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "drivers/driver.h"
+#include "common/ieee802_11_common.h"
+#include "bss.h"
+#include "scan.h"
+
+/**
+ * wpa_supplicant_req_scan - Schedule a scan for neighboring access points
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @sec: Number of seconds after which to scan
+ * @usec: Number of microseconds after which to scan
+ *
+ * This function is used to schedule a scan for neighboring access points after
+ * the specified time.
+ */
+void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
+{
+	int ret;
+	struct wpa_driver_scan_params *params;
+
+	os_sleep(sec, usec);
+
+	if (wpa_s->scanning) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Already scanning - Return");
+		return;
+	}
+	params = os_zalloc(sizeof(*params));
+
+	if (wpa_s->wnm_mode) {
+		/* Use the same memory */
+		params->ssids[0].ssid = wpa_s->current_bss->ssid;
+		params->ssids[0].ssid_len = wpa_s->current_bss->ssid_len;
+		params->num_ssids = 1;
+	}
+	if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
+		/* Use the same memory */
+		params->bssid = wpa_s->next_scan_bssid;
+	}
+
+	if (wpa_s->next_scan_chan)
+		params->channel = wpa_s->next_scan_chan;
+
+	wpa_s->scan_reason = REASON_WNM_BSS_TRANS_REQ;
+	ret = wpa_supplicant_trigger_scan(wpa_s, params);
+
+	os_free(params);
+
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "Failed to issue scan - Return");
+		return;
+	}
+}
+
+/**
+ * wpa_scan_get_ie - Fetch a specified information element from a scan result
+ * @res: Scan result entry
+ * @ie: Information element identitifier (WLAN_EID_*)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the scan
+ * result.
+ */
+const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
+{
+	size_t ie_len = res->ie_len;
+
+	/* Use the Beacon frame IEs if res->ie_len is not available */
+	if (!ie_len)
+		ie_len = res->beacon_ie_len;
+
+	return get_ie((const u8 *) (res + 1), ie_len, ie);
+}
+
+void wpa_scan_free_params(struct wpa_driver_scan_params *params)
+{
+	if (params == NULL)
+		return;
+
+	os_free((u8 *) params->bssid);
+
+	os_free(params);
+}
diff --git a/components/wpa_supplicant/src/common/scan.h b/components/wpa_supplicant/src/common/scan.h
new file mode 100755
index 00000000..c5f9e254
--- /dev/null
+++ b/components/wpa_supplicant/src/common/scan.h
@@ -0,0 +1,25 @@
+/*
+ * WPA Supplicant - Scanning
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SCAN_H
+#define SCAN_H
+
+/*
+ * Noise floor values to use when we have signal strength
+ * measurements, but no noise floor measurements. These values were
+ * measured in an office environment with many APs.
+ */
+#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
+
+struct wpa_driver_scan_params;
+void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
+int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
+				struct wpa_driver_scan_params *params);
+const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie);
+void wpa_scan_free_params(struct wpa_driver_scan_params *params);
+#endif /* SCAN_H */
diff --git a/components/wpa_supplicant/src/common/wnm_sta.c b/components/wpa_supplicant/src/common/wnm_sta.c
new file mode 100755
index 00000000..f238c206
--- /dev/null
+++ b/components/wpa_supplicant/src/common/wnm_sta.c
@@ -0,0 +1,966 @@
+/*
+ * wpa_supplicant - WNM
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "rsn_supp/wpa.h"
+#include "wpa_supplicant_i.h"
+#include "drivers/driver.h"
+#include "scan.h"
+#include "bss.h"
+#include "wnm_sta.h"
+
+#define MAX_TFS_IE_LEN  1024
+#define WNM_MAX_NEIGHBOR_REPORT 10
+
+#define WNM_SCAN_RESULT_AGE 2 /* 2 seconds */
+
+void wnm_deallocate_memory(struct wpa_supplicant *wpa_s)
+{
+	int i;
+
+	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+		os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot);
+		os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid);
+	}
+
+	wpa_s->wnm_num_neighbor_report = 0;
+	os_free(wpa_s->wnm_neighbor_report_elements);
+	wpa_s->wnm_neighbor_report_elements = NULL;
+}
+
+
+static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep,
+					   u8 id, u8 elen, const u8 *pos)
+{
+	switch (id) {
+	case WNM_NEIGHBOR_TSF:
+		if (elen < 2 + 2) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short TSF");
+			break;
+		}
+		rep->tsf_offset = WPA_GET_LE16(pos);
+		rep->beacon_int = WPA_GET_LE16(pos + 2);
+		rep->tsf_present = 1;
+		break;
+	case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING:
+		if (elen < 2) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short condensed "
+				   "country string");
+			break;
+		}
+		os_memcpy(rep->country, pos, 2);
+		rep->country_present = 1;
+		break;
+	case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
+		if (elen < 1) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition "
+				   "candidate");
+			break;
+		}
+		rep->preference = pos[0];
+		rep->preference_present = 1;
+		break;
+	case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
+		if (elen < 10) {
+			wpa_printf(MSG_DEBUG,
+				   "WNM: Too short BSS termination duration");
+			break;
+		}
+		rep->bss_term_tsf = WPA_GET_LE64(pos);
+		rep->bss_term_dur = WPA_GET_LE16(pos + 8);
+		rep->bss_term_present = 1;
+		break;
+	case WNM_NEIGHBOR_BEARING:
+		if (elen < 8) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short neighbor "
+				   "bearing");
+			break;
+		}
+		rep->bearing = WPA_GET_LE16(pos);
+		rep->distance = WPA_GET_LE32(pos + 2);
+		rep->rel_height = WPA_GET_LE16(pos + 2 + 4);
+		rep->bearing_present = 1;
+		break;
+	case WNM_NEIGHBOR_MEASUREMENT_PILOT:
+		if (elen < 1) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short measurement "
+				   "pilot");
+			break;
+		}
+		os_free(rep->meas_pilot);
+		rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot));
+		if (rep->meas_pilot == NULL)
+			break;
+		rep->meas_pilot->measurement_pilot = pos[0];
+		rep->meas_pilot->subelem_len = elen - 1;
+		os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1);
+		break;
+	case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES:
+		if (elen < 5) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled "
+				   "capabilities");
+			break;
+		}
+		os_memcpy(rep->rm_capab, pos, 5);
+		rep->rm_capab_present = 1;
+		break;
+	case WNM_NEIGHBOR_MULTIPLE_BSSID:
+		if (elen < 1) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID");
+			break;
+		}
+		os_free(rep->mul_bssid);
+		rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid));
+		if (rep->mul_bssid == NULL)
+			break;
+		rep->mul_bssid->max_bssid_indicator = pos[0];
+		rep->mul_bssid->subelem_len = elen - 1;
+		os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1);
+		break;
+	}
+}
+
+static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
+				      const u8 *pos, u8 len,
+				      struct neighbor_report *rep)
+{
+	u8 left = len;
+
+	if (left < 13) {
+		wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report");
+		return;
+	}
+
+	os_memcpy(rep->bssid, pos, ETH_ALEN);
+	rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN);
+	rep->regulatory_class = *(pos + 10);
+	rep->channel_number = *(pos + 11);
+	rep->phy_type = *(pos + 12);
+
+	pos += 13;
+	left -= 13;
+
+	while (left >= 2) {
+		u8 id, elen;
+
+		id = *pos++;
+		elen = *pos++;
+		wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen);
+		left -= 2;
+		if (elen > left) {
+			wpa_printf(MSG_DEBUG,
+				   "WNM: Truncated neighbor report subelement");
+			break;
+		}
+		wnm_parse_neighbor_report_elem(rep, id, elen, pos);
+		left -= elen;
+		pos += elen;
+	}
+}
+
+
+static void wnm_clear_acceptable(struct wpa_supplicant *wpa_s)
+{
+	unsigned int i;
+
+	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++)
+		wpa_s->wnm_neighbor_report_elements[i].acceptable = 0;
+}
+
+
+static struct wpa_bss * get_first_acceptable(struct wpa_supplicant *wpa_s)
+{
+	unsigned int i;
+	struct neighbor_report *nei;
+
+	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+		nei = &wpa_s->wnm_neighbor_report_elements[i];
+		if (nei->acceptable)
+			return wpa_bss_get_bssid(wpa_s, nei->bssid);
+	}
+
+	return NULL;
+}
+
+/* basic function to match candidate profile with current bss */
+bool wpa_scan_res_match(struct wpa_supplicant *wpa_s,
+			struct wpa_bss *current_bss,
+			struct wpa_bss *target_bss)
+{
+	if (current_bss->ssid_len != target_bss->ssid_len) {
+		wpa_printf(MSG_DEBUG, "WNM: ssid didn't match");
+		return false;
+	}
+	if (os_memcmp(current_bss->ssid, target_bss->ssid, current_bss->ssid_len) != 0) {
+		wpa_printf(MSG_DEBUG, "WNM: ssid didn't match");
+		return false;
+	}
+
+	/* TODO security Match */
+
+	return true;
+}
+
+
+static struct wpa_bss *
+compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs,
+			      enum mbo_transition_reject_reason *reason)
+{
+	u8 i;
+	struct wpa_bss *bss = wpa_s->current_bss;
+	struct wpa_bss *target;
+
+	if (!bss)
+		return NULL;
+
+	wnm_clear_acceptable(wpa_s);
+
+	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+		struct neighbor_report *nei;
+
+		nei = &wpa_s->wnm_neighbor_report_elements[i];
+		if (nei->preference_present && nei->preference == 0) {
+			wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR,
+				   MAC2STR(nei->bssid));
+			continue;
+		}
+
+		target = wpa_bss_get_bssid(wpa_s, nei->bssid);
+		if (!target) {
+			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+				   " (pref %d) not found in scan results",
+				   MAC2STR(nei->bssid),
+				   nei->preference_present ? nei->preference :
+				   -1);
+			continue;
+		}
+
+		if (age_secs) {
+			struct os_reltime now;
+
+			if (os_get_reltime(&now) == 0 &&
+			    os_time_expired(&now, &target->last_update,
+					       age_secs)) {
+				wpa_printf(MSG_DEBUG,
+					   "Candidate BSS is more than %ld seconds old",
+					   age_secs);
+				continue;
+			}
+		}
+
+		if (bss->ssid_len != target->ssid_len ||
+		    os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) {
+			/*
+			 * TODO: Could consider allowing transition to another
+			 * ESS if PMF was enabled for the association.
+			 */
+			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+				   " (pref %d) in different ESS",
+				   MAC2STR(nei->bssid),
+				   nei->preference_present ? nei->preference :
+				   -1);
+			continue;
+		}
+
+		if (wpa_s->current_bss &&
+		    !wpa_scan_res_match(wpa_s, wpa_s->current_bss, target)) {
+			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+				   " (pref %d) does not match the current network profile",
+				   MAC2STR(nei->bssid),
+				   nei->preference_present ? nei->preference :
+				   -1);
+			continue;
+		}
+
+		if (target->level < bss->level && target->level < -80) {
+			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+				   " (pref %d) does not have sufficient signal level (%d)",
+				   MAC2STR(nei->bssid),
+				   nei->preference_present ? nei->preference :
+				   -1,
+				   target->level);
+			continue;
+		}
+
+		nei->acceptable = 1;
+	}
+
+	target = get_first_acceptable(wpa_s);
+
+	if (target) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Found an acceptable preferred transition candidate BSS "
+			   MACSTR " (RSSI %d)",
+			   MAC2STR(target->bssid), target->level);
+	}
+
+	return target;
+}
+
+
+static int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid)
+{
+	const u8 *ie_a, *ie_b;
+
+	if (!a || !b)
+		return 0;
+
+	ie_a = wpa_bss_get_ie(a, eid);
+	ie_b = wpa_bss_get_ie(b, eid);
+
+	if (!ie_a || !ie_b || ie_a[1] != ie_b[1])
+		return 0;
+
+	return os_memcmp(ie_a, ie_b, ie_a[1]) == 0;
+}
+
+
+static u32 wnm_get_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	u32 info = 0;
+
+	info |= NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH;
+
+	/*
+	 * Leave the security and key scope bits unset to indicate that the
+	 * security information is not available.
+	 */
+
+	if (bss->caps & WLAN_CAPABILITY_SPECTRUM_MGMT)
+		info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
+	if (bss->caps & WLAN_CAPABILITY_QOS)
+		info |= NEI_REP_BSSID_INFO_QOS;
+	if (bss->caps & WLAN_CAPABILITY_APSD)
+		info |= NEI_REP_BSSID_INFO_APSD;
+	if (bss->caps & WLAN_CAPABILITY_RADIO_MEASUREMENT)
+		info |= NEI_REP_BSSID_INFO_RM;
+	if (bss->caps & WLAN_CAPABILITY_DELAYED_BLOCK_ACK)
+		info |= NEI_REP_BSSID_INFO_DELAYED_BA;
+	if (bss->caps & WLAN_CAPABILITY_IMM_BLOCK_ACK)
+		info |= NEI_REP_BSSID_INFO_IMM_BA;
+	if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_MOBILITY_DOMAIN))
+		info |= NEI_REP_BSSID_INFO_MOBILITY_DOMAIN;
+	if (wpa_bss_ies_eq(bss, wpa_s->current_bss, WLAN_EID_HT_CAP))
+		info |= NEI_REP_BSSID_INFO_HT;
+
+	return info;
+}
+
+
+static int wnm_add_nei_rep(struct wpabuf **buf, const u8 *bssid,
+			   u32 bss_info, u8 op_class, u8 chan, u8 phy_type,
+			   u8 pref)
+{
+	if (wpabuf_len(*buf) + 18 >
+	    IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: No room in frame for Neighbor Report element");
+		return -1;
+	}
+
+	if (wpabuf_resize(buf, 18) < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Failed to allocate memory for Neighbor Report element");
+		return -1;
+	}
+
+	wpabuf_put_u8(*buf, WLAN_EID_NEIGHBOR_REPORT);
+	/* length: 13 for basic neighbor report + 3 for preference subelement */
+	wpabuf_put_u8(*buf, 16);
+	wpabuf_put_data(*buf, bssid, ETH_ALEN);
+	wpabuf_put_le32(*buf, bss_info);
+	wpabuf_put_u8(*buf, op_class);
+	wpabuf_put_u8(*buf, chan);
+	wpabuf_put_u8(*buf, phy_type);
+	wpabuf_put_u8(*buf, WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE);
+	wpabuf_put_u8(*buf, 1);
+	wpabuf_put_u8(*buf, pref);
+	return 0;
+}
+
+static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s,
+			       struct wpa_bss *bss, struct wpabuf **buf,
+			       u8 pref)
+{
+	const u8 *ie;
+	u8 op_class;
+	int sec_chan = 0;
+	enum phy_type phy_type;
+	u32 info;
+	struct ieee80211_ht_operation *ht_oper = NULL;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION);
+	if (ie && ie[1] >= 2) {
+		ht_oper = (struct ieee80211_ht_operation *) (ie + 2);
+
+		if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+			sec_chan = 1;
+		else if (ht_oper->ht_param &
+			 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+			sec_chan = -1;
+	}
+
+	op_class = get_operating_class(bss->channel, sec_chan);
+
+	phy_type = (sec_chan != 0) ? PHY_TYPE_HT : PHY_TYPE_ERP;
+
+	info = wnm_get_bss_info(wpa_s, bss);
+
+	return wnm_add_nei_rep(buf, bss->bssid, info, op_class, bss->channel, phy_type,
+			       pref);
+}
+
+
+static void wnm_add_cand_list(struct wpa_supplicant *wpa_s, struct wpabuf **buf)
+{
+	unsigned int i, pref = 255;
+	struct os_reltime now;
+
+	if (!wpa_s->current_bss)
+		return;
+
+	/*
+	 * TODO: Define when scan results are no longer valid for the candidate
+	 * list.
+	 */
+	os_get_reltime(&now);
+	if (os_time_expired(&now, &wpa_s->last_scan, 10))
+		return;
+
+	wpa_printf(MSG_DEBUG,
+		   "WNM: Add candidate list to BSS Transition Management Response frame");
+	for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) {
+		struct wpa_bss *bss = wpa_s->last_scan_res[i];
+		int res;
+
+		if (wpa_scan_res_match(wpa_s, wpa_s->current_bss, bss)) {
+			res = wnm_nei_rep_add_bss(wpa_s, bss, buf, pref--);
+			if (res == -2)
+				continue; /* could not build entry for BSS */
+			if (res < 0)
+				break; /* no more room for candidates */
+			if (pref == 1)
+				break;
+		}
+	}
+
+	wpa_hexdump_buf(MSG_DEBUG,
+			"WNM: BSS Transition Management Response candidate list",
+			*buf);
+}
+
+
+#define BTM_RESP_MIN_SIZE	5 + ETH_ALEN
+
+static void wnm_send_bss_transition_mgmt_resp(
+	struct wpa_supplicant *wpa_s, u8 dialog_token,
+	enum bss_trans_mgmt_status_code status,
+	enum mbo_transition_reject_reason reason,
+	u8 delay, const u8 *target_bssid)
+{
+	struct wpabuf *buf;
+	int res;
+
+	wpa_printf(MSG_DEBUG,
+		   "WNM: Send BSS Transition Management Response to " MACSTR
+		   " dialog_token=%u status=%u reason=%u delay=%d",
+		   MAC2STR(wpa_s->current_bss->bssid), dialog_token, status, reason, delay);
+	if (!wpa_s->current_bss) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Current BSS not known - drop response");
+		return;
+	}
+
+	buf = wpabuf_alloc(BTM_RESP_MIN_SIZE);
+	if (!buf) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Failed to allocate memory for BTM response");
+		return;
+	}
+
+	wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+	wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_RESP);
+	wpabuf_put_u8(buf, dialog_token);
+	wpabuf_put_u8(buf, status);
+	wpabuf_put_u8(buf, delay);
+	if (target_bssid) {
+		wpabuf_put_data(buf, target_bssid, ETH_ALEN);
+	} else if (status == WNM_BSS_TM_ACCEPT) {
+		/*
+		 * P802.11-REVmc clarifies that the Target BSSID field is always
+		 * present when status code is zero, so use a fake value here if
+		 * no BSSID is yet known.
+		 */
+		wpabuf_put_data(buf, "\0\0\0\0\0\0", ETH_ALEN);
+	}
+
+	if (status == WNM_BSS_TM_ACCEPT)
+		wnm_add_cand_list(wpa_s, &buf);
+
+	res = wpa_drv_send_action(wpa_s, 0, 0,
+				  wpabuf_head_u8(buf), wpabuf_len(buf), 0);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Failed to send BSS Transition Management Response");
+	}
+
+	wpabuf_free(buf);
+}
+
+void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s,
+			struct wpa_bss *bss, char *ssid,
+			int after_new_scan)
+{
+	wpa_printf(MSG_DEBUG,
+		"WNM: Transition to BSS " MACSTR
+		" based on BSS Transition Management Request after_new_scan=%d)",
+		MAC2STR(bss->bssid), after_new_scan);
+
+	/* Send the BSS Management Response - Accept */
+	if (wpa_s->wnm_reply) {
+		wpa_s->wnm_reply = 0;
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Sending successful BSS Transition Management Response");
+		wnm_send_bss_transition_mgmt_resp(
+			wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_ACCEPT,
+			MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
+			bss->bssid);
+	}
+
+	if (bss == wpa_s->current_bss) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Already associated with the preferred candidate");
+		wnm_deallocate_memory(wpa_s);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "WNM: Issuing connect");
+
+	wpa_supplicant_connect(wpa_s, bss, ssid);
+	wnm_deallocate_memory(wpa_s);
+}
+
+
+int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
+{
+	struct wpa_bss *bss;
+	enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED;
+	enum mbo_transition_reject_reason reason =
+		MBO_TRANSITION_REJECT_REASON_UNSPECIFIED;
+
+	if (!wpa_s->wnm_neighbor_report_elements)
+		return 0;
+
+	wpa_dbg(wpa_s, MSG_DEBUG,
+		"WNM: Process scan results for BSS Transition Management");
+	if (os_reltime_before(&wpa_s->wnm_cand_valid_until,
+			      &wpa_s->scan_trigger_time)) {
+		wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it");
+		wnm_deallocate_memory(wpa_s);
+		return 0;
+	}
+
+	/* Compare the Neighbor Report and scan results */
+	bss = compare_scan_neighbor_results(wpa_s, 0, &reason);
+	if (!bss) {
+		wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found");
+		status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES;
+		goto send_bss_resp_fail;
+	}
+
+	/* Associate to the network */
+	wnm_bss_tm_connect(wpa_s, bss, NULL, 1);
+	return 1;
+
+send_bss_resp_fail:
+	if (!reply_on_fail)
+		return 0;
+
+	/* Send reject response for all the failures */
+
+	if (wpa_s->wnm_reply) {
+		wpa_s->wnm_reply = 0;
+		wnm_send_bss_transition_mgmt_resp(wpa_s,
+						  wpa_s->wnm_dialog_token,
+						  status, reason, 0, NULL);
+	}
+	wnm_deallocate_memory(wpa_s);
+
+	return 0;
+}
+
+
+static int cand_pref_compar(const void *a, const void *b)
+{
+	const struct neighbor_report *aa = a;
+	const struct neighbor_report *bb = b;
+
+	if (!aa->preference_present && !bb->preference_present)
+		return 0;
+	if (!aa->preference_present)
+		return 1;
+	if (!bb->preference_present)
+		return -1;
+	if (bb->preference > aa->preference)
+		return 1;
+	if (bb->preference < aa->preference)
+		return -1;
+	return 0;
+}
+
+
+static void wnm_sort_cand_list(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->wnm_neighbor_report_elements)
+		return;
+	qsort(wpa_s->wnm_neighbor_report_elements,
+	      wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report),
+	      cand_pref_compar);
+}
+
+
+static void wnm_dump_cand_list(struct wpa_supplicant *wpa_s)
+{
+#ifdef DEBUG_PRINT
+	unsigned int i;
+
+	wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List");
+	if (!wpa_s->wnm_neighbor_report_elements)
+		return;
+	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+		struct neighbor_report *nei;
+
+		nei = &wpa_s->wnm_neighbor_report_elements[i];
+		wpa_printf(MSG_DEBUG, "%u: " MACSTR
+			   " info=0x%x op_class=%u chan=%u phy=%u pref=%d",
+			   i, MAC2STR(nei->bssid), nei->bssid_info,
+			   nei->regulatory_class,
+			   nei->channel_number, nei->phy_type,
+			   nei->preference_present ? nei->preference : -1);
+	}
+#endif
+}
+
+static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s)
+{
+	unsigned int i;
+	int num_chan;
+	u8 chan = 0;
+
+	wpa_s->next_scan_chan = 0;
+	if (!wpa_s->wnm_neighbor_report_elements)
+		return;
+
+	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+		struct neighbor_report *nei;
+
+		nei = &wpa_s->wnm_neighbor_report_elements[i];
+		if (nei->channel_number <= 0) {
+			wpa_printf(MSG_DEBUG,
+				   "WNM: Unknown neighbor operating channel_number for "
+				   MACSTR " - scan all channels",
+				   MAC2STR(nei->bssid));
+			return;
+		}
+		if (nei->channel_number != chan)
+			num_chan++;
+	}
+
+	if (num_chan == 1) {
+		wpa_s->next_scan_chan = chan;
+	}
+}
+
+static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s)
+{
+	/* ESP doesn't support this */
+	return 0;
+}
+
+static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
+					     const u8 *pos, const u8 *end,
+					     int reply)
+{
+	unsigned int beacon_int;
+	u8 valid_int;
+
+	if (wpa_s->disable_btm)
+		return;
+
+	if (end - pos < 5)
+		return;
+
+#ifdef CONFIG_MBO
+	wpa_s->wnm_mbo_trans_reason_present = 0;
+	wpa_s->wnm_mbo_transition_reason = 0;
+#endif /* CONFIG_MBO */
+
+	if (wpa_s->current_bss)
+		beacon_int = wpa_s->current_bss->beacon_int;
+	else
+		beacon_int = 100; /* best guess */
+
+	wpa_s->wnm_dialog_token = pos[0];
+	wpa_s->wnm_mode = pos[1];
+	wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2);
+	valid_int = pos[4];
+	wpa_s->wnm_reply = reply;
+
+	wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
+		   "dialog_token=%u request_mode=0x%x "
+		   "disassoc_timer=%u validity_interval=%u",
+		   wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
+		   wpa_s->wnm_dissoc_timer, valid_int);
+
+	pos += 5;
+
+	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
+		if (end - pos < 12) {
+			wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
+			return;
+		}
+		os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12);
+		pos += 12; /* BSS Termination Duration */
+	}
+
+	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
+		char url[256];
+
+		if (end - pos < 1 || 1 + pos[0] > end - pos) {
+			wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
+				   "Management Request (URL)");
+			return;
+		}
+		os_memcpy(url, pos + 1, pos[0]);
+		url[pos[0]] = '\0';
+		pos += 1 + pos[0];
+
+		wpa_msg(wpa_s, MSG_DEBUG, "ESS_DISASSOC_IMMINENT %u %s",
+			wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url);
+	}
+
+	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
+		wpa_msg(wpa_s, MSG_DEBUG, "WNM: Disassociation Imminent - "
+			"Disassociation Timer %u", wpa_s->wnm_dissoc_timer);
+		if (wpa_s->wnm_dissoc_timer) {
+			/* TODO: mark current BSS less preferred for
+			 * selection */
+			wpa_printf(MSG_DEBUG, "Trying to find another BSS");
+			wpa_supplicant_req_scan(wpa_s, 0, 0);
+		}
+	}
+
+#ifdef CONFIG_MBO
+	vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC);
+	if (vendor)
+		wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]);
+#endif /* CONFIG_MBO */
+
+	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
+		unsigned int valid_ms;
+
+		wpa_msg(wpa_s, MSG_DEBUG, "WNM: Preferred List Available");
+		wnm_deallocate_memory(wpa_s);
+		wpa_s->wnm_neighbor_report_elements = os_calloc(
+			WNM_MAX_NEIGHBOR_REPORT,
+			sizeof(struct neighbor_report));
+		if (wpa_s->wnm_neighbor_report_elements == NULL)
+			return;
+
+		while (end - pos >= 2 &&
+		       wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT)
+		{
+			u8 tag = *pos++;
+			u8 len = *pos++;
+
+			wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u",
+				   tag);
+			if (len > end - pos) {
+				wpa_printf(MSG_DEBUG, "WNM: Truncated request");
+				return;
+			}
+			if (tag == WLAN_EID_NEIGHBOR_REPORT) {
+				struct neighbor_report *rep;
+				rep = &wpa_s->wnm_neighbor_report_elements[
+					wpa_s->wnm_num_neighbor_report];
+				wnm_parse_neighbor_report(wpa_s, pos, len, rep);
+				wpa_s->wnm_num_neighbor_report++;
+#ifdef CONFIG_MBO
+				if (wpa_s->wnm_mbo_trans_reason_present &&
+				    wpa_s->wnm_num_neighbor_report == 1) {
+					rep->is_first = 1;
+					wpa_printf(MSG_DEBUG,
+						   "WNM: First transition candidate is "
+						   MACSTR, MAC2STR(rep->bssid));
+				}
+#endif /* CONFIG_MBO */
+			}
+
+			pos += len;
+		}
+
+		if (!wpa_s->wnm_num_neighbor_report) {
+			wpa_printf(MSG_DEBUG,
+				   "WNM: Candidate list included bit is set, but no candidates found");
+			wnm_send_bss_transition_mgmt_resp(
+				wpa_s, wpa_s->wnm_dialog_token,
+				WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES,
+				MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
+				NULL);
+			return;
+		}
+
+		wnm_sort_cand_list(wpa_s);
+		wnm_dump_cand_list(wpa_s);
+		valid_ms = valid_int * beacon_int * 128 / 125;
+		wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms",
+			   valid_ms);
+		os_get_reltime(&wpa_s->wnm_cand_valid_until);
+		wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000;
+		wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000;
+		wpa_s->wnm_cand_valid_until.sec +=
+			wpa_s->wnm_cand_valid_until.usec / 1000000;
+		wpa_s->wnm_cand_valid_until.usec %= 1000000;
+
+		/*
+		 * Fetch the latest scan results from the kernel and check for
+		 * candidates based on those results first. This can help in
+		 * finding more up-to-date information should the driver has
+		 * done some internal scanning operations after the last scan
+		 * result update in wpa_supplicant.
+		 */
+		if (wnm_fetch_scan_results(wpa_s) > 0)
+			return;
+
+		/*
+		 * Try to use previously received scan results, if they are
+		 * recent enough to use for a connection.
+		 */
+		if (wpa_s->last_scan_res_used > 0) {
+			struct os_reltime now;
+
+			os_get_reltime(&now);
+			if (!os_time_expired(&now, &wpa_s->last_scan, 10)) {
+				wpa_printf(MSG_DEBUG,
+					   "WNM: Try to use recent scan results");
+				if (wnm_scan_process(wpa_s, 0) > 0)
+					return;
+				wpa_printf(MSG_DEBUG,
+					   "WNM: No match in previous scan results - try a new scan");
+			}
+		}
+		wnm_set_scan_freqs(wpa_s);
+		if (wpa_s->wnm_num_neighbor_report == 1) {
+			os_memcpy(wpa_s->next_scan_bssid,
+				  wpa_s->wnm_neighbor_report_elements[0].bssid,
+				  ETH_ALEN);
+			wpa_printf(MSG_DEBUG,
+				   "WNM: Scan only for a specific BSSID since there is only a single candidate "
+				   MACSTR, MAC2STR(wpa_s->next_scan_bssid));
+		}
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+	} else if (reply) {
+		enum bss_trans_mgmt_status_code status;
+		if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT)
+			status = WNM_BSS_TM_ACCEPT;
+		else {
+			wpa_msg(wpa_s, MSG_DEBUG, "WNM: BSS Transition Management Request did not include candidates");
+			status = WNM_BSS_TM_REJECT_UNSPECIFIED;
+		}
+		wpa_s->wnm_reply = 0;
+		wnm_send_bss_transition_mgmt_resp(
+			wpa_s, wpa_s->wnm_dialog_token, status,
+			MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL);
+	}
+}
+
+
+#define BTM_QUERY_MIN_SIZE	4
+
+int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
+				       u8 query_reason,
+				       const char *btm_candidates,
+				       int cand_list)
+{
+	struct wpabuf *buf;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to "
+		   MACSTR " query_reason=%u%s",
+		   MAC2STR(wpa_s->current_bss->bssid), query_reason,
+		   cand_list ? " candidate list" : "");
+
+	buf = wpabuf_alloc(BTM_QUERY_MIN_SIZE);
+	if (!buf)
+		return -1;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_WNM);
+	wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_QUERY);
+	wpabuf_put_u8(buf, 1);
+	wpabuf_put_u8(buf, query_reason);
+
+	if (cand_list)
+		wnm_add_cand_list(wpa_s, &buf);
+
+	if (btm_candidates) {
+		const size_t max_len = 1000;
+
+		ret = wpabuf_resize(&buf, max_len);
+		if (ret < 0) {
+			wpabuf_free(buf);
+			return ret;
+		}
+
+		ret = ieee802_11_parse_candidate_list(btm_candidates,
+						      wpabuf_put(buf, 0),
+						      max_len);
+		if (ret < 0) {
+			wpabuf_free(buf);
+			return ret;
+		}
+
+		wpabuf_put(buf, ret);
+	}
+
+	ret = wpa_drv_send_action(wpa_s, 0, 0,
+				  wpabuf_head_u8(buf), wpabuf_len(buf), 0);
+
+	wpabuf_free(buf);
+	return ret;
+}
+
+void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
+			      u8 *sender, u8 *payload, size_t len)
+{
+	const u8 *pos, *end;
+	u8 act;
+
+	if (len < 2)
+		return;
+
+	pos = payload;
+	act = *pos++;
+	end = payload + len;
+
+	wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
+		   act, MAC2STR(sender));
+
+	switch (act) {
+	case WNM_BSS_TRANS_MGMT_REQ:
+		ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end,
+						 !(sender[0] & 0x01));
+		break;
+	default:
+		wpa_printf(MSG_ERROR, "WNM: Unknown request");
+		break;
+	}
+}
diff --git a/components/wpa_supplicant/src/common/wnm_sta.h b/components/wpa_supplicant/src/common/wnm_sta.h
new file mode 100755
index 00000000..e513e1a5
--- /dev/null
+++ b/components/wpa_supplicant/src/common/wnm_sta.h
@@ -0,0 +1,70 @@
+/*
+ * IEEE 802.11v WNM related functions and structures
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WNM_STA_H
+#define WNM_STA_H
+
+struct measurement_pilot {
+	u8 measurement_pilot;
+	u8 subelem_len;
+	u8 subelems[255];
+};
+
+struct multiple_bssid {
+	u8 max_bssid_indicator;
+	u8 subelem_len;
+	u8 subelems[255];
+};
+
+struct neighbor_report {
+	u8 bssid[ETH_ALEN];
+	u32 bssid_info;
+	u8 regulatory_class;
+	u8 channel_number;
+	u8 phy_type;
+	u8 preference; /* valid if preference_present=1 */
+	u16 tsf_offset; /* valid if tsf_present=1 */
+	u16 beacon_int; /* valid if tsf_present=1 */
+	char country[2]; /* valid if country_present=1 */
+	u8 rm_capab[5]; /* valid if rm_capab_present=1 */
+	u16 bearing; /* valid if bearing_present=1 */
+	u16 rel_height; /* valid if bearing_present=1 */
+	u32 distance; /* valid if bearing_present=1 */
+	u64 bss_term_tsf; /* valid if bss_term_present=1 */
+	u16 bss_term_dur; /* valid if bss_term_present=1 */
+	unsigned int preference_present:1;
+	unsigned int tsf_present:1;
+	unsigned int country_present:1;
+	unsigned int rm_capab_present:1;
+	unsigned int bearing_present:1;
+	unsigned int bss_term_present:1;
+	unsigned int acceptable:1;
+	struct measurement_pilot *meas_pilot;
+	struct multiple_bssid *mul_bssid;
+	int freq;
+};
+
+
+int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
+				 u8 action, u16 intval, struct wpabuf *tfs_req);
+
+void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
+			      u8 *sender, u8 *payload, size_t len);
+
+int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
+				       u8 query_reason,
+				       const char *btm_candidates,
+				       int cand_list);
+
+void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
+int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail);
+void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s,
+			struct wpa_bss *bss, char *ssid,
+			int after_new_scan);
+
+#endif /* WNM_STA_H */
diff --git a/components/wpa_supplicant/src/common/wpa_supplicant_i.h b/components/wpa_supplicant/src/common/wpa_supplicant_i.h
new file mode 100755
index 00000000..f3c07a9a
--- /dev/null
+++ b/components/wpa_supplicant/src/common/wpa_supplicant_i.h
@@ -0,0 +1,110 @@
+/*
+ * wpa_supplicant - Internal definitions
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_I_H
+#define WPA_SUPPLICANT_I_H
+
+
+#include "drivers/driver.h"
+#include "common/ieee802_11_defs.h"
+/*
+ * struct rrm_data - Data used for managing RRM features
+ */
+struct rrm_data {
+	/* rrm_used - indication regarding the current connection */
+	unsigned int rrm_used:1;
+
+	/*
+	 * notify_neighbor_rep - Callback for notifying report requester
+	 */
+	void (*notify_neighbor_rep)(void *ctx, const u8 *neighbor_rep, size_t len);
+
+	/*
+	 * neighbor_rep_cb_ctx - Callback context
+	 * Received in the callback registration, and sent to the callback
+	 * function as a parameter.
+	 */
+	void *neighbor_rep_cb_ctx;
+
+	/* next_neighbor_rep_token - Next request's dialog token */
+	u8 next_neighbor_rep_token;
+
+	/* token - Dialog token of the current radio measurement */
+	u8 token;
+
+	/* destination address of the current radio measurement request */
+	u8 dst_addr[ETH_ALEN];
+};
+
+#define SSID_MAX_LEN 32
+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;
+	u8 bssid[ETH_ALEN];
+	enum beacon_report_detail report_detail;
+	struct bitfield *eids;
+};
+
+enum scan_trigger_reason {
+	REASON_INVALID,
+	REASON_RRM_BEACON_REPORT,
+	REASON_WNM_BSS_TRANS_REQ,
+};
+
+struct wpa_supplicant {
+	int disable_btm;
+	/* rrm ie */
+	uint8_t rrm_ie[5];
+	u8 extend_caps[8];
+
+	int scanning;
+	enum scan_trigger_reason scan_reason;
+	u64 scan_start_tsf;
+	u8 tsf_bssid[ETH_ALEN];
+	struct wpa_bss *current_bss;
+
+	struct dl_list bss; /* struct wpa_bss::list */
+	struct dl_list bss_id; /* struct wpa_bss::list_id */
+	size_t num_bss;
+	unsigned int bss_update_idx;
+	unsigned int bss_next_id;
+
+	 /*
+	  * Pointers to BSS entries in the order they were in the last scan
+	  * results.
+	  */
+	struct wpa_bss **last_scan_res;
+	unsigned int last_scan_res_used;
+	unsigned int last_scan_res_size;
+	struct os_reltime last_scan;
+
+	struct os_reltime scan_trigger_time, scan_start_time;
+
+	u8 next_scan_bssid[ETH_ALEN];
+	/* type and subtype of frames for which supplicant has registered */
+	uint32_t type, subtype;
+	u8 next_scan_chan;
+#ifdef CONFIG_WNM
+	u8 wnm_dialog_token;
+	u8 wnm_reply;
+	u8 wnm_num_neighbor_report;
+	u8 wnm_mode;
+	u16 wnm_dissoc_timer;
+	u8 wnm_bss_termination_duration[12];
+	struct neighbor_report *wnm_neighbor_report_elements;
+	struct os_reltime wnm_cand_valid_until;
+#endif /* CONFIG_WNM */
+	struct rrm_data rrm;
+	struct beacon_rep_data beacon_rep_data;
+	struct os_reltime beacon_rep_scan;
+};
+
+#endif
diff --git a/components/wpa_supplicant/src/drivers/driver.h b/components/wpa_supplicant/src/drivers/driver.h
new file mode 100755
index 00000000..759e5b62
--- /dev/null
+++ b/components/wpa_supplicant/src/drivers/driver.h
@@ -0,0 +1,187 @@
+/*
+ * Driver interface definition
+ * 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.
+ *
+ * This file defines a driver interface used by both %wpa_supplicant and
+ * hostapd. The first part of the file defines data structures used in various
+ * driver operations. This is followed by the struct wpa_driver_ops that each
+ * driver wrapper will beed to define with callback functions for requesting
+ * driver operations. After this, there are definitions for driver event
+ * reporting with wpa_supplicant_event() and some convenience helper functions
+ * that can be used to report events.
+ */
+
+#ifndef DRIVER_H
+#define DRIVER_H
+
+#define WPA_SUPPLICANT_DRIVER_VERSION 4
+
+#include "common/defs.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_common.h"
+#include "utils/list.h"
+struct wpa_bss;
+struct wpa_supplicant;
+/**
+ * struct wpa_scan_res - Scan result for an BSS/IBSS
+ * @flags: information flags about the BSS/IBSS (WPA_SCAN_*)
+ * @bssid: BSSID
+ * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
+ * @beacon_int: beacon interval in TUs (host byte order)
+ * @caps: capability information field in host byte order
+ * @qual: signal quality
+ * @noise: noise level
+ * @level: signal level
+ * @tsf: Timestamp
+ * @age: Age of the information in milliseconds (i.e., how many milliseconds
+ * ago the last Beacon or Probe Response frame was received)
+ * @snr: Signal-to-noise ratio in dB (calculated during scan result processing)
+ * @parent_tsf: Time when the Beacon/Probe Response frame was received in terms
+ * of TSF of the BSS specified by %tsf_bssid.
+ * @tsf_bssid: The BSS that %parent_tsf TSF time refers to.
+ * @ie_len: length of the following IE field in octets
+ * @beacon_ie_len: length of the following Beacon IE field in octets
+ *
+ * This structure is used as a generic format for scan results from the
+ * driver. Each driver interface implementation is responsible for converting
+ * the driver or OS specific scan results into this format.
+ *
+ * If the driver does not support reporting all IEs, the IE data structure is
+ * constructed of the IEs that are available. This field will also need to
+ * include SSID in IE format. All drivers are encouraged to be extended to
+ * report all IEs to make it easier to support future additions.
+ *
+ * This structure data is followed by ie_len octets of IEs from Probe Response
+ * frame (or if the driver does not indicate source of IEs, these may also be
+ * from Beacon frame). After the first set of IEs, another set of IEs may follow
+ * (with beacon_ie_len octets of data) if the driver provides both IE sets.
+ */
+struct wpa_scan_res {
+	unsigned int flags;
+	u8 bssid[ETH_ALEN];
+	int chan;
+	u16 beacon_int;
+	u16 caps;
+	int noise;
+	int level;
+	u64 tsf;
+	unsigned int age;
+	u64 parent_tsf;
+	u8 tsf_bssid[ETH_ALEN];
+	size_t ie_len;
+	size_t beacon_ie_len;
+	/* Followed by ie_len + beacon_ie_len octets of IE data */
+};
+
+/**
+ * struct wpa_scan_results - Scan results
+ * @res: Array of pointers to allocated variable length scan result entries
+ * @num: Number of entries in the scan result array
+ * @fetch_time: Time when the results were fetched from the driver
+ */
+struct wpa_scan_results {
+	struct wpa_scan_res **res;
+	size_t num;
+	struct os_reltime fetch_time;
+};
+
+#define WPAS_MAX_SCAN_SSIDS 1
+
+/**
+ * struct wpa_driver_scan_ssid - SSIDs to scan for
+ * @ssid - specific SSID to scan for (ProbeReq)
+ *	%NULL or zero-length SSID is used to indicate active scan
+ *	with wildcard SSID.
+ * @ssid_len - Length of the SSID in octets
+ */
+struct wpa_driver_scan_ssid {
+	const u8 *ssid;
+	size_t ssid_len;
+};
+
+/**
+ * struct wpa_driver_scan_params - Scan parameters
+ * Data for struct wpa_driver_ops::scan2().
+ */
+struct wpa_driver_scan_params {
+	/**
+	 * ssids - SSIDs to scan for
+	 */
+	struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS];
+
+	/**
+	 * num_ssids - Number of entries in ssids array
+	 * Zero indicates a request for a passive scan.
+	 */
+	size_t num_ssids;
+
+	/**
+	 * freqs - Array of frequencies to scan or %NULL for all frequencies
+	 *
+	 * The frequency is set in MHz. The array is zero-terminated.
+	 */
+	int channel;
+
+	/**
+	 * bssid - Specific BSSID to scan for
+	 *
+	 * This optional parameter can be used to replace the default wildcard
+	 * BSSID with a specific BSSID to scan for if results are needed from
+	 * only a single BSS.
+	 */
+	const u8 *bssid;
+
+	 /**
+	  * duration - Dwell time on each channel
+	  *
+	  * This optional parameter can be used to set the dwell time on each
+	  * channel. In TUs.
+	  */
+	 u16 duration;
+
+	 unsigned int duration_mandatory;
+};
+
+/**
+ * struct scan_info - Optional data for EVENT_SCAN_RESULTS events
+ * @aborted: Whether the scan was aborted
+ * @freqs: Scanned frequencies in MHz (%NULL = all channels scanned)
+ * @num_freqs: Number of entries in freqs array
+ * @ssids: Scanned SSIDs (%NULL or zero-length SSID indicates wildcard
+ *	SSID)
+ * @num_ssids: Number of entries in ssids array
+ * @external_scan: Whether the scan info is for an external scan
+ * @nl_scan_event: 1 if the source of this scan event is a normal scan,
+ * 	0 if the source of the scan event is a vendor scan
+ * @scan_start_tsf: Time when the scan started in terms of TSF of the
+ *	BSS that the interface that requested the scan is connected to
+ *	(if available).
+ * @scan_start_tsf_bssid: The BSSID according to which %scan_start_tsf
+ *	is set.
+ */
+struct scan_info {
+	int aborted;
+	const int *freqs;
+	size_t num_freqs;
+	struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS];
+	size_t num_ssids;
+	int external_scan;
+	int nl_scan_event;
+	u64 scan_start_tsf;
+	u8 scan_start_tsf_bssid[ETH_ALEN];
+} scan_info;
+
+
+/* driver_common.c */
+void wpa_scan_results_free(struct wpa_scan_results *res);
+
+int wpa_drv_send_action(struct wpa_supplicant *wpa_s,
+			unsigned int chan, unsigned int wait,
+			const u8 *data, size_t data_len, int no_cck);
+
+void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
+			    struct wpa_bss *bss, char *ssid);
+#endif /* DRIVER_H */
diff --git a/components/wpa_supplicant/src/eap_peer/chap.h b/components/wpa_supplicant/src/eap_peer/chap.h
new file mode 100755
index 00000000..a791505f
--- /dev/null
+++ b/components/wpa_supplicant/src/eap_peer/chap.h
@@ -0,0 +1,17 @@
+/*
+ * CHAP-MD5 (RFC 1994)
+ * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CHAP_H
+#define CHAP_H
+
+#define CHAP_MD5_LEN 16
+
+int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge,
+	     size_t challenge_len, u8 *response);
+
+#endif /* CHAP_H */
diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_common.c b/components/wpa_supplicant/src/esp_supplicant/esp_common.c
new file mode 100755
index 00000000..65aaa33a
--- /dev/null
+++ b/components/wpa_supplicant/src/esp_supplicant/esp_common.c
@@ -0,0 +1,403 @@
+/**
+ * Copyright 2020 Espressif Systems (Shanghai) PTE LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "esp_event.h"
+#include "esp_wifi.h"
+#include "esp_wifi_types.h"
+#include "esp_wifi_driver.h"
+#include "drivers/driver.h"
+#include "common/bss.h"
+#include "common/rrm.h"
+#include "common/wnm_sta.h"
+#include "common/wpa_supplicant_i.h"
+#include "esp_supplicant/esp_scan_i.h"
+#include "esp_supplicant/esp_common_i.h"
+#include "common/ieee802_11_common.h"
+#include "esp_rrm.h"
+#include "esp_wnm.h"
+
+struct wpa_supplicant g_wpa_supp;
+
+static void *s_supplicant_task_hdl = NULL;
+static void *s_supplicant_evt_queue = NULL;
+static void *s_supplicant_api_lock = NULL;
+
+static int esp_handle_action_frm(u8 *frame, size_t len,
+				 u8 *sender, u32 rssi, u8 channel)
+{
+	struct ieee_mgmt_frame *frm = os_malloc(sizeof(struct ieee_mgmt_frame) + len);
+
+	if (!frm) {
+		wpa_printf(MSG_ERROR, "memory allocation failed");
+		return -1;
+	}
+
+	os_memcpy(frm->sender, sender, ETH_ALEN);
+	frm->len = len;
+	frm->channel = channel;
+	frm->rssi = rssi;
+
+	os_memcpy(frm->payload, frame, len);
+	if (esp_supplicant_post_evt(SIG_SUPPLICANT_RX_ACTION, (u32)frm) != 0) {
+		os_free(frm);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void esp_handle_rrm_frame(struct wpa_supplicant *wpa_s, u8 *sender,
+				 u8 *payload, size_t len, u32 rssi)
+{
+	if (payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) {
+		/* neighbor report parsing */
+		wpas_rrm_process_neighbor_rep(wpa_s, payload + 1, len - 1);
+	} else if (payload[0] == WLAN_RRM_RADIO_MEASUREMENT_REQUEST) {
+		/* Beacon measurement */
+		wpas_rrm_handle_radio_measurement_request(wpa_s, NULL,
+				sender, payload + 1, len - 1);
+	} else if (payload[0] == WLAN_RRM_LINK_MEASUREMENT_REQUEST) {
+		/* Link measurement */
+		wpas_rrm_handle_link_measurement_request(wpa_s, NULL,
+				payload + 1, len - 1, rssi);
+	}
+}
+
+static int esp_mgmt_rx_action(u8 *sender, u8 *payload, size_t len, u8 channel, u32 rssi)
+{
+	u8 category;
+	u8 bssid[ETH_ALEN];
+	struct wpa_supplicant *wpa_s = &g_wpa_supp;
+	int ret = esp_wifi_get_assoc_bssid_internal(bssid);
+
+	if (ret < 0) {
+		wpa_printf(MSG_INFO, "STA not associated");
+		return -1;
+	}
+
+	category = *payload++;
+	len--;
+	if (category == WLAN_ACTION_WNM) {
+		ieee802_11_rx_wnm_action(wpa_s, sender, payload, len);
+	} else if (category == WLAN_ACTION_RADIO_MEASUREMENT) {
+		esp_handle_rrm_frame(wpa_s, sender, payload, len, rssi);
+	}
+
+	return 0;
+}
+
+static void esp_supplicant_task(void *pvParameters)
+{
+	supplicant_event_t *evt;
+	bool task_del = false;
+
+	while(1) {
+		if (xQueueReceive(s_supplicant_evt_queue, &evt, portMAX_DELAY) != pdTRUE)
+			continue;
+
+		/* event validation failed */
+		if (evt->id >= SIG_SUPPLICANT_MAX) {
+			os_free(evt);
+			continue;
+		}
+
+		/* get lock */
+		SUPPLICANT_API_LOCK();
+
+		switch (evt->id) {
+		case SIG_SUPPLICANT_RX_ACTION:
+		{
+			struct ieee_mgmt_frame *frm = (struct ieee_mgmt_frame *)evt->data;
+			esp_mgmt_rx_action(frm->sender, frm->payload, frm->len, frm->channel, frm->rssi);
+			os_free(frm);
+			break;
+		}
+
+		case SIG_SUPPLICANT_SCAN_DONE:
+			esp_supplicant_handle_scan_done_evt();
+			break;
+		case SIG_SUPPLICANT_DEL_TASK:
+			task_del = true;
+			break;
+		default:
+			break;
+		}
+
+		os_free(evt);
+		SUPPLICANT_API_UNLOCK();
+
+		if (task_del)
+			break;
+	}
+
+	vQueueDelete(s_supplicant_evt_queue);
+	s_supplicant_evt_queue = NULL;
+
+	if (s_supplicant_api_lock) {
+		vSemaphoreDelete(s_supplicant_api_lock);
+		s_supplicant_api_lock = NULL;
+	}
+
+	/* At this point, we completed */
+	vTaskDelete(NULL);
+}
+
+static void esp_clear_bssid_flag(struct wpa_supplicant *wpa_s)
+{
+	wifi_config_t *config;
+
+	/* Reset only if btm is enabled */
+	if (esp_wifi_is_btm_enabled_internal(ESP_IF_WIFI_STA) == false)
+		return;
+
+	config = os_zalloc(sizeof(wifi_config_t));
+
+	if (!config) {
+		wpa_printf(MSG_ERROR, "failed to allocate memory");
+		return;
+	}
+
+	esp_wifi_get_config(ESP_IF_WIFI_STA, config);
+	config->sta.bssid_set = 0;
+	esp_wifi_set_config(ESP_IF_WIFI_STA, config);
+	os_free(config);
+	wpa_printf(MSG_DEBUG, "cleared bssid flag");
+}
+
+static void esp_regsiter_action_frame(struct wpa_supplicant *wpa_s)
+{
+	wpa_s->type &= ~WLAN_FC_STYPE_ACTION;
+	/* subtype is defined only for action frame */
+	wpa_s->subtype = 0;
+
+	/* current supported features in supplicant: rrm and btm */
+	if (esp_wifi_is_rm_enabled_internal(ESP_IF_WIFI_STA))
+		wpa_s->subtype = 1 << WLAN_ACTION_RADIO_MEASUREMENT;
+	if (esp_wifi_is_btm_enabled_internal(ESP_IF_WIFI_STA))
+		wpa_s->subtype |= 1 << WLAN_ACTION_WNM;
+
+	if (wpa_s->subtype)
+		wpa_s->type |= 1 << WLAN_FC_STYPE_ACTION;
+
+	esp_wifi_register_frame_internal(wpa_s->type, wpa_s->subtype);
+}
+
+static void esp_supplicant_sta_conn_handler(void* arg, esp_event_base_t event_base,
+					    int event_id, void* event_data)
+{
+	u8 bssid[ETH_ALEN];
+	u8 *ie;
+	struct wpa_supplicant *wpa_s = &g_wpa_supp;
+	int ret = esp_wifi_get_assoc_bssid_internal(bssid);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "Not able to get connected bssid");
+		return;
+	}
+	struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, bssid);
+	if (!bss) {
+		wpa_printf(MSG_INFO, "connected bss entry not present in scan cache");
+		return;
+	}
+	wpa_s->current_bss = bss;
+	ie = (u8 *)bss;
+	ie += sizeof(struct wpa_bss);
+	ieee802_11_parse_elems(wpa_s, ie, bss->ie_len);
+	wpa_bss_flush(wpa_s);
+	/* Register for action frames */
+	esp_regsiter_action_frame(wpa_s);
+	/* clear set bssid flag */
+	esp_clear_bssid_flag(wpa_s);
+}
+
+static void esp_supplicant_sta_disconn_handler(void* arg, esp_event_base_t event_base,
+						int event_id, void* event_data)
+{
+	struct wpa_supplicant *wpa_s = &g_wpa_supp;
+	wpas_rrm_reset(wpa_s);
+	if (wpa_s->current_bss) {
+		wpa_s->current_bss = NULL;
+	}
+}
+
+void esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
+{
+	struct wpa_supplicant *wpa_s = &g_wpa_supp;
+
+	s_supplicant_evt_queue = xQueueCreate(3, sizeof(supplicant_event_t));
+	xTaskCreate(esp_supplicant_task, "supplicantT", SUPPLICANT_TASK_STACK_SIZE, NULL, 2, s_supplicant_task_hdl);
+
+	s_supplicant_api_lock = xSemaphoreCreateRecursiveMutex();
+	if (!s_supplicant_api_lock) {
+		wpa_printf(MSG_ERROR, "esp_supplicant_common_init: failed to create Supplicant API lock");
+		return;
+	}
+
+	esp_scan_init(wpa_s);
+	wpas_rrm_reset(wpa_s);
+	wpas_clear_beacon_rep_data(wpa_s);
+
+	esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED,
+			&esp_supplicant_sta_conn_handler, NULL);
+	esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED,
+			&esp_supplicant_sta_disconn_handler, NULL);
+
+	wpa_s->type = 0;
+	wpa_s->subtype = 0;
+	wpa_cb->esp_sta_rx_mgmt = esp_ieee80211_handle_rx_frm;
+}
+
+int esp_rrm_send_neighbor_rep_request(neighbor_rep_request_cb cb,
+				      void *cb_ctx)
+{
+	struct wpa_supplicant *wpa_s = &g_wpa_supp;
+	struct wpa_ssid_value wpa_ssid = {0};
+	struct wifi_ssid *ssid = esp_wifi_sta_get_prof_ssid_internal();
+	os_memcpy(wpa_ssid.ssid, ssid->ssid, ssid->len);
+	wpa_ssid.ssid_len = ssid->len;
+	wpas_rrm_send_neighbor_rep_request(wpa_s, &wpa_ssid, 0, 0, cb, cb_ctx);
+
+	return 0;
+}
+
+int esp_wnm_send_bss_transition_mgmt_query(enum btm_query_reason query_reason,
+					   const char *btm_candidates,
+					   int cand_list)
+{
+	struct wpa_supplicant *wpa_s = &g_wpa_supp;
+	return wnm_send_bss_transition_mgmt_query(wpa_s, query_reason, btm_candidates, cand_list);
+}
+
+void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
+			    struct wpa_bss *bss, char *ssid)
+{
+	wifi_config_t *config = os_zalloc(sizeof(wifi_config_t));
+
+	if (!config) {
+		wpa_printf(MSG_ERROR, "failed to allocate memory");
+		return;
+	}
+
+	esp_wifi_get_config(ESP_IF_WIFI_STA, config);
+	esp_wifi_disconnect();
+	/* We only support roaming in same ESS, therefore only bssid setting is needed */
+	os_memcpy(config->sta.bssid, bss->bssid, ETH_ALEN);
+	config->sta.bssid_set = 1;
+	esp_wifi_set_config(ESP_IF_WIFI_STA, config);
+	os_free(config);
+	esp_wifi_connect();
+}
+
+void esp_set_rm_enabled_ie(void)
+{
+	uint8_t rmm_ie[5] = {0};
+	uint8_t rrm_ie_len = 5;
+	uint8_t *pos = rmm_ie;
+
+	*pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
+
+	*pos |= WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
+#ifdef SCAN_CACHE_SUPPORTED
+		WLAN_RRM_CAPS_BEACON_REPORT_TABLE |
+#endif
+		WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE;
+
+	/* set rm enabled IE if enabled in driver */
+	if (esp_wifi_is_rm_enabled_internal(ESP_IF_WIFI_STA)) {
+		esp_wifi_set_appie_internal(WIFI_APPIE_RM_ENABLED_CAPS, rmm_ie, rrm_ie_len, 0);
+	}
+}
+
+void esp_get_tx_power(uint8_t *tx_power)
+{
+#define DEFAULT_MAX_TX_POWER 19 /* max tx power is 19.5 dbm */
+	s8 power;
+	/* esp sends management frames at max tx power configured */
+	int ret = esp_wifi_get_max_tx_power(&power);
+	if (ret != 0) {
+		wpa_printf(MSG_ERROR, "failed to get tx power");
+		*tx_power = DEFAULT_MAX_TX_POWER;
+		return;
+	}
+	*tx_power = power/4;
+#undef DEFAULT_MAX_TX_POWER
+}
+
+int wpa_drv_send_action(struct wpa_supplicant *wpa_s,
+			unsigned int channel,
+			unsigned int wait,
+			const u8 *data, size_t data_len,
+			int no_cck)
+{
+	int ret = 0;
+	mgmt_frm_req_t *req = os_zalloc(sizeof(*req) + data_len);;
+	if (!req)
+		return -1;
+
+	if (!wpa_s->current_bss) {
+		wpa_printf(MSG_ERROR, "STA not associated, return");
+		ret = -1;
+		goto cleanup;
+	}
+
+	req->ifx = ESP_IF_WIFI_STA;
+	req->subtype = WLAN_FC_STYPE_ACTION;
+	req->data_len = data_len;
+	os_memcpy(req->data, data, req->data_len);
+
+	if (esp_wifi_send_mgmt_frm_internal(req) != 0) {
+		wpa_printf(MSG_ERROR, "action frame sending failed");
+		ret = -1;
+		goto cleanup;
+	}
+	wpa_printf(MSG_INFO, "action frame sent");
+
+cleanup:
+	os_free(req);
+	return ret;
+}
+
+int esp_supplicant_post_evt(uint32_t evt_id, uint32_t data)
+{
+	supplicant_event_t *evt = os_zalloc(sizeof(supplicant_event_t));
+	if (evt == NULL) {
+		return -1;
+	}
+	evt->id = evt_id;
+	evt->data = data;
+
+	SUPPLICANT_API_LOCK();
+	if (xQueueSend(s_supplicant_evt_queue, &evt, 10 / portTICK_PERIOD_MS ) != pdPASS) {
+		SUPPLICANT_API_UNLOCK();
+		os_free(evt);
+		return -1;
+	}
+	SUPPLICANT_API_UNLOCK();
+	return 0;
+}
+
+int esp_ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender,
+				u32 rssi, u8 channel, u64 current_tsf)
+{
+	if (type == WLAN_FC_STYPE_BEACON || type == WLAN_FC_STYPE_PROBE_RESP) {
+		return esp_handle_beacon_probe(type, frame, len, sender, rssi, channel, current_tsf);
+	} else if (type ==  WLAN_FC_STYPE_ACTION) {
+		return esp_handle_action_frm(frame, len, sender, rssi, channel);
+	}
+
+	return -1;
+}
diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_common_i.h b/components/wpa_supplicant/src/esp_supplicant/esp_common_i.h
new file mode 100755
index 00000000..8d87d077
--- /dev/null
+++ b/components/wpa_supplicant/src/esp_supplicant/esp_common_i.h
@@ -0,0 +1,80 @@
+/**
+ * Copyright 2020 Espressif Systems (Shanghai) PTE LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ESP_COMMON_I_H
+#define ESP_COMMON_I_H
+
+#include "utils/includes.h"
+
+struct wpa_funcs;
+
+#ifdef ROAMING_SUPPORT
+struct ieee_mgmt_frame {
+	u8 sender[ETH_ALEN];
+	u8 channel;
+	u32 rssi;
+	size_t len;
+	u8 payload[0];
+};
+
+typedef struct {
+    uint32_t id;
+    uint32_t data;
+} supplicant_event_t;
+
+#define SUPPLICANT_API_LOCK() xSemaphoreTakeRecursive(s_supplicant_api_lock, portMAX_DELAY)
+#define SUPPLICANT_API_UNLOCK() xSemaphoreGiveRecursive(s_supplicant_api_lock)
+
+#define SUPPLICANT_TASK_STACK_SIZE (6144 + TASK_STACK_SIZE_ADD)
+enum SIG_SUPPLICANT {
+	SIG_SUPPLICANT_RX_ACTION,
+	SIG_SUPPLICANT_SCAN_DONE,
+	SIG_SUPPLICANT_DEL_TASK,
+	SIG_SUPPLICANT_MAX,
+};
+
+int esp_supplicant_post_evt(uint32_t evt_id, uint32_t data);
+int esp_ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender,
+			    u32 rssi, u8 channel, u64 current_tsf);
+void esp_set_rm_enabled_ie(void);
+void esp_get_tx_power(uint8_t *tx_power);
+void esp_supplicant_common_init(struct wpa_funcs *wpa_cb);
+#else
+
+#include "esp_rrm.h"
+#include "esp_wnm.h"
+
+static inline void esp_set_rm_enabled_ie(void) {}
+static inline int esp_ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender,
+			    u32 rssi, u8 channel, u64 current_tsf)
+{
+	return -1;
+}
+int esp_rrm_send_neighbor_rep_request(neighbor_rep_request_cb cb,
+				      void *cb_ctx)
+{
+	return -1;
+}
+
+int esp_wnm_send_bss_transition_mgmt_query(enum btm_query_reason query_reason,
+					   const char *btm_candidates,
+					   int cand_list)
+{
+	return -1;
+}
+
+#endif
+#endif
diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_scan.c b/components/wpa_supplicant/src/esp_supplicant/esp_scan.c
new file mode 100755
index 00000000..788d584c
--- /dev/null
+++ b/components/wpa_supplicant/src/esp_supplicant/esp_scan.c
@@ -0,0 +1,270 @@
+/**
+ * Copyright 2020 Espressif Systems (Shanghai) PTE LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_supplicant_i.h"
+#include "utils/wpa_debug.h"
+#include "esp_wifi_driver.h"
+#include "esp_wifi_types.h"
+#include "drivers/driver.h"
+#include "common/scan.h"
+#include "common/bss.h"
+#include "common/rrm.h"
+#include "common/ieee802_11_common.h"
+#include "esp_supplicant/esp_common_i.h"
+#include "common/wnm_sta.h"
+
+extern struct wpa_supplicant g_wpa_supp;
+
+static void esp_scan_done_event_handler(void* arg, esp_event_base_t event_base,
+					int event_id, void* event_data)
+{
+	struct wpa_supplicant *wpa_s = &g_wpa_supp;
+	if (!wpa_s->scanning) {
+		/* update last scan time */
+		wpa_s->scan_start_tsf = esp_wifi_get_tsf_time(ESP_IF_WIFI_STA);
+		wpa_printf(MSG_DEBUG, "scan not triggered by supplicant, ignore");
+		return;
+	}
+	wpa_s->type &= ~(1 << WLAN_FC_STYPE_BEACON) & ~(1 << WLAN_FC_STYPE_PROBE_RESP);
+	esp_wifi_register_frame_internal(wpa_s->type, wpa_s->subtype);
+	esp_supplicant_post_evt(SIG_SUPPLICANT_SCAN_DONE, 0);
+
+}
+
+static void esp_supp_handle_wnm_scan_done(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss = wpa_bss_get_next_bss(wpa_s, wpa_s->current_bss);
+
+	if (wpa_s->wnm_neighbor_report_elements) {
+		wnm_scan_process(wpa_s, 1);
+	} else if (wpa_s->wnm_dissoc_timer) {
+		if (wpa_s->num_bss == 1) {
+			wpa_printf(MSG_INFO, "not able to find another candidate, do nothing");
+			return;
+		}
+		/* this is a already matched bss */
+		if (bss)
+			wnm_bss_tm_connect(wpa_s, bss, NULL, 1);
+	}
+}
+
+static void esp_supp_scan_done_cleanup(struct wpa_supplicant *wpa_s)
+{
+	uint16_t number = 1;
+	wifi_ap_record_t ap_records;
+
+	wpa_s->scanning = 0;
+	wpa_s->scan_reason = 0;
+	/* clean scan list from net80211 */
+	esp_wifi_scan_get_ap_records(&number, &ap_records);
+}
+
+void esp_supplicant_handle_scan_done_evt(void)
+{
+	struct wpa_supplicant *wpa_s = &g_wpa_supp;
+
+	wpa_printf(MSG_INFO, "scan done received");
+	/* Check which module started this, call the respective function */
+	if (wpa_s->scan_reason == REASON_RRM_BEACON_REPORT) {
+		wpas_beacon_rep_scan_process(wpa_s, wpa_s->scan_start_tsf);
+	} else if (wpa_s->scan_reason == REASON_WNM_BSS_TRANS_REQ) {
+		esp_supp_handle_wnm_scan_done(wpa_s);
+	}
+	esp_supp_scan_done_cleanup(wpa_s);
+	wpa_bss_update_end(wpa_s);
+#ifndef SCAN_CACHE_SUPPORTED
+	wpa_bss_flush(wpa_s);
+#endif
+}
+
+void esp_scan_init(struct wpa_supplicant *wpa_s)
+{
+	wpa_s->scanning = 0;
+	wpa_bss_init(wpa_s);
+	wpa_s->last_scan_res = NULL;
+	esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_SCAN_DONE,
+			&esp_scan_done_event_handler, NULL);
+}
+
+void esp_scan_deinit(struct wpa_supplicant *wpa_s)
+{
+	wpa_bss_deinit(wpa_s);
+}
+
+int esp_handle_beacon_probe(u8 type, u8 *frame, size_t len, u8 *sender,
+			    u32 rssi, u8 channel, u64 current_tsf)
+{
+	struct wpa_supplicant *wpa_s = &g_wpa_supp;
+	struct os_reltime now;
+	struct wpa_scan_res *res;
+	u8 *ptr;
+
+	if (len < 12) {
+		wpa_printf(MSG_ERROR, "beacon/probe is having short len=%d\n", len);
+		return -1;
+	}
+
+	res = os_zalloc(sizeof(struct wpa_scan_res) + len - 12);
+	if (!res) {
+		wpa_printf(MSG_ERROR, "failed to allocate memory");
+		return -1;
+	}
+
+	ptr = (u8 *)res;
+	os_get_time(&now);
+	os_memcpy(res->bssid, sender, ETH_ALEN);
+	res->tsf = WPA_GET_LE64(frame);
+	frame += 8;
+	len -= 8;
+
+	if ((wpa_s->scan_start_tsf == 0) &&
+	    wpa_s->current_bss &&
+	    (os_memcmp(wpa_s->current_bss, sender, ETH_ALEN) == 0)) {
+		wpa_s->scan_start_tsf = res->tsf;
+		os_memcpy(wpa_s->tsf_bssid, sender, ETH_ALEN);
+	}
+	res->beacon_int = WPA_GET_LE16(frame);
+
+	frame += 2;
+	len -= 2;
+	res->caps = WPA_GET_LE16(frame);
+	frame += 2;
+	len -= 2;
+
+	res->chan = channel;
+	res->noise = 0;
+	res->level = rssi;
+	os_memcpy(res->tsf_bssid, wpa_s->tsf_bssid, ETH_ALEN);
+	res->parent_tsf = current_tsf - wpa_s->scan_start_tsf;
+	if (type == WLAN_FC_STYPE_PROBE_RESP)
+		res->ie_len = len;
+	else if (type == WLAN_FC_STYPE_BEACON)
+		res->beacon_ie_len = len;
+
+	ptr += sizeof(struct wpa_scan_res);
+
+	/* update rest of the frame */
+	os_memcpy(ptr, frame, len);
+	wpa_bss_update_scan_res(wpa_s, res, &now);
+	os_free(res);
+
+	return 0;
+}
+
+static int esp_issue_scan(struct wpa_supplicant *wpa_s,
+			       struct wpa_driver_scan_params *scan_params)
+{
+	wifi_scan_config_t *params = NULL;
+	int ret = 0;
+	u64 scan_start_tsf = esp_wifi_get_tsf_time(ESP_IF_WIFI_STA);
+
+	/* TODO: Directly try to connect if scan results are recent */
+	if ((scan_start_tsf -  wpa_s->scan_start_tsf) > 100000) {
+		wpa_printf(MSG_DEBUG, "flushing old scan cache %llu",
+				(scan_start_tsf -  wpa_s->scan_start_tsf));
+		wpa_bss_flush(wpa_s);
+	}
+
+	esp_wifi_get_macaddr_internal(ESP_IF_WIFI_STA, wpa_s->tsf_bssid);
+
+	if (scan_params) {
+		params = os_zalloc(sizeof(wifi_scan_config_t));
+		if (!params) {
+			wpa_printf(MSG_ERROR, "failed to allocate memory");
+			return -1;
+		}
+		if (scan_params->num_ssids) {
+			params->ssid = os_zalloc(scan_params->ssids[0].ssid_len + 1);
+			if (!params->ssid) {
+				wpa_printf(MSG_ERROR, "failed to allocate memory");
+				return -1;
+			}
+			os_memcpy(params->ssid, scan_params->ssids[0].ssid, scan_params->ssids[0].ssid_len);
+			params->scan_type = WIFI_SCAN_TYPE_ACTIVE;
+		} else
+			params->scan_type = WIFI_SCAN_TYPE_PASSIVE;
+
+		if (scan_params->bssid) {
+			params->bssid = os_zalloc(ETH_ALEN);
+			if (!params->bssid) {
+				wpa_printf(MSG_ERROR, "failed to allocate memory");
+				return -1;
+			}
+			os_memcpy(params->bssid, scan_params->bssid, ETH_ALEN);
+		}
+		if (scan_params->channel) {
+			params->channel = scan_params->channel;
+		}
+
+		if (scan_params->duration) {
+			params->scan_time.passive = scan_params->duration;
+			params->scan_time.active.min = scan_params->duration;
+			params->scan_time.active.max = scan_params->duration;
+		}
+	}
+
+	wpa_s->scan_start_tsf = scan_start_tsf;
+	/* Register frames to come to supplicant when we park on channel */
+	wpa_s->type |= (1 << WLAN_FC_STYPE_BEACON) | (1 << WLAN_FC_STYPE_PROBE_RESP);
+	esp_wifi_register_frame_internal(wpa_s->type, wpa_s->subtype);
+
+	/* issue scan */
+	if (esp_wifi_scan_start(params, false) < 0) {
+		ret = -1;
+		goto cleanup;
+	}
+	wpa_s->scanning = 1;
+	wpa_bss_update_start(wpa_s);
+	wpa_printf(MSG_INFO, "scan issued at time=%llu", wpa_s->scan_start_tsf);
+
+cleanup:
+	if (params->ssid)
+		os_free(params->ssid);
+	if (params->bssid)
+		os_free(params->bssid);
+	os_free(params);
+
+	return ret;
+}
+
+/**
+ * wpa_supplicant_trigger_scan - Request driver to start a scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
+				struct wpa_driver_scan_params *params)
+{
+	return esp_issue_scan(wpa_s, params);
+}
+
+void wpa_scan_results_free(struct wpa_scan_results *res)
+{
+	size_t i;
+
+	if (res == NULL)
+		return;
+
+	for (i = 0; i < res->num; i++)
+		os_free(res->res[i]);
+	os_free(res->res);
+	os_free(res);
+}
diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_scan_i.h b/components/wpa_supplicant/src/esp_supplicant/esp_scan_i.h
new file mode 100755
index 00000000..25442a6a
--- /dev/null
+++ b/components/wpa_supplicant/src/esp_supplicant/esp_scan_i.h
@@ -0,0 +1,25 @@
+/**
+ * Copyright 2020 Espressif Systems (Shanghai) PTE LTD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ESP_SCAN_I_H
+#define ESP_SCAN_I_H
+void esp_scan_init(struct wpa_supplicant *wpa_s);
+void esp_scan_deinit(struct wpa_supplicant *wpa_s);
+int esp_handle_beacon_probe(u8 type, u8 *frame, size_t len, u8 *sender,
+			    u32 rssi, u8 channel, u64 current_tsf);
+
+void esp_supplicant_handle_scan_done_evt(void);
+#endif
diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h
old mode 100644
new mode 100755
index 77b5d4a5..ffd054da
--- a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h
+++ b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h
@@ -39,6 +39,7 @@ enum {
     WIFI_APPIE_FREQ_ERROR,
     WIFI_APPIE_ESP_MANUFACTOR,
     WIFI_APPIE_COUNTRY,
+    WIFI_APPIE_RM_ENABLED_CAPS,
     WIFI_APPIE_MAX,
 };
 
@@ -107,6 +108,7 @@ struct wpa_funcs {
     int (*wpa_michael_mic_failure)(u16 is_unicast);
     uint8_t *(*wpa3_build_sae_msg)(uint8_t *bssid, uint32_t type, size_t *len);
     int (*wpa3_parse_sae_msg)(uint8_t *buf, size_t len, uint32_t type, uint16_t status);
+    int (*esp_sta_rx_mgmt)(u8 type, u8 *frame, size_t len, u8 *sender, u32 rssi, u8 channel, u64 current_tsf);
 };
 
 struct wpa2_funcs {
@@ -156,7 +158,13 @@ typedef struct {
     uint8_t igtk[WPA_IGTK_LEN];
 } wifi_wpa_igtk_t;
 
-/*wpa_auth.c*/
+typedef struct {
+    wifi_interface_t ifx;
+    uint8_t subtype;
+    uint32_t data_len;
+    uint8_t data[0];
+} mgmt_frm_req_t;
+
 uint8_t *esp_wifi_ap_get_prof_pmk_internal(void);
 struct wifi_ssid *esp_wifi_ap_get_prof_ap_ssid_internal(void);
 uint8_t esp_wifi_ap_get_prof_authmode_internal(void);
@@ -224,5 +232,9 @@ uint8_t esp_wifi_get_user_init_flag_internal(void);
 int esp_wifi_ipc_internal(wifi_ipc_config_t *cfg, bool sync);
 esp_err_t esp_wifi_internal_issue_disconnect(uint8_t reason_code);
 int esp_wifi_ap_deauth_internal(uint8_t *mac, uint32_t reason);
+bool esp_wifi_is_rm_enabled_internal(uint8_t if_index);
+bool esp_wifi_is_btm_enabled_internal(uint8_t if_index);
+void esp_wifi_register_frame_internal(uint32_t type, uint32_t subtype);
+esp_err_t esp_wifi_send_mgmt_frm_internal(const mgmt_frm_req_t *req);
 
 #endif /* _ESP_WIFI_DRIVER_H_ */
diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c
index 4fa9d1cc..7b37a6c0 100644
--- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c
+++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c
@@ -34,6 +34,7 @@
 #include "esp_wifi_driver.h"
 #include "esp_private/wifi.h"
 #include "esp_wpa3_i.h"
+#include "esp_common_i.h"
 
 void  wpa_install_key(enum wpa_alg alg, u8 *addr, int key_idx, int set_tx,
                       u8 *seq, size_t seq_len, u8 *key, size_t key_len, int key_entry_valid)
@@ -102,6 +103,7 @@ void  wpa_config_assoc_ie(u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len)
     } else {
         esp_wifi_set_appie_internal(WIFI_APPIE_RSN, assoc_buf, assoc_wpa_ie_len, 1);
     }
+    esp_set_rm_enabled_ie();
 }
 
 void  wpa_neg_complete(void)
@@ -154,6 +156,7 @@ bool  wpa_deattach(void)
 
 void  wpa_sta_connect(uint8_t *bssid)
 {
+
     int ret = 0;
     wpa_config_profile();
     ret = wpa_config_bss(bssid);
@@ -198,6 +201,13 @@ static void wpa_sta_disconnected_cb(uint8_t reason_code)
     }
 }
 
+#ifndef ROAMING_SUPPORT
+static void esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
+{
+	wpa_cb->esp_sta_rx_mgmt = NULL;
+}
+#endif
+
 int esp_supplicant_init(void)
 {
     struct wpa_funcs *wpa_cb;
@@ -226,6 +236,7 @@ int esp_supplicant_init(void)
     wpa_cb->wpa_config_bss = NULL;//wpa_config_bss;
     wpa_cb->wpa_michael_mic_failure = wpa_michael_mic_failure;
     esp_wifi_register_wpa3_cb(wpa_cb);
+    esp_supplicant_common_init(wpa_cb);
 
     esp_wifi_register_wpa_cb_internal(wpa_cb);
 
diff --git a/components/wpa_supplicant/src/utils/bitfield.c b/components/wpa_supplicant/src/utils/bitfield.c
new file mode 100755
index 00000000..8dcec390
--- /dev/null
+++ b/components/wpa_supplicant/src/utils/bitfield.c
@@ -0,0 +1,89 @@
+/*
+ * Bitfield
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "bitfield.h"
+
+
+struct bitfield {
+	u8 *bits;
+	size_t max_bits;
+};
+
+
+struct bitfield * bitfield_alloc(size_t max_bits)
+{
+	struct bitfield *bf;
+
+	bf = os_zalloc(sizeof(*bf) + (max_bits + 7) / 8);
+	if (bf == NULL)
+		return NULL;
+	bf->bits = (u8 *) (bf + 1);
+	bf->max_bits = max_bits;
+	return bf;
+}
+
+
+void bitfield_free(struct bitfield *bf)
+{
+	os_free(bf);
+}
+
+
+void bitfield_set(struct bitfield *bf, size_t bit)
+{
+	if (bit >= bf->max_bits)
+		return;
+	bf->bits[bit / 8] |= BIT(bit % 8);
+}
+
+
+void bitfield_clear(struct bitfield *bf, size_t bit)
+{
+	if (bit >= bf->max_bits)
+		return;
+	bf->bits[bit / 8] &= ~BIT(bit % 8);
+}
+
+
+int bitfield_is_set(struct bitfield *bf, size_t bit)
+{
+	if (bit >= bf->max_bits)
+		return 0;
+	return !!(bf->bits[bit / 8] & BIT(bit % 8));
+}
+
+
+static int first_zero(u8 val)
+{
+	int i;
+	for (i = 0; i < 8; i++) {
+		if (!(val & 0x01))
+			return i;
+		val >>= 1;
+	}
+	return -1;
+}
+
+
+int bitfield_get_first_zero(struct bitfield *bf)
+{
+	size_t i;
+	for (i = 0; i < (bf->max_bits + 7) / 8; i++) {
+		if (bf->bits[i] != 0xff)
+			break;
+	}
+	if (i == (bf->max_bits + 7) / 8)
+		return -1;
+	i = i * 8 + first_zero(bf->bits[i]);
+	if (i >= bf->max_bits)
+		return -1;
+	return i;
+}
diff --git a/components/wpa_supplicant/src/utils/bitfield.h b/components/wpa_supplicant/src/utils/bitfield.h
new file mode 100755
index 00000000..7050a208
--- /dev/null
+++ b/components/wpa_supplicant/src/utils/bitfield.h
@@ -0,0 +1,21 @@
+/*
+ * Bitfield
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BITFIELD_H
+#define BITFIELD_H
+
+struct bitfield;
+
+struct bitfield * bitfield_alloc(size_t max_bits);
+void bitfield_free(struct bitfield *bf);
+void bitfield_set(struct bitfield *bf, size_t bit);
+void bitfield_clear(struct bitfield *bf, size_t bit);
+int bitfield_is_set(struct bitfield *bf, size_t bit);
+int bitfield_get_first_zero(struct bitfield *bf);
+
+#endif /* BITFIELD_H */
diff --git a/components/wpa_supplicant/src/utils/common.c b/components/wpa_supplicant/src/utils/common.c
index b57feee3..47305b0c 100644
--- a/components/wpa_supplicant/src/utils/common.c
+++ b/components/wpa_supplicant/src/utils/common.c
@@ -491,3 +491,59 @@ int hwaddr_aton2(const char *txt, u8 *addr)
 
 	return pos - txt;
 }
+
+static inline int os_reltime_expired(struct os_time *now,
+				     struct os_time *ts,
+				     os_time_t timeout_secs)
+{
+	struct os_time age;
+
+	os_time_sub(now, ts, &age);
+	return (age.sec > timeout_secs) ||
+		(age.sec == timeout_secs && age.usec > 0);
+}
+
+int os_time_expired(struct os_time *now,
+		struct os_time *ts,
+		os_time_t timeout_secs)
+{
+	return os_reltime_expired(now, ts, timeout_secs);
+}
+
+u8 rssi_to_rcpi(int rssi)
+{
+	if (!rssi)
+		return 255; /* not available */
+	if (rssi < -110)
+		return 0;
+	if (rssi > 0)
+		return 220;
+	return (rssi + 110) * 2;
+}
+
+/**
+ * wpa_ssid_txt - Convert SSID to a printable string
+ * @ssid: SSID (32-octet string)
+ * @ssid_len: Length of ssid in octets
+ * Returns: Pointer to a printable string
+ *
+ * This function can be used to convert SSIDs into printable form. In most
+ * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
+ * does not limit the used character set, so anything could be used in an SSID.
+ *
+ * This function uses a static buffer, so only one call can be used at the
+ * time, i.e., this is not re-entrant and the returned buffer must be used
+ * before calling this again.
+ */
+const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len)
+{
+	static char ssid_txt[SSID_MAX_LEN * 4 + 1];
+
+	if (ssid == NULL) {
+		ssid_txt[0] = '\0';
+		return ssid_txt;
+	}
+
+	printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len);
+	return ssid_txt;
+}
diff --git a/components/wpa_supplicant/src/utils/common.h b/components/wpa_supplicant/src/utils/common.h
index fb486565..7e6b4352 100644
--- a/components/wpa_supplicant/src/utils/common.h
+++ b/components/wpa_supplicant/src/utils/common.h
@@ -13,6 +13,7 @@
 #endif /* ets */
 #include "os.h"
 #include "esp_bit_defs.h"
+#include "utils/list.h"
 
 /* Define platform specific variable type macros */
 #if defined(ESP_PLATFORM)
@@ -117,6 +118,12 @@ static inline unsigned int wpa_swap_32(unsigned int v)
 #define WPA_BYTE_SWAP_DEFINED
 #endif /* !WPA_BYTE_SWAP_DEFINED */
 
+#define SSID_MAX_LEN 32
+
+struct wpa_ssid_value {
+	u8 ssid[SSID_MAX_LEN];
+	size_t ssid_len;
+};
 
 /* Macros for handling unaligned memory accesses */
 
@@ -381,6 +388,10 @@ int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
 			       size_t len);
 
 int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask);
+u8 rssi_to_rcpi(int rssi);
+int os_time_expired(struct os_time *now,
+		struct os_time *ts,
+		os_time_t timeout_secs);
 
 #ifdef CONFIG_NATIVE_WINDOWS
 void wpa_unicode2ascii_inplace(TCHAR *str);
diff --git a/components/wpa_supplicant/src/utils/list.h b/components/wpa_supplicant/src/utils/list.h
index a67a0496..a9a48754 100755
--- a/components/wpa_supplicant/src/utils/list.h
+++ b/components/wpa_supplicant/src/utils/list.h
@@ -12,8 +12,8 @@
  * See README and COPYING for more details.
  */
 
-#ifndef LIST_H
-#define LIST_H
+#ifndef WPA_LIST_H
+#define WPA_LIST_H
 
 #include <stddef.h>
 
@@ -100,4 +100,4 @@ static inline unsigned int dl_list_len(struct dl_list *list)
 #define DEFINE_DL_LIST(name) \
 	struct dl_list name = { &(name), &(name) }
 
-#endif /* LIST_H */
+#endif /* WPA_LIST_H */
diff --git a/components/wpa_supplicant/src/utils/wpa_debug.c b/components/wpa_supplicant/src/utils/wpa_debug.c
index 20a0ae44..8d53bf49 100644
--- a/components/wpa_supplicant/src/utils/wpa_debug.c
+++ b/components/wpa_supplicant/src/utils/wpa_debug.c
@@ -91,22 +91,22 @@ void  wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
 	size_t i;
 	char output[50];
 
-	if (level < MSG_MSGDUMP)
+	if (level < MSG_ERROR)
 		return;
 
-	wpa_printf(MSG_DEBUG, "%s - hexdump(len=%lu):", title, (unsigned long) len);
+	wpa_printf(level, "%s - hexdump(len=%lu):", title, (unsigned long) len);
 	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG, " [NULL]");
+		wpa_printf(level, " [NULL]");
 	} else {
 		for (i = 0; i < len / 16; i++) {
 			_wpa_snprintf_hex(output, 50, buf + i * 16, 16, 0, 1);
-			wpa_printf(MSG_DEBUG, "%s", output);
+			wpa_printf(level, "%s", output);
 		}
 		if (len % 16) {
 			int bytes_printed = (len / 16) * 16;
 			_wpa_snprintf_hex(output, 50, buf + bytes_printed,
 							  len - bytes_printed, 0, 1);
-			wpa_printf(MSG_DEBUG, "%s", output);
+			wpa_printf(level, "%s", output);
 		}
 	} 
 #endif