mirror of
https://github.com/espressif/esp-idf.git
synced 2026-05-28 16:46:31 +03:00
feat(esp_wifi): NAN Pairing Improvements and bugfixes
- Route NAN pairing bootstrap via NPBA receive path - extend datapath_req wait time to fit secured M1-M4 handshake - Plug ND-PMK derived from KDK into NDP - prefers paired-peer cached ND-PMK (from PASN pairing complete), when available - carry ND-PMK metadata in pairing install callback - Extend PASN key-installed callback payload to include role, mapped NDP CSID and derived ND-PMK so the NAN layer can populate paired-peer security cache. Co-authored-by: Akshat Agrawal <akshat.agrawal@espressif.com> Co-authored-by: Sarvesh Bodakhe <sarvesh.bodakhe@espressif.com>
This commit is contained in:
committed by
Sarvesh Bodakhe
parent
9f361f478d
commit
0f8d4b74a0
@@ -356,12 +356,10 @@ menu "Wi-Fi"
|
||||
|
||||
config ESP_WIFI_PASN_SUPPORT
|
||||
bool "Enable PASN support"
|
||||
depends on ESP_WIFI_NAN_PAIRING
|
||||
default y if ESP_WIFI_NAN_PAIRING
|
||||
default n
|
||||
help
|
||||
Enable PASN for Wi-Fi NAN; the supplicant exposes CONFIG_PASN when this is on.
|
||||
This option is only available when "NAN-Sync pairing bootstrapping"
|
||||
(ESP_WIFI_NAN_PAIRING) is enabled, because NAN PASN builds on that path.
|
||||
Pre-Association Security Negotiation (PASN) for Wi-Fi NAN.
|
||||
The wpa_supplicant exposes CONFIG_PASN when this is on.
|
||||
|
||||
config ESP_WIFI_SLP_IRAM_OPT
|
||||
bool "WiFi SLP IRAM speed optimization"
|
||||
@@ -628,12 +626,13 @@ menu "Wi-Fi"
|
||||
|
||||
config ESP_WIFI_NAN_PAIRING
|
||||
bool "Enable NAN Pairing"
|
||||
depends on ESP_WIFI_NAN_SYNC_ENABLE
|
||||
depends on ESP_WIFI_NAN_SECURITY && IDF_EXPERIMENTAL_FEATURES && ESP_WIFI_MBEDTLS_CRYPTO
|
||||
select ESP_WIFI_PASN_SUPPORT
|
||||
default n
|
||||
help
|
||||
Enable NAN Pairing support. This allows devices to establish
|
||||
secure pairing using bootstrapping methods like PIN code or
|
||||
opportunistic pairing as defined in Wi-Fi Aware specification.
|
||||
secure pairing using bootstrapping methods like PIN code.
|
||||
Requires PASN in wpa_supplicant (ESP_WIFI_PASN_SUPPORT)
|
||||
|
||||
config ESP_WIFI_MBEDTLS_CRYPTO
|
||||
bool "Use MbedTLS crypto APIs"
|
||||
|
||||
@@ -73,22 +73,26 @@ typedef struct {
|
||||
} wifi_nan_security_params_t;
|
||||
|
||||
/**
|
||||
* @brief NAN peer security material parsed from Publish/Subscribe SDF SCIA
|
||||
* @brief NAN peer security and pairing material parsed from Publish/Subscribe SDF
|
||||
*
|
||||
* @note Per Wi-Fi Aware v4.0 §7.1.3.5, a publisher SDF SCIA may advertise
|
||||
* multiple ND-PMKIDs (one per cached PMK). The receiver stores them
|
||||
* and matches against locally-derived PMKID at NDP-initiation time.
|
||||
* Pairing flags mirror wifi_event_nan_svc_match_t and are filled by the
|
||||
* NAN blob when parsing CSIA/SCIA/DCEA.
|
||||
* Internal only — not part of the public API. Shared between WiFi
|
||||
* libraries and NAN app layer.
|
||||
*/
|
||||
#define NAN_PEER_MAX_PMKIDS 2 /**< Internal cap; can grow without API impact */
|
||||
typedef struct {
|
||||
uint16_t csid_bitmap; /**< Peer's advertised Cipher Suite ID bitmap */
|
||||
uint16_t csid_bitmap; /**< Peer's advertised Cipher Suite ID bitmap (WIFI_NAN_CSID_BIT_*) */
|
||||
uint8_t num_pmkids; /**< Number of parsed PMKIDs */
|
||||
uint8_t pmkids[NAN_PEER_MAX_PMKIDS][ESP_WIFI_NAN_NDP_PMKID_LEN]; /**< Parsed ND-PMKIDs */
|
||||
uint8_t group_data_prot: 1; /**< Peer advertises group data frame protection */
|
||||
uint8_t group_mgmt_prot: 1; /**< Peer advertises group mgmt frame protection */
|
||||
uint8_t reserved: 6; /**< Reserved */
|
||||
uint8_t pairing_setup: 1; /**< Pairing setup: 0 - disabled, 1 - enabled */
|
||||
uint8_t npk_nik_caching: 1; /**< NPK/NIK caching: 0 - disabled, 1 - enabled (valid if pairing_setup) */
|
||||
uint8_t reserved: 4; /**< Reserved */
|
||||
} wifi_nan_peer_sdf_security_t;
|
||||
|
||||
/* NAN Peer info parsed from SDF */
|
||||
@@ -102,7 +106,6 @@ struct nan_cb_peer_info {
|
||||
uint16_t ssi_len; /**< SSI length in bytes */
|
||||
wifi_nan_peer_sdf_security_t *peer_security_params; /**< Peer's discovery security params parsed from SDF */
|
||||
nan_vendor_ie_t *vendor_ie; /**< Vendor-specific IE, if any */
|
||||
uint8_t *shared_key_attr; /**< Shared key descriptor attribute, if any */
|
||||
};
|
||||
|
||||
/* NDP Peer info parsed from NAF. */
|
||||
@@ -114,6 +117,13 @@ struct ndp_cb_peer_info {
|
||||
uint16_t ssi_len;
|
||||
};
|
||||
|
||||
/* NAN Pairing Bootstrapping parameters parsed from SDF */
|
||||
struct nan_cb_npba_t {
|
||||
uint8_t type;
|
||||
uint8_t status;
|
||||
uint16_t methods;
|
||||
};
|
||||
|
||||
/* Host-side callbacks the closed-source NAN blob fires up into nan_app.
|
||||
* Registered once at nan_app init; all callbacks run in blob/WiFi-task
|
||||
* context, so handlers must be non-blocking and avoid heavy work. */
|
||||
@@ -121,8 +131,10 @@ struct nan_sync_callbacks {
|
||||
/* Subscriber side: a Publish SDF matching the local subscribe was
|
||||
* received from a peer.
|
||||
* sub_id -- local subscribe service instance ID
|
||||
* peer_info -- publisher details (see struct nan_cb_peer_info) */
|
||||
void (* service_match)(uint8_t sub_id, struct nan_cb_peer_info *peer_info);
|
||||
* peer_info -- publisher details (see struct nan_cb_peer_info)
|
||||
* npba -- NPBA parsed from Publish SDF (Advertise), or NULL */
|
||||
void (* service_match)(uint8_t sub_id, struct nan_cb_peer_info *peer_info,
|
||||
struct nan_cb_npba_t *npba);
|
||||
|
||||
/* Publisher side: a Solicited Publish SDF was just transmitted in
|
||||
* response to a Subscribe match. Fires once per recipient.
|
||||
@@ -133,8 +145,14 @@ struct nan_sync_callbacks {
|
||||
/* Either side: a Follow-up SDF was received for an existing service
|
||||
* match (post-discovery messaging).
|
||||
* svc_id -- local service instance ID this Follow-up targets
|
||||
* peer_info -- sender MAC and SSI payload */
|
||||
void (* receive)(uint8_t svc_id, struct nan_cb_peer_info *peer_info);
|
||||
* peer_info -- sender MAC and SSI payload
|
||||
* shared_key_attr -- Shared key descriptor attribute, if any
|
||||
* shared_key_attr_buf_len -- total attribute length for pointer
|
||||
* shared_key_attr (0 if shared_key_attr is NULL)
|
||||
* npba -- NAN Pairing Bootstrapping parameters, if any */
|
||||
void (* receive)(uint8_t svc_id, struct nan_cb_peer_info *peer_info,
|
||||
uint8_t *shared_key_attr, uint16_t shared_key_attr_len,
|
||||
struct nan_cb_npba_t *npba);
|
||||
|
||||
/* Publisher side (NDP Responder): an NDP Request (M1) was received.
|
||||
* Host either auto-accepts or waits for esp_wifi_nan_datapath_resp()
|
||||
@@ -174,8 +192,6 @@ struct nan_sync_callbacks {
|
||||
* 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);
|
||||
void (* pairing_indication)(uint8_t peer_svc_id, uint8_t pub_id, uint8_t peer_nmi[6], uint16_t selected_method);
|
||||
void (* pairing_confirm)(uint8_t status, uint8_t peer_svc_id, uint8_t sub_id, uint8_t peer_nmi[6], uint16_t matched_method, uint8_t reason_code);
|
||||
void (* receive_pasn)(uint8_t *buf, size_t len, uint16_t trans_seq, uint16_t status);
|
||||
uint32_t (* get_nira_len)(void);
|
||||
int (* construct_nira)(uint8_t *frm);
|
||||
@@ -1181,23 +1197,6 @@ uint32_t esp_nan_get_nira_len(void);
|
||||
*/
|
||||
int esp_nan_construct_nira(uint8_t *frm);
|
||||
|
||||
/**
|
||||
* @brief Get length of Management MIC Element (MME)
|
||||
*
|
||||
* @return Length in bytes
|
||||
*/
|
||||
uint32_t esp_nan_get_mme_len(void);
|
||||
|
||||
/**
|
||||
* @brief Construct dummy Management MIC Element (MME)
|
||||
*
|
||||
* @param[out] frm Buffer to write the element to
|
||||
* @param[in] ipn Incremental Packet Number (6-byte IPN, lower 4 bytes used from this param)
|
||||
*
|
||||
* @return Number of bytes written
|
||||
*/
|
||||
int esp_nan_construct_mme(uint8_t *frm, uint32_t ipn);
|
||||
|
||||
/**
|
||||
* @brief Get the time information from the MAC clock. The time is precise only if modem sleep or light sleep is not enabled.
|
||||
*
|
||||
|
||||
@@ -979,10 +979,10 @@ typedef struct {
|
||||
} wifi_nan_discovery_security_params_t;
|
||||
|
||||
/**
|
||||
* @brief NAN Pairing Bootstrapping Method bitmask (per Wi-Fi Aware 4.0 spec)
|
||||
* @brief NAN Pairing Bootstrapping Method bitmap (per Wi-Fi Aware 4.0 spec)
|
||||
*
|
||||
* Each bit corresponds to a bootstrapping method capability.
|
||||
* Multiple bits can be set simultaneously in the NPBA attribute.
|
||||
* Each bit corresponds to one bootstrapping method (WIFI_NAN_BOOTSTRAP_*).
|
||||
* Multiple bits may be set in bootstrapping_methods / NPBA.
|
||||
*/
|
||||
#define WIFI_NAN_BOOTSTRAP_OPPORTUNISTIC BIT(0) /**< Opportunistic bootstrapping */
|
||||
#define WIFI_NAN_BOOTSTRAP_PIN_CODE_DISPLAY BIT(1) /**< Pin-code display */
|
||||
@@ -1003,7 +1003,7 @@ typedef struct {
|
||||
uint8_t npk_nik_caching: 1; /**< 0 - NPK/NIK caching disabled, 1 - enabled */
|
||||
uint8_t pairing_verification: 1; /**< 0 - Pairing verification disabled, 1 - enabled */
|
||||
uint8_t reserved: 5; /**< Reserved bits */
|
||||
uint16_t bootstrapping_methods; /**< Bitmask of wifi_nan_bootstrap_method_t */
|
||||
uint16_t bootstrapping_methods; /**< Bitmap of WIFI_NAN_BOOTSTRAP_* method bits */
|
||||
uint16_t comeback_delay; /**< Comeback delay in TUs, 0 if comeback not required */
|
||||
} wifi_nan_pairing_cfg_t;
|
||||
|
||||
@@ -1056,7 +1056,7 @@ typedef struct {
|
||||
The driver makes a private copy during esp_wifi_nan_publish_service();
|
||||
the caller may free this immediately after the call returns. */
|
||||
nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in publish frames */
|
||||
wifi_nan_pairing_cfg_t pairing; /**< Pairing configuration parameters */
|
||||
wifi_nan_pairing_cfg_t *pairing; /**< Pairing configuration parameters */
|
||||
} wifi_nan_publish_cfg_t;
|
||||
|
||||
/**
|
||||
@@ -1083,7 +1083,7 @@ typedef struct {
|
||||
The driver makes a private copy during esp_wifi_nan_subscribe_service();
|
||||
the caller may free this immediately after the call returns. */
|
||||
nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in subscribe frames */
|
||||
wifi_nan_pairing_cfg_t pairing; /**< Pairing configuration parameters */
|
||||
wifi_nan_pairing_cfg_t *pairing; /**< Pairing configuration parameters */
|
||||
} wifi_nan_subscribe_cfg_t;
|
||||
|
||||
/**
|
||||
@@ -1292,10 +1292,6 @@ typedef enum {
|
||||
WIFI_EVENT_NDP_INDICATION, /**< Received NDP Request from a NAN Peer */
|
||||
WIFI_EVENT_NDP_CONFIRM, /**< NDP Confirm Indication */
|
||||
WIFI_EVENT_NDP_TERMINATED, /**< NAN Datapath terminated indication */
|
||||
WIFI_EVENT_NAN_BOOTSTRAP_INDICATION, /**< Received NAN Pairing Bootstrapping Request from a Peer */
|
||||
WIFI_EVENT_NAN_BOOTSTRAP_COMPLETED, /**< NAN Pairing Bootstrapping completed (success/failure) */
|
||||
WIFI_EVENT_NAN_PAIRING_INDICATION, /**< Received NAN Pairing indication (reserved) */
|
||||
WIFI_EVENT_NAN_PAIRING_CONFIRM, /**< NAN PASN pairwise key installation completed */
|
||||
WIFI_EVENT_HOME_CHANNEL_CHANGE, /**< Wi-Fi home channel change,doesn't occur when scanning */
|
||||
|
||||
WIFI_EVENT_STA_NEIGHBOR_REP, /**< Received Neighbor Report response */
|
||||
@@ -1306,6 +1302,10 @@ typedef enum {
|
||||
WIFI_EVENT_DPP_URI_READY, /**< DPP URI is ready through Bootstrapping */
|
||||
WIFI_EVENT_DPP_CFG_RECVD, /**< Config received via DPP Authentication */
|
||||
WIFI_EVENT_DPP_FAILED, /**< DPP failed */
|
||||
WIFI_EVENT_NAN_BOOTSTRAP_INDICATION, /**< Received NAN Pairing Bootstrapping Request from a Peer */
|
||||
WIFI_EVENT_NAN_BOOTSTRAP_COMPLETED, /**< NAN Pairing Bootstrapping completed (success/failure) */
|
||||
WIFI_EVENT_NAN_PAIRING_INDICATION, /**< Received NAN Pairing indication (reserved) */
|
||||
WIFI_EVENT_NAN_PAIRING_CONFIRM, /**< NAN PASN pairwise key installation completed */
|
||||
WIFI_EVENT_MAX, /**< Invalid Wi-Fi event ID */
|
||||
} wifi_event_t;
|
||||
|
||||
@@ -1543,21 +1543,24 @@ typedef struct {
|
||||
* @brief Argument structure for WIFI_EVENT_NAN_SVC_MATCH event
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t subscribe_id; /**< Subscribe Service Identifier */
|
||||
uint8_t publish_id; /**< Publish Service Identifier */
|
||||
uint8_t pub_if_mac[6]; /**< NAN Interface MAC of the Publisher */
|
||||
bool update_pub_id; /**< Indicates whether publisher's service ID needs to be updated */
|
||||
uint8_t datapath_reqd: 1; /**< NAN Datapath required for the service */
|
||||
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 ndpe_support: 1; /**< NDPE supported by peer */
|
||||
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_2; /**< Reserved */
|
||||
uint8_t ssi_version; /**< Indicates version of SSI in Publish instance, 0 if not available */
|
||||
uint16_t ssi_len; /**< Length of service specific info */
|
||||
uint8_t ssi[]; /**< Service specific info of Publisher */
|
||||
uint8_t subscribe_id; /**< Subscribe Service Identifier */
|
||||
uint8_t publish_id; /**< Publish Service Identifier */
|
||||
uint8_t pub_if_mac[6]; /**< NAN Interface MAC of the Publisher */
|
||||
bool update_pub_id; /**< Indicates whether publisher's service ID needs to be updated */
|
||||
uint8_t datapath_reqd: 1; /**< NAN Datapath required for the service */
|
||||
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 ndpe_support: 1; /**< NDPE supported by peer */
|
||||
uint8_t security_reqd: 1; /**< Security: 0 - Open, 1 - Required (NDP Security) */
|
||||
uint8_t pairing_setup: 1; /**< Pairing setup: 0 - disabled, 1 - enabled (needs security_reqd:1) */
|
||||
uint8_t npk_nik_caching: 1; /**< NPK/NIK caching: 0 - disabled, 1 - enabled (valid if pairing_setup:1)*/
|
||||
uint8_t already_paired: 1; /**< 0 - not paired, 1 - device already paired */
|
||||
uint16_t csid_bitmap; /**< Supported Cipher Suite bitmap, each bit of type WIFI_NAN_CSID_BIT_[] */
|
||||
uint16_t bootstrapping_methods; /**< Peer advertised bootstrapping methods (WIFI_NAN_BOOTSTRAP_* bitmap) */
|
||||
uint32_t reserved_2; /**< Reserved */
|
||||
uint8_t ssi_version; /**< Indicates version of SSI in Publish instance, 0 if not available */
|
||||
uint16_t ssi_len; /**< Length of service specific info */
|
||||
uint8_t ssi[]; /**< Service specific info of Publisher */
|
||||
} wifi_event_nan_svc_match_t;
|
||||
|
||||
/**
|
||||
@@ -1627,13 +1630,13 @@ typedef struct {
|
||||
* @brief Argument structure for WIFI_EVENT_NAN_BOOTSTRAP_INDICATION event
|
||||
*
|
||||
* Posted when a NAN Pairing Bootstrapping Request is received from a peer.
|
||||
* The application should respond using esp_wifi_nan_pairing_response().
|
||||
* The application should respond using esp_wifi_nan_bootstrap_response().
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t peer_svc_id; /**< Peer's service instance id */
|
||||
uint8_t own_svc_id; /**< Own service instance id */
|
||||
uint8_t peer_nmi[6]; /**< Peer's NAN Management Interface MAC */
|
||||
uint16_t selected_method; /**< Bootstrapping method selected by initiator (wifi_nan_bootstrap_method_t) */
|
||||
uint16_t selected_method; /**< Bootstrapping method selected by initiator (one WIFI_NAN_BOOTSTRAP_* bit) */
|
||||
uint8_t is_comeback; /**< 1 if this is a comeback retry with cookie */
|
||||
uint32_t cookie; /**< Comeback cookie from initiator (0 if none) */
|
||||
} wifi_event_nan_bootstrap_indication_t;
|
||||
@@ -1649,7 +1652,7 @@ typedef struct {
|
||||
uint8_t peer_svc_id; /**< Peer's service instance id */
|
||||
uint8_t own_svc_id; /**< Own service instance id */
|
||||
uint8_t peer_nmi[6]; /**< Peer's NAN Management Interface MAC */
|
||||
uint16_t matched_method; /**< Matched bootstrapping method (valid if accepted) */
|
||||
uint16_t matched_method; /**< Matched bootstrapping method, one WIFI_NAN_BOOTSTRAP_* bit (valid if accepted) */
|
||||
uint8_t reason_code; /**< Rejection reason (valid if rejected) */
|
||||
uint16_t comeback_after; /**< Comeback deferral time in TUs (valid if comeback) */
|
||||
uint32_t cookie; /**< Comeback cookie from responder (0 if none) */
|
||||
|
||||
Submodule components/esp_wifi/lib updated: e61a56b9e6...b83b04d03d
@@ -335,12 +335,10 @@ config WIFI_RMT_ENABLE_WPA3_OWE_SOFTAP
|
||||
|
||||
config WIFI_RMT_PASN_SUPPORT
|
||||
bool "Enable PASN support"
|
||||
depends on WIFI_RMT_NAN_PAIRING
|
||||
default y if WIFI_RMT_NAN_PAIRING
|
||||
default n
|
||||
help
|
||||
Enable PASN for Wi-Fi NAN; the supplicant exposes CONFIG_PASN when this is on.
|
||||
This option is only available when "NAN-Sync pairing bootstrapping"
|
||||
(WIFI_RMT_NAN_PAIRING) is enabled, because NAN PASN builds on that path.
|
||||
Pre-Association Security Negotiation (PASN) for Wi-Fi NAN.
|
||||
The wpa_supplicant exposes CONFIG_PASN when this is on.
|
||||
|
||||
config WIFI_RMT_SLP_IRAM_OPT
|
||||
bool "WiFi SLP IRAM speed optimization"
|
||||
@@ -607,12 +605,13 @@ config WIFI_RMT_NAN_USD_ENABLE
|
||||
|
||||
config WIFI_RMT_NAN_PAIRING
|
||||
bool "Enable NAN Pairing"
|
||||
depends on WIFI_RMT_NAN_SYNC_ENABLE
|
||||
depends on WIFI_RMT_NAN_SECURITY && IDF_EXPERIMENTAL_FEATURES && WIFI_RMT_MBEDTLS_CRYPTO
|
||||
select WIFI_RMT_PASN_SUPPORT
|
||||
default n
|
||||
help
|
||||
Enable NAN Pairing support. This allows devices to establish
|
||||
secure pairing using bootstrapping methods like PIN code or
|
||||
opportunistic pairing as defined in Wi-Fi Aware specification.
|
||||
secure pairing using bootstrapping methods like PIN code.
|
||||
Requires PASN in wpa_supplicant (WIFI_RMT_PASN_SUPPORT)
|
||||
|
||||
config WIFI_RMT_MBEDTLS_CRYPTO
|
||||
bool "Use MbedTLS crypto APIs"
|
||||
|
||||
@@ -152,7 +152,6 @@ endif
|
||||
if WIFI_RMT_PASN_SUPPORT
|
||||
config ESP_WIFI_PASN_SUPPORT # ignore: multiple-definition
|
||||
bool
|
||||
depends on WIFI_RMT_NAN_PAIRING
|
||||
default WIFI_RMT_PASN_SUPPORT
|
||||
endif
|
||||
|
||||
@@ -314,7 +313,7 @@ endif
|
||||
if WIFI_RMT_NAN_PAIRING
|
||||
config ESP_WIFI_NAN_PAIRING # ignore: multiple-definition
|
||||
bool
|
||||
depends on WIFI_RMT_NAN_SYNC_ENABLE
|
||||
depends on WIFI_RMT_NAN_SECURITY && IDF_EXPERIMENTAL_FEATURES && WIFI_RMT_MBEDTLS_CRYPTO
|
||||
default WIFI_RMT_NAN_PAIRING
|
||||
endif
|
||||
|
||||
|
||||
@@ -979,10 +979,10 @@ typedef struct {
|
||||
} wifi_nan_discovery_security_params_t;
|
||||
|
||||
/**
|
||||
* @brief NAN Pairing Bootstrapping Method bitmask (per Wi-Fi Aware 4.0 spec)
|
||||
* @brief NAN Pairing Bootstrapping Method bitmap (per Wi-Fi Aware 4.0 spec)
|
||||
*
|
||||
* Each bit corresponds to a bootstrapping method capability.
|
||||
* Multiple bits can be set simultaneously in the NPBA attribute.
|
||||
* Each bit corresponds to one bootstrapping method (WIFI_NAN_BOOTSTRAP_*).
|
||||
* Multiple bits may be set in bootstrapping_methods / NPBA.
|
||||
*/
|
||||
#define WIFI_NAN_BOOTSTRAP_OPPORTUNISTIC BIT(0) /**< Opportunistic bootstrapping */
|
||||
#define WIFI_NAN_BOOTSTRAP_PIN_CODE_DISPLAY BIT(1) /**< Pin-code display */
|
||||
@@ -1003,7 +1003,7 @@ typedef struct {
|
||||
uint8_t npk_nik_caching: 1; /**< 0 - NPK/NIK caching disabled, 1 - enabled */
|
||||
uint8_t pairing_verification: 1; /**< 0 - Pairing verification disabled, 1 - enabled */
|
||||
uint8_t reserved: 5; /**< Reserved bits */
|
||||
uint16_t bootstrapping_methods; /**< Bitmask of wifi_nan_bootstrap_method_t */
|
||||
uint16_t bootstrapping_methods; /**< Bitmap of WIFI_NAN_BOOTSTRAP_* method bits */
|
||||
uint16_t comeback_delay; /**< Comeback delay in TUs, 0 if comeback not required */
|
||||
} wifi_nan_pairing_cfg_t;
|
||||
|
||||
@@ -1056,7 +1056,7 @@ typedef struct {
|
||||
The driver makes a private copy during esp_wifi_nan_publish_service();
|
||||
the caller may free this immediately after the call returns. */
|
||||
nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in publish frames */
|
||||
wifi_nan_pairing_cfg_t pairing; /**< Pairing configuration parameters */
|
||||
wifi_nan_pairing_cfg_t *pairing; /**< Pairing configuration parameters */
|
||||
} wifi_nan_publish_cfg_t;
|
||||
|
||||
/**
|
||||
@@ -1083,7 +1083,7 @@ typedef struct {
|
||||
The driver makes a private copy during esp_wifi_nan_subscribe_service();
|
||||
the caller may free this immediately after the call returns. */
|
||||
nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in subscribe frames */
|
||||
wifi_nan_pairing_cfg_t pairing; /**< Pairing configuration parameters */
|
||||
wifi_nan_pairing_cfg_t *pairing; /**< Pairing configuration parameters */
|
||||
} wifi_nan_subscribe_cfg_t;
|
||||
|
||||
/**
|
||||
@@ -1292,10 +1292,6 @@ typedef enum {
|
||||
WIFI_EVENT_NDP_INDICATION, /**< Received NDP Request from a NAN Peer */
|
||||
WIFI_EVENT_NDP_CONFIRM, /**< NDP Confirm Indication */
|
||||
WIFI_EVENT_NDP_TERMINATED, /**< NAN Datapath terminated indication */
|
||||
WIFI_EVENT_NAN_BOOTSTRAP_INDICATION, /**< Received NAN Pairing Bootstrapping Request from a Peer */
|
||||
WIFI_EVENT_NAN_BOOTSTRAP_COMPLETED, /**< NAN Pairing Bootstrapping completed (success/failure) */
|
||||
WIFI_EVENT_NAN_PAIRING_INDICATION, /**< Received NAN Pairing indication (reserved) */
|
||||
WIFI_EVENT_NAN_PAIRING_CONFIRM, /**< NAN PASN pairwise key installation completed */
|
||||
WIFI_EVENT_HOME_CHANNEL_CHANGE, /**< Wi-Fi home channel change,doesn't occur when scanning */
|
||||
|
||||
WIFI_EVENT_STA_NEIGHBOR_REP, /**< Received Neighbor Report response */
|
||||
@@ -1306,6 +1302,10 @@ typedef enum {
|
||||
WIFI_EVENT_DPP_URI_READY, /**< DPP URI is ready through Bootstrapping */
|
||||
WIFI_EVENT_DPP_CFG_RECVD, /**< Config received via DPP Authentication */
|
||||
WIFI_EVENT_DPP_FAILED, /**< DPP failed */
|
||||
WIFI_EVENT_NAN_BOOTSTRAP_INDICATION, /**< Received NAN Pairing Bootstrapping Request from a Peer */
|
||||
WIFI_EVENT_NAN_BOOTSTRAP_COMPLETED, /**< NAN Pairing Bootstrapping completed (success/failure) */
|
||||
WIFI_EVENT_NAN_PAIRING_INDICATION, /**< Received NAN Pairing indication (reserved) */
|
||||
WIFI_EVENT_NAN_PAIRING_CONFIRM, /**< NAN PASN pairwise key installation completed */
|
||||
WIFI_EVENT_MAX, /**< Invalid Wi-Fi event ID */
|
||||
} wifi_event_t;
|
||||
|
||||
@@ -1543,21 +1543,24 @@ typedef struct {
|
||||
* @brief Argument structure for WIFI_EVENT_NAN_SVC_MATCH event
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t subscribe_id; /**< Subscribe Service Identifier */
|
||||
uint8_t publish_id; /**< Publish Service Identifier */
|
||||
uint8_t pub_if_mac[6]; /**< NAN Interface MAC of the Publisher */
|
||||
bool update_pub_id; /**< Indicates whether publisher's service ID needs to be updated */
|
||||
uint8_t datapath_reqd: 1; /**< NAN Datapath required for the service */
|
||||
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 ndpe_support: 1; /**< NDPE supported by peer */
|
||||
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_2; /**< Reserved */
|
||||
uint8_t ssi_version; /**< Indicates version of SSI in Publish instance, 0 if not available */
|
||||
uint16_t ssi_len; /**< Length of service specific info */
|
||||
uint8_t ssi[]; /**< Service specific info of Publisher */
|
||||
uint8_t subscribe_id; /**< Subscribe Service Identifier */
|
||||
uint8_t publish_id; /**< Publish Service Identifier */
|
||||
uint8_t pub_if_mac[6]; /**< NAN Interface MAC of the Publisher */
|
||||
bool update_pub_id; /**< Indicates whether publisher's service ID needs to be updated */
|
||||
uint8_t datapath_reqd: 1; /**< NAN Datapath required for the service */
|
||||
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 ndpe_support: 1; /**< NDPE supported by peer */
|
||||
uint8_t security_reqd: 1; /**< Security: 0 - Open, 1 - Required (NDP Security) */
|
||||
uint8_t pairing_setup: 1; /**< Pairing setup: 0 - disabled, 1 - enabled (needs security_reqd:1) */
|
||||
uint8_t npk_nik_caching: 1; /**< NPK/NIK caching: 0 - disabled, 1 - enabled (valid if pairing_setup:1)*/
|
||||
uint8_t already_paired: 1; /**< 0 - not paired, 1 - device already paired */
|
||||
uint16_t csid_bitmap; /**< Supported Cipher Suite bitmap, each bit of type WIFI_NAN_CSID_BIT_[] */
|
||||
uint16_t bootstrapping_methods; /**< Peer advertised bootstrapping methods (WIFI_NAN_BOOTSTRAP_* bitmap) */
|
||||
uint32_t reserved_2; /**< Reserved */
|
||||
uint8_t ssi_version; /**< Indicates version of SSI in Publish instance, 0 if not available */
|
||||
uint16_t ssi_len; /**< Length of service specific info */
|
||||
uint8_t ssi[]; /**< Service specific info of Publisher */
|
||||
} wifi_event_nan_svc_match_t;
|
||||
|
||||
/**
|
||||
@@ -1627,13 +1630,13 @@ typedef struct {
|
||||
* @brief Argument structure for WIFI_EVENT_NAN_BOOTSTRAP_INDICATION event
|
||||
*
|
||||
* Posted when a NAN Pairing Bootstrapping Request is received from a peer.
|
||||
* The application should respond using esp_wifi_nan_pairing_response().
|
||||
* The application should respond using esp_wifi_nan_bootstrap_response().
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t peer_svc_id; /**< Peer's service instance id */
|
||||
uint8_t own_svc_id; /**< Own service instance id */
|
||||
uint8_t peer_nmi[6]; /**< Peer's NAN Management Interface MAC */
|
||||
uint16_t selected_method; /**< Bootstrapping method selected by initiator (wifi_nan_bootstrap_method_t) */
|
||||
uint16_t selected_method; /**< Bootstrapping method selected by initiator (one WIFI_NAN_BOOTSTRAP_* bit) */
|
||||
uint8_t is_comeback; /**< 1 if this is a comeback retry with cookie */
|
||||
uint32_t cookie; /**< Comeback cookie from initiator (0 if none) */
|
||||
} wifi_event_nan_bootstrap_indication_t;
|
||||
@@ -1649,7 +1652,7 @@ typedef struct {
|
||||
uint8_t peer_svc_id; /**< Peer's service instance id */
|
||||
uint8_t own_svc_id; /**< Own service instance id */
|
||||
uint8_t peer_nmi[6]; /**< Peer's NAN Management Interface MAC */
|
||||
uint16_t matched_method; /**< Matched bootstrapping method (valid if accepted) */
|
||||
uint16_t matched_method; /**< Matched bootstrapping method, one WIFI_NAN_BOOTSTRAP_* bit (valid if accepted) */
|
||||
uint8_t reason_code; /**< Rejection reason (valid if rejected) */
|
||||
uint16_t comeback_after; /**< Comeback deferral time in TUs (valid if comeback) */
|
||||
uint32_t cookie; /**< Comeback cookie from responder (0 if none) */
|
||||
|
||||
@@ -218,7 +218,7 @@ typedef struct {
|
||||
uint8_t inst_id; /**< Own service instance id */
|
||||
uint8_t peer_inst_id; /**< Peer's service instance id */
|
||||
uint8_t peer_mac[6]; /**< Peer's NAN Management Interface MAC */
|
||||
uint16_t selected_method; /**< One selected method from wifi_nan_bootstrap_method_t */
|
||||
uint16_t selected_method; /**< One selected WIFI_NAN_BOOTSTRAP_* method bit */
|
||||
wifi_nan_pairing_status_t status; /**< Set to COMEBACK when resending with cookie */
|
||||
uint16_t comeback_after; /**< Comeback deferral time in TUs (only when status=COMEBACK) */
|
||||
uint32_t cookie; /**< Opaque cookie from responder (only when status=COMEBACK) */
|
||||
@@ -235,7 +235,7 @@ typedef struct {
|
||||
uint8_t peer_inst_id; /**< Peer's service instance id */
|
||||
uint8_t peer_mac[6]; /**< Peer's NAN Management Interface MAC */
|
||||
wifi_nan_pairing_status_t status; /**< Accepted, Rejected, or Comeback */
|
||||
uint16_t matched_method; /**< Matched bootstrapping method (valid if accepted) */
|
||||
uint16_t matched_method; /**< Matched bootstrapping method, one WIFI_NAN_BOOTSTRAP_* bit (valid if accepted) */
|
||||
uint8_t reason_code; /**< Rejection reason code (valid if rejected) */
|
||||
uint16_t comeback_after; /**< Comeback deferral time in TUs (only when status=COMEBACK) */
|
||||
uint32_t cookie; /**< Opaque cookie for comeback (only when status=COMEBACK) */
|
||||
@@ -261,7 +261,7 @@ esp_err_t esp_wifi_nan_bootstrap_request(wifi_nan_pairing_bootstrap_req_t *req);
|
||||
* @brief Respond to a NAN Pairing Bootstrapping request from a peer
|
||||
*
|
||||
* @attention This API should be called by the Publisher after receiving a
|
||||
* WIFI_EVENT_NAN_PAIRING_INDICATION event.
|
||||
* WIFI_EVENT_NAN_BOOTSTRAP_INDICATION event.
|
||||
*
|
||||
* @param resp Pairing bootstrapping response parameters.
|
||||
*
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_mac.h"
|
||||
#include "esp_timer.h"
|
||||
#include "os.h"
|
||||
#include "esp_nan.h"
|
||||
#include "utils/common.h"
|
||||
@@ -22,6 +23,44 @@
|
||||
#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE
|
||||
#include "esp_private/esp_nan_usd.h"
|
||||
#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */
|
||||
|
||||
bool esp_nan_ndp_info_present(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t esp_nan_ndp_get_info_len(void)
|
||||
{
|
||||
return 12;
|
||||
}
|
||||
|
||||
int esp_nan_construct_ndp_info(uint8_t *frm)
|
||||
{
|
||||
static const uint8_t ndp_info_attr[] = {
|
||||
0x01, 0x09, 0x00, 0x50, 0x6f, 0x9a, 0x02, 0x00, 0x02, 0x00, 0x05, 0x0d
|
||||
};
|
||||
|
||||
if (!frm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(frm, ndp_info_attr, sizeof(ndp_info_attr));
|
||||
return sizeof(ndp_info_attr);
|
||||
}
|
||||
|
||||
#if !CONFIG_ESP_WIFI_NAN_PAIRING
|
||||
uint32_t esp_nan_get_nira_len(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int esp_nan_construct_nira(uint8_t *frm)
|
||||
{
|
||||
(void)frm;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_SYNC_ENABLE) && defined(CONFIG_ESP_WIFI_PASN_SUPPORT)
|
||||
#include "esp_private/esp_supp_nan.h"
|
||||
#include "apps_private/wifi_apps_private.h"
|
||||
@@ -85,6 +124,118 @@ const uint8_t *nan_pairing_get_null_mac(void)
|
||||
{
|
||||
return null_mac;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||
/* ---- Paired-peer cache ---------------------------------------------------
|
||||
*
|
||||
* Tracks ND-PMK + cipher per peer NMI after PASN/Pairing completes. The
|
||||
* security layer (nan_security.c) consumes these on inbound SDF match and on
|
||||
* NDP request/response to source ND-PMK without an app-provided service
|
||||
* credential. Lifetime accounting is timestamp-based; auto-purge is left to
|
||||
* the consumer (current path: explicit remove or stop).
|
||||
*/
|
||||
|
||||
static struct nan_paired_peer *nan_app_find_paired_slot_locked(const uint8_t *peer_nmi)
|
||||
{
|
||||
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
||||
struct nan_paired_peer *p = &s_nan_ctx.paired_peers[i];
|
||||
if (p->valid && memcmp(p->peer_nmi, peer_nmi, MACADDR_LEN) == 0) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nan_paired_peer *nan_app_alloc_paired_slot_locked(const uint8_t *peer_nmi)
|
||||
{
|
||||
struct nan_paired_peer *p = nan_app_find_paired_slot_locked(peer_nmi);
|
||||
if (p) {
|
||||
return p;
|
||||
}
|
||||
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
||||
if (!s_nan_ctx.paired_peers[i].valid) {
|
||||
return &s_nan_ctx.paired_peers[i];
|
||||
}
|
||||
}
|
||||
/* Evict oldest entry by established_us. */
|
||||
int oldest = 0;
|
||||
int64_t oldest_ts = s_nan_ctx.paired_peers[0].established_us;
|
||||
for (int i = 1; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
||||
if (s_nan_ctx.paired_peers[i].established_us < oldest_ts) {
|
||||
oldest_ts = s_nan_ctx.paired_peers[i].established_us;
|
||||
oldest = i;
|
||||
}
|
||||
}
|
||||
return &s_nan_ctx.paired_peers[oldest];
|
||||
}
|
||||
|
||||
esp_err_t nan_app_register_paired_peer(const uint8_t *peer_nmi,
|
||||
uint8_t role,
|
||||
uint8_t ndp_csid,
|
||||
const uint8_t *nd_pmk,
|
||||
size_t nd_pmk_len,
|
||||
uint32_t lifetime_sec)
|
||||
{
|
||||
if (!peer_nmi || !nd_pmk || nd_pmk_len != ESP_WIFI_NAN_NDP_PMK_LEN) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (ndp_csid != WIFI_NAN_CSID_NCS_SK_128 && ndp_csid != WIFI_NAN_CSID_NCS_SK_256) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
NAN_DATA_LOCK();
|
||||
struct nan_paired_peer *p = nan_app_alloc_paired_slot_locked(peer_nmi);
|
||||
forced_memzero(p->nd_pmk, sizeof(p->nd_pmk));
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->valid = true;
|
||||
MACADDR_COPY(p->peer_nmi, peer_nmi);
|
||||
p->role = role;
|
||||
p->ndp_csid = ndp_csid;
|
||||
memcpy(p->nd_pmk, nd_pmk, nd_pmk_len);
|
||||
p->lifetime_sec = lifetime_sec;
|
||||
p->established_us = esp_timer_get_time();
|
||||
NAN_DATA_UNLOCK();
|
||||
|
||||
ESP_LOGI(TAG, "Paired peer cached: " MACSTR " role=%u csid=%u lifetime=%us",
|
||||
MAC2STR(peer_nmi), role, ndp_csid, lifetime_sec);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
const struct nan_paired_peer *nan_app_find_paired_peer(const uint8_t *peer_nmi)
|
||||
{
|
||||
if (!peer_nmi) {
|
||||
return NULL;
|
||||
}
|
||||
/* Caller holds NAN_DATA_LOCK (see nan_i.h). */
|
||||
return nan_app_find_paired_slot_locked(peer_nmi);
|
||||
}
|
||||
|
||||
void nan_app_remove_paired_peer(const uint8_t *peer_nmi)
|
||||
{
|
||||
if (!peer_nmi) {
|
||||
return;
|
||||
}
|
||||
NAN_DATA_LOCK();
|
||||
struct nan_paired_peer *p = nan_app_find_paired_slot_locked(peer_nmi);
|
||||
if (p) {
|
||||
forced_memzero(p->nd_pmk, sizeof(p->nd_pmk));
|
||||
memset(p, 0, sizeof(*p));
|
||||
}
|
||||
NAN_DATA_UNLOCK();
|
||||
}
|
||||
|
||||
void nan_app_clear_paired_peers(void)
|
||||
{
|
||||
NAN_DATA_LOCK();
|
||||
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
||||
forced_memzero(s_nan_ctx.paired_peers[i].nd_pmk,
|
||||
sizeof(s_nan_ctx.paired_peers[i].nd_pmk));
|
||||
}
|
||||
memset(s_nan_ctx.paired_peers, 0, sizeof(s_nan_ctx.paired_peers));
|
||||
NAN_DATA_UNLOCK();
|
||||
}
|
||||
#endif /* CONFIG_ESP_WIFI_NAN_SECURITY */
|
||||
|
||||
#endif /* CONFIG_ESP_WIFI_NAN_PAIRING */
|
||||
|
||||
void esp_wifi_nan_get_ipv6_linklocal_from_mac(ip6_addr_t *ip6, uint8_t *mac_addr)
|
||||
@@ -575,7 +726,8 @@ void nan_app_post_event(int32_t event_id, void* event_data, size_t event_data_si
|
||||
g_wifi_osi_funcs._event_post(WIFI_EVENT, event_id, event_data, event_data_size, OSI_FUNCS_TIME_BLOCKING);
|
||||
}
|
||||
|
||||
void nan_app_service_match_cb(uint8_t sub_id, struct nan_cb_peer_info *peer_info)
|
||||
void nan_app_service_match_cb(uint8_t sub_id, struct nan_cb_peer_info *peer_info,
|
||||
struct nan_cb_npba_t *npba)
|
||||
{
|
||||
if (!peer_info) {
|
||||
return;
|
||||
@@ -656,6 +808,19 @@ void nan_app_service_match_cb(uint8_t sub_id, struct nan_cb_peer_info *peer_info
|
||||
evt->datapath_reqd = (capab & NAN_SDEA_CTRL_DATAPATH_REQD) ? 1 : 0;
|
||||
evt->ndpe_support = (device_caps & NAN_CAPS_NDPE_ATTR) ? 1 : 0;
|
||||
evt->security_reqd = (capab & NAN_SDEA_CTRL_SECURITY_REQD) ? 1 : 0;
|
||||
|
||||
if (peer_info->peer_security_params) {
|
||||
const wifi_nan_peer_sdf_security_t *peer_sec = peer_info->peer_security_params;
|
||||
|
||||
evt->csid_bitmap = peer_sec->csid_bitmap;
|
||||
evt->pairing_setup = peer_sec->pairing_setup;
|
||||
evt->npk_nik_caching = peer_sec->npk_nik_caching;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_WIFI_NAN_PAIRING
|
||||
evt->bootstrapping_methods = nan_app_parse_npba_from_publish(npba);
|
||||
#endif
|
||||
|
||||
evt->ssi_version = ssi_ver;
|
||||
if (ssi && ssi_len) {
|
||||
if (ssi_ver) {
|
||||
@@ -712,7 +877,9 @@ void nan_app_replied_cb(uint8_t pub_id, struct nan_cb_peer_info *peer_info)
|
||||
os_free(evt);
|
||||
}
|
||||
|
||||
void nan_app_receive_cb(uint8_t svc_id, struct nan_cb_peer_info *peer_info)
|
||||
void nan_app_receive_cb(uint8_t svc_id, struct nan_cb_peer_info *peer_info,
|
||||
uint8_t *shared_key_attr, uint16_t shared_key_attr_buf_len,
|
||||
struct nan_cb_npba_t *npba)
|
||||
{
|
||||
if (!peer_info) {
|
||||
return;
|
||||
@@ -722,7 +889,6 @@ void nan_app_receive_cb(uint8_t svc_id, struct nan_cb_peer_info *peer_info)
|
||||
uint8_t *ssi = peer_info->ssi;
|
||||
uint16_t ssi_len = peer_info->ssi_len;
|
||||
uint32_t device_caps = peer_info->device_caps;
|
||||
uint8_t *shared_key_attr = peer_info->shared_key_attr;
|
||||
|
||||
NAN_DATA_LOCK();
|
||||
if (!nan_find_peer_svc(svc_id, peer_svc_id, peer_mac)) {
|
||||
@@ -732,11 +898,18 @@ void nan_app_receive_cb(uint8_t svc_id, struct nan_cb_peer_info *peer_info)
|
||||
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_SECURITY) && defined(CONFIG_ESP_WIFI_NAN_PAIRING) && defined(CONFIG_ESP_WIFI_PASN_SUPPORT)
|
||||
if (shared_key_attr) {
|
||||
nan_app_receive_pairing_followup(svc_id, peer_svc_id, peer_mac, shared_key_attr);
|
||||
nan_app_receive_pairing_followup(svc_id, peer_svc_id, peer_mac, shared_key_attr,
|
||||
shared_key_attr_buf_len);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_PAIRING)
|
||||
if (npba) {
|
||||
nan_app_parse_npba_from_receive(svc_id, peer_svc_id, peer_mac, npba);
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t evt_data_len = sizeof(wifi_event_nan_receive_t) + ssi_len;
|
||||
wifi_event_nan_receive_t *evt = (wifi_event_nan_receive_t *)os_zalloc(evt_data_len);
|
||||
if (!evt) {
|
||||
@@ -1260,8 +1433,6 @@ void esp_nan_action_start(esp_netif_t *nan_netif)
|
||||
.action_txdone = nan_action_txdone_cb,
|
||||
.ndp_response_indication = nan_app_ndp_response_indication_cb,
|
||||
#ifdef CONFIG_ESP_WIFI_NAN_PAIRING
|
||||
.pairing_indication = nan_app_bootstrap_indication_cb,
|
||||
.pairing_confirm = nan_app_bootstrap_completed_cb,
|
||||
.get_nira_len = esp_nan_get_nira_len,
|
||||
.construct_nira = esp_nan_construct_nira,
|
||||
.receive_pasn = handle_auth_pasn,
|
||||
@@ -1288,6 +1459,13 @@ void esp_nan_action_stop(void)
|
||||
s_nan_ctx.state |= NAN_STOPPED_BIT;
|
||||
NAN_DATA_UNLOCK();
|
||||
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_PAIRING) && defined(CONFIG_ESP_WIFI_NAN_SECURITY)
|
||||
/* ND-PMKs are bound to the local NMI used at PASN time; a later
|
||||
* sync_start may use a different (randomized) NMI, which would
|
||||
* invalidate every cached derivation. */
|
||||
nan_app_clear_paired_peers();
|
||||
#endif
|
||||
|
||||
esp_nan_internal_register_callbacks(NULL);
|
||||
os_event_group_set_bits(nan_event_group, NAN_STOPPED_BIT);
|
||||
}
|
||||
@@ -1447,9 +1625,14 @@ uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_WIFI_NAN_PAIRING
|
||||
if (!nan_pairing_validate_publish_bootstrapping(publish_cfg->pairing.bootstrapping_methods)) {
|
||||
ESP_LOGE(TAG, "Invalid bootstrapping methods for Publisher. Only OPPORTUNISTIC and PIN_CODE_DISPLAY allowed");
|
||||
return 0;
|
||||
{
|
||||
uint16_t bootstrap_methods = publish_cfg->pairing ?
|
||||
publish_cfg->pairing->bootstrapping_methods : 0;
|
||||
|
||||
if (!nan_pairing_validate_publish_bootstrapping(bootstrap_methods)) {
|
||||
ESP_LOGE(TAG, "Invalid bootstrapping methods for Publisher. Only OPPORTUNISTIC and PIN_CODE_DISPLAY allowed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_ESP_WIFI_NAN_PAIRING */
|
||||
|
||||
@@ -1523,6 +1706,15 @@ uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg)
|
||||
goto fail;
|
||||
}
|
||||
memcpy(cfg, publish_cfg, sizeof(*cfg));
|
||||
cfg->pairing = NULL;
|
||||
if (publish_cfg->pairing) {
|
||||
cfg->pairing = os_malloc(sizeof(*cfg->pairing));
|
||||
if (!cfg->pairing) {
|
||||
ESP_LOGE(TAG, "Failed to copy pairing config");
|
||||
goto fail;
|
||||
}
|
||||
memcpy(cfg->pairing, publish_cfg->pairing, sizeof(*cfg->pairing));
|
||||
}
|
||||
|
||||
/* Pre-claim host slot BEFORE calling into the blob. Reason: the blob
|
||||
* invokes our derive_security_params callback on the WiFi task and looks
|
||||
@@ -1549,12 +1741,20 @@ uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg)
|
||||
|
||||
ESP_LOGI(TAG, "Started Publishing %s [Service ID - %u]", publish_cfg->service_name, pub_id);
|
||||
nan_finalize_own_svc(publish_cfg->service_name, pub_id, publish_cfg->ndp_resp_needed);
|
||||
if (cfg->pairing) {
|
||||
os_free(cfg->pairing);
|
||||
}
|
||||
os_free(cfg);
|
||||
NAN_DATA_UNLOCK();
|
||||
|
||||
return pub_id;
|
||||
fail:
|
||||
os_free(cfg);
|
||||
if (cfg) {
|
||||
if (cfg->pairing) {
|
||||
os_free(cfg->pairing);
|
||||
}
|
||||
os_free(cfg);
|
||||
}
|
||||
NAN_DATA_UNLOCK();
|
||||
return 0;
|
||||
#endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */
|
||||
@@ -1593,9 +1793,14 @@ uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_WIFI_NAN_PAIRING
|
||||
if (!nan_pairing_validate_subscribe_bootstrapping(subscribe_cfg->pairing.bootstrapping_methods)) {
|
||||
ESP_LOGE(TAG, "Invalid bootstrapping methods for Subscriber. Only OPPORTUNISTIC and PIN_CODE_KEYPAD allowed");
|
||||
return 0;
|
||||
{
|
||||
uint16_t bootstrap_methods = subscribe_cfg->pairing ?
|
||||
subscribe_cfg->pairing->bootstrapping_methods : 0;
|
||||
|
||||
if (!nan_pairing_validate_subscribe_bootstrapping(bootstrap_methods)) {
|
||||
ESP_LOGE(TAG, "Invalid bootstrapping methods for Subscriber. Only OPPORTUNISTIC and PIN_CODE_KEYPAD allowed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_ESP_WIFI_NAN_PAIRING */
|
||||
|
||||
@@ -1665,7 +1870,7 @@ uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (esp_nan_internal_subscribe_service(subscribe_cfg, (uint8_t*) &sub_id, false) != ESP_OK) {
|
||||
if (esp_nan_internal_subscribe_service(subscribe_cfg, (uint8_t *) &sub_id, false) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to subscribe to service '%s'", subscribe_cfg->service_name);
|
||||
nan_abort_own_svc(subscribe_cfg->service_name);
|
||||
goto fail;
|
||||
@@ -1899,7 +2104,12 @@ uint8_t esp_wifi_nan_datapath_req(wifi_nan_datapath_req_t *req)
|
||||
|
||||
ESP_LOGD(TAG, "Requested NDP with "MACSTR" [NDP ID - %d]", MAC2STR(req->peer_mac), ndp_id);
|
||||
|
||||
EventBits_t bits = os_event_group_wait_bits(nan_event_group, NDP_ACCEPTED | NDP_REJECTED, pdFALSE, pdFALSE, pdMS_TO_TICKS(NAN_ACTION_TIMEOUT));
|
||||
/* At worst, Secured NDP (M1..M4) needs ~2.1s; 4*DW races the confirm.
|
||||
* Pick 6 (~3.1s). Harmless for open NDP - success unblocks instantly;
|
||||
* only failure path waits longer. */
|
||||
EventBits_t bits = os_event_group_wait_bits(nan_event_group, NDP_ACCEPTED | NDP_REJECTED,
|
||||
pdFALSE, pdFALSE,
|
||||
pdMS_TO_TICKS(6 * NAN_DW_INTVL_MS));
|
||||
if (bits & NDP_ACCEPTED) {
|
||||
return ndp_id;
|
||||
} else if (bits & NDP_REJECTED) {
|
||||
|
||||
@@ -159,6 +159,25 @@ enum nan_handshake_state {
|
||||
/* NIK length for cipher version 0 (Wi-Fi Aware spec v4.0). */
|
||||
#define NAN_APP_PEER_NIK_LEN 16
|
||||
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_SECURITY) && defined(CONFIG_ESP_WIFI_NAN_PAIRING)
|
||||
/*
|
||||
* Per-peer pairing record: holds the ND-PMK derived from NM-KDK during the
|
||||
* PASN/Pairing handshake, together with the cipher that paired NDPs must use.
|
||||
* Wi-Fi Aware v4.0 §7.6.4.2 — ND-PMK is keyed by (Initiator NMI, Responder NMI)
|
||||
* and shared across all secured NDPs between the same paired peers, so the
|
||||
* cache is keyed by peer NMI alone (independent of svc_id).
|
||||
*/
|
||||
struct nan_paired_peer {
|
||||
bool valid;
|
||||
uint8_t peer_nmi[MACADDR_LEN];
|
||||
uint8_t role; /* enum nan_role value */
|
||||
uint8_t ndp_csid; /* WIFI_NAN_CSID_NCS_SK_128 / _256 */
|
||||
uint8_t nd_pmk[ESP_WIFI_NAN_NDP_PMK_LEN];
|
||||
uint32_t lifetime_sec;
|
||||
int64_t established_us;
|
||||
};
|
||||
#endif /* CONFIG_ESP_WIFI_NAN_SECURITY && CONFIG_ESP_WIFI_NAN_PAIRING */
|
||||
|
||||
/* Per-peer service info */
|
||||
struct peer_svc_info {
|
||||
SLIST_ENTRY(peer_svc_info) next;
|
||||
@@ -275,6 +294,12 @@ typedef struct {
|
||||
#ifdef CONFIG_ESP_WIFI_PASN_SUPPORT
|
||||
struct nan_pasn_data *nan_pasn_data;
|
||||
#endif
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_SECURITY) && defined(CONFIG_ESP_WIFI_NAN_PAIRING)
|
||||
/* Pairing records produced by PASN/Pairing key-install. Sized to the
|
||||
* datapath peer cap since paired peers are the population that can
|
||||
* actually run an NDP; LRU-evicted on overflow. */
|
||||
struct nan_paired_peer paired_peers[ESP_WIFI_NAN_DATAPATH_MAX_PEERS];
|
||||
#endif
|
||||
} nan_ctx_t;
|
||||
|
||||
extern nan_ctx_t s_nan_ctx;
|
||||
@@ -304,11 +329,15 @@ const uint8_t *nan_pairing_get_null_mac(void);
|
||||
bool nan_pairing_validate_publish_bootstrapping(uint16_t bootstrapping_methods);
|
||||
bool nan_pairing_validate_subscribe_bootstrapping(uint16_t bootstrapping_methods);
|
||||
|
||||
void nan_app_bootstrap_indication_cb(uint8_t peer_svc_id, uint8_t pub_id,
|
||||
uint8_t peer_nmi[6], uint16_t selected_method);
|
||||
void nan_app_bootstrap_completed_cb(uint8_t status, uint8_t peer_svc_id, uint8_t sub_id,
|
||||
uint8_t peer_nmi[6], uint16_t matched_method,
|
||||
uint8_t reason_code);
|
||||
uint16_t nan_app_parse_npba_from_publish(const struct nan_cb_npba_t *npba);
|
||||
|
||||
void nan_app_bootstrap_indication(uint8_t peer_svc_id, uint8_t pub_id,
|
||||
uint8_t peer_nmi[6], uint16_t selected_method);
|
||||
void nan_app_bootstrap_completed(uint8_t status, uint8_t peer_svc_id, uint8_t sub_id,
|
||||
uint8_t peer_nmi[6], uint16_t matched_method,
|
||||
uint8_t reason_code);
|
||||
bool nan_app_parse_npba_from_receive(uint8_t own_svc_id, uint8_t peer_svc_id,
|
||||
uint8_t peer_nmi[6], const struct nan_cb_npba_t *npba);
|
||||
#endif /* CONFIG_ESP_WIFI_NAN_PAIRING */
|
||||
|
||||
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||
@@ -416,9 +445,31 @@ bool nan_security_service_match(const struct own_svc_info *own_svc,
|
||||
#if CONFIG_ESP_WIFI_NAN_PAIRING
|
||||
void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id,
|
||||
const uint8_t *peer_mac,
|
||||
const uint8_t *shared_key_attr);
|
||||
const uint8_t *shared_key_attr,
|
||||
size_t shared_key_attr_buf_len);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESP_WIFI_NAN_SECURITY
|
||||
/*
|
||||
* Paired-peer cache API. Called from nan_pairing.c after the PASN install
|
||||
* callback fires; consumed by the NDP security layer to source ND-PMK + cipher
|
||||
* for paired peers (no per-service credential involved).
|
||||
*
|
||||
* Caller of nan_app_find_paired_peer() must hold NAN_DATA_LOCK while using the
|
||||
* returned pointer -- it points into s_nan_ctx storage. Same convention as
|
||||
* nan_find_own_svc() / nan_find_peer_svc().
|
||||
*/
|
||||
esp_err_t nan_app_register_paired_peer(const uint8_t *peer_nmi,
|
||||
uint8_t role,
|
||||
uint8_t ndp_csid,
|
||||
const uint8_t *nd_pmk,
|
||||
size_t nd_pmk_len,
|
||||
uint32_t lifetime_sec);
|
||||
const struct nan_paired_peer *nan_app_find_paired_peer(const uint8_t *peer_nmi);
|
||||
void nan_app_remove_paired_peer(const uint8_t *peer_nmi);
|
||||
void nan_app_clear_paired_peers(void);
|
||||
#endif /* CONFIG_ESP_WIFI_NAN_SECURITY */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_PAIRING)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_private/wifi.h"
|
||||
@@ -28,6 +29,11 @@
|
||||
|
||||
static const char *TAG = "nan_pairing";
|
||||
|
||||
/* Default NIK / pairing-record lifetime (also reused for paired-peer cache
|
||||
* entries) — matches the NIK Key Lifetime KDE we transmit in the post-pairing
|
||||
* Shared Key Descriptor (Wi-Fi Aware v4.0 §7.6.4.2). */
|
||||
#define NAN_PAIRING_DEFAULT_NIK_LIFETIME_SEC 86400U
|
||||
|
||||
#if defined(CONFIG_ESP_WIFI_PASN_SUPPORT)
|
||||
struct nan_pasn_data *esp_nan_app_get_pasn_data(void)
|
||||
{
|
||||
@@ -39,7 +45,11 @@ void esp_nan_app_set_pasn_data(struct nan_pasn_data *pd)
|
||||
s_nan_ctx.nan_pasn_data = pd;
|
||||
}
|
||||
|
||||
static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi)
|
||||
static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi,
|
||||
uint8_t role,
|
||||
uint8_t ndp_csid,
|
||||
const uint8_t *nd_pmk,
|
||||
size_t nd_pmk_len)
|
||||
{
|
||||
wifi_event_nan_pairing_complete_t evt = {0};
|
||||
|
||||
@@ -47,6 +57,29 @@ static void nan_pairing_key_installed_cb(const uint8_t *peer_nmi)
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_SECURITY)
|
||||
/* Cache ND-PMK for future paired NDPs (Wi-Fi Aware v4.0 §7.6.4.2). The
|
||||
* NDP cipher (CSID) is determined by the PASN cipher and resolved on the
|
||||
* supplicant side before this callback fires; if either is missing, the
|
||||
* pairing event still fires but the security layer will fall back to its
|
||||
* service-credential path for any subsequent NDP. */
|
||||
if (ndp_csid && nd_pmk && nd_pmk_len == ESP_WIFI_NAN_NDP_PMK_LEN) {
|
||||
(void)nan_app_register_paired_peer(peer_nmi, role, ndp_csid,
|
||||
nd_pmk, nd_pmk_len,
|
||||
NAN_PAIRING_DEFAULT_NIK_LIFETIME_SEC);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Pairing complete for " MACSTR
|
||||
": ND-PMK unavailable (csid=%u nd_pmk_len=%u); "
|
||||
"paired-peer cache not updated",
|
||||
MAC2STR(peer_nmi), ndp_csid, (unsigned)nd_pmk_len);
|
||||
}
|
||||
#else
|
||||
(void)role;
|
||||
(void)ndp_csid;
|
||||
(void)nd_pmk;
|
||||
(void)nd_pmk_len;
|
||||
#endif
|
||||
|
||||
evt.status = WIFI_NAN_PAIRING_STATUS_ACCEPTED;
|
||||
evt.reason_code = 0;
|
||||
MACADDR_COPY(evt.peer_nmi, peer_nmi);
|
||||
@@ -72,8 +105,16 @@ bool nan_pairing_validate_subscribe_bootstrapping(uint16_t bootstrapping_methods
|
||||
return (bootstrapping_methods & ~valid_methods) == 0;
|
||||
}
|
||||
|
||||
void nan_app_bootstrap_indication_cb(uint8_t peer_svc_id, uint8_t pub_id,
|
||||
uint8_t peer_nmi[6], uint16_t selected_method)
|
||||
uint16_t nan_app_parse_npba_from_publish(const struct nan_cb_npba_t *npba)
|
||||
{
|
||||
if (!npba || npba->type != WIFI_NAN_NPBA_TYPE_ADVERTISE) {
|
||||
return 0;
|
||||
}
|
||||
return npba->methods;
|
||||
}
|
||||
|
||||
void nan_app_bootstrap_indication(uint8_t peer_svc_id, uint8_t pub_id,
|
||||
uint8_t peer_nmi[6], uint16_t selected_method)
|
||||
{
|
||||
ESP_LOGI(TAG, "Pairing Bootstrapping Request from "MACSTR" [pub_id=%d, method=0x%x]",
|
||||
MAC2STR(peer_nmi), pub_id, selected_method);
|
||||
@@ -87,9 +128,9 @@ void nan_app_bootstrap_indication_cb(uint8_t peer_svc_id, uint8_t pub_id,
|
||||
nan_app_post_event(WIFI_EVENT_NAN_BOOTSTRAP_INDICATION, &evt, sizeof(evt));
|
||||
}
|
||||
|
||||
void nan_app_bootstrap_completed_cb(uint8_t status, uint8_t peer_svc_id, uint8_t sub_id,
|
||||
uint8_t peer_nmi[6], uint16_t matched_method,
|
||||
uint8_t reason_code)
|
||||
void nan_app_bootstrap_completed(uint8_t status, uint8_t peer_svc_id, uint8_t sub_id,
|
||||
uint8_t peer_nmi[6], uint16_t matched_method,
|
||||
uint8_t reason_code)
|
||||
{
|
||||
ESP_LOGI(TAG, "Pairing Bootstrapping Response from "MACSTR" [sub_id=%d, status=%d, method=0x%x]",
|
||||
MAC2STR(peer_nmi), sub_id, status, matched_method);
|
||||
@@ -105,6 +146,26 @@ void nan_app_bootstrap_completed_cb(uint8_t status, uint8_t peer_svc_id, uint8_t
|
||||
nan_app_post_event(WIFI_EVENT_NAN_BOOTSTRAP_COMPLETED, &evt, sizeof(evt));
|
||||
}
|
||||
|
||||
bool nan_app_parse_npba_from_receive(uint8_t own_svc_id, uint8_t peer_svc_id,
|
||||
uint8_t peer_nmi[6], const struct nan_cb_npba_t *npba)
|
||||
{
|
||||
if (!npba || !peer_nmi) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (npba->type) {
|
||||
case WIFI_NAN_NPBA_TYPE_REQUEST:
|
||||
nan_app_bootstrap_indication(peer_svc_id, own_svc_id, peer_nmi, npba->methods);
|
||||
return true;
|
||||
case WIFI_NAN_NPBA_TYPE_RESPONSE:
|
||||
nan_app_bootstrap_completed(npba->status, peer_svc_id, own_svc_id, peer_nmi,
|
||||
npba->methods, 0);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t nan_send_bootstrap_followup(uint8_t inst_id, uint8_t peer_inst_id,
|
||||
uint8_t *peer_mac,
|
||||
wifi_nan_pairing_npba_params_t *pairing_npba)
|
||||
@@ -339,55 +400,6 @@ int esp_nan_construct_nira(uint8_t *frm)
|
||||
return (int)(p - frm);
|
||||
}
|
||||
|
||||
#define NAN_MME_ELEMENT_ID 0x4C
|
||||
/* MME: ElementID(1) + Length(1) + KeyID(2) + IPN(6) + MIC(8) = 18 */
|
||||
#define NAN_MME_LEN 18
|
||||
|
||||
uint32_t esp_nan_get_mme_len(void)
|
||||
{
|
||||
return NAN_MME_LEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct dummy Management MIC Element (MME)
|
||||
*
|
||||
* Format: Element ID(1) + Length(1) + Key ID(2) + IPN/BIPN(6) + MIC(8)
|
||||
* Key ID is set to 4, MIC is 8 bytes random (dummy).
|
||||
*/
|
||||
int esp_nan_construct_mme(uint8_t *frm, uint32_t ipn)
|
||||
{
|
||||
if (!frm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *p = frm;
|
||||
|
||||
/* Element ID */
|
||||
*p++ = NAN_MME_ELEMENT_ID;
|
||||
|
||||
/* Length: KeyID(2) + IPN(6) + MIC(8) = 16 */
|
||||
*p++ = 16;
|
||||
|
||||
/* Key ID: 4 (LE16) */
|
||||
*p++ = 4;
|
||||
*p++ = 0;
|
||||
|
||||
/* IPN/BIPN: 6 bytes from ipn parameter (LE, zero-padded upper 2 bytes) */
|
||||
*p++ = (uint8_t)(ipn & 0xFF);
|
||||
*p++ = (uint8_t)((ipn >> 8) & 0xFF);
|
||||
*p++ = (uint8_t)((ipn >> 16) & 0xFF);
|
||||
*p++ = (uint8_t)((ipn >> 24) & 0xFF);
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
|
||||
/* MIC: 8 bytes random (dummy) */
|
||||
os_get_random(p, 8);
|
||||
p += 8;
|
||||
|
||||
ESP_LOGI(TAG, "Constructed MME (dummy): len=%d, ipn=0x%lx", (int)(p - frm), (unsigned long)ipn);
|
||||
return (int)(p - frm);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_PAIRING) && defined(CONFIG_ESP_WIFI_PASN_SUPPORT) && defined(CONFIG_ESP_WIFI_NAN_SECURITY)
|
||||
|
||||
#include "crypto/sha256.h"
|
||||
@@ -400,7 +412,7 @@ int esp_nan_construct_mme(uint8_t *frm, uint32_t ipn)
|
||||
#define NAN_PASN_KDE_OUI_TYPE_NIK 36
|
||||
#define NAN_PASN_KDE_OUI_TYPE_LIFETIME 37
|
||||
#define NAN_PASN_KEY_LIFETIME_NIK_BIT BIT(3)
|
||||
#define NAN_PAIRING_DEFAULT_NIK_LIFETIME_SEC 86400U
|
||||
/* NAN_PAIRING_DEFAULT_NIK_LIFETIME_SEC is defined at file scope above. */
|
||||
#define NAN_ATTR_ID_SHARED_KEY_DESC 0x24
|
||||
#define GSP_SUBATTR_TRANSPORT_PORT 0x00
|
||||
#define GSP_SUBATTR_INSTANCE_NAME 0x03
|
||||
@@ -770,10 +782,11 @@ static void nan_app_send_pairing_followup_eloop(void *eloop_data, void *user_dat
|
||||
|
||||
void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id,
|
||||
const uint8_t *peer_mac,
|
||||
const uint8_t *shared_key_attr)
|
||||
const uint8_t *shared_key_attr,
|
||||
size_t shared_key_attr_buf_len)
|
||||
{
|
||||
uint16_t attr_len;
|
||||
uint16_t total_len;
|
||||
size_t attr_body_len;
|
||||
size_t total_len;
|
||||
uint8_t nik[NAN_APP_PEER_NIK_LEN];
|
||||
uint8_t cipher_ver = 0;
|
||||
uint32_t lifetime_sec = 0;
|
||||
@@ -783,13 +796,23 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id,
|
||||
if (!shared_key_attr || !peer_mac) {
|
||||
return;
|
||||
}
|
||||
if (shared_key_attr_buf_len < NAN_PAIRING_FUP_MIN_ATTR_LEN) {
|
||||
return;
|
||||
}
|
||||
if (shared_key_attr[0] != NAN_ATTR_ID_SHARED_KEY_DESC) {
|
||||
return;
|
||||
}
|
||||
|
||||
attr_len = shared_key_attr[1] | (shared_key_attr[2] << 8);
|
||||
total_len = attr_len + 3;
|
||||
if (total_len < NAN_PAIRING_FUP_MIN_ATTR_LEN) {
|
||||
const uint16_t *attr_body_len_field = (const uint16_t *)&shared_key_attr[1];
|
||||
|
||||
attr_body_len = *attr_body_len_field;
|
||||
if (attr_body_len > shared_key_attr_buf_len - 3) {
|
||||
ESP_LOGW(TAG, "Pairing follow-up: truncated Shared Key Descriptor (body=%zu, avail=%zu)",
|
||||
attr_body_len, shared_key_attr_buf_len);
|
||||
return;
|
||||
}
|
||||
total_len = attr_body_len + 3;
|
||||
if (total_len > shared_key_attr_buf_len) {
|
||||
return;
|
||||
}
|
||||
if (nan_pasn_followup_decrypt_keys(shared_key_attr, total_len,
|
||||
@@ -809,10 +832,12 @@ void nan_app_receive_pairing_followup(uint8_t svc_id, uint8_t peer_svc_id,
|
||||
p_peer_svc->has_nik = true;
|
||||
ESP_LOGI(TAG, "Stored peer NIK from " MACSTR " (cipher_ver=%u, lifetime=%u s)",
|
||||
MAC2STR(peer_mac), cipher_ver, lifetime_sec);
|
||||
ESP_LOG_BUFFER_HEXDUMP("NIK", nik, NAN_APP_PEER_NIK_LEN, ESP_LOG_INFO);
|
||||
}
|
||||
NAN_DATA_UNLOCK();
|
||||
|
||||
if (total_len > SIZE_MAX - sizeof(*ctx)) {
|
||||
return;
|
||||
}
|
||||
alloc_len = sizeof(*ctx) + total_len;
|
||||
ctx = os_zalloc(alloc_len);
|
||||
if (!ctx) {
|
||||
|
||||
@@ -426,6 +426,37 @@ static struct ndl_info *nan_ndl_claim_for_pub_peer(uint8_t pub_id, const uint8_t
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill NDL security context from paired-peer cache (produced at PASN pairing
|
||||
* completion). Caller must hold NAN_DATA_LOCK.
|
||||
*/
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_PAIRING)
|
||||
static bool nan_security_fill_from_paired_cache(struct ndl_info *ndl, const uint8_t *peer_nmi)
|
||||
{
|
||||
const struct nan_paired_peer *paired;
|
||||
|
||||
if (!ndl || !peer_nmi) {
|
||||
return false;
|
||||
}
|
||||
|
||||
paired = nan_app_find_paired_peer(peer_nmi);
|
||||
if (!paired || !paired->valid) {
|
||||
return false;
|
||||
}
|
||||
if (paired->ndp_csid == 0 || paired->ndp_csid > 15) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ndl->security_ctx.type = WIFI_NAN_SECURITY_ENCRYPTED;
|
||||
ndl->security_ctx.csid_bitmap = (uint16_t)(1u << paired->ndp_csid);
|
||||
memcpy(ndl->security_ctx.nd_pmk, paired->nd_pmk, ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
|
||||
ESP_LOGD(TAG, "Loaded ND-PMK from paired-peer cache for peer "MACSTR" (csid=%u)",
|
||||
MAC2STR(peer_nmi), paired->ndp_csid);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Build RSNA Key Descriptor payload (95-byte EAPOL-Key layout, see
|
||||
* IEEE 802.11-2020 §12.7.2). NAN carries this body inside the NAN
|
||||
@@ -896,11 +927,23 @@ esp_err_t nan_security_populate_initiator_ndl(struct ndl_info *ndl,
|
||||
const struct peer_svc_info *peer_svc,
|
||||
const uint8_t *peer_nmi)
|
||||
{
|
||||
const wifi_nan_credential_t *cred = NULL;
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_PAIRING)
|
||||
const struct nan_paired_peer *paired = NULL;
|
||||
#endif
|
||||
|
||||
if (!ndl || !own_svc || !peer_nmi) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
const wifi_nan_discovery_security_params_t *cfg = &own_svc->user_cfg;
|
||||
if (cfg->num_credentials == 0) {
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_PAIRING)
|
||||
paired = nan_app_find_paired_peer(peer_nmi);
|
||||
#endif
|
||||
if (cfg->num_credentials == 0
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_PAIRING)
|
||||
&& (!paired || !paired->valid)
|
||||
#endif
|
||||
) {
|
||||
return ESP_OK; /* subscriber didn't request encrypted datapath */
|
||||
}
|
||||
|
||||
@@ -913,12 +956,14 @@ esp_err_t nan_security_populate_initiator_ndl(struct ndl_info *ndl,
|
||||
if (cred_idx >= cfg->num_credentials) {
|
||||
cred_idx = 0;
|
||||
}
|
||||
const wifi_nan_credential_t *cred = &cfg->creds[cred_idx];
|
||||
ESP_LOGD(TAG, "NDP req security: svc='%s' using cred[%u] for peer "MACSTR
|
||||
" (matched_idx=%d, num_creds=%u)",
|
||||
own_svc->svc_name, cred_idx, MAC2STR(peer_nmi),
|
||||
(matched_idx == NAN_NO_MATCHED_CRED) ? -1 : (int)matched_idx,
|
||||
cfg->num_credentials);
|
||||
if (cfg->num_credentials > 0) {
|
||||
cred = &cfg->creds[cred_idx];
|
||||
ESP_LOGD(TAG, "NDP req security: svc='%s' using cred[%u] for peer "MACSTR
|
||||
" (matched_idx=%d, num_creds=%u)",
|
||||
own_svc->svc_name, cred_idx, MAC2STR(peer_nmi),
|
||||
(matched_idx == NAN_NO_MATCHED_CRED) ? -1 : (int)matched_idx,
|
||||
cfg->num_credentials);
|
||||
}
|
||||
|
||||
uint8_t pmk[ESP_WIFI_NAN_NDP_PMK_LEN];
|
||||
uint8_t service_id[6];
|
||||
@@ -934,17 +979,35 @@ esp_err_t nan_security_populate_initiator_ndl(struct ndl_info *ndl,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (cred->use_pmk) {
|
||||
memcpy(pmk, cred->pmk, ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
} else {
|
||||
if (cred->csid == 0) {
|
||||
uint8_t ndp_csid = 0;
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_PAIRING)
|
||||
if (paired && paired->valid && paired->ndp_csid >= WIFI_NAN_CSID_NCS_SK_128 &&
|
||||
paired->ndp_csid <= WIFI_NAN_CSID_NCS_SK_256) {
|
||||
memcpy(pmk, paired->nd_pmk, ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
ndp_csid = paired->ndp_csid;
|
||||
ESP_LOGD(TAG, "NDP req security: using paired-peer cached ND-PMK for " MACSTR
|
||||
" (csid=%u)", MAC2STR(peer_nmi), ndp_csid);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (!cred) {
|
||||
ESP_LOGE(TAG, "NDP req security: no credential and no paired cache for peer " MACSTR,
|
||||
MAC2STR(peer_nmi));
|
||||
goto cleanup;
|
||||
}
|
||||
if (nan_derive_nd_pmk_from_passphrase(cred->passphrase, cred->csid, service_id,
|
||||
peer_nmi, pmk) != 0) {
|
||||
ESP_LOGE(TAG, "NDP req security: passphrase->PMK failed");
|
||||
goto cleanup;
|
||||
if (cred->use_pmk) {
|
||||
memcpy(pmk, cred->pmk, ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
} else {
|
||||
if (cred->csid == 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (nan_derive_nd_pmk_from_passphrase(cred->passphrase, cred->csid, service_id,
|
||||
peer_nmi, pmk) != 0) {
|
||||
ESP_LOGE(TAG, "NDP req security: passphrase->PMK failed");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
ndp_csid = cred->csid;
|
||||
}
|
||||
|
||||
uint8_t pair_pmkid[ESP_WIFI_NAN_NDP_PMKID_LEN];
|
||||
@@ -954,7 +1017,7 @@ esp_err_t nan_security_populate_initiator_ndl(struct ndl_info *ndl,
|
||||
}
|
||||
|
||||
ndl->security_ctx.type = WIFI_NAN_SECURITY_ENCRYPTED;
|
||||
ndl->security_ctx.csid_bitmap = (uint16_t)(1u << cred->csid);
|
||||
ndl->security_ctx.csid_bitmap = (uint16_t)(1u << ndp_csid);
|
||||
memcpy(ndl->security_ctx.nd_pmk, pmk, ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
memcpy(ndl->security_ctx.nd_pmkid, pair_pmkid, ESP_WIFI_NAN_NDP_PMKID_LEN);
|
||||
|
||||
@@ -1044,8 +1107,6 @@ int esp_nan_construct_scia_ndp_resp(uint8_t *frm, uint8_t ndp_id, const uint8_t
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Constructing SCIA (NDP Response M2): ndp_id=%d, pub_id=%d", ndp_id, ndl->publisher_id);
|
||||
ESP_LOGD(TAG, "Using pair-specific PMKID from M1 (not Publish PMKID):");
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, ndl->security_ctx.nd_pmkid, ESP_WIFI_NAN_NDP_PMKID_LEN, ESP_LOG_DEBUG);
|
||||
|
||||
uint8_t pub_id = ndl->publisher_id;
|
||||
uint8_t pmkid_one[1][ESP_WIFI_NAN_NDP_PMKID_LEN];
|
||||
@@ -1131,7 +1192,16 @@ int esp_nan_get_ndp_resp_shared_key_desc(uint8_t *buf, size_t buf_len, uint8_t n
|
||||
bool need_pmk = (ndl->security_ctx.type != WIFI_NAN_SECURITY_ENCRYPTED) ||
|
||||
(memcmp(ndl->security_ctx.nd_pmk, zero_pmk, ESP_WIFI_NAN_NDP_PMK_LEN) == 0);
|
||||
|
||||
if (need_pmk && have_peer_pmkid) {
|
||||
bool resolved_from_pairing_cache = false;
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_PAIRING)
|
||||
if (need_pmk) {
|
||||
resolved_from_pairing_cache = nan_security_fill_from_paired_cache(ndl, peer_nmi);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (resolved_from_pairing_cache) {
|
||||
ESP_LOGD(TAG, "NDP Resp Key Desc: resolved PMK from paired-peer cache");
|
||||
} else if (need_pmk && have_peer_pmkid) {
|
||||
struct own_svc_info *p_svc = nan_find_own_svc(ndl->publisher_id);
|
||||
int matched_idx = p_svc ? nan_match_pmkid(p_svc, ndl->security_ctx.nd_pmkid,
|
||||
ndl->peer_nmi, ndl->peer_ndi) : -1;
|
||||
@@ -1187,20 +1257,6 @@ int esp_nan_get_ndp_resp_shared_key_desc(uint8_t *buf, size_t buf_len, uint8_t n
|
||||
ndl->kek_len = NAN_NCS_SK_128_KEK_LEN;
|
||||
ndl->tk_len = NAN_NCS_SK_128_TK_LEN;
|
||||
ndl->ptk_set = 1;
|
||||
|
||||
ESP_LOGD(TAG, "=== PTK Derivation Debug (M2 Responder) ===");
|
||||
ESP_LOGD(TAG, "ND-PMK:");
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, ndl->security_ctx.nd_pmk, ESP_WIFI_NAN_NDP_PMK_LEN, ESP_LOG_DEBUG);
|
||||
ESP_LOGD(TAG, "ANonce:");
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, ndl->anonce, NAN_NONCE_LEN, ESP_LOG_DEBUG);
|
||||
ESP_LOGD(TAG, "SNonce:");
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, ndl->snonce, NAN_NONCE_LEN, ESP_LOG_DEBUG);
|
||||
ESP_LOGD(TAG, "KCK:");
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, ndl->nd_kck, NAN_NCS_SK_128_KCK_LEN, ESP_LOG_DEBUG);
|
||||
ESP_LOGD(TAG, "KEK:");
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, ndl->nd_kek, NAN_NCS_SK_128_KEK_LEN, ESP_LOG_DEBUG);
|
||||
ESP_LOGD(TAG, "TK:");
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, ndl->nd_tk, NAN_NCS_SK_128_TK_LEN, ESP_LOG_DEBUG);
|
||||
}
|
||||
|
||||
uint8_t *p = buf;
|
||||
@@ -1598,7 +1654,6 @@ esp_err_t esp_nan_parse_publish_security(const uint8_t *attrs, size_t attrs_len,
|
||||
scia = nan_find_attr(attrs, attrs_len, NAN_ATTR_ID_SECURITY_CONTEXT, &scia_len);
|
||||
if (scia && scia_len > 0) {
|
||||
ESP_LOGD(TAG, "Found SCIA in Publish SDF, len=%d", scia_len);
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, scia, scia_len, ESP_LOG_DEBUG);
|
||||
|
||||
size_t offset = 0;
|
||||
while (offset + 4 <= scia_len && security->num_pmkids < NAN_PEER_MAX_PMKIDS) {
|
||||
@@ -1658,7 +1713,13 @@ void nan_security_apply_pending(struct ndl_info *ndl,
|
||||
p_own_svc->derived_security[matched_idx].nd_pmk,
|
||||
ESP_WIFI_NAN_NDP_PMK_LEN);
|
||||
ESP_LOGD(TAG, "NDP Indication: PMKID validated via cred slot %d", matched_idx);
|
||||
} else {
|
||||
}
|
||||
#if defined(CONFIG_ESP_WIFI_NAN_PAIRING)
|
||||
else if (nan_security_fill_from_paired_cache(ndl, peer_nmi)) {
|
||||
ESP_LOGD(TAG, "NDP Indication: PMK sourced from paired-peer cache");
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
ESP_LOGW(TAG, "NDP Indication: PMKID validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,8 +260,16 @@ else()
|
||||
set(pasn_src "")
|
||||
endif()
|
||||
|
||||
if(CONFIG_ESP_WIFI_NAN_PAIRING)
|
||||
set(nan_pair_src
|
||||
"esp_supplicant/src/esp_nan_supplicant.c")
|
||||
else()
|
||||
set(nan_pair_src "")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}" "${esp_srcs}" "${tls_src}" "${roaming_src}"
|
||||
"${crypto_src}" "${mbo_src}" "${dpp_src}" "${wps_registrar_src}" "${usd_src}" "${pasn_src}"
|
||||
"${crypto_src}" "${mbo_src}" "${dpp_src}" "${wps_registrar_src}"
|
||||
"${usd_src}" "${pasn_src}" "${nan_pair_src}"
|
||||
INCLUDE_DIRS include port/include esp_supplicant/include
|
||||
PRIV_INCLUDE_DIRS src src/utils src/common esp_supplicant/src src/crypto
|
||||
../esp_wifi/wifi_apps/roaming_app/include
|
||||
|
||||
@@ -27,7 +27,6 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
struct nan_data;
|
||||
typedef void (*esp_nan_pairing_key_installed_cb_t)(const uint8_t *peer_nmi);
|
||||
|
||||
#if CONFIG_ESP_WIFI_PASN_SUPPORT
|
||||
#ifndef ETH_ALEN
|
||||
@@ -46,11 +45,33 @@ typedef void (*esp_nan_pairing_key_installed_cb_t)(const uint8_t *peer_nmi);
|
||||
#define NAN_PASN_NIK_LEN 16
|
||||
#endif
|
||||
|
||||
#ifndef ESP_NAN_ROLE_ENUM_DEFINED
|
||||
#define ESP_NAN_ROLE_ENUM_DEFINED
|
||||
enum nan_role {
|
||||
NAN_ROLE_IDLE = 0,
|
||||
NAN_ROLE_PAIRING_INITIATOR = 1,
|
||||
NAN_ROLE_PAIRING_RESPONDER = 2,
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Pairing-complete callback. Fires after the PASN pairwise TK is installed and
|
||||
* -- if the PASN PTK carried a KDK -- the ND-PMK has been derived
|
||||
* (Wi-Fi Aware v4.0 section 7.6.4.2: KDF-HASH-256(NM-KDK, "NDP PMK Derivation",
|
||||
* Pairing Initiator NMI || Pairing Responder NMI)).
|
||||
*
|
||||
* @param peer_nmi Peer NMI (6 bytes).
|
||||
* @param role enum nan_role value for the local device.
|
||||
* @param ndp_csid NCS-SK CSID for paired-peer NDP (WIFI_NAN_CSID_NCS_SK_128
|
||||
* or _SK_256), 0 if no usable cipher mapping was available.
|
||||
* @param nd_pmk ND-PMK bytes (32) or NULL if KDK was absent.
|
||||
* @param nd_pmk_len Length of @a nd_pmk (32 when present, 0 otherwise).
|
||||
*/
|
||||
typedef void (*esp_nan_pairing_key_installed_cb_t)(const uint8_t *peer_nmi,
|
||||
uint8_t role,
|
||||
uint8_t ndp_csid,
|
||||
const uint8_t *nd_pmk,
|
||||
size_t nd_pmk_len);
|
||||
|
||||
/**
|
||||
* Last PASN key material after successful pairing (PMK + flattened PTK KCK|KEK|TK|KDK).
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_ESP_WIFI_NAN_PAIRING
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "esp_private/esp_supp_nan.h"
|
||||
@@ -13,7 +17,7 @@ struct wpabuf;
|
||||
struct pasn_data;
|
||||
struct rsn_pmksa_cache;
|
||||
|
||||
typedef void (*nan_pasn_pairing_key_installed_cb_t)(const uint8_t *peer_nmi);
|
||||
typedef esp_nan_pairing_key_installed_cb_t nan_pasn_pairing_key_installed_cb_t;
|
||||
|
||||
struct nan_config {
|
||||
uint8_t dev_addr[ETH_ALEN];
|
||||
@@ -53,3 +57,5 @@ int nan_pasn_verify_eloop(unsigned int secs, unsigned int usecs,
|
||||
const uint8_t *peer_addr, int freq, int role,
|
||||
const uint8_t *bssid,
|
||||
const uint8_t *ssid, size_t ssid_len);
|
||||
|
||||
#endif /* CONFIG_ESP_WIFI_NAN_PAIRING */
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_private/esp_supp_nan.h"
|
||||
#include "esp_nan_supp_i.h"
|
||||
|
||||
#if CONFIG_ESP_WIFI_PASN_SUPPORT
|
||||
#if CONFIG_ESP_WIFI_NAN_PAIRING
|
||||
|
||||
#include "esp_nan_supp_i.h"
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
@@ -54,11 +55,27 @@ int temp = 1;
|
||||
#define NAN_PASN_AES_WRAP_OVERHEAD 8
|
||||
#define NAN_PASN_AES_WRAP_MIN_CIPHERTEXT (NAN_PASN_AES_WRAP_OVERHEAD + 8)
|
||||
|
||||
/**
|
||||
* Map PASN pairwise cipher to the NCS-SK CSID used for paired-peer NDPs
|
||||
* (Wi-Fi Aware v4.0 §7.6.4.2: paired NDP runs NCS-SK style M1-M4, key length
|
||||
* inherits from the PASN cipher).
|
||||
*
|
||||
* Returns 0 when the PASN cipher has no SK equivalent.
|
||||
*/
|
||||
static uint8_t nan_pasn_pasn_cipher_to_ndp_csid(int pasn_cipher)
|
||||
{
|
||||
switch (pasn_cipher) {
|
||||
case WPA_CIPHER_CCMP: return WIFI_NAN_CSID_NCS_SK_128;
|
||||
case WPA_CIPHER_GCMP_256: return WIFI_NAN_CSID_NCS_SK_256;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Key lengths for NCS-PK-PASN-128 / NCS-PK-PASN-256 (Wi-Fi Aware pairing).
|
||||
* Mirrors hostap @c nan_crypto_cipher_*_len in src/nan/nan_crypto.c.
|
||||
*/
|
||||
static size_t nan_pasn_cipher_kck_len(int cipher)
|
||||
static size_t __attribute__((unused)) nan_pasn_cipher_kck_len(int cipher)
|
||||
{
|
||||
switch (cipher) {
|
||||
case WPA_CIPHER_CCMP:
|
||||
@@ -239,8 +256,7 @@ static int nan_pasn_install_nan_pairwise_tk(struct nan_pasn_data *nan, struct pa
|
||||
return -1;
|
||||
}
|
||||
|
||||
ESP_LOG_BUFFER_HEXDUMP("NAN PASN: NM-TK",
|
||||
ptk->tk, ptk->tk_len, ESP_LOG_INFO);
|
||||
wpa_hexdump_key(MSG_DEBUG, "NAN PASN: NM-TK", ptk->tk, ptk->tk_len);
|
||||
kret = esp_wifi_set_nan_key_internal(
|
||||
NAN_PASN_WIFI_ALG_CCMP, pasn->peer_addr, temp, 1, key_rsc, sizeof(key_rsc),
|
||||
ptk->tk, ptk->tk_len,
|
||||
@@ -541,25 +557,17 @@ static int nan_pasn_parse_nik_kdes(const u8 *data, size_t len, int cipher,
|
||||
} else if (gtk_key_len && selector == sel_igtk &&
|
||||
kde_body_len >= gtk_kde_min) {
|
||||
/* IGTK KDE: KeyID(2 LE) | IPN(6) | IGTK */
|
||||
size_t igtk_len = kde_body_len - 8;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"NAN: IGTK KDE KeyID=%u igtk_len=%zu",
|
||||
WPA_GET_LE16(kde_body), igtk_len);
|
||||
wpa_printf(MSG_DEBUG, "NAN: IGTK KDE KeyID=%u igtk_len=%zu",
|
||||
WPA_GET_LE16(kde_body), kde_body_len - 8);
|
||||
wpa_hexdump(MSG_DEBUG, "NAN: IGTK IPN", kde_body + 2, 6);
|
||||
wpa_hexdump_key(MSG_DEBUG, "NAN: IGTK",
|
||||
kde_body + 8, igtk_len);
|
||||
ESP_LOG_BUFFER_HEXDUMP("IGTK", kde_body + 8, igtk_len, ESP_LOG_INFO);
|
||||
wpa_hexdump_key(MSG_DEBUG, "NAN: IGTK", kde_body + 8, kde_body_len - 8);
|
||||
} else if (gtk_key_len && selector == sel_bigtk &&
|
||||
kde_body_len >= gtk_kde_min) {
|
||||
/* BIGTK KDE: KeyID(2 LE) | BIPN(6) | BIGTK */
|
||||
size_t bigtk_len = kde_body_len - 8;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"NAN: BIGTK KDE KeyID=%u bigtk_len=%zu",
|
||||
WPA_GET_LE16(kde_body), bigtk_len);
|
||||
wpa_printf(MSG_DEBUG, "NAN: BIGTK KDE KeyID=%u bigtk_len=%zu",
|
||||
WPA_GET_LE16(kde_body), kde_body_len - 8);
|
||||
wpa_hexdump(MSG_DEBUG, "NAN: BIPN", kde_body + 2, 6);
|
||||
wpa_hexdump_key(MSG_DEBUG, "NAN: BIGTK",
|
||||
kde_body + 8, bigtk_len);
|
||||
ESP_LOG_BUFFER_HEXDUMP("BIGTK", kde_body + 8, bigtk_len, ESP_LOG_INFO);
|
||||
wpa_hexdump_key(MSG_DEBUG, "NAN: BIGTK", kde_body + 8, kde_body_len - 8);
|
||||
}
|
||||
|
||||
pos += 2 + elen;
|
||||
@@ -708,7 +716,6 @@ int nan_pasn_followup_decrypt_keys(const uint8_t *shared_key_attr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
ESP_LOG_BUFFER_HEXDUMP("Key Data", wpabuf_head(key_data), wpabuf_len(key_data), ESP_LOG_INFO);
|
||||
if (nan_pasn_parse_nik_kdes(wpabuf_head(key_data), wpabuf_len(key_data),
|
||||
saved->cipher, nik, &found_cipher_ver,
|
||||
&found_lifetime, &lifetime_bitmap) != 0) {
|
||||
@@ -764,20 +771,6 @@ static int nan_pasn_get_current_freq_mhz(void)
|
||||
return nan_chan_to_freq_mhz(primary);
|
||||
}
|
||||
|
||||
static const char * __attribute__((unused))
|
||||
nan_pasn_role_to_str(enum nan_role role)
|
||||
{
|
||||
switch (role) {
|
||||
case NAN_ROLE_PAIRING_INITIATOR:
|
||||
return "initiator";
|
||||
case NAN_ROLE_PAIRING_RESPONDER:
|
||||
return "responder";
|
||||
case NAN_ROLE_IDLE:
|
||||
default:
|
||||
return "idle";
|
||||
}
|
||||
}
|
||||
|
||||
static void nan_pasn_auth_timeout_cancel(struct nan_pasn_data *nan);
|
||||
|
||||
static void nan_pasn_auth_timeout_cb(void *eloop_ctx, void *user_data)
|
||||
@@ -790,7 +783,9 @@ static void nan_pasn_auth_timeout_cb(void *eloop_ctx, void *user_data)
|
||||
|
||||
wpa_printf(MSG_INFO,
|
||||
"NAN PASN: %s auth timed out after %u seconds",
|
||||
nan_pasn_role_to_str((enum nan_role)(uintptr_t)user_data),
|
||||
((enum nan_role)(uintptr_t)user_data == NAN_ROLE_PAIRING_INITIATOR) ?
|
||||
"initiator" :
|
||||
"responder",
|
||||
NAN_PASN_AUTH_TIMEOUT_SECS);
|
||||
nan_pasn_data_deinit(nan);
|
||||
}
|
||||
@@ -1253,7 +1248,13 @@ static int nan_handle_pasn_auth(struct nan_pasn_data *nan,
|
||||
nan_pasn_copy_keys_from_pasn(nan, pasn);
|
||||
if (nan_pasn_install_nan_pairwise_tk(nan, pasn) == 0 &&
|
||||
nan->pairing_key_installed_cb) {
|
||||
nan->pairing_key_installed_cb(pasn->peer_addr);
|
||||
const uint8_t *nd_pmk = pasn_nd_pmk_global.valid ?
|
||||
pasn_nd_pmk_global.nd_pmk : NULL;
|
||||
size_t nd_pmk_len = pasn_nd_pmk_global.valid ? PMK_LEN : 0;
|
||||
nan->pairing_key_installed_cb(pasn->peer_addr,
|
||||
(uint8_t)nan->dev_role,
|
||||
nan_pasn_pasn_cipher_to_ndp_csid(pasn->cipher),
|
||||
nd_pmk, nd_pmk_len);
|
||||
}
|
||||
forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk));
|
||||
nan_pasn_data_deinit(nan);
|
||||
@@ -1304,7 +1305,13 @@ int nan_pasn_auth_rx(struct nan_pasn_data *nan, const struct ieee80211_auth *mgm
|
||||
nan_pasn_copy_keys_from_pasn(nan, pasn);
|
||||
if (nan_pasn_install_nan_pairwise_tk(nan, pasn) == 0 &&
|
||||
nan->pairing_key_installed_cb) {
|
||||
nan->pairing_key_installed_cb(pasn->peer_addr);
|
||||
const uint8_t *nd_pmk = pasn_nd_pmk_global.valid ?
|
||||
pasn_nd_pmk_global.nd_pmk : NULL;
|
||||
size_t nd_pmk_len = pasn_nd_pmk_global.valid ? PMK_LEN : 0;
|
||||
nan->pairing_key_installed_cb(pasn->peer_addr,
|
||||
(uint8_t)nan->dev_role,
|
||||
nan_pasn_pasn_cipher_to_ndp_csid(pasn->cipher),
|
||||
nd_pmk, nd_pmk_len);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
@@ -1809,141 +1816,4 @@ int esp_nan_supp_pasn_responder_init(const uint8_t *peer_nmi, uint32_t pincode,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !CONFIG_ESP_WIFI_PASN_SUPPORT */
|
||||
|
||||
void handle_auth_pasn(uint8_t *buf, size_t len, uint16_t trans_seq, uint16_t status)
|
||||
{
|
||||
(void)buf;
|
||||
(void)len;
|
||||
(void)trans_seq;
|
||||
(void)status;
|
||||
}
|
||||
|
||||
int nan_initiate_pasn_verify(struct nan_pasn_data *pd, const uint8_t *peer_addr,
|
||||
int freq, int role, const uint8_t *bssid,
|
||||
const uint8_t *ssid, size_t ssid_len)
|
||||
{
|
||||
(void)pd;
|
||||
(void)peer_addr;
|
||||
(void)freq;
|
||||
(void)role;
|
||||
(void)bssid;
|
||||
(void)ssid;
|
||||
(void)ssid_len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int nan_initiate_pasn_auth(struct nan_pasn_data *pd, const uint8_t *addr, int freq)
|
||||
{
|
||||
(void)pd;
|
||||
(void)addr;
|
||||
(void)freq;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct nan_pasn_data *nan_pasn_data_init(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void nan_pasn_data_deinit(struct nan_pasn_data *pd)
|
||||
{
|
||||
(void)pd;
|
||||
}
|
||||
|
||||
int nan_pasn_auth_initiate(struct nan_pasn_data *pd, const uint8_t *peer_addr, int freq)
|
||||
{
|
||||
(void)pd;
|
||||
(void)peer_addr;
|
||||
(void)freq;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int nan_pasn_auth(struct nan_pasn_data **pd_out, const uint8_t *peer_addr, int freq)
|
||||
{
|
||||
(void)pd_out;
|
||||
(void)peer_addr;
|
||||
(void)freq;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int nan_pasn_auth_eloop(const uint8_t *peer_addr, uint32_t pincode)
|
||||
{
|
||||
(void)peer_addr;
|
||||
(void)pincode;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int nan_pasn_verify_eloop(unsigned int secs, unsigned int usecs,
|
||||
const uint8_t *peer_addr, int freq, int role,
|
||||
const uint8_t *bssid,
|
||||
const uint8_t *ssid, size_t ssid_len)
|
||||
{
|
||||
(void)secs;
|
||||
(void)usecs;
|
||||
(void)peer_addr;
|
||||
(void)freq;
|
||||
(void)role;
|
||||
(void)bssid;
|
||||
(void)ssid;
|
||||
(void)ssid_len;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pasn_responder_init(const uint8_t *peer_addr, uint32_t pincode)
|
||||
{
|
||||
(void)peer_addr;
|
||||
(void)pincode;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pasn_responder_init_eloop(const uint8_t *peer_addr, uint32_t pincode)
|
||||
{
|
||||
(void)peer_addr;
|
||||
(void)pincode;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int esp_nan_supp_pasn_responder_init(const uint8_t *peer_nmi, uint32_t pincode,
|
||||
esp_nan_pairing_key_installed_cb_t pairing_key_installed_cb)
|
||||
{
|
||||
(void)peer_nmi;
|
||||
(void)pincode;
|
||||
(void)pairing_key_installed_cb;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int esp_nan_supp_pasn_initiator_auth(const uint8_t *peer_nmi, uint32_t pincode,
|
||||
esp_nan_pairing_key_installed_cb_t pairing_key_installed_cb)
|
||||
{
|
||||
(void)peer_nmi;
|
||||
(void)pincode;
|
||||
(void)pairing_key_installed_cb;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const struct nan_pasn_key_material *nan_pasn_get_saved_keys(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void nan_pasn_clear_saved_keys(void)
|
||||
{
|
||||
}
|
||||
|
||||
int nan_pasn_followup_decrypt_keys(const uint8_t *shared_key_attr,
|
||||
size_t attr_total_len,
|
||||
uint8_t *nik, size_t nik_size,
|
||||
uint8_t *cipher_ver,
|
||||
uint32_t *lifetime_sec)
|
||||
{
|
||||
(void)shared_key_attr;
|
||||
(void)attr_total_len;
|
||||
(void)nik;
|
||||
(void)nik_size;
|
||||
(void)cipher_ver;
|
||||
(void)lifetime_sec;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ESP_WIFI_PASN_SUPPORT */
|
||||
#endif /* CONFIG_ESP_WIFI_NAN_PAIRING */
|
||||
|
||||
@@ -333,7 +333,6 @@ void esp_wifi_set_sigma_internal(bool flag);
|
||||
void esp_wifi_ap_set_group_mgmt_cipher_internal(wifi_cipher_type_t cipher);
|
||||
uint8_t esp_wifi_op_class_supported_internal(uint8_t op_class, uint8_t min_chan, uint8_t max_chan, uint8_t inc, uint8_t bw, channel_bitmap_t *non_pref_channels);
|
||||
bool esp_wifi_is_wpa3_compatible_mode_enabled(uint8_t if_index);
|
||||
esp_err_t esp_wifi_nan_get_pasn_attr(uint8_t *buf, size_t buf_len, size_t *actual_len);
|
||||
uint8_t esp_wifi_ap_get_owe_config_internal(void);
|
||||
|
||||
#endif /* _ESP_WIFI_DRIVER_H_ */
|
||||
|
||||
@@ -66,6 +66,7 @@ void pmksa_cache_remove(struct rsn_pmksa_cache *pmksa,
|
||||
e->next = entry->next;
|
||||
break;
|
||||
}
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
if (!e) {
|
||||
@@ -394,6 +395,8 @@ struct rsn_pmksa_cache_entry *
|
||||
pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
|
||||
const u8 *aa)
|
||||
{
|
||||
if (!pmksa)
|
||||
return NULL;
|
||||
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "RSN: Consider " MACSTR " for OKC", MAC2STR(aa));
|
||||
|
||||
Reference in New Issue
Block a user