diff --git a/components/esp_common/src/esp_err_to_name.c b/components/esp_common/src/esp_err_to_name.c index a6ac17ddbd..59963fa78c 100644 --- a/components/esp_common/src/esp_err_to_name.c +++ b/components/esp_common/src/esp_err_to_name.c @@ -44,6 +44,9 @@ #if __has_include("esp_spi_flash.h") #include "esp_spi_flash.h" #endif +#if __has_include("esp_supplicant/esp_dpp.h") +#include "esp_supplicant/esp_dpp.h" +#endif #if __has_include("esp_supplicant/esp_wps.h") #include "esp_supplicant/esp_wps.h" #endif @@ -62,9 +65,6 @@ #if __has_include("ulp_common.h") #include "ulp_common.h" #endif -#if __has_include("esp_supplicant/esp_dpp.h") -#include "esp_supplicant/esp_dpp.h" -#endif #ifdef CONFIG_ESP_ERR_TO_NAME_LOOKUP #define ERR_TBL_IT(err) {err, #err} @@ -415,20 +415,11 @@ static const esp_err_msg_t esp_err_msg_table[] = { # ifdef ESP_ERR_DPP_FAILURE ERR_TBL_IT(ESP_ERR_DPP_FAILURE), /* 12439 0x3097 Generic failure during DPP Operation */ # endif -# ifdef ESP_ERR_DPP_NO_MEM - ERR_TBL_IT(ESP_ERR_DPP_NO_MEM), /* 12440 0x3098 Failure to allocate memory in DPP Operation */ -# endif -# ifdef ESP_ERR_DPP_TIMEOUT - ERR_TBL_IT(ESP_ERR_DPP_TIMEOUT), /* 12441 0x3099 DPP Operation timed out */ -# endif # ifdef ESP_ERR_DPP_TX_FAILURE - ERR_TBL_IT(ESP_ERR_DPP_TX_FAILURE), /* 12442 0x309a DPP Frame Tx failed OR not Acked */ + ERR_TBL_IT(ESP_ERR_DPP_TX_FAILURE), /* 12440 0x3098 DPP Frame Tx failed OR not Acked */ # endif # ifdef ESP_ERR_DPP_INVALID_ATTR - ERR_TBL_IT(ESP_ERR_DPP_INVALID_ATTR), /* 12443 0x309b Encountered invalid DPP Attribute */ -# endif -# ifdef ESP_ERR_DPP_NOT_SUPPORTED - ERR_TBL_IT(ESP_ERR_DPP_NOT_SUPPORTED), /* 12444 0x309c DPP Configuration not supported */ + ERR_TBL_IT(ESP_ERR_DPP_INVALID_ATTR), /* 12441 0x3099 Encountered invalid DPP Attribute */ # endif // components/esp_common/include/esp_err.h # ifdef ESP_ERR_MESH_BASE diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index 131cf35884..e72afb2e09 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -331,12 +331,6 @@ menu "Wi-Fi" If neither of them are enabled, the other 7.4KB IRAM memory would be taken by this option. Wi-Fi power-save mode average current would be reduced if this option is enabled. - config ESP32_WIFI_OFFCHANNEL_OPS - bool "Enable Offchannel operations" - default n - help - Select this option to enable Offchannel Tx and Remain on Channel features. - endmenu # Wi-Fi menu "PHY" diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index b69f47de2e..238e90a8aa 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -35,6 +35,12 @@ typedef enum { WIFI_IF_AP = ESP_IF_WIFI_AP, } wifi_interface_t; +#define WIFI_OFFCHAN_TX_REQ 1 +#define WIFI_OFFCHAN_TX_CANCEL 0 + +#define WIFI_ROC_REQ 1 +#define WIFI_ROC_CANCEL 0 + typedef enum { WIFI_COUNTRY_POLICY_AUTO, /**< Country policy is auto, use the country info of AP to which the station is connected */ WIFI_COUNTRY_POLICY_MANUAL, /**< Country policy is manual, always use the configured country info */ @@ -484,19 +490,30 @@ typedef struct { } wifi_ant_config_t; /** - * @brief Management Frame Tx Request + * @brief The Rx callback function of Action Tx operations + * + * @param hdr pointer to the IEEE 802.11 Header structure + * @param payload pointer to the Payload following 802.11 Header + * @param len length of the Payload + * @param channel channel number the frame is received on + * + */ +typedef int (* wifi_action_rx_cb_t)(uint8_t *hdr, uint8_t *payload, + size_t len, uint8_t channel); + +/** + * @brief Action Frame Tx Request * * */ typedef struct { - wifi_interface_t ifx; /**< WiFi interface to send request to */ - uint8_t subtype; /**< Frame Subtype of Management frame */ - uint8_t dest_mac[6]; /**< Destination MAC address */ - bool no_ack; /**< Indicates no ack required for the frame */ - uint32_t cookie; /**< Context to identify the request */ - uint32_t data_len; /**< Length of the appended Data */ - uint8_t data[0]; /**< Appended Data payload */ -} mgmt_tx_req_t; + wifi_interface_t ifx; /**< WiFi interface to send request to */ + uint8_t dest_mac[6]; /**< Destination MAC address */ + bool no_ack; /**< Indicates no ack required */ + wifi_action_rx_cb_t rx_cb; /**< Rx Callback to receive any response */ + uint32_t data_len; /**< Length of the appended Data */ + uint8_t data[0]; /**< Appended Data payload */ +} wifi_action_tx_req_t; /** * @brief WiFi PHY rate encodings @@ -662,17 +679,17 @@ typedef struct { #define WIFI_STATIS_PS (1<<4) #define WIFI_STATIS_ALL (-1) -/** Argument structure for WIFI_EVENT_MGMT_TX_STATUS event */ +/** Argument structure for WIFI_EVENT_ACTION_TX_STATUS event */ typedef struct { wifi_interface_t ifx; /**< WiFi interface to send request to */ - uint32_t cookie; /**< Context to identify the request */ + uint32_t context; /**< Context to identify the request */ uint8_t da[6]; /**< Destination MAC address */ uint8_t status; /**< Status of the operation */ -} wifi_event_mgmt_tx_status_t; +} wifi_event_action_tx_status_t; /** Argument structure for WIFI_EVENT_ROC_DONE event */ typedef struct { - uint32_t cookie; /**< Context to identify the request */ + uint32_t context; /**< Context to identify the request */ } wifi_event_roc_done_t; #ifdef __cplusplus diff --git a/components/wpa_supplicant/include/esp_supplicant/esp_dpp.h b/components/wpa_supplicant/include/esp_supplicant/esp_dpp.h index 0e5bccbf55..c6c86bc536 100644 --- a/components/wpa_supplicant/include/esp_supplicant/esp_dpp.h +++ b/components/wpa_supplicant/include/esp_supplicant/esp_dpp.h @@ -1,4 +1,4 @@ -// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,35 +23,92 @@ extern "C" { #endif -#define ESP_ERR_DPP_FAILURE (ESP_ERR_WIFI_BASE + 151) /*!< Generic failure during DPP Operation */ -#define ESP_ERR_DPP_NO_MEM (ESP_ERR_WIFI_BASE + 152) /*!< Failure to allocate memory in DPP Operation */ -#define ESP_ERR_DPP_TIMEOUT (ESP_ERR_WIFI_BASE + 153) /*!< DPP Operation timed out */ -#define ESP_ERR_DPP_TX_FAILURE (ESP_ERR_WIFI_BASE + 154) /*!< DPP Frame Tx failed OR not Acked */ -#define ESP_ERR_DPP_INVALID_ATTR (ESP_ERR_WIFI_BASE + 155) /*!< Encountered invalid DPP Attribute */ -#define ESP_ERR_DPP_NOT_SUPPORTED (ESP_ERR_WIFI_BASE + 156) /*!< Encountered invalid DPP Attribute */ +#define ESP_ERR_DPP_FAILURE (ESP_ERR_WIFI_BASE + 151) /*!< Generic failure during DPP Operation */ +#define ESP_ERR_DPP_TX_FAILURE (ESP_ERR_WIFI_BASE + 152) /*!< DPP Frame Tx failed OR not Acked */ +#define ESP_ERR_DPP_INVALID_ATTR (ESP_ERR_WIFI_BASE + 153) /*!< Encountered invalid DPP Attribute */ -enum dpp_bootstrap_type { - DPP_BOOTSTRAP_QR_CODE, - DPP_BOOTSTRAP_PKEX, - DPP_BOOTSTRAP_NFC_URI, -}; +/** @brief Types of Bootstrap Methods for DPP. */ +typedef enum dpp_bootstrap_type { + DPP_BOOTSTRAP_QR_CODE, /**< QR Code Method */ + DPP_BOOTSTRAP_PKEX, /**< Proof of Knowledge Method */ + DPP_BOOTSTRAP_NFC_URI, /**< NFC URI record Method */ +} esp_supp_dpp_bootstrap_t; +/** @brief Types of Callback Events received from DPP Supplicant. */ typedef enum { - WIFI_DPP_URI_READY, - WIFI_DPP_CFG_RECVD, - WIFI_DPP_FAIL, -} wifi_dpp_event_t; + ESP_SUPP_DPP_URI_READY, /**< URI is ready through Bootstrapping */ + ESP_SUPP_DPP_CFG_RECVD, /**< Config received via DPP Authentication */ + ESP_SUPP_DPP_FAIL, /**< DPP Authentication failure */ +} esp_supp_dpp_event_t; -typedef void (*wifi_dpp_event_cb_t)(wifi_dpp_event_t evt, void *data); +/** + * @brief Callback function for receiving DPP Events from Supplicant. + * + * Callback function will be called with DPP related information. + * + * @param evt DPP event ID + * @param data Event data payload + */ +typedef void (*esp_supp_dpp_event_cb_t)(esp_supp_dpp_event_t evt, void *data); -esp_err_t esp_supp_dpp_init(wifi_dpp_event_cb_t evt_cb); +/** + * @brief Initialize DPP Supplicant + * + * Starts DPP Supplicant and initializes related Data Structures. + * + * @param evt_cb Callback function to receive DPP related events + * + * return + * - ESP_OK: Success + * - ESP_FAIL: Failure + */ +esp_err_t esp_supp_dpp_init(esp_supp_dpp_event_cb_t evt_cb); + +/** + * @brief De-initalize DPP Supplicant + * + * Frees memory from DPP Supplicant Data Structures. + */ void esp_supp_dpp_deinit(void); -esp_err_t esp_dpp_bootstrap_gen(uint8_t channel, enum dpp_bootstrap_type type, - const char *key, const char *info); +/** + * @brief Generates Bootstrap Information as an Enrollee. + * + * Generates Out Of Band Bootstrap information as an Enrollee which can be + * used by a DPP Configurator to provision the Enrollee. + * + * @param chan_list List of channels device will be available on for listening + * @param type Bootstrap method type, only QR Code method is supported for now. + * @param key (Optional) Private Key used to generate a Bootstrapping Public Key + * @param info (Optional) Ancilliary Device Information like Serial Number + * + * @return + * - ESP_OK: Success + * - ESP_FAIL: Failure + */ +esp_err_t +esp_supp_dpp_bootstrap_gen(const char *chan_list, esp_supp_dpp_bootstrap_t type, + const char *key, const char *info); -void esp_dpp_start_listen(uint8_t channel); -void esp_dpp_stop_listen(void); +/** + * @brief Start listening on Channels provided during esp_supp_dpp_bootstrap_gen. + * + * Listens on every Channel from Channel List for a pre-defined wait time. + * + * @return + * - ESP_OK: Success + * - ESP_FAIL: Generic Failure + * - ESP_ERR_INVALID_STATE: ROC attempted before WiFi is started + * - ESP_ERR_NO_MEM: Memory allocation failed while posting ROC request + */ +esp_err_t esp_supp_dpp_start_listen(void); + +/** + * @brief Stop listening on Channels. + * + * Stops listening on Channels and cancels ongoing listen operation. + */ +void esp_supp_dpp_stop_listen(void); #ifdef __cplusplus } diff --git a/components/wpa_supplicant/src/common/dpp.c b/components/wpa_supplicant/src/common/dpp.c index 462a228d9a..c96869b318 100644 --- a/components/wpa_supplicant/src/common/dpp.c +++ b/components/wpa_supplicant/src/common/dpp.c @@ -2406,8 +2406,16 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, size_t len[2]; u8 *unwrapped = NULL; size_t unwrapped_len = 0; - const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap; - u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len, i_bootstrap_len; + const u8 *wrapped_data; + const u8 *i_proto; + const u8 *i_nonce; + const u8 *i_capab; + const u8 *i_bootstrap; + u16 wrapped_data_len; + u16 i_proto_len; + u16 i_nonce_len; + u16 i_capab_len; + u16 i_bootstrap_len; struct dpp_authentication *auth = NULL; #ifdef CONFIG_WPA_TESTING_OPTIONS @@ -4628,7 +4636,7 @@ static int dpp_parse_cred_legacy(struct dpp_config_obj *conf, (u8 *)pass->string, len); if (len < 8 || len > 63) return -1; - os_strncpy(conf->passphrase, pass->string, + os_strlcpy(conf->passphrase, pass->string, sizeof(conf->passphrase)); } else if (psk_hex && psk_hex->type == JSON_STRING) { if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) { @@ -6139,8 +6147,8 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) info ? "I:" : "", info ? info : "", info ? ";" : "", pk); - bi->id = dpp_next_id(dpp); - dl_list_add(&dpp->bootstrap, &bi->list); + bi->id = dpp_next_id(dpp); + dl_list_add(&dpp->bootstrap, &bi->list); ret = bi->id; bi = NULL; fail: diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_dpp.c b/components/wpa_supplicant/src/esp_supplicant/esp_dpp.c index 5c59d9c2f7..1ebe8912bd 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_dpp.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_dpp.c @@ -1,28 +1,33 @@ -/* - * wpa_supplicant - DPP - * Copyright (c) 2017, Qualcomm Atheros, Inc. - * Copyright (c) 2018-2019, The Linux Foundation - * - * This software may be distributed under the terms of the BSD license. - */ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #include "esp_dpp_i.h" #include "esp_dpp.h" #include "esp_wpa.h" #include "esp_timer.h" #include "esp_event.h" +#include "esp_wifi.h" #include "common/ieee802_11_defs.h" static void *s_dpp_task_hdl = NULL; static void *s_dpp_evt_queue = NULL; static void *s_dpp_api_lock = NULL; -static bool s_dpp_auth_start; +static bool s_dpp_stop_listening; static int s_dpp_auth_retries; struct esp_dpp_context_t s_dpp_ctx; - -#define REQUEST_ADD 1 -#define REQUEST_CANCEL 0 +static wifi_action_rx_cb_t s_action_rx_cb = esp_supp_rx_action; #define DPP_API_LOCK() xSemaphoreTakeRecursive(s_dpp_api_lock, portMAX_DELAY) #define DPP_API_UNLOCK() xSemaphoreGiveRecursive(s_dpp_api_lock) @@ -35,14 +40,14 @@ struct action_rx_param { struct ieee80211_action *action_frm; }; -int esp_dpp_post_evt(uint32_t evt_id, uint32_t data) +static int esp_dpp_post_evt(uint32_t evt_id, uint32_t data) { DPP_API_LOCK(); dpp_event_t *evt = os_zalloc(sizeof(dpp_event_t)); if (evt == NULL) { DPP_API_UNLOCK(); - return ESP_ERR_DPP_NO_MEM; + return ESP_ERR_NO_MEM; } evt->id = evt_id; evt->data = data; @@ -55,7 +60,7 @@ int esp_dpp_post_evt(uint32_t evt_id, uint32_t data) return ESP_OK; } -static void esp_dpp_call_cb(wifi_dpp_event_t evt, void *data) +static void esp_dpp_call_cb(esp_supp_dpp_event_t evt, void *data) { s_dpp_ctx.dpp_event_cb(evt, data); } @@ -63,21 +68,25 @@ static void esp_dpp_call_cb(wifi_dpp_event_t evt, void *data) void esp_send_action_frame(uint8_t *dest_mac, const uint8_t *buf, uint32_t len, uint8_t channel, uint32_t wait_time_ms) { - mgmt_tx_req_t *req = os_zalloc(sizeof(*req) + len);; + wifi_action_tx_req_t *req = os_zalloc(sizeof(*req) + len);; + if (!req) { + return; + } req->ifx = ESP_IF_WIFI_STA; - req->subtype = WLAN_FC_STYPE_ACTION; memcpy(req->dest_mac, dest_mac, ETH_ALEN); req->no_ack = false; req->data_len = len; + req->rx_cb = s_action_rx_cb; memcpy(req->data, buf, req->data_len); wpa_printf(MSG_DEBUG, "DPP: Mgmt Tx - MAC:" MACSTR ", Channel-%d, WaitT-%d", - MAC2STR(dest_mac), channel, wait_time_ms); + MAC2STR(dest_mac), channel, wait_time_ms); - if (ESP_OK != esp_wifi_mgmt_tx_req(REQUEST_ADD, channel, wait_time_ms, req)) { + if (ESP_OK != esp_wifi_action_tx_req(WIFI_OFFCHAN_TX_REQ, channel, + wait_time_ms, req)) { wpa_printf(MSG_ERROR, "DPP: Failed to perfrm offchannel operation"); - esp_dpp_call_cb(WIFI_DPP_FAIL, (void *)ESP_ERR_DPP_TX_FAILURE); + esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_DPP_TX_FAILURE); os_free(req); return; } @@ -96,7 +105,7 @@ static void esp_dpp_rx_auth_req(struct action_rx_param *rx_param, uint8_t *dpp_d wpa_printf(MSG_INFO, "DPP: Authentication Request from " MACSTR, MAC2STR(rx_param->sa)); r_bootstrap = dpp_get_attr(dpp_data, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, - &r_bootstrap_len); + &r_bootstrap_len); if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) { wpa_printf(MSG_INFO, "DPP: Missing or invalid Responder Bootstrapping Key Hash attribute"); rc = ESP_ERR_DPP_INVALID_ATTR; @@ -105,7 +114,7 @@ static void esp_dpp_rx_auth_req(struct action_rx_param *rx_param, uint8_t *dpp_d wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash", r_bootstrap, r_bootstrap_len); i_bootstrap = dpp_get_attr(dpp_data, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH, - &i_bootstrap_len); + &i_bootstrap_len); if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) { wpa_printf(MSG_INFO, "DPP: Missing or invalid Initiator Bootstrapping Key Hash attribute"); rc = ESP_ERR_DPP_INVALID_ATTR; @@ -132,7 +141,7 @@ static void esp_dpp_rx_auth_req(struct action_rx_param *rx_param, uint8_t *dpp_d rx_param->channel, OFFCHAN_TX_WAIT_TIME); return; fail: - esp_dpp_call_cb(WIFI_DPP_FAIL, (void *)rc); + esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)rc); } static void gas_query_req_tx(struct dpp_authentication *auth) @@ -144,7 +153,7 @@ static void gas_query_req_tx(struct dpp_authentication *auth) supp_op_classes); if (!buf) { wpa_printf(MSG_DEBUG, "DPP: No configuration request data available"); - esp_dpp_call_cb(WIFI_DPP_FAIL, (void *)ESP_ERR_DPP_FAILURE); + esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_DPP_FAILURE); return; } @@ -183,9 +192,9 @@ static int esp_dpp_handle_config_obj(struct dpp_authentication *auth, wpa_printf(MSG_INFO, DPP_EVENT_CONNECTOR "%s", conf->connector); } - s_dpp_auth_start = false; - esp_wifi_mgmt_tx_req(REQUEST_CANCEL, 0, 0, NULL); - esp_dpp_call_cb(WIFI_DPP_CFG_RECVD, wifi_cfg); + s_dpp_stop_listening = false; + esp_wifi_action_tx_req(WIFI_OFFCHAN_TX_CANCEL, 0, 0, NULL); + esp_dpp_call_cb(ESP_SUPP_DPP_CFG_RECVD, wifi_cfg); return 0; } @@ -193,8 +202,8 @@ static int esp_dpp_handle_config_obj(struct dpp_authentication *auth, static void esp_dpp_rx_auth_conf(struct action_rx_param *rx_param, uint8_t *dpp_data) { struct dpp_authentication *auth = s_dpp_ctx.dpp_auth; - struct ieee80211_public_action *public_action = - &rx_param->action_frm->u.public_action; + struct ieee80211_public_action *public_action = + &rx_param->action_frm->u.public_action; size_t len = rx_param->vendor_data_len - 2; int rc; @@ -227,7 +236,7 @@ static void esp_dpp_rx_auth_conf(struct action_rx_param *rx_param, uint8_t *dpp_ return; fail: - esp_dpp_call_cb(WIFI_DPP_FAIL, (void *)rc); + esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)rc); } static void esp_dpp_rx_auth(struct action_rx_param *rx_param) @@ -241,7 +250,7 @@ static void esp_dpp_rx_auth(struct action_rx_param *rx_param) if (crypto_suit != 1) { wpa_printf(MSG_ERROR, "DPP: Unsupported crypto suit"); - esp_dpp_call_cb(WIFI_DPP_FAIL, (void *)ESP_ERR_DPP_NOT_SUPPORTED); + esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_NOT_SUPPORTED); return; } @@ -263,44 +272,44 @@ static void gas_query_resp_rx(struct action_rx_param *rx_param) int i, res; if (pos[1] == WLAN_EID_VENDOR_SPECIFIC && pos[2] == 5 && - WPA_GET_BE24(&pos[3]) == OUI_WFA && pos[6] == 0x1a && pos[7] == 1) { - if (dpp_conf_resp_rx(auth, resp, rx_param->vendor_data_len-2) < 0) { + WPA_GET_BE24(&pos[3]) == OUI_WFA && pos[6] == 0x1a && pos[7] == 1) { + if (dpp_conf_resp_rx(auth, resp, rx_param->vendor_data_len - 2) < 0) { wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); goto fail; } for (i = 0; i < auth->num_conf_obj; i++) { res = esp_dpp_handle_config_obj(auth, &auth->conf_obj[i]); - if (res < 0) + if (res < 0) { goto fail; + } } } return; fail: - esp_dpp_call_cb(WIFI_DPP_FAIL, (void *)ESP_ERR_DPP_FAILURE); + esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_DPP_FAILURE); } static void esp_dpp_rx_action(struct action_rx_param *rx_param) { if (rx_param->action_frm->category == WLAN_ACTION_PUBLIC) { - struct ieee80211_public_action *public_action = - &rx_param->action_frm->u.public_action; + struct ieee80211_public_action *public_action = + &rx_param->action_frm->u.public_action; wpa_printf(MSG_DEBUG, "DPP: Rx Public Action frame: action - %d", public_action->action); if (public_action->action == WLAN_PA_VENDOR_SPECIFIC && - WPA_GET_BE24(public_action->v.pa_vendor_spec.oui) == OUI_WFA && - public_action->v.pa_vendor_spec.wfa_stype == DPP_OUI_TYPE) { + WPA_GET_BE24(public_action->v.pa_vendor_spec.oui) == OUI_WFA && + public_action->v.pa_vendor_spec.wfa_stype == DPP_OUI_TYPE) { rx_param->vendor_data_len = rx_param->frm_len - - (size_t)(public_action->v.pa_vendor_spec.vendor_data - - (u8 *)rx_param->action_frm); + (size_t)(public_action->v.pa_vendor_spec.vendor_data - + (u8 *)rx_param->action_frm); - if (!s_dpp_auth_start) { - s_dpp_auth_start = true; - esp_dpp_stop_listen(); + if (!s_dpp_stop_listening) { + esp_supp_dpp_stop_listen(); } esp_dpp_rx_auth(rx_param); @@ -310,9 +319,9 @@ static void esp_dpp_rx_action(struct action_rx_param *rx_param) public_action->v.pa_gas_resp.status_code == 0) { rx_param->vendor_data_len = rx_param->frm_len - - (size_t)(public_action->v.pa_gas_resp.data + - public_action->v.pa_gas_resp.length - - (u8 *)rx_param->action_frm); + (size_t)(public_action->v.pa_gas_resp.data + + public_action->v.pa_gas_resp.length - + (u8 *)rx_param->action_frm); gas_query_resp_rx(rx_param); } @@ -322,7 +331,7 @@ static void esp_dpp_rx_action(struct action_rx_param *rx_param) os_free(rx_param); } -void esp_dpp_task(void *pvParameters ) +static void esp_dpp_task(void *pvParameters ) { dpp_event_t *evt; bool task_del = false; @@ -337,38 +346,48 @@ void esp_dpp_task(void *pvParameters ) } switch (evt->id) { - case SIG_DPP_DEL_TASK: - task_del = true; + case SIG_DPP_DEL_TASK: + task_del = true; break; - case SIG_DPP_BOOTSTRAP_GEN: - { - char *command = (char *)evt->data; - const char *uri; + case SIG_DPP_BOOTSTRAP_GEN: { + char *command = (char *)evt->data; + const char *uri; - s_dpp_ctx.id = dpp_bootstrap_gen(s_dpp_ctx.dpp_global, command); - uri = dpp_bootstrap_get_uri(s_dpp_ctx.dpp_global, s_dpp_ctx.id); + s_dpp_ctx.id = dpp_bootstrap_gen(s_dpp_ctx.dpp_global, command); + uri = dpp_bootstrap_get_uri(s_dpp_ctx.dpp_global, s_dpp_ctx.id); - esp_dpp_call_cb(WIFI_DPP_URI_READY, (void *)uri); - os_free(command); - } - break; + esp_dpp_call_cb(ESP_SUPP_DPP_URI_READY, (void *)uri); + os_free(command); + } + break; - case SIG_DPP_RX_ACTION: - { - esp_dpp_rx_action((struct action_rx_param *)evt->data); - } - break; + case SIG_DPP_RX_ACTION: { + esp_dpp_rx_action((struct action_rx_param *)evt->data); + } + break; - default: + case SIG_DPP_LISTEN_NEXT_CHANNEL: { + struct dpp_bootstrap_params_t *p = &s_dpp_ctx.bootstrap_params; + static int counter; + int channel; + + channel = p->chan_list[counter++ % p->num_chan]; + esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, WIFI_ROC_REQ, channel, + BOOTSTRAP_ROC_WAIT_TIME, s_action_rx_cb); + } + break; + + default: break; } os_free(evt); DPP_API_UNLOCK(); - if (task_del) + if (task_del) { break; + } } } @@ -384,7 +403,7 @@ void esp_dpp_task(void *pvParameters ) vTaskDelete(NULL); } -int esp_dpp_rx_mgmt(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel) +int esp_supp_rx_action(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel) { struct ieee80211_hdr *rx_hdr = (struct ieee80211_hdr *)hdr; struct action_rx_param *rx_param; @@ -406,53 +425,110 @@ int esp_dpp_rx_mgmt(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel) return ESP_ERR_NOT_SUPPORTED; } -static void offchan_event_handler(void* arg, esp_event_base_t event_base, - int event_id, void* event_data) +static void offchan_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) { - if (event_id == WIFI_EVENT_MGMT_TX_STATUS) { - wifi_event_mgmt_tx_status_t *evt = - (wifi_event_mgmt_tx_status_t *)event_data; + if (event_id == WIFI_EVENT_ACTION_TX_STATUS) { + wifi_event_action_tx_status_t *evt = + (wifi_event_action_tx_status_t *)event_data; wpa_printf(MSG_DEBUG, "Mgmt Tx Status - %d, Cookie - 0x%x", - evt->status, (uint32_t)evt->cookie); + evt->status, (uint32_t)evt->context); - if (evt->status) - esp_dpp_call_cb(WIFI_DPP_FAIL, (void *)ESP_ERR_DPP_TX_FAILURE); + if (evt->status) { + esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_DPP_TX_FAILURE); + } } else if (event_id == WIFI_EVENT_ROC_DONE) { wifi_event_roc_done_t *evt = (wifi_event_roc_done_t *)event_data; - if (!s_dpp_auth_start && evt->cookie == BOOTSTRAP_ROC_COOKIE) { - esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, REQUEST_ADD, - s_dpp_ctx.bootstrap_params.channel, - BOOTSTRAP_ROC_WAIT_TIME, - (void *)BOOTSTRAP_ROC_COOKIE); + if (!s_dpp_stop_listening && evt->context == (uint32_t)s_action_rx_cb) { + esp_dpp_post_evt(SIG_DPP_LISTEN_NEXT_CHANNEL, 0); } } } -esp_err_t esp_dpp_bootstrap_gen(uint8_t channel, enum dpp_bootstrap_type type, - const char *key, const char *uri_info) +static char *esp_dpp_parse_chan_list(const char *chan_list) { struct dpp_bootstrap_params_t *params = &s_dpp_ctx.bootstrap_params; + char *uri_channels = os_zalloc(14 * 6 + 1); + const char *pos = chan_list; + const char *pos2; + char *pos3 = uri_channels; + params->num_chan = 0; + + os_memcpy(pos3, " chan=", strlen(" chan=")); + pos3 += strlen(" chan="); + + while (pos && *pos) { + int channel; + int len = strlen(chan_list); + + pos2 = pos; + while (*pos2 >= '0' && *pos2 <= '9') { + pos2++; + } + if (*pos2 == ',' || *pos2 == ' ' || *pos2 == '\0') { + channel = atoi(pos); + if (channel < 1 || channel > 14) { + os_free(uri_channels); + return NULL; + } + params->chan_list[params->num_chan++] = channel; + os_memcpy(pos3, "81/", strlen("81/")); + pos3 += strlen("81/"); + os_memcpy(pos3, pos, (pos2 - pos)); + pos3 += (pos2 - pos); + *pos3++ = ','; + + pos = pos2 + 1; + } + while (*pos == ',' || *pos == ' ' || *pos == '\0') { + pos++; + } + + if (((int)(pos - chan_list) >= len)) { + break; + } + } + *(pos3 - 1) = ' '; + + return uri_channels; +} + +esp_err_t +esp_supp_dpp_bootstrap_gen(const char *chan_list, enum dpp_bootstrap_type type, + const char *key, const char *uri_info) +{ + struct dpp_bootstrap_params_t *params = &s_dpp_ctx.bootstrap_params; + char *uri_chan_list = esp_dpp_parse_chan_list(chan_list); char *command = os_zalloc(1200); int ret; + if (!uri_chan_list || !command || params->num_chan >= 14 || params->num_chan == 0) { + wpa_printf(MSG_ERROR, "Invalid Channel list - %s", chan_list); + if (command) { + os_free(command); + } + ret = ESP_ERR_DPP_FAILURE; + goto fail; + } + if (type != DPP_BOOTSTRAP_QR_CODE) { wpa_printf(MSG_INFO, "Bootstrap type %d not supported", type); os_free(command); - ret = ESP_ERR_DPP_NOT_SUPPORTED; + ret = ESP_ERR_NOT_SUPPORTED; goto fail; } params->type = type; - params->channel = channel; esp_wifi_get_mac(ESP_IF_WIFI_STA, params->mac); if (uri_info) { params->info_len = strlen(uri_info); if (params->info_len) { - params->info = os_zalloc(params->info_len+1); + params->info = os_zalloc(params->info_len + 1); if (!params->info) { - ret = ESP_ERR_DPP_NO_MEM; + os_free(command); + ret = ESP_ERR_NO_MEM; goto fail; } os_memcpy(params->info, uri_info, params->info_len); @@ -468,19 +544,20 @@ esp_err_t esp_dpp_bootstrap_gen(uint8_t channel, enum dpp_bootstrap_type type, params->key = os_zalloc(params->key_len + sizeof(prefix) + sizeof(postfix)); if (!params->key) { - ret = ESP_ERR_DPP_NO_MEM; + os_free(command); + ret = ESP_ERR_NO_MEM; goto fail; } sprintf(params->key, "%s%s%s", prefix, key, postfix); } } - sprintf(command, "type=qrcode mac=" MACSTR " chan=81/%d %s%s%s%s", - MAC2STR(params->mac), channel, - params->key_len ? "key=" : "", - params->key_len ? params->key : "", - params->info_len ? " info=" : "", - params->info_len ? params->info : ""); + sprintf(command, "type=qrcode mac=" MACSTR "%s%s%s%s%s", + MAC2STR(params->mac), uri_chan_list, + params->key_len ? "key=" : "", + params->key_len ? params->key : "", + params->info_len ? " info=" : "", + params->info_len ? params->info : ""); ret = esp_dpp_post_evt(SIG_DPP_BOOTSTRAP_GEN, (u32)command); if (ret != ESP_OK) { @@ -496,23 +573,32 @@ esp_err_t esp_dpp_bootstrap_gen(uint8_t channel, enum dpp_bootstrap_type type, goto fail; } - return ESP_OK; + ret = ESP_OK; fail: + if (uri_chan_list) { + os_free(uri_chan_list); + } + return ret; } -void esp_dpp_start_listen(uint8_t channel) +esp_err_t esp_supp_dpp_start_listen(void) { - esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, REQUEST_ADD, channel, - BOOTSTRAP_ROC_WAIT_TIME, (void *)BOOTSTRAP_ROC_COOKIE); + if (esp_wifi_get_user_init_flag_internal() == 0) { + wpa_printf(MSG_ERROR, "DPP: ROC not possible before wifi is started"); + return ESP_ERR_INVALID_STATE; + } + + return esp_dpp_post_evt(SIG_DPP_LISTEN_NEXT_CHANNEL, 0); } -void esp_dpp_stop_listen(void) +void esp_supp_dpp_stop_listen(void) { - esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, REQUEST_CANCEL, 0, 0, NULL); + s_dpp_stop_listening = true; + esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, WIFI_ROC_CANCEL, 0, 0, NULL); } -esp_err_t esp_supp_dpp_init(wifi_dpp_event_cb_t cb) +esp_err_t esp_supp_dpp_init(esp_supp_dpp_event_cb_t cb) { struct dpp_global_config cfg = {0}; @@ -523,17 +609,17 @@ esp_err_t esp_supp_dpp_init(wifi_dpp_event_cb_t cb) cfg.msg_ctx = &s_dpp_ctx; s_dpp_ctx.dpp_global = dpp_global_init(&cfg); - s_dpp_auth_start = false; + s_dpp_stop_listening = false; s_dpp_evt_queue = xQueueCreate(3, sizeof(dpp_event_t)); xTaskCreate(esp_dpp_task, "dppT", DPP_TASK_STACK_SIZE, NULL, 2, s_dpp_task_hdl); s_dpp_api_lock = xSemaphoreCreateRecursiveMutex(); if (!s_dpp_api_lock) { wpa_printf(MSG_ERROR, "DPP: dpp_init: failed to create DPP API lock"); - return ESP_ERR_DPP_NO_MEM; + return ESP_ERR_NO_MEM; } - esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_MGMT_TX_STATUS, + esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_ACTION_TX_STATUS, &offchan_event_handler, NULL); esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_ROC_DONE, &offchan_event_handler, NULL); diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_dpp_i.h b/components/wpa_supplicant/src/esp_supplicant/esp_dpp_i.h index 43dce6a75d..3c7aea750a 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_dpp_i.h +++ b/components/wpa_supplicant/src/esp_supplicant/esp_dpp_i.h @@ -1,4 +1,4 @@ -// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ enum SIG_DPP { SIG_DPP_RESET = 0, SIG_DPP_BOOTSTRAP_GEN, SIG_DPP_RX_ACTION, + SIG_DPP_LISTEN_NEXT_CHANNEL, SIG_DPP_DEL_TASK, SIG_DPP_MAX, }; @@ -38,14 +39,13 @@ typedef struct { uint32_t data; } dpp_event_t; -#define BOOTSTRAP_ROC_WAIT_TIME 5000 +#define BOOTSTRAP_ROC_WAIT_TIME 500 #define OFFCHAN_TX_WAIT_TIME 500 -#define BOOTSTRAP_ROC_COOKIE 0xABABABAB - struct dpp_bootstrap_params_t { enum dpp_bootstrap_type type; - uint8_t channel; + uint8_t chan_list[14]; + uint8_t num_chan; uint8_t mac[6]; uint32_t key_len; char *key; @@ -57,13 +57,12 @@ struct esp_dpp_context_t { struct dpp_bootstrap_params_t bootstrap_params; struct dpp_authentication *dpp_auth; int gas_dialog_token; - wifi_config_t wifi_config; - wifi_dpp_event_cb_t dpp_event_cb; + esp_supp_dpp_event_cb_t dpp_event_cb; struct dpp_global *dpp_global; wifi_config_t wifi_cfg; int id; }; -int esp_dpp_rx_mgmt(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel); +int esp_supp_rx_action(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel); #endif /* ESP_DPP_I_H */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h index 9f79597386..86e951e5f7 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h @@ -136,7 +136,6 @@ struct wpa_funcs { uint8_t *(*wpa3_build_sae_msg)(uint8_t *bssid, uint32_t type, size_t *len); int (*wpa3_parse_sae_msg)(uint8_t *buf, size_t len, uint32_t type, uint16_t status); int (*wpa_sta_rx_mgmt)(u8 type, u8 *frame, size_t len, u8 *sender, u32 rssi, u8 channel, u64 current_tsf); - int (*offchan_rx_mgmt)(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel); }; struct wpa2_funcs { @@ -262,9 +261,9 @@ bool esp_wifi_is_btm_enabled_internal(uint8_t if_index); esp_err_t esp_wifi_register_mgmt_frame_internal(uint32_t type, uint32_t subtype); esp_err_t esp_wifi_send_mgmt_frm_internal(const wifi_mgmt_frm_req_t *req); uint8_t esp_wifi_ap_get_prof_pairwise_cipher_internal(void); -esp_err_t esp_wifi_mgmt_tx_req(uint8_t action, uint8_t channel, - uint32_t wait_time_ms, const mgmt_tx_req_t *req); -esp_err_t esp_wifi_remain_on_channel(uint8_t ifx, uint8_t action, uint8_t channel, - uint32_t wait_time_ms, void *ctx); +esp_err_t esp_wifi_action_tx_req(uint8_t type, uint8_t channel, + uint32_t wait_time_ms, const wifi_action_tx_req_t *req); +esp_err_t esp_wifi_remain_on_channel(uint8_t ifx, uint8_t type, uint8_t channel, + uint32_t wait_time_ms, wifi_action_rx_cb_t rx_cb); #endif /* _ESP_WIFI_DRIVER_H_ */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c index 8177c9c1e7..f2fad8643f 100644 --- a/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c @@ -36,7 +36,6 @@ #include "esp_wpa3_i.h" #include "esp_wpa2.h" #include "esp_common_i.h" -#include "esp_dpp_i.h" void wpa_install_key(enum wpa_alg alg, u8 *addr, int key_idx, int set_tx, u8 *seq, size_t seq_len, u8 *key, size_t key_len, int key_entry_valid) @@ -254,7 +253,6 @@ int esp_supplicant_init(void) wpa_cb->wpa_parse_wpa_ie = wpa_parse_wpa_ie_wrapper; wpa_cb->wpa_config_bss = NULL;//wpa_config_bss; wpa_cb->wpa_michael_mic_failure = wpa_michael_mic_failure; - wpa_cb->offchan_rx_mgmt = esp_dpp_rx_mgmt; esp_wifi_register_wpa3_cb(wpa_cb); esp_supplicant_common_init(wpa_cb); diff --git a/components/wpa_supplicant/test/test_offchannel.c b/components/wpa_supplicant/test/test_offchannel.c new file mode 100644 index 0000000000..97e1e8e828 --- /dev/null +++ b/components/wpa_supplicant/test/test_offchannel.c @@ -0,0 +1,245 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "string.h" +#include "esp_system.h" +#include "unity.h" +#include "esp_system.h" +#include "esp_event.h" +#include "esp_wifi_types.h" +#include "utils/common.h" +#include "common/ieee802_11_defs.h" +#include "../src/esp_supplicant/esp_wifi_driver.h" +#include "esp_log.h" +#include "test_utils.h" +#include "freertos/event_groups.h" + +#define WIFI_START_EVENT 0x00000001 +#define WIFI_ROC_DONE_EVENT 0x00000002 +#define WIFI_ACTION_RX_EVENT 0x00000003 +#define WIFI_SCAN_DONE_EVENT 0x00000004 + +#define TEST_LISTEN_CHANNEL 6 + +#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32C3) + +static const char *TAG = "test_offchan"; +esp_netif_t *wifi_netif; +static EventGroupHandle_t wifi_event; + +static void wifi_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + switch (event_id) { + case WIFI_EVENT_STA_START: + ESP_LOGI(TAG, "WIFI Started"); + xEventGroupSetBits(wifi_event, WIFI_START_EVENT); + break; + case WIFI_EVENT_ACTION_TX_STATUS: { + wifi_event_action_tx_status_t *evt = + (wifi_event_action_tx_status_t *)event_data; + + if (evt->status == 0) { + ESP_LOGI(TAG, "Action Tx Successful"); + } + } + break; + case WIFI_EVENT_ROC_DONE: + ESP_LOGI(TAG, "ROC Done"); + xEventGroupSetBits(wifi_event, WIFI_ROC_DONE_EVENT); + break; + case WIFI_EVENT_SCAN_DONE: + ESP_LOGI(TAG, "Scan Done"); + xEventGroupSetBits(wifi_event, WIFI_SCAN_DONE_EVENT); + break; + default: + break; + } + return; +} + +static esp_err_t event_init(void) +{ + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL)); + wifi_netif = esp_netif_create_default_wifi_sta(); + + return ESP_OK; +} + +static void start_wifi_as_sta(void) +{ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + cfg.nvs_enable = false; + + event_init(); + + // can't deinit event loop, need to reset leak check + unity_reset_leak_checks(); + + if (wifi_event == NULL) { + wifi_event = xEventGroupCreate(); + } else { + xEventGroupClearBits(wifi_event, 0x00ffffff); + } + + TEST_ESP_OK(esp_wifi_init(&cfg)); + TEST_ESP_OK(esp_wifi_set_mode(WIFI_MODE_STA)); + TEST_ESP_OK(esp_wifi_start()); + +} + +static void stop_wifi(void) +{ + esp_event_loop_delete_default(); + ESP_LOGI(TAG, "Stop wifi\n"); + TEST_ESP_OK(esp_wifi_stop()); + TEST_ESP_OK(esp_wifi_deinit()); + esp_wifi_clear_default_wifi_driver_and_handlers(wifi_netif); + esp_netif_destroy(wifi_netif); + if (wifi_event) { + vEventGroupDelete(wifi_event); + wifi_event = NULL; + } + vTaskDelay(1000 / portTICK_PERIOD_MS); +} + +int dummy_rx_action(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel) +{ + return ESP_OK; +} + +static const char *frame_data = "This is a test data"; + +void esp_send_action_frame(uint8_t *dest_mac, const uint8_t *buf, uint32_t len, + uint8_t channel, uint32_t wait_time_ms) +{ + wifi_action_tx_req_t *req = os_zalloc(sizeof(*req) + len);; + TEST_ASSERT( req != NULL); + + req->ifx = ESP_IF_WIFI_STA; + memcpy(req->dest_mac, dest_mac, ETH_ALEN); + req->no_ack = false; + req->data_len = len; + req->rx_cb = dummy_rx_action; + memcpy(req->data, buf, req->data_len); + + ESP_LOGI(TAG, "Action Tx - MAC:" MACSTR ", Channel-%d, WaitT-%d", + MAC2STR(dest_mac), channel, wait_time_ms); + + TEST_ESP_OK(esp_wifi_action_tx_req(WIFI_OFFCHAN_TX_REQ, channel, wait_time_ms, req)); + + os_free(req); +} + + +/* Test that foreground Scan doesn't pre-empt ROC & vice versa */ +TEST_CASE("Test scan and ROC simultaneously", "[Offchan]") +{ + wifi_action_rx_cb_t rx_cb = dummy_rx_action; + EventBits_t bits; + + test_case_uses_tcpip(); + start_wifi_as_sta(); + + xEventGroupWaitBits(wifi_event, WIFI_START_EVENT, 1, 0, 5000 / portTICK_RATE_MS); + + TEST_ESP_OK(esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, WIFI_ROC_REQ, TEST_LISTEN_CHANNEL, + 100, rx_cb)); + ESP_ERROR_CHECK(esp_wifi_scan_start(NULL, false)); + bits = xEventGroupWaitBits(wifi_event, WIFI_ROC_DONE_EVENT | WIFI_SCAN_DONE_EVENT, + pdTRUE, pdFALSE, 5000 / portTICK_RATE_MS); + TEST_ASSERT_TRUE(bits == WIFI_ROC_DONE_EVENT); + + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_ERROR_CHECK(esp_wifi_scan_start(NULL, false)); + TEST_ESP_OK(esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, WIFI_ROC_REQ, TEST_LISTEN_CHANNEL, + 100, rx_cb)); + bits = xEventGroupWaitBits(wifi_event, WIFI_ROC_DONE_EVENT | WIFI_SCAN_DONE_EVENT, + pdTRUE, pdFALSE, 5000 / portTICK_RATE_MS); + TEST_ASSERT_TRUE(bits == WIFI_SCAN_DONE_EVENT); + + stop_wifi(); +} + +static void test_wifi_offchan_tx(void) +{ + int i; + char mac_str[19]; + uint8_t mac[6]; + + test_case_uses_tcpip(); + start_wifi_as_sta(); + xEventGroupWaitBits(wifi_event, WIFI_START_EVENT, 1, 0, 5000 / portTICK_RATE_MS); + + unity_wait_for_signal_param("Listener mac", mac_str, 19); + + TEST_ASSERT_TRUE(unity_util_convert_mac_from_string(mac_str, mac)); + + for (i = 0; i < 3; i++) { + esp_send_action_frame(mac, (const uint8_t *)frame_data, strlen(frame_data), + TEST_LISTEN_CHANNEL, 500); + vTaskDelay(500 / portTICK_PERIOD_MS); + } + + stop_wifi(); +} + +static int test_rx_action(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel) +{ + struct ieee80211_hdr *rx_hdr = (struct ieee80211_hdr *)hdr; + + ESP_LOGI(TAG, "Rxd Action Frame from " MACSTR " (Seq-%lu)", MAC2STR(rx_hdr->addr2), + WLAN_GET_SEQ_SEQ(rx_hdr->seq_ctrl)); + + if (!os_memcmp(payload, frame_data, strlen(frame_data))) { + xEventGroupSetBits(wifi_event, WIFI_ACTION_RX_EVENT); + } + + return ESP_OK; +} + +static void test_wifi_roc(void) +{ + wifi_action_rx_cb_t rx_cb = test_rx_action; + char mac_str[19] = {0}; + EventBits_t bits; + uint8_t mac[6]; + + test_case_uses_tcpip(); + start_wifi_as_sta(); + + xEventGroupWaitBits(wifi_event, WIFI_START_EVENT, 1, 0, 5000 / portTICK_RATE_MS); + TEST_ESP_OK(esp_wifi_get_mac(ESP_IF_WIFI_STA, mac)); + sprintf(mac_str, MACSTR, MAC2STR(mac)); + unity_send_signal_param("Listener mac", mac_str); + + TEST_ESP_OK(esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, WIFI_ROC_REQ, TEST_LISTEN_CHANNEL, + 10000, rx_cb)); + bits = xEventGroupWaitBits(wifi_event, WIFI_ROC_DONE_EVENT | WIFI_ACTION_RX_EVENT, + pdTRUE, pdFALSE, portMAX_DELAY); + /* Confirm that Frame has been received successfully */ + if (bits == WIFI_ACTION_RX_EVENT) { + TEST_ESP_OK(esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, WIFI_ROC_CANCEL, 0, 0, NULL)); + vTaskDelay(1000 / portTICK_PERIOD_MS); + stop_wifi(); + } else { + stop_wifi(); + TEST_FAIL(); + } +} + +TEST_CASE_MULTIPLE_DEVICES("test ROC and Offchannel Action Frame Tx", "[Offchan][test_env=UT_T2_1][timeout=90]", test_wifi_roc, test_wifi_offchan_tx); + +#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32C3) diff --git a/examples/common_components/qrcode/CMakeLists.txt b/examples/common_components/qrcode/CMakeLists.txt index 605e33b2d5..fa3bd8e418 100644 --- a/examples/common_components/qrcode/CMakeLists.txt +++ b/examples/common_components/qrcode/CMakeLists.txt @@ -1,5 +1,3 @@ idf_component_register(SRCS "esp_qrcode_main.c" "esp_qrcode_wrapper.c" "qrcodegen.c" - INCLUDE_DIRS "include" - REQUIRES - PRIV_REQUIRES ) - + INCLUDE_DIRS "include" + ) diff --git a/examples/common_components/qrcode/README.md b/examples/common_components/qrcode/README.md new file mode 100644 index 0000000000..16bb27c06b --- /dev/null +++ b/examples/common_components/qrcode/README.md @@ -0,0 +1,9 @@ +# QR Code generator component + +This directory contains a QR code generator component written in C. This component is based on [QR-Code-generator](https://github.com/nayuki/QR-Code-generator). +This component is used as part of the following ESP-IDF examples: +- [DPP Enrollee Example](../../wifi/wifi_easy_connect/dpp-enrollee/). + +To learn more about how to use this component, please check API Documentation from header file [qrcode.h](./include/qrcode.h). + +Please note that this component is not considered to be a part of ESP-IDF stable API. It may change and may be removed in the future releases. diff --git a/examples/common_components/qrcode/component.mk b/examples/common_components/qrcode/component.mk new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/common_components/qrcode/esp_qrcode_main.c b/examples/common_components/qrcode/esp_qrcode_main.c index e6ba3fa03f..7b03d5d4f4 100644 --- a/examples/common_components/qrcode/esp_qrcode_main.c +++ b/examples/common_components/qrcode/esp_qrcode_main.c @@ -1,4 +1,4 @@ -// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,10 +14,13 @@ #include #include +#include "esp_log.h" #include "qrcodegen.h" #include "qrcode.h" +static const char *TAG = "QRCODE"; + static const char *lt[] = { /* 0 */ " ", /* 1 */ "\u2580 ", @@ -67,13 +70,14 @@ void esp_qrcode_print_console(esp_qrcode_handle_t qrcode) esp_err_t esp_qrcode_generate(esp_qrcode_config_t *cfg, const char *text) { - enum qrcodegen_Ecc ecc_lvl; + enum qrcodegen_Ecc ecc_lvl; uint8_t *qrcode, *tempbuf; esp_err_t err = ESP_FAIL; qrcode = calloc(1, qrcodegen_BUFFER_LEN_FOR_VERSION(cfg->max_qrcode_version)); - if (!qrcode) + if (!qrcode) { return ESP_ERR_NO_MEM; + } tempbuf = calloc(1, qrcodegen_BUFFER_LEN_FOR_VERSION(cfg->max_qrcode_version)); if (!tempbuf) { @@ -99,12 +103,15 @@ esp_err_t esp_qrcode_generate(esp_qrcode_config_t *cfg, const char *text) break; } - // Make and print the QR Code symbol - bool ok = qrcodegen_encodeText(text, tempbuf, qrcode, ecc_lvl, - qrcodegen_VERSION_MIN, cfg->max_qrcode_version, + ESP_LOGI(TAG, "Encoding below text with ECC LVL %d & QR Code Version %d", + ecc_lvl, cfg->max_qrcode_version); + ESP_LOGI(TAG, "%s", text); + // Make and print the QR Code symbol + bool ok = qrcodegen_encodeText(text, tempbuf, qrcode, ecc_lvl, + qrcodegen_VERSION_MIN, cfg->max_qrcode_version, qrcodegen_Mask_AUTO, true); - if (ok && cfg->display_func) { - cfg->display_func((esp_qrcode_handle_t)qrcode); + if (ok && cfg->display_func) { + cfg->display_func((esp_qrcode_handle_t)qrcode); err = ESP_OK; } diff --git a/examples/common_components/qrcode/esp_qrcode_wrapper.c b/examples/common_components/qrcode/esp_qrcode_wrapper.c index 3b44421333..cde516586b 100644 --- a/examples/common_components/qrcode/esp_qrcode_wrapper.c +++ b/examples/common_components/qrcode/esp_qrcode_wrapper.c @@ -1,4 +1,4 @@ -// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/examples/common_components/qrcode/include/qrcode.h b/examples/common_components/qrcode/include/qrcode.h index 651a2baca2..75002c3e0e 100644 --- a/examples/common_components/qrcode/include/qrcode.h +++ b/examples/common_components/qrcode/include/qrcode.h @@ -1,4 +1,4 @@ -// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -95,9 +95,9 @@ bool esp_qrcode_get_module(esp_qrcode_handle_t qrcode, int x, int y); #define ESP_QRCODE_CONFIG_DEFAULT() (esp_qrcode_config_t) { \ .display_func = esp_qrcode_print_console, \ - .qrcode_ecc_level = ESP_QRCODE_ECC_LOW, \ .max_qrcode_version = 10, \ -} \ + .qrcode_ecc_level = ESP_QRCODE_ECC_LOW, \ +} #ifdef __cplusplus } diff --git a/examples/wifi/wifi_easy_connect/dpp-enrollee/CMakeLists.txt b/examples/wifi/wifi_easy_connect/dpp-enrollee/CMakeLists.txt new file mode 100644 index 0000000000..2d4a908a8e --- /dev/null +++ b/examples/wifi/wifi_easy_connect/dpp-enrollee/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/qrcode) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(dpp-enrollee) diff --git a/examples/wifi/wifi_easy_connect/dpp-enrollee/Makefile b/examples/wifi/wifi_easy_connect/dpp-enrollee/Makefile new file mode 100644 index 0000000000..681e7b2b48 --- /dev/null +++ b/examples/wifi/wifi_easy_connect/dpp-enrollee/Makefile @@ -0,0 +1,10 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := dpp-enrollee + +EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/qrcode + +include $(IDF_PATH)/make/project.mk diff --git a/examples/wifi/wifi_easy_connect/dpp-enrollee/README.md b/examples/wifi/wifi_easy_connect/dpp-enrollee/README.md new file mode 100644 index 0000000000..03ced1a144 --- /dev/null +++ b/examples/wifi/wifi_easy_connect/dpp-enrollee/README.md @@ -0,0 +1,66 @@ +# Device Provisioning Protocol (Enrollee) Example + +This example shows how to configure ESP32 as an enrollee using Device Provisioning Protocol(DPP) also known as Wi-Fi Easy Connect. + +DPP provides a simple and secure way to onboard ESP32 to a network. +We now support Responder-Enrollee mode of DPP with PSK mode of authentication. + +You need a Wi-Fi Easy Connect with Initiator mode capable device to make use of this example. Some Android 10+ devices have this capability. (Vendor specific) + +To run the example with an Android 10+ device follow below steps - +1. Compile and flash the example on ESP32, a QR code will appear on your console. +2. Connect your phone to the network, say named "Example-AP". +3. Now go to Settings->WiFi & Internet->Wi-Fi->Example-AP->Advanced->Add Device. +4. Scan QR Code using the scanner, which will make ESP32 connect to Example-AP. + +Optional configuration available + +*Note:* +- QR Code should be displayed as dark on a white/light background to work properly. +- If displayed QR Code had line gaps, try switching to a new font or a diiferent Terminal program. See below QR Code for for checking beforehand. + +### Example output + +Here is an example of the console output. +``` +I (807) wifi:mode : sta (24:0a:c4:23:da:20) +I (807) wifi dpp-enrollee: Started listening on Channel 11 for DPP Authentication +I (1157) wifi dpp-enrollee: Scan below QR Code to configure the enrollee: + + + █▀▀▀▀▀█ ██▄▄▄█▄▀██▄▄█▄ ▀ ▀▄ █▄▄ █▀▀▀▀▀█ + █ ███ █ ██▀█▀ ▀▀██▀█▄█▀▄▀ ██▀▀█ ▄ █ ███ █ + █ ▀▀▀ █ ▄█▀▄▄ ▄▄▀ █▄▀ ▄ ▄ ▄▀▄ ██ █ ▀▀▀ █ + ▀▀▀▀▀▀▀ ▀ █▄▀ ▀ ▀▄▀▄▀▄▀ █ ▀ ▀▄█ ▀ ▀▀▀▀▀▀▀ + █▀ ▄██▀ ▄█ ▀█ ▄▀▄▄▄ ▀▀█▄ ▄▀█▄█▀▀▄▄▄▀▄██▀█ + █▄▀ ▄ ▀▄█▄ ▀▀█▀▀█ ▀▄ ▄█▀▀▀▀█▀▄▄▄ ██▄ ▄█ + ▀█▀█▀ ▀▀ ▀ ▄▀▄▀▀ ▄ ▄▀▀▀ █▄ ▄▄ ▀█▄▀▄ █ + ▀ ▀ ▀▀▀█▄ █▀▀ █▄▄▄ █▄ █▄▀ ██▄ ▄▄▀█▄▀ ▄█ + ▀██▀▄█▀▄ ▄█ ▀▄▀ █ ▄ ▄█▄▀▄▀▄▄▀▄ ▄▄▄▀▄▄ + ▀▀▄█▀█▄▀▀█▄ ▄▀ █▄ ▀█▄█▄▀ ▀█▄▄ ▄▀▄ █▄▀ █ + ▄▀▀ ▀█▀▀▀ ▄ ▀█▀▀▄ ▀ ▄▄█▄ █ ██▀▄▀▀▄▄▄▄█▀▄ + ▀ ███▀▀▄ ▄ ▄ ▀█▄▄▀█▀▀▀ ▀▀▄▄ ▀ █▄ ▄█ + █ ▀▄▄ ▀▀▀▀▄▀▀▀▄█▄▄ ▄▀▄▀ ▀▄▀▄▀█▀▀▄▀ ▄█▄▀ + ███ ▄▀▄▀▀▄▀▀█▀▀▄ ▀▄ ████ █▀▄█▄▄ ▀█▄ ▀▀ ▀ + ▄▀█▀▀▀▀█▀ ▄█▄▀▀ ▄ ▀█▀▀ ▀ ▄▀▀ ▀▄█ ▄ ▀ + █ ▀▀▀▄██▄█▀ ▀█▄█▄ ▀██▀▄▀▄▀ █▀ ▀ ▄▄▀█ ▄█ + ▀▀▀ ▀▀▀▀▄▄█▄▀█▄ ▄ ▄ ▀▀▀█▄▄▀▀▀ █▀▀▀██▀▀▄ + █▀▀▀▀▀█ ▄▄▀█▀ ▄█▄█▄▄█▄ ▀ ▀▀▀█▄ ▀█ ▀ █ ▀ █ + █ ███ █ ▀█▀ ▀█▀▀▄▄▀ ▀▄█▀▀ ██▀█▀▀▀█▀▄▄▄█ + █ ▀▀▀ █ ▄▀█ ▄ ▄ ▀█▄ ▀▄▀█ ▀▄██▄ ▀ ▄█ ▄▀▄█ + ▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀ ▀▀▀▀▀ ▀ ▀ ▀ + +I (6357) wifi dpp-enrollee: DPP Authentication successful, connecting to AP : DigitalFortress +I (6477) wifi:new:<1,0>, old:<1,0>, ap:<255,255>, sta:<1,0>, prof:1 +I (7277) wifi:state: init -> auth (b0) +I (7277) wifi:state: auth -> assoc (0) +I (7287) wifi:state: assoc -> run (10) +I (7317) wifi:connected with DigitalFortress, aid = 4, channel 1, BW20, bssid = 04:d4:c4:5e:22:f0 +I (7317) wifi:security type: 3, phy: bgn, rssi: -60 +I (7427) wifi:pm start, type: 1 + +I (7427) wifi:AP's beacon interval = 102400 us, DTIM period = 1 +I (11617) esp_netif_handlers: sta ip: 192.168.1.216, mask: 255.255.255.0, gw: 192.168.1.1 +I (11617) wifi dpp-enrollee: got ip:192.168.1.216 +I (11617) wifi dpp-enrollee: connected to ap SSID:DigitalFortress password:password +``` diff --git a/examples/wifi/wifi_easy_connect/dpp-enrollee/main/CMakeLists.txt b/examples/wifi/wifi_easy_connect/dpp-enrollee/main/CMakeLists.txt new file mode 100644 index 0000000000..97a762af08 --- /dev/null +++ b/examples/wifi/wifi_easy_connect/dpp-enrollee/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "dpp_enrollee_main.c" + INCLUDE_DIRS ".") diff --git a/examples/wifi/wifi_easy_connect/dpp-enrollee/main/Kconfig.projbuild b/examples/wifi/wifi_easy_connect/dpp-enrollee/main/Kconfig.projbuild new file mode 100644 index 0000000000..307533583f --- /dev/null +++ b/examples/wifi/wifi_easy_connect/dpp-enrollee/main/Kconfig.projbuild @@ -0,0 +1,17 @@ +menu "Example Configuration" + config ESP_DPP_LISTEN_CHANNEL_LIST + string "DPP Listen channel list" + default "6" + help + DPP Bootstrapping listen channels separated by commas. + + config ESP_DPP_BOOTSTRAPPING_KEY + string "Bootstrapping key" + help + Private key string for DPP Bootstrapping in PEM format. + + config ESP_DPP_DEVICE_INFO + string "Additional Device Info" + help + Additional ancillary information to be included in QR Code. +endmenu diff --git a/examples/wifi/wifi_easy_connect/dpp-enrollee/main/component.mk b/examples/wifi/wifi_easy_connect/dpp-enrollee/main/component.mk new file mode 100644 index 0000000000..0adf45649a --- /dev/null +++ b/examples/wifi/wifi_easy_connect/dpp-enrollee/main/component.mk @@ -0,0 +1,8 @@ +# +# Main component makefile. +# +# This Makefile can be left empty. By default, it will take the sources in the +# src/ directory, compile them and link them into lib(subdirectory_name).a +# in the build directory. This behaviour is entirely configurable, +# please read the ESP-IDF documents if you need to do this. +# diff --git a/examples/wifi/wifi_easy_connect/dpp-enrollee/main/dpp_enrollee_main.c b/examples/wifi/wifi_easy_connect/dpp-enrollee/main/dpp_enrollee_main.c new file mode 100644 index 0000000000..ae9f99d73c --- /dev/null +++ b/examples/wifi/wifi_easy_connect/dpp-enrollee/main/dpp_enrollee_main.c @@ -0,0 +1,169 @@ +/* DPP Enrollee Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_dpp.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "qrcode.h" + +#ifdef CONFIG_ESP_DPP_LISTEN_CHANNEL +#define EXAMPLE_DPP_LISTEN_CHANNEL_LIST CONFIG_ESP_DPP_LISTEN_CHANNEL_LIST +#else +#define EXAMPLE_DPP_LISTEN_CHANNEL_LIST "6" +#endif + +#ifdef CONFIG_ESP_DPP_BOOTSTRAPPING_KEY +#define EXAMPLE_DPP_BOOTSTRAPPING_KEY CONFIG_ESP_DPP_BOOTSTRAPPING_KEY +#else +#define EXAMPLE_DPP_BOOTSTRAPPING_KEY 0 +#endif + +#ifdef CONFIG_ESP_DPP_DEVICE_INFO +#define EXAMPLE_DPP_DEVICE_INFO CONFIG_ESP_DPP_DEVICE_INFO +#else +#define EXAMPLE_DPP_DEVICE_INFO 0 +#endif + +static const char *TAG = "wifi dpp-enrollee"; +wifi_config_t s_dpp_wifi_config; + +static int s_retry_num = 0; + +/* FreeRTOS event group to signal when we are connected*/ +static EventGroupHandle_t s_dpp_event_group; + +#define DPP_CONNECTED_BIT BIT0 +#define DPP_CONNECT_FAIL_BIT BIT1 +#define DPP_AUTH_FAIL_BIT BIT2 + +static void event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + ESP_ERROR_CHECK(esp_supp_dpp_start_listen()); + ESP_LOGI(TAG, "Started listening for DPP Authentication"); + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { + if (s_retry_num < 5) { + esp_wifi_connect(); + s_retry_num++; + ESP_LOGI(TAG, "retry to connect to the AP"); + } else { + xEventGroupSetBits(s_dpp_event_group, DPP_CONNECT_FAIL_BIT); + } + ESP_LOGI(TAG, "connect to the AP fail"); + } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; + ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); + s_retry_num = 0; + xEventGroupSetBits(s_dpp_event_group, DPP_CONNECTED_BIT); + } +} + +void dpp_enrollee_event_cb(esp_supp_dpp_event_t event, void *data) +{ + switch (event) { + case ESP_SUPP_DPP_URI_READY: + if (data != NULL) { + esp_qrcode_config_t cfg = ESP_QRCODE_CONFIG_DEFAULT(); + + ESP_LOGI(TAG, "Scan below QR Code to configure the enrollee:\n"); + esp_qrcode_generate(&cfg, (const char *)data); + } + break; + case ESP_SUPP_DPP_CFG_RECVD: + memcpy(&s_dpp_wifi_config, data, sizeof(s_dpp_wifi_config)); + esp_wifi_set_config(ESP_IF_WIFI_STA, &s_dpp_wifi_config); + ESP_LOGI(TAG, "DPP Authentication successful, connecting to AP : %s", + s_dpp_wifi_config.sta.ssid); + s_retry_num = 0; + esp_wifi_connect(); + break; + case ESP_SUPP_DPP_FAIL: + if (s_retry_num < 5) { + ESP_LOGI(TAG, "DPP Auth failed (Reason: %s), retry...", esp_err_to_name((int)data)); + ESP_ERROR_CHECK(esp_supp_dpp_start_listen()); + s_retry_num++; + } else { + xEventGroupSetBits(s_dpp_event_group, DPP_AUTH_FAIL_BIT); + } + break; + default: + break; + } +} + +void dpp_enrollee_init(void) +{ + s_dpp_event_group = xEventGroupCreate(); + + ESP_ERROR_CHECK(esp_netif_init()); + + ESP_ERROR_CHECK(esp_event_loop_create_default()); + esp_netif_create_default_wifi_sta(); + + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL)); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + ESP_ERROR_CHECK(esp_supp_dpp_init(dpp_enrollee_event_cb)); + /* Currently only supported method is QR Code */ + ESP_ERROR_CHECK(esp_supp_dpp_bootstrap_gen(EXAMPLE_DPP_LISTEN_CHANNEL_LIST, DPP_BOOTSTRAP_QR_CODE, + EXAMPLE_DPP_BOOTSTRAPPING_KEY, EXAMPLE_DPP_DEVICE_INFO)); + + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_start()); + + /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum + * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ + EventBits_t bits = xEventGroupWaitBits(s_dpp_event_group, + DPP_CONNECTED_BIT | DPP_CONNECT_FAIL_BIT | DPP_AUTH_FAIL_BIT, + pdFALSE, + pdFALSE, + portMAX_DELAY); + + /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually + * happened. */ + if (bits & DPP_CONNECTED_BIT) { + ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", + s_dpp_wifi_config.sta.ssid, s_dpp_wifi_config.sta.password); + } else if (bits & DPP_CONNECT_FAIL_BIT) { + ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", + s_dpp_wifi_config.sta.ssid, s_dpp_wifi_config.sta.password); + } else if (bits & DPP_AUTH_FAIL_BIT) { + ESP_LOGI(TAG, "DPP Authentication failed after %d retries", s_retry_num); + } else { + ESP_LOGE(TAG, "UNEXPECTED EVENT"); + } + + esp_supp_dpp_deinit(); + ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler)); + ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler)); + vEventGroupDelete(s_dpp_event_group); +} + +void app_main(void) +{ + //Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + dpp_enrollee_init(); +}