Skip to content

Commit 92d4bb6

Browse files
committed
Merge branch 'bugfix/wps_multiple_ap_creds' into 'master'
Fix handling of multiple AP credentials in WPS Closes FCS-356 See merge request espressif/esp-idf!9137
2 parents 9d21b17 + 81f037a commit 92d4bb6

File tree

7 files changed

+127
-44
lines changed

7 files changed

+127
-44
lines changed

components/esp_event/include/esp_event_legacy.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ typedef wifi_event_sta_authmode_change_t system_event_sta_authmode_change_t;
8080
/** Argument structure of SYSTEM_EVENT_STA_WPS_ER_PIN event */
8181
typedef wifi_event_sta_wps_er_pin_t system_event_sta_wps_er_pin_t;
8282

83+
/** Argument structure of SYSTEM_EVENT_STA_WPS_ER_PIN event */
84+
typedef wifi_event_sta_wps_er_success_t system_event_sta_wps_er_success_t;
85+
8386
/** Argument structure of event */
8487
typedef wifi_event_ap_staconnected_t system_event_ap_staconnected_t;
8588

@@ -107,6 +110,7 @@ typedef union {
107110
system_event_sta_got_ip_t got_ip; /*!< ESP32 station got IP, first time got IP or when IP is changed */
108111
system_event_sta_wps_er_pin_t sta_er_pin; /*!< ESP32 station WPS enrollee mode PIN code received */
109112
system_event_sta_wps_fail_reason_t sta_er_fail_reason; /*!< ESP32 station WPS enrollee mode failed reason code received */
113+
system_event_sta_wps_er_success_t sta_er_success; /*!< ESP32 station WPS enrollee success */
110114
system_event_ap_staconnected_t sta_connected; /*!< a station connected to ESP32 soft-AP */
111115
system_event_ap_stadisconnected_t sta_disconnected; /*!< a station disconnected to ESP32 soft-AP */
112116
system_event_ap_probe_req_rx_t ap_probereqrecved; /*!< ESP32 soft-AP receive probe request packet */

components/esp_wifi/include/esp_wifi_types.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,19 @@ typedef enum {
581581
WPS_FAIL_REASON_MAX
582582
} wifi_event_sta_wps_fail_reason_t;
583583

584+
#define MAX_SSID_LEN 32
585+
#define MAX_PASSPHRASE_LEN 64
586+
#define MAX_WPS_AP_CRED 3
587+
588+
/** Argument structure for WIFI_EVENT_STA_WPS_ER_SUCCESS event */
589+
typedef struct {
590+
uint8_t ap_cred_cnt; /**< Number of AP credentials received */
591+
struct {
592+
uint8_t ssid[MAX_SSID_LEN]; /**< SSID of AP */
593+
uint8_t passphrase[MAX_PASSPHRASE_LEN]; /**< Passphrase for the AP */
594+
} ap_cred[MAX_WPS_AP_CRED]; /**< All AP credentials received from WPS handshake */
595+
} wifi_event_sta_wps_er_success_t;
596+
584597
/** Argument structure for WIFI_EVENT_AP_STACONNECTED event */
585598
typedef struct {
586599
uint8_t mac[6]; /**< MAC address of the station connected to ESP32 soft-AP */

components/wpa_supplicant/src/esp_supplicant/esp_wps.c

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -593,19 +593,16 @@ wps_parse_scan_result(struct wps_scan_ie *scan)
593593
}
594594

595595
esp_wifi_enable_sta_privacy_internal();
596-
os_bzero(sm->ssid, sizeof(sm->ssid));
597-
strncpy((char *)sm->ssid, (char *)&scan->ssid[2], (int)scan->ssid[1]);
598-
sm->ssid_len = scan->ssid[1];
596+
strncpy((char *)sm->config.ssid, (char *)&scan->ssid[2], (int)scan->ssid[1]);
599597
if (scan->bssid) {
600598
memcpy(gWpsSm->bssid, scan->bssid, ETH_ALEN);
601599
memcpy(sm->config.bssid, scan->bssid, ETH_ALEN);
602600
sm->config.bssid_set = 1;
603601
} else {
604602
}
605-
wpa_printf(MSG_DEBUG, "wps discover [%s]", sm->ssid);
603+
wpa_printf(MSG_DEBUG, "wps discover [%s]", (char *)sm->config.ssid);
606604
sm->scan_cnt = 0;
607605

608-
memcpy(sm->config.ssid, sm->ssid, sm->ssid_len);
609606
sm->channel = scan->chan;
610607

611608
return true;
@@ -943,9 +940,10 @@ int wps_stop_process(wifi_event_sta_wps_fail_reason_t reason_code)
943940
sm->discover_ssid_cnt = 0;
944941
sm->wps->state = SEND_M1;
945942
os_bzero(sm->bssid, ETH_ALEN);
946-
os_bzero(sm->ssid, 32);
947-
sm->ssid_len = 0;
943+
os_bzero(sm->ssid, sizeof(sm->ssid));
944+
os_bzero(sm->ssid_len, sizeof(sm->ssid_len));
948945
os_bzero((u8 *)&sm->config, sizeof(wifi_sta_config_t));
946+
sm->ap_cred_cnt = 0;
949947

950948
esp_wifi_disarm_sta_connection_timer_internal();
951949
ets_timer_disarm(&sm->wps_msg_timeout_timer);
@@ -983,15 +981,17 @@ int wps_finish(void)
983981
ets_timer_disarm(&sm->wps_timeout_timer);
984982
ets_timer_disarm(&sm->wps_msg_timeout_timer);
985983

986-
memset(config, 0x00, sizeof(wifi_sta_config_t));
987-
memcpy(config->sta.ssid, sm->ssid, sm->ssid_len);
988-
memcpy(config->sta.password, sm->key, sm->key_len);
989-
memcpy(config->sta.bssid, sm->bssid, ETH_ALEN);
990-
config->sta.bssid_set = 0;
991-
esp_wifi_set_config(0, config);
992-
os_free(config);
993-
config = NULL;
984+
if (sm->ap_cred_cnt == 1) {
985+
memset(config, 0x00, sizeof(wifi_sta_config_t));
986+
memcpy(config->sta.ssid, sm->ssid[0], sm->ssid_len[0]);
987+
memcpy(config->sta.password, sm->key[0], sm->key_len[0]);
988+
memcpy(config->sta.bssid, sm->bssid, ETH_ALEN);
989+
config->sta.bssid_set = 0;
990+
esp_wifi_set_config(0, config);
994991

992+
os_free(config);
993+
config = NULL;
994+
}
995995
ets_timer_disarm(&sm->wps_success_cb_timer);
996996
ets_timer_arm(&sm->wps_success_cb_timer, 1000, 0);
997997

@@ -1494,7 +1494,26 @@ void wifi_station_wps_msg_timeout(void)
14941494

14951495
void wifi_station_wps_success_internal(void)
14961496
{
1497-
esp_event_send_internal(WIFI_EVENT, WIFI_EVENT_STA_WPS_ER_SUCCESS, 0, 0, portMAX_DELAY);
1497+
wifi_event_sta_wps_er_success_t evt = {0};
1498+
struct wps_sm *sm = gWpsSm;
1499+
int i;
1500+
1501+
/*
1502+
* For only one AP credential don't sned event data, wps_finish() has already set
1503+
* the config. This is for backward compatibility.
1504+
*/
1505+
if (sm->ap_cred_cnt > 1) {
1506+
evt.ap_cred_cnt = sm->ap_cred_cnt;
1507+
for (i = 0; i < MAX_WPS_AP_CRED; i++) {
1508+
os_memcpy(evt.ap_cred[i].ssid, sm->ssid[i], sm->ssid_len[i]);
1509+
os_memcpy(evt.ap_cred[i].passphrase, sm->key[i], sm->key_len[i]);
1510+
}
1511+
esp_event_send_internal(WIFI_EVENT, WIFI_EVENT_STA_WPS_ER_SUCCESS, &evt,
1512+
sizeof(evt), portMAX_DELAY);
1513+
} else {
1514+
esp_event_send_internal(WIFI_EVENT, WIFI_EVENT_STA_WPS_ER_SUCCESS,
1515+
0, 0, portMAX_DELAY);
1516+
}
14981517
}
14991518

15001519
void wifi_station_wps_success(void)
@@ -1705,44 +1724,45 @@ wps_sm_get(void)
17051724
}
17061725

17071726
int
1708-
wps_ssid_save(u8 *ssid, u8 ssid_len)
1727+
wps_ssid_save(u8 *ssid, u8 ssid_len, u8 idx)
17091728
{
17101729
u8 *tmpssid;
17111730

1712-
if (!ssid || !gWpsSm) {
1731+
if (!ssid || !gWpsSm || idx > 2) {
17131732
return ESP_FAIL;
17141733
}
17151734

1716-
memset(gWpsSm->ssid, 0x00, sizeof(gWpsSm->ssid));
1717-
memcpy(gWpsSm->ssid, ssid, ssid_len);
1718-
gWpsSm->ssid_len = ssid_len;
1735+
memset(gWpsSm->ssid[idx], 0x00, sizeof(gWpsSm->ssid[idx]));
1736+
memcpy(gWpsSm->ssid[idx], ssid, ssid_len);
1737+
gWpsSm->ssid_len[idx] = ssid_len;
1738+
gWpsSm->ap_cred_cnt++;
17191739

17201740
tmpssid = (u8 *)os_zalloc(ssid_len + 1);
17211741
if (tmpssid) {
17221742
memcpy(tmpssid, ssid, ssid_len);
1723-
wpa_printf(MSG_DEBUG, "WPS: ssid[%s]", tmpssid);
1743+
wpa_printf(MSG_DEBUG, "WPS: key[%s]", tmpssid);
17241744
os_free(tmpssid);
17251745
}
17261746
return ESP_OK;
17271747
}
17281748

17291749
int
1730-
wps_key_save(char *key, u8 key_len)
1750+
wps_key_save(char *key, u8 key_len, u8 idx)
17311751
{
17321752
u8 *tmpkey;
17331753

1734-
if (!key || !gWpsSm) {
1754+
if (!key || !gWpsSm || idx > 2) {
17351755
return ESP_FAIL;
17361756
}
17371757

1738-
memset(gWpsSm->key, 0x00, sizeof(gWpsSm->key));
1739-
memcpy(gWpsSm->key, key, key_len);
1740-
gWpsSm->key_len = key_len;
1758+
memset(gWpsSm->key[idx], 0x00, sizeof(gWpsSm->key[idx]));
1759+
memcpy(gWpsSm->key[idx], key, key_len);
1760+
gWpsSm->key_len[idx] = key_len;
17411761

17421762
tmpkey = (u8 *)os_zalloc(key_len + 1);
17431763
if (tmpkey) {
17441764
memcpy(tmpkey, key, key_len);
1745-
wpa_printf(MSG_DEBUG, "WPS: key[%s]", tmpkey);
1765+
wpa_printf(MSG_DEBUG, "WPS: key[%s], idx - %d", tmpkey, idx);
17461766
os_free(tmpkey);
17471767
}
17481768
return ESP_OK;

components/wpa_supplicant/src/wps/wps.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,13 +1031,14 @@ struct wps_sm {
10311031
u8 identity_len;
10321032
u8 ownaddr[ETH_ALEN];
10331033
u8 bssid[ETH_ALEN];
1034-
u8 ssid[32];
1035-
u8 ssid_len;
1034+
u8 ssid[MAX_WPS_AP_CRED][MAX_SSID_LEN];
1035+
u8 ssid_len[MAX_WPS_AP_CRED];
1036+
char key[MAX_WPS_AP_CRED][MAX_PASSPHRASE_LEN];
1037+
u8 key_len[MAX_WPS_AP_CRED];
1038+
u8 ap_cred_cnt;
10361039
struct wps_device_data *dev;
10371040
u8 uuid[16];
10381041
u8 eapol_version;
1039-
char key[64];
1040-
u8 key_len;
10411042
ETSTimer wps_timeout_timer;
10421043
ETSTimer wps_msg_timeout_timer;
10431044
ETSTimer wps_scan_timer;
@@ -1061,8 +1062,8 @@ struct wps_sm {
10611062
#define WIFI_CAPINFO_PRIVACY 0x0010
10621063

10631064
struct wps_sm *wps_sm_get(void);
1064-
int wps_ssid_save(u8 *ssid, u8 ssid_len);
1065-
int wps_key_save(char *key, u8 key_len);
1065+
int wps_ssid_save(u8 *ssid, u8 ssid_len, u8 idx);
1066+
int wps_key_save(char *key, u8 key_len, u8 idx);
10661067
int wps_station_wps_register_cb(wps_st_cb_t cb);
10671068
int wps_station_wps_unregister_cb(void);
10681069
int wps_start_pending(void);

components/wpa_supplicant/src/wps/wps_enrollee.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)
652652

653653

654654
static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
655-
size_t cred_len, int wps2)
655+
size_t cred_len, int cred_idx, int wps2)
656656
{
657657
struct wps_parse_attr *attr;
658658
struct wpabuf msg;
@@ -712,9 +712,8 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
712712
goto _out;
713713
}
714714
#endif /* CONFIG_WPS2 */
715-
716-
wps_ssid_save(wps->cred.ssid, wps->cred.ssid_len);
717-
wps_key_save((char *)wps->cred.key, wps->cred.key_len);
715+
wps_ssid_save(wps->cred.ssid, wps->cred.ssid_len, cred_idx);
716+
wps_key_save((char *)wps->cred.key, wps->cred.key_len, cred_idx);
718717

719718
if (wps->wps->cred_cb) {
720719
wps->cred.cred_attr = cred - 4;
@@ -749,7 +748,7 @@ static int wps_process_creds(struct wps_data *wps, const u8 *cred[],
749748

750749
for (i = 0; i < num_cred; i++) {
751750
int res;
752-
res = wps_process_cred_e(wps, cred[i], cred_len[i], wps2);
751+
res = wps_process_cred_e(wps, cred[i], cred_len[i], i, wps2);
753752
if (res == 0)
754753
ok++;
755754
else if (res == -2) {

examples/wifi/wps/main/wps.c

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "esp_wps.h"
2828
#include "esp_event.h"
2929
#include "nvs_flash.h"
30+
#include <string.h>
3031

3132

3233
/*set wps mode via project configuration */
@@ -38,6 +39,7 @@
3839
#define WPS_MODE WPS_TYPE_DISABLE
3940
#endif /*CONFIG_EXAMPLE_WPS_TYPE_PBC*/
4041

42+
#define MAX_RETRY_ATTEMPTS 2
4143

4244
#ifndef PIN2STR
4345
#define PIN2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5], (a)[6], (a)[7]
@@ -46,23 +48,67 @@
4648

4749
static const char *TAG = "example_wps";
4850
static esp_wps_config_t config = WPS_CONFIG_INIT_DEFAULT(WPS_MODE);
51+
static wifi_config_t wps_ap_creds[MAX_WPS_AP_CRED];
52+
static int s_ap_creds_num = 0;
53+
static int s_retry_num = 0;
4954

5055
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
5156
int32_t event_id, void* event_data)
5257
{
58+
static int ap_idx = 1;
59+
5360
switch (event_id) {
5461
case WIFI_EVENT_STA_START:
5562
ESP_LOGI(TAG, "WIFI_EVENT_STA_START");
5663
break;
5764
case WIFI_EVENT_STA_DISCONNECTED:
5865
ESP_LOGI(TAG, "WIFI_EVENT_STA_DISCONNECTED");
59-
ESP_ERROR_CHECK(esp_wifi_connect());
66+
if (s_retry_num < MAX_RETRY_ATTEMPTS) {
67+
ESP_ERROR_CHECK(esp_wifi_connect());
68+
s_retry_num++;
69+
} else if (ap_idx < s_ap_creds_num) {
70+
/* Try the next AP credential if first one fails */
71+
72+
if (ap_idx < s_ap_creds_num) {
73+
ESP_LOGI(TAG, "Connecting to SSID: %s, Passphrase: %s",
74+
wps_ap_creds[ap_idx].sta.ssid, wps_ap_creds[ap_idx].sta.password);
75+
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wps_ap_creds[ap_idx++]) );
76+
ESP_ERROR_CHECK(esp_wifi_connect());
77+
}
78+
s_retry_num = 0;
79+
} else {
80+
ESP_LOGI(TAG, "Failed to connect!");
81+
}
82+
6083
break;
6184
case WIFI_EVENT_STA_WPS_ER_SUCCESS:
6285
ESP_LOGI(TAG, "WIFI_EVENT_STA_WPS_ER_SUCCESS");
63-
/* esp_wifi_wps_start() only gets ssid & password, so call esp_wifi_connect() here. */
64-
ESP_ERROR_CHECK(esp_wifi_wps_disable());
65-
ESP_ERROR_CHECK(esp_wifi_connect());
86+
{
87+
wifi_event_sta_wps_er_success_t *evt =
88+
(wifi_event_sta_wps_er_success_t *)event_data;
89+
int i;
90+
91+
if (evt) {
92+
s_ap_creds_num = evt->ap_cred_cnt;
93+
for (i = 0; i < s_ap_creds_num; i++) {
94+
memcpy(wps_ap_creds[i].sta.ssid, evt->ap_cred[i].ssid,
95+
sizeof(evt->ap_cred[i].ssid));
96+
memcpy(wps_ap_creds[i].sta.password, evt->ap_cred[i].passphrase,
97+
sizeof(evt->ap_cred[i].passphrase));
98+
}
99+
/* If multiple AP credentials are received from WPS, connect with first one */
100+
ESP_LOGI(TAG, "Connecting to SSID: %s, Passphrase: %s",
101+
wps_ap_creds[0].sta.ssid, wps_ap_creds[0].sta.password);
102+
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wps_ap_creds[0]) );
103+
}
104+
/*
105+
* If only one AP credential is received from WPS, there will be no event data and
106+
* esp_wifi_set_config() is already called by WPS modules for backward compatibility
107+
* with legacy apps. So directly attempt connection here.
108+
*/
109+
ESP_ERROR_CHECK(esp_wifi_wps_disable());
110+
ESP_ERROR_CHECK(esp_wifi_connect());
111+
}
66112
break;
67113
case WIFI_EVENT_STA_WPS_ER_FAILED:
68114
ESP_LOGI(TAG, "WIFI_EVENT_STA_WPS_ER_FAILED");

0 commit comments

Comments
 (0)