فهرست منبع

wpa_supplicant: Add support for FT psk

kapil.gupta 5 سال پیش
والد
کامیت
3d5ca7ee6e
31فایلهای تغییر یافته به همراه2112 افزوده شده و 348 حذف شده
  1. 0 4
      components/esp_rom/esp32c2/ld/esp32c2.rom.ld
  2. 2 1
      components/esp_wifi/include/esp_wifi_types.h
  3. 1 1
      components/esp_wifi/lib
  4. 16 9
      components/wpa_supplicant/CMakeLists.txt
  5. 8 2
      components/wpa_supplicant/Kconfig
  6. 231 51
      components/wpa_supplicant/esp_supplicant/src/esp_common.c
  7. 8 30
      components/wpa_supplicant/esp_supplicant/src/esp_common_i.h
  8. 6 1
      components/wpa_supplicant/esp_supplicant/src/esp_scan.c
  9. 8 3
      components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h
  10. 8 21
      components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c
  11. 2 2
      components/wpa_supplicant/include/utils/wpa_debug.h
  12. 5 17
      components/wpa_supplicant/port/include/supplicant_opt.h
  13. 47 42
      components/wpa_supplicant/src/ap/wpa_auth.c
  14. 22 5
      components/wpa_supplicant/src/ap/wpa_auth_i.h
  15. 12 12
      components/wpa_supplicant/src/ap/wpa_auth_ie.c
  16. 1 0
      components/wpa_supplicant/src/common/bss.h
  17. 0 1
      components/wpa_supplicant/src/common/dpp.h
  18. 21 3
      components/wpa_supplicant/src/common/ieee802_11_common.c
  19. 1 0
      components/wpa_supplicant/src/common/ieee802_11_common.h
  20. 2 0
      components/wpa_supplicant/src/common/scan.c
  21. 529 17
      components/wpa_supplicant/src/common/wpa_common.c
  22. 52 10
      components/wpa_supplicant/src/common/wpa_common.h
  23. 7 5
      components/wpa_supplicant/src/common/wpa_supplicant_i.h
  24. 101 13
      components/wpa_supplicant/src/rsn_supp/wpa.c
  25. 71 87
      components/wpa_supplicant/src/rsn_supp/wpa.h
  26. 900 0
      components/wpa_supplicant/src/rsn_supp/wpa_ft.c
  27. 47 10
      components/wpa_supplicant/src/rsn_supp/wpa_i.h
  28. 2 0
      components/wpa_supplicant/src/utils/common.h
  29. 1 0
      examples/wifi/roaming/main/roaming_example.c
  30. 1 0
      examples/wifi/roaming/sdkconfig.defaults
  31. 0 1
      tools/ci/check_copyright_ignore.txt

+ 0 - 4
components/esp_rom/esp32c2/ld/esp32c2.rom.ld

@@ -2010,7 +2010,6 @@ dbg_hmac_rxtx_statis_dump = 0x40001e84;
 dbg_hmac_statis_dump = 0x40001e88;
 ieee80211_send_action_vendor_spec = 0x40001e8c;
 ieee80211_send_mgmt = 0x40001e90;
-ieee80211_auth_construct = 0x40001e94;
 ieee80211_vnd_lora_ie_size = 0x40001ea0;
 ieee80211_vnd_ie_size = 0x40001ea4;
 ieee80211_add_ssid = 0x40001ea8;
@@ -2032,7 +2031,6 @@ cnx_coexist_timeout = 0x40001ee8;
 sta_recv_mgmt = 0x40001eec;
 ieee80211_send_setup = 0x40001ef0;
 ieee80211_send_probereq = 0x40001ef4;
-sta_auth_open = 0x40001ef8;
 sta_auth_shared = 0x40001efc;
 sta_auth_sae = 0x40001f00;
 cnx_coexist_timeout_process = 0x40001f04;
@@ -2046,7 +2044,6 @@ ieee80211_add_csa = 0x40001f20;
 ieee80211_add_extcap = 0x40001f24;
 ieee80211_regdomain_get_country = 0x40001f28;
 ieee80211_add_countryie = 0x40001f2c;
-ieee80211_alloc_proberesp = 0x40001f30;
 ieee80211_amsdu_adjust_head = 0x40001f34;
 ieee80211_amsdu_adjust_last_length = 0x40001f38;
 ieee80211_amsdu_send_check = 0x40001f3c;
@@ -2078,7 +2075,6 @@ ieee80211_set_max_rate = 0x40001fa4;
 ic_set_sta = 0x40001fa8;
 ieee80211_match_security = 0x40001fac;
 ieee80211_parse_wpa = 0x40001fb0;
-ieee80211_parse_rsn = 0x40001fb4;
 ieee80211_add_assoc_req_ies = 0x40001fb8;
 ieee80211_add_probe_req_ies = 0x40001fbc;
 /* Data (.data, .bss, .rodata) */

+ 2 - 1
components/esp_wifi/include/esp_wifi_types.h

@@ -249,7 +249,8 @@ typedef struct {
     uint32_t rm_enabled:1;        /**< Whether Radio Measurements are enabled for the connection */
     uint32_t btm_enabled:1;       /**< Whether BSS Transition Management is enabled for the connection */
     uint32_t mbo_enabled:1;       /**< Whether MBO is enabled for the connection */
-    uint32_t reserved:29;         /**< Reserved for future feature set */
+    uint32_t ft_enabled:1;        /**< Whether FT is enabled for the connection */
+    uint32_t reserved:28;         /**< Reserved for future feature set */
 } wifi_sta_config_t;
 
 /** @brief Configuration data for ESP32 AP or STA.

+ 1 - 1
components/esp_wifi/lib

@@ -1 +1 @@
-Subproject commit 39fd190dfaa5b41f564bdb3b86519bea7b7255f9
+Subproject commit 3298902a408a9c57a1c3d94d38d7641c7b872d42

+ 16 - 9
components/wpa_supplicant/CMakeLists.txt

@@ -58,6 +58,7 @@ set(srcs "port/os_xtensa.c"
 set(esp_srcs "esp_supplicant/src/esp_wpa2.c"
     "esp_supplicant/src/esp_wpa_main.c"
     "esp_supplicant/src/esp_wpas_glue.c"
+    "esp_supplicant/src/esp_common.c"
     "esp_supplicant/src/esp_wps.c"
     "esp_supplicant/src/esp_wpa3.c")
 if(CONFIG_ESP_WIFI_SOFTAP_SUPPORT)
@@ -147,16 +148,18 @@ else()
     "src/crypto/sha256.c")
 endif()
 
-if(CONFIG_WPA_11KV_SUPPORT)
+if(CONFIG_WPA_11KV_SUPPORT OR CONFIG_WPA_11R_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"
-    "esp_supplicant/src/esp_common.c"
-    "esp_supplicant/src/esp_scan.c"
-    )
+    "esp_supplicant/src/esp_scan.c")
+    if(CONFIG_WPA_11KV_SUPPORT)
+        set(roaming_src ${roaming_src} "src/common/rrm.c" "src/common/wnm_sta.c")
+    endif()
+    if(CONFIG_WPA_11R_SUPPORT)
+        set(roaming_src ${roaming_src} "src/rsn_supp/wpa_ft.c")
+    endif()
 else()
     set(roaming_src "")
 endif()
@@ -180,7 +183,7 @@ idf_component_register(SRCS "${srcs}" ${esp_srcs} "${tls_src}" "${roaming_src}"
                     PRIV_INCLUDE_DIRS src src/utils esp_supplicant/src
                     PRIV_REQUIRES mbedtls esp_timer)
 
-target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-strict-aliasing -Wno-write-strings)
+target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-strict-aliasing -Wno-write-strings -Werror)
 target_compile_definitions(${COMPONENT_LIB} PRIVATE
     __ets__
     ESP_SUPPLICANT
@@ -200,7 +203,6 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE
     CONFIG_ECC
     CONFIG_IEEE80211W
     CONFIG_SHA256
-    CONFIG_WNM
     )
 
 if(CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE)
@@ -221,11 +223,16 @@ endif()
 if(CONFIG_ESP_WIFI_GMAC_SUPPORT)
     target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_GMAC)
 endif()
-
 if(CONFIG_WPA_MBO_SUPPORT)
     target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_MBO)
 endif()
 if(CONFIG_WPA_DPP_SUPPORT)
     target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_DPP)
 endif()
+if(CONFIG_WPA_11KV_SUPPORT)
+    target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_SUPPLICANT_TASK CONFIG_WNM CONFIG_RRM)
+endif()
+if(CONFIG_WPA_11R_SUPPORT)
+    target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_IEEE80211R)
+endif()
 set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 3)

+ 8 - 2
components/wpa_supplicant/Kconfig

@@ -53,7 +53,7 @@ menu "Supplicant"
             Enabling this may cause inter operability issues with some APs.
 
     config WPA_11KV_SUPPORT
-        bool "Enable 802.11k, 802.11v APIs handling"
+        bool "Enable 802.11k, 802.11v APIs Support"
         default n
         help
             Select this option to enable 802.11k 802.11v APIs(RRM and BTM support).
@@ -77,7 +77,7 @@ menu "Supplicant"
             will be flushed immediately.
 
     config WPA_MBO_SUPPORT
-        bool "Enable MBO support"
+        bool "Enable Multi Band Operation Certification Support"
         default n
         select WPA_11KV_SUPPORT
         select WPA_SCAN_CACHE
@@ -91,4 +91,10 @@ menu "Supplicant"
         help
             Select this option to enable WiFi Easy Connect Support.
 
+    config WPA_11R_SUPPORT
+        bool "Enable 802.11R (Fast Transition)"
+        default n
+        help
+            Select this option to enable WiFi Fast Transition Support.
+
 endmenu

+ 231 - 51
components/wpa_supplicant/esp_supplicant/src/esp_common.c

@@ -20,9 +20,13 @@
 #include "common/ieee802_11_common.h"
 #include "esp_rrm.h"
 #include "esp_wnm.h"
+#include "rsn_supp/wpa_i.h"
+#include "rsn_supp/wpa.h"
 
+#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R)
 struct wpa_supplicant g_wpa_supp;
 
+#ifdef CONFIG_SUPPLICANT_TASK
 static TaskHandle_t s_supplicant_task_hdl = NULL;
 static void *s_supplicant_evt_queue = NULL;
 static void *s_supplicant_api_lock = NULL;
@@ -50,7 +54,9 @@ static int handle_action_frm(u8 *frame, size_t len,
 
 	return 0;
 }
+#endif
 
+#if defined(CONFIG_WPA_11KV_SUPPORT)
 static void handle_rrm_frame(struct wpa_supplicant *wpa_s, u8 *sender,
 			     u8 *payload, size_t len, u32 rssi)
 {
@@ -68,7 +74,7 @@ static void handle_rrm_frame(struct wpa_supplicant *wpa_s, u8 *sender,
 	}
 }
 
-static int mgmt_rx_action(u8 *sender, u8 *payload, size_t len, u8 channel, u32 rssi)
+static int mgmt_rx_action(u8 *frame, size_t len, u8 *sender, u32 rssi, u8 channel)
 {
 	u8 category;
 	u8 bssid[ETH_ALEN];
@@ -80,17 +86,19 @@ static int mgmt_rx_action(u8 *sender, u8 *payload, size_t len, u8 channel, u32 r
 		return -1;
 	}
 
-	category = *payload++;
+	category = *frame++;
 	len--;
 	if (category == WLAN_ACTION_WNM) {
-		ieee802_11_rx_wnm_action(wpa_s, sender, payload, len);
+		ieee802_11_rx_wnm_action(wpa_s, sender, frame, len);
 	} else if (category == WLAN_ACTION_RADIO_MEASUREMENT) {
-		handle_rrm_frame(wpa_s, sender, payload, len, rssi);
+		handle_rrm_frame(wpa_s, sender, frame, len, rssi);
 	}
 
 	return 0;
 }
+#endif
 
+#ifdef CONFIG_SUPPLICANT_TASK
 static void btm_rrm_task(void *pvParameters)
 {
 	supplicant_event_t *evt;
@@ -110,7 +118,7 @@ static void btm_rrm_task(void *pvParameters)
 		case SIG_SUPPLICANT_RX_ACTION:
 		{
 			struct ieee_mgmt_frame *frm = (struct ieee_mgmt_frame *)evt->data;
-			mgmt_rx_action(frm->sender, frm->payload, frm->len, frm->channel, frm->rssi);
+			mgmt_rx_action(frm->payload, frm->len, frm->sender, frm->rssi, frm->channel);
 			os_free(frm);
 			break;
 		}
@@ -142,6 +150,7 @@ static void btm_rrm_task(void *pvParameters)
 	/* At this point, we completed */
 	vTaskDelete(NULL);
 }
+#endif
 
 static void clear_bssid_flag(struct wpa_supplicant *wpa_s)
 {
@@ -165,12 +174,13 @@ static void clear_bssid_flag(struct wpa_supplicant *wpa_s)
 	wpa_printf(MSG_DEBUG, "cleared bssid flag");
 }
 
-static void register_action_frame(struct wpa_supplicant *wpa_s)
+static void register_mgmt_frames(struct wpa_supplicant *wpa_s)
 {
 	wpa_s->type &= ~(1 << WLAN_FC_STYPE_ACTION);
 	/* subtype is defined only for action frame */
 	wpa_s->subtype = 0;
 
+#ifdef CONFIG_WPA_11KV_SUPPORT
 	/* current supported features in supplicant: rrm and btm */
 	if (esp_wifi_is_rm_enabled_internal(WIFI_IF_STA))
 		wpa_s->subtype = 1 << WLAN_ACTION_RADIO_MEASUREMENT;
@@ -179,7 +189,15 @@ static void register_action_frame(struct wpa_supplicant *wpa_s)
 
 	if (wpa_s->subtype)
 		wpa_s->type |= 1 << WLAN_FC_STYPE_ACTION;
+#endif
 
+#ifdef CONFIG_IEEE80211R
+	/* register auth/assoc frames if FT is enabled */
+	if (esp_wifi_is_ft_enabled_internal(ESP_IF_WIFI_STA))
+		wpa_s->type |= (1 << WLAN_FC_STYPE_AUTH) |
+				(1 << WLAN_FC_STYPE_ASSOC_RESP) |
+				(1 << WLAN_FC_STYPE_REASSOC_RESP);
+#endif
 	esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype);
 }
 
@@ -204,8 +222,8 @@ static void supplicant_sta_conn_handler(void* arg, esp_event_base_t event_base,
 	ie += sizeof(struct wpa_bss);
 	ieee802_11_parse_elems(wpa_s, ie, bss->ie_len);
 	wpa_bss_flush(wpa_s);
-	/* Register for action frames */
-	register_action_frame(wpa_s);
+	/* Register for mgmt frames */
+	register_mgmt_frames(wpa_s);
 	/* clear set bssid flag */
 	clear_bssid_flag(wpa_s);
 }
@@ -216,7 +234,10 @@ static void supplicant_sta_disconn_handler(void* arg, esp_event_base_t event_bas
 	struct wpa_supplicant *wpa_s = &g_wpa_supp;
 	wifi_event_sta_disconnected_t *disconn = event_data;
 
+#ifdef CONFIG_WPA_11KV_SUPPORT
 	wpas_rrm_reset(wpa_s);
+	wpas_clear_beacon_rep_data(wpa_s);
+#endif
 	if (wpa_s->current_bss) {
 		wpa_s->current_bss = NULL;
 	}
@@ -226,23 +247,79 @@ static void supplicant_sta_disconn_handler(void* arg, esp_event_base_t event_bas
 	}
 }
 
+#ifdef CONFIG_IEEE80211R
+static int handle_auth_frame(u8 *frame, size_t len,
+			     u8 *sender, u32 rssi, u8 channel)
+{
+	if (gWpaSm.key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+		if (gWpaSm.ft_protocol) {
+			if (wpa_ft_process_response(&gWpaSm, frame + 6,
+						    len - 6, 0, sender, NULL, 0) < 0) {
+				wpa_sm_set_ft_params(&gWpaSm, NULL, 0);
+				return -1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int handle_assoc_frame(u8 *frame, size_t len,
+			      u8 *sender, u32 rssi, u8 channel)
+{
+	if (gWpaSm.key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+		if (gWpaSm.ft_protocol) {
+			if (wpa_ft_validate_reassoc_resp(&gWpaSm, frame + 6, len - 6, sender)) {
+				wpa_sm_set_ft_params(&gWpaSm, NULL, 0);
+				return -1;
+			}
+		}
+		wpa_sm_set_ft_params(&gWpaSm, frame + 6, len - 6);
+	}
+	return 0;
+}
+#endif
+
 static int 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 handle_action_frm(frame, len, sender, rssi, channel);
+	int ret = 0;
+
+	switch (type) {
+	case WLAN_FC_STYPE_BEACON:
+	case WLAN_FC_STYPE_PROBE_RESP:
+		ret = esp_handle_beacon_probe(type, frame, len, sender, rssi, channel, current_tsf);
+		break;
+#ifdef CONFIG_IEEE80211R
+	case WLAN_FC_STYPE_AUTH:
+		ret = handle_auth_frame(frame, len, sender, rssi, channel);
+		break;
+	case WLAN_FC_STYPE_ASSOC_RESP:
+	case WLAN_FC_STYPE_REASSOC_RESP:
+		ret = handle_assoc_frame(frame, len, sender, rssi, channel);
+		break;
+#endif
+#if defined(CONFIG_WPA_11KV_SUPPORT)
+	case WLAN_FC_STYPE_ACTION:
+#ifdef CONFIG_SUPPLICANT_TASK
+		ret = handle_action_frm(frame, len, sender, rssi, channel);
+#else
+		ret = mgmt_rx_action(frame, len, sender, rssi, channel);
+#endif
+		break;
+#endif
+	default:
+		ret = -1;
+		break;
 	}
 
-	return -1;
+	return ret;
 }
 
 #ifdef CONFIG_MBO
-static bool bss_profile_match(u8 *sender)
+bool mbo_bss_profile_match(u8 *bssid)
 {
 	/* Incase supplicant wants drivers to skip this BSS, return false */
-	struct wpa_bss *bss = wpa_bss_get_bssid(&g_wpa_supp, sender);
+	struct wpa_bss *bss = wpa_bss_get_bssid(&g_wpa_supp, bssid);
 	if (!bss) {
 		return true;
 	}
@@ -266,8 +343,9 @@ static bool bss_profile_match(u8 *sender)
 int esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
 {
 	struct wpa_supplicant *wpa_s = &g_wpa_supp;
-	int ret;
+	int ret = 0;
 
+#ifdef CONFIG_SUPPLICANT_TASK
 	s_supplicant_api_lock = xSemaphoreCreateRecursiveMutex();
 	if (!s_supplicant_api_lock) {
 		wpa_printf(MSG_ERROR, "%s: failed to create Supplicant API lock", __func__);
@@ -288,10 +366,12 @@ int esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
 		ret = -1;
 		goto err;
 	}
-
-	esp_scan_init(wpa_s);
+#endif
+#ifdef CONFIG_WPA_11KV_SUPPORT
 	wpas_rrm_reset(wpa_s);
 	wpas_clear_beacon_rep_data(wpa_s);
+#endif
+	esp_scan_init(wpa_s);
 
 	esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED,
 			&supplicant_sta_conn_handler, NULL);
@@ -300,14 +380,16 @@ int esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
 
 	wpa_s->type = 0;
 	wpa_s->subtype = 0;
-	esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype);
+#ifdef CONFIG_IEEE80211R
+	wpa_s->type |= (1 << WLAN_FC_STYPE_ASSOC_RESP) | (1 << WLAN_FC_STYPE_REASSOC_RESP) | (1 << WLAN_FC_STYPE_AUTH);
+#endif
+	if (esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype) != ESP_OK) {
+		ret = -1;
+		goto err;
+	}
 	wpa_cb->wpa_sta_rx_mgmt = ieee80211_handle_rx_frm;
-	/* Matching is done only for MBO at the moment, this can be extended for other features*/
 #ifdef CONFIG_MBO
-	wpa_cb->wpa_sta_profile_match = bss_profile_match;
 	dl_list_init(&wpa_s->bss_tmp_disallowed);
-#else
-	wpa_cb->wpa_sta_profile_match = NULL;
 #endif
 	return 0;
 err:
@@ -320,8 +402,10 @@ void esp_supplicant_common_deinit(void)
 	struct wpa_supplicant *wpa_s = &g_wpa_supp;
 
 	esp_scan_deinit(wpa_s);
+#ifdef CONFIG_WPA_11KV_SUPPORT
 	wpas_rrm_reset(wpa_s);
 	wpas_clear_beacon_rep_data(wpa_s);
+#endif
 	esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED,
 			&supplicant_sta_conn_handler);
 	esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED,
@@ -330,6 +414,7 @@ void esp_supplicant_common_deinit(void)
 		wpa_s->type = 0;
 		esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype);
 	}
+#ifdef CONFIG_SUPPLICANT_TASK
 	if (!s_supplicant_task_hdl && esp_supplicant_post_evt(SIG_SUPPLICANT_DEL_TASK, 0) != 0) {
 		if (s_supplicant_evt_queue) {
 			vQueueDelete(s_supplicant_evt_queue);
@@ -339,10 +424,11 @@ void esp_supplicant_common_deinit(void)
 			vSemaphoreDelete(s_supplicant_api_lock);
 			s_supplicant_api_lock = NULL;
 		}
-		wpa_printf(MSG_ERROR, "failed to send task delete event");
 	}
+#endif
 }
 
+#ifdef CONFIG_WPA_11KV_SUPPORT
 int esp_rrm_send_neighbor_rep_request(neighbor_rep_request_cb cb,
 				      void *cb_ctx)
 {
@@ -365,9 +451,6 @@ int esp_wnm_send_bss_transition_mgmt_query(enum btm_query_reason query_reason,
 int esp_mbo_update_non_pref_chan(struct non_pref_chan_s *non_pref_chan)
 {
 	int ret = wpas_mbo_update_non_pref_chan(&g_wpa_supp, non_pref_chan);
-	if (ret == 0) {
-		esp_set_assoc_ie();
-	}
 
 	return ret;
 }
@@ -455,6 +538,24 @@ static size_t get_mbo_oce_assoc_ie(uint8_t *ie, size_t len)
 
 	return mbo_ie_len;
 }
+
+static uint8_t get_operating_class_ie(uint8_t *ie, size_t len)
+{
+	uint8_t op_class_ie[4] = {0};
+	uint8_t op_class_ie_len = 2;
+	uint8_t *pos = op_class_ie;
+
+	*pos++ = WLAN_EID_SUPPORTED_OPERATING_CLASSES;
+	*pos++ = op_class_ie_len;
+#define OPER_CLASS 0x51
+        /* Current Operating Class */
+        *pos++ = OPER_CLASS;
+#undef OPER_CLASS
+        *pos = 0;
+	os_memcpy(ie, op_class_ie, sizeof(op_class_ie));
+
+	return op_class_ie_len + 2;
+}
 #endif
 
 static uint8_t get_extended_caps_ie(uint8_t *ie, size_t len)
@@ -479,27 +580,11 @@ static uint8_t get_extended_caps_ie(uint8_t *ie, size_t len)
 	return ext_caps_ie_len + 2;
 }
 
-
-static uint8_t get_operating_class_ie(uint8_t *ie, size_t len)
-{
-	uint8_t op_class_ie[4] = {0};
-	uint8_t op_class_ie_len = 2;
-	uint8_t *pos = op_class_ie;
-
-	*pos++ = WLAN_EID_SUPPORTED_OPERATING_CLASSES;
-	*pos++ = op_class_ie_len;
-#define OPER_CLASS 0x51
-        /* Current Operating Class */
-        *pos++ = OPER_CLASS;
-#undef OPER_CLASS
-        *pos = 0;
-	os_memcpy(ie, op_class_ie, sizeof(op_class_ie));
-
-	return op_class_ie_len + 2;
-}
+#endif
 
 void esp_set_scan_ie(void)
 {
+#ifdef CONFIG_WPA_11KV_SUPPORT
 #define SCAN_IE_LEN 64
 	uint8_t *ie, *pos;
 	size_t len = SCAN_IE_LEN, ie_len;
@@ -522,40 +607,107 @@ void esp_set_scan_ie(void)
 	esp_wifi_set_appie_internal(WIFI_APPIE_PROBEREQ, ie, SCAN_IE_LEN - len, 0);
 	os_free(ie);
 #undef SCAN_IE_LEN
+#endif
 }
 
-void esp_set_assoc_ie(void)
+#ifdef CONFIG_IEEE80211R
+static size_t add_mdie(uint8_t *bssid, uint8_t *ie, size_t len)
+{
+        size_t mdie_len = 0;
+	struct wpa_sm *sm = &gWpaSm;
+
+	/* Return if MBO IE is not enabled in driver */
+	if (!esp_wifi_is_ft_enabled_internal(WIFI_IF_STA)) {
+		return 0;
+	}
+
+	struct wpa_bss *bss = wpa_bss_get_bssid(&g_wpa_supp, bssid);
+	if (bss && wpa_key_mgmt_ft(sm->key_mgmt)) {
+		const u8 *mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
+
+		if (mdie && mdie[1] >= MOBILITY_DOMAIN_ID_LEN) {
+			const u8 *md = mdie + 2;
+			const u8 *wpa_md = wpa_sm_get_ft_md(sm);
+
+			if (os_memcmp(md, wpa_md,
+				      MOBILITY_DOMAIN_ID_LEN) == 0) {
+				/* Add mobility domain IE */
+				mdie_len = wpa_ft_add_mdie(
+						sm, ie,
+						len, mdie);
+			}
+		}
+	}
+
+	return mdie_len;
+}
+#endif
+
+void esp_set_assoc_ie(uint8_t *bssid, const u8 *ies, size_t ies_len, bool mdie)
 {
 #define ASSOC_IE_LEN 128
 	uint8_t *ie, *pos;
 	size_t len = ASSOC_IE_LEN, ie_len;
 
-	ie = os_malloc(ASSOC_IE_LEN);
+	ie = os_malloc(ASSOC_IE_LEN + ies_len);
 	if (!ie) {
 		wpa_printf(MSG_ERROR, "failed to allocate ie");
 		return;
 	}
 	pos = ie;
+#ifdef CONFIG_WPA_11KV_SUPPORT
 	ie_len = get_extended_caps_ie(pos, len);
 	pos += ie_len;
 	len -= ie_len;
-	ie_len = get_operating_class_ie(pos, len);
-	pos += ie_len;
-	len -= ie_len;
 	ie_len = get_rm_enabled_ie(pos, len);
 	pos += ie_len;
 	len -= ie_len;
 #ifdef CONFIG_MBO
+	ie_len = get_operating_class_ie(pos, len);
+	pos += ie_len;
+	len -= ie_len;
 	ie_len = get_mbo_oce_assoc_ie(pos, len);
 	pos += ie_len;
 	len -= ie_len;
 #endif
-	esp_wifi_unset_appie_internal(WIFI_APPIE_ASSOC_REQ);
+#endif
+#ifdef CONFIG_IEEE80211R
+	if (mdie) {
+		ie_len = add_mdie(bssid, pos, len);
+		pos += ie_len;
+		len -= ie_len;
+	}
+#endif
+	if (ies_len) {
+		os_memcpy(pos, ies, ies_len);
+		pos += ies_len;
+		len -= ies_len;
+	}
 	esp_wifi_set_appie_internal(WIFI_APPIE_ASSOC_REQ, ie, ASSOC_IE_LEN - len, 0);
 	os_free(ie);
 #undef ASSOC_IE_LEN
 }
 
+#ifdef CONFIG_IEEE80211R
+int wpa_sm_update_ft_ies(struct wpa_sm *sm, const u8 *md,
+			 const u8 *ies, size_t ies_len, bool auth_ie)
+{
+	wpa_printf(MSG_INFO, "Updating FT IEs (len=%d)", ies_len);
+	if (os_memcmp(sm->mobility_domain, md, MOBILITY_DOMAIN_ID_LEN) != 0) {
+		return 0;
+	}
+	/* Update auth IEs to be used in FT association */
+	if (auth_ie) {
+		esp_wifi_set_appie_internal(WIFI_APPIE_RAM_STA_AUTH, (u8 *)ies, ies_len, 0);
+	} else {
+		esp_set_assoc_ie(sm->bssid, ies, ies_len, false);
+	}
+	wpa_printf(MSG_INFO, "Updated FT IEs (len=%d) auth_ie=%d", ies_len, auth_ie);
+
+	return 0;
+}
+#endif
+
 void esp_get_tx_power(uint8_t *tx_power)
 {
 #define DEFAULT_MAX_TX_POWER 19 /* max tx power is 19.5 dbm */
@@ -605,6 +757,7 @@ cleanup:
 	return ret;
 }
 
+#ifdef CONFIG_SUPPLICANT_TASK
 int esp_supplicant_post_evt(uint32_t evt_id, uint32_t data)
 {
 	supplicant_event_t *evt = os_zalloc(sizeof(supplicant_event_t));
@@ -631,3 +784,30 @@ int esp_supplicant_post_evt(uint32_t evt_id, uint32_t data)
 	}
 	return 0;
 }
+#endif
+#else
+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;
+}
+
+int esp_mbo_update_non_pref_chan(struct non_pref_chan_s *non_pref_chan)
+{
+	return -1;
+}
+void esp_set_scan_ie(void) { }
+void esp_set_assoc_ie(uint8_t *bssid, const u8 *ies, size_t ies_len, bool mdie) { }
+int esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
+{
+	return 0;
+}
+void esp_supplicant_common_deinit(void) { }
+#endif

+ 8 - 30
components/wpa_supplicant/esp_supplicant/src/esp_common_i.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -10,8 +10,9 @@
 #include "utils/includes.h"
 
 struct wpa_funcs;
+extern struct wpa_supplicant g_wpa_supp;
 
-#ifdef ROAMING_SUPPORT
+#ifdef CONFIG_WPA_11KV_SUPPORT
 struct ieee_mgmt_frame {
 	u8 sender[ETH_ALEN];
 	u8 channel;
@@ -38,35 +39,12 @@ enum SIG_SUPPLICANT {
 
 int esp_supplicant_post_evt(uint32_t evt_id, uint32_t data);
 void esp_get_tx_power(uint8_t *tx_power);
+#ifdef CONFIG_MBO
+bool mbo_bss_profile_match(u8 *bssid);
+#endif
+#endif
 int esp_supplicant_common_init(struct wpa_funcs *wpa_cb);
 void esp_supplicant_common_deinit(void);
 void esp_set_scan_ie(void);
-void esp_set_assoc_ie(void);
-#else
-
-#include "esp_rrm.h"
-#include "esp_wnm.h"
-#include "esp_mbo.h"
-
-static inline void esp_set_scan_ie(void) { }
-static inline void esp_set_assoc_ie(void) { }
-
-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;
-}
-
-int esp_mbo_update_non_pref_chan(struct non_pref_chan_s *non_pref_chan)
-{
-	return -1;
-}
-#endif
+void esp_set_assoc_ie(uint8_t *bssid, const u8 *ies, size_t ies_len, bool add_mdie);
 #endif

+ 6 - 1
components/wpa_supplicant/esp_supplicant/src/esp_scan.c

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -18,6 +18,7 @@
 #include "common/rrm.h"
 #include "common/ieee802_11_common.h"
 #include "esp_common_i.h"
+#include "esp_scan_i.h"
 #include "common/wnm_sta.h"
 #include "esp_scan_i.h"
 
@@ -36,6 +37,7 @@ static void scan_done_event_handler(void *arg, STATUS status)
 	esp_supplicant_handle_scan_done_evt();
 }
 
+#if defined(CONFIG_WPA_11KV_SUPPORT)
 static void handle_wnm_scan_done(struct wpa_supplicant *wpa_s)
 {
 	struct wpa_bss *bss = wpa_bss_get_next_bss(wpa_s, wpa_s->current_bss);
@@ -53,6 +55,7 @@ static void handle_wnm_scan_done(struct wpa_supplicant *wpa_s)
 		}
 	}
 }
+#endif
 
 static void scan_done_cleanup(struct wpa_supplicant *wpa_s)
 {
@@ -70,12 +73,14 @@ void esp_supplicant_handle_scan_done_evt(void)
 	struct wpa_supplicant *wpa_s = &g_wpa_supp;
 
 	wpa_printf(MSG_INFO, "scan done received");
+#if defined(CONFIG_WPA_11KV_SUPPORT)
 	/* 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) {
 		handle_wnm_scan_done(wpa_s);
 	}
+#endif
 	if (wpa_s->scanning) {
 		scan_done_cleanup(wpa_s);
 	}

+ 8 - 3
components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h

@@ -49,7 +49,11 @@ typedef enum {
 
 /* wifi_appie_t is in rom code and can't be changed anymore, use wifi_appie_ram_t for new app IEs */
 typedef enum {
-    WIFI_APPIE_RAM_MAX = WIFI_APPIE_MAX,
+    WIFI_APPIE_RAM_BEACON = WIFI_APPIE_MAX,
+    WIFI_APPIE_RAM_PROBE_RSP,
+    WIFI_APPIE_RAM_STA_AUTH,
+    WIFI_APPIE_RAM_AP_AUTH,
+    WIFI_APPIE_RAM_MAX
 } wifi_appie_ram_t;
 
 enum {
@@ -66,7 +70,8 @@ enum {
     WAPI_AUTH_PSK       = 0x0b,
     WAPI_AUTH_CERT      = 0x0c,
     WPA2_AUTH_ENT_SHA384_SUITE_B = 0x0d,
-    WPA2_AUTH_INVALID   = 0x0e,
+    WPA2_AUTH_FT_PSK    = 0x0e,
+    WPA2_AUTH_INVALID
 };
 
 typedef enum {
@@ -129,7 +134,6 @@ struct wpa_funcs {
     int (*wpa3_parse_sae_msg)(uint8_t *buf, size_t len, uint32_t type, uint16_t status);
     int (*wpa_sta_rx_mgmt)(u8 type, u8 *frame, size_t len, u8 *sender, u32 rssi, u8 channel, u64 current_tsf);
     void (*wpa_config_done)(void);
-    bool (*wpa_sta_profile_match)(u8 *bssid);
 };
 
 struct wpa2_funcs {
@@ -269,5 +273,6 @@ esp_err_t esp_wifi_remain_on_channel(uint8_t ifx, uint8_t type, uint8_t channel,
                                      uint32_t wait_time_ms, wifi_action_rx_cb_t rx_cb);
 bool esp_wifi_is_mbo_enabled_internal(uint8_t if_index);
 void esp_wifi_get_pmf_config_internal(wifi_pmf_config_t *pmf_cfg, uint8_t ifx);
+bool esp_wifi_is_ft_enabled_internal(uint8_t if_index);
 
 #endif /* _ESP_WIFI_DRIVER_H_ */

+ 8 - 21
components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -66,8 +66,10 @@ void  wpa_deauthenticate(u8 reason_code)
     esp_wifi_deauthenticate_internal(reason_code);
 }
 
-int  wpa_config_profile(void)
+int  wpa_config_profile(uint8_t *bssid)
 {
+    int ret = 0;
+
     if (esp_wifi_sta_prof_is_wpa_internal()) {
         wpa_set_profile(WPA_PROTO_WPA, esp_wifi_sta_get_prof_authmode_internal());
     } else if (esp_wifi_sta_prof_is_wpa2_internal() || esp_wifi_sta_prof_is_wpa3_internal()) {
@@ -75,10 +77,10 @@ int  wpa_config_profile(void)
     } else if (esp_wifi_sta_prof_is_wapi_internal()) {
         wpa_set_profile(WPA_PROTO_WAPI, esp_wifi_sta_get_prof_authmode_internal());
     } else {
-        /* do nothing */
-        return -1;
+        ret = -1;
     }
-    return 0;
+
+    return ret;
 }
 
 int wpa_config_bss(uint8_t *bssid)
@@ -116,7 +118,6 @@ bool  wpa_attach(void)
         ret = (esp_wifi_register_tx_cb_internal(eapol_txcb, WIFI_TXCB_EAPOL_ID) == ESP_OK);
     }
     esp_set_scan_ie();
-    esp_set_assoc_ie();
     return ret;
 }
 
@@ -169,7 +170,7 @@ int wpa_sta_connect(uint8_t *bssid)
 {
     /* use this API to set AP specific IEs during connection */
     int ret = 0;
-    ret = wpa_config_profile();
+    ret = wpa_config_profile(bssid);
     if (ret == 0) {
         ret = wpa_config_bss(bssid);
         if (ret) {
@@ -184,7 +185,6 @@ int wpa_sta_connect(uint8_t *bssid)
 void wpa_config_done(void)
 {
     /* used in future for setting scan and assoc IEs */
-    esp_set_assoc_ie();
 }
 
 int wpa_parse_wpa_ie_wrapper(const u8 *wpa_ie, size_t wpa_ie_len, wifi_wpa_ie_t *data)
@@ -225,19 +225,6 @@ static void wpa_sta_disconnected_cb(uint8_t reason_code)
     }
 }
 
-#ifndef ROAMING_SUPPORT
-static inline int esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
-{
-	wpa_cb->wpa_sta_rx_mgmt = NULL;
-	wpa_cb->wpa_sta_profile_match = NULL;
-
-	return 0;
-}
-static inline void esp_supplicant_common_deinit(void)
-{
-}
-#endif
-
 int esp_supplicant_init(void)
 {
     int ret = ESP_OK;

+ 2 - 2
components/wpa_supplicant/include/utils/wpa_debug.h

@@ -159,8 +159,8 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
 #define wpa_dbg(...) do {} while(0)
 #endif
 
-#define wpa_auth_logger
-#define wpa_auth_vlogger
+#define wpa_auth_logger(...) do {} while(0)
+#define wpa_auth_vlogger(...) do {} while(0)
 
 /**
  * wpa_msg - Conditional printf for default target and ctrl_iface monitors

+ 5 - 17
components/wpa_supplicant/port/include/supplicant_opt.h

@@ -1,16 +1,8 @@
-// Copyright 2019 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.
+/*
+ * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 
 #ifndef _SUPPLICANT_OPT_H
 #define _SUPPLICANT_OPT_H
@@ -29,10 +21,6 @@
 #define DEBUG_PRINT
 #endif
 
-#if CONFIG_WPA_11KV_SUPPORT
-#define ROAMING_SUPPORT 1
-#endif
-
 #if CONFIG_WPA_SCAN_CACHE
 #define SCAN_CACHE_SUPPORTED
 #endif

+ 47 - 42
components/wpa_supplicant/src/ap/wpa_auth.c

@@ -39,12 +39,12 @@ static int wpa_sm_step(struct wpa_state_machine *sm);
 static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
 			      size_t data_len);
 static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
-                  struct wpa_group *group);
+			      struct wpa_group *group);
 static void wpa_request_new_ptk(struct wpa_state_machine *sm);
 static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
-              struct wpa_group *group);
+			  struct wpa_group *group);
 static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
-                       struct wpa_group *group);
+				       struct wpa_group *group);
 
 static const u32 dot11RSNAConfigGroupUpdateCount = 4;
 static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
@@ -221,7 +221,7 @@ static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
 static int wpa_use_aes_cmac(struct wpa_state_machine *sm)
 {
     int ret = 0;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
     if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
         ret = 1;
 #endif /* CONFIG_IEEE80211R */
@@ -365,7 +365,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
         return NULL;
     }
 
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
     wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
     if (wpa_auth->ft_pmk_cache == NULL) {
         wpa_printf( MSG_ERROR, "FT PMK cache initialization failed.");
@@ -374,7 +374,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
         os_free(wpa_auth);
         return NULL;
     }
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
 
     return wpa_auth;
 }
@@ -402,14 +402,14 @@ int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
     if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
         return -1;
 
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
     if (sm->ft_completed) {
         wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
                 "FT authentication already completed - do not "
                 "start 4-way handshake");
         return 0;
     }
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
 
     if (sm->started) {
         memset(&sm->key_replay, 0, sizeof(sm->key_replay));
@@ -447,9 +447,10 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
         sm->group->GKeyDoneStations--;
         sm->GUpdateStationKeys = FALSE;
     }
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
     os_free(sm->assoc_resp_ftie);
-#endif /* CONFIG_IEEE80211R */
+    wpabuf_free(sm->ft_pending_req_ies);
+#endif /* CONFIG_IEEE80211R_AP */
     wpa_printf( MSG_DEBUG, "wpa_free_sta_sm: free eapol=%p\n", sm->last_rx_eapol_key);
     os_free(sm->last_rx_eapol_key);
     os_free(sm->wpa_ie);
@@ -513,7 +514,7 @@ static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr,
     }
 }
 
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
 static int ICACHE_FLASH_ATTR ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
                    struct wpa_state_machine *sm,
                    struct wpa_eapol_ie_parse *kde)
@@ -560,7 +561,7 @@ static int ICACHE_FLASH_ATTR ft_check_msg_2_of_4(struct wpa_authenticator *wpa_a
 
     return 0;
 }
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
 
 static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
                     struct wpa_state_machine *sm, int group)
@@ -786,12 +787,12 @@ continue_processing:
             wpa_sta_disconnect(wpa_auth, sm->addr);
             return;
         }
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
         if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
             wpa_sta_disconnect(wpa_auth, sm->addr);
             return;
         }
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
         break;
     case PAIRWISE_4:
         if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
@@ -1095,25 +1096,28 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
                 buf, key_data_len);
         if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
             version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
-            if (aes_wrap(sm->PTK.kek, 16, (key_data_len - 8) / 8, buf,
+            if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, (key_data_len - 8) / 8, buf,
                     (u8 *) (key + 1))) {
                 os_free(hdr);
                 os_free(buf);
                 return;
             }
             WPA_PUT_BE16(key->key_data_length, key_data_len);
-        } else {
+        } else if (sm->PTK.kek_len == 16) {
             u8 ek[32];
             memcpy(key->key_iv,
                   sm->group->Counter + WPA_NONCE_LEN - 16, 16);
             inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
             memcpy(ek, key->key_iv, 16);
-            memcpy(ek + 16, sm->PTK.kek, 16);
+            memcpy(ek + 16, sm->PTK.kek, sm->PTK.kek_len);
             memcpy(key + 1, buf, key_data_len);
             rc4_skip(ek, 32, 256, (u8 *) (key + 1), key_data_len);
             WPA_PUT_BE16(key->key_data_length, key_data_len);
+        } else {
+            os_free(buf);
+            os_free(hdr);
+            return;
         }
-        os_free(buf);
     }
 
     if (key_info & WPA_KEY_INFO_MIC) {
@@ -1280,7 +1284,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
         sm->ReAuthenticationRequest = TRUE;
         break;
     case WPA_ASSOC_FT:
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
         wpa_printf( MSG_DEBUG, "FT: Retry PTK configuration "
                "after association");
         wpa_ft_install_ptk(sm);
@@ -1288,14 +1292,14 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
         /* Using FT protocol, not WPA auth state machine */
         sm->ft_completed = 1;
         return 0;
-#else /* CONFIG_IEEE80211R */
+#else /* CONFIG_IEEE80211R_AP */
         break;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
     }
 
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
     sm->ft_completed = 0;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
 
 #ifdef CONFIG_IEEE80211W
     if (sm->mgmt_frame_prot && event == WPA_AUTH)
@@ -1438,20 +1442,20 @@ SM_STATE(WPA_PTK, INITPMK)
     size_t len = 2 * PMK_LEN;
 
     SM_ENTRY_MA(WPA_PTK, INITPMK, wpa_ptk);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
     sm->xxkey_len = 0;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
 
     if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) {
         wpa_printf( MSG_DEBUG, "WPA: PMK from EAPOL state machine "
                "(len=%lu)", (unsigned long) len);
         memcpy(sm->PMK, msk, PMK_LEN);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
         if (len >= 2 * PMK_LEN) {
             memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
             sm->xxkey_len = PMK_LEN;
         }
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
     } else {
         wpa_printf( MSG_DEBUG, "WPA: Could not get PMK");
     }
@@ -1476,10 +1480,10 @@ SM_STATE(WPA_PTK, INITPSK)
     psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL);
     if (psk) {
         memcpy(sm->PMK, psk, PMK_LEN);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
         memcpy(sm->xxkey, psk, PMK_LEN);
         sm->xxkey_len = PMK_LEN;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
     }
     sm->req_replay_counter_used = 0;
 }
@@ -1532,12 +1536,13 @@ SM_STATE(WPA_PTK, PTKSTART)
 static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
 			  const u8 *pmk, struct wpa_ptk *ptk)
 {
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
     size_t ptk_len = sm->pairwise != WPA_CIPHER_TKIP ? 48 : 64;
 
+    size_t ptk_len = sm->pairwise != WPA_CIPHER_TKIP ? 48 : 64;
     if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
-        return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
-#endif /* CONFIG_IEEE80211R */
+        return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
+#endif /* CONFIG_IEEE80211R_AP */
 
     return wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
                   sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
@@ -1592,7 +1597,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
         return;
     }
 
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
     if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
         /*
          * Verify that PMKR1Name from EAPOL-Key message 2/4 matches
@@ -1608,7 +1613,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
             return;
         }
     }
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
 
     sm->pending_1_of_4_timeout = 0;
     eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
@@ -1763,12 +1768,12 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
     kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
     if (gtk)
         kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
     if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
         kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */
         kde_len += 300; /* FTIE + 2 * TIE */
     }
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
     kde = (u8 *)os_malloc(kde_len);
     if (kde == NULL)
         return;
@@ -1776,7 +1781,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
     pos = kde;
     memcpy(pos, wpa_ie, wpa_ie_len);
     pos += wpa_ie_len;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
     if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
         int res = wpa_insert_pmkid(kde, pos - kde, sm->pmk_r1_name);
         if (res < 0) {
@@ -1787,7 +1792,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
         }
         pos += res;
     }
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
     if (gtk) {
         u8 hdr[2];
         hdr[0] = keyidx & 0x03;
@@ -1797,7 +1802,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
     }
     pos = ieee80211w_kde_add(sm, pos);
 
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
     if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
         int res;
         struct wpa_auth_config *conf;
@@ -1829,7 +1834,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
         WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60);
         pos += 4;
     }
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
 
     wpa_send_eapol(sm->wpa_auth, sm,
                (secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC |
@@ -1889,9 +1894,9 @@ SM_STATE(WPA_PTK, PTKINITDONE)
 {
     esp_wifi_wpa_ptk_init_done_internal(sm->addr);
 }
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
     wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr);
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
 }
 
 

+ 22 - 5
components/wpa_supplicant/src/ap/wpa_auth_i.h

@@ -1,6 +1,6 @@
 /*
  * hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -83,7 +83,7 @@ struct wpa_state_machine {
 	unsigned int mgmt_frame_prot:1;
 	unsigned int rx_eapol_key_secure:1;
 	unsigned int update_snonce:1;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
 	unsigned int ft_completed:1;
 	unsigned int pmk_r1_name_valid:1;
 #endif /* CONFIG_IEEE80211R */
@@ -103,9 +103,12 @@ struct wpa_state_machine {
 	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
 	int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */
 
-#ifdef CONFIG_IEEE80211R
-	u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
+#ifdef CONFIG_IEEE80211R_AP
+	u8 xxkey[PMK_LEN_MAX]; /* PSK or the second 256 bits of MSK, or the
+				* first 384 bits of MSK */
 	size_t xxkey_len;
+	u8 pmk_r1[PMK_LEN_MAX];
+	unsigned int pmk_r1_len;
 	u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth
 					   * Request */
 	u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */
@@ -113,7 +116,17 @@ struct wpa_state_machine {
 	u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key
 					       * message 2/4 */
 	u8 *assoc_resp_ftie;
-#endif /* CONFIG_IEEE80211R */
+
+	void (*ft_pending_cb)(void *ctx, const u8 *dst, const u8 *bssid,
+			      u16 auth_transaction, u16 status,
+			      const u8 *ies, size_t ies_len);
+	void *ft_pending_cb_ctx;
+	struct wpabuf *ft_pending_req_ies;
+	u8 ft_pending_pull_nonce[FT_RRB_NONCE_LEN];
+	u8 ft_pending_auth_transaction;
+	u8 ft_pending_current_ap[ETH_ALEN];
+	int ft_pending_pull_left_retries;
+#endif /* CONFIG_IEEE80211R_AP */
 
 	int pending_1_of_4_timeout;
 	u32 index;
@@ -165,6 +178,10 @@ struct wpa_authenticator {
 	size_t wpa_ie_len;
 
 	u8 addr[ETH_ALEN];
+#ifdef CONFIG_IEEE80211R
+	struct rsn_pmksa_cache *pmksa;
+	struct wpa_ft_pmk_cache *ft_pmk_cache;
+#endif
 
 };
 

+ 12 - 12
components/wpa_supplicant/src/ap/wpa_auth_ie.c

@@ -160,7 +160,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
 		pos += RSN_SELECTOR_LEN;
 		num_suites++;
 	}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
 		pos += RSN_SELECTOR_LEN;
@@ -171,7 +171,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
 		pos += RSN_SELECTOR_LEN;
 		num_suites++;
 	}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
 #ifdef CONFIG_IEEE80211W
 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
@@ -314,7 +314,7 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
 			return res;
 		pos += res;
 	}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
 	if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
 		res = wpa_write_mdie(&wpa_auth->conf, pos,
 				     buf + sizeof(buf) - pos);
@@ -322,7 +322,7 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
 			return res;
 		pos += res;
 	}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
 	if (wpa_auth->conf.wpa & WPA_PROTO_WPA) {
 		res = wpa_write_wpa_ie(&wpa_auth->conf,
 				       pos, buf + sizeof(buf) - pos);
@@ -392,12 +392,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 		selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
 		if (0) {
 		}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
 		else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
 			selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
 		else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
 			selector = RSN_AUTH_KEY_MGMT_FT_PSK;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
 #ifdef CONFIG_IEEE80211W
 		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
 			selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
@@ -467,12 +467,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 	}
 	if (0) {
 	}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
 	else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
 	else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
 #ifdef CONFIG_IEEE80211W
 	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
 		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
@@ -542,7 +542,7 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 		sm->mgmt_frame_prot = 1;
 #endif /* CONFIG_IEEE80211W */
 
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
 		if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
 			wpa_printf( MSG_DEBUG, "RSN: Trying to use FT, but "
@@ -556,7 +556,7 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 			return WPA_INVALID_MDIE;
 		}
 	}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
 
 	if (ciphers & WPA_CIPHER_CCMP)
 		sm->pairwise = WPA_CIPHER_CCMP;
@@ -700,14 +700,14 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
 		if (*pos == WLAN_EID_RSN) {
 			ie->rsn_ie = pos;
 			ie->rsn_ie_len = pos[1] + 2;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
 		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
 			ie->mdie = pos;
 			ie->mdie_len = pos[1] + 2;
 		} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
 			ie->ftie = pos;
 			ie->ftie_len = pos[1] + 2;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
 		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
 			ret = wpa_parse_generic(pos, end, ie);
 			if (ret < 0)

+ 1 - 0
components/wpa_supplicant/src/common/bss.h

@@ -10,6 +10,7 @@
 #define BSS_H
 
 struct wpa_scan_res;
+struct wpa_supplicant;
 
 /**
  * struct wpa_bss - BSS table

+ 0 - 1
components/wpa_supplicant/src/common/dpp.h

@@ -25,7 +25,6 @@ struct dpp_global;
 
 #define DPP_HDR_LEN (4 + 2) /* OUI, OUI Type, Crypto Suite, DPP frame type */
 #define DPP_TCP_PORT 7871
-#define SSID_MAX_LEN 32
 #define PMKID_LEN 16
 #define PMK_LEN 32
 #define PMK_LEN_SUITE_B_192 48

+ 21 - 3
components/wpa_supplicant/src/common/ieee802_11_common.c

@@ -6,9 +6,9 @@
  * See README for more details.
  */
 
-#include "utils/includes.h"
+#include "includes.h"
 
-#include "utils/common.h"
+#include "common.h"
 #include "defs.h"
 #include "ieee802_11_defs.h"
 #include "ieee802_11_common.h"
@@ -37,6 +37,22 @@ const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
 	return NULL;
 }
 
+int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
+{
+	const struct element *elem;
+	int count = 0;
+
+	if (ies == NULL)
+		return 0;
+
+	for_each_element(elem, ies, ies_len)
+		count++;
+
+	return count;
+}
+
+
+
 const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type)
 {
 	const struct element *elem;
@@ -50,6 +66,7 @@ const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type)
 	return NULL;
 }
 
+
 size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
 {
 	/*
@@ -184,6 +201,7 @@ int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
  */
 int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t len)
 {
+#ifdef CONFIG_RRM
 	const struct element *elem;
 
 	if (!start)
@@ -192,7 +210,6 @@ int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t
 	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);
@@ -207,6 +224,7 @@ int ieee802_11_parse_elems(struct wpa_supplicant *wpa_s, const u8 *start, size_t
 
 		}
 	}
+#endif
 	return 0;
 }
 

+ 1 - 0
components/wpa_supplicant/src/common/ieee802_11_common.h

@@ -42,4 +42,5 @@ int ieee802_11_ext_capab(const u8 *ie, unsigned int capab);
 const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type);
 size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len);
 u8 get_operating_class(u8 chan, int sec_channel);
+int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
 #endif /* IEEE802_11_COMMON_H */

+ 2 - 0
components/wpa_supplicant/src/common/scan.c

@@ -46,12 +46,14 @@ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
 		wpa_printf(MSG_ERROR, "Memory allocation failed");
 		return;
 	}
+#ifdef CONFIG_WNM
 	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;
 	}
+#endif
 	if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
 		/* Use the same memory */
 		params->bssid = wpa_s->next_scan_bssid;

+ 529 - 17
components/wpa_supplicant/src/common/wpa_common.c

@@ -1,15 +1,9 @@
 /*
  * WPA/RSN - Shared functions for supplicant and authenticator
- * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi>
  *
- * 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.
  */
  #ifdef ESP_SUPPLICANT
 
@@ -25,8 +19,221 @@
 #include "crypto/md5.h"
 #include "crypto/aes.h"
 #include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
 
 #define MD5_MAC_LEN 16
+#ifdef CONFIG_IEEE80211R
+int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
+               const u8 *ap_addr, u8 transaction_seqnum,
+               const u8 *mdie, size_t mdie_len,
+	       const u8 *ftie, size_t ftie_len,
+	       const u8 *rsnie, size_t rsnie_len,
+	       const u8 *ric, size_t ric_len, u8 *mic)
+{
+	u8 *buf, *pos;
+	size_t buf_len;
+
+	if (kck_len != 16) {
+		wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
+				(unsigned int) kck_len);
+		return -1;
+	}
+
+	buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
+	buf = os_malloc(buf_len);
+	if (buf == NULL)
+		return -1;
+
+	pos = buf;
+	os_memcpy(pos, sta_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+	os_memcpy(pos, ap_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+	*pos++ = transaction_seqnum;
+	if (rsnie) {
+		os_memcpy(pos, rsnie, rsnie_len);
+		pos += rsnie_len;
+	}
+	if (mdie) {
+		os_memcpy(pos, mdie, mdie_len);
+		pos += mdie_len;
+	}
+	if (ftie) {
+		struct rsn_ftie *_ftie;
+		os_memcpy(pos, ftie, ftie_len);
+		if (ftie_len < 2 + sizeof(*_ftie)) {
+			os_free(buf);
+			return -1;
+		}
+		_ftie = (struct rsn_ftie *) (pos + 2);
+		os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
+		pos += ftie_len;
+	}
+	if (ric) {
+		os_memcpy(pos, ric, ric_len);
+		pos += ric_len;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
+	if (omac1_aes_128(kck, buf, pos - buf, mic)) {
+		os_free(buf);
+		return -1;
+	}
+
+	os_free(buf);
+
+	return 0;
+}
+
+
+static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
+			     struct wpa_ft_ies *parse)
+{
+	const u8 *end, *pos;
+
+	parse->ftie = ie;
+	parse->ftie_len = ie_len;
+
+	pos = ie + sizeof(struct rsn_ftie);
+	end = ie + ie_len;
+
+	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+		switch (pos[0]) {
+		case FTIE_SUBELEM_R1KH_ID:
+			if (pos[1] != FT_R1KH_ID_LEN) {
+				wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
+					   "length in FTIE: %d", pos[1]);
+				return -1;
+			}
+			parse->r1kh_id = pos + 2;
+			break;
+		case FTIE_SUBELEM_GTK:
+			parse->gtk = pos + 2;
+			parse->gtk_len = pos[1];
+			break;
+		case FTIE_SUBELEM_R0KH_ID:
+			if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
+				wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
+					   "length in FTIE: %d", pos[1]);
+				return -1;
+			}
+			parse->r0kh_id = pos + 2;
+			parse->r0kh_id_len = pos[1];
+			break;
+#ifdef CONFIG_IEEE80211W
+		case FTIE_SUBELEM_IGTK:
+			parse->igtk = pos + 2;
+			parse->igtk_len = pos[1];
+			break;
+#endif /* CONFIG_IEEE80211W */
+		}
+
+		pos += 2 + pos[1];
+	}
+
+	return 0;
+}
+
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
+		     struct wpa_ft_ies *parse)
+{
+	const u8 *end, *pos;
+	struct wpa_ie_data data;
+	int ret;
+	const struct rsn_ftie *ftie;
+	int prot_ie_count = 0;
+
+	os_memset(parse, 0, sizeof(*parse));
+	if (ies == NULL)
+		return 0;
+
+	pos = ies;
+	end = ies + ies_len;
+	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+		switch (pos[0]) {
+		case WLAN_EID_RSN:
+			parse->rsn = pos + 2;
+			parse->rsn_len = pos[1];
+			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
+						   parse->rsn_len + 2,
+						   &data);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
+					   "RSN IE: %d", ret);
+				return -1;
+			}
+			if (data.num_pmkid == 1 && data.pmkid)
+				parse->rsn_pmkid = data.pmkid;
+			break;
+		case WLAN_EID_MOBILITY_DOMAIN:
+			parse->mdie = pos + 2;
+			parse->mdie_len = pos[1];
+			break;
+		case WLAN_EID_FAST_BSS_TRANSITION:
+			if (pos[1] < sizeof(*ftie))
+				return -1;
+			ftie = (const struct rsn_ftie *) (pos + 2);
+			prot_ie_count = ftie->mic_control[1];
+			if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
+				return -1;
+			break;
+		case WLAN_EID_TIMEOUT_INTERVAL:
+			parse->tie = pos + 2;
+			parse->tie_len = pos[1];
+			break;
+		case WLAN_EID_RIC_DATA:
+			if (parse->ric == NULL)
+				parse->ric = pos;
+			break;
+		}
+
+		pos += 2 + pos[1];
+	}
+
+	if (prot_ie_count == 0)
+		return 0; /* no MIC */
+
+	/*
+	 * Check that the protected IE count matches with IEs included in the
+	 * frame.
+	 */
+	if (parse->rsn)
+		prot_ie_count--;
+	if (parse->mdie)
+		prot_ie_count--;
+	if (parse->ftie)
+		prot_ie_count--;
+	if (prot_ie_count < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
+			   "the protected IE count");
+		return -1;
+	}
+
+	if (prot_ie_count == 0 && parse->ric) {
+		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
+			   "included in protected IE count");
+		return -1;
+	}
+
+	/* Determine the end of the RIC IE(s) */
+	pos = parse->ric;
+	while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
+	       prot_ie_count) {
+		prot_ie_count--;
+		pos += 2 + pos[1];
+	}
+	parse->ric_len = pos - parse->ric;
+	if (prot_ie_count) {
+		wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
+			   "frame", (int) prot_ie_count);
+		return -1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IEEE80211R */
+
 
 static unsigned int wpa_kck_len(int akmp)
 {
@@ -113,6 +320,10 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192)
 		return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
 #endif
+#ifdef CONFIG_WPA3_SAE
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
+		return WPA_KEY_MGMT_SAE;
+#endif /* CONFIG_WPA3_SAE */
 	return 0;
 }
 
@@ -164,7 +375,7 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
 	int left;
 	int i, count;
 
-	memset(data, 0, sizeof(*data));
+	os_memset(data, 0, sizeof(*data));
 	data->proto = WPA_PROTO_RSN;
 	data->pairwise_cipher = WPA_CIPHER_CCMP;
 	data->group_cipher = WPA_CIPHER_CCMP;
@@ -181,10 +392,10 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
 	}
 
 	if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
-	    #ifdef DEBUG_PRINT
+#ifdef DEBUG_PRINT
 		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
 			   __func__, (unsigned long) rsn_ie_len);
-	    #endif
+#endif
 		return -1;
 	}
 
@@ -193,10 +404,10 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
 	if (hdr->elem_id != WLAN_EID_RSN ||
 	    hdr->len != rsn_ie_len - 2 ||
 	    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
-	    #ifdef DEBUG_PRINT
+#ifdef DEBUG_PRINT
 		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
 			   __func__);
-	     #endif
+#endif
 		return -2;
 	}
 
@@ -208,10 +419,10 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
 		pos += RSN_SELECTOR_LEN;
 		left -= RSN_SELECTOR_LEN;
 	} else if (left > 0) {
-	    #ifdef DEBUG_PRINT
+#ifdef DEBUG_PRINT
 		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
 			   __func__, left);
-	     #endif
+#endif
 		return -3;
 	}
 
@@ -423,6 +634,194 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
 	return 0;
 }
 
+#ifdef CONFIG_IEEE80211R
+
+/**
+ * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.3
+ */
+void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+		       const u8 *ssid, size_t ssid_len,
+		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
+{
+	u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
+	       FT_R0KH_ID_MAX_LEN + ETH_ALEN];
+	u8 *pos, r0_key_data[48], hash[32];
+	const u8 *addr[2];
+	size_t len[2];
+
+	/*
+	 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
+	 *                       SSIDlength || SSID || MDID || R0KHlength ||
+	 *                       R0KH-ID || S0KH-ID)
+	 * XXKey is either the second 256 bits of MSK or PSK.
+	 * PMK-R0 = L(R0-Key-Data, 0, 256)
+	 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
+	 */
+	if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
+		return;
+	pos = buf;
+	*pos++ = ssid_len;
+	os_memcpy(pos, ssid, ssid_len);
+	pos += ssid_len;
+	os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
+	pos += MOBILITY_DOMAIN_ID_LEN;
+	*pos++ = r0kh_id_len;
+	os_memcpy(pos, r0kh_id, r0kh_id_len);
+	pos += r0kh_id_len;
+	os_memcpy(pos, s0kh_id, ETH_ALEN);
+	pos += ETH_ALEN;
+
+	sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+		   r0_key_data, sizeof(r0_key_data));
+	os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
+
+	/*
+	 * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
+	 */
+	addr[0] = (const u8 *) "FT-R0N";
+	len[0] = 6;
+	addr[1] = r0_key_data + PMK_LEN;
+	len[1] = 16;
+
+	sha256_vector(2, addr, len, hash);
+	os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
+}
+
+
+/**
+ * wpa_derive_pmk_r1_name - Derive PMKR1Name
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.4
+ */
+void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+			    const u8 *s1kh_id, u8 *pmk_r1_name)
+{
+	u8 hash[32];
+	const u8 *addr[4];
+	size_t len[4];
+
+	/*
+	 * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
+	 *                               R1KH-ID || S1KH-ID))
+	 */
+	addr[0] = (const u8 *) "FT-R1N";
+	len[0] = 6;
+	addr[1] = pmk_r0_name;
+	len[1] = WPA_PMK_NAME_LEN;
+	addr[2] = r1kh_id;
+	len[2] = FT_R1KH_ID_LEN;
+	addr[3] = s1kh_id;
+	len[3] = ETH_ALEN;
+
+	sha256_vector(4, addr, len, hash);
+	os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
+}
+
+
+/**
+ * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.4
+ */
+void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+		      const u8 *r1kh_id, const u8 *s1kh_id,
+		      u8 *pmk_r1, u8 *pmk_r1_name)
+{
+	u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
+	u8 *pos;
+
+	/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
+	pos = buf;
+	os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
+	pos += FT_R1KH_ID_LEN;
+	os_memcpy(pos, s1kh_id, ETH_ALEN);
+	pos += ETH_ALEN;
+
+	sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
+
+	wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
+}
+
+
+/**
+ * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.5
+ */
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+                     const u8 *sta_addr, const u8 *bssid,
+                     const u8 *pmk_r1_name,
+                     struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
+{
+	u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
+	u8 *pos, hash[32];
+	const u8 *addr[6];
+	size_t len[6];
+	u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+	size_t ptk_len;
+
+	/*
+	 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
+	 *                  BSSID || STA-ADDR)
+	 */
+	pos = buf;
+	os_memcpy(pos, snonce, WPA_NONCE_LEN);
+	pos += WPA_NONCE_LEN;
+	os_memcpy(pos, anonce, WPA_NONCE_LEN);
+	pos += WPA_NONCE_LEN;
+	os_memcpy(pos, bssid, ETH_ALEN);
+	pos += ETH_ALEN;
+	os_memcpy(pos, sta_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+
+	ptk->kck_len = wpa_kck_len(akmp);
+	ptk->kek_len = wpa_kek_len(akmp);
+	ptk->tk_len = wpa_cipher_key_len(cipher);
+	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+
+	sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, tmp, ptk_len);
+
+	/*
+	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
+	 *                                ANonce || BSSID || STA-ADDR))
+	 */
+	addr[0] = pmk_r1_name;
+	len[0] = WPA_PMK_NAME_LEN;
+	addr[1] = (const u8 *) "FT-PTKN";
+	len[1] = 7;
+	addr[2] = snonce;
+	len[2] = WPA_NONCE_LEN;
+	addr[3] = anonce;
+	len[3] = WPA_NONCE_LEN;
+	addr[4] = bssid;
+	len[4] = ETH_ALEN;
+	addr[5] = sta_addr;
+	len[5] = ETH_ALEN;
+
+	sha256_vector(6, addr, len, hash);
+	os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
+
+	os_memcpy(ptk->kck, tmp, ptk->kck_len);
+	os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
+	os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
+
+	wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
+	wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
+	wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
+	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+
+	os_memset(tmp, 0, sizeof(tmp));
+
+	return 0;
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
+
 /**
  * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
  * @key: EAPOL-Key Key Confirmation Key (KCK)
@@ -500,7 +899,7 @@ int wpa_compare_rsn_ie(int ft_initial_assoc,
 	if (ie1 == NULL || ie2 == NULL)
 		return -1;
 
-	if (ie1len == ie2len && memcmp(ie1, ie2, ie1len) == 0)
+	if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
 		return 0; /* identical IEs */
 
 #ifdef CONFIG_IEEE80211R
@@ -751,6 +1150,108 @@ void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
 	memcpy(pmkid, hash, PMKID_LEN);
 }
 
+
+int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
+{
+	u8 *start, *end, *rpos, *rend;
+	int added = 0;
+
+	start = ies;
+	end = ies + *ies_len;
+
+	while (start < end) {
+		if (*start == WLAN_EID_RSN)
+			break;
+		start += 2 + start[1];
+	}
+	if (start >= end) {
+		wpa_printf(MSG_ERROR, "RSN: Could not find RSNE in IEs data");
+		return -1;
+	}
+	wpa_hexdump(MSG_DEBUG, "RSN: RSNE before modification",
+		    start, 2 + start[1]);
+
+	/* Find start of PMKID-Count */
+	rpos = start + 2;
+	rend = rpos + start[1];
+
+	/* Skip Version and Group Data Cipher Suite */
+	rpos += 2 + 4;
+	/* Skip Pairwise Cipher Suite Count and List */
+	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
+	/* Skip AKM Suite Count and List */
+	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
+
+	if (rpos == rend) {
+		/* Add RSN Capabilities */
+		os_memmove(rpos + 2, rpos, end - rpos);
+		*rpos++ = 0;
+		*rpos++ = 0;
+		added += 2;
+		start[1] += 2;
+		rend = rpos;
+	} else {
+		/* Skip RSN Capabilities */
+		rpos += 2;
+		if (rpos > rend) {
+			wpa_printf(MSG_ERROR,
+				   "RSN: Could not parse RSNE in IEs data");
+			return -1;
+		}
+	}
+
+	if (rpos == rend) {
+		/* No PMKID-Count field included; add it */
+		os_memmove(rpos + 2 + PMKID_LEN, rpos, end + added - rpos);
+		WPA_PUT_LE16(rpos, 1);
+		rpos += 2;
+		os_memcpy(rpos, pmkid, PMKID_LEN);
+		added += 2 + PMKID_LEN;
+		start[1] += 2 + PMKID_LEN;
+	} else {
+		u16 num_pmkid;
+
+		if (rend - rpos < 2)
+			return -1;
+		num_pmkid = WPA_GET_LE16(rpos);
+		/* PMKID-Count was included; use it */
+		if (num_pmkid != 0) {
+			u8 *after;
+
+			if (num_pmkid * PMKID_LEN > rend - rpos - 2)
+				return -1;
+			/*
+			 * PMKID may have been included in RSN IE in
+			 * (Re)Association Request frame, so remove the old
+			 * PMKID(s) first before adding the new one.
+			 */
+			wpa_printf(MSG_DEBUG,
+				   "RSN: Remove %u old PMKID(s) from RSNE",
+				   num_pmkid);
+			after = rpos + 2 + num_pmkid * PMKID_LEN;
+			os_memmove(rpos + 2, after, end - after);
+			start[1] -= num_pmkid * PMKID_LEN;
+			added -= num_pmkid * PMKID_LEN;
+		}
+		WPA_PUT_LE16(rpos, 1);
+		rpos += 2;
+		os_memmove(rpos + PMKID_LEN, rpos, end + added - rpos);
+		os_memcpy(rpos, pmkid, PMKID_LEN);
+		added += PMKID_LEN;
+		start[1] += PMKID_LEN;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "RSN: RSNE after modification (PMKID inserted)",
+		    start, 2 + start[1]);
+
+	*ies_len += added;
+
+	return 0;
+}
+
+
+
+
 int wpa_cipher_key_len(int cipher)
 {
 	switch (cipher) {
@@ -813,6 +1314,17 @@ int wpa_cipher_to_alg(int cipher)
 	return WIFI_WPA_ALG_NONE;
 }
 
+
+int wpa_cipher_valid_pairwise(int cipher)
+{
+	return cipher == WPA_CIPHER_GCMP_256 ||
+		cipher == WPA_CIPHER_CCMP ||
+		cipher == WPA_CIPHER_GCMP ||
+		cipher == WPA_CIPHER_TKIP;
+}
+
+
+
 u32 wpa_cipher_to_suite(int proto, int cipher)
 {
 	if (cipher & WPA_CIPHER_CCMP)

+ 52 - 10
components/wpa_supplicant/src/common/wpa_common.h

@@ -1,15 +1,9 @@
 /*
  * WPA definitions shared between hostapd and wpa_supplicant
- * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi>
  *
- * 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.
  */
 
 #include "os.h"
@@ -71,7 +65,7 @@
 #define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
 #define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_192 \
 RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
-
+#define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
 #define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
 #define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
 #define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
@@ -332,6 +326,29 @@ struct rsn_rdie {
 
 #endif /* CONFIG_IEEE80211R */
 
+
+#ifdef CONFIG_IEEE80211R
+int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
+               const u8 *ap_addr, u8 transaction_seqnum,
+               const u8 *mdie, size_t mdie_len,
+	       const u8 *ftie, size_t ftie_len,
+	       const u8 *rsnie, size_t rsnie_len,
+	       const u8 *ric, size_t ric_len, u8 *mic);
+void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+		       const u8 *ssid, size_t ssid_len,
+		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
+void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+			    const u8 *s1kh_id, u8 *pmk_r1_name);
+void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+		       const u8 *r1kh_id, const u8 *s1kh_id,
+		       u8 *pmk_r1, u8 *pmk_r1_name);
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+                      const u8 *sta_addr, const u8 *bssid,
+                      const u8 *pmk_r1_name,
+                      struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher);
+#endif /* CONFIG_IEEE80211R */
+
 struct wpa_ie_data {
 	int proto;
 	int pairwise_cipher;
@@ -380,6 +397,30 @@ int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
 int wpa_compare_rsn_ie(int ft_initial_assoc,
 		       const u8 *ie1, size_t ie1len,
 		       const u8 *ie2, size_t ie2len);
+int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid);
+
+struct wpa_ft_ies {
+	const u8 *mdie;
+	size_t mdie_len;
+	const u8 *ftie;
+	size_t ftie_len;
+	const u8 *r1kh_id;
+	const u8 *gtk;
+	size_t gtk_len;
+	const u8 *r0kh_id;
+	size_t r0kh_id_len;
+	const u8 *rsn;
+	size_t rsn_len;
+	const u8 *rsn_pmkid;
+	const u8 *tie;
+	size_t tie_len;
+	const u8 *igtk;
+	size_t igtk_len;
+	const u8 *ric;
+	size_t ric_len;
+};
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse);
 
 int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
 		      const u8 *buf, size_t len, u8 *mic);
@@ -394,6 +435,7 @@ void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
 int wpa_cipher_key_len(int cipher);
 int wpa_cipher_rsc_len(int cipher);
 int wpa_cipher_to_alg(int cipher);
+int wpa_cipher_valid_pairwise(int cipher);
 int wpa_cipher_valid_mgmt_group(int cipher);
 u32 wpa_cipher_to_suite(int proto, int cipher);
 

+ 7 - 5
components/wpa_supplicant/src/common/wpa_supplicant_i.h

@@ -71,11 +71,6 @@ enum scan_trigger_reason {
 };
 
 struct wpa_supplicant {
-	int disable_btm;
-	unsigned int disable_mbo_oce;
-	/* rrm ie */
-	uint8_t rrm_ie[5];
-	u8 extend_caps[8];
 
 	int scanning;
 	enum scan_trigger_reason scan_reason;
@@ -105,6 +100,9 @@ struct wpa_supplicant {
 	uint32_t type, subtype;
 	u8 next_scan_chan;
 #ifdef CONFIG_WNM
+	int disable_btm;
+	unsigned int disable_mbo_oce;
+	u8 extend_caps[8];
 	u8 wnm_dialog_token;
 	u8 wnm_reply;
 	u8 wnm_num_neighbor_report;
@@ -136,9 +134,13 @@ struct wpa_supplicant {
 	struct dl_list bss_tmp_disallowed;
 #endif /* CONFIG_MBO */
 #endif /* CONFIG_WNM */
+#ifdef CONFIG_RRM
+	/* rrm ie */
+	uint8_t rrm_ie[5];
 	struct rrm_data rrm;
 	struct beacon_rep_data beacon_rep_data;
 	struct os_reltime beacon_rep_scan;
+#endif
 };
 
 struct non_pref_chan_s;

+ 101 - 13
components/wpa_supplicant/src/rsn_supp/wpa.c

@@ -29,6 +29,8 @@
 #include "crypto/aes_wrap.h"
 #include "crypto/ccmp.h"
 #include "esp_rom_sys.h"
+#include "common/bss.h"
+#include "esp_common_i.h"
 
 /**
  * eapol_sm_notify_eap_success - Notification of external EAP success trigger
@@ -54,12 +56,6 @@ u8 assoc_ie_buf[ASSOC_IE_LEN+2];
 
 void set_assoc_ie(u8 * assoc_buf);
 
-static int wpa_sm_set_key(struct install_key *sm, enum wpa_alg alg,
-        u8 *addr, int key_idx, int set_tx,
-        u8 *seq, size_t seq_len,
-        u8 *key, size_t key_len,
-        enum key_flag key_flag);
-
 static int wpa_sm_get_key(uint8_t *ifx, int *alg, u8 *addr, int *key_idx, u8 *key, size_t key_len, enum key_flag key_flag);
 
 void wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len);
@@ -230,8 +226,8 @@ static inline int wpa_sm_ether_send( struct wpa_sm *sm, const u8 *dest, u16 prot
  * @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written
  */
 void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
-            int ver, const u8 *dest, u16 proto,
-            u8 *msg, size_t msg_len, u8 *key_mic)
+                        int ver, const u8 *dest, u16 proto,
+                        u8 *msg, size_t msg_len, u8 *key_mic)
 {
     if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) {
         /*
@@ -542,6 +538,7 @@ int   wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
     size_t mic_len, hdrlen, rlen;
     struct wpa_eapol_key *reply;
     struct wpa_eapol_key_192 *reply192;
+    u8 *rsn_ie_buf = NULL;
     u8 *rbuf, *key_mic;
 
     if (wpa_ie == NULL) {
@@ -552,6 +549,43 @@ int   wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
         return -1;
     }
 
+#ifdef CONFIG_IEEE80211R
+    if (wpa_key_mgmt_ft(sm->key_mgmt)) {
+        int res;
+
+        wpa_hexdump(MSG_DEBUG, "WPA: WPA IE before FT processing",
+                    wpa_ie, wpa_ie_len);
+        /*
+         * Add PMKR1Name into RSN IE (PMKID-List) and add MDIE and
+         * FTIE from (Re)Association Response.
+         */
+        rsn_ie_buf = os_malloc(wpa_ie_len + 2 + 2 + PMKID_LEN +
+                               sm->assoc_resp_ies_len);
+        if (rsn_ie_buf == NULL)
+                return -1;
+        os_memcpy(rsn_ie_buf, wpa_ie, wpa_ie_len);
+        res = wpa_insert_pmkid(rsn_ie_buf, &wpa_ie_len,
+                               sm->pmk_r1_name);
+        if (res < 0) {
+            os_free(rsn_ie_buf);
+            return -1;
+        }
+        wpa_hexdump(MSG_DEBUG,
+                    "WPA: WPA IE after PMKID[PMKR1Name] addition into RSNE",
+                    rsn_ie_buf, wpa_ie_len);
+
+        if (sm->assoc_resp_ies) {
+            wpa_hexdump(MSG_DEBUG, "WPA: Add assoc_resp_ies",
+                        sm->assoc_resp_ies,
+                        sm->assoc_resp_ies_len);
+            os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies,
+                      sm->assoc_resp_ies_len);
+            wpa_ie_len += sm->assoc_resp_ies_len;
+        }
+
+        wpa_ie = rsn_ie_buf;
+    }
+#endif /* CONFIG_IEEE80211R */
     wpa_hexdump(MSG_MSGDUMP, "WPA: WPA IE for msg 2/4\n", wpa_ie, wpa_ie_len);
 
     mic_len = wpa_mic_len(sm->key_mgmt);
@@ -560,6 +594,7 @@ int   wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
                   NULL, hdrlen + wpa_ie_len,
                   &rlen, (void *) &reply);
     if (rbuf == NULL) {
+        os_free(rsn_ie_buf);
         return -1;
     }
     reply192 = (struct wpa_eapol_key_192 *) reply;
@@ -585,7 +620,8 @@ int   wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
         os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
     }
 
-    memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
+    os_free(rsn_ie_buf);
+    os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
 
     wpa_printf(MSG_DEBUG, "WPA Send EAPOL-Key 2/4\n");
 
@@ -599,6 +635,10 @@ int   wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
 static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
               const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
 {
+#ifdef CONFIG_IEEE80211R
+    if (wpa_key_mgmt_ft(sm->key_mgmt))
+        return wpa_derive_ptk_ft(sm, src_addr, key, ptk);
+#endif /* CONFIG_IEEE80211R */
     return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
                   sm->own_addr, sm->bssid, sm->snonce,
                   key->key_nonce, ptk, sm->key_mgmt,
@@ -783,7 +823,13 @@ void   wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
          * the target AP.
          */
     }
-
+#ifdef CONFIG_IEEE80211R
+    if (wpa_key_mgmt_ft(sm->key_mgmt)) {
+        /* Prepare for the next transition */
+        wpa_ft_prepare_auth_request(sm, NULL);
+        sm->ft_protocol = 1;
+    }
+#endif /* CONFIG_IEEE80211R */
 }
 
 static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
@@ -1918,6 +1964,9 @@ int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len)
                    "allow invalid version for non-CCMP group "
                    "keys");
             #endif
+        } else if (ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+              wpa_printf(MSG_DEBUG,
+                        "WPA: Interoperability workaround: allow incorrect (should have been HMAC-SHA1), but stronger      (is AES-128-CMAC), descriptor version to be used");
         } else
             goto out;
     }
@@ -2178,6 +2227,8 @@ void wpa_set_profile(u32 wpa_proto, u8 auth_mode)
          sm->key_mgmt = WPA_KEY_MGMT_WAPI_PSK; /* for WAPI PSK */
     } else if (auth_mode == WPA2_AUTH_ENT_SHA384_SUITE_B) {
          sm->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+    } else if (auth_mode == WPA2_AUTH_FT_PSK) {
+         sm->key_mgmt = WPA_KEY_MGMT_FT_PSK;
     } else {
         sm->key_mgmt = WPA_KEY_MGMT_PSK;  /* fixed to PSK for now */
     }
@@ -2251,7 +2302,7 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher,
 #ifdef CONFIG_SUITEB192
         extern bool g_wpa_suiteb_certification;
         if (g_wpa_suiteb_certification) {
-            if (mgmt_cipher != WIFI_CIPHER_TYPE_AES_GMAC256) {
+            if (sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_256) {
                 wpa_printf(MSG_ERROR, "suite-b 192bit certification, only GMAC256 is supported");
                 return -1;
             }
@@ -2261,13 +2312,46 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher,
         memset(&sm->pmf_cfg, 0, sizeof(sm->pmf_cfg));
         sm->mgmt_group_cipher = WPA_CIPHER_NONE;
     }
+#endif
+#ifdef CONFIG_IEEE80211R
+    if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+        const u8 *ie, *md = NULL;
+        struct wpa_bss *bss = wpa_bss_get_bssid(&g_wpa_supp, (uint8_t *)bssid);
+        if (!bss) {
+            return -1;
+        }
+        ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
+        if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
+                md = ie + 2;
+        if (os_memcmp(md, sm->mobility_domain, MOBILITY_DOMAIN_ID_LEN) != 0) {
+            /* Reset Auth IE here */
+            esp_wifi_unset_appie_internal(WIFI_APPIE_RAM_STA_AUTH);
+            esp_wifi_unset_appie_internal(WIFI_APPIE_ASSOC_REQ);
+            sm->ft_protocol = 0;
+        }
+        wpa_sm_set_ft_params(sm, ie, ie ? 2 + ie[1] : 0);
+    } else {
+        /* Reset FT parameters */
+        wpa_sm_set_ft_params(sm, NULL, 0);
+        esp_wifi_unset_appie_internal(WIFI_APPIE_RAM_STA_AUTH);
+        esp_wifi_unset_appie_internal(WIFI_APPIE_ASSOC_REQ);
+    }
 #endif
     set_assoc_ie(assoc_ie_buf); /* use static buffer */
     res = wpa_gen_wpa_ie(sm, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len);
     if (res < 0)
         return -1;
     sm->assoc_wpa_ie_len = res;
+    esp_set_assoc_ie((uint8_t *)bssid, NULL, 0, true);
+    os_memset(sm->ssid, 0, sizeof(sm->ssid));
+    os_memcpy(sm->ssid, ssid, ssid_len);
+    sm->ssid_len = ssid_len;
     wpa_set_passphrase(passphrase, ssid, ssid_len);
+#ifdef CONFIG_MBO
+    if (!mbo_bss_profile_match((u8 *)bssid))
+        return -1;
+#endif
+
     return 0;
 }
 
@@ -2310,6 +2394,11 @@ wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len)
         memcpy(sm->pmk, esp_wifi_sta_get_ap_info_prof_pmk_internal(), PMK_LEN);
         sm->pmk_len = PMK_LEN;
     }
+#ifdef CONFIG_IEEE80211R
+    /* Set XXKey to be PSK for FT key derivation */
+    sm->xxkey_len = PMK_LEN;
+    os_memcpy(sm->xxkey, sm->pmk, PMK_LEN);
+#endif /* CONFIG_IEEE80211R */
 }
 
   void
@@ -2328,8 +2417,7 @@ set_assoc_ie(u8 * assoc_buf)
     sm->config_assoc_ie(sm->proto, assoc_buf, sm->assoc_wpa_ie_len);
 }
 
-static int
-wpa_sm_set_key(struct install_key *key_sm, enum wpa_alg alg,
+int wpa_sm_set_key(struct install_key *key_sm, enum wpa_alg alg,
         u8 *addr, int key_idx, int set_tx,
         u8 *seq, size_t seq_len,
         u8 *key, size_t key_len,

+ 71 - 87
components/wpa_supplicant/src/rsn_supp/wpa.h

@@ -1,15 +1,9 @@
 /*
  * wpa_supplicant - WPA definitions
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
- * 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 WPA_H
@@ -24,12 +18,11 @@
 #include "esp_wifi_crypto_types.h"
 #include "wpa_i.h"
 
+struct wpa_sm;
 
 #define WPA_SM_STATE(_sm) ((_sm)->wpa_state)
 
-struct wpa_sm;
 
-int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len);
 bool wpa_sta_is_cur_pmksa_set(void);
 bool wpa_sta_in_4way_handshake(void);
 bool wpa_sta_cur_pmksa_matches_akm(void);
@@ -42,87 +35,11 @@ struct l2_ethhdr {
     be16 h_proto;
 } STRUCT_PACKED;
 
-/**
- * set_key - Configure encryption key
- * @ifname: Interface name (for multi-SSID/VLAN support)
- * @priv: private driver interface data
- * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
- *	%WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK);
- *	%WPA_ALG_NONE clears the key.
- * @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for
- *	broadcast/default keys
- * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for
- *	IGTK
- * @set_tx: configure this key as the default Tx key (only used when
- *	driver does not support separate unicast/individual key
- * @seq: sequence number/packet number, seq_len octets, the next
- *	packet number to be used for in replay protection; configured
- *	for Rx keys (in most cases, this is only used with broadcast
- *	keys and set to zero for unicast keys)
- * @seq_len: length of the seq, depends on the algorithm:
- *	TKIP: 6 octets, CCMP: 6 octets, IGTK: 6 octets
- * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
- *	8-byte Rx Mic Key
- * @key_len: length of the key buffer in octets (WEP: 5 or 13,
- *	TKIP: 32, CCMP: 16, IGTK: 16)
- *
- * Returns: 0 on success, -1 on failure
- *
- * Configure the given key for the kernel driver. If the driver
- * supports separate individual keys (4 default keys + 1 individual),
- * addr can be used to determine whether the key is default or
- * individual. If only 4 keys are supported, the default key with key
- * index 0 is used as the individual key. STA must be configured to use
- * it as the default Tx key (set_tx is set) and accept Rx for all the
- * key indexes. In most cases, WPA uses only key indexes 1 and 2 for
- * broadcast keys, so key index 0 is available for this kind of
- * configuration.
- *
- * Please note that TKIP keys include separate TX and RX MIC keys and
- * some drivers may expect them in different order than wpa_supplicant
- * is using. If the TX/RX keys are swapped, all TKIP encrypted packets
- * will tricker Michael MIC errors. This can be fixed by changing the
- * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key
- * in driver_*.c set_key() implementation, see driver_ndis.c for an
- * example on how this can be done.
- */
-
-
-/**
- * send_eapol - Optional function for sending EAPOL packets
- * @priv: private driver interface data
- * @dest: Destination MAC address
- * @proto: Ethertype
- * @data: EAPOL packet starting with IEEE 802.1X header
- * @data_len: Size of the EAPOL packet
- *
- * Returns: 0 on success, -1 on failure
- *
- * This optional function can be used to override l2_packet operations
- * with driver specific functionality. If this function pointer is set,
- * l2_packet module is not used at all and the driver interface code is
- * responsible for receiving and sending all EAPOL packets. The
- * received EAPOL packets are sent to core code with EVENT_EAPOL_RX
- * event. The driver interface is required to implement get_mac_addr()
- * handler if send_eapol() is used.
- */
-
-#define KEYENTRY_TABLE_MAP(key_entry_valid)  ((key_entry_valid)%5)
-
-void pp_michael_mic_failure(u16 isunicast);
 
 void wpa_sm_set_state(enum wpa_states state);
 
-char * dup_binstr(const void *src, size_t len);
-
 void wpa_set_pmk(uint8_t *pmk, const u8 *pmkid, bool cache_pmksa);
 
-int wpa_hook_init(void);
-
-bool wpa_hook_deinit(void);
-
-char * dup_binstr(const void *src, size_t len);
-
 int wpa_michael_mic_failure(u16 isunicast);
 
 wifi_cipher_type_t cipher_type_map_supp_to_public(unsigned cipher);
@@ -131,4 +48,71 @@ unsigned cipher_type_map_public_to_supp(wifi_cipher_type_t cipher);
 
 void wpa_sta_clear_curr_pmksa(void);
 
+int wpa_sm_set_key(struct install_key *sm, enum wpa_alg alg,
+        u8 *addr, int key_idx, int set_tx,
+        u8 *seq, size_t seq_len,
+        u8 *key, size_t key_len,
+        enum key_flag key_flag);
+
+#ifdef CONFIG_IEEE80211R
+
+int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len);
+int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie);
+int wpa_ft_add_mdie(struct wpa_sm *sm, u8 *ies, size_t ies_len,
+		    const u8 *mdie);
+const u8 * wpa_sm_get_ft_md(struct wpa_sm *sm);
+int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
+			    int ft_action, const u8 *target_ap,
+			    const u8 *ric_ies, size_t ric_ies_len);
+int wpa_ft_is_completed(struct wpa_sm *sm);
+void wpa_reset_ft_completed(struct wpa_sm *sm);
+int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
+				 size_t ies_len, const u8 *src_addr);
+int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
+			 const u8 *mdie);
+
+#else /* CONFIG_IEEE80211R */
+
+static inline int
+wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
+{
+	return 0;
+}
+
+static inline int wpa_ft_prepare_auth_request(struct wpa_sm *sm,
+					      const u8 *mdie)
+{
+	return 0;
+}
+
+static inline int wpa_ft_add_mdie(struct wpa_sm *sm, u8 *ies, size_t ies_len,
+				  const u8 *mdie)
+{
+	return 0;
+}
+
+static inline int
+wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
+			int ft_action, const u8 *target_ap)
+{
+	return 0;
+}
+
+static inline int wpa_ft_is_completed(struct wpa_sm *sm)
+{
+	return 0;
+}
+
+static inline void wpa_reset_ft_completed(struct wpa_sm *sm)
+{
+}
+
+static inline int
+wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
+			     const u8 *src_addr)
+{
+	return -1;
+}
+
+#endif /* CONFIG_IEEE80211R */
 #endif /* WPA_H */

+ 900 - 0
components/wpa_supplicant/src/rsn_supp/wpa_ft.c

@@ -0,0 +1,900 @@
+/*
+ * WPA Supplicant - IEEE 802.11r - Fast BSS Transition
+ * Copyright (c) 2006-2018, 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 "crypto/aes_wrap.h"
+#include "crypto/random.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "wpa.h"
+#include "wpa_i.h"
+
+#ifdef CONFIG_IEEE80211R
+
+#define DEFAULT_KEK_LEN 16
+
+int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
+		      const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
+{
+	u8 ptk_name[WPA_PMK_NAME_LEN];
+	const u8 *anonce = key->key_nonce;
+
+	if (sm->xxkey_len == 0) {
+		wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
+			   "derivation");
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "FT: xxkey", sm->xxkey, sm->xxkey_len);
+	wpa_hexdump_key(MSG_DEBUG, "FT: ssid", sm->ssid, sm->ssid_len);
+	wpa_hexdump_key(MSG_DEBUG, "FT: r0kh_id", sm->r0kh_id, sm->r0kh_id_len);
+	wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid,
+			  sm->ssid_len, sm->mobility_domain,
+			  sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
+			  sm->pmk_r0, sm->pmk_r0_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name",
+		    sm->pmk_r0_name, WPA_PMK_NAME_LEN);
+	wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
+			  sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
+		    WPA_PMK_NAME_LEN);
+	return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
+				 sm->bssid, sm->pmk_r1_name, ptk, ptk_name,
+				 sm->key_mgmt, sm->pairwise_cipher);
+}
+
+
+/**
+ * wpa_sm_set_ft_params - Set FT (IEEE 802.11r) parameters
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ies: Association Response IEs or %NULL to clear FT parameters
+ * @ies_len: Length of ies buffer in octets
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
+{
+	struct wpa_ft_ies ft;
+
+	if (sm == NULL)
+		return 0;
+
+	if (!get_ie(ies, ies_len, WLAN_EID_MOBILITY_DOMAIN)) {
+		os_free(sm->assoc_resp_ies);
+		sm->assoc_resp_ies = NULL;
+		sm->assoc_resp_ies_len = 0;
+		os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
+		os_memset(sm->r0kh_id, 0, FT_R0KH_ID_MAX_LEN);
+		sm->r0kh_id_len = 0;
+		os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN);
+		sm->ft_protocol = 0;
+		return 0;
+	}
+
+	if (wpa_ft_parse_ies(ies, ies_len, &ft) < 0)
+		return -1;
+
+	if (ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
+		return -1;
+
+	wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
+		    ft.mdie, MOBILITY_DOMAIN_ID_LEN);
+	os_memcpy(sm->mobility_domain, ft.mdie, MOBILITY_DOMAIN_ID_LEN);
+	sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
+	wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
+		   sm->mdie_ft_capab);
+
+	if (ft.r0kh_id) {
+		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID",
+			    ft.r0kh_id, ft.r0kh_id_len);
+		os_memcpy(sm->r0kh_id, ft.r0kh_id, ft.r0kh_id_len);
+		sm->r0kh_id_len = ft.r0kh_id_len;
+	} else {
+		/* FIX: When should R0KH-ID be cleared? We need to keep the
+		 * old R0KH-ID in order to be able to use this during FT. */
+		/*
+		 * os_memset(sm->r0kh_id, 0, FT_R0KH_ID_LEN);
+		 * sm->r0kh_id_len = 0;
+		 */
+	}
+
+	if (ft.r1kh_id) {
+		wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID",
+			    ft.r1kh_id, FT_R1KH_ID_LEN);
+		os_memcpy(sm->r1kh_id, ft.r1kh_id, FT_R1KH_ID_LEN);
+	} else
+		os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN);
+
+	os_free(sm->assoc_resp_ies);
+	sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2);
+	if (sm->assoc_resp_ies) {
+		u8 *pos = sm->assoc_resp_ies;
+
+		os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2);
+		pos += ft.mdie_len + 2;
+
+		if (ft.ftie) {
+			os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2);
+			pos += ft.ftie_len + 2;
+		}
+		sm->assoc_resp_ies_len = pos - sm->assoc_resp_ies;
+		wpa_hexdump(MSG_DEBUG, "FT: Stored MDIE and FTIE from "
+			    "(Re)Association Response",
+			    sm->assoc_resp_ies, sm->assoc_resp_ies_len);
+	}
+
+	return 0;
+}
+
+/**
+ * wpa_ft_gen_req_ies - Generate FT (IEEE 802.11r) IEs for Auth/ReAssoc Request
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @len: Buffer for returning the length of the IEs
+ * @anonce: ANonce or %NULL if not yet available
+ * @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List
+ * @kck: 128-bit KCK for MIC or %NULL if no MIC is used
+ * @kck_len: KCK length in octet
+ * @target_ap: Target AP address
+ * @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL
+ * @ric_ies_len: Length of ric_ies buffer in octets
+ * @ap_mdie: Mobility Domain IE from the target AP
+ * Returns: Pointer to buffer with IEs or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free();
+ */
+static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
+			       const u8 *anonce, const u8 *pmk_name,
+			       const u8 *kck, size_t kck_len,
+			       const u8 *target_ap,
+			       const u8 *ric_ies, size_t ric_ies_len,
+			       const u8 *ap_mdie)
+{
+	size_t buf_len;
+	u8 *buf, *pos, *ftie_len, *ftie_pos;
+	struct rsn_mdie *mdie;
+	struct rsn_ftie *ftie;
+	struct rsn_ie_hdr *rsnie;
+	int mdie_len;
+	u16 capab;
+
+	sm->ft_completed = 0;
+
+	buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
+		2 + sm->r0kh_id_len + ric_ies_len + 100;
+	buf = os_zalloc(buf_len);
+	if (buf == NULL)
+		return NULL;
+	pos = buf;
+
+	/* RSNIE[PMKR0Name/PMKR1Name] */
+	rsnie = (struct rsn_ie_hdr *) pos;
+	rsnie->elem_id = WLAN_EID_RSN;
+	WPA_PUT_LE16(rsnie->version, RSN_VERSION);
+	pos = (u8 *) (rsnie + 1);
+
+	/* Group Suite Selector */
+	if (sm->group_cipher != WPA_CIPHER_CCMP &&
+	    sm->group_cipher != WPA_CIPHER_GCMP &&
+	    sm->group_cipher != WPA_CIPHER_TKIP) {
+		wpa_printf(MSG_WARNING, "FT: Invalid group cipher (%d)",
+			   sm->group_cipher);
+		os_free(buf);
+		return NULL;
+	}
+	RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
+						  sm->group_cipher));
+	pos += RSN_SELECTOR_LEN;
+
+	/* Pairwise Suite Count */
+	WPA_PUT_LE16(pos, 1);
+	pos += 2;
+
+	/* Pairwise Suite List */
+	if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
+		wpa_printf(MSG_WARNING, "FT: Invalid pairwise cipher (%d)",
+			   sm->pairwise_cipher);
+		os_free(buf);
+		return NULL;
+	}
+	RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
+						  sm->pairwise_cipher));
+	pos += RSN_SELECTOR_LEN;
+
+	/* Authenticated Key Management Suite Count */
+	WPA_PUT_LE16(pos, 1);
+	pos += 2;
+
+	/* Authenticated Key Management Suite List */
+	if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X)
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+	else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK)
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
+	else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE)
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+	else {
+		wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)",
+			   sm->key_mgmt);
+		os_free(buf);
+		return NULL;
+	}
+	pos += RSN_SELECTOR_LEN;
+
+	/* RSN Capabilities */
+	capab = 0;
+#ifdef CONFIG_IEEE80211W
+	if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
+		capab |= WPA_CAPABILITY_MFPC;
+#endif /* CONFIG_IEEE80211W */
+	WPA_PUT_LE16(pos, capab);
+	pos += 2;
+
+	/* PMKID Count */
+	WPA_PUT_LE16(pos, 1);
+	pos += 2;
+
+	/* PMKID List [PMKR0Name/PMKR1Name] */
+	os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN);
+	pos += WPA_PMK_NAME_LEN;
+
+#ifdef CONFIG_IEEE80211W
+	if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
+		/* Management Group Cipher Suite */
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+		pos += RSN_SELECTOR_LEN;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	rsnie->len = (pos - (u8 *) rsnie) - 2;
+
+	/* MDIE */
+	mdie_len = wpa_ft_add_mdie(sm, pos, buf_len - (pos - buf), ap_mdie);
+	if (mdie_len <= 0) {
+		os_free(buf);
+		return NULL;
+	}
+	mdie = (struct rsn_mdie *) (pos + 2);
+	pos += mdie_len;
+
+	/* FTIE[SNonce, [R1KH-ID,] R0KH-ID ] */
+	ftie_pos = pos;
+	*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
+	ftie_len = pos++;
+	ftie = (struct rsn_ftie *) pos;
+	pos += sizeof(*ftie);
+	os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN);
+	if (anonce)
+		os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN);
+	if (kck) {
+		/* R1KH-ID sub-element in third FT message */
+		*pos++ = FTIE_SUBELEM_R1KH_ID;
+		*pos++ = FT_R1KH_ID_LEN;
+		os_memcpy(pos, sm->r1kh_id, FT_R1KH_ID_LEN);
+		pos += FT_R1KH_ID_LEN;
+	}
+	/* R0KH-ID sub-element */
+	*pos++ = FTIE_SUBELEM_R0KH_ID;
+	*pos++ = sm->r0kh_id_len;
+	os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len);
+	pos += sm->r0kh_id_len;
+	*ftie_len = pos - ftie_len - 1;
+
+	if (ric_ies) {
+		/* RIC Request */
+		os_memcpy(pos, ric_ies, ric_ies_len);
+		pos += ric_ies_len;
+	}
+
+	if (kck) {
+		/*
+		 * IEEE Std 802.11r-2008, 11A.8.4
+		 * MIC shall be calculated over:
+		 * non-AP STA MAC address
+		 * Target AP MAC address
+		 * Transaction seq number (5 for ReassocReq, 3 otherwise)
+		 * RSN IE
+		 * MDIE
+		 * FTIE (with MIC field set to 0)
+		 * RIC-Request (if present)
+		 */
+		/* Information element count */
+		ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies,
+							       ric_ies_len);
+		if (wpa_ft_mic(kck, kck_len, sm->own_addr, target_ap, 5,
+			       ((u8 *) mdie) - 2, 2 + sizeof(*mdie),
+			       ftie_pos, 2 + *ftie_len,
+			       (u8 *) rsnie, 2 + rsnie->len, ric_ies,
+			       ric_ies_len, ftie->mic) < 0) {
+			wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
+			os_free(buf);
+			return NULL;
+		}
+	}
+
+	*len = pos - buf;
+
+	return buf;
+}
+
+
+static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
+{
+	int keylen;
+	enum wpa_alg alg;
+	u8 null_rsc[6] = { 0, 0, 0, 0, 0, 0 };
+
+	wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver.");
+
+	if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
+		wpa_printf(MSG_WARNING, "FT: Unsupported pairwise cipher %d",
+			   sm->pairwise_cipher);
+		return -1;
+	}
+
+	alg = wpa_cipher_to_alg(sm->pairwise_cipher);
+	keylen = wpa_cipher_key_len(sm->pairwise_cipher);
+
+	if (wpa_sm_set_key(&(sm->install_ptk), alg, (u8 *)bssid, 0, 1, null_rsc,
+			   sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen, KEY_FLAG_PAIRWISE) < 0) {
+		wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_ft_prepare_auth_request - Generate over-the-air auth request
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @mdie: Target AP MDIE
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie)
+{
+	u8 *ft_ies;
+	size_t ft_ies_len;
+
+	/* Generate a new SNonce */
+	if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
+		wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce");
+		return -1;
+	}
+
+	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
+				    NULL, 0, sm->bssid, NULL, 0, mdie);
+	if (ft_ies) {
+		wpa_sm_update_ft_ies(sm, sm->mobility_domain,
+				     ft_ies, ft_ies_len, true);
+		os_free(ft_ies);
+	}
+
+	return 0;
+}
+
+
+int wpa_ft_add_mdie(struct wpa_sm *sm, u8 *buf, size_t buf_len,
+		    const u8 *ap_mdie)
+{
+	u8 *pos = buf;
+	struct rsn_mdie *mdie;
+
+	if (buf_len < 2 + sizeof(*mdie)) {
+		wpa_printf(MSG_INFO,
+			   "FT: Failed to add MDIE: short buffer, length=%zu",
+			   buf_len);
+		return 0;
+	}
+
+	*pos++ = WLAN_EID_MOBILITY_DOMAIN;
+	*pos++ = sizeof(*mdie);
+	mdie = (struct rsn_mdie *) pos;
+	os_memcpy(mdie->mobility_domain, sm->mobility_domain,
+		  MOBILITY_DOMAIN_ID_LEN);
+	mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] :
+		sm->mdie_ft_capab;
+
+	return 2 + sizeof(*mdie);
+}
+
+
+const u8 * wpa_sm_get_ft_md(struct wpa_sm *sm)
+{
+	return sm->mobility_domain;
+}
+
+
+int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
+			    int ft_action, const u8 *target_ap,
+			    const u8 *ric_ies, size_t ric_ies_len)
+{
+	u8 *ft_ies;
+	size_t ft_ies_len;
+	struct wpa_ft_ies parse;
+	struct rsn_mdie *mdie;
+	struct rsn_ftie *ftie;
+	u8 ptk_name[WPA_PMK_NAME_LEN];
+	int ret;
+	const u8 *bssid;
+
+	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
+	wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len);
+
+	if (ft_action) {
+		if (!sm->over_the_ds_in_progress) {
+			wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress "
+				   "- drop FT Action Response");
+			return -1;
+		}
+
+		if (os_memcmp(target_ap, sm->target_ap, ETH_ALEN) != 0) {
+			wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress "
+				   "with this Target AP - drop FT Action "
+				   "Response");
+			return -1;
+		}
+	}
+
+	if (!wpa_key_mgmt_ft(sm->key_mgmt)) {
+		wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
+			   "enabled for this connection");
+		return -1;
+	}
+
+	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
+		return -1;
+	}
+
+	mdie = (struct rsn_mdie *) parse.mdie;
+	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
+	    os_memcmp(mdie->mobility_domain, sm->mobility_domain,
+		      MOBILITY_DOMAIN_ID_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
+		return -1;
+	}
+
+	ftie = (struct rsn_ftie *) parse.ftie;
+	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+		return -1;
+	}
+
+	if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
+		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
+			    ftie->snonce, WPA_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
+			    sm->snonce, WPA_NONCE_LEN);
+		return -1;
+	}
+
+	if (parse.r0kh_id == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
+		return -1;
+	}
+
+	if (parse.r0kh_id_len != sm->r0kh_id_len ||
+	    os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
+	{
+		wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
+			   "the current R0KH-ID");
+		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
+			    parse.r0kh_id, parse.r0kh_id_len);
+		wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
+			    sm->r0kh_id, sm->r0kh_id_len);
+		return -1;
+	}
+
+	if (parse.r1kh_id == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
+		return -1;
+	}
+
+	if (parse.rsn_pmkid == NULL ||
+	    os_memcmp_const(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN))
+	{
+		wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in "
+			   "RSNIE");
+		return -1;
+	}
+
+	os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN);
+	os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN);
+	wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
+			  sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
+		    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
+
+	bssid = target_ap;
+
+	if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce,
+			      sm->own_addr, bssid, sm->pmk_r1_name, &sm->ptk,
+			      ptk_name, sm->key_mgmt, sm->pairwise_cipher) < 0)
+		return -1;
+
+	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
+				    sm->pmk_r1_name,
+				    sm->ptk.kck, sm->ptk.kck_len, bssid,
+				    ric_ies, ric_ies_len,
+				    parse.mdie ? parse.mdie - 2 : NULL);
+	if (ft_ies) {
+		wpa_sm_update_ft_ies(sm, sm->mobility_domain,
+				     ft_ies, ft_ies_len, false);
+		os_free(ft_ies);
+	}
+
+	wpa_sm_mark_authenticated(sm, bssid);
+	ret = wpa_ft_install_ptk(sm, bssid);
+	if (ret) {
+		/*
+		 * Some drivers do not support key configuration when we are
+		 * not associated with the target AP. Work around this by
+		 * trying again after the following reassociation gets
+		 * completed.
+		 */
+		wpa_printf(MSG_DEBUG, "FT: Failed to set PTK prior to "
+			   "association - try again after reassociation");
+		sm->set_ptk_after_assoc = 1;
+	} else
+		sm->set_ptk_after_assoc = 0;
+
+	sm->ft_completed = 1;
+	if (ft_action) {
+		/*
+		 * The caller is expected trigger re-association with the
+		 * Target AP.
+		 */
+		os_memcpy(sm->bssid, target_ap, ETH_ALEN);
+	}
+
+	return 0;
+}
+
+
+int wpa_ft_is_completed(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return 0;
+
+	if (!wpa_key_mgmt_ft(sm->key_mgmt))
+		return 0;
+
+	return sm->ft_completed;
+}
+
+
+void wpa_reset_ft_completed(struct wpa_sm *sm)
+{
+	if (sm != NULL)
+		sm->ft_completed = 0;
+}
+
+
+static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
+				      size_t gtk_elem_len)
+{
+	u8 gtk[32];
+	int keyidx;
+	enum wpa_alg alg;
+	size_t gtk_len, keylen, rsc_len;
+
+	if (gtk_elem == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE");
+		return 0;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp",
+			gtk_elem, gtk_elem_len);
+
+	if (gtk_elem_len < 11 + 24 || (gtk_elem_len - 11) % 8 ||
+	    gtk_elem_len - 19 > sizeof(gtk)) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid GTK sub-elem "
+			   "length %lu", (unsigned long) gtk_elem_len);
+		return -1;
+	}
+	gtk_len = gtk_elem_len - 19;
+	if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, gtk_len / 8, gtk_elem + 11, gtk)) {
+		wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
+			   "decrypt GTK");
+		return -1;
+	}
+
+	keylen = wpa_cipher_key_len(sm->group_cipher);
+	rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
+	alg = wpa_cipher_to_alg(sm->group_cipher);
+	if (alg == WIFI_WPA_ALG_NONE) {
+		wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d",
+			   sm->group_cipher);
+		return -1;
+	}
+
+	if (gtk_len < keylen) {
+		wpa_printf(MSG_DEBUG, "FT: Too short GTK in FTIE");
+		return -1;
+	}
+
+	/* Key Info[2] | Key Length[1] | RSC[8] | Key[5..32]. */
+
+	keyidx = WPA_GET_LE16(gtk_elem) & 0x03;
+
+	if (gtk_elem[2] != keylen) {
+		wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d "
+			   "negotiated %lu",
+			   gtk_elem[2], (unsigned long) keylen);
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen);
+	if (sm->group_cipher == WPA_CIPHER_TKIP) {
+		/* Swap Tx/Rx keys for Michael MIC */
+		u8 tmp[8];
+		os_memcpy(tmp, gtk + 16, 8);
+		os_memcpy(gtk + 16, gtk + 24, 8);
+		os_memcpy(gtk + 24, tmp, 8);
+	}
+	if (wpa_sm_set_key(&(sm->install_gtk), alg, sm->bssid, keyidx, 0,
+			   (u8 *)(gtk_elem + 3), rsc_len, gtk, keylen, KEY_FLAG_GROUP | KEY_FLAG_RX) < 0) {
+		wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
+			   "driver.");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
+				       size_t igtk_elem_len)
+{
+	u8 igtk[WPA_IGTK_LEN];
+
+	if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
+		return 0;
+
+	if (igtk_elem == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No IGTK included in FTIE");
+		return 0;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp",
+			igtk_elem, igtk_elem_len);
+
+	if (igtk_elem_len != 2 + 6 + 1 + WPA_IGTK_LEN + 8) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem "
+			   "length %lu", (unsigned long) igtk_elem_len);
+		return -1;
+	}
+	if (igtk_elem[8] != WPA_IGTK_LEN) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem Key Length "
+			   "%d", igtk_elem[8]);
+		return -1;
+	}
+
+	if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, WPA_IGTK_LEN / 8,
+		       igtk_elem + 9, igtk)) {
+		wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
+			   "decrypt IGTK");
+		return -1;
+	}
+
+	/* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */
+
+	wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk,
+			WPA_IGTK_LEN);
+#ifdef ESP_SUPPLICANT
+        if (esp_wifi_set_igtk_internal(WIFI_IF_STA, (wifi_wpa_igtk_t *)igtk) < 0) {
+#else
+	keyidx = WPA_GET_LE16(igtk_elem);
+	if (wpa_sm_set_key(&(sm->install_gtk), WIFI_WPA_ALG_IGTK, sm->bssid, keyidx, 0,
+			   (u8 *)(igtk_elem + 2), 6, igtk, WPA_IGTK_LEN, sm->key_entry_valid) < 0) {
+#endif
+		wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
+			   "driver.");
+		return -1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IEEE80211W */
+
+
+int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
+				 size_t ies_len, const u8 *src_addr)
+{
+	struct wpa_ft_ies parse;
+	struct rsn_mdie *mdie;
+	struct rsn_ftie *ftie;
+	unsigned int count;
+	u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+
+	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
+
+	if (!wpa_key_mgmt_ft(sm->key_mgmt)) {
+		wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
+			   "enabled for this connection");
+		return -1;
+	}
+
+	if (sm->ft_reassoc_completed) {
+		wpa_printf(MSG_DEBUG, "FT: Reassociation has already been completed for this FT protocol instance - ignore unexpected retransmission");
+		return 0;
+	}
+
+	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
+		return -1;
+	}
+
+	mdie = (struct rsn_mdie *) parse.mdie;
+	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
+	    os_memcmp(mdie->mobility_domain, sm->mobility_domain,
+		      MOBILITY_DOMAIN_ID_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
+		return -1;
+	}
+
+	ftie = (struct rsn_ftie *) parse.ftie;
+	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+		return -1;
+	}
+
+	if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
+		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
+			    ftie->snonce, WPA_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
+			    sm->snonce, WPA_NONCE_LEN);
+		return -1;
+	}
+
+	if (os_memcmp(ftie->anonce, sm->anonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
+		wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
+			    ftie->anonce, WPA_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
+			    sm->anonce, WPA_NONCE_LEN);
+		return -1;
+	}
+
+	if (parse.r0kh_id == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
+		return -1;
+	}
+
+	if (parse.r0kh_id_len != sm->r0kh_id_len ||
+	    os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
+	{
+		wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
+			   "the current R0KH-ID");
+		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
+			    parse.r0kh_id, parse.r0kh_id_len);
+		wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
+			    sm->r0kh_id, sm->r0kh_id_len);
+		return -1;
+	}
+
+	if (parse.r1kh_id == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
+		return -1;
+	}
+
+	if (os_memcmp_const(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
+			   "ReassocResp");
+		return -1;
+	}
+
+	if (parse.rsn_pmkid == NULL ||
+	    os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN))
+	{
+		wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
+			   "RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
+		return -1;
+	}
+
+	count = 3;
+	if (parse.ric)
+		count += ieee802_11_ie_count(parse.ric, parse.ric_len);
+	if (ftie->mic_control[1] != count) {
+		wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
+			   "Control: received %u expected %u",
+			   ftie->mic_control[1], count);
+		return -1;
+	}
+
+	if (wpa_ft_mic(sm->ptk.kck, sm->ptk.kck_len, sm->own_addr, src_addr, 6,
+		       parse.mdie - 2, parse.mdie_len + 2,
+		       parse.ftie - 2, parse.ftie_len + 2,
+		       parse.rsn - 2, parse.rsn_len + 2,
+		       parse.ric, parse.ric_len,
+		       mic) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
+		return -1;
+	}
+
+	if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
+		wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
+		wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
+		return -1;
+	}
+
+	sm->ft_reassoc_completed = 1;
+	if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
+		return -1;
+
+#ifdef CONFIG_IEEE80211W
+	if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0)
+		return -1;
+#endif /* CONFIG_IEEE80211W */
+
+	if (sm->set_ptk_after_assoc) {
+		wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we "
+			   "are associated");
+		if (wpa_ft_install_ptk(sm, src_addr) < 0)
+			return -1;
+		sm->set_ptk_after_assoc = 0;
+	}
+
+	if (parse.ric) {
+		wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response",
+			    parse.ric, parse.ric_len);
+		/* TODO: parse response and inform driver about results when
+		 * using wpa_supplicant SME */
+	}
+
+	wpa_printf(MSG_DEBUG, "FT: Completed successfully");
+
+	return 0;
+}
+
+
+/**
+ * wpa_ft_start_over_ds - Generate over-the-DS auth request
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @target_ap: Target AP Address
+ * @mdie: Mobility Domain IE from the target AP
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
+			 const u8 *mdie)
+{
+	u8 *ft_ies;
+	size_t ft_ies_len;
+
+	wpa_printf(MSG_DEBUG, "FT: Request over-the-DS with " MACSTR,
+		   MAC2STR(target_ap));
+
+	/* Generate a new SNonce */
+	if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
+		wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce");
+		return -1;
+	}
+
+	ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
+				    NULL, 0, target_ap, NULL, 0, mdie);
+	if (ft_ies) {
+		sm->over_the_ds_in_progress = 1;
+		os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
+		wpa_sm_send_ft_action(sm, 1, target_ap, ft_ies, ft_ies_len);
+		os_free(ft_ies);
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_IEEE80211R */

+ 47 - 10
components/wpa_supplicant/src/rsn_supp/wpa_i.h

@@ -1,20 +1,15 @@
 /*
  * Internal WPA/RSN supplicant state machine definitions
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
  *
- * 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 WPA_I_H
 #define WPA_I_H
 
+extern struct wpa_sm gWpaSm;
 struct install_key {
     int keys_cleared;
     enum wpa_alg alg;
@@ -31,7 +26,6 @@ struct install_key {
 struct wpa_sm {
     u8 pmk[PMK_LEN_MAX];
     size_t pmk_len;
-
     struct wpa_ptk ptk, tptk;
     int ptk_set, tptk_set;
     u8 snonce[WPA_NONCE_LEN];
@@ -42,6 +36,8 @@ struct wpa_sm {
     u8 request_counter[WPA_REPLAY_COUNTER_LEN];
     struct rsn_pmksa_cache *pmksa; /* PMKSA cache */
     struct rsn_pmksa_cache_entry *cur_pmksa; /* current PMKSA entry */
+    u8 ssid[32];
+    size_t ssid_len;
 
     unsigned int pairwise_cipher;
     unsigned int group_cipher;
@@ -91,6 +87,27 @@ struct wpa_sm {
     wifi_pmf_config_t pmf_cfg;
     u8 eapol1_count;
     struct rsn_sppamsdu_sup spp_sup;
+#ifdef CONFIG_IEEE80211R
+    u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
+    size_t xxkey_len;
+    u8 pmk_r0[PMK_LEN];
+    u8 pmk_r0_name[WPA_PMK_NAME_LEN];
+    u8 pmk_r1[PMK_LEN];
+    u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+    u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
+    u8 r0kh_id[FT_R0KH_ID_MAX_LEN];
+    size_t r0kh_id_len;
+    u8 r1kh_id[FT_R1KH_ID_LEN];
+    unsigned int ft_completed:1;
+    unsigned int ft_reassoc_completed:1;
+    unsigned int ft_protocol:1;
+    int over_the_ds_in_progress;
+    u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */
+    int set_ptk_after_assoc;
+    u8 mdie_ft_capab; /* FT Capability and Policy from target AP MDIE */
+    u8 *assoc_resp_ies; /* MDIE and FTIE from (Re)Association Response */
+    size_t assoc_resp_ies_len;
+#endif /* CONFIG_IEEE80211R */
 };
 
 /**
@@ -141,6 +158,22 @@ struct wpa_sm {
 
 typedef void (* WPA_SEND_FUNC)(void *buffer, u16 len);
 
+int wpa_sm_update_ft_ies(struct wpa_sm *sm, const u8 *md,
+			 const u8 *ies, size_t ies_len, bool auth_ie);
+
+static inline int wpa_sm_send_ft_action(struct wpa_sm *sm, u8 action,
+					const u8 *target_ap,
+					const u8 *ies, size_t ies_len)
+{
+	return -1;
+}
+
+static inline int wpa_sm_mark_authenticated(struct wpa_sm *sm,
+					    const u8 *target_ap)
+{
+	return 0;
+}
+
 typedef void (* WPA_SET_ASSOC_IE)(u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len);
 
 typedef void (*WPA_INSTALL_KEY) (enum wpa_alg alg, u8 *addr, int key_idx, int set_tx,
@@ -152,6 +185,7 @@ typedef void (*WPA_DEAUTH_FUNC)(u8 reason_code);
 
 typedef void (*WPA_NEG_COMPLETE)(void);
 
+
 bool wpa_sm_init(char * payload, WPA_SEND_FUNC snd_func, \
         WPA_SET_ASSOC_IE set_assoc_ie_func, \
         WPA_INSTALL_KEY ppinstallkey, \
@@ -168,4 +202,7 @@ void wpa_set_profile(u32 wpa_proto, u8 auth_mode);
 int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len);
 
 int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len);
+
+int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
+                      const struct wpa_eapol_key *key, struct wpa_ptk *ptk);
 #endif /* WPA_I_H */

+ 2 - 0
components/wpa_supplicant/src/utils/common.h

@@ -370,6 +370,8 @@ typedef u64 __bitwise le64;
 #endif /* __GNUC__ */
 #endif /* __must_check */
 
+#define SSID_MAX_LEN 32
+
 int hwaddr_aton(const char *txt, u8 *addr);
 int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable);
 int hwaddr_compact_aton(const char *txt, u8 *addr);

+ 1 - 0
examples/wifi/roaming/main/roaming_example.c

@@ -383,6 +383,7 @@ static void initialise_wifi(void)
 			.btm_enabled =1,
 			.mbo_enabled =1,
 			.pmf_cfg.capable = 1,
+			.ft_enabled =1,
 		},
 	};
 

+ 1 - 0
examples/wifi/roaming/sdkconfig.defaults

@@ -1,3 +1,4 @@
 CONFIG_WPA_11KV_SUPPORT=y
 CONFIG_WPA_SCAN_CACHE=y
 CONFIG_WPA_MBO_SUPPORT=y
+CONFIG_WPA_11R_SUPPORT=y

+ 0 - 1
tools/ci/check_copyright_ignore.txt

@@ -1679,7 +1679,6 @@ components/wpa_supplicant/include/utils/wpabuf.h
 components/wpa_supplicant/port/include/byteswap.h
 components/wpa_supplicant/port/include/endian.h
 components/wpa_supplicant/port/include/os.h
-components/wpa_supplicant/port/include/supplicant_opt.h
 components/wpa_supplicant/port/os_xtensa.c
 components/wpa_supplicant/src/ap/ap_config.c
 components/wpa_supplicant/src/ap/ap_config.h