Fix handling of multiple AP credentials in WPS

WPS can send multiple AP credentials, while existing implementation
will only use the first credentials which could be for the 5G band.
Fix this by passing these credentials to the App and attempting
to connect using each of those. Older Apps will remain compatible
without breaking WPS, but the issue will remain.
This commit is contained in:
Nachiket Kukade 2020-06-10 14:21:57 +05:30 committed by bot
parent 5da526a0cb
commit 81f037a299
7 changed files with 127 additions and 44 deletions

View File

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

View File

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

@ -1 +1 @@
Subproject commit b783042634c6cfb70c962b796be1b44977a1ea7e Subproject commit fad0f87b2c31d0ff2779bbf834ad0edc6e2a99a7

View File

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

View File

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

View File

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

View File

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