diff --git a/components/esp32/include/esp_event_legacy.h b/components/esp32/include/esp_event_legacy.h index 0ee6046c7e..43a315d77d 100644 --- a/components/esp32/include/esp_event_legacy.h +++ b/components/esp32/include/esp_event_legacy.h @@ -106,6 +106,9 @@ typedef struct { tcpip_adapter_ip6_info_t ip6_info; } system_event_got_ip6_t; +/** Argument structure of SYSTEM_EVENT_STA_WPS_ER_SUCCESS event */ +typedef wifi_event_sta_wps_er_success_t system_event_sta_wps_er_success_t; + typedef struct { uint8_t mac[6]; /**< MAC address of the station connected to ESP32 soft-AP */ uint8_t aid; /**< the aid that ESP32 soft-AP gives to the station connected to */ @@ -133,6 +136,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 */ diff --git a/components/esp32/include/esp_wifi_types.h b/components/esp32/include/esp_wifi_types.h index 9b6b08e777..382e5a250b 100644 --- a/components/esp32/include/esp_wifi_types.h +++ b/components/esp32/include/esp_wifi_types.h @@ -502,6 +502,19 @@ typedef enum { WIFI_IOCTL_MAX, } wifi_ioctl_cmd_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; + /** * @brief Configuration for STA's HT2040 coexist management * diff --git a/components/wpa_supplicant/include/wps/wps.h b/components/wpa_supplicant/include/wps/wps.h index 31092cbb83..bea83d78ae 100644 --- a/components/wpa_supplicant/include/wps/wps.h +++ b/components/wpa_supplicant/include/wps/wps.h @@ -1024,13 +1024,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; @@ -1054,8 +1055,8 @@ struct wps_sm { #define IEEE80211_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); diff --git a/components/wpa_supplicant/src/wps/wps_enrollee.c b/components/wpa_supplicant/src/wps/wps_enrollee.c index 6a4f9bdfb9..65147b66f4 100644 --- a/components/wpa_supplicant/src/wps/wps_enrollee.c +++ b/components/wpa_supplicant/src/wps/wps_enrollee.c @@ -673,7 +673,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; @@ -734,8 +734,8 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred, } #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; @@ -770,7 +770,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) { diff --git a/examples/wifi/wps/main/wps.c b/examples/wifi/wps/main/wps.c index 50ab8de9bc..0873e2b6b5 100644 --- a/examples/wifi/wps/main/wps.c +++ b/examples/wifi/wps/main/wps.c @@ -21,6 +21,7 @@ #include "esp_wps.h" #include "esp_event_loop.h" #include "nvs_flash.h" +#include /*set wps mode via "make menuconfig"*/ @@ -32,6 +33,7 @@ #define WPS_TEST_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] @@ -41,9 +43,14 @@ static const char *TAG = "example_wps"; static esp_wps_config_t config = WPS_CONFIG_INIT_DEFAULT(WPS_TEST_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 esp_err_t event_handler(void *ctx, system_event_t *event) { + static int ap_idx = 1; + switch(event->event_id) { case SYSTEM_EVENT_STA_START: ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START"); @@ -54,16 +61,51 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip)); break; case SYSTEM_EVENT_STA_DISCONNECTED: - ESP_LOGI(TAG, "SYSTEM_EVENT_STA_DISCONNECTED"); - ESP_ERROR_CHECK(esp_wifi_connect()); + ESP_LOGI(TAG, "SYSTEM_EVENT_STA_DISCONNECTED"); + 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 SYSTEM_EVENT_STA_WPS_ER_SUCCESS: /*point: the function esp_wifi_wps_start() only get ssid & password * so call the function esp_wifi_connect() here * */ ESP_LOGI(TAG, "SYSTEM_EVENT_STA_WPS_ER_SUCCESS"); - ESP_ERROR_CHECK(esp_wifi_wps_disable()); - ESP_ERROR_CHECK(esp_wifi_connect()); + { + wifi_event_sta_wps_er_success_t *evt = &event->event_info.sta_er_success; + int i; + if (evt && evt->ap_cred_cnt > 1) { + 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 SYSTEM_EVENT_STA_WPS_ER_FAILED: ESP_LOGI(TAG, "SYSTEM_EVENT_STA_WPS_ER_FAILED");