diff --git a/components/esp_event/include/esp_event_legacy.h b/components/esp_event/include/esp_event_legacy.h index 00d402c435..ba74ec776c 100644 --- a/components/esp_event/include/esp_event_legacy.h +++ b/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 */ diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index a0cf2ce823..c1d73d0632 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -581,6 +581,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 */ diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index b783042634..fad0f87b2c 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit b783042634c6cfb70c962b796be1b44977a1ea7e +Subproject commit fad0f87b2c31d0ff2779bbf834ad0edc6e2a99a7 diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wps.c b/components/wpa_supplicant/src/esp_supplicant/esp_wps.c index 1cd859cdeb..acccaf32bd 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wps.c +++ b/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); @@ -983,15 +981,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); @@ -1494,7 +1494,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) @@ -1705,44 +1724,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; diff --git a/components/wpa_supplicant/src/wps/wps.h b/components/wpa_supplicant/src/wps/wps.h index 4aace58660..9f31a8e637 100644 --- a/components/wpa_supplicant/src/wps/wps.h +++ b/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); diff --git a/components/wpa_supplicant/src/wps/wps_enrollee.c b/components/wpa_supplicant/src/wps/wps_enrollee.c index 3a47303abf..daaadd6400 100644 --- a/components/wpa_supplicant/src/wps/wps_enrollee.c +++ b/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) { diff --git a/examples/wifi/wps/main/wps.c b/examples/wifi/wps/main/wps.c index a3f7237a7b..edf87ae54a 100644 --- a/examples/wifi/wps/main/wps.c +++ b/examples/wifi/wps/main/wps.c @@ -27,6 +27,7 @@ #include "esp_wps.h" #include "esp_event.h" #include "nvs_flash.h" +#include /*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");