mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
feat(wifi): NAN encrypted datapath (Wi-Fi Aware M1-M4 handshake)
Implement the NAN Data Path encrypted datapath per Wi-Fi Aware v4.0 (§7.1.3.5, §9.5.16): - Responder + initiator sides of the M1-M4 Shared-Key Descriptor exchange, with MIC compute/verify, PTK derivation, and PMK/PMKID derivation via PBKDF2-SHA256 over passphrase or pre-shared PMK. - CSIA / SCIA attribute build + parse, NCS-SK-128 cipher suite. - Per-NDL security context on ndl_info::security_ctx; per-svc PMK cache. - ndp_response_indication callback for initiator peer-NDI binding. - host<->blob ABI migrated from 27 direct esp_nan_* externs to a single nan_secure_dp_funcs callback struct in esp_private/wifi.h. - nan_security.c split out of nan_app.c (~340 lines de-duplicated into shared M1-M4 helpers). - CONFIG_ESP_WIFI_NAN_ENCRYPTED_DATAPATH gates the secure path so non- security builds compile out the crypto/handshake code. - ROM patch (esp32s31): mask ieee80211_encap_esfbuf to match the c5/c6/c61 pattern for NAN-capable chips. Hardening: PMK stack copies zeroized on every return, NDP attribute parsers bounds-checked, CSID range-checked before shifting, NDL slot reuse only when handshake state is IDLE, get_csia/scia_len aligned with their builders on empty input. API surface: NDP security types moved out of esp_wifi_types_generic.h into esp_private/wifi.h (internal-only). security pointer dropped from struct ndp_cb_peer_info. Discovery-side wifi_nan_security_type_t and the NDP Info callbacks removed (subsumed by csid_bitmap and SSI respectively).
This commit is contained in:
@@ -852,5 +852,6 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
|||||||
- CONFIG_SPIRAM_SPEED_120M && CONFIG_SPIRAM_MODE_OCT
|
- CONFIG_SPIRAM_SPEED_120M && CONFIG_SPIRAM_MODE_OCT
|
||||||
- CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH
|
- CONFIG_BOOTLOADER_CACHE_32BIT_ADDR_QUAD_FLASH
|
||||||
- CONFIG_ESP_WIFI_EAP_TLS1_3
|
- CONFIG_ESP_WIFI_EAP_TLS1_3
|
||||||
|
- CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
- CONFIG_USB_HOST_EXT_PORT_RESET_ATTEMPTS
|
- CONFIG_USB_HOST_EXT_PORT_RESET_ATTEMPTS
|
||||||
- CONFIG_GDMA_ENABLE_WEIGHTED_ARBITRATION
|
- CONFIG_GDMA_ENABLE_WEIGHTED_ARBITRATION
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ ic_reset_extra_softap_rx_ba = 0x2f800c78;
|
|||||||
ieee80211_align_eb = 0x2f800c7c;
|
ieee80211_align_eb = 0x2f800c7c;
|
||||||
ieee80211_ampdu_reorder = 0x2f800c80;
|
ieee80211_ampdu_reorder = 0x2f800c80;
|
||||||
ieee80211_ampdu_start_age_timer = 0x2f800c84;
|
ieee80211_ampdu_start_age_timer = 0x2f800c84;
|
||||||
ieee80211_encap_esfbuf = 0x2f800c88;
|
/*ieee80211_encap_esfbuf = 0x2f800c88;*/
|
||||||
ieee80211_is_tx_allowed = 0x2f800c8c;
|
ieee80211_is_tx_allowed = 0x2f800c8c;
|
||||||
ieee80211_output_pending_eb = 0x2f800c90;
|
ieee80211_output_pending_eb = 0x2f800c90;
|
||||||
ieee80211_output_process = 0x2f800c94;
|
ieee80211_output_process = 0x2f800c94;
|
||||||
|
|||||||
@@ -70,6 +70,9 @@ if(CONFIG_ESP_WIFI_ENABLED OR CONFIG_ESP_HOST_WIFI_ENABLED)
|
|||||||
|
|
||||||
if(CONFIG_ESP_WIFI_NAN_SYNC_ENABLE OR CONFIG_ESP_WIFI_NAN_USD_ENABLE)
|
if(CONFIG_ESP_WIFI_NAN_SYNC_ENABLE OR CONFIG_ESP_WIFI_NAN_USD_ENABLE)
|
||||||
list(APPEND srcs "wifi_apps/nan_app/src/nan_app.c")
|
list(APPEND srcs "wifi_apps/nan_app/src/nan_app.c")
|
||||||
|
if(CONFIG_ESP_WIFI_NAN_SECURITY)
|
||||||
|
list(APPEND srcs "wifi_apps/nan_app/src/nan_security.c")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
if(CONFIG_ESP_WIFI_ENABLE_ROAMING_APP)
|
if(CONFIG_ESP_WIFI_ENABLE_ROAMING_APP)
|
||||||
list(APPEND srcs "wifi_apps/roaming_app/src/roaming_app.c")
|
list(APPEND srcs "wifi_apps/roaming_app/src/roaming_app.c")
|
||||||
|
|||||||
@@ -593,6 +593,23 @@ menu "Wi-Fi"
|
|||||||
help
|
help
|
||||||
Enable Wi-Fi Aware: Synchronization feature (NAN-Sync).
|
Enable Wi-Fi Aware: Synchronization feature (NAN-Sync).
|
||||||
|
|
||||||
|
config ESP_WIFI_NAN_SECURITY
|
||||||
|
bool "Enable Wi-Fi Aware: Encrypted Pairwise Datapath (NDP Security)"
|
||||||
|
depends on ESP_WIFI_NAN_SYNC_ENABLE && IDF_EXPERIMENTAL_FEATURES && ESP_WIFI_MBEDTLS_CRYPTO
|
||||||
|
select MBEDTLS_PKCS5_C
|
||||||
|
select MBEDTLS_SHA256_C
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Enable encrypted pairwise datapath for Wi-Fi Aware (NAN).
|
||||||
|
Adds PBKDF2 key derivation (mbedTLS PKCS#5), 4-way handshake (M1-M4),
|
||||||
|
PTK derivation, and CCMP key installation for secured NAN
|
||||||
|
data links. Disable to save code size when only open
|
||||||
|
datapaths are needed.
|
||||||
|
|
||||||
|
Requires ESP_WIFI_MBEDTLS_CRYPTO + MBEDTLS_PKCS5_C + MBEDTLS_SHA256_C
|
||||||
|
for ND-PMK derivation via pbkdf2_sha256() (MBEDTLS_MD_C is pulled in
|
||||||
|
transitively by MBEDTLS_PKCS5_C).
|
||||||
|
|
||||||
config ESP_WIFI_NAN_USD_ENABLE
|
config ESP_WIFI_NAN_USD_ENABLE
|
||||||
bool "Enable Wi-Fi Aware: Unsynchronized service discovery (NAN-USD)"
|
bool "Enable Wi-Fi Aware: Unsynchronized service discovery (NAN-USD)"
|
||||||
depends on IDF_EXPERIMENTAL_FEATURES
|
depends on IDF_EXPERIMENTAL_FEATURES
|
||||||
|
|||||||
@@ -39,6 +39,29 @@ typedef struct {
|
|||||||
void *storage; /**< storage for FreeRTOS queue */
|
void *storage; /**< storage for FreeRTOS queue */
|
||||||
} wifi_static_queue_t;
|
} wifi_static_queue_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief NAN Datapath Security Type (Wi-Fi Aware v4.0 §9.5.16.1 Table 85, "Security Present" bit)
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
WIFI_NAN_SECURITY_OPEN = 0, /**< NDP does not require security */
|
||||||
|
WIFI_NAN_SECURITY_ENCRYPTED = 1, /**< NDP requires security */
|
||||||
|
} wifi_nan_security_type_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief NAN Datapath security parameters (Spec 6.1.1 - Data Path Request/Response)
|
||||||
|
*
|
||||||
|
* @note Shared between WiFi libraries and NAN app layer.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
wifi_nan_security_type_t type; /**< Security Type (Open/Encrypted) */
|
||||||
|
uint16_t csid_bitmap; /**< Bitmap of Cipher Suite IDs (WIFI_NAN_CSID_BIT_*) */
|
||||||
|
uint8_t nd_pmk[ESP_WIFI_NAN_NDP_PMK_LEN]; /**< ND-PMK (Required for Datapath) */
|
||||||
|
uint8_t nd_pmkid[ESP_WIFI_NAN_NDP_PMKID_LEN]; /**< ND-PMKID */
|
||||||
|
uint8_t group_data_prot: 1; /**< Group addressed data frame protection. Reserved: not supported right now. */
|
||||||
|
uint8_t group_mgmt_prot: 1; /**< Group addressed management frame protection. Reserved: not supported right now. */
|
||||||
|
uint8_t reserved: 6; /**< Reserved */
|
||||||
|
} wifi_nan_datapath_security_params_t;
|
||||||
|
|
||||||
/* NAN Peer info parsed from SDF */
|
/* NAN Peer info parsed from SDF */
|
||||||
struct nan_cb_peer_info {
|
struct nan_cb_peer_info {
|
||||||
uint8_t peer_mac[6]; /**< Peer NMI / interface MAC */
|
uint8_t peer_mac[6]; /**< Peer NMI / interface MAC */
|
||||||
@@ -48,10 +71,11 @@ struct nan_cb_peer_info {
|
|||||||
uint8_t ssi_ver; /**< SSI version (service_match) */
|
uint8_t ssi_ver; /**< SSI version (service_match) */
|
||||||
uint8_t *ssi; /**< Service-specific information */
|
uint8_t *ssi; /**< Service-specific information */
|
||||||
uint16_t ssi_len; /**< SSI length in bytes */
|
uint16_t ssi_len; /**< SSI length in bytes */
|
||||||
|
wifi_nan_discovery_security_params_t *peer_security_params; /**< Peer's discovery security params (cipher / PMKIDs) */
|
||||||
nan_vendor_ie_t *vendor_ie; /**< Vendor-specific IE, if any */
|
nan_vendor_ie_t *vendor_ie; /**< Vendor-specific IE, if any */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* NDP Peer info parsed from NAF */
|
/* NDP Peer info parsed from NAF. */
|
||||||
struct ndp_cb_peer_info {
|
struct ndp_cb_peer_info {
|
||||||
uint8_t ndp_id;
|
uint8_t ndp_id;
|
||||||
uint8_t peer_nmi[6];
|
uint8_t peer_nmi[6];
|
||||||
@@ -69,6 +93,95 @@ struct nan_sync_callbacks {
|
|||||||
uint8_t own_ndi[6], uint8_t ipv6_identifier[8]);
|
uint8_t own_ndi[6], uint8_t ipv6_identifier[8]);
|
||||||
void (* ndp_terminated)(uint8_t reason, uint8_t ndp_id, uint8_t init_ndi[6]);
|
void (* ndp_terminated)(uint8_t reason, uint8_t ndp_id, uint8_t init_ndi[6]);
|
||||||
void (* action_txdone)(uint32_t context, bool tx_status);
|
void (* action_txdone)(uint32_t context, bool tx_status);
|
||||||
|
/* Initiator-side M2 RX indication. Blob fires this after parsing the
|
||||||
|
* Responder NDI from the M2 NDP attribute (Wi-Fi Aware v4.0 §9.5.16.1
|
||||||
|
* Table 82) and before invoking esp_nan_verify_ndp_resp_mic, so the
|
||||||
|
* host can populate ndl->peer_ndi for spec-correct PTK derivation
|
||||||
|
* (§7.1.3.5: PTK uses Data Interface addresses). */
|
||||||
|
void (* ndp_response_indication)(struct ndp_cb_peer_info *peer_info);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Host helpers for NAN encrypted-datapath, registered via
|
||||||
|
* esp_nan_internal_register_secure_dp_funcs() at nan_app init.
|
||||||
|
* Security-gated fields are NULL when CONFIG_ESP_WIFI_NAN_SECURITY=n. */
|
||||||
|
struct nan_secure_dp_funcs {
|
||||||
|
/* === Always-present helpers === */
|
||||||
|
|
||||||
|
/* TX completion notification for M2/M4 frames */
|
||||||
|
void (*ndp_tx_done_cb)(uint8_t ndp_id, const uint8_t *peer_nmi,
|
||||||
|
uint8_t msg_type, bool tx_status);
|
||||||
|
|
||||||
|
/* === Security-gated helpers (24 fields, NULL when SECURITY=n) === */
|
||||||
|
|
||||||
|
/* Length getters */
|
||||||
|
uint32_t (*get_csia_len)(uint16_t own_csid_bitmap, uint16_t peer_csid_bitmap);
|
||||||
|
uint32_t (*get_scia_len)(uint8_t num_pmkids);
|
||||||
|
uint32_t (*get_shared_key_desc_attr_len)(uint16_t key_data_len);
|
||||||
|
int (*ndp_security_install_get_shared_desc_len)(void);
|
||||||
|
|
||||||
|
/* CSIA / SCIA construction (publish + NDP req/resp) */
|
||||||
|
int (*construct_csia)(uint8_t *frm, uint8_t pub_id,
|
||||||
|
uint16_t own_csid_bitmap, uint16_t peer_csid_bitmap);
|
||||||
|
int (*construct_scia_publish)(uint8_t *frm, uint8_t pub_id,
|
||||||
|
uint8_t num_pmkids,
|
||||||
|
const uint8_t pmkids[][ESP_WIFI_NAN_NDP_PMKID_LEN]);
|
||||||
|
int (*construct_scia_ndp_req)(uint8_t *frm, uint8_t ndp_id,
|
||||||
|
const uint8_t *peer_nmi);
|
||||||
|
int (*construct_scia_ndp_resp)(uint8_t *frm, uint8_t ndp_id,
|
||||||
|
const uint8_t *peer_nmi);
|
||||||
|
|
||||||
|
/* Shared Key Descriptor builders (M1 / M2 / M3 / M4) -- MIC left zeroed */
|
||||||
|
int (*get_ndp_req_shared_key_desc)(uint8_t *buf, size_t buf_len,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
int (*get_ndp_resp_shared_key_desc)(uint8_t *buf, size_t buf_len,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
int (*get_ndp_confirm_shared_key_desc)(uint8_t *buf, size_t buf_len,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
int (*get_ndp_security_install_key_desc)(uint8_t *buf, size_t buf_len,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
|
||||||
|
/* M1 Auth_Token capture (host stores SHA-256(M1_body)[0:16] for M3 MIC) */
|
||||||
|
int (*capture_m1_auth_token)(const uint8_t *m1_body, size_t body_len,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
|
||||||
|
/* MIC compute (TX path) -- fills MIC field in already-built key descriptor */
|
||||||
|
int (*update_ndp_resp_mic)(uint8_t *m2_body, size_t body_len,
|
||||||
|
uint8_t *key_desc_attr,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
int (*update_ndp_confirm_mic)(uint8_t *m3_body, size_t body_len,
|
||||||
|
uint8_t *key_desc_attr,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
int (*update_ndp_security_install_mic)(uint8_t *m4_body, size_t body_len,
|
||||||
|
uint8_t *key_desc_attr,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
|
||||||
|
/* MIC verify (RX path) -- 0 on pass, -1 on mismatch (caller tears down NDP) */
|
||||||
|
int (*verify_ndp_resp_mic)(uint8_t *m2_body, size_t body_len,
|
||||||
|
uint8_t *key_desc_attr,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
int (*verify_ndp_confirm_mic)(uint8_t *m3_body, size_t body_len,
|
||||||
|
uint8_t *key_desc_attr,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
int (*verify_ndp_security_install_mic)(uint8_t *m4_body, size_t body_len,
|
||||||
|
uint8_t *key_desc_attr,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
|
||||||
|
/* RX-path attribute parsers (CSIA / SCIA / key-desc). */
|
||||||
|
void (*parse_ndp_csia)(void *frm, size_t buf_len, wifi_nan_datapath_security_params_t *param);
|
||||||
|
void (*parse_ndp_scia)(void *frm, size_t buf_len, wifi_nan_datapath_security_params_t *param);
|
||||||
|
void (*parse_ndp_key_desc)(void *frm, size_t buf_len, uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
|
||||||
|
/* Publish-side security parser (called when blob processes inbound publish SDF) */
|
||||||
|
esp_err_t (*parse_publish_security)(const uint8_t *attrs, size_t attrs_len,
|
||||||
|
wifi_nan_discovery_security_params_t *security);
|
||||||
|
|
||||||
|
/* Publish-init helper -- derives ND-PMK / ND-PMKID from the publish cfg
|
||||||
|
* passphrase and stores them on the host service record. Result is
|
||||||
|
* unused when CONFIG_ESP_WIFI_NAN_SECURITY=n. */
|
||||||
|
esp_err_t (*derive_security_params)(wifi_nan_publish_cfg_t *cfg);
|
||||||
|
|
||||||
|
/* NDP security gate: cipher-suite bitmap for (ndp_id, peer_nmi), or 0 for open. */
|
||||||
|
uint16_t (*get_ndp_security_csid)(uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -810,6 +923,36 @@ esp_err_t esp_nan_internal_datapath_end(wifi_nan_datapath_end_req_t *req);
|
|||||||
*/
|
*/
|
||||||
esp_err_t esp_nan_internal_register_callbacks(struct nan_sync_callbacks *cb);
|
esp_err_t esp_nan_internal_register_callbacks(struct nan_sync_callbacks *cb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register the NAN secure-datapath helper table with the WiFi libraries.
|
||||||
|
*
|
||||||
|
* Pass a pointer to a static struct populated by the host; pass NULL to
|
||||||
|
* deregister at deinit time.
|
||||||
|
*
|
||||||
|
* @param fns Pointer to populated nan_secure_dp_funcs (or NULL to deregister)
|
||||||
|
* @return ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t esp_nan_internal_register_secure_dp_funcs(struct nan_secure_dp_funcs *fns);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Install NAN pairwise/group key into Wi-Fi firmware key table
|
||||||
|
*
|
||||||
|
|
||||||
|
* @param[in] alg Cipher algorithm identifier (for CCMP use 3)
|
||||||
|
* @param[in] addr Peer address used for key lookup (NDI for NAN data path)
|
||||||
|
* @param[in] key_idx Key index (use 0 for pairwise key)
|
||||||
|
* @param[in] set_tx Set key as TX key when non-zero
|
||||||
|
* @param[in] seq Initial sequence/RSC value (typically 8 bytes)
|
||||||
|
* @param[in] seq_len Length of seq in bytes
|
||||||
|
* @param[in] key Key material
|
||||||
|
* @param[in] key_len Key length in bytes
|
||||||
|
* @param[in] key_flag Key usage flags bitmask
|
||||||
|
*
|
||||||
|
* @return 0 on success, negative value on failure
|
||||||
|
*/
|
||||||
|
int esp_wifi_set_nan_key_internal(int alg, uint8_t *addr, int key_idx, int set_tx,
|
||||||
|
uint8_t *seq, size_t seq_len, uint8_t *key, size_t key_len, int key_flag);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Connect WiFi station to the AP.
|
* @brief Connect WiFi station to the AP.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define WIFI_AP_DEFAULT_MAX_IDLE_PERIOD 292 /**< Default timeout for SoftAP BSS Max Idle. Unit: 1000TUs >**/
|
#define WIFI_AP_DEFAULT_MAX_IDLE_PERIOD 292 /**< Default timeout for SoftAP BSS Max Idle. Unit: 1000TUs >**/
|
||||||
|
#define MAX_SSID_LEN 32 /**< Maximum length of SSID */
|
||||||
|
#define MAX_PASSPHRASE_LEN 64 /**< Maximum length of passphrase */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Wi-Fi mode type
|
* @brief Wi-Fi mode type
|
||||||
@@ -864,6 +866,10 @@ typedef struct {
|
|||||||
#define ESP_WIFI_NDP_ROLE_INITIATOR 1 /**< Initiator role for NAN Data Path */
|
#define ESP_WIFI_NDP_ROLE_INITIATOR 1 /**< Initiator role for NAN Data Path */
|
||||||
#define ESP_WIFI_NDP_ROLE_RESPONDER 2 /**< Responder role for NAN Data Path */
|
#define ESP_WIFI_NDP_ROLE_RESPONDER 2 /**< Responder role for NAN Data Path */
|
||||||
|
|
||||||
|
#define ESP_WIFI_NAN_NDP_PMK_LEN 32 /**< Length of NAN Datapath PMK */
|
||||||
|
#define ESP_WIFI_NAN_NDP_PMKID_LEN 16 /**< Length of NAN Datapath PMKID */
|
||||||
|
#define ESP_WIFI_NAN_MAX_PMKIDS 2 /**< Maximum number of PMKIDs supported */
|
||||||
|
|
||||||
#define ESP_WIFI_MAX_SVC_NAME_LEN 256 /**< Maximum length of NAN service name */
|
#define ESP_WIFI_MAX_SVC_NAME_LEN 256 /**< Maximum length of NAN service name */
|
||||||
#define ESP_WIFI_MAX_FILTER_LEN 256 /**< Maximum length of NAN service filter */
|
#define ESP_WIFI_MAX_FILTER_LEN 256 /**< Maximum length of NAN service filter */
|
||||||
#define ESP_WIFI_MAX_SVC_INFO_LEN 64 /**< Maximum length of NAN service info */
|
#define ESP_WIFI_MAX_SVC_INFO_LEN 64 /**< Maximum length of NAN service info */
|
||||||
@@ -905,6 +911,46 @@ typedef enum {
|
|||||||
NAN_SUBSCRIBE_PASSIVE, /**< Passively listens to Publish frames */
|
NAN_SUBSCRIBE_PASSIVE, /**< Passively listens to Publish frames */
|
||||||
} wifi_nan_service_type_t;
|
} wifi_nan_service_type_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief NAN Cipher Suite IDs (Spec 4.1.1 & 6.1.1)
|
||||||
|
*
|
||||||
|
* @note Only WIFI_NAN_CSID_NCS_SK_128 is currently supported by the firmware.
|
||||||
|
* The other values are reserved for future support; selecting any of
|
||||||
|
* them via csid_bitmap will cause esp_wifi_nan_publish_service() and
|
||||||
|
* esp_wifi_nan_subscribe_service() to fail.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
WIFI_NAN_CSID_NCS_SK_128 = 1, /**< NCS-SK-128 (PSK/Passphrase) */
|
||||||
|
WIFI_NAN_CSID_NCS_SK_256 = 2, /**< NCS-SK-256 (PSK/Passphrase). Reserved: not supported right now. */
|
||||||
|
WIFI_NAN_CSID_NCS_PK_2WDH_128 = 3, /**< NCS-PK-2WDH-128. Reserved: not supported right now. */
|
||||||
|
WIFI_NAN_CSID_NCS_PK_2WDH_256 = 4, /**< NCS-PK-2WDH-256. Reserved: not supported right now. */
|
||||||
|
WIFI_NAN_CSID_NCS_PK_PASN_128 = 7, /**< NCS-PK-PASN-128. Reserved: not supported right now. */
|
||||||
|
WIFI_NAN_CSID_NCS_PK_PASN_256 = 8, /**< NCS-PK-PASN-256. Reserved: not supported right now. */
|
||||||
|
} wifi_nan_cipher_suite_id_t;
|
||||||
|
|
||||||
|
#define WIFI_NAN_CSID_BIT_NCS_SK_128 (1 << WIFI_NAN_CSID_NCS_SK_128)
|
||||||
|
#define WIFI_NAN_CSID_BIT_NCS_SK_256 (1 << WIFI_NAN_CSID_NCS_SK_256)
|
||||||
|
#define WIFI_NAN_CSID_BIT_NCS_PK_2WDH_128 (1 << WIFI_NAN_CSID_NCS_PK_2WDH_128)
|
||||||
|
#define WIFI_NAN_CSID_BIT_NCS_PK_2WDH_256 (1 << WIFI_NAN_CSID_NCS_PK_2WDH_256)
|
||||||
|
#define WIFI_NAN_CSID_BIT_NCS_PK_PASN_128 (1 << WIFI_NAN_CSID_NCS_PK_PASN_128)
|
||||||
|
#define WIFI_NAN_CSID_BIT_NCS_PK_PASN_256 (1 << WIFI_NAN_CSID_NCS_PK_PASN_256)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief NAN Discovery security parameters (Spec 4.1.1 - Publish/Subscribe)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint16_t csid_bitmap; /**< Bitmap of Supported Cipher Suite IDs (WIFI_NAN_CSID_BIT_*) */
|
||||||
|
uint8_t num_pmkids; /**< Number of PMKIDs */
|
||||||
|
uint8_t pmkids[ESP_WIFI_NAN_MAX_PMKIDS][ESP_WIFI_NAN_NDP_PMKID_LEN]; /**< ND-PMKIDs */
|
||||||
|
uint8_t group_data_prot: 1; /**< Group addressed data frame protection. Reserved: not supported right now. */
|
||||||
|
uint8_t group_mgmt_prot: 1; /**< Group addressed management frame protection. Reserved: not supported right now. */
|
||||||
|
uint8_t use_pmk: 1; /**< 0 - Use passphrase, 1 - Use PMK directly */
|
||||||
|
uint8_t reserved: 5; /**< Reserved */
|
||||||
|
char passphrase[MAX_PASSPHRASE_LEN]; /**< NCS-SK passphrase (use_pmk=0). NUL-terminated. */
|
||||||
|
uint8_t pmk[ESP_WIFI_NAN_NDP_PMK_LEN]; /**< NCS-SK PMK (use_pmk=1). Raw bytes, not NUL-terminated. */
|
||||||
|
} wifi_nan_discovery_security_params_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief USD specific configuration parameters
|
* @brief USD specific configuration parameters
|
||||||
*
|
*
|
||||||
@@ -943,12 +989,14 @@ typedef struct {
|
|||||||
uint8_t fsd_gas: 1; /**< 0 - Follow-up used for FSD, 1 - GAS used for FSD */
|
uint8_t fsd_gas: 1; /**< 0 - Follow-up used for FSD, 1 - GAS used for FSD */
|
||||||
uint8_t ndp_resp_needed: 1; /**< 0 - Auto-Accept NDP Requests, 1 - Require explicit response with esp_wifi_nan_datapath_resp */
|
uint8_t ndp_resp_needed: 1; /**< 0 - Auto-Accept NDP Requests, 1 - Require explicit response with esp_wifi_nan_datapath_resp */
|
||||||
uint8_t usd_discovery_flag: 1; /**< 0 - NAN Synchronization for Discovery, 1 - USD for Discovery. 'NAN Discovery flag' from specification */
|
uint8_t usd_discovery_flag: 1; /**< 0 - NAN Synchronization for Discovery, 1 - USD for Discovery. 'NAN Discovery flag' from specification */
|
||||||
uint8_t reserved: 2; /**< Reserved */
|
uint8_t security_reqd: 1; /**< Security: 0 - Open, 1 - Required (NDP Security) */
|
||||||
|
uint8_t reserved: 1; /**< Reserved */
|
||||||
uint16_t ssi_len; /**< Length of service specific info, maximum allowed length - ESP_WIFI_MAX_SVC_SSI_LEN */
|
uint16_t ssi_len; /**< Length of service specific info, maximum allowed length - ESP_WIFI_MAX_SVC_SSI_LEN */
|
||||||
uint8_t *ssi; /**< Service Specific Info of type wifi_nan_wfa_ssi_t for WFA defined protocols, otherwise proprietary and defined by Applications */
|
uint8_t *ssi; /**< Service Specific Info of type wifi_nan_wfa_ssi_t for WFA defined protocols, otherwise proprietary and defined by Applications */
|
||||||
unsigned int ttl; /**< Run publish function for a given time interval in seconds. If ttl=0 and usd_discovery_flag is enabled,
|
unsigned int ttl; /**< Run publish function for a given time interval in seconds. If ttl=0 and usd_discovery_flag is enabled,
|
||||||
only one Publish message is transmitted */
|
only one Publish message is transmitted */
|
||||||
wifi_nan_usd_config_t usd_publish_config; /**< USD configuration parameters. Relevant only when 'usd_discovery_flag' is set. */
|
wifi_nan_usd_config_t usd_publish_config; /**< USD configuration parameters. Relevant only when 'usd_discovery_flag' is set. */
|
||||||
|
wifi_nan_discovery_security_params_t security_cfg; /**< Security configuration parameters */
|
||||||
nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in publish frames */
|
nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in publish frames */
|
||||||
} wifi_nan_publish_cfg_t;
|
} wifi_nan_publish_cfg_t;
|
||||||
|
|
||||||
@@ -965,12 +1013,14 @@ typedef struct {
|
|||||||
uint8_t fsd_reqd: 1; /**< Further Service Discovery(FSD) required */
|
uint8_t fsd_reqd: 1; /**< Further Service Discovery(FSD) required */
|
||||||
uint8_t fsd_gas: 1; /**< 0 - Follow-up used for FSD, 1 - GAS used for FSD */
|
uint8_t fsd_gas: 1; /**< 0 - Follow-up used for FSD, 1 - GAS used for FSD */
|
||||||
uint8_t usd_discovery_flag: 1; /**< 0 - NAN Synchronization for Discovery, 1 - USD for Discovery. 'NAN Discovery flag' from specification */
|
uint8_t usd_discovery_flag: 1; /**< 0 - NAN Synchronization for Discovery, 1 - USD for Discovery. 'NAN Discovery flag' from specification */
|
||||||
uint8_t reserved: 3; /**< Reserved */
|
uint8_t security_reqd: 1; /**< Security: 0 - Open, 1 - Required (NDP Security) */
|
||||||
|
uint8_t reserved: 2; /**< Reserved */
|
||||||
uint16_t ssi_len; /**< Length of service specific info, maximum allowed length - ESP_WIFI_MAX_SVC_SSI_LEN */
|
uint16_t ssi_len; /**< Length of service specific info, maximum allowed length - ESP_WIFI_MAX_SVC_SSI_LEN */
|
||||||
uint8_t *ssi; /**< Service Specific Info of type wifi_nan_wfa_ssi_t for WFA defined protocols, otherwise proprietary and defined by Applications */
|
uint8_t *ssi; /**< Service Specific Info of type wifi_nan_wfa_ssi_t for WFA defined protocols, otherwise proprietary and defined by Applications */
|
||||||
unsigned int ttl; /**< Run subscribe function for a given time interval in seconds. If ttl=0 and usd_discovery_flag is enabled,
|
unsigned int ttl; /**< Run subscribe function for a given time interval in seconds. If ttl=0 and usd_discovery_flag is enabled,
|
||||||
the subscriber listens until the first service match is reported. */
|
the subscriber listens until the first service match is reported. */
|
||||||
wifi_nan_usd_config_t usd_subscribe_config; /**< USD configuration parameters. Relevant only when 'usd_discovery_flag' is set. */
|
wifi_nan_usd_config_t usd_subscribe_config; /**< USD configuration parameters. Relevant only when 'usd_discovery_flag' is set. */
|
||||||
|
wifi_nan_discovery_security_params_t security_cfg; /**< Security configuration parameters */
|
||||||
nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in subscribe frames */
|
nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in subscribe frames */
|
||||||
} wifi_nan_subscribe_cfg_t;
|
} wifi_nan_subscribe_cfg_t;
|
||||||
|
|
||||||
@@ -990,16 +1040,28 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* @brief NAN Datapath Request parameters
|
* @brief NAN Datapath Request parameters
|
||||||
*
|
*
|
||||||
|
* @note Datapath security is governed by the security_cfg passed to
|
||||||
|
* esp_wifi_nan_subscribe_service(); the NAN library derives ND-PMK,
|
||||||
|
* ND-PMKID and cipher selection internally from that subscribe-time
|
||||||
|
* configuration and applies them to every NDP initiated against the
|
||||||
|
* matched publisher. Per-NDP security parameters are not exposed on
|
||||||
|
* this struct: the caller never handles raw key material.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t pub_id; /**< Publisher's service instance id */
|
uint8_t pub_id; /**< Publisher's service instance id */
|
||||||
uint8_t peer_mac[6]; /**< Peer's MAC address */
|
uint8_t peer_mac[6]; /**< Peer's MAC address */
|
||||||
bool confirm_required; /**< NDP Confirm frame required */
|
bool confirm_required; /**< NDP Confirm frame required. Always used for the secure NDP handshake. */
|
||||||
} wifi_nan_datapath_req_t;
|
} wifi_nan_datapath_req_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief NAN Datapath Response parameters
|
* @brief NAN Datapath Response parameters
|
||||||
*
|
*
|
||||||
|
* @note Datapath security is governed by the security_cfg passed to
|
||||||
|
* esp_wifi_nan_publish_service(); the NAN library derives ND-PMK,
|
||||||
|
* ND-PMKID and cipher selection internally from that publish-time
|
||||||
|
* configuration and applies them to every NDP this responder
|
||||||
|
* accepts. Per-NDP security parameters are not exposed on this
|
||||||
|
* struct: the caller never handles raw key material.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool accept; /**< True - Accept incoming NDP, False - Reject it */
|
bool accept; /**< True - Accept incoming NDP, False - Reject it */
|
||||||
@@ -1230,8 +1292,6 @@ typedef enum {
|
|||||||
WPS_FAIL_REASON_MAX /**< Max WPS fail reason */
|
WPS_FAIL_REASON_MAX /**< Max WPS fail reason */
|
||||||
} wifi_event_sta_wps_fail_reason_t;
|
} wifi_event_sta_wps_fail_reason_t;
|
||||||
|
|
||||||
#define MAX_SSID_LEN 32 /**< Maximum length of SSID */
|
|
||||||
#define MAX_PASSPHRASE_LEN 64 /**< Maximum length of passphrase */
|
|
||||||
#define MAX_WPS_AP_CRED 3 /**< Maximum number of AP credentials received from WPS handshake */
|
#define MAX_WPS_AP_CRED 3 /**< Maximum number of AP credentials received from WPS handshake */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1412,7 +1472,8 @@ typedef struct {
|
|||||||
uint8_t fsd_reqd: 1; /**< Further Service Discovery(FSD) required */
|
uint8_t fsd_reqd: 1; /**< Further Service Discovery(FSD) required */
|
||||||
uint8_t fsd_gas: 1; /**< 0 - Follow-up used for FSD, 1 - GAS used for FSD */
|
uint8_t fsd_gas: 1; /**< 0 - Follow-up used for FSD, 1 - GAS used for FSD */
|
||||||
uint8_t ndpe_support: 1; /**< NDPE supported by peer */
|
uint8_t ndpe_support: 1; /**< NDPE supported by peer */
|
||||||
uint8_t reserved: 4; /**< Reserved */
|
uint8_t security_reqd: 1; /**< Security: 0 - Open, 1 - Required (NDP Security) */
|
||||||
|
uint8_t reserved: 3; /**< Reserved */
|
||||||
uint32_t reserved_1; /**< Reserved */
|
uint32_t reserved_1; /**< Reserved */
|
||||||
uint32_t reserved_2; /**< Reserved */
|
uint32_t reserved_2; /**< Reserved */
|
||||||
uint8_t ssi_version; /**< Indicates version of SSI in Publish instance, 0 if not available */
|
uint8_t ssi_version; /**< Indicates version of SSI in Publish instance, 0 if not available */
|
||||||
|
|||||||
+1
-1
Submodule components/esp_wifi/lib updated: 4bc9760929...bf7ccb11fe
@@ -572,6 +572,23 @@ config WIFI_RMT_NAN_SYNC_ENABLE
|
|||||||
help
|
help
|
||||||
Enable Wi-Fi Aware: Synchronization feature (NAN-Sync).
|
Enable Wi-Fi Aware: Synchronization feature (NAN-Sync).
|
||||||
|
|
||||||
|
config WIFI_RMT_NAN_SECURITY
|
||||||
|
bool "Enable Wi-Fi Aware: Encrypted Pairwise Datapath (NDP Security)"
|
||||||
|
depends on WIFI_RMT_NAN_SYNC_ENABLE && IDF_EXPERIMENTAL_FEATURES && WIFI_RMT_MBEDTLS_CRYPTO
|
||||||
|
select MBEDTLS_PKCS5_C
|
||||||
|
select MBEDTLS_SHA256_C
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Enable encrypted pairwise datapath for Wi-Fi Aware (NAN).
|
||||||
|
Adds PBKDF2 key derivation (mbedTLS PKCS#5), 4-way handshake (M1-M4),
|
||||||
|
PTK derivation, and CCMP key installation for secured NAN
|
||||||
|
data links. Disable to save code size when only open
|
||||||
|
datapaths are needed.
|
||||||
|
|
||||||
|
Requires WIFI_RMT_MBEDTLS_CRYPTO + MBEDTLS_PKCS5_C + MBEDTLS_SHA256_C
|
||||||
|
for ND-PMK derivation via pbkdf2_sha256() (MBEDTLS_MD_C is pulled in
|
||||||
|
transitively by MBEDTLS_PKCS5_C).
|
||||||
|
|
||||||
config WIFI_RMT_NAN_USD_ENABLE
|
config WIFI_RMT_NAN_USD_ENABLE
|
||||||
bool "Enable Wi-Fi Aware: Unsynchronized service discovery (NAN-USD)"
|
bool "Enable Wi-Fi Aware: Unsynchronized service discovery (NAN-USD)"
|
||||||
depends on IDF_EXPERIMENTAL_FEATURES
|
depends on IDF_EXPERIMENTAL_FEATURES
|
||||||
|
|||||||
@@ -290,6 +290,13 @@ if WIFI_RMT_NAN_SYNC_ENABLE
|
|||||||
default WIFI_RMT_NAN_SYNC_ENABLE
|
default WIFI_RMT_NAN_SYNC_ENABLE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if WIFI_RMT_NAN_SECURITY
|
||||||
|
config ESP_WIFI_NAN_SECURITY # ignore: multiple-definition
|
||||||
|
bool
|
||||||
|
depends on WIFI_RMT_NAN_SYNC_ENABLE && IDF_EXPERIMENTAL_FEATURES && WIFI_RMT_MBEDTLS_CRYPTO
|
||||||
|
default WIFI_RMT_NAN_SECURITY
|
||||||
|
endif
|
||||||
|
|
||||||
if WIFI_RMT_NAN_USD_ENABLE
|
if WIFI_RMT_NAN_USD_ENABLE
|
||||||
config ESP_WIFI_NAN_USD_ENABLE # ignore: multiple-definition
|
config ESP_WIFI_NAN_USD_ENABLE # ignore: multiple-definition
|
||||||
bool
|
bool
|
||||||
|
|||||||
@@ -864,6 +864,10 @@ typedef struct {
|
|||||||
#define ESP_WIFI_NDP_ROLE_INITIATOR 1 /**< Initiator role for NAN Data Path */
|
#define ESP_WIFI_NDP_ROLE_INITIATOR 1 /**< Initiator role for NAN Data Path */
|
||||||
#define ESP_WIFI_NDP_ROLE_RESPONDER 2 /**< Responder role for NAN Data Path */
|
#define ESP_WIFI_NDP_ROLE_RESPONDER 2 /**< Responder role for NAN Data Path */
|
||||||
|
|
||||||
|
#define ESP_WIFI_NAN_NDP_PMK_LEN 32 /**< Length of NAN Datapath PMK */
|
||||||
|
#define ESP_WIFI_NAN_NDP_PMKID_LEN 16 /**< Length of NAN Datapath PMKID */
|
||||||
|
#define ESP_WIFI_NAN_MAX_PMKIDS 2 /**< Maximum number of PMKIDs supported */
|
||||||
|
|
||||||
#define ESP_WIFI_MAX_SVC_NAME_LEN 256 /**< Maximum length of NAN service name */
|
#define ESP_WIFI_MAX_SVC_NAME_LEN 256 /**< Maximum length of NAN service name */
|
||||||
#define ESP_WIFI_MAX_FILTER_LEN 256 /**< Maximum length of NAN service filter */
|
#define ESP_WIFI_MAX_FILTER_LEN 256 /**< Maximum length of NAN service filter */
|
||||||
#define ESP_WIFI_MAX_SVC_INFO_LEN 64 /**< Maximum length of NAN service info */
|
#define ESP_WIFI_MAX_SVC_INFO_LEN 64 /**< Maximum length of NAN service info */
|
||||||
@@ -905,6 +909,46 @@ typedef enum {
|
|||||||
NAN_SUBSCRIBE_PASSIVE, /**< Passively listens to Publish frames */
|
NAN_SUBSCRIBE_PASSIVE, /**< Passively listens to Publish frames */
|
||||||
} wifi_nan_service_type_t;
|
} wifi_nan_service_type_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief NAN Cipher Suite IDs (Spec 4.1.1 & 6.1.1)
|
||||||
|
*
|
||||||
|
* @note Only WIFI_NAN_CSID_NCS_SK_128 is currently supported by the firmware.
|
||||||
|
* The other values are reserved for future support; selecting any of
|
||||||
|
* them via csid_bitmap will cause esp_wifi_nan_publish_service() and
|
||||||
|
* esp_wifi_nan_subscribe_service() to fail.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
WIFI_NAN_CSID_NCS_SK_128 = 1, /**< NCS-SK-128 (PSK/Passphrase) */
|
||||||
|
WIFI_NAN_CSID_NCS_SK_256 = 2, /**< NCS-SK-256 (PSK/Passphrase). Reserved: not supported right now. */
|
||||||
|
WIFI_NAN_CSID_NCS_PK_2WDH_128 = 3, /**< NCS-PK-2WDH-128. Reserved: not supported right now. */
|
||||||
|
WIFI_NAN_CSID_NCS_PK_2WDH_256 = 4, /**< NCS-PK-2WDH-256. Reserved: not supported right now. */
|
||||||
|
WIFI_NAN_CSID_NCS_PK_PASN_128 = 7, /**< NCS-PK-PASN-128. Reserved: not supported right now. */
|
||||||
|
WIFI_NAN_CSID_NCS_PK_PASN_256 = 8, /**< NCS-PK-PASN-256. Reserved: not supported right now. */
|
||||||
|
} wifi_nan_cipher_suite_id_t;
|
||||||
|
|
||||||
|
#define WIFI_NAN_CSID_BIT_NCS_SK_128 (1 << WIFI_NAN_CSID_NCS_SK_128)
|
||||||
|
#define WIFI_NAN_CSID_BIT_NCS_SK_256 (1 << WIFI_NAN_CSID_NCS_SK_256)
|
||||||
|
#define WIFI_NAN_CSID_BIT_NCS_PK_2WDH_128 (1 << WIFI_NAN_CSID_NCS_PK_2WDH_128)
|
||||||
|
#define WIFI_NAN_CSID_BIT_NCS_PK_2WDH_256 (1 << WIFI_NAN_CSID_NCS_PK_2WDH_256)
|
||||||
|
#define WIFI_NAN_CSID_BIT_NCS_PK_PASN_128 (1 << WIFI_NAN_CSID_NCS_PK_PASN_128)
|
||||||
|
#define WIFI_NAN_CSID_BIT_NCS_PK_PASN_256 (1 << WIFI_NAN_CSID_NCS_PK_PASN_256)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief NAN Discovery security parameters (Spec 4.1.1 - Publish/Subscribe)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint16_t csid_bitmap; /**< Bitmap of Supported Cipher Suite IDs (WIFI_NAN_CSID_BIT_*) */
|
||||||
|
uint8_t num_pmkids; /**< Number of PMKIDs */
|
||||||
|
uint8_t pmkids[ESP_WIFI_NAN_MAX_PMKIDS][ESP_WIFI_NAN_NDP_PMKID_LEN]; /**< ND-PMKIDs */
|
||||||
|
uint8_t group_data_prot: 1; /**< Group addressed data frame protection. Reserved: not supported right now. */
|
||||||
|
uint8_t group_mgmt_prot: 1; /**< Group addressed management frame protection. Reserved: not supported right now. */
|
||||||
|
uint8_t use_pmk: 1; /**< 0 - Use passphrase, 1 - Use PMK directly */
|
||||||
|
uint8_t reserved: 5; /**< Reserved */
|
||||||
|
char passphrase[MAX_PASSPHRASE_LEN]; /**< NCS-SK passphrase (use_pmk=0). NUL-terminated. */
|
||||||
|
uint8_t pmk[ESP_WIFI_NAN_NDP_PMK_LEN]; /**< NCS-SK PMK (use_pmk=1). Raw bytes, not NUL-terminated. */
|
||||||
|
} wifi_nan_discovery_security_params_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief USD specific configuration parameters
|
* @brief USD specific configuration parameters
|
||||||
*
|
*
|
||||||
@@ -943,12 +987,14 @@ typedef struct {
|
|||||||
uint8_t fsd_gas: 1; /**< 0 - Follow-up used for FSD, 1 - GAS used for FSD */
|
uint8_t fsd_gas: 1; /**< 0 - Follow-up used for FSD, 1 - GAS used for FSD */
|
||||||
uint8_t ndp_resp_needed: 1; /**< 0 - Auto-Accept NDP Requests, 1 - Require explicit response with esp_wifi_nan_datapath_resp */
|
uint8_t ndp_resp_needed: 1; /**< 0 - Auto-Accept NDP Requests, 1 - Require explicit response with esp_wifi_nan_datapath_resp */
|
||||||
uint8_t usd_discovery_flag: 1; /**< 0 - NAN Synchronization for Discovery, 1 - USD for Discovery. 'NAN Discovery flag' from specification */
|
uint8_t usd_discovery_flag: 1; /**< 0 - NAN Synchronization for Discovery, 1 - USD for Discovery. 'NAN Discovery flag' from specification */
|
||||||
uint8_t reserved: 2; /**< Reserved */
|
uint8_t security_reqd: 1; /**< Security: 0 - Open, 1 - Required (NDP Security) */
|
||||||
|
uint8_t reserved: 1; /**< Reserved */
|
||||||
uint16_t ssi_len; /**< Length of service specific info, maximum allowed length - ESP_WIFI_MAX_SVC_SSI_LEN */
|
uint16_t ssi_len; /**< Length of service specific info, maximum allowed length - ESP_WIFI_MAX_SVC_SSI_LEN */
|
||||||
uint8_t *ssi; /**< Service Specific Info of type wifi_nan_wfa_ssi_t for WFA defined protocols, otherwise proprietary and defined by Applications */
|
uint8_t *ssi; /**< Service Specific Info of type wifi_nan_wfa_ssi_t for WFA defined protocols, otherwise proprietary and defined by Applications */
|
||||||
unsigned int ttl; /**< Run publish function for a given time interval in seconds. If ttl=0 and usd_discovery_flag is enabled,
|
unsigned int ttl; /**< Run publish function for a given time interval in seconds. If ttl=0 and usd_discovery_flag is enabled,
|
||||||
only one Publish message is transmitted */
|
only one Publish message is transmitted */
|
||||||
wifi_nan_usd_config_t usd_publish_config; /**< USD configuration parameters. Relevant only when 'usd_discovery_flag' is set. */
|
wifi_nan_usd_config_t usd_publish_config; /**< USD configuration parameters. Relevant only when 'usd_discovery_flag' is set. */
|
||||||
|
wifi_nan_discovery_security_params_t security_cfg; /**< Security configuration parameters */
|
||||||
nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in publish frames */
|
nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in publish frames */
|
||||||
} wifi_nan_publish_cfg_t;
|
} wifi_nan_publish_cfg_t;
|
||||||
|
|
||||||
@@ -965,12 +1011,14 @@ typedef struct {
|
|||||||
uint8_t fsd_reqd: 1; /**< Further Service Discovery(FSD) required */
|
uint8_t fsd_reqd: 1; /**< Further Service Discovery(FSD) required */
|
||||||
uint8_t fsd_gas: 1; /**< 0 - Follow-up used for FSD, 1 - GAS used for FSD */
|
uint8_t fsd_gas: 1; /**< 0 - Follow-up used for FSD, 1 - GAS used for FSD */
|
||||||
uint8_t usd_discovery_flag: 1; /**< 0 - NAN Synchronization for Discovery, 1 - USD for Discovery. 'NAN Discovery flag' from specification */
|
uint8_t usd_discovery_flag: 1; /**< 0 - NAN Synchronization for Discovery, 1 - USD for Discovery. 'NAN Discovery flag' from specification */
|
||||||
uint8_t reserved: 3; /**< Reserved */
|
uint8_t security_reqd: 1; /**< Security: 0 - Open, 1 - Required (NDP Security) */
|
||||||
|
uint8_t reserved: 2; /**< Reserved */
|
||||||
uint16_t ssi_len; /**< Length of service specific info, maximum allowed length - ESP_WIFI_MAX_SVC_SSI_LEN */
|
uint16_t ssi_len; /**< Length of service specific info, maximum allowed length - ESP_WIFI_MAX_SVC_SSI_LEN */
|
||||||
uint8_t *ssi; /**< Service Specific Info of type wifi_nan_wfa_ssi_t for WFA defined protocols, otherwise proprietary and defined by Applications */
|
uint8_t *ssi; /**< Service Specific Info of type wifi_nan_wfa_ssi_t for WFA defined protocols, otherwise proprietary and defined by Applications */
|
||||||
unsigned int ttl; /**< Run subscribe function for a given time interval in seconds. If ttl=0 and usd_discovery_flag is enabled,
|
unsigned int ttl; /**< Run subscribe function for a given time interval in seconds. If ttl=0 and usd_discovery_flag is enabled,
|
||||||
the subscriber listens until the first service match is reported. */
|
the subscriber listens until the first service match is reported. */
|
||||||
wifi_nan_usd_config_t usd_subscribe_config; /**< USD configuration parameters. Relevant only when 'usd_discovery_flag' is set. */
|
wifi_nan_usd_config_t usd_subscribe_config; /**< USD configuration parameters. Relevant only when 'usd_discovery_flag' is set. */
|
||||||
|
wifi_nan_discovery_security_params_t security_cfg; /**< Security configuration parameters */
|
||||||
nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in subscribe frames */
|
nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in subscribe frames */
|
||||||
} wifi_nan_subscribe_cfg_t;
|
} wifi_nan_subscribe_cfg_t;
|
||||||
|
|
||||||
@@ -990,16 +1038,28 @@ typedef struct {
|
|||||||
/**
|
/**
|
||||||
* @brief NAN Datapath Request parameters
|
* @brief NAN Datapath Request parameters
|
||||||
*
|
*
|
||||||
|
* @note Datapath security is governed by the security_cfg passed to
|
||||||
|
* esp_wifi_nan_subscribe_service(); the NAN library derives ND-PMK,
|
||||||
|
* ND-PMKID and cipher selection internally from that subscribe-time
|
||||||
|
* configuration and applies them to every NDP initiated against the
|
||||||
|
* matched publisher. Per-NDP security parameters are not exposed on
|
||||||
|
* this struct: the caller never handles raw key material.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t pub_id; /**< Publisher's service instance id */
|
uint8_t pub_id; /**< Publisher's service instance id */
|
||||||
uint8_t peer_mac[6]; /**< Peer's MAC address */
|
uint8_t peer_mac[6]; /**< Peer's MAC address */
|
||||||
bool confirm_required; /**< NDP Confirm frame required */
|
bool confirm_required; /**< NDP Confirm frame required. Always used for the secure NDP handshake. */
|
||||||
} wifi_nan_datapath_req_t;
|
} wifi_nan_datapath_req_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief NAN Datapath Response parameters
|
* @brief NAN Datapath Response parameters
|
||||||
*
|
*
|
||||||
|
* @note Datapath security is governed by the security_cfg passed to
|
||||||
|
* esp_wifi_nan_publish_service(); the NAN library derives ND-PMK,
|
||||||
|
* ND-PMKID and cipher selection internally from that publish-time
|
||||||
|
* configuration and applies them to every NDP this responder
|
||||||
|
* accepts. Per-NDP security parameters are not exposed on this
|
||||||
|
* struct: the caller never handles raw key material.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool accept; /**< True - Accept incoming NDP, False - Reject it */
|
bool accept; /**< True - Accept incoming NDP, False - Reject it */
|
||||||
@@ -1412,7 +1472,8 @@ typedef struct {
|
|||||||
uint8_t fsd_reqd: 1; /**< Further Service Discovery(FSD) required */
|
uint8_t fsd_reqd: 1; /**< Further Service Discovery(FSD) required */
|
||||||
uint8_t fsd_gas: 1; /**< 0 - Follow-up used for FSD, 1 - GAS used for FSD */
|
uint8_t fsd_gas: 1; /**< 0 - Follow-up used for FSD, 1 - GAS used for FSD */
|
||||||
uint8_t ndpe_support: 1; /**< NDPE supported by peer */
|
uint8_t ndpe_support: 1; /**< NDPE supported by peer */
|
||||||
uint8_t reserved: 4; /**< Reserved */
|
uint8_t security_reqd: 1; /**< Security: 0 - Open, 1 - Required (NDP Security) */
|
||||||
|
uint8_t reserved: 3; /**< Reserved */
|
||||||
uint32_t reserved_1; /**< Reserved */
|
uint32_t reserved_1; /**< Reserved */
|
||||||
uint32_t reserved_2; /**< Reserved */
|
uint32_t reserved_2; /**< Reserved */
|
||||||
uint8_t ssi_version; /**< Indicates version of SSI in Publish instance, 0 if not available */
|
uint8_t ssi_version; /**< Indicates version of SSI in Publish instance, 0 if not available */
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ extern "C" {
|
|||||||
#define IS_ZERO_NAN_ADDR_ID(a) (!((a)[0] | (a)[1] | (a)[2] | (a)[3] | \
|
#define IS_ZERO_NAN_ADDR_ID(a) (!((a)[0] | (a)[1] | (a)[2] | (a)[3] | \
|
||||||
(a)[4] | (a)[5] | (a)[6] | (a)[7]))
|
(a)[4] | (a)[5] | (a)[6] | (a)[7]))
|
||||||
|
|
||||||
|
#define NAN_IPV6_ADDR_ID_LEN 8
|
||||||
|
|
||||||
#define ESP_NAN_SET_IPV6_LINKLOCAL_FROM_IDENTIFIER(_target_addr, _identifier) \
|
#define ESP_NAN_SET_IPV6_LINKLOCAL_FROM_IDENTIFIER(_target_addr, _identifier) \
|
||||||
do { \
|
do { \
|
||||||
(_target_addr).type = IPADDR_TYPE_V6; \
|
(_target_addr).type = IPADDR_TYPE_V6; \
|
||||||
@@ -85,7 +87,7 @@ esp_err_t esp_wifi_nan_sync_stop(void);
|
|||||||
*
|
*
|
||||||
* @attention This API should be called by the Subscriber after a match occurs with a Publisher.
|
* @attention This API should be called by the Subscriber after a match occurs with a Publisher.
|
||||||
*
|
*
|
||||||
* @param req NAN Datapath Request parameters.
|
* @param req NAN Datapath Request parameters
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - non-zero NAN Datapath identifier: If NAN datapath req was accepted by publisher
|
* - non-zero NAN Datapath identifier: If NAN datapath req was accepted by publisher
|
||||||
@@ -99,7 +101,7 @@ uint8_t esp_wifi_nan_datapath_req(wifi_nan_datapath_req_t *req);
|
|||||||
* @attention This API should be called if ndp_resp_needed is set 1 in wifi_nan_publish_cfg_t and
|
* @attention This API should be called if ndp_resp_needed is set 1 in wifi_nan_publish_cfg_t and
|
||||||
* a WIFI_EVENT_NDP_INDICATION event is received due to an incoming NDP request.
|
* a WIFI_EVENT_NDP_INDICATION event is received due to an incoming NDP request.
|
||||||
*
|
*
|
||||||
* @param resp NAN Datapath Response parameters.
|
* @param resp NAN Datapath Response parameters
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: succeed
|
* - ESP_OK: succeed
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include "esp_wifi.h"
|
#include "esp_wifi.h"
|
||||||
#include "esp_private/wifi.h"
|
#include "esp_private/wifi.h"
|
||||||
#include "esp_wifi_netif.h"
|
#include "esp_wifi_netif.h"
|
||||||
@@ -17,6 +18,7 @@
|
|||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "esp_nan.h"
|
#include "esp_nan.h"
|
||||||
#include "utils/common.h"
|
#include "utils/common.h"
|
||||||
|
#include "nan_i.h"
|
||||||
#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE
|
#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE
|
||||||
#include "esp_private/esp_nan_usd.h"
|
#include "esp_private/esp_nan_usd.h"
|
||||||
#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */
|
#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */
|
||||||
@@ -38,21 +40,18 @@
|
|||||||
|
|
||||||
/* Macros */
|
/* Macros */
|
||||||
#define MACADDR_LEN 6
|
#define MACADDR_LEN 6
|
||||||
#define MACADDR_EQUAL(a1, a2) (memcmp(a1, a2, MACADDR_LEN))
|
#define MACADDR_EQUAL(a1, a2) (memcmp(a1, a2, MACADDR_LEN) == 0)
|
||||||
#define MACADDR_COPY(dst, src) (memcpy(dst, src, MACADDR_LEN))
|
#define MACADDR_COPY(dst, src) (memcpy(dst, src, MACADDR_LEN))
|
||||||
#define NAN_DW_INTVL_MS 524 /* NAN DW interval (512 TU's ~= 524 mSec) */
|
#define NAN_DW_INTVL_MS 524 /* NAN DW interval (512 TU's ~= 524 mSec) */
|
||||||
#define NAN_ACTION_TIMEOUT 4*NAN_DW_INTVL_MS
|
#define NAN_ACTION_TIMEOUT 4*NAN_DW_INTVL_MS
|
||||||
|
|
||||||
#define NAN_DATA_LOCK() os_mutex_lock(s_nan_data_lock)
|
|
||||||
#define NAN_DATA_UNLOCK() os_mutex_unlock(s_nan_data_lock)
|
|
||||||
|
|
||||||
/* Global Variables */
|
/* Global Variables */
|
||||||
static const char *TAG = "nan_app";
|
static const char *TAG = "nan_app";
|
||||||
#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE
|
#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE
|
||||||
static EventGroupHandle_t nan_event_group;
|
static EventGroupHandle_t nan_event_group;
|
||||||
static bool s_app_default_handlers_set = false;
|
static bool s_app_default_handlers_set = false;
|
||||||
static uint8_t null_mac[MACADDR_LEN] = {0};
|
static uint8_t null_mac[MACADDR_LEN] = {0};
|
||||||
static void *s_nan_data_lock = NULL;
|
void *s_nan_data_lock = NULL; /* extern in nan_i.h */
|
||||||
static uint32_t s_fup_context;
|
static uint32_t s_fup_context;
|
||||||
#endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */
|
#endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */
|
||||||
#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE
|
#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE
|
||||||
@@ -64,48 +63,12 @@ static const uint8_t s_wfa_oui[3] = {0x50, 0x6f, 0x9a};
|
|||||||
#define NAN_SDEA_CTRL_FSD_REQD BIT(0)
|
#define NAN_SDEA_CTRL_FSD_REQD BIT(0)
|
||||||
#define NAN_SDEA_CTRL_FSD_GAS BIT(1)
|
#define NAN_SDEA_CTRL_FSD_GAS BIT(1)
|
||||||
#define NAN_SDEA_CTRL_DATAPATH_REQD BIT(2)
|
#define NAN_SDEA_CTRL_DATAPATH_REQD BIT(2)
|
||||||
|
#define NAN_SDEA_CTRL_SECURITY_REQD BIT(6)
|
||||||
|
|
||||||
#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE
|
#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE
|
||||||
#define NAN_DATA_LOCK() os_mutex_lock(s_nan_data_lock)
|
|
||||||
#define NAN_DATA_UNLOCK() os_mutex_unlock(s_nan_data_lock)
|
|
||||||
|
|
||||||
struct peer_svc_info {
|
/* Definition of nan_ctx_t storage shared via nan_i.h. */
|
||||||
SLIST_ENTRY(peer_svc_info) next;
|
nan_ctx_t s_nan_ctx;
|
||||||
uint8_t peer_svc_info[ESP_WIFI_MAX_SVC_INFO_LEN]; /**< Information for followup message */
|
|
||||||
uint8_t svc_id; /**< Identifier of peer's service */
|
|
||||||
uint8_t own_svc_id; /**< Identifier for own service */
|
|
||||||
uint8_t type; /**< Service type (Publish/Subscribe) */
|
|
||||||
uint8_t peer_nmi[MACADDR_LEN]; /**< Peer's NAN Management Interface address */
|
|
||||||
uint32_t device_caps;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct own_svc_info {
|
|
||||||
char svc_name[ESP_WIFI_MAX_SVC_NAME_LEN]; /**< Name identifying a service */
|
|
||||||
uint8_t svc_id; /**< Identifier for a service */
|
|
||||||
uint8_t type; /**< Service type (Publish/Subscribe) */
|
|
||||||
bool ndp_resp_needed; /**< If enabled, NDP response is required */
|
|
||||||
uint8_t num_peer_records; /**< Count of peer records associated with svc_id */
|
|
||||||
SLIST_HEAD(peer_list_t, peer_svc_info) peer_list; /**< List of peers matched for specific service */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ndl_info {
|
|
||||||
uint8_t ndp_id; /**< Identifier for instance of NDP */
|
|
||||||
uint8_t peer_ndi[MACADDR_LEN]; /**< Peer's NAN Data Interface address */
|
|
||||||
uint8_t peer_nmi[MACADDR_LEN]; /**< Peer's NAN Management Interface address */
|
|
||||||
uint8_t publisher_id; /**< Publisher's service identifier */
|
|
||||||
uint8_t own_role; /**< Own role (Publisher/Subscriber) */
|
|
||||||
uint32_t device_caps; /**< Peer's Device Capabilities from NDP Indication/Confirm */
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t state;
|
|
||||||
uint8_t event;
|
|
||||||
struct ndl_info ndl[ESP_WIFI_NAN_DATAPATH_MAX_PEERS]; /**< Record of NDL of all peers */
|
|
||||||
struct own_svc_info own_svc[ESP_WIFI_NAN_MAX_SVC_SUPPORTED]; /**< Record of own service(s) */
|
|
||||||
esp_netif_t *nan_netif;
|
|
||||||
} nan_ctx_t;
|
|
||||||
|
|
||||||
static nan_ctx_t s_nan_ctx;
|
|
||||||
|
|
||||||
void esp_wifi_nan_get_ipv6_linklocal_from_mac(ip6_addr_t *ip6, uint8_t *mac_addr)
|
void esp_wifi_nan_get_ipv6_linklocal_from_mac(ip6_addr_t *ip6, uint8_t *mac_addr)
|
||||||
{
|
{
|
||||||
@@ -129,7 +92,7 @@ void esp_wifi_nan_get_ipv6_linklocal_from_mac(ip6_addr_t *ip6, uint8_t *mac_addr
|
|||||||
ip6->zone = IP6_NO_ZONE;
|
ip6->zone = IP6_NO_ZONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct own_svc_info *nan_find_own_svc(uint8_t svc_id)
|
struct own_svc_info *nan_find_own_svc(uint8_t svc_id)
|
||||||
{
|
{
|
||||||
struct own_svc_info *p_svc = NULL;
|
struct own_svc_info *p_svc = NULL;
|
||||||
|
|
||||||
@@ -174,7 +137,7 @@ static struct peer_svc_info *nan_find_peer_svc(uint8_t own_svc_id, uint8_t peer_
|
|||||||
uint8_t *peer_nmi_valid = NULL;
|
uint8_t *peer_nmi_valid = NULL;
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
|
|
||||||
if (MACADDR_EQUAL(peer_nmi, null_mac)) {
|
if (!MACADDR_EQUAL(peer_nmi, null_mac)) {
|
||||||
/* non-zero Peer NMI given, use it */
|
/* non-zero Peer NMI given, use it */
|
||||||
peer_nmi_valid = peer_nmi;
|
peer_nmi_valid = peer_nmi;
|
||||||
}
|
}
|
||||||
@@ -190,7 +153,7 @@ static struct peer_svc_info *nan_find_peer_svc(uint8_t own_svc_id, uint8_t peer_
|
|||||||
}
|
}
|
||||||
SLIST_FOREACH(temp, &(p_own_svc->peer_list), next) {
|
SLIST_FOREACH(temp, &(p_own_svc->peer_list), next) {
|
||||||
if (peer_svc_id != 0 && peer_nmi_valid) {
|
if (peer_svc_id != 0 && peer_nmi_valid) {
|
||||||
if (temp->svc_id == peer_svc_id && !MACADDR_EQUAL(temp->peer_nmi, peer_nmi_valid)) {
|
if (temp->svc_id == peer_svc_id && MACADDR_EQUAL(temp->peer_nmi, peer_nmi_valid)) {
|
||||||
p_peer_svc = temp;
|
p_peer_svc = temp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -200,7 +163,7 @@ static struct peer_svc_info *nan_find_peer_svc(uint8_t own_svc_id, uint8_t peer_
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (peer_nmi_valid && !MACADDR_EQUAL(temp->peer_nmi, peer_nmi_valid)) {
|
if (peer_nmi_valid && MACADDR_EQUAL(temp->peer_nmi, peer_nmi_valid)) {
|
||||||
p_peer_svc = temp;
|
p_peer_svc = temp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -308,7 +271,9 @@ static bool nan_services_limit_reached(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nan_record_own_svc(uint8_t id, uint8_t type, const char svc_name[], bool ndp_resp_needed)
|
static void nan_record_own_svc(uint8_t id, uint8_t type, const char svc_name[],
|
||||||
|
bool ndp_resp_needed,
|
||||||
|
const wifi_nan_discovery_security_params_t *security_cfg)
|
||||||
{
|
{
|
||||||
struct own_svc_info *p_svc = NULL;
|
struct own_svc_info *p_svc = NULL;
|
||||||
|
|
||||||
@@ -330,12 +295,38 @@ static void nan_record_own_svc(uint8_t id, uint8_t type, const char svc_name[],
|
|||||||
if (type == ESP_NAN_PUBLISH) {
|
if (type == ESP_NAN_PUBLISH) {
|
||||||
p_svc->ndp_resp_needed = ndp_resp_needed;
|
p_svc->ndp_resp_needed = ndp_resp_needed;
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
/* Wipe to drop stale PMK material if this slot was previously used. */
|
||||||
|
forced_memzero(&p_svc->security_cfg, sizeof(p_svc->security_cfg));
|
||||||
|
forced_memzero(p_svc->pmk_cache, sizeof(p_svc->pmk_cache));
|
||||||
|
|
||||||
|
if (security_cfg) {
|
||||||
|
memcpy(&p_svc->security_cfg, security_cfg, sizeof(wifi_nan_discovery_security_params_t));
|
||||||
|
if (security_cfg->num_pmkids > 0) {
|
||||||
|
memcpy(p_svc->pmk_cache[0], security_cfg->pmk, ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||||
|
/* Public struct has one pmk[32]; cap num_pmkids to the count we cached. */
|
||||||
|
p_svc->security_cfg.num_pmkids = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void)security_cfg;
|
||||||
|
#endif /* CONFIG_ESP_WIFI_NAN_SECURITY */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A slot is in use once nan_record_new_ndl/preclaim has stamped peer_nmi,
|
||||||
|
* even if ndp_id is still 0 (initiator pre-claim window between M1 build
|
||||||
|
* and the WiFi library returning the real ndp_id). Treating ndp_id==0 alone as
|
||||||
|
* "free" lets a concurrent claim for a different peer overwrite a
|
||||||
|
* pre-claimed slot's security context. */
|
||||||
|
static inline bool nan_ndl_slot_in_use(const struct ndl_info *ndl)
|
||||||
|
{
|
||||||
|
return (ndl->ndp_id != 0) || !MACADDR_EQUAL(ndl->peer_nmi, null_mac);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ndl_limit_reached(void)
|
static bool ndl_limit_reached(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
||||||
if (s_nan_ctx.ndl[i].ndp_id == 0) {
|
if (!nan_ndl_slot_in_use(&s_nan_ctx.ndl[i])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -344,34 +335,56 @@ static bool ndl_limit_reached(void)
|
|||||||
|
|
||||||
static void nan_record_new_ndl(uint8_t ndp_id, uint8_t publish_id, uint8_t peer_nmi[], uint8_t own_role, uint32_t device_caps)
|
static void nan_record_new_ndl(uint8_t ndp_id, uint8_t publish_id, uint8_t peer_nmi[], uint8_t own_role, uint32_t device_caps)
|
||||||
{
|
{
|
||||||
struct ndl_info *ndl = NULL;
|
struct ndl_info *ndl = nan_find_ndl_by_pub_id_and_peer(publish_id, peer_nmi);
|
||||||
|
/* Reuse the slot when either:
|
||||||
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
* - it is an IDLE pre-claim from the initiator security path, or
|
||||||
if (s_nan_ctx.ndl[i].ndp_id == 0) {
|
* - it already holds an active NDP with the same ndp_id. */
|
||||||
ndl = &s_nan_ctx.ndl[i];
|
bool reuse_slot = false;
|
||||||
break;
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
}
|
if (ndl && ndl->handshake_state == NAN_HANDSHAKE_IDLE) {
|
||||||
|
reuse_slot = true;
|
||||||
}
|
}
|
||||||
if (!ndl) {
|
#endif
|
||||||
|
if (ndl && ndp_id != 0 && ndl->ndp_id == ndp_id) {
|
||||||
|
reuse_slot = true;
|
||||||
|
}
|
||||||
|
if (ndl && reuse_slot) {
|
||||||
|
ndl->ndp_id = ndp_id;
|
||||||
|
ndl->own_role = own_role;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (ndl) {
|
||||||
|
/* Stale slot from a prior session; wipe PMK/PTK/handshake state before re-binding. */
|
||||||
|
forced_memzero(ndl, sizeof(*ndl));
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
||||||
|
if (!nan_ndl_slot_in_use(&s_nan_ctx.ndl[i])) {
|
||||||
|
ndl = &s_nan_ctx.ndl[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ndl) {
|
||||||
|
ESP_LOGE(TAG, "No free NDL slot for ndp_id=%u pub_id=%u peer="MACSTR,
|
||||||
|
ndp_id, publish_id, MAC2STR(peer_nmi));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
ndl->ndp_id = ndp_id;
|
ndl->ndp_id = ndp_id;
|
||||||
ndl->device_caps = device_caps;
|
ndl->device_caps = device_caps;
|
||||||
if (peer_nmi) {
|
if (peer_nmi) {
|
||||||
MACADDR_COPY(ndl->peer_nmi, peer_nmi);
|
MACADDR_COPY(ndl->peer_nmi, peer_nmi);
|
||||||
}
|
}
|
||||||
|
/* peer_ndi is populated by WiFi-library callbacks (responder: M1 RX; initiator: M2 RX before MIC verify). */
|
||||||
ndl->publisher_id = publish_id;
|
ndl->publisher_id = publish_id;
|
||||||
ndl->own_role = own_role;
|
ndl->own_role = own_role;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ndl_info *nan_find_ndl(uint8_t ndp_id, uint8_t peer_nmi[])
|
struct ndl_info *nan_find_ndl(uint8_t ndp_id, uint8_t peer_nmi[])
|
||||||
{
|
{
|
||||||
struct ndl_info *ndl = NULL;
|
|
||||||
|
|
||||||
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
||||||
ndl = &s_nan_ctx.ndl[i];
|
struct ndl_info *ndl = &s_nan_ctx.ndl[i];
|
||||||
if (ndp_id != 0 && peer_nmi) {
|
if (ndp_id != 0 && peer_nmi) {
|
||||||
if (ndl->ndp_id == ndp_id && !MACADDR_EQUAL(ndl->peer_nmi, peer_nmi)) {
|
if (ndl->ndp_id == ndp_id && MACADDR_EQUAL(ndl->peer_nmi, peer_nmi)) {
|
||||||
return ndl;
|
return ndl;
|
||||||
}
|
}
|
||||||
} else if (ndp_id != 0) {
|
} else if (ndp_id != 0) {
|
||||||
@@ -379,7 +392,7 @@ static struct ndl_info *nan_find_ndl(uint8_t ndp_id, uint8_t peer_nmi[])
|
|||||||
return ndl;
|
return ndl;
|
||||||
}
|
}
|
||||||
} else if (peer_nmi) {
|
} else if (peer_nmi) {
|
||||||
if (!MACADDR_EQUAL(ndl->peer_nmi, peer_nmi)) {
|
if (MACADDR_EQUAL(ndl->peer_nmi, peer_nmi)) {
|
||||||
return ndl;
|
return ndl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -387,6 +400,21 @@ static struct ndl_info *nan_find_ndl(uint8_t ndp_id, uint8_t peer_nmi[])
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Find NDL by publisher_id + peer_nmi (e.g. when CSIA/SCIA/key desc parsed before NDP/NDL attribute) */
|
||||||
|
struct ndl_info *nan_find_ndl_by_pub_id_and_peer(uint8_t pub_id, const uint8_t *peer_nmi)
|
||||||
|
{
|
||||||
|
if (!peer_nmi) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
||||||
|
struct ndl_info *ndl = &s_nan_ctx.ndl[i];
|
||||||
|
if (ndl->publisher_id == pub_id && MACADDR_EQUAL(ndl->peer_nmi, peer_nmi)) {
|
||||||
|
return ndl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static bool nan_is_datapath_active(void)
|
static bool nan_is_datapath_active(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
||||||
@@ -397,6 +425,56 @@ static bool nan_is_datapath_active(void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initiator NDL pre-claim / finalize.
|
||||||
|
*
|
||||||
|
* Problem:
|
||||||
|
* The M1 Shared-Key Descriptor + SCIA security callbacks
|
||||||
|
* (Wi-Fi Aware v4.0 §7.1.3.5) run inside
|
||||||
|
* esp_nan_internal_datapath_req() and need an NDL to look up by
|
||||||
|
* ndp_id -- but the real ndp_id is only known after that call
|
||||||
|
* returns.
|
||||||
|
*
|
||||||
|
* Workaround:
|
||||||
|
* Pre-claim a slot at ndp_id=0 with security_ctx already populated,
|
||||||
|
* so the security callbacks find it. Once datapath_req returns the
|
||||||
|
* real ndp_id, stamp it onto the pre-claimed slot.
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
* - Pre-claim is SECURITY-only. With CONFIG_ESP_WIFI_NAN_SECURITY=n
|
||||||
|
* the security callbacks are NULL in nan_secure_dp_funcs and never
|
||||||
|
* run, so no pre-lookup is needed.
|
||||||
|
* - Finalize stays unconditional: nan_record_new_ndl() reuses a
|
||||||
|
* pre-claimed slot when one exists, otherwise allocates fresh.
|
||||||
|
* - Other finalize call sites:
|
||||||
|
* * nan_app_ndp_response_indication_cb (M2 RX, if datapath_req
|
||||||
|
* return races M2 indication)
|
||||||
|
* * key-desc parser claim path in nan_security.c
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
static struct ndl_info *nan_ndl_preclaim_initiator(uint8_t pub_id,
|
||||||
|
uint8_t peer_nmi[],
|
||||||
|
uint32_t device_caps)
|
||||||
|
{
|
||||||
|
nan_record_new_ndl(0, pub_id, peer_nmi, ESP_WIFI_NDP_ROLE_INITIATOR, device_caps);
|
||||||
|
return nan_find_ndl_by_pub_id_and_peer(pub_id, peer_nmi);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void nan_ndl_finalize_ndp_id(uint8_t real_ndp_id, uint8_t pub_id,
|
||||||
|
uint8_t peer_nmi[], uint32_t device_caps)
|
||||||
|
{
|
||||||
|
/* nan_record_new_ndl() stamps real_ndp_id onto the pre-claimed
|
||||||
|
* slot found by (pub_id, peer_nmi), or allocates a fresh slot if
|
||||||
|
* no pre-claim exists (SECURITY=n path). */
|
||||||
|
nan_record_new_ndl(real_ndp_id, pub_id, peer_nmi, ESP_WIFI_NDP_ROLE_INITIATOR, device_caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nan_ndl_release(uint8_t ndp_id_or_zero)
|
||||||
|
{
|
||||||
|
nan_reset_ndl(ndp_id_or_zero, false);
|
||||||
|
}
|
||||||
|
|
||||||
/* types of ipv6 addresses to be displayed on ipv6 events */
|
/* types of ipv6 addresses to be displayed on ipv6 events */
|
||||||
static const char *s_ipv6_addr_types[] = {
|
static const char *s_ipv6_addr_types[] = {
|
||||||
"UNKNOWN",
|
"UNKNOWN",
|
||||||
@@ -471,23 +549,31 @@ void nan_app_service_match_cb(uint8_t sub_id, struct nan_cb_peer_info *peer_info
|
|||||||
NAN_DATA_LOCK();
|
NAN_DATA_LOCK();
|
||||||
struct peer_svc_info *p_peer_svc = nan_find_peer_svc(sub_id, 0, pub_mac);
|
struct peer_svc_info *p_peer_svc = nan_find_peer_svc(sub_id, 0, pub_mac);
|
||||||
|
|
||||||
if (p_peer_svc) {
|
if (p_peer_svc && p_peer_svc->svc_id != pub_id) {
|
||||||
struct ndl_info *ndl = nan_find_ndl(0, pub_mac);
|
struct ndl_info *ndl = nan_find_ndl(0, pub_mac);
|
||||||
|
|
||||||
|
p_peer_svc->svc_id = pub_id;
|
||||||
p_peer_svc->device_caps = device_caps;
|
p_peer_svc->device_caps = device_caps;
|
||||||
if (p_peer_svc->svc_id != pub_id) {
|
if (ndl) {
|
||||||
p_peer_svc->svc_id = pub_id;
|
|
||||||
if (ndl) {
|
|
||||||
ndl->publisher_id = pub_id;
|
|
||||||
}
|
|
||||||
} else if (ndl) {
|
|
||||||
ndl->publisher_id = pub_id;
|
ndl->publisher_id = pub_id;
|
||||||
|
ndl->device_caps = device_caps;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
nan_record_peer_svc(sub_id, pub_id, pub_mac, device_caps);
|
nan_record_peer_svc(sub_id, pub_id, pub_mac, device_caps);
|
||||||
}
|
}
|
||||||
NAN_DATA_UNLOCK();
|
NAN_DATA_UNLOCK();
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Service matched with capabilities: 0x%04x", capab);
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
if (peer_info->peer_security_params) {
|
||||||
|
if (!nan_security_service_match(pub_mac, peer_info->peer_security_params)) {
|
||||||
|
ESP_LOGD(TAG, "PMKID mismatch with "MACSTR, MAC2STR(pub_mac));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
size_t evt_data_len = sizeof(wifi_event_nan_svc_match_t) + ssi_len;
|
size_t evt_data_len = sizeof(wifi_event_nan_svc_match_t) + ssi_len;
|
||||||
wifi_event_nan_svc_match_t *evt = (wifi_event_nan_svc_match_t *)os_zalloc(evt_data_len);
|
wifi_event_nan_svc_match_t *evt = (wifi_event_nan_svc_match_t *)os_zalloc(evt_data_len);
|
||||||
if (!evt) {
|
if (!evt) {
|
||||||
@@ -503,6 +589,7 @@ void nan_app_service_match_cb(uint8_t sub_id, struct nan_cb_peer_info *peer_info
|
|||||||
evt->fsd_gas = (capab & NAN_SDEA_CTRL_FSD_GAS) ? 1 : 0;
|
evt->fsd_gas = (capab & NAN_SDEA_CTRL_FSD_GAS) ? 1 : 0;
|
||||||
evt->datapath_reqd = (capab & NAN_SDEA_CTRL_DATAPATH_REQD) ? 1 : 0;
|
evt->datapath_reqd = (capab & NAN_SDEA_CTRL_DATAPATH_REQD) ? 1 : 0;
|
||||||
evt->ndpe_support = (device_caps & NAN_CAPS_NDPE_ATTR) ? 1 : 0;
|
evt->ndpe_support = (device_caps & NAN_CAPS_NDPE_ATTR) ? 1 : 0;
|
||||||
|
evt->security_reqd = (capab & NAN_SDEA_CTRL_SECURITY_REQD) ? 1 : 0;
|
||||||
evt->ssi_version = ssi_ver;
|
evt->ssi_version = ssi_ver;
|
||||||
if (ssi && ssi_len) {
|
if (ssi && ssi_len) {
|
||||||
if (ssi_ver) {
|
if (ssi_ver) {
|
||||||
@@ -532,10 +619,7 @@ void nan_app_replied_cb(uint8_t pub_id, struct nan_cb_peer_info *peer_info)
|
|||||||
uint32_t device_caps = peer_info->device_caps;
|
uint32_t device_caps = peer_info->device_caps;
|
||||||
|
|
||||||
NAN_DATA_LOCK();
|
NAN_DATA_LOCK();
|
||||||
struct peer_svc_info *p_peer_svc = nan_find_peer_svc(pub_id, sub_id, sub_nmi);
|
if (!nan_find_peer_svc(pub_id, sub_id, sub_nmi)) {
|
||||||
if (p_peer_svc) {
|
|
||||||
p_peer_svc->device_caps = device_caps;
|
|
||||||
} else {
|
|
||||||
nan_record_peer_svc(pub_id, sub_id, sub_nmi, device_caps);
|
nan_record_peer_svc(pub_id, sub_id, sub_nmi, device_caps);
|
||||||
}
|
}
|
||||||
NAN_DATA_UNLOCK();
|
NAN_DATA_UNLOCK();
|
||||||
@@ -574,10 +658,7 @@ void nan_app_receive_cb(uint8_t svc_id, struct nan_cb_peer_info *peer_info)
|
|||||||
uint32_t device_caps = peer_info->device_caps;
|
uint32_t device_caps = peer_info->device_caps;
|
||||||
|
|
||||||
NAN_DATA_LOCK();
|
NAN_DATA_LOCK();
|
||||||
struct peer_svc_info *p_peer_svc = nan_find_peer_svc(svc_id, peer_svc_id, peer_mac);
|
if (!nan_find_peer_svc(svc_id, peer_svc_id, peer_mac)) {
|
||||||
if (p_peer_svc) {
|
|
||||||
p_peer_svc->device_caps = device_caps;
|
|
||||||
} else {
|
|
||||||
nan_record_peer_svc(svc_id, peer_svc_id, peer_mac, device_caps);
|
nan_record_peer_svc(svc_id, peer_svc_id, peer_mac, device_caps);
|
||||||
}
|
}
|
||||||
NAN_DATA_UNLOCK();
|
NAN_DATA_UNLOCK();
|
||||||
@@ -605,6 +686,14 @@ void nan_app_receive_cb(uint8_t svc_id, struct nan_cb_peer_info *peer_info)
|
|||||||
|
|
||||||
void nan_app_ndp_indication_cb(uint8_t pub_id, struct ndp_cb_peer_info *peer_info, uint32_t device_caps)
|
void nan_app_ndp_indication_cb(uint8_t pub_id, struct ndp_cb_peer_info *peer_info, uint32_t device_caps)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Responder-side NDP indication. Security parsers (CSIA/SCIA/
|
||||||
|
* Shared-Key) have already run and stashed the peer's security
|
||||||
|
* inputs in static pending caches; nan_security_apply_pending()
|
||||||
|
* below promotes them onto the NDL. NAN_DATA_LOCK guards
|
||||||
|
* s_nan_ctx mutation only and is released before any
|
||||||
|
* esp_nan_internal_* call (see lock contract in nan_i.h).
|
||||||
|
*/
|
||||||
if (!peer_info) {
|
if (!peer_info) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -615,57 +704,81 @@ void nan_app_ndp_indication_cb(uint8_t pub_id, struct ndp_cb_peer_info *peer_inf
|
|||||||
uint16_t ssi_len = peer_info->ssi_len;
|
uint16_t ssi_len = peer_info->ssi_len;
|
||||||
bool ndp_resp_needed = false;
|
bool ndp_resp_needed = false;
|
||||||
|
|
||||||
|
bool send_auto_resp = false;
|
||||||
|
wifi_nan_datapath_resp_t ndp_resp = {0};
|
||||||
|
ip_addr_t own_ipv6 = {0};
|
||||||
|
|
||||||
NAN_DATA_LOCK();
|
NAN_DATA_LOCK();
|
||||||
struct own_svc_info *p_own_svc = nan_find_own_svc(pub_id);
|
struct own_svc_info *p_own_svc = nan_find_own_svc(pub_id);
|
||||||
|
|
||||||
if (!p_own_svc) {
|
if (!p_own_svc) {
|
||||||
ESP_LOGE(TAG, "No Publish found with id %d", pub_id);
|
|
||||||
NAN_DATA_UNLOCK();
|
NAN_DATA_UNLOCK();
|
||||||
|
ESP_LOGE(TAG, "No Publish found with id %d", pub_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ndp_resp_needed = p_own_svc->ndp_resp_needed;
|
ndp_resp_needed = p_own_svc->ndp_resp_needed;
|
||||||
if (ndl_limit_reached()) {
|
if (ndl_limit_reached()) {
|
||||||
ESP_LOGE(TAG, "NDP limit reached");
|
|
||||||
NAN_DATA_UNLOCK();
|
NAN_DATA_UNLOCK();
|
||||||
|
ESP_LOGE(TAG, "NDP limit reached");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nan_record_new_ndl(ndp_id, pub_id, peer_nmi, ESP_WIFI_NDP_ROLE_RESPONDER, device_caps);
|
||||||
|
|
||||||
if (!nan_find_peer_svc(pub_id, 0, peer_nmi)) {
|
if (!nan_find_peer_svc(pub_id, 0, peer_nmi)) {
|
||||||
nan_record_peer_svc(pub_id, 0, peer_nmi, device_caps);
|
nan_record_peer_svc(pub_id, 0, peer_nmi, device_caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ndl_info *ndl = nan_find_ndl(ndp_id, (uint8_t *)peer_nmi);
|
||||||
|
if (ndl && peer_ndi) {
|
||||||
|
MACADDR_COPY(ndl->peer_ndi, peer_ndi);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
/* Apply pending CSIA/SCIA/M1 (captured before this indication) to the NDL. */
|
||||||
|
nan_security_apply_pending(ndl, p_own_svc, pub_id, peer_nmi, peer_ndi);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (p_own_svc->ndp_resp_needed) {
|
if (p_own_svc->ndp_resp_needed) {
|
||||||
nan_record_new_ndl(ndp_id, pub_id, peer_nmi, ESP_WIFI_NDP_ROLE_RESPONDER, device_caps);
|
ESP_LOGD(TAG, "NDP Req from "MACSTR" [NDP Id: %d], Accept OR Deny using NDP command",
|
||||||
ESP_LOGI(TAG, "NDP Req from "MACSTR" [NDP Id: %d], Accept OR Deny using NDP command",
|
|
||||||
MAC2STR(peer_nmi), ndp_id);
|
MAC2STR(peer_nmi), ndp_id);
|
||||||
s_nan_ctx.event |= NDP_INDICATION;
|
s_nan_ctx.event |= NDP_INDICATION;
|
||||||
} else {
|
} else {
|
||||||
uint8_t own_bssid[6];
|
/* Build auto-response from NDL state under lock; dispatch the WiFi-library
|
||||||
ip_addr_t own_ipv6 = {0};
|
* call after release (esp_nan_internal_* must not be called with
|
||||||
|
* NAN_DATA_LOCK held -- see nan_i.h). */
|
||||||
wifi_nan_datapath_resp_t ndp_resp = {0};
|
|
||||||
ndp_resp.accept = true;
|
ndp_resp.accept = true;
|
||||||
ndp_resp.ndp_id = ndp_id;
|
ndp_resp.ndp_id = ndp_id;
|
||||||
MACADDR_COPY(ndp_resp.peer_mac, peer_nmi);
|
MACADDR_COPY(ndp_resp.peer_mac, peer_nmi);
|
||||||
|
|
||||||
if (device_caps & NAN_CAPS_NDPE_ATTR) {
|
if (device_caps & NAN_CAPS_NDPE_ATTR) {
|
||||||
|
uint8_t own_bssid[6];
|
||||||
esp_err_t err = esp_wifi_get_mac(WIFI_IF_NAN, own_bssid);
|
esp_err_t err = esp_wifi_get_mac(WIFI_IF_NAN, own_bssid);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
|
NAN_DATA_UNLOCK();
|
||||||
ESP_LOGE(TAG, "Cannot get own BSSID!");
|
ESP_LOGE(TAG, "Cannot get own BSSID!");
|
||||||
ndp_resp.accept = false;
|
return;
|
||||||
} else {
|
|
||||||
esp_wifi_nan_get_ipv6_linklocal_from_mac(&own_ipv6.u_addr.ip6, own_bssid);
|
|
||||||
}
|
}
|
||||||
|
esp_wifi_nan_get_ipv6_linklocal_from_mac(&own_ipv6.u_addr.ip6, own_bssid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ndp_resp.accept) {
|
/* Datapath security on the auto-respond path is sourced from the
|
||||||
nan_record_new_ndl(ndp_id, pub_id, peer_nmi, ESP_WIFI_NDP_ROLE_RESPONDER, device_caps);
|
* NDL's security_ctx (populated by nan_security_apply_pending above
|
||||||
}
|
* from publish-time cfg). The WiFi library's M2 builder callbacks look it
|
||||||
|
* up by (ndp_id, peer_nmi); no per-resp security field needed. */
|
||||||
esp_nan_internal_datapath_resp(&ndp_resp, (uint8_t *)&own_ipv6.u_addr.ip6.addr[2] );
|
send_auto_resp = true;
|
||||||
}
|
}
|
||||||
NAN_DATA_UNLOCK();
|
NAN_DATA_UNLOCK();
|
||||||
|
|
||||||
|
if (send_auto_resp) {
|
||||||
|
esp_err_t resp_err = esp_nan_internal_datapath_resp(&ndp_resp, (uint8_t *)&own_ipv6.u_addr.ip6.addr[2]);
|
||||||
|
if (resp_err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Auto NDP response failed for ndp_id=%u peer="MACSTR" err=%d",
|
||||||
|
ndp_id, MAC2STR(peer_nmi), resp_err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Event-post path reads only peer_info / ssi (WiFi-library-owned, not s_nan_ctx),
|
||||||
|
* so it runs outside the lock. */
|
||||||
size_t evt_data_len = sizeof(wifi_event_ndp_indication_t) + ssi_len;
|
size_t evt_data_len = sizeof(wifi_event_ndp_indication_t) + ssi_len;
|
||||||
wifi_event_ndp_indication_t *evt = (wifi_event_ndp_indication_t *)os_zalloc(evt_data_len);
|
wifi_event_ndp_indication_t *evt = (wifi_event_ndp_indication_t *)os_zalloc(evt_data_len);
|
||||||
if (!evt) {
|
if (!evt) {
|
||||||
@@ -702,6 +815,56 @@ void nan_app_ndp_indication_cb(uint8_t pub_id, struct ndp_cb_peer_info *peer_inf
|
|||||||
os_free(evt);
|
os_free(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nan_app_ndp_response_indication_cb(struct ndp_cb_peer_info *peer_info)
|
||||||
|
{
|
||||||
|
if (!peer_info) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t ndp_id = peer_info->ndp_id;
|
||||||
|
uint8_t *peer_nmi = peer_info->peer_nmi;
|
||||||
|
uint8_t *peer_ndi = peer_info->peer_ndi;
|
||||||
|
|
||||||
|
NAN_DATA_LOCK();
|
||||||
|
struct ndl_info *ndl = nan_find_ndl(ndp_id, peer_nmi);
|
||||||
|
if (!ndl) {
|
||||||
|
/* Initiator pre-claim path may still have ndp_id=0 if the M1 builder
|
||||||
|
* did not run through the SCIA / key-desc helpers (unsecured path).
|
||||||
|
* Fall back to peer-only lookup and stamp ndp_id. */
|
||||||
|
ndl = nan_find_ndl(0, peer_nmi);
|
||||||
|
if (ndl && ndl->ndp_id == 0 && ndp_id != 0) {
|
||||||
|
ndl->ndp_id = ndp_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ndl && peer_ndi) {
|
||||||
|
MACADDR_COPY(ndl->peer_ndi, peer_ndi);
|
||||||
|
ESP_LOGD(TAG, "NDP M2 RX: stored peer NDI "MACSTR" (ndp_id=%d)",
|
||||||
|
MAC2STR(peer_ndi), ndp_id);
|
||||||
|
} else if (!ndl) {
|
||||||
|
ESP_LOGW(TAG, "NDP M2 RX: no NDL for ndp_id=%d peer="MACSTR,
|
||||||
|
ndp_id, MAC2STR(peer_nmi));
|
||||||
|
}
|
||||||
|
NAN_DATA_UNLOCK();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tear down an NDP whose confirm callback fired but cannot be completed
|
||||||
|
* (TK not ready, initiator handshake not COMPLETE, key install failed,
|
||||||
|
* event alloc failed). Notifies the peer via datapath_end, wipes the NDL
|
||||||
|
* (including TK / KCK / KEK material), and unblocks any waiting app. */
|
||||||
|
static void nan_ndp_confirm_teardown(const uint8_t peer_nmi[6], uint8_t ndp_id)
|
||||||
|
{
|
||||||
|
wifi_nan_datapath_end_req_t ndp_end = {0};
|
||||||
|
|
||||||
|
MACADDR_COPY(ndp_end.peer_mac, peer_nmi);
|
||||||
|
ndp_end.ndp_id = ndp_id;
|
||||||
|
|
||||||
|
NAN_DATA_UNLOCK();
|
||||||
|
esp_nan_internal_datapath_end(&ndp_end);
|
||||||
|
NAN_DATA_LOCK();
|
||||||
|
|
||||||
|
nan_reset_ndl(ndp_id, false);
|
||||||
|
os_event_group_set_bits(nan_event_group, NDP_REJECTED);
|
||||||
|
}
|
||||||
|
|
||||||
void nan_app_ndp_confirm_cb(uint8_t status, struct ndp_cb_peer_info *peer_info,
|
void nan_app_ndp_confirm_cb(uint8_t status, struct ndp_cb_peer_info *peer_info,
|
||||||
uint8_t own_ndi[6], uint8_t ipv6_identifier[8])
|
uint8_t own_ndi[6], uint8_t ipv6_identifier[8])
|
||||||
{
|
{
|
||||||
@@ -742,19 +905,58 @@ void nan_app_ndp_confirm_cb(uint8_t status, struct ndp_cb_peer_info *peer_info,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
if (ndl->security_ctx.type == WIFI_NAN_SECURITY_ENCRYPTED) {
|
||||||
|
if (!ndl->ptk_set || ndl->tk_len < NAN_NCS_SK_128_TK_LEN) {
|
||||||
|
ESP_LOGE(TAG, "NDP confirm: encrypted datapath but TK is not ready (ndp_id=%d)", ndp_id);
|
||||||
|
nan_ndp_confirm_teardown(peer_nmi, ndp_id);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* Initiator: refuse TK install unless M4 MIC verifier promoted state to COMPLETE.
|
||||||
|
* Parser sets M4_RCVD on receipt; verifier transitions to COMPLETE on a passing
|
||||||
|
* HMAC-SHA256(KCK, M4_body). If we're still at M4_RCVD here, MIC verify failed
|
||||||
|
* or was skipped — do not install the TK on a possibly tampered handshake. */
|
||||||
|
if (ndl->own_role == ESP_WIFI_NDP_ROLE_INITIATOR &&
|
||||||
|
ndl->handshake_state != NAN_HANDSHAKE_COMPLETE) {
|
||||||
|
ESP_LOGE(TAG, "NDP confirm (initiator): handshake_state=%d (not COMPLETE); skipping TK install",
|
||||||
|
ndl->handshake_state);
|
||||||
|
nan_ndp_confirm_teardown(peer_nmi, ndp_id);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_ESP_WIFI_NAN_SECURITY */
|
||||||
|
|
||||||
|
/* Allocate the confirm event before installing the pairwise key, so an
|
||||||
|
* allocation failure can tear the NDP down without leaving a stale key
|
||||||
|
* bound to peer_ndi in the MAC's key store. */
|
||||||
size_t evt_data_len = sizeof(wifi_event_ndp_confirm_t) + ssi_len;
|
size_t evt_data_len = sizeof(wifi_event_ndp_confirm_t) + ssi_len;
|
||||||
wifi_event_ndp_confirm_t *evt = (wifi_event_ndp_confirm_t *)os_zalloc(evt_data_len);
|
wifi_event_ndp_confirm_t *evt = (wifi_event_ndp_confirm_t *)os_zalloc(evt_data_len);
|
||||||
if (!evt) {
|
if (!evt) {
|
||||||
wifi_nan_datapath_end_req_t ndp_end = {0};
|
|
||||||
|
|
||||||
MACADDR_COPY(ndp_end.peer_mac, peer_nmi);
|
|
||||||
ndp_end.ndp_id = ndp_id;
|
|
||||||
esp_nan_internal_datapath_end(&ndp_end);
|
|
||||||
ESP_LOGE(TAG, "Failed to allocate for event, terminate NDP");
|
ESP_LOGE(TAG, "Failed to allocate for event, terminate NDP");
|
||||||
nan_reset_ndl(ndp_id, false);
|
nan_ndp_confirm_teardown(peer_nmi, ndp_id);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
if (ndl->security_ctx.type == WIFI_NAN_SECURITY_ENCRYPTED) {
|
||||||
|
uint8_t key_rsc[8] = {0};
|
||||||
|
int ret = esp_wifi_set_nan_key_internal(NAN_WIFI_WPA_ALG_CCMP,
|
||||||
|
peer_ndi,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
key_rsc,
|
||||||
|
sizeof(key_rsc),
|
||||||
|
ndl->nd_tk,
|
||||||
|
NAN_NCS_SK_128_TK_LEN,
|
||||||
|
NAN_KEY_FLAG_PAIRWISE | NAN_KEY_FLAG_RX | NAN_KEY_FLAG_TX);
|
||||||
|
if (ret != 0) {
|
||||||
|
ESP_LOGE(TAG, "NDP confirm: failed to install NAN pairwise key (ndp_id=%d, ret=%d)", ndp_id, ret);
|
||||||
|
os_free(evt);
|
||||||
|
nan_ndp_confirm_teardown(peer_nmi, ndp_id);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_ESP_WIFI_NAN_SECURITY */
|
||||||
evt->status = status;
|
evt->status = status;
|
||||||
evt->ndp_id = ndp_id;
|
evt->ndp_id = ndp_id;
|
||||||
MACADDR_COPY(evt->peer_nmi, peer_nmi);
|
MACADDR_COPY(evt->peer_nmi, peer_nmi);
|
||||||
@@ -768,7 +970,6 @@ void nan_app_ndp_confirm_cb(uint8_t status, struct ndp_cb_peer_info *peer_info,
|
|||||||
} else {
|
} else {
|
||||||
memcpy(evt->ipv6_identifier, ipv6_identifier, NAN_IPV6_ADDR_ID_LEN);
|
memcpy(evt->ipv6_identifier, ipv6_identifier, NAN_IPV6_ADDR_ID_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssi && ssi_len) {
|
if (ssi && ssi_len) {
|
||||||
memcpy(evt->ssi, ssi, ssi_len);
|
memcpy(evt->ssi, ssi, ssi_len);
|
||||||
evt->ssi_len = ssi_len;
|
evt->ssi_len = ssi_len;
|
||||||
@@ -788,7 +989,6 @@ void nan_app_ndp_confirm_cb(uint8_t status, struct ndp_cb_peer_info *peer_info,
|
|||||||
MAC2STR(peer_nmi), ndp_id, inet6_ntoa(peer_ip6));
|
MAC2STR(peer_nmi), ndp_id, inet6_ntoa(peer_ip6));
|
||||||
|
|
||||||
os_event_group_set_bits(nan_event_group, NDP_ACCEPTED);
|
os_event_group_set_bits(nan_event_group, NDP_ACCEPTED);
|
||||||
|
|
||||||
nan_app_post_event(WIFI_EVENT_NDP_CONFIRM, evt, evt_data_len);
|
nan_app_post_event(WIFI_EVENT_NDP_CONFIRM, evt, evt_data_len);
|
||||||
os_free(evt);
|
os_free(evt);
|
||||||
return;
|
return;
|
||||||
@@ -835,8 +1035,106 @@ void nan_action_txdone_cb(uint32_t context, bool tx_status)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void esp_nan_ndp_tx_done_cb(uint8_t ndp_id, const uint8_t *peer_nmi, uint8_t msg_type, bool tx_status)
|
||||||
|
{
|
||||||
|
NAN_DATA_LOCK();
|
||||||
|
|
||||||
|
struct ndl_info *ndl = nan_find_ndl(ndp_id, (uint8_t *)peer_nmi);
|
||||||
|
if (!ndl) {
|
||||||
|
ESP_LOGE(TAG, "NDP TX Confirm: No NDL found for ndp_id=%d", ndp_id);
|
||||||
|
NAN_DATA_UNLOCK();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tx_status) {
|
||||||
|
ESP_LOGE(TAG, "NDP TX Confirm: msg_type=%d transmission failed for ndp_id=%d", msg_type, ndp_id);
|
||||||
|
NAN_DATA_UNLOCK();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "NDP TX Confirm: msg_type=%d sent successfully, ndp_id=%d", msg_type, ndp_id);
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
/* Update security handshake state if encrypted datapath is active */
|
||||||
|
if (msg_type == 2 && ndl->handshake_state == NAN_HANDSHAKE_M1_RCVD) {
|
||||||
|
ndl->handshake_state = NAN_HANDSHAKE_M2_SENT;
|
||||||
|
} else if (msg_type == 4 && ndl->handshake_state == NAN_HANDSHAKE_M3_RCVD) {
|
||||||
|
ndl->handshake_state = NAN_HANDSHAKE_COMPLETE;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_ESP_WIFI_NAN_SECURITY */
|
||||||
|
|
||||||
|
NAN_DATA_UNLOCK();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NAN secure-datapath helpers registered with the WiFi libraries. */
|
||||||
|
static struct nan_secure_dp_funcs s_nan_secure_dp_funcs = {
|
||||||
|
/* Always-present helpers */
|
||||||
|
.ndp_tx_done_cb = esp_nan_ndp_tx_done_cb,
|
||||||
|
|
||||||
|
#if CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
/* Length getters */
|
||||||
|
.get_csia_len = esp_nan_get_csia_len,
|
||||||
|
.get_scia_len = esp_nan_get_scia_len,
|
||||||
|
.get_shared_key_desc_attr_len = esp_nan_get_shared_key_desc_attr_len,
|
||||||
|
.ndp_security_install_get_shared_desc_len = esp_nan_ndp_security_install_get_shared_desc_len,
|
||||||
|
|
||||||
|
/* CSIA / SCIA construction */
|
||||||
|
.construct_csia = esp_nan_construct_csia,
|
||||||
|
.construct_scia_publish = esp_nan_construct_scia_publish,
|
||||||
|
.construct_scia_ndp_req = esp_nan_construct_scia_ndp_req,
|
||||||
|
.construct_scia_ndp_resp = esp_nan_construct_scia_ndp_resp,
|
||||||
|
|
||||||
|
/* Shared Key Descriptor builders */
|
||||||
|
.get_ndp_req_shared_key_desc = esp_nan_get_ndp_req_shared_key_desc,
|
||||||
|
.get_ndp_resp_shared_key_desc = esp_nan_get_ndp_resp_shared_key_desc,
|
||||||
|
.get_ndp_confirm_shared_key_desc = esp_nan_get_ndp_confirm_shared_key_desc,
|
||||||
|
.get_ndp_security_install_key_desc = esp_nan_get_ndp_security_install_key_desc,
|
||||||
|
|
||||||
|
/* M1 Auth_Token capture */
|
||||||
|
.capture_m1_auth_token = esp_nan_capture_m1_auth_token,
|
||||||
|
|
||||||
|
/* MIC compute (TX path) */
|
||||||
|
.update_ndp_resp_mic = esp_nan_update_ndp_resp_mic,
|
||||||
|
.update_ndp_confirm_mic = esp_nan_update_ndp_confirm_mic,
|
||||||
|
.update_ndp_security_install_mic = esp_nan_update_ndp_security_install_mic,
|
||||||
|
|
||||||
|
/* MIC verify (RX path) */
|
||||||
|
.verify_ndp_resp_mic = esp_nan_verify_ndp_resp_mic,
|
||||||
|
.verify_ndp_confirm_mic = esp_nan_verify_ndp_confirm_mic,
|
||||||
|
.verify_ndp_security_install_mic = esp_nan_verify_ndp_security_install_mic,
|
||||||
|
|
||||||
|
/* RX-path attribute parsers */
|
||||||
|
.parse_ndp_csia = esp_nan_parse_ndp_csia,
|
||||||
|
.parse_ndp_scia = esp_nan_parse_ndp_scia,
|
||||||
|
.parse_ndp_key_desc = esp_nan_parse_ndp_key_desc,
|
||||||
|
|
||||||
|
/* Publish-side security parser */
|
||||||
|
.parse_publish_security = esp_nan_parse_publish_security,
|
||||||
|
|
||||||
|
/* Publish-init helper */
|
||||||
|
.derive_security_params = nan_derive_security_params,
|
||||||
|
|
||||||
|
/* NDP security gate query */
|
||||||
|
.get_ndp_security_csid = nan_get_ndp_security_csid,
|
||||||
|
#endif /* CONFIG_ESP_WIFI_NAN_SECURITY */
|
||||||
|
};
|
||||||
|
|
||||||
void esp_nan_app_deinit(void)
|
void esp_nan_app_deinit(void)
|
||||||
{
|
{
|
||||||
|
esp_nan_internal_register_secure_dp_funcs(NULL);
|
||||||
|
|
||||||
|
/* Free per-peer/NDL state in case Wi-Fi is being deinit'd without a
|
||||||
|
* prior esp_wifi_nan_sync_stop. Not SECURITY-gated: reset helpers
|
||||||
|
* touch only fields that exist in both configs; conditional key
|
||||||
|
* material lives inside the #ifdef'd region of struct ndl_info. */
|
||||||
|
if (s_nan_data_lock) {
|
||||||
|
NAN_DATA_LOCK();
|
||||||
|
nan_reset_service(0, true);
|
||||||
|
nan_reset_ndl(0, true);
|
||||||
|
memset(&s_nan_ctx, 0, sizeof(s_nan_ctx));
|
||||||
|
NAN_DATA_UNLOCK();
|
||||||
|
}
|
||||||
|
|
||||||
if (nan_event_group) {
|
if (nan_event_group) {
|
||||||
os_event_group_delete(nan_event_group);
|
os_event_group_delete(nan_event_group);
|
||||||
nan_event_group = NULL;
|
nan_event_group = NULL;
|
||||||
@@ -860,7 +1158,10 @@ void esp_nan_app_init(void)
|
|||||||
if (!s_nan_data_lock) {
|
if (!s_nan_data_lock) {
|
||||||
ESP_LOGE(TAG, "Failed to create NAN data lock");
|
ESP_LOGE(TAG, "Failed to create NAN data lock");
|
||||||
esp_nan_app_deinit();
|
esp_nan_app_deinit();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_nan_internal_register_secure_dp_funcs(&s_nan_secure_dp_funcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void esp_nan_action_start(esp_netif_t *nan_netif)
|
void esp_nan_action_start(esp_netif_t *nan_netif)
|
||||||
@@ -880,6 +1181,7 @@ void esp_nan_action_start(esp_netif_t *nan_netif)
|
|||||||
.ndp_confirm = nan_app_ndp_confirm_cb,
|
.ndp_confirm = nan_app_ndp_confirm_cb,
|
||||||
.ndp_terminated = nan_app_ndp_terminated_cb,
|
.ndp_terminated = nan_app_ndp_terminated_cb,
|
||||||
.action_txdone = nan_action_txdone_cb,
|
.action_txdone = nan_action_txdone_cb,
|
||||||
|
.ndp_response_indication = nan_app_ndp_response_indication_cb,
|
||||||
};
|
};
|
||||||
esp_nan_internal_register_callbacks(&nan_cb);
|
esp_nan_internal_register_callbacks(&nan_cb);
|
||||||
|
|
||||||
@@ -996,6 +1298,10 @@ esp_err_t esp_wifi_nan_sync_stop(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
NAN_DATA_LOCK();
|
NAN_DATA_LOCK();
|
||||||
|
/* Free per-peer linked lists before zeroing own_svc[] heads, else the
|
||||||
|
* peer_svc_info heap allocations leak. */
|
||||||
|
nan_reset_service(0, true);
|
||||||
|
nan_reset_ndl(0, true);
|
||||||
memset(&s_nan_ctx, 0, sizeof(nan_ctx_t));
|
memset(&s_nan_ctx, 0, sizeof(nan_ctx_t));
|
||||||
NAN_DATA_UNLOCK();
|
NAN_DATA_UNLOCK();
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
@@ -1052,6 +1358,8 @@ uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg)
|
|||||||
#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */
|
#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */
|
||||||
|
|
||||||
#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE
|
#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE
|
||||||
|
wifi_nan_publish_cfg_t *cfg = NULL;
|
||||||
|
|
||||||
NAN_DATA_LOCK();
|
NAN_DATA_LOCK();
|
||||||
if (!(s_nan_ctx.state & NAN_STARTED_BIT)) {
|
if (!(s_nan_ctx.state & NAN_STARTED_BIT)) {
|
||||||
ESP_LOGE(TAG, "NAN not started!");
|
ESP_LOGE(TAG, "NAN not started!");
|
||||||
@@ -1069,18 +1377,50 @@ uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (publish_cfg->security_reqd) {
|
||||||
|
#ifndef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
ESP_LOGE(TAG, "Encrypted datapath not enabled (CONFIG_ESP_WIFI_NAN_SECURITY)");
|
||||||
|
goto fail;
|
||||||
|
#else
|
||||||
|
if (!(publish_cfg->security_cfg.csid_bitmap & WIFI_NAN_CSID_BIT_NCS_SK_128)) {
|
||||||
|
ESP_LOGE(TAG, "Unsupported cipher suite in csid_bitmap (only NCS-SK-128 is supported)");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (esp_nan_internal_publish_service(publish_cfg, (uint8_t *) &pub_id, false) != ESP_OK) {
|
/* Heap-allocate config copy to avoid ~700 bytes on stack */
|
||||||
|
cfg = os_zalloc(sizeof(*cfg));
|
||||||
|
if (!cfg) {
|
||||||
|
ESP_LOGE(TAG, "Failed to allocate publish config");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
memcpy(cfg, publish_cfg, sizeof(*cfg));
|
||||||
|
|
||||||
|
/* Security derivation (PMK, PMKID) now runs in WiFi task context —
|
||||||
|
* the WiFi library calls nan_derive_security_params(cfg) during publish processing.
|
||||||
|
* After esp_nan_internal_publish_service returns, cfg->security_cfg has
|
||||||
|
* the derived PMK and PMKID populated by the WiFi task. */
|
||||||
|
|
||||||
|
if (esp_nan_internal_publish_service(cfg, (uint8_t *) &pub_id, false) != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Failed to publish service '%s'", publish_cfg->service_name);
|
ESP_LOGE(TAG, "Failed to publish service '%s'", publish_cfg->service_name);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Started Publishing %s [Service ID - %u]", publish_cfg->service_name, pub_id);
|
ESP_LOGI(TAG, "Started Publishing %s [Service ID - %u]", publish_cfg->service_name, pub_id);
|
||||||
nan_record_own_svc(pub_id, ESP_NAN_PUBLISH, publish_cfg->service_name, publish_cfg->ndp_resp_needed);
|
nan_record_own_svc(pub_id, ESP_NAN_PUBLISH, publish_cfg->service_name, publish_cfg->ndp_resp_needed,
|
||||||
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
&cfg->security_cfg
|
||||||
|
#else
|
||||||
|
NULL
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
os_free(cfg);
|
||||||
NAN_DATA_UNLOCK();
|
NAN_DATA_UNLOCK();
|
||||||
|
|
||||||
return pub_id;
|
return pub_id;
|
||||||
fail:
|
fail:
|
||||||
|
os_free(cfg);
|
||||||
NAN_DATA_UNLOCK();
|
NAN_DATA_UNLOCK();
|
||||||
return 0;
|
return 0;
|
||||||
#endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */
|
#endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */
|
||||||
@@ -1127,11 +1467,26 @@ uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe
|
|||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "Started Subscribing to %s [Service ID - %u]",
|
ESP_LOGI(TAG, "Started Subscribing to %s [Service ID - %u]",
|
||||||
subscribe_cfg->service_name, sub_id);
|
subscribe_cfg->service_name, sub_id);
|
||||||
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
nan_security_cache_subscriber_params(subscribe_cfg->service_name,
|
||||||
|
&subscribe_cfg->security_cfg);
|
||||||
|
#endif
|
||||||
return sub_id;
|
return sub_id;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */
|
#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */
|
||||||
|
|
||||||
#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE
|
#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE
|
||||||
|
if (subscribe_cfg->security_reqd) {
|
||||||
|
#ifndef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
ESP_LOGE(TAG, "Encrypted datapath not enabled (CONFIG_ESP_WIFI_NAN_SECURITY)");
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
if (!(subscribe_cfg->security_cfg.csid_bitmap & WIFI_NAN_CSID_BIT_NCS_SK_128)) {
|
||||||
|
ESP_LOGE(TAG, "Unsupported cipher suite in csid_bitmap (only NCS-SK-128 is supported)");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
NAN_DATA_LOCK();
|
NAN_DATA_LOCK();
|
||||||
if (!(s_nan_ctx.state & NAN_STARTED_BIT)) {
|
if (!(s_nan_ctx.state & NAN_STARTED_BIT)) {
|
||||||
ESP_LOGE(TAG, "NAN not started!");
|
ESP_LOGE(TAG, "NAN not started!");
|
||||||
@@ -1154,7 +1509,10 @@ uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe
|
|||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Started Subscribing to %s [Service ID - %u]", subscribe_cfg->service_name, sub_id);
|
ESP_LOGI(TAG, "Started Subscribing to %s [Service ID - %u]", subscribe_cfg->service_name, sub_id);
|
||||||
nan_record_own_svc((uint8_t) sub_id, ESP_NAN_SUBSCRIBE, subscribe_cfg->service_name, false);
|
nan_record_own_svc((uint8_t) sub_id, ESP_NAN_SUBSCRIBE, subscribe_cfg->service_name, false, &subscribe_cfg->security_cfg);
|
||||||
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
nan_security_cache_subscriber_params(subscribe_cfg->service_name, &subscribe_cfg->security_cfg);
|
||||||
|
#endif
|
||||||
NAN_DATA_UNLOCK();
|
NAN_DATA_UNLOCK();
|
||||||
|
|
||||||
return sub_id;
|
return sub_id;
|
||||||
@@ -1217,7 +1575,7 @@ esp_err_t esp_wifi_nan_send_message(wifi_nan_followup_params_t *fup_params)
|
|||||||
if (!fup_params->peer_inst_id) {
|
if (!fup_params->peer_inst_id) {
|
||||||
fup_params->peer_inst_id = p_peer_svc->svc_id;
|
fup_params->peer_inst_id = p_peer_svc->svc_id;
|
||||||
}
|
}
|
||||||
if (!MACADDR_EQUAL(fup_params->peer_mac, null_mac)) {
|
if (MACADDR_EQUAL(fup_params->peer_mac, null_mac)) {
|
||||||
MACADDR_COPY(fup_params->peer_mac, p_peer_svc->peer_nmi);
|
MACADDR_COPY(fup_params->peer_mac, p_peer_svc->peer_nmi);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1331,17 +1689,48 @@ uint8_t esp_wifi_nan_datapath_req(wifi_nan_datapath_req_t *req)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!MACADDR_EQUAL(req->peer_mac, null_mac)) {
|
if (MACADDR_EQUAL(req->peer_mac, null_mac)) {
|
||||||
MACADDR_COPY(req->peer_mac, p_peer_svc->peer_nmi);
|
MACADDR_COPY(req->peer_mac, p_peer_svc->peer_nmi);
|
||||||
}
|
}
|
||||||
|
|
||||||
os_event_group_clear_bits(nan_event_group, NDP_ACCEPTED | NDP_REJECTED);
|
os_event_group_clear_bits(nan_event_group, NDP_ACCEPTED | NDP_REJECTED);
|
||||||
if (esp_nan_internal_datapath_req(req, &ndp_id,(uint8_t *)&own_ipv6.u_addr.ip6.addr[2]) != ESP_OK) {
|
|
||||||
|
uint32_t saved_pub_id = req->pub_id;
|
||||||
|
uint32_t saved_device_caps = p_peer_svc->device_caps;
|
||||||
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
/* Encrypted datapath: pre-claim an NDL at ndp_id=0 with security_ctx
|
||||||
|
* populated from the subscribe-time security_cfg. The WiFi library's M1 builder
|
||||||
|
* callbacks (construct_scia_ndp_req / get_ndp_req_shared_key_desc /
|
||||||
|
* capture_m1_auth_token) fire inside esp_nan_internal_datapath_req()
|
||||||
|
* before it returns the real ndp_id, and they look up the NDL by
|
||||||
|
* (ndp_id=0, peer_nmi). Open datapath skips the pre-claim entirely --
|
||||||
|
* no security callbacks fire, so there is nothing to look up. */
|
||||||
|
struct ndl_info *preclaimed = nan_ndl_preclaim_initiator(saved_pub_id,
|
||||||
|
req->peer_mac,
|
||||||
|
saved_device_caps);
|
||||||
|
if (preclaimed) {
|
||||||
|
nan_security_populate_initiator_ndl(preclaimed, p_peer_svc->peer_nmi);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Release lock before internal call: the WiFi library may invoke
|
||||||
|
* esp_nan_get_ndp_req_shared_key_desc / esp_nan_construct_scia_ndp_req /
|
||||||
|
* esp_nan_capture_m1_auth_token which all take NAN_DATA_LOCK. Holding
|
||||||
|
* it here would deadlock those callbacks. */
|
||||||
|
NAN_DATA_UNLOCK();
|
||||||
|
|
||||||
|
if (esp_nan_internal_datapath_req(req, &ndp_id, (uint8_t *)&own_ipv6.u_addr.ip6.addr[2]) != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Failed to initiate NDP req");
|
ESP_LOGE(TAG, "Failed to initiate NDP req");
|
||||||
goto fail;
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
NAN_DATA_LOCK();
|
||||||
|
nan_ndl_release(0); /* clean up pre-claimed NDL */
|
||||||
|
NAN_DATA_UNLOCK();
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
nan_record_new_ndl(ndp_id, req->pub_id, req->peer_mac, ESP_WIFI_NDP_ROLE_INITIATOR, p_peer_svc->device_caps);
|
NAN_DATA_LOCK();
|
||||||
|
nan_ndl_finalize_ndp_id(ndp_id, saved_pub_id, req->peer_mac, saved_device_caps);
|
||||||
NAN_DATA_UNLOCK();
|
NAN_DATA_UNLOCK();
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Requested NDP with "MACSTR" [NDP ID - %d]", MAC2STR(req->peer_mac), ndp_id);
|
ESP_LOGD(TAG, "Requested NDP with "MACSTR" [NDP ID - %d]", MAC2STR(req->peer_mac), ndp_id);
|
||||||
@@ -1354,7 +1743,7 @@ uint8_t esp_wifi_nan_datapath_req(wifi_nan_datapath_req_t *req)
|
|||||||
} else {
|
} else {
|
||||||
ESP_LOGE(TAG, "NDP request timed out");
|
ESP_LOGE(TAG, "NDP request timed out");
|
||||||
NAN_DATA_LOCK();
|
NAN_DATA_LOCK();
|
||||||
nan_reset_ndl(ndp_id, false);
|
nan_ndl_release(ndp_id);
|
||||||
NAN_DATA_UNLOCK();
|
NAN_DATA_UNLOCK();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1379,25 +1768,33 @@ esp_err_t esp_wifi_nan_datapath_resp(wifi_nan_datapath_resp_t *resp)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!MACADDR_EQUAL(resp->peer_mac, null_mac)) {
|
if (MACADDR_EQUAL(resp->peer_mac, null_mac)) {
|
||||||
MACADDR_COPY(resp->peer_mac, ndl->peer_nmi);
|
MACADDR_COPY(resp->peer_mac, ndl->peer_nmi);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ndl->device_caps & NAN_CAPS_NDPE_ATTR) {
|
if (ndl->device_caps & NAN_CAPS_NDPE_ATTR) {
|
||||||
esp_err_t err = esp_wifi_get_mac(WIFI_IF_NAN, own_bssid);
|
esp_err_t err = esp_wifi_get_mac(WIFI_IF_NAN, own_bssid);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Cannot get own BSSID!");
|
ESP_LOGE(TAG, "Cannot get own BSSID!");
|
||||||
goto fail;
|
NAN_DATA_UNLOCK();
|
||||||
}
|
goto fail;
|
||||||
esp_wifi_nan_get_ipv6_linklocal_from_mac(&own_ipv6.u_addr.ip6, own_bssid);
|
|
||||||
}
|
}
|
||||||
|
esp_wifi_nan_get_ipv6_linklocal_from_mac(&own_ipv6.u_addr.ip6, own_bssid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release lock before internal call: esp_nan_internal_datapath_resp() may call
|
||||||
|
* esp_nan_get_ndp_resp_shared_key_desc() which takes NAN_DATA_LOCK again → deadlock if we keep the lock. */
|
||||||
|
NAN_DATA_UNLOCK();
|
||||||
|
|
||||||
if (esp_nan_internal_datapath_resp(resp, (uint8_t *)&own_ipv6.u_addr.ip6.addr[2]) == ESP_OK) {
|
if (esp_nan_internal_datapath_resp(resp, (uint8_t *)&own_ipv6.u_addr.ip6.addr[2]) == ESP_OK) {
|
||||||
|
NAN_DATA_LOCK();
|
||||||
s_nan_ctx.event &= ~NDP_INDICATION;
|
s_nan_ctx.event &= ~NDP_INDICATION;
|
||||||
NAN_DATA_UNLOCK();
|
NAN_DATA_UNLOCK();
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ESP_FAIL;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
NAN_DATA_UNLOCK();
|
NAN_DATA_UNLOCK();
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
@@ -1422,7 +1819,7 @@ esp_err_t esp_wifi_nan_datapath_end(wifi_nan_datapath_end_req_t *req)
|
|||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!MACADDR_EQUAL(req->peer_mac, null_mac)) {
|
if (MACADDR_EQUAL(req->peer_mac, null_mac)) {
|
||||||
MACADDR_COPY(req->peer_mac, ndl->peer_nmi);
|
MACADDR_COPY(req->peer_mac, ndl->peer_nmi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,350 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Internal declarations shared between nan_app.c and nan_security.c.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_wifi_types_generic.h"
|
||||||
|
#include "esp_private/wifi.h"
|
||||||
|
#include "esp_nan.h"
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Macros */
|
||||||
|
#ifndef MACADDR_LEN
|
||||||
|
#define MACADDR_LEN 6
|
||||||
|
#endif
|
||||||
|
#define MACADDR_EQUAL(a1, a2) (memcmp(a1, a2, MACADDR_LEN) == 0)
|
||||||
|
#define MACADDR_COPY(dst, src) (memcpy(dst, src, MACADDR_LEN))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shared lock used by both files.
|
||||||
|
*
|
||||||
|
* NAN_DATA_LOCK contract
|
||||||
|
* ----------------------
|
||||||
|
* s_nan_data_lock guards s_nan_ctx (NDL[], own_svc[], state, event,
|
||||||
|
* netif). Anything that reads or mutates these fields takes the lock.
|
||||||
|
*
|
||||||
|
* !!! MUST NOT be held across any esp_nan_internal_* call !!!
|
||||||
|
*
|
||||||
|
* The blob-side esp_nan_internal_* entry points (datapath_req,
|
||||||
|
* datapath_resp, datapath_end, publish_service, subscribe_service,
|
||||||
|
* send_followup, register_callbacks) re-enter host code from the WiFi
|
||||||
|
* task to:
|
||||||
|
* - assemble M1 / M2 / M3 / M4 NDP frames (esp_nan_get_ndp_*_key_desc,
|
||||||
|
* esp_nan_construct_csia / scia, esp_nan_capture_m1_auth_token,
|
||||||
|
* esp_nan_update_ndp_*_mic, esp_nan_verify_ndp_*_mic)
|
||||||
|
* - parse inbound NDP frames (esp_nan_parse_ndp_*)
|
||||||
|
* - fire indication / confirm / response_indication / terminated
|
||||||
|
* callbacks (nan_app_ndp_*_cb)
|
||||||
|
*
|
||||||
|
* All of those re-entry points take NAN_DATA_LOCK themselves. Holding
|
||||||
|
* the lock around the blob call deadlocks the WiFi task as soon as it
|
||||||
|
* tries to call back. Pattern:
|
||||||
|
*
|
||||||
|
* NAN_DATA_LOCK();
|
||||||
|
* ... mutate / capture state needed by the call ...
|
||||||
|
* NAN_DATA_UNLOCK();
|
||||||
|
* err = esp_nan_internal_datapath_req(...);
|
||||||
|
* NAN_DATA_LOCK();
|
||||||
|
* ... record result ...
|
||||||
|
* NAN_DATA_UNLOCK();
|
||||||
|
*
|
||||||
|
* Several past bug-fix commits on this branch (`fix(nan): release
|
||||||
|
* NAN_DATA_LOCK before initiator datapath_req`, `fix(nan): unlock
|
||||||
|
* NAN_DATA on all paths in ndp_indication_cb`) trace back to forgotten
|
||||||
|
* unlocks; new sites that call the blob must follow this pattern.
|
||||||
|
*/
|
||||||
|
extern void *s_nan_data_lock;
|
||||||
|
#define NAN_DATA_LOCK() os_mutex_lock(s_nan_data_lock)
|
||||||
|
#define NAN_DATA_UNLOCK() os_mutex_unlock(s_nan_data_lock)
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
/* NAN 4-way handshake constants (RSNA key descriptor layout) */
|
||||||
|
#define NAN_NONCE_LEN 32
|
||||||
|
#define NAN_REPLAY_COUNTER_LEN 8
|
||||||
|
#define NAN_KEY_RSC_LEN 8
|
||||||
|
#define NAN_KEY_MIC_LEN 16
|
||||||
|
/* KCK/KEK/TK buffer sizes are sized for the largest cipher suite the host
|
||||||
|
* could potentially run (NCS-SK-256 KCK=24, KEK=32, TK=32). Only NCS-SK-128
|
||||||
|
* is wired through M1–M4 today (see nan_get_first_csid) so the *_set fields
|
||||||
|
* mark the live length in the buffer. */
|
||||||
|
#define NAN_ND_KCK_MAX_LEN 24
|
||||||
|
#define NAN_ND_KEK_MAX_LEN 32
|
||||||
|
#define NAN_ND_TK_MAX_LEN 32
|
||||||
|
#define NAN_GTK_MAX_LEN 32
|
||||||
|
#define NAN_AUTH_TOKEN_MAX_LEN 24
|
||||||
|
|
||||||
|
/* RSNA Key Descriptor offsets (same as 802.11 EAPOL-Key) */
|
||||||
|
#define NAN_KEY_DESC_TYPE_OFF 0
|
||||||
|
#define NAN_KEY_DESC_KEY_INFO_OFF 1
|
||||||
|
#define NAN_KEY_DESC_KEY_LEN_OFF 3
|
||||||
|
#define NAN_KEY_DESC_REPLAY_OFF 5
|
||||||
|
#define NAN_KEY_DESC_NONCE_OFF 13
|
||||||
|
#define NAN_KEY_DESC_IV_OFF 45
|
||||||
|
#define NAN_KEY_DESC_RSC_OFF 61
|
||||||
|
#define NAN_KEY_DESC_KEY_ID_OFF 69
|
||||||
|
#define NAN_KEY_DESC_MIC_OFF 77
|
||||||
|
#define NAN_KEY_DESC_DATA_LEN_OFF 93
|
||||||
|
#define NAN_KEY_DESC_DATA_OFF 95
|
||||||
|
#define NAN_KEY_DESC_MIN_LEN 95
|
||||||
|
|
||||||
|
/* Key Descriptor Type (same as 802.11 EAPOL-Key) */
|
||||||
|
#define NAN_KEY_DESC_TYPE_RSN 2
|
||||||
|
|
||||||
|
/* Security Context Identifier (SCID) types (Table 123) */
|
||||||
|
#define NAN_SEC_CTX_TYPE_ND_PMKID 1
|
||||||
|
|
||||||
|
/* Key Info bits (same semantics as RSNA) */
|
||||||
|
#define NAN_KEY_INFO_MIC BIT(8)
|
||||||
|
#define NAN_KEY_INFO_SECURE BIT(9)
|
||||||
|
#define NAN_KEY_INFO_INSTALL BIT(6)
|
||||||
|
#define NAN_KEY_INFO_ACK BIT(7)
|
||||||
|
#define NAN_KEY_INFO_ENC_KEY BIT(12)
|
||||||
|
#define NAN_KEY_INFO_KEY_TYPE BIT(3) /* 1=Pairwise, 0=Group */
|
||||||
|
|
||||||
|
/* NCS-SK-128 only for now (Table 21): KCK 128 bits, KEK 128 bits, TK 128 bits, MIC 16 bytes */
|
||||||
|
#define NAN_NCS_SK_128_KCK_LEN 16
|
||||||
|
#define NAN_NCS_SK_128_KEK_LEN 16
|
||||||
|
#define NAN_NCS_SK_128_TK_LEN 16
|
||||||
|
#define NAN_NCS_SK_128_MIC_LEN 16
|
||||||
|
#define NAN_NCS_SK_128_PTK_LEN (NAN_NCS_SK_128_KCK_LEN + NAN_NCS_SK_128_KEK_LEN + NAN_NCS_SK_128_TK_LEN)
|
||||||
|
|
||||||
|
/* Internal key-install constants matching esp_wifi_set_sta_key_internal semantics. */
|
||||||
|
#define NAN_WIFI_WPA_ALG_CCMP 3
|
||||||
|
#define NAN_KEY_FLAG_RX BIT(2)
|
||||||
|
#define NAN_KEY_FLAG_TX BIT(3)
|
||||||
|
#define NAN_KEY_FLAG_PAIRWISE BIT(5)
|
||||||
|
|
||||||
|
/* Handshake state */
|
||||||
|
enum nan_handshake_state {
|
||||||
|
NAN_HANDSHAKE_IDLE = 0,
|
||||||
|
NAN_HANDSHAKE_M1_SENT, /* Initiator: sent NDP Request (M1) */
|
||||||
|
NAN_HANDSHAKE_M1_RCVD,
|
||||||
|
NAN_HANDSHAKE_M2_SENT,
|
||||||
|
NAN_HANDSHAKE_M2_RCVD,
|
||||||
|
NAN_HANDSHAKE_M3_SENT,
|
||||||
|
NAN_HANDSHAKE_M3_PENDING_VERIFY, /* Responder: M3 parsed, awaits Auth_Token||body MIC verify */
|
||||||
|
NAN_HANDSHAKE_M3_RCVD,
|
||||||
|
NAN_HANDSHAKE_M4_RCVD,
|
||||||
|
NAN_HANDSHAKE_COMPLETE
|
||||||
|
};
|
||||||
|
#endif /* CONFIG_ESP_WIFI_NAN_SECURITY */
|
||||||
|
|
||||||
|
/* Per-peer service info */
|
||||||
|
struct peer_svc_info {
|
||||||
|
SLIST_ENTRY(peer_svc_info) next;
|
||||||
|
uint8_t peer_svc_info[ESP_WIFI_MAX_SVC_INFO_LEN];
|
||||||
|
uint8_t svc_id;
|
||||||
|
uint8_t own_svc_id;
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t peer_nmi[MACADDR_LEN];
|
||||||
|
uint32_t device_caps;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Own (locally registered) service info */
|
||||||
|
struct own_svc_info {
|
||||||
|
char svc_name[ESP_WIFI_MAX_SVC_NAME_LEN];
|
||||||
|
uint8_t svc_id;
|
||||||
|
uint8_t type;
|
||||||
|
|
||||||
|
bool ndp_resp_needed;
|
||||||
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
wifi_nan_discovery_security_params_t security_cfg;
|
||||||
|
uint8_t pmk_cache[ESP_WIFI_NAN_MAX_PMKIDS][ESP_WIFI_NAN_NDP_PMK_LEN];
|
||||||
|
#endif
|
||||||
|
uint8_t num_peer_records;
|
||||||
|
SLIST_HEAD(peer_list_t, peer_svc_info) peer_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Per-NDP link state */
|
||||||
|
struct ndl_info {
|
||||||
|
uint8_t ndp_id;
|
||||||
|
uint8_t peer_ndi[MACADDR_LEN];
|
||||||
|
uint8_t peer_nmi[MACADDR_LEN];
|
||||||
|
uint8_t publisher_id;
|
||||||
|
uint8_t own_role;
|
||||||
|
uint32_t device_caps;
|
||||||
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
wifi_nan_datapath_security_params_t security_ctx;
|
||||||
|
|
||||||
|
uint8_t anonce[NAN_NONCE_LEN];
|
||||||
|
uint8_t snonce[NAN_NONCE_LEN];
|
||||||
|
|
||||||
|
uint8_t nd_kck[NAN_ND_KCK_MAX_LEN];
|
||||||
|
uint8_t nd_kek[NAN_ND_KEK_MAX_LEN];
|
||||||
|
uint8_t nd_tk[NAN_ND_TK_MAX_LEN];
|
||||||
|
uint8_t kck_len;
|
||||||
|
uint8_t kek_len;
|
||||||
|
uint8_t tk_len;
|
||||||
|
uint8_t ptk_set: 1;
|
||||||
|
uint8_t ptk_reserved: 7;
|
||||||
|
|
||||||
|
uint8_t tx_replay_counter[NAN_REPLAY_COUNTER_LEN];
|
||||||
|
uint8_t rx_replay_counter[NAN_REPLAY_COUNTER_LEN];
|
||||||
|
uint8_t rx_replay_counter_set: 1;
|
||||||
|
uint8_t replay_reserved: 7;
|
||||||
|
|
||||||
|
uint8_t auth_token[NAN_AUTH_TOKEN_MAX_LEN];
|
||||||
|
uint8_t auth_token_len;
|
||||||
|
|
||||||
|
uint8_t handshake_state;
|
||||||
|
|
||||||
|
/* Group key state (unsupported -- pairwise-only M1-M4 flow today;
|
||||||
|
* fields kept to match the spec-defined RSNA key descriptor layout
|
||||||
|
* and stay forward-compatible). */
|
||||||
|
uint8_t gtk[NAN_GTK_MAX_LEN];
|
||||||
|
uint8_t igtk[NAN_GTK_MAX_LEN];
|
||||||
|
uint8_t bigtk[NAN_GTK_MAX_LEN];
|
||||||
|
uint8_t gtk_len;
|
||||||
|
uint8_t igtk_len;
|
||||||
|
uint8_t bigtk_len;
|
||||||
|
uint8_t gtk_set: 1;
|
||||||
|
uint8_t igtk_set: 1;
|
||||||
|
uint8_t bigtk_set: 1;
|
||||||
|
uint8_t group_keys_reserved: 5;
|
||||||
|
|
||||||
|
uint8_t key_rsc[NAN_KEY_RSC_LEN];
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/* NAN context shared between files */
|
||||||
|
typedef struct {
|
||||||
|
uint8_t state;
|
||||||
|
uint8_t event;
|
||||||
|
struct ndl_info ndl[ESP_WIFI_NAN_DATAPATH_MAX_PEERS];
|
||||||
|
struct own_svc_info own_svc[ESP_WIFI_NAN_MAX_SVC_SUPPORTED];
|
||||||
|
esp_netif_t *nan_netif;
|
||||||
|
} nan_ctx_t;
|
||||||
|
|
||||||
|
extern nan_ctx_t s_nan_ctx;
|
||||||
|
|
||||||
|
/* Helpers defined in nan_app.c, used by nan_security.c */
|
||||||
|
struct own_svc_info *nan_find_own_svc(uint8_t svc_id);
|
||||||
|
struct ndl_info *nan_find_ndl(uint8_t ndp_id, uint8_t peer_nmi[]);
|
||||||
|
struct ndl_info *nan_find_ndl_by_pub_id_and_peer(uint8_t pub_id, const uint8_t *peer_nmi);
|
||||||
|
|
||||||
|
/* === nan_secure_dp_funcs initializer targets === */
|
||||||
|
|
||||||
|
/* Always-present (defined in nan_app.c) */
|
||||||
|
void esp_nan_ndp_tx_done_cb(uint8_t ndp_id, const uint8_t *peer_nmi,
|
||||||
|
uint8_t msg_type, bool tx_status);
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||||
|
/* Security-gated (defined in nan_security.c) */
|
||||||
|
uint32_t esp_nan_get_csia_len(uint16_t own_csid_bitmap, uint16_t peer_csid_bitmap);
|
||||||
|
uint32_t esp_nan_get_scia_len(uint8_t num_pmkids);
|
||||||
|
uint32_t esp_nan_get_shared_key_desc_attr_len(uint16_t key_data_len);
|
||||||
|
int esp_nan_ndp_security_install_get_shared_desc_len(void);
|
||||||
|
|
||||||
|
int esp_nan_construct_csia(uint8_t *frm, uint8_t pub_id,
|
||||||
|
uint16_t own_csid_bitmap, uint16_t peer_csid_bitmap);
|
||||||
|
int esp_nan_construct_scia_publish(uint8_t *frm, uint8_t pub_id,
|
||||||
|
uint8_t num_pmkids,
|
||||||
|
const uint8_t pmkids[][ESP_WIFI_NAN_NDP_PMKID_LEN]);
|
||||||
|
int esp_nan_construct_scia_ndp_req(uint8_t *frm, uint8_t ndp_id,
|
||||||
|
const uint8_t *peer_nmi);
|
||||||
|
int esp_nan_construct_scia_ndp_resp(uint8_t *frm, uint8_t ndp_id,
|
||||||
|
const uint8_t *peer_nmi);
|
||||||
|
|
||||||
|
int esp_nan_get_ndp_req_shared_key_desc(uint8_t *buf, size_t buf_len,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
int esp_nan_get_ndp_resp_shared_key_desc(uint8_t *buf, size_t buf_len,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
int esp_nan_get_ndp_confirm_shared_key_desc(uint8_t *buf, size_t buf_len,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
int esp_nan_get_ndp_security_install_key_desc(uint8_t *buf, size_t buf_len,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
|
||||||
|
int esp_nan_capture_m1_auth_token(const uint8_t *m1_body, size_t body_len,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
|
||||||
|
int esp_nan_update_ndp_resp_mic(uint8_t *m2_body, size_t body_len,
|
||||||
|
uint8_t *key_desc_attr,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
int esp_nan_update_ndp_confirm_mic(uint8_t *m3_body, size_t body_len,
|
||||||
|
uint8_t *key_desc_attr,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
int esp_nan_update_ndp_security_install_mic(uint8_t *m4_body, size_t body_len,
|
||||||
|
uint8_t *key_desc_attr,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
|
||||||
|
int esp_nan_verify_ndp_resp_mic(uint8_t *m2_body, size_t body_len,
|
||||||
|
uint8_t *key_desc_attr,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
int esp_nan_verify_ndp_confirm_mic(uint8_t *m3_body, size_t body_len,
|
||||||
|
uint8_t *key_desc_attr,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
int esp_nan_verify_ndp_security_install_mic(uint8_t *m4_body, size_t body_len,
|
||||||
|
uint8_t *key_desc_attr,
|
||||||
|
uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
|
||||||
|
void esp_nan_parse_ndp_csia(void *frm, size_t buf_len, wifi_nan_datapath_security_params_t *param);
|
||||||
|
void esp_nan_parse_ndp_scia(void *frm, size_t buf_len, wifi_nan_datapath_security_params_t *param);
|
||||||
|
void esp_nan_parse_ndp_key_desc(void *frm, size_t buf_len, uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
|
||||||
|
esp_err_t esp_nan_parse_publish_security(const uint8_t *attrs, size_t attrs_len,
|
||||||
|
wifi_nan_discovery_security_params_t *security);
|
||||||
|
|
||||||
|
/* Helpers defined in nan_security.c, used by nan_app.c */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Apply any pending CSIA/SCIA/M1 state captured by the NDP key-desc parser
|
||||||
|
* onto the freshly-created NDL. Called from nan_app_ndp_indication_cb once
|
||||||
|
* (ndp_id, peer_nmi, peer_ndi, p_own_svc) are all known.
|
||||||
|
*/
|
||||||
|
void nan_security_apply_pending(struct ndl_info *ndl,
|
||||||
|
struct own_svc_info *p_own_svc,
|
||||||
|
uint8_t pub_id,
|
||||||
|
const uint8_t *peer_nmi,
|
||||||
|
const uint8_t *peer_ndi);
|
||||||
|
|
||||||
|
/* PMK / PMKID derivation entry point used by the publish path. */
|
||||||
|
esp_err_t nan_derive_security_params(wifi_nan_publish_cfg_t *cfg);
|
||||||
|
|
||||||
|
/* Blob-side gate query: returns ndl->security_ctx.csid_bitmap for the NDP
|
||||||
|
* keyed on (ndp_id, peer_nmi), or 0 if no NDL match. ndp_id=0 is valid for
|
||||||
|
* the initiator pre-claim window (peer-only lookup). */
|
||||||
|
uint16_t nan_get_ndp_security_csid(uint8_t ndp_id, const uint8_t *peer_nmi);
|
||||||
|
|
||||||
|
/* Subscribe path: cache security_cfg + service name for PMKID verification on match. */
|
||||||
|
void nan_security_cache_subscriber_params(const char *service_name,
|
||||||
|
const wifi_nan_discovery_security_params_t *security_cfg);
|
||||||
|
|
||||||
|
/* Subscribe path: populate the initiator NDL's security_ctx (cipher + pair-PMKID +
|
||||||
|
* ND-PMK) from the cached subscriber params, so the blob's CSIA/SCIA/Shared-Key
|
||||||
|
* Descriptor builder callbacks find security keyed by (ndp_id, peer_nmi).
|
||||||
|
* No-op if subscriber didn't request encrypted datapath. */
|
||||||
|
esp_err_t nan_security_populate_initiator_ndl(struct ndl_info *ndl,
|
||||||
|
const uint8_t *peer_nmi);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare locally derived ND-PMKID (subscriber passphrase, publisher NMI) to
|
||||||
|
* peer discovery security params. publisher_nmi is the publisher's NAN MAC
|
||||||
|
* from the service-match callback.
|
||||||
|
*/
|
||||||
|
bool nan_security_service_match(const uint8_t *publisher_nmi,
|
||||||
|
const wifi_nan_discovery_security_params_t *peer_sec);
|
||||||
|
#else
|
||||||
|
static inline esp_err_t nan_derive_security_params(wifi_nan_publish_cfg_t *cfg)
|
||||||
|
{
|
||||||
|
(void)cfg;
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_ESP_WIFI_NAN_SECURITY */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user