From d66ccc2479dfac081eb370b5409f2f330f53afe8 Mon Sep 17 00:00:00 2001 From: Akshat Agrawal Date: Sat, 2 May 2026 16:01:26 +0530 Subject: [PATCH] feat(wifi): Add multiple NAN Service Discovery improvements - Add Country Code, Vendor IE to NAN frames - Support parsing of multiple availibility & SDA attributes - Add parsing of service response filter - Support Bloom filter parsing and generation - Record peer_svc for nan_indication_cb - Add support for NDPE Extension attribute --- .../esp_wifi/include/esp_private/wifi.h | 44 +++- .../esp_wifi/include/esp_wifi_types_generic.h | 31 ++- components/esp_wifi/lib | 2 +- .../include/injected/esp_wifi_types_generic.h | 31 ++- .../wifi_apps/nan_app/include/esp_nan.h | 17 +- .../esp_wifi/wifi_apps/nan_app/src/nan_app.c | 201 +++++++++++++++--- .../wifi_aware/nan_console/main/nan_main.c | 2 +- .../nan_publisher/main/publisher_main.c | 4 +- .../nan_subscriber/main/subscriber_main.c | 10 +- 9 files changed, 276 insertions(+), 66 deletions(-) diff --git a/components/esp_wifi/include/esp_private/wifi.h b/components/esp_wifi/include/esp_private/wifi.h index d95f3ffae30..06373a8a7cb 100644 --- a/components/esp_wifi/include/esp_private/wifi.h +++ b/components/esp_wifi/include/esp_private/wifi.h @@ -39,15 +39,34 @@ typedef struct { void *storage; /**< storage for FreeRTOS queue */ } wifi_static_queue_t; +/* NAN Peer info parsed from SDF */ +struct nan_cb_peer_info { + uint8_t peer_mac[6]; /**< Peer NMI / interface MAC */ + uint8_t peer_svc_id; /**< Peer's service instance ID */ + uint16_t sdea; /**< SDEA control field bits */ + uint32_t device_caps; /**< NAN device capabilities */ + uint8_t ssi_ver; /**< SSI version (service_match) */ + uint8_t *ssi; /**< Service-specific information */ + uint16_t ssi_len; /**< SSI length in bytes */ + nan_vendor_ie_t *vendor_ie; /**< Vendor-specific IE, if any */ +}; + +/* NDP Peer info parsed from NAF */ +struct ndp_cb_peer_info { + uint8_t ndp_id; + uint8_t peer_nmi[6]; + uint8_t peer_ndi[6]; + uint8_t *ssi; + uint16_t ssi_len; +}; + struct nan_sync_callbacks { - void (* service_match)(uint8_t sub_id, uint8_t pub_id, uint8_t pub_mac[6], uint16_t capab, - uint8_t ssi_ver, uint8_t *ssi, uint16_t ssi_len); - void (* replied)(uint8_t pub_id, uint8_t sub_id, uint8_t pub_mac[6], uint8_t *ssi, uint16_t ssi_len); - void (* receive)(uint8_t svc_id, uint8_t peer_svc_id, uint8_t peer_mac[6], uint8_t *ssi, uint16_t ssi_len); - void (* ndp_indication)(uint8_t pub_id, uint8_t ndp_id, uint8_t peer_nmi[6], uint8_t peer_ndi[6], - uint8_t *ssi, uint16_t ssi_len); - void (* ndp_confirm)(uint8_t status, uint8_t ndp_id, uint8_t peer_nmi[6], uint8_t peer_ndi[6], - uint8_t own_ndi[6], uint8_t *ssi, uint16_t ssi_len); + void (* service_match)(uint8_t sub_id, struct nan_cb_peer_info *peer_info); + void (* replied)(uint8_t pub_id, struct nan_cb_peer_info *peer_info); + void (* receive)(uint8_t svc_id, struct nan_cb_peer_info *peer_info); + void (* ndp_indication)(uint8_t pub_id, struct ndp_cb_peer_info *peer_info, uint32_t device_caps); + void (* ndp_confirm)(uint8_t status, struct ndp_cb_peer_info *peer_info, + 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 (* action_txdone)(uint32_t context, bool tx_status); }; @@ -741,13 +760,15 @@ esp_err_t esp_nan_internal_send_followup(const wifi_nan_followup_params_t *fup_p * * @attention This API should be called after WIFI_EVENT_NAN_SVC_MATCH event is received. * - * @param req NAN Datapath Request parameters. + * @param[in] req NAN Datapath Request parameters. + * @param[out] ndp_id Pointer to the NDP ID in the NAN Datapath Request. + * @param[in] ipv6_identifier IPV6 Address Identifier to be sent in the NDPE attribute. * * @return * - ESP_OK: succeed * - others: failed */ -esp_err_t esp_nan_internal_datapath_req(wifi_nan_datapath_req_t *req, uint8_t *ndp_id); +esp_err_t esp_nan_internal_datapath_req(wifi_nan_datapath_req_t *req, uint8_t *ndp_id, uint8_t ipv6_identifier[8]); /** * @brief Send Datapath Response to accept or reject the received request @@ -755,12 +776,13 @@ esp_err_t esp_nan_internal_datapath_req(wifi_nan_datapath_req_t *req, uint8_t *n * @attention This API should be called on the Publisher after receiving WIFI_EVENT_NDP_INDICATION event. * * @param resp NAN Datapath Response parameters. + * @param ipv6_identifier IPV6 Address Identifier to be sent in the NDPE attribute. * * @return * - ESP_OK: succeed * - others: failed */ -esp_err_t esp_nan_internal_datapath_resp(wifi_nan_datapath_resp_t *resp); +esp_err_t esp_nan_internal_datapath_resp(wifi_nan_datapath_resp_t *resp, uint8_t ipv6_identifier[8]); /** * @brief End NAN Datapath that is active diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index c79d5e6c820..83b82fd73ae 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -592,10 +592,11 @@ typedef struct { * @brief NAN Discovery start configuration */ typedef struct { - uint8_t op_channel; /**< NAN Discovery operating channel */ - uint8_t master_pref; /**< Device's preference value to serve as NAN Master */ - uint8_t scan_time; /**< Scan time in seconds while searching for a NAN cluster */ - uint16_t warm_up_sec; /**< Warm up time before assuming NAN Anchor Master role */ + uint8_t op_channel; /**< NAN Discovery operating channel */ + uint8_t master_pref; /**< Device's preference value to serve as NAN Master */ + uint8_t scan_time; /**< Scan time in seconds while searching for a NAN cluster */ + uint16_t warm_up_sec; /**< Warm up time before assuming NAN Anchor Master role */ + bool disable_random_mac;/**< Disable the MAC Randomisation in NAN */ } wifi_nan_sync_config_t; /** @@ -916,6 +917,17 @@ typedef struct { uint8_t m_max; /**< Indicates maximum value of dwell period M used in the USD (Mmax)*/ } wifi_nan_usd_config_t; +#define NAN_VENDOR_IE_MAX_BODY_LEN 255 + +/** + * @brief NAN Vendor Specific Attribute format + */ +typedef struct { + uint8_t vendor_oui[3]; /**< Vendor identifier (OUI) */ + uint16_t body_len; /**< Length of body payload (max NAN_VENDOR_IE_MAX_BODY_LEN bytes) */ + uint8_t *body; /**< Vendor specific body payload */ +} nan_vendor_ie_t; + /** * @brief NAN Publish service configuration parameters * @@ -936,6 +948,7 @@ typedef struct { 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 */ wifi_nan_usd_config_t usd_publish_config; /**< USD configuration parameters. Relevant only when 'usd_discovery_flag' is set. */ + nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in publish frames */ } wifi_nan_publish_cfg_t; /** @@ -957,6 +970,7 @@ typedef struct { 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. */ wifi_nan_usd_config_t usd_subscribe_config; /**< USD configuration parameters. Relevant only when 'usd_discovery_flag' is set. */ + nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in subscribe frames */ } wifi_nan_subscribe_cfg_t; /** @@ -969,6 +983,7 @@ typedef struct { uint8_t peer_mac[6]; /**< Peer's MAC address */ uint16_t ssi_len; /**< Length of service specific info, maximum allowed length - ESP_WIFI_MAX_FUP_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 */ + nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in followup frames */ } wifi_nan_followup_params_t; /** @@ -989,6 +1004,8 @@ typedef struct { bool accept; /**< True - Accept incoming NDP, False - Reject it */ uint8_t ndp_id; /**< NAN Datapath Identifier */ uint8_t peer_mac[6]; /**< Peer's MAC address */ + 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 */ } wifi_nan_datapath_resp_t; /** @@ -1393,7 +1410,8 @@ typedef struct { 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 reserved: 5; /**< Reserved */ + uint8_t ndpe_support: 1; /**< NDPE supported by peer */ + uint8_t reserved: 4; /**< 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 */ @@ -1450,8 +1468,7 @@ typedef struct { uint8_t peer_nmi[6]; /**< Peer's NAN Management Interface MAC */ uint8_t peer_ndi[6]; /**< Peer's NAN Data Interface MAC */ uint8_t own_ndi[6]; /**< Own NAN Data Interface MAC */ - uint32_t reserved_1; /**< Reserved */ - uint32_t reserved_2; /**< Reserved */ + uint8_t ipv6_identifier[8]; /**< Peer's IPV6 Address Identifier */ uint16_t ssi_len; /**< Length of Service Specific Info */ uint8_t ssi[]; /**< Service specific info from NDP/NDPE Attribute */ } wifi_event_ndp_confirm_t; diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 2eed7daab08..4088f42e77f 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 2eed7daab08418de739af00fe8b3cbc8ea65bb9a +Subproject commit 4088f42e77f99edebd47a531c5e017c6bfa1157f diff --git a/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h b/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h index fc01e6f4959..be9a81a0070 100644 --- a/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h +++ b/components/esp_wifi/remote/include/injected/esp_wifi_types_generic.h @@ -592,10 +592,11 @@ typedef struct { * @brief NAN Discovery start configuration */ typedef struct { - uint8_t op_channel; /**< NAN Discovery operating channel */ - uint8_t master_pref; /**< Device's preference value to serve as NAN Master */ - uint8_t scan_time; /**< Scan time in seconds while searching for a NAN cluster */ - uint16_t warm_up_sec; /**< Warm up time before assuming NAN Anchor Master role */ + uint8_t op_channel; /**< NAN Discovery operating channel */ + uint8_t master_pref; /**< Device's preference value to serve as NAN Master */ + uint8_t scan_time; /**< Scan time in seconds while searching for a NAN cluster */ + uint16_t warm_up_sec; /**< Warm up time before assuming NAN Anchor Master role */ + bool disable_random_mac;/**< Disable the MAC Randomisation in NAN */ } wifi_nan_sync_config_t; /** @@ -916,6 +917,17 @@ typedef struct { uint8_t m_max; /**< Indicates maximum value of dwell period M used in the USD (Mmax)*/ } wifi_nan_usd_config_t; +#define NAN_VENDOR_IE_MAX_BODY_LEN 255 + +/** + * @brief NAN Vendor Specific Attribute format + */ +typedef struct { + uint8_t vendor_oui[3]; /**< Vendor identifier (OUI) */ + uint16_t body_len; /**< Length of body payload (max NAN_VENDOR_IE_MAX_BODY_LEN bytes) */ + uint8_t *body; /**< Vendor specific body payload */ +} nan_vendor_ie_t; + /** * @brief NAN Publish service configuration parameters * @@ -936,6 +948,7 @@ typedef struct { 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 */ wifi_nan_usd_config_t usd_publish_config; /**< USD configuration parameters. Relevant only when 'usd_discovery_flag' is set. */ + nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in publish frames */ } wifi_nan_publish_cfg_t; /** @@ -957,6 +970,7 @@ typedef struct { 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. */ wifi_nan_usd_config_t usd_subscribe_config; /**< USD configuration parameters. Relevant only when 'usd_discovery_flag' is set. */ + nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in subscribe frames */ } wifi_nan_subscribe_cfg_t; /** @@ -969,6 +983,7 @@ typedef struct { uint8_t peer_mac[6]; /**< Peer's MAC address */ uint16_t ssi_len; /**< Length of service specific info, maximum allowed length - ESP_WIFI_MAX_FUP_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 */ + nan_vendor_ie_t *vendor_ie; /**< Vendor specific IE to be added in followup frames */ } wifi_nan_followup_params_t; /** @@ -989,6 +1004,8 @@ typedef struct { bool accept; /**< True - Accept incoming NDP, False - Reject it */ uint8_t ndp_id; /**< NAN Datapath Identifier */ uint8_t peer_mac[6]; /**< Peer's MAC address */ + 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 */ } wifi_nan_datapath_resp_t; /** @@ -1393,7 +1410,8 @@ typedef struct { 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 reserved: 5; /**< Reserved */ + uint8_t ndpe_support: 1; /**< NDPE supported by peer */ + uint8_t reserved: 4; /**< 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 */ @@ -1450,8 +1468,7 @@ typedef struct { uint8_t peer_nmi[6]; /**< Peer's NAN Management Interface MAC */ uint8_t peer_ndi[6]; /**< Peer's NAN Data Interface MAC */ uint8_t own_ndi[6]; /**< Own NAN Data Interface MAC */ - uint32_t reserved_1; /**< Reserved */ - uint32_t reserved_2; /**< Reserved */ + uint8_t ipv6_identifier[8]; /**< Peer's IPV6 Address Identifier */ uint16_t ssi_len; /**< Length of Service Specific Info */ uint8_t ssi[]; /**< Service specific info from NDP/NDPE Attribute */ } wifi_event_ndp_confirm_t; diff --git a/components/esp_wifi/wifi_apps/nan_app/include/esp_nan.h b/components/esp_wifi/wifi_apps/nan_app/include/esp_nan.h index 98391602c0b..63c58bc44c8 100644 --- a/components/esp_wifi/wifi_apps/nan_app/include/esp_nan.h +++ b/components/esp_wifi/wifi_apps/nan_app/include/esp_nan.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -21,6 +21,7 @@ extern "C" { .master_pref = 2, \ .scan_time = 3, \ .warm_up_sec = 5, \ + .disable_random_mac = false, \ }; #define NDP_STATUS_ACCEPTED 1 @@ -29,6 +30,20 @@ extern "C" { #define NAN_MAX_PEERS_RECORD 15 #define ESP_NAN_PUBLISH 2 #define ESP_NAN_SUBSCRIBE 1 +#define NAN_IPV6_ADDR_ID_LEN 8 + +#define IS_ZERO_NAN_ADDR_ID(a) (!((a)[0] | (a)[1] | (a)[2] | (a)[3] | \ + (a)[4] | (a)[5] | (a)[6] | (a)[7])) + +#define ESP_NAN_SET_IPV6_LINKLOCAL_FROM_IDENTIFIER(_target_addr, _identifier) \ + do { \ + (_target_addr).type = IPADDR_TYPE_V6; \ + (_target_addr).u_addr.ip6.addr[0] = htonl(0xFE800000); \ + (_target_addr).u_addr.ip6.addr[1] = 0; \ + memcpy(&(_target_addr).u_addr.ip6.addr[2], \ + (_identifier), \ + NAN_IPV6_ADDR_ID_LEN); \ + } while (0) /** Parameters of a peer service record */ struct nan_peer_record { diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c index ad5a117621d..6a56bd5d1d4 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -33,6 +33,9 @@ #define NDP_TERMINATED BIT6 #define NDP_REJECTED BIT7 +/* NAN Caps */ +#define NAN_CAPS_NDPE_ATTR BIT3 + /* Macros */ #define MACADDR_LEN 6 #define MACADDR_EQUAL(a1, a2) (memcmp(a1, a2, MACADDR_LEN)) @@ -73,6 +76,7 @@ struct peer_svc_info { 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 { @@ -90,6 +94,7 @@ struct ndl_info { 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 { @@ -208,7 +213,7 @@ static struct peer_svc_info *nan_find_peer_svc(uint8_t own_svc_id, uint8_t peer_ return p_peer_svc; } -static bool nan_record_peer_svc(uint8_t own_svc_id, uint8_t peer_svc_id, uint8_t peer_nmi[]) +static bool nan_record_peer_svc(uint8_t own_svc_id, uint8_t peer_svc_id, uint8_t peer_nmi[], uint32_t device_caps) { struct own_svc_info *p_own_svc; struct peer_svc_info *p_peer_svc; @@ -227,7 +232,7 @@ static bool nan_record_peer_svc(uint8_t own_svc_id, uint8_t peer_svc_id, uint8_t p_peer_svc->own_svc_id = own_svc_id; p_peer_svc->type = (p_own_svc->type == ESP_NAN_SUBSCRIBE) ? ESP_NAN_PUBLISH : ESP_NAN_SUBSCRIBE; MACADDR_COPY(p_peer_svc->peer_nmi, peer_nmi); - + p_peer_svc->device_caps = device_caps; if (p_own_svc->num_peer_records < NAN_MAX_PEERS_RECORD) { SLIST_INSERT_HEAD(&(p_own_svc->peer_list), p_peer_svc, next); p_own_svc->num_peer_records++; @@ -337,7 +342,7 @@ static bool ndl_limit_reached(void) return true; } -static void nan_record_new_ndl(uint8_t ndp_id, uint8_t publish_id, uint8_t peer_nmi[], uint8_t own_role) +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; @@ -351,6 +356,7 @@ static void nan_record_new_ndl(uint8_t ndp_id, uint8_t publish_id, uint8_t peer_ return; } ndl->ndp_id = ndp_id; + ndl->device_caps = device_caps; if (peer_nmi) { MACADDR_COPY(ndl->peer_nmi, peer_nmi); } @@ -449,21 +455,36 @@ static void nan_app_post_event(int32_t event_id, void* event_data, size_t event_ 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, uint8_t pub_id, uint8_t pub_mac[6], uint16_t capab, - uint8_t ssi_ver, uint8_t *ssi, uint16_t ssi_len) +void nan_app_service_match_cb(uint8_t sub_id, struct nan_cb_peer_info *peer_info) { - NAN_DATA_LOCK(); - struct peer_svc_info *peer_info = nan_find_peer_svc(sub_id, 0, pub_mac); + if (!peer_info) { + return; + } + uint8_t pub_id = peer_info->peer_svc_id; + uint8_t *pub_mac = peer_info->peer_mac; + uint16_t capab = peer_info->sdea; + uint8_t ssi_ver = peer_info->ssi_ver; + uint8_t *ssi = peer_info->ssi; + uint16_t ssi_len = peer_info->ssi_len; + uint32_t device_caps = peer_info->device_caps; - if (peer_info && peer_info->svc_id != pub_id) { + NAN_DATA_LOCK(); + struct peer_svc_info *p_peer_svc = nan_find_peer_svc(sub_id, 0, pub_mac); + + if (p_peer_svc) { struct ndl_info *ndl = nan_find_ndl(0, pub_mac); - peer_info->svc_id = pub_id; - if (ndl) { + p_peer_svc->device_caps = device_caps; + if (p_peer_svc->svc_id != pub_id) { + p_peer_svc->svc_id = pub_id; + if (ndl) { + ndl->publisher_id = pub_id; + } + } else if (ndl) { ndl->publisher_id = pub_id; } } else { - nan_record_peer_svc(sub_id, pub_id, pub_mac); + nan_record_peer_svc(sub_id, pub_id, pub_mac, device_caps); } NAN_DATA_UNLOCK(); @@ -481,6 +502,7 @@ void nan_app_service_match_cb(uint8_t sub_id, uint8_t pub_id, uint8_t pub_mac[6] evt->fsd_reqd = (capab & NAN_SDEA_CTRL_FSD_REQD) ? 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->ndpe_support = (device_caps & NAN_CAPS_NDPE_ATTR) ? 1 : 0; evt->ssi_version = ssi_ver; if (ssi && ssi_len) { if (ssi_ver) { @@ -498,11 +520,23 @@ void nan_app_service_match_cb(uint8_t sub_id, uint8_t pub_id, uint8_t pub_mac[6] os_free(evt); } -void nan_app_replied_cb(uint8_t pub_id, uint8_t sub_id, uint8_t sub_nmi[6], uint8_t *ssi, uint16_t ssi_len) +void nan_app_replied_cb(uint8_t pub_id, struct nan_cb_peer_info *peer_info) { + if (!peer_info) { + return; + } + uint8_t sub_id = peer_info->peer_svc_id; + uint8_t *sub_nmi = peer_info->peer_mac; + uint8_t *ssi = peer_info->ssi; + uint16_t ssi_len = peer_info->ssi_len; + uint32_t device_caps = peer_info->device_caps; + NAN_DATA_LOCK(); - if (!nan_find_peer_svc(pub_id, sub_id, sub_nmi)) { - nan_record_peer_svc(pub_id, sub_id, sub_nmi); + struct peer_svc_info *p_peer_svc = 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_DATA_UNLOCK(); @@ -524,15 +558,27 @@ void nan_app_replied_cb(uint8_t pub_id, uint8_t sub_id, uint8_t sub_nmi[6], uint ESP_LOG_BUFFER_HEXDUMP(TAG, ssi, ssi_len, ESP_LOG_DEBUG); } - nan_app_post_event(WIFI_EVENT_NAN_REPLIED, evt, sizeof(wifi_event_nan_replied_t)); + nan_app_post_event(WIFI_EVENT_NAN_REPLIED, evt, evt_data_len); os_free(evt); } -void nan_app_receive_cb(uint8_t svc_id, uint8_t peer_svc_id, uint8_t peer_mac[6], uint8_t *ssi, uint16_t ssi_len) +void nan_app_receive_cb(uint8_t svc_id, struct nan_cb_peer_info *peer_info) { + if (!peer_info) { + return; + } + uint8_t peer_svc_id = peer_info->peer_svc_id; + uint8_t *peer_mac = peer_info->peer_mac; + uint8_t *ssi = peer_info->ssi; + uint16_t ssi_len = peer_info->ssi_len; + uint32_t device_caps = peer_info->device_caps; + NAN_DATA_LOCK(); - if (!nan_find_peer_svc(svc_id, peer_svc_id, peer_mac)) { - nan_record_peer_svc(svc_id, peer_svc_id, peer_mac); + struct peer_svc_info *p_peer_svc = 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_DATA_UNLOCK(); @@ -557,9 +603,18 @@ void nan_app_receive_cb(uint8_t svc_id, uint8_t peer_svc_id, uint8_t peer_mac[6] os_free(evt); } -void nan_app_ndp_indication_cb(uint8_t pub_id, uint8_t ndp_id, uint8_t peer_nmi[6], uint8_t peer_ndi[6], - uint8_t *ssi, uint16_t ssi_len) +void nan_app_ndp_indication_cb(uint8_t pub_id, struct ndp_cb_peer_info *peer_info, uint32_t device_caps) { + 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; + uint8_t *ssi = peer_info->ssi; + uint16_t ssi_len = peer_info->ssi_len; + bool ndp_resp_needed = false; + NAN_DATA_LOCK(); struct own_svc_info *p_own_svc = nan_find_own_svc(pub_id); @@ -568,25 +623,46 @@ void nan_app_ndp_indication_cb(uint8_t pub_id, uint8_t ndp_id, uint8_t peer_nmi[ NAN_DATA_UNLOCK(); return; } + ndp_resp_needed = p_own_svc->ndp_resp_needed; if (ndl_limit_reached()) { ESP_LOGE(TAG, "NDP limit reached"); NAN_DATA_UNLOCK(); return; } - nan_record_new_ndl(ndp_id, pub_id, peer_nmi, ESP_WIFI_NDP_ROLE_RESPONDER); + if (!nan_find_peer_svc(pub_id, 0, peer_nmi)) { + nan_record_peer_svc(pub_id, 0, peer_nmi, device_caps); + } 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_LOGI(TAG, "NDP Req from "MACSTR" [NDP Id: %d], Accept OR Deny using NDP command", MAC2STR(peer_nmi), ndp_id); s_nan_ctx.event |= NDP_INDICATION; } else { + uint8_t own_bssid[6]; + ip_addr_t own_ipv6 = {0}; + wifi_nan_datapath_resp_t ndp_resp = {0}; ndp_resp.accept = true; ndp_resp.ndp_id = ndp_id; MACADDR_COPY(ndp_resp.peer_mac, peer_nmi); - esp_nan_internal_datapath_resp(&ndp_resp); + if (device_caps & NAN_CAPS_NDPE_ATTR) { + esp_err_t err = esp_wifi_get_mac(WIFI_IF_NAN, own_bssid); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Cannot get own BSSID!"); + ndp_resp.accept = false; + } else { + esp_wifi_nan_get_ipv6_linklocal_from_mac(&own_ipv6.u_addr.ip6, own_bssid); + } + } + + if (ndp_resp.accept) { + nan_record_new_ndl(ndp_id, pub_id, peer_nmi, ESP_WIFI_NDP_ROLE_RESPONDER, device_caps); + } + + esp_nan_internal_datapath_resp(&ndp_resp, (uint8_t *)&own_ipv6.u_addr.ip6.addr[2] ); } NAN_DATA_UNLOCK(); @@ -594,6 +670,21 @@ void nan_app_ndp_indication_cb(uint8_t pub_id, uint8_t ndp_id, uint8_t peer_nmi[ wifi_event_ndp_indication_t *evt = (wifi_event_ndp_indication_t *)os_zalloc(evt_data_len); if (!evt) { ESP_LOGE(TAG, "Failed to allocate for event"); + if (ndp_resp_needed) { + uint8_t ipv6_identifier[8] = {0}; + wifi_nan_datapath_resp_t ndp_resp = {0}; + + ndp_resp.accept = false; + ndp_resp.ndp_id = ndp_id; + MACADDR_COPY(ndp_resp.peer_mac, peer_nmi); + + NAN_DATA_LOCK(); + nan_reset_ndl(ndp_id, false); + s_nan_ctx.event &= ~NDP_INDICATION; + NAN_DATA_UNLOCK(); + + esp_nan_internal_datapath_resp(&ndp_resp, ipv6_identifier); + } return; } @@ -611,9 +702,17 @@ void nan_app_ndp_indication_cb(uint8_t pub_id, uint8_t ndp_id, uint8_t peer_nmi[ os_free(evt); } -void nan_app_ndp_confirm_cb(uint8_t status, uint8_t ndp_id, uint8_t peer_nmi[6], uint8_t peer_ndi[6], - uint8_t own_ndi[6], uint8_t *ssi, uint16_t ssi_len) +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]) { + 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; + uint8_t *ssi = peer_info->ssi; + uint16_t ssi_len = peer_info->ssi_len; NAN_DATA_LOCK(); struct ndl_info *ndl = nan_find_ndl(ndp_id, peer_nmi); if (!ndl) { @@ -643,6 +742,7 @@ void nan_app_ndp_confirm_cb(uint8_t status, uint8_t ndp_id, uint8_t peer_nmi[6], goto done; } + 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); if (!evt) { @@ -660,6 +760,15 @@ void nan_app_ndp_confirm_cb(uint8_t status, uint8_t ndp_id, uint8_t peer_nmi[6], MACADDR_COPY(evt->peer_nmi, peer_nmi); MACADDR_COPY(evt->peer_ndi, peer_ndi); MACADDR_COPY(evt->own_ndi, own_ndi); + + if (IS_ZERO_NAN_ADDR_ID(ipv6_identifier)) { + ip6_addr_t linklocal; + esp_wifi_nan_get_ipv6_linklocal_from_mac(&linklocal, peer_ndi); + memcpy(evt->ipv6_identifier, &linklocal.addr[2], NAN_IPV6_ADDR_ID_LEN); + } else { + memcpy(evt->ipv6_identifier, ipv6_identifier, NAN_IPV6_ADDR_ID_LEN); + } + if (ssi && ssi_len) { memcpy(evt->ssi, ssi, ssi_len); evt->ssi_len = ssi_len; @@ -670,11 +779,14 @@ void nan_app_ndp_confirm_cb(uint8_t status, uint8_t ndp_id, uint8_t peer_nmi[6], esp_netif_create_ip6_linklocal(s_nan_ctx.nan_netif); NAN_DATA_UNLOCK(); - ip_addr_t target_addr = {0}; - esp_wifi_nan_get_ipv6_linklocal_from_mac(&target_addr.u_addr.ip6, peer_ndi); - target_addr.type = IPADDR_TYPE_V6; + ip6_addr_t peer_ip6 = {0}; + peer_ip6.addr[0] = PP_HTONL(0xfe800000); + peer_ip6.addr[1] = 0; + memcpy(&peer_ip6.addr[2], evt->ipv6_identifier, 8); + ESP_LOGI(TAG, "NDP confirmed with Peer "MACSTR" [NDP ID - %d, Peer IPv6 - %s]", - MAC2STR(peer_nmi), ndp_id, inet6_ntoa(*ip_2_ip6(&target_addr))); + MAC2STR(peer_nmi), ndp_id, inet6_ntoa(peer_ip6)); + os_event_group_set_bits(nan_event_group, NDP_ACCEPTED); nan_app_post_event(WIFI_EVENT_NDP_CONFIRM, evt, evt_data_len); @@ -1187,7 +1299,8 @@ done: uint8_t esp_wifi_nan_datapath_req(wifi_nan_datapath_req_t *req) { uint8_t ndp_id = 0; - + uint8_t own_bssid[6]; + ip_addr_t own_ipv6 = {0}; NAN_DATA_LOCK(); struct peer_svc_info *p_peer_svc = nan_find_peer_svc(0, req->pub_id, req->peer_mac); @@ -1195,6 +1308,17 @@ uint8_t esp_wifi_nan_datapath_req(wifi_nan_datapath_req_t *req) ESP_LOGE(TAG, "Cannot send NDP Req, peer not found!"); goto fail; } + + if (p_peer_svc->device_caps & NAN_CAPS_NDPE_ATTR) { + esp_err_t err = esp_wifi_get_mac(WIFI_IF_NAN, own_bssid); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "Cannot get own BSSID!"); + goto fail; + } + esp_wifi_nan_get_ipv6_linklocal_from_mac(&own_ipv6.u_addr.ip6, own_bssid); + } + if (req->pub_id == 0) req->pub_id = p_peer_svc->svc_id; @@ -1212,12 +1336,12 @@ uint8_t esp_wifi_nan_datapath_req(wifi_nan_datapath_req_t *req) } os_event_group_clear_bits(nan_event_group, NDP_ACCEPTED | NDP_REJECTED); - if (esp_nan_internal_datapath_req(req, &ndp_id) != ESP_OK) { + 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"); goto fail; } - nan_record_new_ndl(ndp_id, req->pub_id, req->peer_mac, ESP_WIFI_NDP_ROLE_INITIATOR); + nan_record_new_ndl(ndp_id, req->pub_id, req->peer_mac, ESP_WIFI_NDP_ROLE_INITIATOR, p_peer_svc->device_caps); NAN_DATA_UNLOCK(); ESP_LOGD(TAG, "Requested NDP with "MACSTR" [NDP ID - %d]", MAC2STR(req->peer_mac), ndp_id); @@ -1243,6 +1367,8 @@ esp_err_t esp_wifi_nan_datapath_resp(wifi_nan_datapath_resp_t *resp) { NAN_DATA_LOCK(); struct ndl_info *ndl = nan_find_ndl(resp->ndp_id, NULL); + uint8_t own_bssid[6]; + ip_addr_t own_ipv6 = {0}; if (!ndl) { ESP_LOGE(TAG, "No NDL with ndp id %d", resp->ndp_id); @@ -1257,7 +1383,16 @@ esp_err_t esp_wifi_nan_datapath_resp(wifi_nan_datapath_resp_t *resp) MACADDR_COPY(resp->peer_mac, ndl->peer_nmi); } - if (esp_nan_internal_datapath_resp(resp) == ESP_OK) { + if (ndl->device_caps & NAN_CAPS_NDPE_ATTR) { + esp_err_t err = esp_wifi_get_mac(WIFI_IF_NAN, own_bssid); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Cannot get own BSSID!"); + goto fail; + } + esp_wifi_nan_get_ipv6_linklocal_from_mac(&own_ipv6.u_addr.ip6, own_bssid); + } + + if (esp_nan_internal_datapath_resp(resp, (uint8_t *)&own_ipv6.u_addr.ip6.addr[2]) == ESP_OK) { s_nan_ctx.event &= ~NDP_INDICATION; NAN_DATA_UNLOCK(); return ESP_OK; diff --git a/examples/wifi/wifi_aware/nan_console/main/nan_main.c b/examples/wifi/wifi_aware/nan_console/main/nan_main.c index 8c91fcf09d1..f487d105d17 100644 --- a/examples/wifi/wifi_aware/nan_console/main/nan_main.c +++ b/examples/wifi/wifi_aware/nan_console/main/nan_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ diff --git a/examples/wifi/wifi_aware/nan_publisher/main/publisher_main.c b/examples/wifi/wifi_aware/nan_publisher/main/publisher_main.c index 2ea6cd3cc4e..fefb6956528 100644 --- a/examples/wifi/wifi_aware/nan_publisher/main/publisher_main.c +++ b/examples/wifi/wifi_aware/nan_publisher/main/publisher_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -70,6 +70,7 @@ static void nan_ndp_indication_event_handler(void *arg, esp_event_base_t event_b esp_wifi_nan_datapath_resp(&ndp_resp); } + void wifi_nan_publish(void) { nan_event_group = xEventGroupCreate(); @@ -106,6 +107,7 @@ void wifi_nan_publish(void) /* 0 - All incoming NDP requests will be internally accepted, 1 - All incoming NDP requests raise NDP_INDICATION event and require esp_wifi_nan_datapath_resp to accept or reject. */ .ndp_resp_needed = 1, + .datapath_reqd = 1, }; pub_id = esp_wifi_nan_publish_service(&publish_cfg); diff --git a/examples/wifi/wifi_aware/nan_subscriber/main/subscriber_main.c b/examples/wifi/wifi_aware/nan_subscriber/main/subscriber_main.c index 88fbca9807d..2e72d1bcbde 100644 --- a/examples/wifi/wifi_aware/nan_subscriber/main/subscriber_main.c +++ b/examples/wifi/wifi_aware/nan_subscriber/main/subscriber_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -45,6 +45,8 @@ const int NDP_FAILED = BIT2; static wifi_event_nan_svc_match_t g_svc_match_evt; +static uint8_t s_ipv6_identifier[8] = {0}; + static void nan_receive_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { @@ -111,6 +113,7 @@ static void nan_ndp_confirmed_event_handler(void *arg, esp_event_base_t event_ba xEventGroupSetBits(nan_event_group, NDP_FAILED); } else { memcpy(g_peer_ndi, evt->peer_ndi, sizeof(g_peer_ndi)); + memcpy(s_ipv6_identifier, evt->ipv6_identifier, sizeof(evt->ipv6_identifier)); xEventGroupSetBits(nan_event_group, NDP_CONFIRMED); } } @@ -121,8 +124,7 @@ static void ping_nan_peer(esp_netif_t *netif) config.task_stack_size = 4096; ip_addr_t target_addr = {0}; - esp_wifi_nan_get_ipv6_linklocal_from_mac(&target_addr.u_addr.ip6, g_peer_ndi); - target_addr.type = IPADDR_TYPE_V6; + ESP_NAN_SET_IPV6_LINKLOCAL_FROM_IDENTIFIER(target_addr, s_ipv6_identifier); config.target_addr = target_addr; config.interface = esp_netif_get_netif_impl_index(netif); @@ -183,6 +185,7 @@ void wifi_nan_subscribe(void) esp_wifi_nan_sync_start(&nan_cfg); /* Subscribe a service */ + memset(s_ipv6_identifier, 0, sizeof(s_ipv6_identifier)); uint8_t sub_id; wifi_nan_subscribe_cfg_t subscribe_cfg = { .service_name = EXAMPLE_NAN_SERV_NAME, @@ -216,7 +219,6 @@ void wifi_nan_subscribe(void) return; } memcpy((char *)fup.ssi, EXAMPLE_NAN_SVC_MSG, fup.ssi_len); - if (esp_wifi_nan_send_message(&fup) == ESP_OK) ESP_LOGI(TAG, "Sending message '%s' to Publisher "MACSTR" ...", EXAMPLE_NAN_SVC_MSG, MAC2STR(g_svc_match_evt.pub_if_mac));