Parcourir la source

esp_wifi: Update wifi lib

1. Add STA checks during STA PMF operations
2. Fix WPA2-Ent issue with Open AP
3. Skip WPA-TKIP profile if PMF is required
4. Skip & clear Supplicant PMK Cache with mismatching AP config
5. Use flag ESP32_WIFI_ENABLE_WPA3_SAE to control WPA3 code, disabling
   it code footprint reduces by 7.7kB in libwpa_supplicant.a
6. Fix handling of multiple AP credentials in WPS, apps need update
   to handle the new event for the fix to work

Closes https://github.com/espressif/esp-idf/issues/5971
Nachiket Kukade il y a 5 ans
Parent
commit
ffc87ab7d9

+ 4 - 0
components/esp_event/include/esp_event_legacy.h

@@ -80,6 +80,9 @@ typedef wifi_event_sta_authmode_change_t system_event_sta_authmode_change_t;
 /** Argument structure of SYSTEM_EVENT_STA_WPS_ER_PIN event */
 /** Argument structure of SYSTEM_EVENT_STA_WPS_ER_PIN event */
 typedef wifi_event_sta_wps_er_pin_t system_event_sta_wps_er_pin_t;
 typedef wifi_event_sta_wps_er_pin_t system_event_sta_wps_er_pin_t;
 
 
+/** Argument structure of SYSTEM_EVENT_STA_WPS_ER_PIN event */
+typedef wifi_event_sta_wps_er_success_t system_event_sta_wps_er_success_t;
+
 /** Argument structure of  event */
 /** Argument structure of  event */
 typedef wifi_event_ap_staconnected_t system_event_ap_staconnected_t;
 typedef wifi_event_ap_staconnected_t system_event_ap_staconnected_t;
 
 
@@ -107,6 +110,7 @@ typedef union {
     system_event_sta_got_ip_t                  got_ip;             /*!< ESP32 station got IP, first time got IP or when IP is changed */
     system_event_sta_got_ip_t                  got_ip;             /*!< ESP32 station got IP, first time got IP or when IP is changed */
     system_event_sta_wps_er_pin_t              sta_er_pin;         /*!< ESP32 station WPS enrollee mode PIN code received */
     system_event_sta_wps_er_pin_t              sta_er_pin;         /*!< ESP32 station WPS enrollee mode PIN code received */
     system_event_sta_wps_fail_reason_t         sta_er_fail_reason; /*!< ESP32 station WPS enrollee mode failed reason code received */
     system_event_sta_wps_fail_reason_t         sta_er_fail_reason; /*!< ESP32 station WPS enrollee mode failed reason code received */
+    system_event_sta_wps_er_success_t          sta_er_success;     /*!< ESP32 station WPS enrollee success */
     system_event_ap_staconnected_t             sta_connected;      /*!< a station connected to ESP32 soft-AP */
     system_event_ap_staconnected_t             sta_connected;      /*!< a station connected to ESP32 soft-AP */
     system_event_ap_stadisconnected_t          sta_disconnected;   /*!< a station disconnected to ESP32 soft-AP */
     system_event_ap_stadisconnected_t          sta_disconnected;   /*!< a station disconnected to ESP32 soft-AP */
     system_event_ap_probe_req_rx_t             ap_probereqrecved;  /*!< ESP32 soft-AP receive probe request packet */
     system_event_ap_probe_req_rx_t             ap_probereqrecved;  /*!< ESP32 soft-AP receive probe request packet */

+ 13 - 0
components/esp_wifi/include/esp_wifi_types.h

@@ -578,6 +578,19 @@ typedef enum {
     WPS_FAIL_REASON_MAX
     WPS_FAIL_REASON_MAX
 } wifi_event_sta_wps_fail_reason_t;
 } wifi_event_sta_wps_fail_reason_t;
 
 
+#define MAX_SSID_LEN        32
+#define MAX_PASSPHRASE_LEN  64
+#define MAX_WPS_AP_CRED     3
+
+/** Argument structure for WIFI_EVENT_STA_WPS_ER_SUCCESS event */
+typedef struct {
+    uint8_t ap_cred_cnt;                        /**< Number of AP credentials received */
+    struct {
+        uint8_t ssid[MAX_SSID_LEN];             /**< SSID of AP */
+        uint8_t passphrase[MAX_PASSPHRASE_LEN]; /**< Passphrase for the AP */
+    } ap_cred[MAX_WPS_AP_CRED];                 /**< All AP credentials received from WPS handshake */
+} wifi_event_sta_wps_er_success_t;
+
 /** Argument structure for WIFI_EVENT_AP_STACONNECTED event */
 /** Argument structure for WIFI_EVENT_AP_STACONNECTED event */
 typedef struct {
 typedef struct {
     uint8_t mac[6];           /**< MAC address of the station connected to ESP32 soft-AP */
     uint8_t mac[6];           /**< MAC address of the station connected to ESP32 soft-AP */

+ 4 - 1
components/wpa_supplicant/CMakeLists.txt

@@ -121,8 +121,11 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE
     ESP32_WORKAROUND
     ESP32_WORKAROUND
     CONFIG_ECC
     CONFIG_ECC
     CONFIG_IEEE80211W
     CONFIG_IEEE80211W
-    CONFIG_WPA3_SAE
     CONFIG_SHA256
     CONFIG_SHA256
     )
     )
 
 
+if(CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE)
+    target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_WPA3_SAE)
+endif()
+
 set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 3)
 set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 3)

+ 5 - 1
components/wpa_supplicant/component.mk

@@ -26,4 +26,8 @@ else
     COMPONENT_OBJEXCLUDE := src/crypto/tls_mbedtls.o
     COMPONENT_OBJEXCLUDE := src/crypto/tls_mbedtls.o
 endif
 endif
 
 
-CFLAGS += -DCONFIG_WPA3_SAE -DCONFIG_IEEE80211W -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_TLS -DEAP_TTLS -DEAP_PEAP -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DCONFIG_ECC -D__ets__ -Wno-strict-aliasing
+CFLAGS += -DCONFIG_IEEE80211W -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_TLS -DEAP_TTLS -DEAP_PEAP -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DCONFIG_ECC -D__ets__ -Wno-strict-aliasing
+
+ifdef CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE
+	CFLAGS += -DCONFIG_WPA3_SAE
+endif

+ 3 - 3
components/wpa_supplicant/src/common/wpa_common.c

@@ -58,11 +58,11 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
 		return WPA_KEY_MGMT_FT_PSK;
 		return WPA_KEY_MGMT_FT_PSK;
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
 #ifdef CONFIG_WPA3_SAE
 #ifdef CONFIG_WPA3_SAE
         if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
         if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
                 return WPA_KEY_MGMT_SAE;
                 return WPA_KEY_MGMT_SAE;
 #endif /* CONFIG_WPA3_SAE */
 #endif /* CONFIG_WPA3_SAE */
-#ifdef CONFIG_IEEE80211W
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
 		return WPA_KEY_MGMT_IEEE8021X_SHA256;
 		return WPA_KEY_MGMT_IEEE8021X_SHA256;
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
@@ -396,10 +396,10 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
 #ifdef CONFIG_IEEE80211W
 #ifdef CONFIG_IEEE80211W
 #ifdef CONFIG_WPA3_SAE
 #ifdef CONFIG_WPA3_SAE
        case WPA_KEY_INFO_TYPE_AKM_DEFINED:
        case WPA_KEY_INFO_TYPE_AKM_DEFINED:
-#endif
+#endif /* CONFIG_WPA3_SAE */
 	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
 	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
 		return omac1_aes_128(key, buf, len, mic);
 		return omac1_aes_128(key, buf, len, mic);
-#endif
+#endif /* CONFIG_IEEE80211W */
 	default:
 	default:
 		return -1;
 		return -1;
 	}
 	}

+ 1 - 0
components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h

@@ -234,5 +234,6 @@ uint16_t esp_wifi_sta_pmf_enabled(void);
 wifi_cipher_type_t esp_wifi_sta_get_mgmt_group_cipher(void);
 wifi_cipher_type_t esp_wifi_sta_get_mgmt_group_cipher(void);
 int esp_wifi_set_igtk_internal(uint8_t if_index, const wifi_wpa_igtk_t *igtk);
 int esp_wifi_set_igtk_internal(uint8_t if_index, const wifi_wpa_igtk_t *igtk);
 esp_err_t esp_wifi_internal_issue_disconnect(uint8_t reason_code);
 esp_err_t esp_wifi_internal_issue_disconnect(uint8_t reason_code);
+bool esp_wifi_skip_supp_pmkcaching(void);
 
 
 #endif /* _ESP_WIFI_DRIVER_H_ */
 #endif /* _ESP_WIFI_DRIVER_H_ */

+ 4 - 0
components/wpa_supplicant/src/esp_supplicant/esp_wpa3_i.h

@@ -31,5 +31,9 @@ static inline void esp_wifi_register_wpa3_cb(struct wpa_funcs *wpa_cb)
     wpa_cb->wpa3_parse_sae_msg = NULL;
     wpa_cb->wpa3_parse_sae_msg = NULL;
 }
 }
 
 
+static inline void esp_wpa3_free_sae_data(void)
+{
+}
+
 #endif /* CONFIG_WPA3_SAE */
 #endif /* CONFIG_WPA3_SAE */
 #endif /* ESP_WPA3_H */
 #endif /* ESP_WPA3_H */

+ 48 - 28
components/wpa_supplicant/src/esp_supplicant/esp_wps.c

@@ -593,19 +593,16 @@ wps_parse_scan_result(struct wps_scan_ie *scan)
             }
             }
 
 
             esp_wifi_enable_sta_privacy_internal();
             esp_wifi_enable_sta_privacy_internal();
-            os_bzero(sm->ssid, sizeof(sm->ssid));
-            strncpy((char *)sm->ssid, (char *)&scan->ssid[2], (int)scan->ssid[1]);
-            sm->ssid_len = scan->ssid[1];
+            strncpy((char *)sm->config.ssid, (char *)&scan->ssid[2], (int)scan->ssid[1]);
             if (scan->bssid) {
             if (scan->bssid) {
                 memcpy(gWpsSm->bssid, scan->bssid, ETH_ALEN);
                 memcpy(gWpsSm->bssid, scan->bssid, ETH_ALEN);
                 memcpy(sm->config.bssid, scan->bssid, ETH_ALEN);
                 memcpy(sm->config.bssid, scan->bssid, ETH_ALEN);
                 sm->config.bssid_set = 1;
                 sm->config.bssid_set = 1;
             } else {
             } else {
             }
             }
-            wpa_printf(MSG_DEBUG, "wps discover [%s]", sm->ssid);
+            wpa_printf(MSG_DEBUG, "wps discover [%s]", (char *)sm->config.ssid);
             sm->scan_cnt = 0;
             sm->scan_cnt = 0;
 
 
-            memcpy(sm->config.ssid, sm->ssid, sm->ssid_len);
             sm->channel = scan->chan;
             sm->channel = scan->chan;
 
 
             return true;
             return true;
@@ -943,9 +940,10 @@ int wps_stop_process(wifi_event_sta_wps_fail_reason_t reason_code)
     sm->discover_ssid_cnt = 0;
     sm->discover_ssid_cnt = 0;
     sm->wps->state = SEND_M1;
     sm->wps->state = SEND_M1;
     os_bzero(sm->bssid, ETH_ALEN);
     os_bzero(sm->bssid, ETH_ALEN);
-    os_bzero(sm->ssid, 32);
-    sm->ssid_len = 0;
+    os_bzero(sm->ssid, sizeof(sm->ssid));
+    os_bzero(sm->ssid_len, sizeof(sm->ssid_len));
     os_bzero((u8 *)&sm->config, sizeof(wifi_sta_config_t));
     os_bzero((u8 *)&sm->config, sizeof(wifi_sta_config_t));
+    sm->ap_cred_cnt = 0;
 
 
     esp_wifi_disarm_sta_connection_timer_internal();
     esp_wifi_disarm_sta_connection_timer_internal();
     ets_timer_disarm(&sm->wps_msg_timeout_timer);
     ets_timer_disarm(&sm->wps_msg_timeout_timer);
@@ -984,15 +982,17 @@ int wps_finish(void)
         ets_timer_disarm(&sm->wps_timeout_timer);
         ets_timer_disarm(&sm->wps_timeout_timer);
         ets_timer_disarm(&sm->wps_msg_timeout_timer);
         ets_timer_disarm(&sm->wps_msg_timeout_timer);
 
 
-        memset(config, 0x00, sizeof(wifi_sta_config_t));
-        memcpy(config->sta.ssid, sm->ssid, sm->ssid_len);
-        memcpy(config->sta.password, sm->key, sm->key_len);
-        memcpy(config->sta.bssid, sm->bssid, ETH_ALEN);
-        config->sta.bssid_set = 0;
-        esp_wifi_set_config(0, config);
-        os_free(config);
-        config = NULL;
+        if (sm->ap_cred_cnt == 1) {
+            memset(config, 0x00, sizeof(wifi_sta_config_t));
+            memcpy(config->sta.ssid, sm->ssid[0], sm->ssid_len[0]);
+            memcpy(config->sta.password, sm->key[0], sm->key_len[0]);
+            memcpy(config->sta.bssid, sm->bssid, ETH_ALEN);
+            config->sta.bssid_set = 0;
+            esp_wifi_set_config(0, config);
 
 
+            os_free(config);
+            config = NULL;
+        }
         ets_timer_disarm(&sm->wps_success_cb_timer);
         ets_timer_disarm(&sm->wps_success_cb_timer);
         ets_timer_arm(&sm->wps_success_cb_timer, 1000, 0);
         ets_timer_arm(&sm->wps_success_cb_timer, 1000, 0);
 
 
@@ -1496,7 +1496,26 @@ void wifi_station_wps_msg_timeout(void)
 
 
 void wifi_station_wps_success_internal(void)
 void wifi_station_wps_success_internal(void)
 {
 {
-    esp_event_send_internal(WIFI_EVENT, WIFI_EVENT_STA_WPS_ER_SUCCESS, 0, 0, portMAX_DELAY);
+    wifi_event_sta_wps_er_success_t evt = {0};
+    struct wps_sm *sm = gWpsSm;
+    int i;
+
+    /*
+     * For only one AP credential don't sned event data, wps_finish() has already set
+     * the config. This is for backward compatibility.
+     */
+    if (sm->ap_cred_cnt > 1) {
+        evt.ap_cred_cnt = sm->ap_cred_cnt;
+        for (i = 0; i < MAX_WPS_AP_CRED; i++) {
+            os_memcpy(evt.ap_cred[i].ssid, sm->ssid[i], sm->ssid_len[i]);
+            os_memcpy(evt.ap_cred[i].passphrase, sm->key[i], sm->key_len[i]);
+        }
+        esp_event_send_internal(WIFI_EVENT, WIFI_EVENT_STA_WPS_ER_SUCCESS, &evt,
+                                sizeof(evt), portMAX_DELAY);
+    } else {
+        esp_event_send_internal(WIFI_EVENT, WIFI_EVENT_STA_WPS_ER_SUCCESS,
+                                0, 0, portMAX_DELAY);
+    }
 }
 }
 
 
 void wifi_station_wps_success(void)
 void wifi_station_wps_success(void)
@@ -1707,44 +1726,45 @@ wps_sm_get(void)
 }
 }
 
 
 int
 int
-wps_ssid_save(u8 *ssid, u8 ssid_len)
+wps_ssid_save(u8 *ssid, u8 ssid_len, u8 idx)
 {
 {
     u8 *tmpssid;
     u8 *tmpssid;
 
 
-    if (!ssid || !gWpsSm) {
+    if (!ssid || !gWpsSm || idx > 2) {
         return ESP_FAIL;
         return ESP_FAIL;
     }
     }
 
 
-    memset(gWpsSm->ssid, 0x00, sizeof(gWpsSm->ssid));
-    memcpy(gWpsSm->ssid, ssid, ssid_len);
-    gWpsSm->ssid_len = ssid_len;
+    memset(gWpsSm->ssid[idx], 0x00, sizeof(gWpsSm->ssid[idx]));
+    memcpy(gWpsSm->ssid[idx], ssid, ssid_len);
+    gWpsSm->ssid_len[idx] = ssid_len;
+    gWpsSm->ap_cred_cnt++;
 
 
     tmpssid = (u8 *)os_zalloc(ssid_len + 1);
     tmpssid = (u8 *)os_zalloc(ssid_len + 1);
     if (tmpssid) {
     if (tmpssid) {
         memcpy(tmpssid, ssid, ssid_len);
         memcpy(tmpssid, ssid, ssid_len);
-        wpa_printf(MSG_DEBUG, "WPS: ssid[%s]", tmpssid);
+        wpa_printf(MSG_DEBUG, "WPS: key[%s]", tmpssid);
         os_free(tmpssid);
         os_free(tmpssid);
     }
     }
     return ESP_OK;
     return ESP_OK;
 }
 }
 
 
 int
 int
-wps_key_save(char *key, u8 key_len)
+wps_key_save(char *key, u8 key_len, u8 idx)
 {
 {
     u8 *tmpkey;
     u8 *tmpkey;
 
 
-    if (!key || !gWpsSm) {
+    if (!key || !gWpsSm || idx > 2) {
         return ESP_FAIL;
         return ESP_FAIL;
     }
     }
 
 
-    memset(gWpsSm->key, 0x00, sizeof(gWpsSm->key));
-    memcpy(gWpsSm->key, key, key_len);
-    gWpsSm->key_len = key_len;
+    memset(gWpsSm->key[idx], 0x00, sizeof(gWpsSm->key[idx]));
+    memcpy(gWpsSm->key[idx], key, key_len);
+    gWpsSm->key_len[idx] = key_len;
 
 
     tmpkey = (u8 *)os_zalloc(key_len + 1);
     tmpkey = (u8 *)os_zalloc(key_len + 1);
     if (tmpkey) {
     if (tmpkey) {
         memcpy(tmpkey, key, key_len);
         memcpy(tmpkey, key, key_len);
-        wpa_printf(MSG_DEBUG, "WPS: key[%s]", tmpkey);
+        wpa_printf(MSG_DEBUG, "WPS: key[%s], idx - %d", tmpkey, idx);
         os_free(tmpkey);
         os_free(tmpkey);
     }
     }
     return ESP_OK;
     return ESP_OK;

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

@@ -2128,8 +2128,19 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher,
     if (sm->key_mgmt == WPA_KEY_MGMT_SAE ||
     if (sm->key_mgmt == WPA_KEY_MGMT_SAE ||
         (esp_wifi_sta_prof_is_wpa2_internal() &&
         (esp_wifi_sta_prof_is_wpa2_internal() &&
          esp_wifi_sta_get_prof_authmode_internal() == WPA2_AUTH_ENT)) {
          esp_wifi_sta_get_prof_authmode_internal() == WPA2_AUTH_ENT)) {
-        pmksa_cache_set_current(sm, NULL, (const u8*) bssid, 0, 0);
-        wpa_sm_set_pmk_from_pmksa(sm);
+        if (!esp_wifi_skip_supp_pmkcaching()) {
+            pmksa_cache_set_current(sm, NULL, (const u8*) bssid, 0, 0);
+            wpa_sm_set_pmk_from_pmksa(sm);
+        } else {
+            struct rsn_pmksa_cache_entry *entry = NULL;
+
+            if (sm->pmksa) {
+                entry = pmksa_cache_get(sm->pmksa, (const u8 *)bssid, NULL, NULL);
+            }
+            if (entry) {
+                pmksa_cache_flush(sm->pmksa, NULL, entry->pmk, entry->pmk_len);
+            }
+        }
     }
     }
 
 
     sm->eapol1_count = 0;
     sm->eapol1_count = 0;

+ 1 - 1
components/wpa_supplicant/src/rsn_supp/wpa_ie.c

@@ -203,11 +203,11 @@ static int  wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
     } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
     } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
-#endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_WPA3_SAE
 #ifdef CONFIG_WPA3_SAE
     } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
     } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
 #endif /* CONFIG_WPA3_SAE */
 #endif /* CONFIG_WPA3_SAE */
+#endif /* CONFIG_IEEE80211W */
     } else {
     } else {
         wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
         wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
                key_mgmt);
                key_mgmt);

+ 7 - 6
components/wpa_supplicant/src/wps/wps.h

@@ -1031,13 +1031,14 @@ struct wps_sm {
     u8 identity_len;
     u8 identity_len;
     u8 ownaddr[ETH_ALEN];
     u8 ownaddr[ETH_ALEN];
     u8 bssid[ETH_ALEN];
     u8 bssid[ETH_ALEN];
-    u8 ssid[32];
-    u8 ssid_len;
+    u8 ssid[MAX_WPS_AP_CRED][MAX_SSID_LEN];
+    u8 ssid_len[MAX_WPS_AP_CRED];
+    char key[MAX_WPS_AP_CRED][MAX_PASSPHRASE_LEN];
+    u8 key_len[MAX_WPS_AP_CRED];
+    u8 ap_cred_cnt;
     struct wps_device_data *dev;
     struct wps_device_data *dev;
     u8 uuid[16];
     u8 uuid[16];
     u8 eapol_version;
     u8 eapol_version;
-    char key[64];
-    u8 key_len;
     ETSTimer wps_timeout_timer;
     ETSTimer wps_timeout_timer;
     ETSTimer wps_msg_timeout_timer;
     ETSTimer wps_msg_timeout_timer;
     ETSTimer wps_scan_timer;
     ETSTimer wps_scan_timer;
@@ -1061,8 +1062,8 @@ struct wps_sm {
 #define    WIFI_CAPINFO_PRIVACY        0x0010
 #define    WIFI_CAPINFO_PRIVACY        0x0010
 
 
 struct wps_sm *wps_sm_get(void);
 struct wps_sm *wps_sm_get(void);
-int wps_ssid_save(u8 *ssid, u8 ssid_len);
-int wps_key_save(char *key, u8 key_len);
+int wps_ssid_save(u8 *ssid, u8 ssid_len, u8 idx);
+int wps_key_save(char *key, u8 key_len, u8 idx);
 int wps_station_wps_register_cb(wps_st_cb_t cb);
 int wps_station_wps_register_cb(wps_st_cb_t cb);
 int wps_station_wps_unregister_cb(void);
 int wps_station_wps_unregister_cb(void);
 int wps_start_pending(void);
 int wps_start_pending(void);

+ 4 - 5
components/wpa_supplicant/src/wps/wps_enrollee.c

@@ -652,7 +652,7 @@ static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)
 
 
 
 
 static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
 static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
-			      size_t cred_len, int wps2)
+			      size_t cred_len, int cred_idx, int wps2)
 {
 {
 	struct wps_parse_attr *attr;
 	struct wps_parse_attr *attr;
 	struct wpabuf msg;
 	struct wpabuf msg;
@@ -712,9 +712,8 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
 		goto _out;
 		goto _out;
 	}
 	}
 #endif /* CONFIG_WPS2 */
 #endif /* CONFIG_WPS2 */
-
-	    wps_ssid_save(wps->cred.ssid, wps->cred.ssid_len);
-        wps_key_save((char *)wps->cred.key, wps->cred.key_len);
+    wps_ssid_save(wps->cred.ssid, wps->cred.ssid_len, cred_idx);
+    wps_key_save((char *)wps->cred.key, wps->cred.key_len, cred_idx);
 
 
 	if (wps->wps->cred_cb) {
 	if (wps->wps->cred_cb) {
 		wps->cred.cred_attr = cred - 4;
 		wps->cred.cred_attr = cred - 4;
@@ -749,7 +748,7 @@ static int wps_process_creds(struct wps_data *wps, const u8 *cred[],
 
 
 	for (i = 0; i < num_cred; i++) {
 	for (i = 0; i < num_cred; i++) {
 		int res;
 		int res;
-		res = wps_process_cred_e(wps, cred[i], cred_len[i], wps2);
+		res = wps_process_cred_e(wps, cred[i], cred_len[i], i, wps2);
 		if (res == 0)
 		if (res == 0)
 			ok++;
 			ok++;
 		else if (res == -2) {
 		else if (res == -2) {

+ 50 - 4
examples/wifi/wps/main/wps.c

@@ -27,6 +27,7 @@
 #include "esp_wps.h"
 #include "esp_wps.h"
 #include "esp_event.h"
 #include "esp_event.h"
 #include "nvs_flash.h"
 #include "nvs_flash.h"
+#include <string.h>
 
 
 
 
 /*set wps mode via project configuration */
 /*set wps mode via project configuration */
@@ -38,6 +39,7 @@
 #define WPS_MODE WPS_TYPE_DISABLE
 #define WPS_MODE WPS_TYPE_DISABLE
 #endif /*CONFIG_EXAMPLE_WPS_TYPE_PBC*/
 #endif /*CONFIG_EXAMPLE_WPS_TYPE_PBC*/
 
 
+#define MAX_RETRY_ATTEMPTS     2
 
 
 #ifndef PIN2STR
 #ifndef PIN2STR
 #define PIN2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5], (a)[6], (a)[7]
 #define PIN2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5], (a)[6], (a)[7]
@@ -46,23 +48,67 @@
 
 
 static const char *TAG = "example_wps";
 static const char *TAG = "example_wps";
 static esp_wps_config_t config = WPS_CONFIG_INIT_DEFAULT(WPS_MODE);
 static esp_wps_config_t config = WPS_CONFIG_INIT_DEFAULT(WPS_MODE);
+static wifi_config_t wps_ap_creds[MAX_WPS_AP_CRED];
+static int s_ap_creds_num = 0;
+static int s_retry_num = 0;
 
 
 static void wifi_event_handler(void* arg, esp_event_base_t event_base,
 static void wifi_event_handler(void* arg, esp_event_base_t event_base,
                                 int32_t event_id, void* event_data)
                                 int32_t event_id, void* event_data)
 {
 {
+    static int ap_idx = 1;
+
     switch (event_id) {
     switch (event_id) {
         case WIFI_EVENT_STA_START:
         case WIFI_EVENT_STA_START:
             ESP_LOGI(TAG, "WIFI_EVENT_STA_START");
             ESP_LOGI(TAG, "WIFI_EVENT_STA_START");
             break;
             break;
         case WIFI_EVENT_STA_DISCONNECTED:
         case WIFI_EVENT_STA_DISCONNECTED:
             ESP_LOGI(TAG, "WIFI_EVENT_STA_DISCONNECTED");
             ESP_LOGI(TAG, "WIFI_EVENT_STA_DISCONNECTED");
-            ESP_ERROR_CHECK(esp_wifi_connect());
+            if (s_retry_num < MAX_RETRY_ATTEMPTS) {
+                ESP_ERROR_CHECK(esp_wifi_connect());
+                s_retry_num++;
+            } else if (ap_idx < s_ap_creds_num) {
+                /* Try the next AP credential if first one fails */
+
+                if (ap_idx < s_ap_creds_num) {
+                    ESP_LOGI(TAG, "Connecting to SSID: %s, Passphrase: %s",
+                             wps_ap_creds[ap_idx].sta.ssid, wps_ap_creds[ap_idx].sta.password);
+                    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wps_ap_creds[ap_idx++]) );
+                    ESP_ERROR_CHECK(esp_wifi_connect());
+                }
+                s_retry_num = 0;
+            } else {
+                ESP_LOGI(TAG, "Failed to connect!");
+            }
+
             break;
             break;
         case WIFI_EVENT_STA_WPS_ER_SUCCESS:
         case WIFI_EVENT_STA_WPS_ER_SUCCESS:
             ESP_LOGI(TAG, "WIFI_EVENT_STA_WPS_ER_SUCCESS");
             ESP_LOGI(TAG, "WIFI_EVENT_STA_WPS_ER_SUCCESS");
-            /* esp_wifi_wps_start() only gets ssid & password, so call esp_wifi_connect() here. */
-            ESP_ERROR_CHECK(esp_wifi_wps_disable());
-            ESP_ERROR_CHECK(esp_wifi_connect());
+            {
+                wifi_event_sta_wps_er_success_t *evt =
+                    (wifi_event_sta_wps_er_success_t *)event_data;
+                int i;
+
+                if (evt) {
+                    s_ap_creds_num = evt->ap_cred_cnt;
+                    for (i = 0; i < s_ap_creds_num; i++) {
+                        memcpy(wps_ap_creds[i].sta.ssid, evt->ap_cred[i].ssid,
+                               sizeof(evt->ap_cred[i].ssid));
+                        memcpy(wps_ap_creds[i].sta.password, evt->ap_cred[i].passphrase,
+                               sizeof(evt->ap_cred[i].passphrase));
+                    }
+                    /* If multiple AP credentials are received from WPS, connect with first one */
+                    ESP_LOGI(TAG, "Connecting to SSID: %s, Passphrase: %s",
+                             wps_ap_creds[0].sta.ssid, wps_ap_creds[0].sta.password);
+                    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wps_ap_creds[0]) );
+                }
+                /*
+                 * If only one AP credential is received from WPS, there will be no event data and
+                 * esp_wifi_set_config() is already called by WPS modules for backward compatibility
+                 * with legacy apps. So directly attempt connection here.
+                 */
+                ESP_ERROR_CHECK(esp_wifi_wps_disable());
+                ESP_ERROR_CHECK(esp_wifi_connect());
+            }
             break;
             break;
         case WIFI_EVENT_STA_WPS_ER_FAILED:
         case WIFI_EVENT_STA_WPS_ER_FAILED:
             ESP_LOGI(TAG, "WIFI_EVENT_STA_WPS_ER_FAILED");
             ESP_LOGI(TAG, "WIFI_EVENT_STA_WPS_ER_FAILED");