Quellcode durchsuchen

Merge branch 'bugfix/fix_some_wifi_bugs_1120_v4.1' into 'release/v4.1'

WiFi: fix some wifi bugs 1120 (backport v4.1)

See merge request espressif/esp-idf!11317
Jiang Jiang Jian vor 5 Jahren
Ursprung
Commit
5b73ec939c
42 geänderte Dateien mit 495 neuen und 141 gelöschten Zeilen
  1. 6 0
      components/esp_common/src/esp_err_to_name.c
  2. 4 0
      components/esp_event/include/esp_event_legacy.h
  3. 16 0
      components/esp_netif/include/esp_netif.h
  4. 14 0
      components/esp_netif/include/esp_netif_net_stack.h
  5. 1 0
      components/esp_netif/include/esp_netif_types.h
  6. 19 0
      components/esp_netif/lwip/esp_netif_lwip.c
  7. 1 0
      components/esp_netif/lwip/esp_netif_lwip_internal.h
  8. 17 6
      components/esp_wifi/Kconfig
  9. 67 14
      components/esp_wifi/include/esp_private/wifi.h
  10. 22 8
      components/esp_wifi/include/esp_wifi.h
  11. 3 1
      components/esp_wifi/include/esp_wifi_crypto_types.h
  12. 20 1
      components/esp_wifi/include/esp_wifi_types.h
  13. 1 1
      components/esp_wifi/lib
  14. 4 0
      components/esp_wifi/src/wifi_default.c
  15. 35 1
      components/esp_wifi/src/wifi_init.c
  16. 11 0
      components/esp_wifi/src/wifi_netif.c
  17. 11 2
      components/lwip/Kconfig
  18. 12 4
      components/lwip/port/esp32/netif/wlanif.c
  19. 4 1
      components/wpa_supplicant/CMakeLists.txt
  20. 11 0
      components/wpa_supplicant/Kconfig
  21. 5 1
      components/wpa_supplicant/component.mk
  22. 20 23
      components/wpa_supplicant/include/utils/wpa_debug.h
  23. 4 0
      components/wpa_supplicant/port/include/supplicant_opt.h
  24. 3 3
      components/wpa_supplicant/src/common/wpa_common.c
  25. 8 2
      components/wpa_supplicant/src/crypto/aes-ccm.c
  26. 2 2
      components/wpa_supplicant/src/crypto/aes.h
  27. 14 13
      components/wpa_supplicant/src/crypto/ccmp.c
  28. 1 1
      components/wpa_supplicant/src/crypto/ccmp.h
  29. 2 0
      components/wpa_supplicant/src/eap_peer/eap_tls_common.c
  30. 2 0
      components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h
  31. 2 4
      components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c
  32. 4 0
      components/wpa_supplicant/src/esp_supplicant/esp_wpa3_i.h
  33. 48 28
      components/wpa_supplicant/src/esp_supplicant/esp_wps.c
  34. 23 2
      components/wpa_supplicant/src/rsn_supp/wpa.c
  35. 1 0
      components/wpa_supplicant/src/rsn_supp/wpa_i.h
  36. 1 1
      components/wpa_supplicant/src/rsn_supp/wpa_ie.c
  37. 7 6
      components/wpa_supplicant/src/wps/wps.h
  38. 4 5
      components/wpa_supplicant/src/wps/wps_enrollee.c
  39. 10 2
      components/wpa_supplicant/src/wps/wps_registrar.c
  40. 2 2
      examples/wifi/README.md
  41. 3 3
      examples/wifi/iperf/components/iperf/iperf.c
  42. 50 4
      examples/wifi/wps/main/wps.c

+ 6 - 0
components/esp_common/src/esp_err_to_name.c

@@ -351,6 +351,12 @@ static const esp_err_msg_t esp_err_msg_table[] = {
 #   endif
 #   ifdef      ESP_ERR_WIFI_STOP_STATE
     ERR_TBL_IT(ESP_ERR_WIFI_STOP_STATE),                        /* 12308 0x3014 Returned when WiFi is stopping */
+#   endif
+#   ifdef      ESP_ERR_WIFI_NOT_ASSOC
+    ERR_TBL_IT(ESP_ERR_WIFI_NOT_ASSOC),                         /* 12309 0x3015 The WiFi connection is not associated */
+#   endif
+#   ifdef      ESP_ERR_WIFI_TX_DISALLOW
+    ERR_TBL_IT(ESP_ERR_WIFI_TX_DISALLOW),                       /* 12310 0x3016 The WiFi TX is disallowed */
 #   endif
     // components/wpa_supplicant/include/esp_supplicant/esp_wps.h
 #   ifdef      ESP_ERR_WIFI_REGISTRAR

+ 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 */
 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 */
 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_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_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_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 */

+ 16 - 0
components/esp_netif/include/esp_netif.h

@@ -760,6 +760,22 @@ esp_netif_t *esp_netif_next(esp_netif_t *esp_netif);
  */
 size_t esp_netif_get_nr_of_ifs(void);
 
+/**
+ * @brief increase the reference counter of net stack buffer
+ *
+ * @param[in]  netstack_buf the net stack buffer
+ *
+ */
+void esp_netif_netstack_buf_ref(void *netstack_buf);
+
+/**
+ * @brief free the netstack buffer
+ *
+ * @param[in]  netstack_buf the net stack buffer
+ *
+ */
+void esp_netif_netstack_buf_free(void *netstack_buf);
+
 /**
  * @}
  */

+ 14 - 0
components/esp_netif/include/esp_netif_net_stack.h

@@ -69,6 +69,20 @@ void* esp_netif_get_netif_impl(esp_netif_t *esp_netif);
   */
 esp_err_t esp_netif_transmit(esp_netif_t *esp_netif, void* data, size_t len);
 
+/**
+  * @brief  Outputs packets from the TCP/IP stack to the media to be transmitted
+  *
+  * This function gets called from network stack to output packets to IO driver.
+  *
+  * @param[in]  esp_netif Handle to esp-netif instance
+  * @param[in]  data Data to be transmitted
+  * @param[in]  len Length of the data frame
+  * @param[in]  netstack_buf net stack buffer
+  *
+  * @return   ESP_OK on success, an error passed from the I/O driver otherwise
+  */
+esp_err_t esp_netif_transmit_wrap(esp_netif_t *esp_netif, void *data, size_t len, void *netstack_buf);
+
 /**
   * @brief  Free the rx buffer allocated by the media driver
   *

+ 1 - 0
components/esp_netif/include/esp_netif_types.h

@@ -182,6 +182,7 @@ typedef struct esp_netif_driver_base_s {
 struct esp_netif_driver_ifconfig {
     esp_netif_iodriver_handle handle;
     esp_err_t (*transmit)(void *h, void *buffer, size_t len);
+    esp_err_t (*transmit_wrap)(void *h, void *buffer, size_t len, void *netstack_buffer);
     void (*driver_free_rx_buffer)(void *h, void* buffer);
 };
 

+ 19 - 0
components/esp_netif/lwip/esp_netif_lwip.c

@@ -384,6 +384,9 @@ static esp_err_t esp_netif_init_configuration(esp_netif_t *esp_netif, const esp_
         if (esp_netif_driver_config->transmit) {
             esp_netif->driver_transmit = esp_netif_driver_config->transmit;
         }
+        if (esp_netif_driver_config->transmit_wrap) {
+            esp_netif->driver_transmit_wrap = esp_netif_driver_config->transmit_wrap;
+        }
         if (esp_netif_driver_config->driver_free_rx_buffer) {
             esp_netif->driver_free_rx_buffer = esp_netif_driver_config->driver_free_rx_buffer;
         }
@@ -538,6 +541,7 @@ esp_err_t esp_netif_set_driver_config(esp_netif_t *esp_netif,
     }
     esp_netif->driver_handle = driver_config->handle;
     esp_netif->driver_transmit = driver_config->transmit;
+    esp_netif->driver_transmit_wrap = driver_config->transmit_wrap;
     esp_netif->driver_free_rx_buffer = driver_config->driver_free_rx_buffer;
     return ESP_OK;
 }
@@ -725,6 +729,16 @@ esp_err_t esp_netif_stop(esp_netif_t *esp_netif)
     return esp_netif_lwip_ipc_call(esp_netif_stop_api, esp_netif, NULL);
 }
 
+void esp_netif_netstack_buf_ref(void *pbuf)
+{
+    pbuf_ref(pbuf);
+}
+
+void esp_netif_netstack_buf_free(void *pbuf)
+{
+    pbuf_free(pbuf);
+}
+
 //
 // IO translate functions
 //
@@ -739,6 +753,11 @@ esp_err_t esp_netif_transmit(esp_netif_t *esp_netif, void* data, size_t len)
     return (esp_netif->driver_transmit)(esp_netif->driver_handle, data, len);
 }
 
+esp_err_t esp_netif_transmit_wrap(esp_netif_t *esp_netif, void *data, size_t len, void *pbuf)
+{
+    return (esp_netif->driver_transmit_wrap)(esp_netif->driver_handle, data, len, pbuf);
+}
+
 esp_err_t esp_netif_receive(esp_netif_t *esp_netif, void *buffer, size_t len, void *eb)
 {
     esp_netif->lwip_input_fn(esp_netif->netif_handle, buffer, len, eb);

+ 1 - 0
components/esp_netif/lwip/esp_netif_lwip_internal.h

@@ -81,6 +81,7 @@ struct esp_netif_obj {
     // io driver related
     void* driver_handle;
     esp_err_t (*driver_transmit)(void *h, void *buffer, size_t len);
+    esp_err_t (*driver_transmit_wrap)(void *h, void *buffer, size_t len, void *pbuf);
     void (*driver_free_rx_buffer)(void *h, void* buffer);
 
     // dhcp related

+ 17 - 6
components/esp_wifi/Kconfig

@@ -14,8 +14,7 @@ menu "Wi-Fi"
 
     config ESP32_WIFI_STATIC_RX_BUFFER_NUM
         int "Max number of WiFi static RX buffers"
-        range 2 25 if !SPIRAM_TRY_ALLOCATE_WIFI_LWIP
-        range 8 25 if SPIRAM_TRY_ALLOCATE_WIFI_LWIP
+        range 2 25
         default 10 if !SPIRAM_TRY_ALLOCATE_WIFI_LWIP
         default 16 if SPIRAM_TRY_ALLOCATE_WIFI_LWIP
         help
@@ -79,7 +78,7 @@ menu "Wi-Fi"
     config ESP32_WIFI_STATIC_TX_BUFFER_NUM
         int "Max number of WiFi static TX buffers"
         depends on ESP32_WIFI_STATIC_TX_BUFFER
-        range 6 64
+        range 1 64
         default 16
         help
             Set the number of WiFi static TX buffers. Each buffer takes approximately 1.6KB of RAM.
@@ -91,10 +90,23 @@ menu "Wi-Fi"
             layer can deliver frames faster than WiFi layer can transmit. In these cases, we may run out
             of TX buffers.
 
+    config ESP32_WIFI_CACHE_TX_BUFFER_NUM
+        int "Max number of WiFi cache TX buffers"
+        depends on (ESP32_SPIRAM_SUPPORT || ESP32S2_SPIRAM_SUPPORT)
+        range 16 128
+        default 32
+        help
+            Set the number of WiFi cache TX buffer number.
+
+            For each TX packet from uplayer, such as LWIP etc, WiFi driver needs to allocate a static TX
+            buffer and makes a copy of uplayer packet. If WiFi driver fails to allocate the static TX buffer,
+            it caches the uplayer packets to a dedicated buffer queue, this option is used to configure the
+            size of the cached TX queue.
+
     config ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM
         int "Max number of WiFi dynamic TX buffers"
         depends on ESP32_WIFI_DYNAMIC_TX_BUFFER
-        range 16 128
+        range 1 128
         default 32
         help
             Set the number of WiFi dynamic TX buffers. The size of each dynamic TX buffer is not fixed,
@@ -140,8 +152,7 @@ menu "Wi-Fi"
     config ESP32_WIFI_RX_BA_WIN
         int "WiFi AMPDU RX BA window size"
         depends on ESP32_WIFI_AMPDU_RX_ENABLED
-        range 2 32 if !SPIRAM_TRY_ALLOCATE_WIFI_LWIP
-        range 16 32 if SPIRAM_TRY_ALLOCATE_WIFI_LWIP
+        range 2 32
         default 6 if !SPIRAM_TRY_ALLOCATE_WIFI_LWIP
         default 16 if SPIRAM_TRY_ALLOCATE_WIFI_LWIP
         help

+ 67 - 14
components/esp_wifi/include/esp_private/wifi.h

@@ -53,7 +53,8 @@ typedef struct {
   *
   */
 typedef enum {
-    WIFI_LOG_ERROR = 0,   /*enabled by default*/
+    WIFI_LOG_NONE = 0,
+    WIFI_LOG_ERROR,       /*enabled by default*/
     WIFI_LOG_WARNING,     /*enabled by default*/
     WIFI_LOG_INFO,        /*enabled by default*/
     WIFI_LOG_DEBUG,       /*can be set in menuconfig*/
@@ -119,15 +120,6 @@ esp_err_t esp_wifi_init_internal(const wifi_init_config_t *config);
  */
 esp_err_t esp_wifi_deinit_internal(void);
 
-/**
-  * @brief  get whether the wifi driver is allowed to transmit data or not
-  *
-  * @return
-  *     - true  : upper layer should stop to transmit data to wifi driver
-  *     - false : upper layer can transmit data to wifi driver
-  */
-bool esp_wifi_internal_tx_is_stop(void);
-
 /**
   * @brief  free the rx buffer which allocated by wifi driver
   *
@@ -138,18 +130,79 @@ void esp_wifi_internal_free_rx_buffer(void* buffer);
 /**
   * @brief  transmit the buffer via wifi driver
   *
+  * This API makes a copy of the input buffer and then forwards the buffer
+  * copy to WiFi driver.
+  *
   * @param  wifi_interface_t wifi_if : wifi interface id
   * @param  void *buffer : the buffer to be tansmit
   * @param  uint16_t len : the length of buffer
   *
   * @return
-  *    - ERR_OK  : Successfully transmit the buffer to wifi driver
-  *    - ERR_MEM : Out of memory
-  *    - ERR_IF : WiFi driver error
-  *    - ERR_ARG : Invalid argument
+  *    - ESP_OK  : Successfully transmit the buffer to wifi driver
+  *    - ESP_ERR_NO_MEM: out of memory
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - ESP_ERR_WIFI_IF : WiFi interface is invalid
+  *    - ESP_ERR_WIFI_CONN : WiFi interface is not created, e.g. send the data to STA while WiFi mode is AP mode
+  *    - ESP_ERR_WIFI_NOT_STARTED : WiFi is not started
+  *    - ESP_ERR_WIFI_STATE : WiFi internal state is not ready, e.g. WiFi is not started
+  *    - ESP_ERR_WIFI_NOT_ASSOC : WiFi is not associated
+  *    - ESP_ERR_WIFI_TX_DISALLOW : WiFi TX is disallowed, e.g. WiFi hasn't pass the authentication 
+  *    - ESP_ERR_WIFI_POST : caller fails to post event to WiFi task
   */
 int esp_wifi_internal_tx(wifi_interface_t wifi_if, void *buffer, uint16_t len);
 
+/**
+  * @brief     The net stack buffer reference counter callback function
+  *
+  */
+typedef void (*wifi_netstack_buf_ref_cb_t)(void *netstack_buf);
+
+/**
+  * @brief     The net stack buffer free callback function
+  *
+  */
+typedef void (*wifi_netstack_buf_free_cb_t)(void *netstack_buf);
+
+/**
+  * @brief  transmit the buffer by reference via wifi driver
+  *
+  * This API firstly increases the reference counter of the input buffer and
+  * then forwards the buffer to WiFi driver. The WiFi driver will free the buffer
+  * after processing it. Use esp_wifi_internal_tx() if the uplayer buffer doesn't
+  * supports reference counter.
+  * 
+  * @param  wifi_if : wifi interface id
+  * @param  buffer : the buffer to be tansmit
+  * @param  len : the length of buffer
+  * @param  netstack_buf : the netstack buffer related to bufffer
+  *
+  * @return
+  *    - ESP_OK  : Successfully transmit the buffer to wifi driver
+  *    - ESP_ERR_NO_MEM: out of memory
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - ESP_ERR_WIFI_IF : WiFi interface is invalid
+  *    - ESP_ERR_WIFI_CONN : WiFi interface is not created, e.g. send the data to STA while WiFi mode is AP mode
+  *    - ESP_ERR_WIFI_NOT_STARTED : WiFi is not started
+  *    - ESP_ERR_WIFI_STATE : WiFi internal state is not ready, e.g. WiFi is not started
+  *    - ESP_ERR_WIFI_NOT_ASSOC : WiFi is not associated
+  *    - ESP_ERR_WIFI_TX_DISALLOW : WiFi TX is disallowed, e.g. WiFi hasn't pass the authentication 
+  *    - ESP_ERR_WIFI_POST : caller fails to post event to WiFi task
+  */
+esp_err_t esp_wifi_internal_tx_by_ref(wifi_interface_t ifx, void *buffer, size_t len, void *netstack_buf);
+
+/**
+  * @brief  register the net stack buffer reference increasing and free callback
+  *
+  * @param  ref : net stack buffer reference callback
+  * @param  free: net stack buffer free callback
+  *
+  * @return
+  *    - ESP_OK  : Successfully transmit the buffer to wifi driver
+  *    - others  : failed to register the callback
+  */
+esp_err_t esp_wifi_internal_reg_netstack_buf_cb(wifi_netstack_buf_ref_cb_t ref, wifi_netstack_buf_free_cb_t free);
+
+
 /**
   * @brief     The WiFi RX callback function
   *

+ 22 - 8
components/esp_wifi/include/esp_wifi.h

@@ -88,6 +88,8 @@ extern "C" {
 #define ESP_ERR_WIFI_POST        (ESP_ERR_WIFI_BASE + 18)  /*!< Failed to post the event to WiFi task */
 #define ESP_ERR_WIFI_INIT_STATE  (ESP_ERR_WIFI_BASE + 19)  /*!< Invalod WiFi state when init/deinit is called */
 #define ESP_ERR_WIFI_STOP_STATE  (ESP_ERR_WIFI_BASE + 20)  /*!< Returned when WiFi is stopping */
+#define ESP_ERR_WIFI_NOT_ASSOC   (ESP_ERR_WIFI_BASE + 21)  /*!< The WiFi connection is not associated */
+#define ESP_ERR_WIFI_TX_DISALLOW (ESP_ERR_WIFI_BASE + 22)  /*!< The WiFi TX is disallowed */
 
 /**
  * @brief WiFi stack configuration parameters passed to esp_wifi_init call.
@@ -101,12 +103,12 @@ typedef struct {
     int                    tx_buf_type;            /**< WiFi TX buffer type */
     int                    static_tx_buf_num;      /**< WiFi static TX buffer number */
     int                    dynamic_tx_buf_num;     /**< WiFi dynamic TX buffer number */
+    int                    cache_tx_buf_num;       /**< WiFi TX cache buffer number */
     int                    csi_enable;             /**< WiFi channel state information enable flag */
     int                    ampdu_rx_enable;        /**< WiFi AMPDU RX feature enable flag */
     int                    ampdu_tx_enable;        /**< WiFi AMPDU TX feature enable flag */
     int                    nvs_enable;             /**< WiFi NVS flash enable flag */
     int                    nano_enable;            /**< Nano option for printf/scan family enable flag */
-    int                    tx_ba_win;              /**< WiFi Block Ack TX window size */
     int                    rx_ba_win;              /**< WiFi Block Ack RX window size */
     int                    wifi_task_core_id;      /**< WiFi Task Core ID */
     int                    beacon_max_len;         /**< WiFi softAP maximum length of the beacon */
@@ -121,6 +123,12 @@ typedef struct {
 #define WIFI_STATIC_TX_BUFFER_NUM 0
 #endif
 
+#if (CONFIG_ESP32_SPIRAM_SUPPORT | CONFIG_ESP32S2_SPIRAM_SUPPORT)
+#define WIFI_CACHE_TX_BUFFER_NUM  CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM
+#else
+#define WIFI_CACHE_TX_BUFFER_NUM  0
+#endif
+
 #ifdef CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM
 #define WIFI_DYNAMIC_TX_BUFFER_NUM CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM
 #else
@@ -162,12 +170,6 @@ extern uint64_t g_wifi_feature_caps;
 
 #define WIFI_INIT_CONFIG_MAGIC    0x1F2F3F4F
 
-#ifdef CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED
-#define WIFI_DEFAULT_TX_BA_WIN CONFIG_ESP32_WIFI_TX_BA_WIN
-#else
-#define WIFI_DEFAULT_TX_BA_WIN 0 /* unused if ampdu_tx_enable == false */
-#endif
-
 #ifdef CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED
 #define WIFI_DEFAULT_RX_BA_WIN CONFIG_ESP32_WIFI_RX_BA_WIN
 #else
@@ -193,6 +195,7 @@ extern uint64_t g_wifi_feature_caps;
 #endif
 
 #define CONFIG_FEATURE_WPA3_SAE_BIT     (1<<0)
+#define CONFIG_FEATURE_CACHE_TX_BUF_BIT (1<<1)
 
 #define WIFI_INIT_CONFIG_DEFAULT() { \
     .event_handler = &esp_event_send_internal, \
@@ -203,12 +206,12 @@ extern uint64_t g_wifi_feature_caps;
     .tx_buf_type = CONFIG_ESP32_WIFI_TX_BUFFER_TYPE,\
     .static_tx_buf_num = WIFI_STATIC_TX_BUFFER_NUM,\
     .dynamic_tx_buf_num = WIFI_DYNAMIC_TX_BUFFER_NUM,\
+    .cache_tx_buf_num = WIFI_CACHE_TX_BUFFER_NUM,\
     .csi_enable = WIFI_CSI_ENABLED,\
     .ampdu_rx_enable = WIFI_AMPDU_RX_ENABLED,\
     .ampdu_tx_enable = WIFI_AMPDU_TX_ENABLED,\
     .nvs_enable = WIFI_NVS_ENABLED,\
     .nano_enable = WIFI_NANO_FORMAT_ENABLED,\
-    .tx_ba_win = WIFI_DEFAULT_TX_BA_WIN,\
     .rx_ba_win = WIFI_DEFAULT_RX_BA_WIN,\
     .wifi_task_core_id = WIFI_TASK_CORE_ID,\
     .beacon_max_len = WIFI_SOFTAP_BEACON_MAX_LEN, \
@@ -1124,6 +1127,17 @@ esp_err_t esp_wifi_set_inactive_time(wifi_interface_t ifx, uint16_t sec);
   */
 esp_err_t esp_wifi_get_inactive_time(wifi_interface_t ifx, uint16_t *sec);
 
+/**
+  * @brief     Dump WiFi statistics
+  *
+  * @param     modules statistic modules to be dumped
+  *
+  * @return
+  *    - ESP_OK: succeed
+  *    - others: failed
+  */
+esp_err_t esp_wifi_statis_dump(uint32_t modules);
+
 #ifdef __cplusplus
 }
 #endif

+ 3 - 1
components/esp_wifi/include/esp_wifi_crypto_types.h

@@ -336,10 +336,12 @@ typedef int (*esp_omac1_aes_128_t)(const uint8_t *key, const uint8_t *data, size
  * @data: Pointer to encrypted data buffer
  * @data_len: Encrypted data length in bytes
  * @decrypted_len: Length of decrypted data
+ * @espnow_pkt: Indicates if it's an ESPNOW packet
  * Returns: Pointer to decrypted data on success, NULL on failure
  */
 typedef uint8_t * (*esp_ccmp_decrypt_t)(const uint8_t *tk, const uint8_t *ieee80211_hdr,
-                                        const uint8_t *data, size_t data_len, size_t *decrypted_len);
+                                        const uint8_t *data, size_t data_len,
+                                        size_t *decrypted_len, bool espnow_pkt);
 
 /**
  * @brief Encrypt data using CCMP (Counter Mode CBC-MAC Protocol OR

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

@@ -220,7 +220,7 @@ typedef struct {
     wifi_auth_mode_t authmode;  /**< Auth mode of ESP32 soft-AP. Do not support AUTH_WEP in soft-AP mode */
     uint8_t ssid_hidden;        /**< Broadcast SSID or not, default 0, broadcast the SSID */
     uint8_t max_connection;     /**< Max number of stations allowed to connect in, default 4, max 10 */
-    uint16_t beacon_interval;   /**< Beacon interval, 100 ~ 60000 ms, default 100 ms */
+    uint16_t beacon_interval;   /**< Beacon interval which should be multiples of 100. Unit: TU(time unit, 1 TU = 1024 us). Range: 100 ~ 60000. Default value: 100 */
 } wifi_ap_config_t;
 
 /** @brief STA configuration settings for the ESP32 */
@@ -578,6 +578,19 @@ typedef enum {
     WPS_FAIL_REASON_MAX
 } 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 */
 typedef struct {
     uint8_t mac[6];           /**< MAC address of the station connected to ESP32 soft-AP */
@@ -596,6 +609,12 @@ typedef struct {
     uint8_t mac[6];           /**< MAC address of the station which send probe request */
 } wifi_event_ap_probe_req_rx_t;
 
+#define WIFI_STATIS_BUFFER    (1<<0)
+#define WIFI_STATIS_RXTX      (1<<1)
+#define WIFI_STATIS_HW        (1<<2)
+#define WIFI_STATIS_DIAG      (1<<3)
+#define WIFI_STATIS_ALL       (-1)
+
 #ifdef __cplusplus
 }
 #endif

+ 1 - 1
components/esp_wifi/lib

@@ -1 +1 @@
-Subproject commit 3836c5efbdb0d8eabb5f04e9baf173ea608f58ad
+Subproject commit 0d17296d8734dd901e5935d9729fe416fc875742

+ 4 - 0
components/esp_wifi/src/wifi_default.c

@@ -58,6 +58,10 @@ static void wifi_start(void *esp_netif, esp_event_base_t base, int32_t event_id,
         }
     }
 
+    if ((ret = esp_wifi_internal_reg_netstack_buf_cb(esp_netif_netstack_buf_ref, esp_netif_netstack_buf_free)) != ESP_OK) {
+        ESP_LOGE(TAG, "netstack cb reg failed with %d", ret);
+        return;
+    }
     esp_netif_set_mac(esp_netif, mac);
     esp_netif_action_start(esp_netif, base, event_id, data);
 }

+ 35 - 1
components/esp_wifi/src/wifi_init.c

@@ -47,6 +47,9 @@ uint64_t g_wifi_feature_caps =
 #if CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE
     CONFIG_FEATURE_WPA3_SAE_BIT |
 #endif
+#if (CONFIG_ESP32_SPIRAM_SUPPORT | CONFIG_ESP32S2_SPIRAM_SUPPORT)
+    CONFIG_FEATURE_CACHE_TX_BUF_BIT |
+#endif
 0;
 
 static const char* TAG = "wifi_init";
@@ -59,6 +62,8 @@ static void __attribute__((constructor)) s_set_default_wifi_log_level(void)
     */
     esp_log_level_set("wifi", CONFIG_LOG_DEFAULT_LEVEL);
     esp_log_level_set("mesh", CONFIG_LOG_DEFAULT_LEVEL);
+    esp_log_level_set("smartconfig", CONFIG_LOG_DEFAULT_LEVEL);
+    esp_log_level_set("ESPNOW", CONFIG_LOG_DEFAULT_LEVEL);
 }
 
 static void esp_wifi_set_debug_log(void)
@@ -131,6 +136,35 @@ esp_err_t esp_wifi_deinit(void)
     return err;
 }
 
+static void esp_wifi_config_info(void)
+{
+#ifdef CONFIG_ESP32_WIFI_RX_BA_WIN
+    ESP_LOGI(TAG, "rx ba win: %d", CONFIG_ESP32_WIFI_RX_BA_WIN);
+#endif
+    ESP_LOGI(TAG, "tcpip mbox: %d", CONFIG_LWIP_TCPIP_RECVMBOX_SIZE);
+    ESP_LOGI(TAG, "udp mbox: %d", CONFIG_LWIP_UDP_RECVMBOX_SIZE);
+    ESP_LOGI(TAG, "tcp mbox: %d", CONFIG_LWIP_TCP_RECVMBOX_SIZE);
+    ESP_LOGI(TAG, "tcp tx win: %d", CONFIG_LWIP_TCP_SND_BUF_DEFAULT);
+    ESP_LOGI(TAG, "tcp rx win: %d", CONFIG_LWIP_TCP_WND_DEFAULT);
+    ESP_LOGI(TAG, "tcp mss: %d", CONFIG_LWIP_TCP_MSS);
+
+#ifdef CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP
+    ESP_LOGI(TAG, "WiFi/LWIP prefer SPIRAM");
+#endif
+
+#ifdef CONFIG_ESP32_WIFI_IRAM_OPT
+    ESP_LOGI(TAG, "WiFi IRAM OP enabled");
+#endif
+
+#ifdef CONFIG_ESP32_WIFI_RX_IRAM_OPT
+    ESP_LOGI(TAG, "WiFi RX IRAM OP enabled");
+#endif
+
+#ifdef CONFIG_LWIP_IRAM_OPTIMIZATION
+    ESP_LOGI(TAG, "LWIP IRAM OP enabled");
+#endif
+}
+
 esp_err_t esp_wifi_init(const wifi_init_config_t *config)
 {
 #ifdef CONFIG_PM_ENABLE
@@ -166,7 +200,7 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config)
             return result;
         } 
     }
-
+    esp_wifi_config_info();
     return result;
 }
 

+ 11 - 0
components/esp_wifi/src/wifi_netif.c

@@ -63,6 +63,16 @@ static esp_err_t wifi_transmit(void *h, void *buffer, size_t len)
     return esp_wifi_internal_tx(driver->wifi_if, buffer, len);
 }
 
+static esp_err_t wifi_transmit_wrap(void *h, void *buffer, size_t len, void *netstack_buf)
+{
+    wifi_netif_driver_t driver = h;
+#if (CONFIG_ESP32_SPIRAM_SUPPORT | CONFIG_ESP32S2_SPIRAM_SUPPORT)
+    return esp_wifi_internal_tx_by_ref(driver->wifi_if, buffer, len, netstack_buf);
+#else
+    return esp_wifi_internal_tx(driver->wifi_if, buffer, len);
+#endif
+}
+
 static esp_err_t wifi_driver_start(esp_netif_t * esp_netif, void * args)
 {
     wifi_netif_driver_t driver = args;
@@ -70,6 +80,7 @@ static esp_err_t wifi_driver_start(esp_netif_t * esp_netif, void * args)
     esp_netif_driver_ifconfig_t driver_ifconfig = {
             .handle =  driver,
             .transmit = wifi_transmit,
+            .transmit_wrap= wifi_transmit_wrap,
             .driver_free_rx_buffer = wifi_free
     };
 

+ 11 - 2
components/lwip/Kconfig

@@ -346,6 +346,13 @@ menu "LWIP"
                 change the memory usage of LWIP, except for preventing
                 new listening TCP connections after the limit is reached.
 
+        config LWIP_TCP_HIGH_SPEED_RETRANSMISSION
+            bool "TCP high speed retransmissions"
+            default y
+            help
+                Speed up the TCP retransmission interval. If disabled,
+                it is recommended to change the number of SYN retransmissions to 6,
+                and TCP initial rto time to 3000.
 
         config LWIP_TCP_MAXRTX
             int "Maximum number of retransmissions of data segments"
@@ -356,7 +363,8 @@ menu "LWIP"
 
         config LWIP_TCP_SYNMAXRTX
             int "Maximum number of retransmissions of SYN segments"
-            default 6
+            default 6 if !LWIP_TCP_HIGH_SPEED_RETRANSMISSION
+            default 12 if LWIP_TCP_HIGH_SPEED_RETRANSMISSION
             range 3 12
             help
                 Set maximum number of retransmissions of SYN segments.
@@ -505,7 +513,8 @@ menu "LWIP"
 
         config LWIP_TCP_RTO_TIME
             int "Default TCP rto time"
-            default 3000
+            default 3000 if !LWIP_TCP_HIGH_SPEED_RETRANSMISSION
+            default 1500 if LWIP_TCP_HIGH_SPEED_RETRANSMISSION
             help
                 Set default TCP rto time for a reasonable initial rto.
                 In bad network environment, recommend set value of rto time to 1500.

+ 12 - 4
components/lwip/port/esp32/netif/wlanif.c

@@ -129,10 +129,10 @@ low_level_output(struct netif *netif, struct pbuf *p)
   }
 
   struct pbuf *q = p;
-  err_t ret;
+  esp_err_t ret;
 
   if(q->next == NULL) {
-    ret = esp_netif_transmit(esp_netif, q->payload, q->len);
+    ret = esp_netif_transmit_wrap(esp_netif, q->payload, q->len, q);
 
   } else {
     LWIP_DEBUGF(PBUF_DEBUG, ("low_level_output: pbuf is a list, application may has bug"));
@@ -143,12 +143,20 @@ low_level_output(struct netif *netif, struct pbuf *p)
     } else {
       return ERR_MEM;
     }
-    ret = esp_netif_transmit(esp_netif, q->payload, q->len);
+    ret = esp_netif_transmit_wrap(esp_netif, q->payload, q->len, q);
 
     pbuf_free(q);
   }
 
-  return ret;
+  if (ret == ESP_OK) {
+    return ERR_OK;
+  } else if (ret == ESP_ERR_NO_MEM) {
+    return ERR_MEM;
+  } else if (ret == ESP_ERR_INVALID_ARG) {
+    return ERR_ARG;
+  } else {
+    return ERR_IF;
+  }
 }
 
 /**

+ 4 - 1
components/wpa_supplicant/CMakeLists.txt

@@ -121,8 +121,11 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE
     ESP32_WORKAROUND
     CONFIG_ECC
     CONFIG_IEEE80211W
-    CONFIG_WPA3_SAE
     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)

+ 11 - 0
components/wpa_supplicant/Kconfig

@@ -31,4 +31,15 @@ menu "Supplicant"
             button bit without setting virtual/physical display/button bit which
             will cause M2 validation fail, bypassing WPS-Config method validation.
 
+    config WPA_DEBUG_PRINT
+        bool "Print debug messages from WPA Supplicant"
+        default n
+        help
+            Select this option to print logging information from WPA supplicant,
+            this includes handshake information and key hex dumps depending
+            on the project logging level.
+
+            Enabling this could increase the build size ~60kb
+            depending on the project logging level.
+
 endmenu

+ 5 - 1
components/wpa_supplicant/component.mk

@@ -26,4 +26,8 @@ else
     COMPONENT_OBJEXCLUDE := src/crypto/tls_mbedtls.o
 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

+ 20 - 23
components/wpa_supplicant/include/utils/wpa_debug.h

@@ -47,6 +47,7 @@ void wpa_debug_close_file(void);
  */
 void wpa_debug_print_timestamp(void);
 
+#ifdef DEBUG_PRINT
 /**
  * wpa_printf - conditional printf
  * @level: priority level (MSG_*) of the message
@@ -58,21 +59,6 @@ void wpa_debug_print_timestamp(void);
  *
  * Note: New line '\n' is added to the end of the text when printing to stdout.
  */
-#define  DEBUG_PRINT
-#define   MSG_PRINT
-
-/**
- * wpa_hexdump - conditional hex dump
- * @level: priority level (MSG_*) of the message
- * @title: title of for the message
- * @buf: data buffer to be dumped
- * @len: length of the buf
- *
- * This function is used to print conditional debugging and error messages. The
- * output may be directed to stdout, stderr, and/or syslog based on
- * configuration. The contents of buf is printed out has hex dump.
- */
-#ifdef DEBUG_PRINT
 #define wpa_printf(level,fmt, args...) ESP_LOG_LEVEL_LOCAL(level, TAG, fmt, ##args)
 
 void wpa_dump_mem(char* desc, uint8_t *addr, uint16_t len);
@@ -85,7 +71,17 @@ static inline void wpa_hexdump_ascii_key(int level, const char *title, const u8
 {
 }
 
-
+/**
+ * wpa_hexdump - conditional hex dump
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the buf
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration. The contents of buf is printed out has hex dump.
+ */
 void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len);
 
 static inline void wpa_hexdump_buf(int level, const char *title,
@@ -149,13 +145,14 @@ void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
 void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
 			   size_t len);
 #else
-#define wpa_printf(level,fmt, args...)
-#define wpa_hexdump(...)
-#define wpa_hexdump_buf(...)
-#define wpa_hexdump_key(...)
-#define wpa_hexdump_buf_key(...)
-#define wpa_hexdump_ascii(...)
-#define wpa_hexdump_ascii_key(...)
+#define wpa_printf(level,fmt, args...) do {} while(0)
+#define wpa_hexdump(...) do {} while(0)
+#define wpa_dump_mem(...) do {} while(0)
+#define wpa_hexdump_buf(...) do {} while(0)
+#define wpa_hexdump_key(...) do {} while(0)
+#define wpa_hexdump_buf_key(...) do {} while(0)
+#define wpa_hexdump_ascii(...) do {} while(0)
+#define wpa_hexdump_ascii_key(...) do {} while(0)
 #endif
 
 #define wpa_auth_logger

+ 4 - 0
components/wpa_supplicant/port/include/supplicant_opt.h

@@ -28,4 +28,8 @@
 #define DEBUG_PRINT
 #endif
 
+#if CONFIG_WPA_DEBUG_PRINT
+#define DEBUG_PRINT
+#endif
+
 #endif /* _SUPPLICANT_OPT_H */

+ 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)
 		return WPA_KEY_MGMT_FT_PSK;
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
 #ifdef CONFIG_WPA3_SAE
         if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
                 return WPA_KEY_MGMT_SAE;
 #endif /* CONFIG_WPA3_SAE */
-#ifdef CONFIG_IEEE80211W
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
 		return WPA_KEY_MGMT_IEEE8021X_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_WPA3_SAE
        case WPA_KEY_INFO_TYPE_AKM_DEFINED:
-#endif
+#endif /* CONFIG_WPA3_SAE */
 	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
 		return omac1_aes_128(key, buf, len, mic);
-#endif
+#endif /* CONFIG_IEEE80211W */
 	default:
 		return -1;
 	}

+ 8 - 2
components/wpa_supplicant/src/crypto/aes-ccm.c

@@ -177,9 +177,10 @@ int aes_ccm_ae(const u8 *key, size_t key_len, const u8 *nonce,
 
 
 /* AES-CCM with fixed L=2 and aad_len <= 30 assumption */
-int aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce,
+int aes_ccm_ad(const u8 *key, size_t key_len, u8 *nonce,
 	       size_t M, const u8 *crypt, size_t crypt_len,
-	       const u8 *aad, size_t aad_len, const u8 *auth, u8 *plain)
+	       const u8 *aad, size_t aad_len, const u8 *auth,
+	       u8 *plain, bool skip_auth)
 {
 	const size_t L = 2;
 	void *aes;
@@ -200,6 +201,11 @@ int aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce,
 	/* plaintext = msg XOR (S_1 | S_2 | ... | S_n) */
 	aes_ccm_encr(aes, L, crypt, crypt_len, plain, a);
 
+	if (skip_auth) {
+		aes_encrypt_deinit(aes);
+		return 0;
+	}
+
 	aes_ccm_auth_start(aes, M, L, nonce, aad, aad_len, crypt_len, x);
 	aes_ccm_auth(aes, plain, crypt_len, x);
 

+ 2 - 2
components/wpa_supplicant/src/crypto/aes.h

@@ -29,8 +29,8 @@ int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac);
 int aes_ccm_ae(const u8 *key, size_t key_len, const u8 *nonce,
                size_t M, const u8 *plain, size_t plain_len,
                const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth);
-int aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce,
+int aes_ccm_ad(const u8 *key, size_t key_len, u8 *nonce,
                size_t M, const u8 *crypt, size_t crypt_len,
                const u8 *aad, size_t aad_len, const u8 *auth,
-               u8 *plain);
+               u8 *plain, bool skip_auth);
 #endif /* AES_H */

+ 14 - 13
components/wpa_supplicant/src/crypto/ccmp.c

@@ -16,7 +16,7 @@
 #include "aes_wrap.h"
 
 static void ccmp_aad_nonce(const struct ieee80211_hdr *hdr, const u8 *data,
-			   u8 *aad, size_t *aad_len, u8 *nonce)
+                           u8 *aad, size_t *aad_len, u8 *nonce, bool espnow_pkt)
 {
 	u16 fc, stype, seq;
 	int qos = 0, addr4 = 0;
@@ -41,7 +41,7 @@ static void ccmp_aad_nonce(const struct ieee80211_hdr *hdr, const u8 *data,
 				qc += ETH_ALEN;
 			nonce[0] = qc[0] & 0x0f;
 		}
-	} else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
+	} else if (!espnow_pkt && WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
 		nonce[0] |= 0x10; /* Management */
 
 	fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
@@ -136,7 +136,7 @@ static void ccmp_aad_nonce_pv1(const u8 *hdr, const u8 *a1, const u8 *a2,
 
 
 u8 * ccmp_decrypt(const u8 *tk, const u8 *hdr, const u8 *data,
-		  size_t data_len, size_t *decrypted_len)
+		  size_t data_len, size_t *decrypted_len, bool espnow_pkt)
 {
 	u8 aad[30], nonce[13];
 	size_t aad_len;
@@ -153,22 +153,22 @@ u8 * ccmp_decrypt(const u8 *tk, const u8 *hdr, const u8 *data,
 	mlen = data_len - 8 - 8;
 
 	os_memset(aad, 0, sizeof(aad));
-	ccmp_aad_nonce((const struct ieee80211_hdr *)hdr, data, aad, &aad_len, nonce);
-	//wpa_hexdump(MSG_DEBUG, "CCMP AAD", aad, aad_len);
-	//wpa_hexdump(MSG_DEBUG, "CCMP nonce", nonce, 13);
+	ccmp_aad_nonce((const struct ieee80211_hdr *)hdr, data, aad, &aad_len,
+                   nonce, espnow_pkt);
+	wpa_hexdump(MSG_DEBUG, "CCMP AAD", aad, aad_len);
+	wpa_hexdump(MSG_DEBUG, "CCMP nonce", nonce, 13);
 
 	if (aes_ccm_ad(tk, 16, nonce, 8, data + 8, mlen, aad, aad_len,
-		       data + 8 + mlen, plain) < 0) {
+                   data + 8 + mlen, plain, espnow_pkt ? true : false) < 0) {
 		os_free(plain);
 		return NULL;
 	}
-	//wpa_hexdump(MSG_DEBUG, "CCMP decrypted", plain, mlen);
+	wpa_hexdump(MSG_DEBUG, "CCMP decrypted", plain, mlen);
 
 	*decrypted_len = mlen;
 	return plain;
 }
 
-
 void ccmp_get_pn(u8 *pn, const u8 *data)
 {
 	pn[0] = data[7]; /* PN5 */
@@ -210,7 +210,7 @@ u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
 	*pos++ = pn[0]; /* PN5 */
 
 	os_memset(aad, 0, sizeof(aad));
-	ccmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce);
+	ccmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce, false);
 	wpa_hexdump(MSG_DEBUG, "CCMP AAD", aad, aad_len);
 	wpa_hexdump(MSG_DEBUG, "CCMP nonce", nonce, 13);
 
@@ -288,12 +288,13 @@ u8 * ccmp_256_decrypt(const u8 *tk, const u8 *hdr, const u8 *data,
 	mlen = data_len - 8 - 16;
 
 	os_memset(aad, 0, sizeof(aad));
-	ccmp_aad_nonce((const struct ieee80211_hdr *)hdr, data, aad, &aad_len, nonce);
+	ccmp_aad_nonce((const struct ieee80211_hdr *)hdr, data, aad,
+                   &aad_len, nonce, false);
 	wpa_hexdump(MSG_DEBUG, "CCMP-256 AAD", aad, aad_len);
 	wpa_hexdump(MSG_DEBUG, "CCMP-256 nonce", nonce, 13);
 
 	if (aes_ccm_ad(tk, 32, nonce, 16, data + 8, mlen, aad, aad_len,
-		       data + 8 + mlen, plain) < 0) {
+		       data + 8 + mlen, plain, false) < 0) {
 		os_free(plain);
 		return NULL;
 	}
@@ -334,7 +335,7 @@ u8 * ccmp_256_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
 	*pos++ = pn[0]; /* PN5 */
 
 	os_memset(aad, 0, sizeof(aad));
-	ccmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce);
+	ccmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce, false);
 	wpa_hexdump(MSG_DEBUG, "CCMP-256 AAD", aad, aad_len);
 	wpa_hexdump(MSG_DEBUG, "CCMP-256 nonce", nonce, 13);
 

+ 1 - 1
components/wpa_supplicant/src/crypto/ccmp.h

@@ -11,7 +11,7 @@
 #define CCMP_H
 
 u8 * ccmp_decrypt(const u8 *tk, const u8 *hdr, const u8 *data,
-		  size_t data_len, size_t *decrypted_len);
+		  size_t data_len, size_t *decrypted_len, bool espnow_pkt);
 u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
 		  u8 *pn, int keyid, size_t *encrypted_len);
 u8 * ccmp_encrypt_pv1(const u8 *tk, const u8 *a1, const u8 *a2, const u8 *a3,

+ 2 - 0
components/wpa_supplicant/src/eap_peer/eap_tls_common.c

@@ -1005,7 +1005,9 @@ get_defaults:
 int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,
 			    struct eap_hdr *hdr, struct wpabuf **resp)
 {
+#ifdef DEBUG_PRINT
 	u8 *pos = (u8 *) (hdr + 1);
+#endif
 	size_t i;
 
 	/* TODO: add support for expanded Nak */

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

@@ -233,5 +233,7 @@ esp_err_t esp_wifi_set_wps_start_flag_internal(bool start);
 uint16_t esp_wifi_sta_pmf_enabled(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);
+esp_err_t esp_wifi_internal_issue_disconnect(uint8_t reason_code);
+bool esp_wifi_skip_supp_pmkcaching(void);
 
 #endif /* _ESP_WIFI_DRIVER_H_ */

+ 2 - 4
components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c

@@ -187,7 +187,6 @@ void wpa2_task(void *pvParameters )
     ETSEvent *e;
     struct eap_sm *sm = gEapSm;
     bool task_del = false;
-    uint32_t sig = 0;
 
     if (!sm) {
         return;
@@ -195,7 +194,6 @@ void wpa2_task(void *pvParameters )
 
     for (;;) {
         if ( pdPASS == xQueueReceive(s_wpa2_queue, &e, portMAX_DELAY) ) {
-            sig = e->sig;
             if (e->sig < SIG_WPA2_MAX) {
                 DATA_MUTEX_TAKE();
                 if(sm->wpa2_sig_cnt[e->sig]) {
@@ -232,7 +230,7 @@ void wpa2_task(void *pvParameters )
             break;
         } else {
             if (s_wifi_wpa2_sync_sem) {
-                wpa_printf(MSG_DEBUG, "WPA2: wifi->wpa2 api completed sig(%d)", sig);
+                wpa_printf(MSG_DEBUG, "WPA2: wifi->wpa2 api completed sig(%d)", e->sig);
                 xSemaphoreGive(s_wifi_wpa2_sync_sem);
             } else {
                 wpa_printf(MSG_ERROR, "WPA2: null wifi->wpa2 sync sem");
@@ -245,7 +243,7 @@ void wpa2_task(void *pvParameters )
     wpa_printf(MSG_DEBUG, "WPA2: task deleted");
     s_wpa2_queue = NULL;
     if (s_wifi_wpa2_sync_sem) {
-        wpa_printf(MSG_DEBUG, "WPA2: wifi->wpa2 api completed sig(%d)", sig);
+        wpa_printf(MSG_DEBUG, "WPA2: wifi->wpa2 api completed sig(%d)", e->sig);
         xSemaphoreGive(s_wifi_wpa2_sync_sem);
     } else {
         wpa_printf(MSG_ERROR, "WPA2: null wifi->wpa2 sync sem");

+ 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;
 }
 
+static inline void esp_wpa3_free_sae_data(void)
+{
+}
+
 #endif /* CONFIG_WPA3_SAE */
 #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();
-            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) {
                 memcpy(gWpsSm->bssid, scan->bssid, ETH_ALEN);
                 memcpy(sm->config.bssid, scan->bssid, ETH_ALEN);
                 sm->config.bssid_set = 1;
             } 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;
 
-            memcpy(sm->config.ssid, sm->ssid, sm->ssid_len);
             sm->channel = scan->chan;
 
             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->wps->state = SEND_M1;
     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));
+    sm->ap_cred_cnt = 0;
 
     esp_wifi_disarm_sta_connection_timer_internal();
     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_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_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)
 {
-    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)
@@ -1707,44 +1726,45 @@ wps_sm_get(void)
 }
 
 int
-wps_ssid_save(u8 *ssid, u8 ssid_len)
+wps_ssid_save(u8 *ssid, u8 ssid_len, u8 idx)
 {
     u8 *tmpssid;
 
-    if (!ssid || !gWpsSm) {
+    if (!ssid || !gWpsSm || idx > 2) {
         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);
     if (tmpssid) {
         memcpy(tmpssid, ssid, ssid_len);
-        wpa_printf(MSG_DEBUG, "WPS: ssid[%s]", tmpssid);
+        wpa_printf(MSG_DEBUG, "WPS: key[%s]", tmpssid);
         os_free(tmpssid);
     }
     return ESP_OK;
 }
 
 int
-wps_key_save(char *key, u8 key_len)
+wps_key_save(char *key, u8 key_len, u8 idx)
 {
     u8 *tmpkey;
 
-    if (!key || !gWpsSm) {
+    if (!key || !gWpsSm || idx > 2) {
         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);
     if (tmpkey) {
         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);
     }
     return ESP_OK;

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

@@ -48,6 +48,7 @@
 #define WPA_TX_MSG_BUFF_MAXLEN 200
 
 #define ASSOC_IE_LEN 24 + 2 + PMKID_LEN + RSN_SELECTOR_LEN
+#define MAX_EAPOL_RETRIES 3
 u8 assoc_ie_buf[ASSOC_IE_LEN+2]; 
 
 void set_assoc_ie(u8 * assoc_buf);
@@ -1938,6 +1939,14 @@ int   wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len)
             wpa_supplicant_process_3_of_4(sm, key, ver);
         } else {
             /* 1/4 4-Way Handshake */
+            sm->eapol1_count++;
+            if (sm->eapol1_count > MAX_EAPOL_RETRIES) {
+#ifdef DEBUG_PRINT
+                wpa_printf(MSG_INFO, "EAPOL1 received for %d times, sending deauth", sm->eapol1_count);
+#endif
+                esp_wifi_internal_issue_disconnect(WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT);
+                goto out;
+            }
             wpa_supplicant_process_1_of_4(sm, src_addr, key,
                               ver);
         }
@@ -2119,10 +2128,22 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher,
     if (sm->key_mgmt == WPA_KEY_MGMT_SAE ||
         (esp_wifi_sta_prof_is_wpa2_internal() &&
          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;
 #ifdef CONFIG_IEEE80211W
     if (esp_wifi_sta_pmf_enabled()) {
         wifi_config_t wifi_cfg;

+ 1 - 0
components/wpa_supplicant/src/rsn_supp/wpa_i.h

@@ -90,6 +90,7 @@ struct wpa_sm {
     u16 txcb_flags;
     bool   ap_notify_completed_rsne;
     wifi_pmf_config_t pmf_cfg;
+    u8 eapol1_count;
 };
 
 /**

+ 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);
     } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
-#endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_WPA3_SAE
     } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
 #endif /* CONFIG_WPA3_SAE */
+#endif /* CONFIG_IEEE80211W */
     } else {
         wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
                key_mgmt);

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

@@ -1031,13 +1031,14 @@ struct wps_sm {
     u8 identity_len;
     u8 ownaddr[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;
     u8 uuid[16];
     u8 eapol_version;
-    char key[64];
-    u8 key_len;
     ETSTimer wps_timeout_timer;
     ETSTimer wps_msg_timeout_timer;
     ETSTimer wps_scan_timer;
@@ -1061,8 +1062,8 @@ struct wps_sm {
 #define    WIFI_CAPINFO_PRIVACY        0x0010
 
 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_unregister_cb(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,
-			      size_t cred_len, int wps2)
+			      size_t cred_len, int cred_idx, int wps2)
 {
 	struct wps_parse_attr *attr;
 	struct wpabuf msg;
@@ -712,9 +712,8 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
 		goto _out;
 	}
 #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) {
 		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++) {
 		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)
 			ok++;
 		else if (res == -2) {

+ 10 - 2
components/wpa_supplicant/src/wps/wps_registrar.c

@@ -2423,14 +2423,18 @@ static int wps_process_wps_state(struct wps_data *wps, const u8 *state)
 
 static int wps_process_assoc_state(struct wps_data *wps, const u8 *assoc)
 {
-	u16 a;
+#ifdef DEBUG_PRINT
+    u16 a;
+#endif
 
 	if (assoc == NULL) {
 		wpa_printf(MSG_DEBUG,  "WPS: No Association State received");
 		return -1;
 	}
 
+#ifdef DEBUG_PRINT
 	a = WPA_GET_BE16(assoc);
+#endif
 	wpa_printf(MSG_DEBUG,  "WPS: Enrollee Association State %d", a);
 
 	return 0;
@@ -2439,14 +2443,18 @@ static int wps_process_assoc_state(struct wps_data *wps, const u8 *assoc)
 
 static int wps_process_config_error(struct wps_data *wps, const u8 *err)
 {
-	u16 e;
+#ifdef DEBUG_PRINT
+    u16 e;
+#endif
 
 	if (err == NULL) {
 		wpa_printf(MSG_DEBUG,  "WPS: No Configuration Error received");
 		return -1;
 	}
 
+#ifdef DEBUG_PRINT
 	e = WPA_GET_BE16(err);
+#endif
 	wpa_printf(MSG_DEBUG,  "WPS: Enrollee Configuration Error %d", e);
 
 	return 0;

+ 2 - 2
examples/wifi/README.md

@@ -30,13 +30,13 @@ See the [README.md](./espnow/README.md) file in the project [espnow](./espnow/).
 
 Show how to use fast scan while connecting to an AP.
 
-See the [README.md](./fast_scan/README.md) file in the project [espnow](./espnow/).
+See the [README.md](./fast_scan/README.md) file in the project [fast_scan](./fast_scan/).
 
 ## scan
 
 Show how to scan for all the available APs.
 
-See the [README.md](./scan/README.md) file in the project [espnow](./espnow/).
+See the [README.md](./scan/README.md) file in the project [scan](./scan/).
 
 # More
 

+ 3 - 3
examples/wifi/iperf/components/iperf/iperf.c

@@ -124,7 +124,7 @@ static esp_err_t IRAM_ATTR iperf_run_tcp_server(void)
     int listen_socket;
     struct timeval t;
     int sockfd;
-    int opt;
+    int opt = 1;
 
     listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     if (listen_socket < 0) {
@@ -195,7 +195,7 @@ static esp_err_t IRAM_ATTR iperf_run_udp_server(void)
     int want_recv = 0;
     uint8_t *buffer;
     int sockfd;
-    int opt;
+    int opt = 1;
     bool udp_recv_start = true ;
 
     sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
@@ -253,7 +253,7 @@ static esp_err_t iperf_run_udp_client(void)
     int want_send = 0;
     uint8_t *buffer;
     int sockfd;
-    int opt;
+    int opt = 1;
     int err;
     int id;
 

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

@@ -27,6 +27,7 @@
 #include "esp_wps.h"
 #include "esp_event.h"
 #include "nvs_flash.h"
+#include <string.h>
 
 
 /*set wps mode via project configuration */
@@ -38,6 +39,7 @@
 #define WPS_MODE WPS_TYPE_DISABLE
 #endif /*CONFIG_EXAMPLE_WPS_TYPE_PBC*/
 
+#define MAX_RETRY_ATTEMPTS     2
 
 #ifndef PIN2STR
 #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 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,
                                 int32_t event_id, void* event_data)
 {
+    static int ap_idx = 1;
+
     switch (event_id) {
         case WIFI_EVENT_STA_START:
             ESP_LOGI(TAG, "WIFI_EVENT_STA_START");
             break;
         case 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;
         case 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;
         case WIFI_EVENT_STA_WPS_ER_FAILED:
             ESP_LOGI(TAG, "WIFI_EVENT_STA_WPS_ER_FAILED");