Add DPP Enrollee example

1. Add Example for DPP Enrollee
2. Use DPP Supplicant API's to setup connection
3. Add support for multiple channels in Bootstrapping
4. Add Unity testcase for testing Offchannel operations

Closes https://github.com/espressif/esp-idf/issues/5654
This commit is contained in:
Nachiket Kukade 2020-10-27 18:23:19 +05:30
parent 87205dc2f4
commit 76b2cb28d2
23 changed files with 882 additions and 194 deletions

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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
}

View File

@ -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:

View File

@ -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);

View File

@ -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 */

View File

@ -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_ */

View File

@ -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);

View File

@ -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)

View File

@ -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"
)

View File

@ -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.

View File

@ -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 <stdio.h>
#include <esp_err.h>
#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;
}

View File

@ -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.

View File

@ -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
}

View File

@ -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)

View File

@ -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

View File

@ -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
```

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "dpp_enrollee_main.c"
INCLUDE_DIRS ".")

View File

@ -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

View File

@ -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.
#

View File

@ -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 <string.h>
#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();
}