diff --git a/components/esp_event/include/esp_event_legacy.h b/components/esp_event/include/esp_event_legacy.h index 44e95546a1..4678330d14 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 aa57e921b8..971eabbfb3 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -569,6 +569,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/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index 0772a36eaa..30570e7c5c 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -123,7 +123,10 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_ECC CONFIG_SHA256 CONFIG_IEEE80211W - CONFIG_WPA3_SAE ) +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) diff --git a/components/wpa_supplicant/component.mk b/components/wpa_supplicant/component.mk index 29212dd64c..c616e49f93 100644 --- a/components/wpa_supplicant/component.mk +++ b/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 diff --git a/components/wpa_supplicant/src/common/wpa_common.c b/components/wpa_supplicant/src/common/wpa_common.c index ba909fee26..a7532c47b9 100644 --- a/components/wpa_supplicant/src/common/wpa_common.c +++ b/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; } diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa3_i.h b/components/wpa_supplicant/src/esp_supplicant/esp_wpa3_i.h index 93223040e8..738df29181 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa3_i.h +++ b/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 */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wps.c b/components/wpa_supplicant/src/esp_supplicant/esp_wps.c index cbcd351973..9f71aeb98d 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wps.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wps.c @@ -594,19 +594,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; @@ -944,9 +941,10 @@ int wps_stop_process(system_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); @@ -988,15 +986,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); @@ -1505,7 +1505,25 @@ void wifi_station_wps_success_internal(void) { system_event_t evt; evt.event_id = SYSTEM_EVENT_STA_WPS_ER_SUCCESS; - esp_wifi_send_event_internal(&evt); + 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.event_info.sta_er_success.ap_cred_cnt = sm->ap_cred_cnt; + for (i = 0; i < MAX_WPS_AP_CRED; i++) { + os_memcpy(evt.event_info.sta_er_success.ap_cred[i].ssid, + sm->ssid[i], sm->ssid_len[i]); + os_memcpy(evt.event_info.sta_er_success.ap_cred[i].passphrase, + sm->key[i], sm->key_len[i]); + } + esp_wifi_send_event_internal(&evt); + } else { + esp_wifi_send_event_internal(&evt); + } } void wifi_station_wps_success(void) @@ -1716,44 +1734,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/rsn_supp/wpa_ie.c b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c index d648a45429..497d50ec7b 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c +++ b/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); diff --git a/components/wpa_supplicant/src/wps/wps.h b/components/wpa_supplicant/src/wps/wps.h index ab2eb00bda..dd7245b7c0 100644 --- a/components/wpa_supplicant/src/wps/wps.h +++ b/components/wpa_supplicant/src/wps/wps.h @@ -1027,13 +1027,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; @@ -1057,8 +1058,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 7a30836577..77c7580202 100644 --- a/components/wpa_supplicant/src/wps/wps_enrollee.c +++ b/components/wpa_supplicant/src/wps/wps_enrollee.c @@ -651,7 +651,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; @@ -711,9 +711,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; @@ -748,7 +747,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 5ac103b7f1..ed99100fde 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");