mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-30 18:57:19 +02:00
Merge branch 'feature/add_dpp_support' into 'master'
Add dpp support Closes WIFI-1054 and WIFI-2627 See merge request espressif/esp-idf!8167
This commit is contained in:
@ -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
|
||||
@ -407,6 +410,16 @@ static const esp_err_msg_t esp_err_msg_table[] = {
|
||||
# endif
|
||||
# ifdef ESP_ERR_ESPNOW_IF
|
||||
ERR_TBL_IT(ESP_ERR_ESPNOW_IF), /* 12396 0x306c Interface error */
|
||||
# endif
|
||||
// components/wpa_supplicant/include/esp_supplicant/esp_dpp.h
|
||||
# ifdef ESP_ERR_DPP_FAILURE
|
||||
ERR_TBL_IT(ESP_ERR_DPP_FAILURE), /* 12439 0x3097 Generic failure during DPP Operation */
|
||||
# endif
|
||||
# ifdef ESP_ERR_DPP_TX_FAILURE
|
||||
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), /* 12441 0x3099 Encountered invalid DPP Attribute */
|
||||
# endif
|
||||
// components/esp_common/include/esp_err.h
|
||||
# ifdef ESP_ERR_MESH_BASE
|
||||
|
@ -85,6 +85,12 @@ static system_event_id_t esp_event_legacy_wifi_event_id(int32_t event_id)
|
||||
case WIFI_EVENT_AP_PROBEREQRECVED:
|
||||
return SYSTEM_EVENT_AP_PROBEREQRECVED;
|
||||
|
||||
case WIFI_EVENT_ACTION_TX_STATUS:
|
||||
return SYSTEM_EVENT_ACTION_TX_STATUS;
|
||||
|
||||
case WIFI_EVENT_ROC_DONE:
|
||||
return SYSTEM_EVENT_ROC_DONE;
|
||||
|
||||
default:
|
||||
ESP_LOGE(TAG, "invalid wifi event id %d", event_id);
|
||||
return SYSTEM_EVENT_MAX;
|
||||
|
@ -48,6 +48,8 @@ typedef enum {
|
||||
SYSTEM_EVENT_AP_STADISCONNECTED, /*!< a station disconnected from ESP32 soft-AP */
|
||||
SYSTEM_EVENT_AP_STAIPASSIGNED, /*!< ESP32 soft-AP assign an IP to a connected station */
|
||||
SYSTEM_EVENT_AP_PROBEREQRECVED, /*!< Receive probe request packet in soft-AP interface */
|
||||
SYSTEM_EVENT_ACTION_TX_STATUS, /*!< Receive status of Action frame transmitted */
|
||||
SYSTEM_EVENT_ROC_DONE, /*!< Indicates the completion of Remain-on-Channel operation status */
|
||||
SYSTEM_EVENT_GOT_IP6, /*!< ESP32 station or ap or ethernet interface v6IP addr is preferred */
|
||||
SYSTEM_EVENT_ETH_START, /*!< ESP32 ethernet start */
|
||||
SYSTEM_EVENT_ETH_STOP, /*!< ESP32 ethernet stop */
|
||||
|
@ -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 */
|
||||
@ -483,6 +489,32 @@ typedef struct {
|
||||
enabled_ant1: 4; /**< Index (in antenna GPIO configuration) of enabled WIFI_ANT_MODE_ANT1 */
|
||||
} wifi_ant_config_t;
|
||||
|
||||
/**
|
||||
* @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 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
|
||||
*
|
||||
@ -551,6 +583,8 @@ typedef enum {
|
||||
|
||||
/* Add next events after this only */
|
||||
WIFI_EVENT_STA_BSS_RSSI_LOW, /**< AP's RSSI crossed configured threshold */
|
||||
WIFI_EVENT_ACTION_TX_STATUS, /**< Status indication of Action Tx operation */
|
||||
WIFI_EVENT_ROC_DONE, /**< Remain-on-Channel operation complete */
|
||||
|
||||
WIFI_EVENT_MAX, /**< Invalid WiFi event ID */
|
||||
} wifi_event_t;
|
||||
@ -645,6 +679,19 @@ typedef struct {
|
||||
#define WIFI_STATIS_PS (1<<4)
|
||||
#define WIFI_STATIS_ALL (-1)
|
||||
|
||||
/** Argument structure for WIFI_EVENT_ACTION_TX_STATUS event */
|
||||
typedef struct {
|
||||
wifi_interface_t ifx; /**< WiFi interface to send request to */
|
||||
uint32_t context; /**< Context to identify the request */
|
||||
uint8_t da[6]; /**< Destination MAC address */
|
||||
uint8_t status; /**< Status of the operation */
|
||||
} wifi_event_action_tx_status_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_ROC_DONE event */
|
||||
typedef struct {
|
||||
uint32_t context; /**< Context to identify the request */
|
||||
} wifi_event_roc_done_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Submodule components/esp_wifi/lib updated: 21001cb8ac...bad7d9df47
@ -18,7 +18,7 @@ set(srcs "port/os_xtensa.c"
|
||||
"src/crypto/aes-omac1.c"
|
||||
"src/crypto/aes-unwrap.c"
|
||||
"src/crypto/aes-wrap.c"
|
||||
"src/crypto/aes-omac1.c"
|
||||
"src/crypto/sha256-tlsprf.c"
|
||||
"src/crypto/bignum.c"
|
||||
"src/crypto/ccmp.c"
|
||||
"src/crypto/crypto_mbedtls.c"
|
||||
@ -63,6 +63,7 @@ set(srcs "port/os_xtensa.c"
|
||||
"src/esp_supplicant/esp_wpas_glue.c"
|
||||
"src/esp_supplicant/esp_wps.c"
|
||||
"src/esp_supplicant/esp_wpa3.c"
|
||||
"src/esp_supplicant/esp_dpp.c"
|
||||
"src/rsn_supp/pmksa_cache.c"
|
||||
"src/rsn_supp/wpa.c"
|
||||
"src/rsn_supp/wpa_ie.c"
|
||||
|
116
components/wpa_supplicant/include/esp_supplicant/esp_dpp.h
Normal file
116
components/wpa_supplicant/include/esp_supplicant/esp_dpp.h
Normal file
@ -0,0 +1,116 @@
|
||||
// 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.
|
||||
|
||||
#ifndef ESP_DPP_H
|
||||
#define ESP_DPP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#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 */
|
||||
|
||||
/** @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 {
|
||||
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;
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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
|
||||
}
|
||||
#endif
|
||||
#endif /* ESP_DPP_H */
|
@ -2397,7 +2397,7 @@ struct dpp_authentication *
|
||||
dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
|
||||
struct dpp_bootstrap_info *peer_bi,
|
||||
struct dpp_bootstrap_info *own_bi,
|
||||
unsigned int freq, const u8 *hdr, const u8 *attr_start,
|
||||
unsigned int curr_chan, const u8 *hdr, const u8 *attr_start,
|
||||
size_t attr_len)
|
||||
{
|
||||
struct crypto_key *pi = NULL;
|
||||
@ -2406,10 +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,
|
||||
*channel;
|
||||
u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len,
|
||||
i_bootstrap_len, channel_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
|
||||
@ -2438,10 +2444,11 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
|
||||
auth->peer_bi = peer_bi;
|
||||
auth->own_bi = own_bi;
|
||||
auth->curve = own_bi->curve;
|
||||
auth->curr_freq = freq;
|
||||
auth->curr_chan = curr_chan;
|
||||
|
||||
auth->peer_version = 1; /* default to the first version */
|
||||
|
||||
#if 0
|
||||
channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
|
||||
&channel_len);
|
||||
if (channel) {
|
||||
@ -2452,7 +2459,6 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifndef ESP_SUPPLICANT
|
||||
neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
|
||||
@ -2469,10 +2475,10 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
|
||||
freq, neg_freq);
|
||||
auth->curr_freq = neg_freq;
|
||||
}
|
||||
#endif
|
||||
/* rename it to chan */
|
||||
auth->curr_freq = *channel;
|
||||
auth->curr_chan = *channel;
|
||||
}
|
||||
#endif
|
||||
|
||||
i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
|
||||
&i_proto_len);
|
||||
@ -5386,7 +5392,7 @@ fail:
|
||||
|
||||
|
||||
int dpp_conf_resp_rx(struct dpp_authentication *auth,
|
||||
const struct wpabuf *resp)
|
||||
const uint8_t *resp, uint32_t resp_len)
|
||||
{
|
||||
const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
|
||||
u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
|
||||
@ -5398,12 +5404,12 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth,
|
||||
|
||||
auth->conf_resp_status = 255;
|
||||
|
||||
if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
|
||||
if (dpp_check_attrs(resp, resp_len) < 0) {
|
||||
dpp_auth_fail(auth, "Invalid attribute in config response");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
|
||||
wrapped_data = dpp_get_attr(resp, resp_len,
|
||||
DPP_ATTR_WRAPPED_DATA,
|
||||
&wrapped_data_len);
|
||||
if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
|
||||
@ -5419,8 +5425,8 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth,
|
||||
if (!unwrapped)
|
||||
return -1;
|
||||
|
||||
addr[0] = wpabuf_head(resp);
|
||||
len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
|
||||
addr[0] = resp;
|
||||
len[0] = wrapped_data - 4 - resp;
|
||||
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
|
||||
|
||||
if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
|
||||
@ -5451,7 +5457,7 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
|
||||
status = dpp_get_attr(resp, resp_len,
|
||||
DPP_ATTR_STATUS, &status_len);
|
||||
if (!status || status_len < 1) {
|
||||
dpp_auth_fail(auth,
|
||||
@ -6083,9 +6089,6 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
|
||||
int ret = -1;
|
||||
struct dpp_bootstrap_info *bi;
|
||||
|
||||
if (!dpp)
|
||||
return -1;
|
||||
|
||||
bi = os_zalloc(sizeof(*bi));
|
||||
if (!bi)
|
||||
goto fail;
|
||||
@ -6143,6 +6146,7 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
|
||||
mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
|
||||
info ? "I:" : "", info ? info : "", info ? ";" : "",
|
||||
pk);
|
||||
|
||||
bi->id = dpp_next_id(dpp);
|
||||
dl_list_add(&dpp->bootstrap, &bi->list);
|
||||
ret = bi->id;
|
||||
|
@ -13,8 +13,11 @@
|
||||
#ifdef CONFIG_DPP
|
||||
|
||||
#include "utils/list.h"
|
||||
#include "common/wpa_common.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_dpp.h"
|
||||
|
||||
struct crypto_ecdh;
|
||||
struct hostapd_ip_addr;
|
||||
@ -147,12 +150,6 @@ struct dpp_curve_params {
|
||||
const char *jws_alg;
|
||||
};
|
||||
|
||||
enum dpp_bootstrap_type {
|
||||
DPP_BOOTSTRAP_QR_CODE,
|
||||
DPP_BOOTSTRAP_PKEX,
|
||||
DPP_BOOTSTRAP_NFC_URI,
|
||||
};
|
||||
|
||||
struct dpp_bootstrap_info {
|
||||
struct dl_list list;
|
||||
unsigned int id;
|
||||
@ -258,6 +255,7 @@ struct dpp_authentication {
|
||||
* Authentication exchange */
|
||||
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
|
||||
unsigned int num_freq, freq_idx;
|
||||
unsigned int curr_chan;
|
||||
unsigned int curr_freq;
|
||||
unsigned int neg_freq;
|
||||
unsigned int num_freq_iters;
|
||||
@ -488,8 +486,8 @@ void dpp_auth_deinit(struct dpp_authentication *auth);
|
||||
struct wpabuf *
|
||||
dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
|
||||
size_t attr_len);
|
||||
int dpp_conf_resp_rx(struct dpp_authentication *auth,
|
||||
const struct wpabuf *resp);
|
||||
int dpp_conf_resp_rx(struct dpp_authentication *auth, const u8 *resp,
|
||||
u32 resp_len);
|
||||
enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
|
||||
const u8 *hdr,
|
||||
const u8 *attr_start, size_t attr_len);
|
||||
|
@ -263,6 +263,13 @@
|
||||
#define WLAN_ACTION_UNPROTECTED_WNM 11
|
||||
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
|
||||
|
||||
/* Public action codes (IEEE Std 802.11-2016, 9.6.8.1, Table 9-307) */
|
||||
#define WLAN_PA_VENDOR_SPECIFIC 9
|
||||
#define WLAN_PA_GAS_INITIAL_REQ 10
|
||||
#define WLAN_PA_GAS_INITIAL_RESP 11
|
||||
#define WLAN_PA_GAS_COMEBACK_REQ 12
|
||||
#define WLAN_PA_GAS_COMEBACK_RESP 13
|
||||
|
||||
/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
|
||||
#define WLAN_SA_QUERY_REQUEST 0
|
||||
#define WLAN_SA_QUERY_RESPONSE 1
|
||||
@ -274,6 +281,8 @@
|
||||
#define WLAN_TIMEOUT_KEY_LIFETIME 2
|
||||
#define WLAN_TIMEOUT_ASSOC_COMEBACK 3
|
||||
|
||||
#define OUI_WFA 0x506f9a
|
||||
#define DPP_OUI_TYPE 0x1A
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
@ -343,110 +352,37 @@ enum lci_req_subelem {
|
||||
LCI_REQ_SUBELEM_MAX_AGE = 4,
|
||||
};
|
||||
|
||||
struct ieee80211_mgmt {
|
||||
le16 frame_control;
|
||||
le16 duration;
|
||||
u8 da[6];
|
||||
u8 sa[6];
|
||||
u8 bssid[6];
|
||||
le16 seq_ctrl;
|
||||
union {
|
||||
struct {
|
||||
le16 auth_alg;
|
||||
le16 auth_transaction;
|
||||
le16 status_code;
|
||||
/* possibly followed by Challenge text */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED auth;
|
||||
struct {
|
||||
le16 reason_code;
|
||||
} STRUCT_PACKED deauth;
|
||||
struct {
|
||||
le16 capab_info;
|
||||
le16 listen_interval;
|
||||
/* followed by SSID and Supported rates */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED assoc_req;
|
||||
struct {
|
||||
le16 capab_info;
|
||||
le16 status_code;
|
||||
le16 aid;
|
||||
/* followed by Supported rates */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED assoc_resp, reassoc_resp;
|
||||
struct {
|
||||
le16 capab_info;
|
||||
le16 listen_interval;
|
||||
u8 current_ap[6];
|
||||
/* followed by SSID and Supported rates */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED reassoc_req;
|
||||
struct {
|
||||
le16 reason_code;
|
||||
} STRUCT_PACKED disassoc;
|
||||
struct {
|
||||
u8 timestamp[8];
|
||||
le16 beacon_int;
|
||||
le16 capab_info;
|
||||
/* followed by some of SSID, Supported rates,
|
||||
* FH Params, DS Params, CF Params, IBSS Params, TIM */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED beacon;
|
||||
struct {
|
||||
/* only variable items: SSID, Supported rates */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED probe_req;
|
||||
struct {
|
||||
u8 timestamp[8];
|
||||
le16 beacon_int;
|
||||
le16 capab_info;
|
||||
/* followed by some of SSID, Supported rates,
|
||||
* FH Params, DS Params, CF Params, IBSS Params */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED probe_resp;
|
||||
struct {
|
||||
u8 category;
|
||||
union {
|
||||
struct {
|
||||
u8 action_code;
|
||||
u8 dialog_token;
|
||||
u8 status_code;
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED wmm_action;
|
||||
struct{
|
||||
u8 action_code;
|
||||
u8 element_id;
|
||||
u8 length;
|
||||
u8 switch_mode;
|
||||
u8 new_chan;
|
||||
u8 switch_count;
|
||||
} STRUCT_PACKED chan_switch;
|
||||
struct {
|
||||
u8 action;
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
u8 target_ap_addr[ETH_ALEN];
|
||||
u8 variable[0]; /* FT Request */
|
||||
} STRUCT_PACKED ft_action_req;
|
||||
struct {
|
||||
u8 action;
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
u8 target_ap_addr[ETH_ALEN];
|
||||
le16 status_code;
|
||||
u8 variable[0]; /* FT Request */
|
||||
} STRUCT_PACKED ft_action_resp;
|
||||
struct {
|
||||
u8 action;
|
||||
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
|
||||
} STRUCT_PACKED sa_query_req;
|
||||
struct {
|
||||
u8 action; /* */
|
||||
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
|
||||
} STRUCT_PACKED sa_query_resp;
|
||||
} u;
|
||||
} STRUCT_PACKED action;
|
||||
} u;
|
||||
#ifdef ESP_SUPPLICANT
|
||||
struct ieee80211_pa_vendor {
|
||||
u8 oui[3];
|
||||
u8 wfa_stype;
|
||||
u8 vendor_data[];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
struct ieee80211_gas_resp {
|
||||
u8 diag_token;
|
||||
u16 status_code;
|
||||
u16 comeback_delay;
|
||||
u8 type;
|
||||
u8 length;
|
||||
u8 data[];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
struct ieee80211_public_action {
|
||||
u8 action;
|
||||
union {
|
||||
struct ieee80211_pa_vendor pa_vendor_spec;
|
||||
struct ieee80211_gas_resp pa_gas_resp;
|
||||
} v;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
struct ieee80211_action {
|
||||
u8 category;
|
||||
union {
|
||||
struct ieee80211_public_action public_action;
|
||||
} u;
|
||||
} STRUCT_PACKED;
|
||||
#endif /* ESP_SUPPLICANT */
|
||||
|
||||
#define IEEE80211_MAX_MMPDU_SIZE 2304
|
||||
struct ieee80211_ht_capabilities {
|
||||
|
648
components/wpa_supplicant/src/esp_supplicant/esp_dpp.c
Normal file
648
components/wpa_supplicant/src/esp_supplicant/esp_dpp.c
Normal file
@ -0,0 +1,648 @@
|
||||
// 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_stop_listening;
|
||||
static int s_dpp_auth_retries;
|
||||
struct esp_dpp_context_t s_dpp_ctx;
|
||||
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)
|
||||
|
||||
struct action_rx_param {
|
||||
u8 sa[ETH_ALEN];
|
||||
u32 channel;
|
||||
u32 frm_len;
|
||||
u32 vendor_data_len;
|
||||
struct ieee80211_action *action_frm;
|
||||
};
|
||||
|
||||
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_NO_MEM;
|
||||
}
|
||||
evt->id = evt_id;
|
||||
evt->data = data;
|
||||
if ( xQueueSend(s_dpp_evt_queue, &evt, 10 / portTICK_PERIOD_MS ) != pdPASS) {
|
||||
DPP_API_UNLOCK();
|
||||
os_free(evt);
|
||||
return ESP_ERR_DPP_FAILURE;
|
||||
}
|
||||
DPP_API_UNLOCK();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void esp_dpp_call_cb(esp_supp_dpp_event_t evt, void *data)
|
||||
{
|
||||
s_dpp_ctx.dpp_event_cb(evt, 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);;
|
||||
if (!req) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 = 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);
|
||||
|
||||
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(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_DPP_TX_FAILURE);
|
||||
os_free(req);
|
||||
return;
|
||||
}
|
||||
|
||||
os_free(req);
|
||||
}
|
||||
|
||||
static void esp_dpp_rx_auth_req(struct action_rx_param *rx_param, uint8_t *dpp_data)
|
||||
{
|
||||
size_t len = rx_param->vendor_data_len - 2;
|
||||
const u8 *r_bootstrap, *i_bootstrap;
|
||||
u16 r_bootstrap_len, i_bootstrap_len;
|
||||
struct dpp_bootstrap_info *own_bi;
|
||||
int rc;
|
||||
|
||||
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);
|
||||
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;
|
||||
goto fail;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
goto fail;
|
||||
}
|
||||
wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash", i_bootstrap, i_bootstrap_len);
|
||||
|
||||
own_bi = dpp_bootstrap_get_id(s_dpp_ctx.dpp_global, s_dpp_ctx.id);
|
||||
/* Try to find own and peer bootstrapping key matches based on the
|
||||
* received hash values */
|
||||
if (os_memcmp(own_bi->pubkey_hash, r_bootstrap, SHA256_MAC_LEN)) {
|
||||
wpa_printf(MSG_INFO, "DPP: No matching own bootstrapping key found as responder - ignore message");
|
||||
rc = ESP_ERR_DPP_INVALID_ATTR;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s_dpp_ctx.dpp_auth = dpp_auth_req_rx(NULL, DPP_CAPAB_ENROLLEE, 0, NULL,
|
||||
own_bi, rx_param->channel,
|
||||
(const u8 *)&rx_param->action_frm->u.public_action.v, dpp_data, len);
|
||||
os_memcpy(s_dpp_ctx.dpp_auth->peer_mac_addr, rx_param->sa, ETH_ALEN);
|
||||
|
||||
esp_send_action_frame(rx_param->sa, wpabuf_head(s_dpp_ctx.dpp_auth->resp_msg),
|
||||
wpabuf_len(s_dpp_ctx.dpp_auth->resp_msg),
|
||||
rx_param->channel, OFFCHAN_TX_WAIT_TIME);
|
||||
return;
|
||||
fail:
|
||||
esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)rc);
|
||||
}
|
||||
|
||||
static void gas_query_req_tx(struct dpp_authentication *auth)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
int supp_op_classes[] = {81, 0};
|
||||
|
||||
buf = dpp_build_conf_req_helper(auth, NULL, 0, NULL,
|
||||
supp_op_classes);
|
||||
if (!buf) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: No configuration request data available");
|
||||
esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_DPP_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (chan %u)",
|
||||
MAC2STR(auth->peer_mac_addr), auth->curr_chan);
|
||||
|
||||
esp_send_action_frame(auth->peer_mac_addr, wpabuf_head(buf), wpabuf_len(buf),
|
||||
auth->curr_chan, OFFCHAN_TX_WAIT_TIME);
|
||||
}
|
||||
|
||||
static int esp_dpp_handle_config_obj(struct dpp_authentication *auth,
|
||||
struct dpp_config_obj *conf)
|
||||
{
|
||||
wifi_config_t *wifi_cfg = &s_dpp_ctx.wifi_cfg;
|
||||
|
||||
if (conf->ssid_len) {
|
||||
os_memcpy(wifi_cfg->sta.ssid, conf->ssid, conf->ssid_len);
|
||||
}
|
||||
|
||||
if (dpp_akm_legacy(conf->akm)) {
|
||||
if (conf->passphrase[0])
|
||||
os_memcpy(wifi_cfg->sta.password, conf->passphrase,
|
||||
sizeof(wifi_cfg->sta.password));
|
||||
if (conf->akm == DPP_AKM_PSK_SAE) {
|
||||
wifi_cfg->sta.pmf_cfg.capable = true;
|
||||
wifi_cfg->sta.pmf_cfg.required = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (conf->connector) {
|
||||
/* TODO: Save the Connector and consider using a command
|
||||
* to fetch the value instead of sending an event with
|
||||
* it. The Connector could end up being larger than what
|
||||
* most clients are ready to receive as an event
|
||||
* message. */
|
||||
wpa_printf(MSG_INFO, DPP_EVENT_CONNECTOR "%s",
|
||||
conf->connector);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
size_t len = rx_param->vendor_data_len - 2;
|
||||
int rc;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR,
|
||||
MAC2STR(rx_param->sa));
|
||||
|
||||
if (!auth) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: No DPP Authentication in progress - drop");
|
||||
rc = ESP_ERR_DPP_FAILURE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (os_memcmp(rx_param->sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
|
||||
MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
|
||||
rc = ESP_ERR_DPP_FAILURE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (dpp_auth_conf_rx(auth, (const u8 *)&public_action->v,
|
||||
dpp_data, len) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
|
||||
rc = ESP_ERR_DPP_FAILURE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Send GAS Query Req */
|
||||
gas_query_req_tx(auth);
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)rc);
|
||||
}
|
||||
|
||||
static void esp_dpp_rx_auth(struct action_rx_param *rx_param)
|
||||
{
|
||||
uint8_t crypto_suit, type;
|
||||
uint8_t *tmp;
|
||||
|
||||
tmp = rx_param->action_frm->u.public_action.v.pa_vendor_spec.vendor_data;
|
||||
crypto_suit = tmp[0];
|
||||
type = tmp[1];
|
||||
|
||||
if (crypto_suit != 1) {
|
||||
wpa_printf(MSG_ERROR, "DPP: Unsupported crypto suit");
|
||||
esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_NOT_SUPPORTED);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case DPP_PA_AUTHENTICATION_REQ:
|
||||
esp_dpp_rx_auth_req(rx_param, &tmp[2]);
|
||||
break;
|
||||
case DPP_PA_AUTHENTICATION_CONF:
|
||||
esp_dpp_rx_auth_conf(rx_param, &tmp[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gas_query_resp_rx(struct action_rx_param *rx_param)
|
||||
{
|
||||
struct dpp_authentication *auth = s_dpp_ctx.dpp_auth;
|
||||
uint8_t *pos = rx_param->action_frm->u.public_action.v.pa_gas_resp.data;
|
||||
uint8_t *resp = &pos[10];
|
||||
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_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) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
fail:
|
||||
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;
|
||||
|
||||
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) {
|
||||
|
||||
rx_param->vendor_data_len = rx_param->frm_len -
|
||||
(size_t)(public_action->v.pa_vendor_spec.vendor_data -
|
||||
(u8 *)rx_param->action_frm);
|
||||
|
||||
if (!s_dpp_stop_listening) {
|
||||
esp_supp_dpp_stop_listen();
|
||||
}
|
||||
|
||||
esp_dpp_rx_auth(rx_param);
|
||||
} else if (public_action->action == WLAN_PA_GAS_INITIAL_RESP &&
|
||||
public_action->v.pa_gas_resp.type == WLAN_EID_ADV_PROTO &&
|
||||
public_action->v.pa_gas_resp.length == 8 &&
|
||||
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);
|
||||
|
||||
gas_query_resp_rx(rx_param);
|
||||
}
|
||||
}
|
||||
|
||||
os_free(rx_param->action_frm);
|
||||
os_free(rx_param);
|
||||
}
|
||||
|
||||
static void esp_dpp_task(void *pvParameters )
|
||||
{
|
||||
dpp_event_t *evt;
|
||||
bool task_del = false;
|
||||
|
||||
for (;;) {
|
||||
if (xQueueReceive(s_dpp_evt_queue, &evt, portMAX_DELAY) == pdTRUE) {
|
||||
if (evt->id < SIG_DPP_MAX) {
|
||||
DPP_API_LOCK();
|
||||
} else {
|
||||
os_free(evt);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (evt->id) {
|
||||
case SIG_DPP_DEL_TASK:
|
||||
task_del = true;
|
||||
break;
|
||||
|
||||
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);
|
||||
|
||||
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_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) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vQueueDelete(s_dpp_evt_queue);
|
||||
s_dpp_evt_queue = NULL;
|
||||
|
||||
if (s_dpp_api_lock) {
|
||||
vSemaphoreDelete(s_dpp_api_lock);
|
||||
s_dpp_api_lock = NULL;
|
||||
}
|
||||
|
||||
/* At this point, we completed */
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (WLAN_FC_GET_STYPE(rx_hdr->frame_control) == WLAN_FC_STYPE_ACTION) {
|
||||
rx_param = os_zalloc(sizeof(struct action_rx_param));
|
||||
os_memcpy(rx_param->sa, rx_hdr->addr2, ETH_ALEN);
|
||||
rx_param->channel = channel;
|
||||
rx_param->action_frm = os_zalloc(len);
|
||||
rx_param->frm_len = len;
|
||||
os_memcpy(rx_param->action_frm, payload, len);
|
||||
|
||||
if (ESP_OK != esp_dpp_post_evt(SIG_DPP_RX_ACTION, (u32)rx_param)) {
|
||||
os_free(rx_param->action_frm);
|
||||
os_free(rx_param);
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
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_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->context);
|
||||
|
||||
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_stop_listening && evt->context == (uint32_t)s_action_rx_cb) {
|
||||
esp_dpp_post_evt(SIG_DPP_LISTEN_NEXT_CHANNEL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_NOT_SUPPORTED;
|
||||
goto fail;
|
||||
}
|
||||
params->type = type;
|
||||
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);
|
||||
if (!params->info) {
|
||||
os_free(command);
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto fail;
|
||||
}
|
||||
os_memcpy(params->info, uri_info, params->info_len);
|
||||
}
|
||||
}
|
||||
|
||||
if (key) {
|
||||
params->key_len = strlen(key);
|
||||
if (params->key_len) {
|
||||
char prefix[] = "30310201010420";
|
||||
char postfix[] = "a00a06082a8648ce3d030107";
|
||||
|
||||
params->key = os_zalloc(params->key_len +
|
||||
sizeof(prefix) + sizeof(postfix));
|
||||
if (!params->key) {
|
||||
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 "%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) {
|
||||
os_free(command);
|
||||
if (params->info) {
|
||||
os_free(params->info);
|
||||
params->info = NULL;
|
||||
}
|
||||
if (params->key) {
|
||||
os_free(params->key);
|
||||
params->key = NULL;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = ESP_OK;
|
||||
fail:
|
||||
if (uri_chan_list) {
|
||||
os_free(uri_chan_list);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t esp_supp_dpp_start_listen(void)
|
||||
{
|
||||
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_supp_dpp_stop_listen(void)
|
||||
{
|
||||
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(esp_supp_dpp_event_cb_t cb)
|
||||
{
|
||||
struct dpp_global_config cfg = {0};
|
||||
|
||||
os_bzero(&s_dpp_ctx, sizeof(s_dpp_ctx));
|
||||
s_dpp_ctx.dpp_event_cb = cb;
|
||||
|
||||
cfg.cb_ctx = &s_dpp_ctx;
|
||||
cfg.msg_ctx = &s_dpp_ctx;
|
||||
s_dpp_ctx.dpp_global = dpp_global_init(&cfg);
|
||||
|
||||
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_NO_MEM;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
wpa_printf(MSG_INFO, "esp_dpp_task prio:%d, stack:%d\n", 2, DPP_TASK_STACK_SIZE);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_supp_dpp_deinit(void)
|
||||
{
|
||||
struct dpp_bootstrap_params_t *params = &s_dpp_ctx.bootstrap_params;
|
||||
|
||||
if (params->info) {
|
||||
os_free(params->info);
|
||||
params->info = NULL;
|
||||
}
|
||||
if (params->key) {
|
||||
os_free(params->key);
|
||||
params->key = NULL;
|
||||
}
|
||||
|
||||
s_dpp_auth_retries = 0;
|
||||
dpp_global_deinit(s_dpp_ctx.dpp_global);
|
||||
esp_dpp_post_evt(SIG_DPP_DEL_TASK, 0);
|
||||
}
|
68
components/wpa_supplicant/src/esp_supplicant/esp_dpp_i.h
Normal file
68
components/wpa_supplicant/src/esp_supplicant/esp_dpp_i.h
Normal file
@ -0,0 +1,68 @@
|
||||
// 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.
|
||||
|
||||
#ifndef ESP_DPP_I_H
|
||||
#define ESP_DPP_I_H
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
|
||||
#include "common/dpp.h"
|
||||
#include "esp_dpp.h"
|
||||
#include "esp_wifi_driver.h"
|
||||
|
||||
#define DPP_TASK_STACK_SIZE (6144 + TASK_STACK_SIZE_ADD)
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t id;
|
||||
uint32_t data;
|
||||
} dpp_event_t;
|
||||
|
||||
#define BOOTSTRAP_ROC_WAIT_TIME 500
|
||||
#define OFFCHAN_TX_WAIT_TIME 500
|
||||
|
||||
struct dpp_bootstrap_params_t {
|
||||
enum dpp_bootstrap_type type;
|
||||
uint8_t chan_list[14];
|
||||
uint8_t num_chan;
|
||||
uint8_t mac[6];
|
||||
uint32_t key_len;
|
||||
char *key;
|
||||
uint32_t info_len;
|
||||
char *info;
|
||||
};
|
||||
|
||||
struct esp_dpp_context_t {
|
||||
struct dpp_bootstrap_params_t bootstrap_params;
|
||||
struct dpp_authentication *dpp_auth;
|
||||
int gas_dialog_token;
|
||||
esp_supp_dpp_event_cb_t dpp_event_cb;
|
||||
struct dpp_global *dpp_global;
|
||||
wifi_config_t wifi_cfg;
|
||||
int id;
|
||||
};
|
||||
|
||||
int esp_supp_rx_action(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel);
|
||||
|
||||
#endif /* ESP_DPP_I_H */
|
@ -261,5 +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_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_ */
|
||||
|
245
components/wpa_supplicant/test/test_offchannel.c
Normal file
245
components/wpa_supplicant/test/test_offchannel.c
Normal 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)
|
@ -67,6 +67,8 @@ These third party libraries can be included into the application (firmware) prod
|
||||
|
||||
* :component_file:` TLSF allocator <heap/heap_tlsf.c>` Two Level Segregated Fit memory allocator, Copyright (c) 2006-2016, Matthew Conte, and licensed under the BSD license.
|
||||
|
||||
* `qrcode`_ QR Code generator library Copyright (c) Project Nayuki, is licensed under MIT license.
|
||||
|
||||
Build Tools
|
||||
-----------
|
||||
|
||||
@ -179,3 +181,4 @@ Copyright (C) 2011, ChaN, all right reserved.
|
||||
.. _sphinx_idf_theme: https://github.com/espressif/sphinx_idf_theme
|
||||
.. _sphinx_rtd_theme: https://github.com/readthedocs/sphinx_rtd_theme
|
||||
.. _cryptoauthlib: https://github.com/MicrochipTech/cryptoauthlib
|
||||
.. _qrcode: https://github.com/nayuki/QR-Code-generator
|
||||
|
3
examples/common_components/qrcode/CMakeLists.txt
Normal file
3
examples/common_components/qrcode/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "esp_qrcode_main.c" "esp_qrcode_wrapper.c" "qrcodegen.c"
|
||||
INCLUDE_DIRS "include"
|
||||
)
|
9
examples/common_components/qrcode/README.md
Normal file
9
examples/common_components/qrcode/README.md
Normal 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.
|
0
examples/common_components/qrcode/component.mk
Normal file
0
examples/common_components/qrcode/component.mk
Normal file
121
examples/common_components/qrcode/esp_qrcode_main.c
Normal file
121
examples/common_components/qrcode/esp_qrcode_main.c
Normal file
@ -0,0 +1,121 @@
|
||||
// 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 <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 ",
|
||||
/* 2 */ " \u2580",
|
||||
/* 3 */ "\u2580\u2580",
|
||||
/* 4 */ "\u2584 ",
|
||||
/* 5 */ "\u2588 ",
|
||||
/* 6 */ "\u2584\u2580",
|
||||
/* 7 */ "\u2588\u2580",
|
||||
/* 8 */ " \u2584",
|
||||
/* 9 */ "\u2580\u2584",
|
||||
/* 10 */ " \u2588",
|
||||
/* 11 */ "\u2580\u2588",
|
||||
/* 12 */ "\u2584\u2584",
|
||||
/* 13 */ "\u2588\u2584",
|
||||
/* 14 */ "\u2584\u2588",
|
||||
/* 15 */ "\u2588\u2588",
|
||||
};
|
||||
|
||||
void esp_qrcode_print_console(esp_qrcode_handle_t qrcode)
|
||||
{
|
||||
int size = qrcodegen_getSize(qrcode);
|
||||
int border = 2;
|
||||
unsigned char num = 0;
|
||||
|
||||
for (int y = -border; y < size + border; y+=2) {
|
||||
for (int x = -border; x < size + border; x+=2) {
|
||||
num = 0;
|
||||
if (qrcodegen_getModule(qrcode, x, y)) {
|
||||
num |= 1 << 0;
|
||||
}
|
||||
if ((x < size + border) && qrcodegen_getModule(qrcode, x+1, y)) {
|
||||
num |= 1 << 1;
|
||||
}
|
||||
if ((y < size + border) && qrcodegen_getModule(qrcode, x, y+1)) {
|
||||
num |= 1 << 2;
|
||||
}
|
||||
if ((x < size + border) && (y < size + border) && qrcodegen_getModule(qrcode, x+1, y+1)) {
|
||||
num |= 1 << 3;
|
||||
}
|
||||
printf("%s", lt[num]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
esp_err_t esp_qrcode_generate(esp_qrcode_config_t *cfg, const char *text)
|
||||
{
|
||||
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) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
tempbuf = calloc(1, qrcodegen_BUFFER_LEN_FOR_VERSION(cfg->max_qrcode_version));
|
||||
if (!tempbuf) {
|
||||
free(qrcode);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
switch(cfg->qrcode_ecc_level) {
|
||||
case ESP_QRCODE_ECC_LOW:
|
||||
ecc_lvl = qrcodegen_Ecc_LOW;
|
||||
break;
|
||||
case ESP_QRCODE_ECC_MED:
|
||||
ecc_lvl = qrcodegen_Ecc_MEDIUM;
|
||||
break;
|
||||
case ESP_QRCODE_ECC_QUART:
|
||||
ecc_lvl = qrcodegen_Ecc_QUARTILE;
|
||||
break;
|
||||
case ESP_QRCODE_ECC_HIGH:
|
||||
ecc_lvl = qrcodegen_Ecc_HIGH;
|
||||
break;
|
||||
default:
|
||||
ecc_lvl = qrcodegen_Ecc_LOW;
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
err = ESP_OK;
|
||||
}
|
||||
|
||||
free(qrcode);
|
||||
free(tempbuf);
|
||||
return err;
|
||||
}
|
29
examples/common_components/qrcode/esp_qrcode_wrapper.c
Normal file
29
examples/common_components/qrcode/esp_qrcode_wrapper.c
Normal file
@ -0,0 +1,29 @@
|
||||
// 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 <stdio.h>
|
||||
#include <esp_err.h>
|
||||
|
||||
#include "qrcodegen.h"
|
||||
#include "qrcode.h"
|
||||
|
||||
int esp_qrcode_get_size(esp_qrcode_handle_t qrcode)
|
||||
{
|
||||
return qrcodegen_getSize(qrcode);
|
||||
}
|
||||
|
||||
bool esp_qrcode_get_module(esp_qrcode_handle_t qrcode, int x, int y)
|
||||
{
|
||||
return qrcodegen_getModule(qrcode, x, y);
|
||||
}
|
104
examples/common_components/qrcode/include/qrcode.h
Normal file
104
examples/common_components/qrcode/include/qrcode.h
Normal file
@ -0,0 +1,104 @@
|
||||
// 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.
|
||||
#pragma once
|
||||
|
||||
#include <esp_err.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief QR Code handle used by the display function
|
||||
*/
|
||||
typedef const uint8_t * esp_qrcode_handle_t;
|
||||
|
||||
/**
|
||||
* @brief QR Code configuration options
|
||||
*/
|
||||
typedef struct {
|
||||
void (*display_func)(esp_qrcode_handle_t qrcode); /**< Function called for displaying the QR Code after encoding is complete */
|
||||
int max_qrcode_version; /**< Max QR Code Version to be used. Range: 2 - 40 */
|
||||
int qrcode_ecc_level; /**< Error Correction Level for QR Code */
|
||||
} esp_qrcode_config_t;
|
||||
|
||||
/**
|
||||
* @brief Error Correction Level in a QR Code Symbol
|
||||
*/
|
||||
enum {
|
||||
ESP_QRCODE_ECC_LOW, /**< QR Code Error Tolerance of 7% */
|
||||
ESP_QRCODE_ECC_MED, /**< QR Code Error Tolerance of 15% */
|
||||
ESP_QRCODE_ECC_QUART, /**< QR Code Error Tolerance of 25% */
|
||||
ESP_QRCODE_ECC_HIGH /**< QR Code Error Tolerance of 30% */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Encodes the given string into a QR Code and calls the display function
|
||||
*
|
||||
* @attention 1. Can successfully encode a UTF-8 string of up to 2953 bytes or an alphanumeric
|
||||
* string of up to 4296 characters or any digit string of up to 7089 characters
|
||||
*
|
||||
* @param cfg Configuration used for QR Code encoding.
|
||||
* @param text String to encode into a QR Code.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_FAIL: Failed to encode string into a QR Code
|
||||
* - ESP_ERR_NO_MEM: Failed to allocate buffer for given max_qrcode_version
|
||||
*/
|
||||
esp_err_t esp_qrcode_generate(esp_qrcode_config_t *cfg, const char *text);
|
||||
|
||||
/**
|
||||
* @brief Displays QR Code on the console
|
||||
*
|
||||
* @param qrcode QR Code handle used by the display function.
|
||||
*/
|
||||
void esp_qrcode_print_console(esp_qrcode_handle_t qrcode);
|
||||
|
||||
/**
|
||||
* @brief Returns the side length of the given QR Code
|
||||
*
|
||||
* @param qrcode QR Code handle used by the display function.
|
||||
*
|
||||
* @return
|
||||
* - val[21, 177]: Side length of QR Code
|
||||
*/
|
||||
int esp_qrcode_get_size(esp_qrcode_handle_t qrcode);
|
||||
|
||||
/**
|
||||
* @brief Returns the Pixel value for the given coordinates
|
||||
* False indicates White and True indicates Black
|
||||
*
|
||||
* @attention 1. Coordinates for top left corner are (x=0, y=0)
|
||||
* @attention 2. For out of bound coordinates false (White) is returned
|
||||
*
|
||||
* @param qrcode QR Code handle used by the display function.
|
||||
* @param x X-Coordinate of QR Code module
|
||||
* @param y Y-Coordinate of QR Code module
|
||||
*
|
||||
* @return
|
||||
* - true: (x, y) Pixel is Black
|
||||
* - false: (x, y) Pixel is White
|
||||
*/
|
||||
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, \
|
||||
.max_qrcode_version = 10, \
|
||||
.qrcode_ecc_level = ESP_QRCODE_ECC_LOW, \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
1022
examples/common_components/qrcode/qrcodegen.c
Normal file
1022
examples/common_components/qrcode/qrcodegen.c
Normal file
File diff suppressed because it is too large
Load Diff
311
examples/common_components/qrcode/qrcodegen.h
Normal file
311
examples/common_components/qrcode/qrcodegen.h
Normal file
@ -0,0 +1,311 @@
|
||||
/*
|
||||
* QR Code generator library (C)
|
||||
*
|
||||
* Copyright (c) Project Nayuki. (MIT License)
|
||||
* https://www.nayuki.io/page/qr-code-generator-library
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
* - The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
* - The Software is provided "as is", without warranty of any kind, express or
|
||||
* implied, including but not limited to the warranties of merchantability,
|
||||
* fitness for a particular purpose and noninfringement. In no event shall the
|
||||
* authors or copyright holders be liable for any claim, damages or other
|
||||
* liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
* out of or in connection with the Software or the use or other dealings in the
|
||||
* Software.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* This library creates QR Code symbols, which is a type of two-dimension barcode.
|
||||
* Invented by Denso Wave and described in the ISO/IEC 18004 standard.
|
||||
* A QR Code structure is an immutable square grid of black and white cells.
|
||||
* The library provides functions to create a QR Code from text or binary data.
|
||||
* The library covers the QR Code Model 2 specification, supporting all versions (sizes)
|
||||
* from 1 to 40, all 4 error correction levels, and 4 character encoding modes.
|
||||
*
|
||||
* Ways to create a QR Code object:
|
||||
* - High level: Take the payload data and call qrcodegen_encodeText() or qrcodegen_encodeBinary().
|
||||
* - Low level: Custom-make the list of segments and call
|
||||
* qrcodegen_encodeSegments() or qrcodegen_encodeSegmentsAdvanced().
|
||||
* (Note that all ways require supplying the desired error correction level and various byte buffers.)
|
||||
*/
|
||||
|
||||
|
||||
/*---- Enum and struct types----*/
|
||||
|
||||
/*
|
||||
* The error correction level in a QR Code symbol.
|
||||
*/
|
||||
enum qrcodegen_Ecc {
|
||||
// Must be declared in ascending order of error protection
|
||||
// so that an internal qrcodegen function works properly
|
||||
qrcodegen_Ecc_LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords
|
||||
qrcodegen_Ecc_MEDIUM , // The QR Code can tolerate about 15% erroneous codewords
|
||||
qrcodegen_Ecc_QUARTILE, // The QR Code can tolerate about 25% erroneous codewords
|
||||
qrcodegen_Ecc_HIGH , // The QR Code can tolerate about 30% erroneous codewords
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The mask pattern used in a QR Code symbol.
|
||||
*/
|
||||
enum qrcodegen_Mask {
|
||||
// A special value to tell the QR Code encoder to
|
||||
// automatically select an appropriate mask pattern
|
||||
qrcodegen_Mask_AUTO = -1,
|
||||
// The eight actual mask patterns
|
||||
qrcodegen_Mask_0 = 0,
|
||||
qrcodegen_Mask_1,
|
||||
qrcodegen_Mask_2,
|
||||
qrcodegen_Mask_3,
|
||||
qrcodegen_Mask_4,
|
||||
qrcodegen_Mask_5,
|
||||
qrcodegen_Mask_6,
|
||||
qrcodegen_Mask_7,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Describes how a segment's data bits are interpreted.
|
||||
*/
|
||||
enum qrcodegen_Mode {
|
||||
qrcodegen_Mode_NUMERIC = 0x1,
|
||||
qrcodegen_Mode_ALPHANUMERIC = 0x2,
|
||||
qrcodegen_Mode_BYTE = 0x4,
|
||||
qrcodegen_Mode_KANJI = 0x8,
|
||||
qrcodegen_Mode_ECI = 0x7,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* A segment of character/binary/control data in a QR Code symbol.
|
||||
* The mid-level way to create a segment is to take the payload data
|
||||
* and call a factory function such as qrcodegen_makeNumeric().
|
||||
* The low-level way to create a segment is to custom-make the bit buffer
|
||||
* and initialize a qrcodegen_Segment struct with appropriate values.
|
||||
* Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
|
||||
* Any segment longer than this is meaningless for the purpose of generating QR Codes.
|
||||
* Moreover, the maximum allowed bit length is 32767 because
|
||||
* the largest QR Code (version 40) has 31329 modules.
|
||||
*/
|
||||
struct qrcodegen_Segment {
|
||||
// The mode indicator of this segment.
|
||||
enum qrcodegen_Mode mode;
|
||||
|
||||
// The length of this segment's unencoded data. Measured in characters for
|
||||
// numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
|
||||
// Always zero or positive. Not the same as the data's bit length.
|
||||
int numChars;
|
||||
|
||||
// The data bits of this segment, packed in bitwise big endian.
|
||||
// Can be null if the bit length is zero.
|
||||
uint8_t *data;
|
||||
|
||||
// The number of valid data bits used in the buffer. Requires
|
||||
// 0 <= bitLength <= 32767, and bitLength <= (capacity of data array) * 8.
|
||||
// The character count (numChars) must agree with the mode and the bit buffer length.
|
||||
int bitLength;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*---- Macro constants and functions ----*/
|
||||
|
||||
#define qrcodegen_VERSION_MIN 1 // The minimum version number supported in the QR Code Model 2 standard
|
||||
#define qrcodegen_VERSION_MAX 40 // The maximum version number supported in the QR Code Model 2 standard
|
||||
|
||||
// Calculates the number of bytes needed to store any QR Code up to and including the given version number,
|
||||
// as a compile-time constant. For example, 'uint8_t buffer[qrcodegen_BUFFER_LEN_FOR_VERSION(25)];'
|
||||
// can store any single QR Code from version 1 to 25 (inclusive). The result fits in an int (or int16).
|
||||
// Requires qrcodegen_VERSION_MIN <= n <= qrcodegen_VERSION_MAX.
|
||||
#define qrcodegen_BUFFER_LEN_FOR_VERSION(n) ((((n) * 4 + 17) * ((n) * 4 + 17) + 7) / 8 + 1)
|
||||
|
||||
// The worst-case number of bytes needed to store one QR Code, up to and including
|
||||
// version 40. This value equals 3918, which is just under 4 kilobytes.
|
||||
// Use this more convenient value to avoid calculating tighter memory bounds for buffers.
|
||||
#define qrcodegen_BUFFER_LEN_MAX qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX)
|
||||
|
||||
|
||||
|
||||
/*---- Functions (high level) to generate QR Codes ----*/
|
||||
|
||||
/*
|
||||
* Encodes the given text string to a QR Code, returning true if encoding succeeded.
|
||||
* If the data is too long to fit in any version in the given range
|
||||
* at the given ECC level, then false is returned.
|
||||
* - The input text must be encoded in UTF-8 and contain no NULs.
|
||||
* - The variables ecl and mask must correspond to enum constant values.
|
||||
* - Requires 1 <= minVersion <= maxVersion <= 40.
|
||||
* - The arrays tempBuffer and qrcode must each have a length
|
||||
* of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion).
|
||||
* - After the function returns, tempBuffer contains no useful data.
|
||||
* - If successful, the resulting QR Code may use numeric,
|
||||
* alphanumeric, or byte mode to encode the text.
|
||||
* - In the most optimistic case, a QR Code at version 40 with low ECC
|
||||
* can hold any UTF-8 string up to 2953 bytes, or any alphanumeric string
|
||||
* up to 4296 characters, or any digit string up to 7089 characters.
|
||||
* These numbers represent the hard upper limit of the QR Code standard.
|
||||
* - Please consult the QR Code specification for information on
|
||||
* data capacities per version, ECC level, and text encoding mode.
|
||||
*/
|
||||
bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[],
|
||||
enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl);
|
||||
|
||||
|
||||
/*
|
||||
* Encodes the given binary data to a QR Code, returning true if encoding succeeded.
|
||||
* If the data is too long to fit in any version in the given range
|
||||
* at the given ECC level, then false is returned.
|
||||
* - The input array range dataAndTemp[0 : dataLen] should normally be
|
||||
* valid UTF-8 text, but is not required by the QR Code standard.
|
||||
* - The variables ecl and mask must correspond to enum constant values.
|
||||
* - Requires 1 <= minVersion <= maxVersion <= 40.
|
||||
* - The arrays dataAndTemp and qrcode must each have a length
|
||||
* of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion).
|
||||
* - After the function returns, the contents of dataAndTemp may have changed,
|
||||
* and does not represent useful data anymore.
|
||||
* - If successful, the resulting QR Code will use byte mode to encode the data.
|
||||
* - In the most optimistic case, a QR Code at version 40 with low ECC can hold any byte
|
||||
* sequence up to length 2953. This is the hard upper limit of the QR Code standard.
|
||||
* - Please consult the QR Code specification for information on
|
||||
* data capacities per version, ECC level, and text encoding mode.
|
||||
*/
|
||||
bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[],
|
||||
enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl);
|
||||
|
||||
|
||||
/*---- Functions (low level) to generate QR Codes ----*/
|
||||
|
||||
/*
|
||||
* Renders a QR Code representing the given segments at the given error correction level.
|
||||
* The smallest possible QR Code version is automatically chosen for the output. Returns true if
|
||||
* QR Code creation succeeded, or false if the data is too long to fit in any version. The ECC level
|
||||
* of the result may be higher than the ecl argument if it can be done without increasing the version.
|
||||
* This function allows the user to create a custom sequence of segments that switches
|
||||
* between modes (such as alphanumeric and byte) to encode text in less space.
|
||||
* This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary().
|
||||
* To save memory, the segments' data buffers can alias/overlap tempBuffer, and will
|
||||
* result in them being clobbered, but the QR Code output will still be correct.
|
||||
* But the qrcode array must not overlap tempBuffer or any segment's data buffer.
|
||||
*/
|
||||
bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len,
|
||||
enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]);
|
||||
|
||||
|
||||
/*
|
||||
* Renders a QR Code representing the given segments with the given encoding parameters.
|
||||
* Returns true if QR Code creation succeeded, or false if the data is too long to fit in the range of versions.
|
||||
* The smallest possible QR Code version within the given range is automatically
|
||||
* chosen for the output. Iff boostEcl is true, then the ECC level of the result
|
||||
* may be higher than the ecl argument if it can be done without increasing the
|
||||
* version. The mask is either between qrcodegen_Mask_0 to 7 to force that mask, or
|
||||
* qrcodegen_Mask_AUTO to automatically choose an appropriate mask (which may be slow).
|
||||
* This function allows the user to create a custom sequence of segments that switches
|
||||
* between modes (such as alphanumeric and byte) to encode text in less space.
|
||||
* This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary().
|
||||
* To save memory, the segments' data buffers can alias/overlap tempBuffer, and will
|
||||
* result in them being clobbered, but the QR Code output will still be correct.
|
||||
* But the qrcode array must not overlap tempBuffer or any segment's data buffer.
|
||||
*/
|
||||
bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl,
|
||||
int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]);
|
||||
|
||||
|
||||
/*
|
||||
* Tests whether the given string can be encoded as a segment in alphanumeric mode.
|
||||
* A string is encodable iff each character is in the following set: 0 to 9, A to Z
|
||||
* (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
|
||||
*/
|
||||
bool qrcodegen_isAlphanumeric(const char *text);
|
||||
|
||||
|
||||
/*
|
||||
* Tests whether the given string can be encoded as a segment in numeric mode.
|
||||
* A string is encodable iff each character is in the range 0 to 9.
|
||||
*/
|
||||
bool qrcodegen_isNumeric(const char *text);
|
||||
|
||||
|
||||
/*
|
||||
* Returns the number of bytes (uint8_t) needed for the data buffer of a segment
|
||||
* containing the given number of characters using the given mode. Notes:
|
||||
* - Returns SIZE_MAX on failure, i.e. numChars > INT16_MAX or
|
||||
* the number of needed bits exceeds INT16_MAX (i.e. 32767).
|
||||
* - Otherwise, all valid results are in the range [0, ceil(INT16_MAX / 8)], i.e. at most 4096.
|
||||
* - It is okay for the user to allocate more bytes for the buffer than needed.
|
||||
* - For byte mode, numChars measures the number of bytes, not Unicode code points.
|
||||
* - For ECI mode, numChars must be 0, and the worst-case number of bytes is returned.
|
||||
* An actual ECI segment can have shorter data. For non-ECI modes, the result is exact.
|
||||
*/
|
||||
size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars);
|
||||
|
||||
|
||||
/*
|
||||
* Returns a segment representing the given binary data encoded in
|
||||
* byte mode. All input byte arrays are acceptable. Any text string
|
||||
* can be converted to UTF-8 bytes and encoded as a byte mode segment.
|
||||
*/
|
||||
struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]);
|
||||
|
||||
|
||||
/*
|
||||
* Returns a segment representing the given string of decimal digits encoded in numeric mode.
|
||||
*/
|
||||
struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]);
|
||||
|
||||
|
||||
/*
|
||||
* Returns a segment representing the given text string encoded in alphanumeric mode.
|
||||
* The characters allowed are: 0 to 9, A to Z (uppercase only), space,
|
||||
* dollar, percent, asterisk, plus, hyphen, period, slash, colon.
|
||||
*/
|
||||
struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]);
|
||||
|
||||
|
||||
/*
|
||||
* Returns a segment representing an Extended Channel Interpretation
|
||||
* (ECI) designator with the given assignment value.
|
||||
*/
|
||||
struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]);
|
||||
|
||||
|
||||
/*---- Functions to extract raw data from QR Codes ----*/
|
||||
|
||||
/*
|
||||
* Returns the side length of the given QR Code, assuming that encoding succeeded.
|
||||
* The result is in the range [21, 177]. Note that the length of the array buffer
|
||||
* is related to the side length - every 'uint8_t qrcode[]' must have length at least
|
||||
* qrcodegen_BUFFER_LEN_FOR_VERSION(version), which equals ceil(size^2 / 8 + 1).
|
||||
*/
|
||||
int qrcodegen_getSize(const uint8_t qrcode[]);
|
||||
|
||||
|
||||
/*
|
||||
* Returns the color of the module (pixel) at the given coordinates, which is false
|
||||
* for white or true for black. The top left corner has the coordinates (x=0, y=0).
|
||||
* If the given coordinates are out of bounds, then false (white) is returned.
|
||||
*/
|
||||
bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -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)
|
10
examples/wifi/wifi_easy_connect/dpp-enrollee/Makefile
Normal file
10
examples/wifi/wifi_easy_connect/dpp-enrollee/Makefile
Normal 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
|
66
examples/wifi/wifi_easy_connect/dpp-enrollee/README.md
Normal file
66
examples/wifi/wifi_easy_connect/dpp-enrollee/README.md
Normal 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
|
||||
```
|
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "dpp_enrollee_main.c"
|
||||
INCLUDE_DIRS ".")
|
@ -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
|
@ -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.
|
||||
#
|
@ -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();
|
||||
}
|
Reference in New Issue
Block a user