From e1791e769c17717206024f9b1f4a991c07cc7226 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 10 Feb 2024 10:58:01 +0200 Subject: [PATCH 01/24] NAN: Protocol definitions Add NAN protocol definitions that are needed for USD based on Wi-Fi Aware specification v4.0. Signed-off-by: Jouni Malinen --- .../src/common/ieee802_11_defs.h | 6 +- components/wpa_supplicant/src/common/nan.h | 98 +++++++++++++++++++ 2 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 components/wpa_supplicant/src/common/nan.h diff --git a/components/wpa_supplicant/src/common/ieee802_11_defs.h b/components/wpa_supplicant/src/common/ieee802_11_defs.h index e8adaeef0c4..86231b09a1b 100644 --- a/components/wpa_supplicant/src/common/ieee802_11_defs.h +++ b/components/wpa_supplicant/src/common/ieee802_11_defs.h @@ -567,8 +567,12 @@ struct ieee80211_ht_operation { /* 2 - Reserved */ #define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3 -#define MBO_IE_VENDOR_TYPE 0x506f9a16 #define OSEN_IE_VENDOR_TYPE 0x506f9a12 +#define NAN_IE_VENDOR_TYPE 0x506f9a13 +#define NAN_SDF_VENDOR_TYPE 0x506f9a13 +#define NAN_OUI_TYPE 0x13 +#define MBO_IE_VENDOR_TYPE 0x506f9a16 +#define NAN_NAF_VENDOR_TYPE 0x506f9a18 #define SAE_PK_IE_VENDOR_TYPE 0x506f9a1f #define SAE_PK_OUI_TYPE 0x1f #define MBO_OUI_TYPE 22 diff --git a/components/wpa_supplicant/src/common/nan.h b/components/wpa_supplicant/src/common/nan.h new file mode 100644 index 00000000000..19ab7468711 --- /dev/null +++ b/components/wpa_supplicant/src/common/nan.h @@ -0,0 +1,98 @@ +/* + * NAN (Wi-Fi Aware) definitions + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef NAN_H +#define NAN_H + +enum nan_attr_id { + NAN_ATTR_MASTER_INDICATION = 0x00, + NAN_ATTR_CLUSTER = 0x01, + NAN_ATTR_NAN_ATTR_SERVICE_ID_LIST = 0x02, + NAN_ATTR_SDA = 0x03, /* Service Descriptor attribute */ + NAN_ATTR_CONN_CAPA = 0x04, + NAN_ATTR_WLAN_INFRA = 0x05, + NAN_ATTR_P2P_OPER = 0x06, + NAN_ATTR_IBSS = 0x07, + NAN_ATTR_MESH = 0x08, + NAN_ATTR_FURTHER_NAN_SD = 0x09, + NAN_ATTR_FURTHER_AVAIL_MAP = 0x0A, + NAN_ATTR_COUNTRY_CODE = 0x0B, + NAN_ATTR_RANGIN = 0x0C, + NAN_ATTR_CLUSTER_DISCOVERY = 0x0D, + NAN_ATTR_SDEA = 0x0E, /* Service Descriptor Extension attribute */ + NAN_ATTR_DEVICE_CAPABILITY = 0x0F, + NAN_ATTR_NDP = 0x10, + NAN_ATTR_NAN_AVAILABILITY = 0x12, + NAN_ATTR_NDC = 0x13, + NAN_ATTR_NDL = 0x14, + NAN_ATTR_NDL_QOS = 0x15, + NAN_ATTR_UNALIGNED_SCHEDULE = 0x17, + NAN_ATTR_RANGING_INFO = 0x1A, + NAN_ATTR_RANGING_SETUP = 0x1B, + NAN_ATTR_FTM_RANGING_REPORT = 0x1C, + NAN_ATTR_ELEM_CONTAINER = 0x1D, + NAN_ATTR_EXT_WLAN_INFRA = 0x1E, + NAN_ATTR_EXT_P2P_OPER = 0x1FE, + NAN_ATTR_EXT_IBSS = 0x20, + NAN_ATTR_EXT_MESH = 0x21, + NAN_ATTR_CSIA = 0x22, /* Cipher Suite Info attribute */ + NAN_ATTR_SCIA = 0x23, /* Security Context Info attribute */ + NAN_ATTR_SHARED_KEY_DESCR = 0x24, + NAN_ATTR_PUBLIC_AVAILABILITY = 0x27, + NAN_ATTR_SUBSC_SERVICE_ID_LIST = 0x28, + NAN_ATTR_NDP_EXT = 0x29, + NAN_ATTR_DCEA = 0x2A, /* Device Capability Extension attribute */ + NAN_ATTR_NIRA = 0x2B, /* NAN Identity Resolution attribute */ + NAN_ATTR_BPBA = 0x2C, /* NAN Pairing Bootstrapping attribute */ + NAN_ATTR_S3 = 0x2D, + NAN_ATTR_TPEA = 0x2E, /* Transmit Power Envelope attribute */ + NAN_ATTR_VENDOR_SPECIFIC = 0xDD, +}; + +/* Service Descriptor attribute (SDA) */ + +/* Service Control field */ +#define NAN_SRV_CTRL_TYPE_MASK (BIT(0) | BIT(1)) +#define NAN_SRV_CTRL_MATCHING_FILTER BIT(2) +#define NAN_SRV_CTRL_RESP_FILTER BIT(3) +#define NAN_SRV_CTRL_SRV_INFO BIT(4) +#define NAN_SRV_CTRL_DISCOVERY_RANGE_LIMITED BIT(5) +#define NAN_SRV_CTRL_BINDING_BITMAP BIT(6) + +enum nan_service_control_type { + NAN_SRV_CTRL_PUBLISH = 0, + NAN_SRV_CTRL_SUBSCRIBE = 1, + NAN_SRV_CTRL_FOLLOW_UP = 2, +}; + +/* Service Descriptor Extension attribute (SDEA) */ + +/* SDEA Control field */ +#define NAN_SDEA_CTRL_FSD_REQ BIT(0) +#define NAN_SDEA_CTRL_FSD_GAS BIT(1) +#define NAN_SDEA_CTRL_DATA_PATH_REQ BIT(2) +#define NAN_SDEA_CTRL_DATA_PATH_TYPE BIT(3) +#define NAN_SDEA_CTRL_QOS_REQ BIT(5) +#define NAN_SDEA_CTRL_SECURITY_REQ BIT(6) +#define NAN_SDEA_CTRL_RANGING_REQ BIT(7) +#define NAN_SDEA_CTRL_RANGE_LIMIT BIT(8) +#define NAN_SDEA_CTRL_SRV_UPD_INDIC BIT(9) +#define NAN_SDEA_CTRL_GTK_REQ BIT(10) + +enum nan_service_protocol_type { + NAN_SRV_PROTO_BONJOUR = 1, + NAN_SRV_PROTO_GENERIC = 2, + NAN_SRV_PROTO_CSA_MATTER = 3, +}; + +#define NAN_ATTR_HDR_LEN 3 +#define NAN_SERVICE_ID_LEN 6 + +#define NAN_USD_DEFAULT_FREQ 2437 + +#endif /* NAN_H */ From 6a1c9a5f26ee3629cb2250754c66b85761f0b702 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 10 Feb 2024 11:57:23 +0200 Subject: [PATCH 02/24] NAN: Unsynchronized service discovery (USD) Add NAN discovery engine and wpa_supplicant interface to use it for the subset of NAN functionality that is needed for USD. Signed-off-by: Jouni Malinen --- components/wpa_supplicant/src/common/nan_de.c | 1389 +++++++++++++++++ components/wpa_supplicant/src/common/nan_de.h | 145 ++ 2 files changed, 1534 insertions(+) create mode 100644 components/wpa_supplicant/src/common/nan_de.c create mode 100644 components/wpa_supplicant/src/common/nan_de.h diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c new file mode 100644 index 00000000000..e1999a06bec --- /dev/null +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -0,0 +1,1389 @@ +/* + * NAN Discovery Engine + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "utils/eloop.h" +#include "crypto/crypto.h" +#include "crypto/sha256.h" +#include "ieee802_11_defs.h" +#include "nan.h" +#include "nan_de.h" + +static const u8 nan_network_id[ETH_ALEN] = +{ 0x51, 0x6f, 0x9a, 0x01, 0x00, 0x00 }; +static const u8 wildcard_bssid[ETH_ALEN] = +{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +enum nan_de_service_type { + NAN_DE_PUBLISH, + NAN_DE_SUBSCRIBE, +}; + +struct nan_de_service { + int id; + enum nan_de_service_type type; + char *service_name; + u8 service_id[NAN_SERVICE_ID_LEN]; + struct nan_publish_params publish; + struct nan_subscribe_params subscribe; + enum nan_service_protocol_type srv_proto_type; + struct wpabuf *ssi; + struct wpabuf *elems; + struct os_reltime time_started; + struct os_reltime end_time; + struct os_reltime last_multicast; + struct os_reltime first_discovered; + struct os_reltime last_followup; + bool needs_fsd; + unsigned int freq; + unsigned int default_freq; + int *freq_list; + + /* pauseState information for Publish function */ + struct os_reltime pause_state_end; + u8 sel_peer_id; + u8 sel_peer_addr[ETH_ALEN]; + + /* Publish state - channel iteration */ + bool in_multi_chan; + bool first_multi_chan; + int multi_chan_idx; /* index to freq_list[] */ + struct os_reltime next_publish_state; + struct os_reltime next_publish_chan; + unsigned int next_publish_duration; +}; + +struct nan_de { + u8 nmi[ETH_ALEN]; + bool ap; + struct nan_callbacks cb; + + struct nan_de_service *service[NAN_DE_MAX_SERVICE]; + unsigned int num_service; + + int next_handle; + + unsigned int ext_listen_freq; + unsigned int listen_freq; + unsigned int tx_wait_status_freq; + unsigned int tx_wait_end_freq; +}; + + +struct nan_de * nan_de_init(const u8 *nmi, bool ap, + const struct nan_callbacks *cb) +{ + struct nan_de *de; + + de = os_zalloc(sizeof(*de)); + if (!de) + return NULL; + + os_memcpy(de->nmi, nmi, ETH_ALEN); + de->ap = ap; + os_memcpy(&de->cb, cb, sizeof(*cb)); + + return de; +} + + +static void nan_de_service_free(struct nan_de_service *srv) +{ + os_free(srv->service_name); + wpabuf_free(srv->ssi); + wpabuf_free(srv->elems); + os_free(srv->freq_list); + os_free(srv); +} + + +static void nan_de_service_deinit(struct nan_de *de, struct nan_de_service *srv, + enum nan_de_reason reason) +{ + if (!srv) + return; + if (srv->type == NAN_DE_PUBLISH && de->cb.publish_terminated) + de->cb.publish_terminated(de->cb.ctx, srv->id, reason); + if (srv->type == NAN_DE_SUBSCRIBE && de->cb.subscribe_terminated) + de->cb.subscribe_terminated(de->cb.ctx, srv->id, reason); + nan_de_service_free(srv); +} + + +static void nan_de_clear_pending(struct nan_de *de) +{ + de->listen_freq = 0; + de->tx_wait_status_freq = 0; + de->tx_wait_end_freq = 0; +} + + +void nan_de_flush(struct nan_de *de) +{ + unsigned int i; + + if (!de) + return; + + for (i = 0; i < NAN_DE_MAX_SERVICE; i++) { + nan_de_service_deinit(de, de->service[i], + NAN_DE_REASON_USER_REQUEST); + de->service[i] = NULL; + } + + de->num_service = 0; + nan_de_clear_pending(de); +} + + +static void nan_de_pause_state(struct nan_de_service *srv, const u8 *peer_addr, + u8 peer_id) +{ + wpa_printf(MSG_DEBUG, "NAN: Start pauseState"); + os_get_reltime(&srv->pause_state_end); + srv->pause_state_end.sec += 60; + os_memcpy(srv->sel_peer_addr, peer_addr, ETH_ALEN); + srv->sel_peer_id = peer_id; +} + + +static void nan_de_unpause_state(struct nan_de_service *srv) +{ + wpa_printf(MSG_DEBUG, "NAN: Stop pauseState"); + srv->pause_state_end.sec = 0; + srv->pause_state_end.usec = 0; + os_memset(srv->sel_peer_addr, 0, ETH_ALEN); + srv->sel_peer_id = 0; +} + + +static struct wpabuf * nan_de_alloc_sdf(size_t len) +{ + struct wpabuf *buf; + + buf = wpabuf_alloc(2 + 4 + len); + if (buf) { + wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); + wpabuf_put_u8(buf, WLAN_PA_VENDOR_SPECIFIC); + wpabuf_put_be32(buf, NAN_SDF_VENDOR_TYPE); + } + + return buf; +} + + +static int nan_de_tx(struct nan_de *de, unsigned int freq, + unsigned int wait_time, + const u8 *dst, const u8 *src, const u8 *bssid, + const struct wpabuf *buf) +{ + int res; + + if (!de->cb.tx) + return -1; + + res = de->cb.tx(de->cb.ctx, freq, wait_time, dst, src, bssid, buf); + if (res < 0) + return res; + + de->tx_wait_status_freq = freq; + de->tx_wait_end_freq = wait_time ? freq : 0; + + return res; +} + + +static void nan_de_tx_sdf(struct nan_de *de, struct nan_de_service *srv, + unsigned int wait_time, + enum nan_service_control_type type, + const u8 *dst, u8 req_instance_id, + const struct wpabuf *ssi) +{ + struct wpabuf *buf; + size_t len = 0, sda_len, sdea_len; + u8 ctrl = type; + u16 sdea_ctrl = 0; + + /* Service Descriptor attribute */ + sda_len = NAN_SERVICE_ID_LEN + 1 + 1 + 1; + len += NAN_ATTR_HDR_LEN + sda_len; + + /* Service Descriptor Extension attribute */ + sdea_len = 1 + 2; + if (ssi) + sdea_len += 2 + 4 + wpabuf_len(ssi); + len += NAN_ATTR_HDR_LEN + sdea_len; + + /* Element Container attribute */ + if (srv->elems) + len += NAN_ATTR_HDR_LEN + 1 + wpabuf_len(srv->elems); + + buf = nan_de_alloc_sdf(len); + if (!buf) + return; + + /* Service Descriptor attribute */ + wpabuf_put_u8(buf, NAN_ATTR_SDA); + wpabuf_put_le16(buf, sda_len); + wpabuf_put_data(buf, srv->service_id, NAN_SERVICE_ID_LEN); + wpabuf_put_u8(buf, srv->id); /* Instance ID */ + wpabuf_put_u8(buf, req_instance_id); /* Requestor Instance ID */ + wpabuf_put_u8(buf, ctrl); + + /* Service Descriptor Extension attribute */ + if (srv->type == NAN_DE_PUBLISH || ssi) { + wpabuf_put_u8(buf, NAN_ATTR_SDEA); + wpabuf_put_le16(buf, sdea_len); + wpabuf_put_u8(buf, srv->id); /* Instance ID */ + if (srv->type == NAN_DE_PUBLISH) { + if (srv->publish.fsd) + sdea_ctrl |= NAN_SDEA_CTRL_FSD_REQ; + if (srv->publish.fsd_gas) + sdea_ctrl |= NAN_SDEA_CTRL_FSD_GAS; + } + wpabuf_put_le16(buf, sdea_ctrl); + if (ssi) { + wpabuf_put_le16(buf, 4 + wpabuf_len(ssi)); + wpabuf_put_be24(buf, OUI_WFA); + wpabuf_put_u8(buf, srv->srv_proto_type); + wpabuf_put_buf(buf, ssi); + } + } + + /* Element Container attribute */ + if (srv->elems) { + wpabuf_put_u8(buf, NAN_ATTR_ELEM_CONTAINER); + wpabuf_put_le16(buf, 1 + wpabuf_len(srv->elems)); + wpabuf_put_u8(buf, 0); /* Map ID */ + wpabuf_put_buf(buf, srv->elems); + } + + /* Wi-Fi Aware specification v4.0 uses NAN Cluster ID as A3 for USD, + * but there is no synchronization in USD as as such, no NAN Cluster + * either. Use Wildcard BSSID instead. */ + nan_de_tx(de, srv->freq, wait_time, dst, de->nmi, wildcard_bssid, buf); + wpabuf_free(buf); +} + + +static int nan_de_time_to_next_chan_change(struct nan_de_service *srv) +{ + struct os_reltime tmp, diff, now; + + if (os_reltime_before(&srv->next_publish_state, + &srv->next_publish_chan)) + tmp = srv->next_publish_state; + else if (srv->in_multi_chan) + tmp = srv->next_publish_chan; + else + tmp = srv->next_publish_state; + + os_get_reltime(&now); + os_reltime_sub(&tmp, &now, &diff); + return os_reltime_in_ms(&diff); +} + + +static void nan_de_set_publish_times(struct nan_de_service *srv) +{ + os_get_reltime(&srv->next_publish_state); + srv->next_publish_chan = srv->next_publish_state; + /* Swap single/multi channel state in N * 100 TU */ + os_reltime_add_ms(&srv->next_publish_state, + srv->next_publish_duration * 1024 / 1000); + + /* Swap channel in multi channel state after 150 ms */ + os_reltime_add_ms(&srv->next_publish_chan, 150); +} + + +static void nan_de_check_chan_change(struct nan_de_service *srv) +{ + if (srv->next_publish_duration) { + /* Update end times for the first operation of the publish + * iteration */ + nan_de_set_publish_times(srv); + srv->next_publish_duration = 0; + } else if (srv->in_multi_chan) { + if (!os_reltime_initialized(&srv->pause_state_end)) { + srv->multi_chan_idx++; + if (srv->freq_list[srv->multi_chan_idx] == 0) + srv->multi_chan_idx = 0; + srv->freq = srv->freq_list[srv->multi_chan_idx]; + wpa_printf(MSG_DEBUG, + "NAN: Publish multi-channel change to %u MHz", + srv->freq); + } + os_get_reltime(&srv->next_publish_chan); + os_reltime_add_ms(&srv->next_publish_chan, 150); + } +} + + +static void nan_de_tx_multicast(struct nan_de *de, struct nan_de_service *srv, + u8 req_instance_id) +{ + enum nan_service_control_type type; + unsigned int wait_time = 100; + + if (srv->type == NAN_DE_PUBLISH) { + int ms; + + type = NAN_SRV_CTRL_PUBLISH; + + nan_de_check_chan_change(srv); + ms = nan_de_time_to_next_chan_change(srv); + if (ms < 100) + ms = 100; + wait_time = ms; + } else if (srv->type == NAN_DE_SUBSCRIBE) { + type = NAN_SRV_CTRL_SUBSCRIBE; + } else { + return; + } + + nan_de_tx_sdf(de, srv, wait_time, type, nan_network_id, + req_instance_id, srv->ssi); + os_get_reltime(&srv->last_multicast); +} + + +static void nan_de_add_srv(struct nan_de *de, struct nan_de_service *srv) +{ + int ttl; + + os_get_reltime(&srv->time_started); + ttl = srv->type == NAN_DE_PUBLISH ? srv->publish.ttl : + srv->subscribe.ttl; + if (ttl) { + srv->end_time = srv->time_started; + srv->end_time.sec += ttl; + } + + de->service[srv->id - 1] = srv; + de->num_service++; +} + + +static void nan_de_del_srv(struct nan_de *de, struct nan_de_service *srv, + enum nan_de_reason reason) +{ + de->service[srv->id - 1] = NULL; + nan_de_service_deinit(de, srv, reason); + de->num_service--; + if (de->num_service == 0) + nan_de_clear_pending(de); +} + + +static bool nan_de_srv_expired(struct nan_de_service *srv, + struct os_reltime *now) +{ + if (os_reltime_initialized(&srv->end_time)) + return os_reltime_before(&srv->end_time, now); + + if (srv->type == NAN_DE_PUBLISH) { + /* Time out after one transmission (and wait for FSD) */ + if (!os_reltime_initialized(&srv->last_multicast)) + return false; + if (!srv->publish.fsd) + return true; + if (os_reltime_initialized(&srv->last_followup) && + !os_reltime_expired(now, &srv->last_followup, 1)) + return false; + if (os_reltime_expired(now, &srv->last_multicast, 1)) + return true; + } + + if (srv->type == NAN_DE_SUBSCRIBE) { + /* Time out after first DiscoveryResult event (and wait for + * FSD) */ + if (!os_reltime_initialized(&srv->first_discovered)) + return false; + if (!srv->needs_fsd) + return true; + if (os_reltime_initialized(&srv->last_followup) && + !os_reltime_expired(now, &srv->last_followup, 1)) + return false; + if (os_reltime_expired(now, &srv->first_discovered, 1)) + return true; + } + + return false; +} + + +static int nan_de_next_multicast(struct nan_de *de, struct nan_de_service *srv, + struct os_reltime *now) +{ + unsigned int period; + struct os_reltime next, diff; + + if (srv->type == NAN_DE_PUBLISH && !srv->publish.unsolicited) + return -1; + if (srv->type == NAN_DE_SUBSCRIBE && !srv->subscribe.active) + return -1; + + if (!os_reltime_initialized(&srv->last_multicast)) + return 0; + + if (srv->type == NAN_DE_PUBLISH && srv->publish.ttl == 0) + return -1; + + if (srv->type == NAN_DE_PUBLISH && + os_reltime_initialized(&srv->pause_state_end)) + return -1; + + period = srv->type == NAN_DE_PUBLISH ? + srv->publish.announcement_period : + srv->subscribe.query_period; + if (period == 0) + period = 100; + next = srv->last_multicast; + os_reltime_add_ms(&next, period); + + if (srv->type == NAN_DE_PUBLISH) { + if (!de->tx_wait_end_freq && srv->publish.unsolicited && + os_reltime_before(&next, now)) + return 0; + next = srv->next_publish_state; + } + + if (os_reltime_before(&next, now)) + return 0; + + os_reltime_sub(&next, now, &diff); + return os_reltime_in_ms(&diff); +} + + +static int nan_de_srv_time_to_next(struct nan_de *de, + struct nan_de_service *srv, + struct os_reltime *now) +{ + struct os_reltime diff; + int next = -1, tmp; + + if (os_reltime_initialized(&srv->end_time)) { + os_reltime_sub(&srv->end_time, now, &diff); + tmp = os_reltime_in_ms(&diff); + if (next == -1 || tmp < next) + next = tmp; + } + + tmp = nan_de_next_multicast(de, srv, now); + if (tmp >= 0 && (next == -1 || tmp < next)) + next = tmp; + + if (srv->type == NAN_DE_PUBLISH && + os_reltime_initialized(&srv->last_multicast)) { + /* Time out after one transmission (and wait for FSD) */ + tmp = srv->publish.fsd ? 1000 : 100; + if (next == -1 || tmp < next) + next = tmp; + } + + if (srv->type == NAN_DE_SUBSCRIBE && + os_reltime_initialized(&srv->first_discovered)) { + /* Time out after first DiscoveryResult event (and wait for + * FSD) */ + tmp = srv->needs_fsd ? 1000 : 100; + if (next == -1 || tmp < next) + next = tmp; + } + + if (os_reltime_initialized(&srv->next_publish_state)) { + os_reltime_sub(&srv->next_publish_state, now, &diff); + if (diff.sec < 0 || (diff.sec == 0 && diff.usec < 0)) + tmp = 0; + else + tmp = os_reltime_in_ms(&diff); + if (next == -1 || tmp < next) + next = tmp; + } + + return next; +} + + +static void nan_de_start_new_publish_state(struct nan_de_service *srv, + bool force_single) +{ + unsigned int n; + + if (force_single || !srv->freq_list || srv->freq_list[0] == 0) + srv->in_multi_chan = false; + else + srv->in_multi_chan = !srv->in_multi_chan; + + /* Use hardcoded Nmin=5 and Nmax=10 and pick a random N from that range. + * Use same values for M. */ + n = 5 + os_random() % 5; + srv->next_publish_duration = n * 100; + + nan_de_set_publish_times(srv); + + if (os_reltime_initialized(&srv->pause_state_end)) + return; + + if (srv->in_multi_chan && srv->freq_list && srv->freq_list[0]) { + if (!srv->first_multi_chan) + srv->multi_chan_idx++; + if (srv->freq_list[srv->multi_chan_idx] == 0) + srv->multi_chan_idx = 0; + srv->first_multi_chan = false; + srv->freq = srv->freq_list[srv->multi_chan_idx]; + } else { + srv->freq = srv->default_freq; + } + + wpa_printf(MSG_DEBUG, + "NAN: Publish in %s channel state for %u TU; starting with %u MHz", + srv->in_multi_chan ? "multi" : "single", n * 100, srv->freq); +} + + +static void nan_de_timer(void *eloop_ctx, void *timeout_ctx) +{ + struct nan_de *de = eloop_ctx; + unsigned int i; + int next = -1; + bool started = false; + struct os_reltime now; + + os_get_reltime(&now); + + for (i = 0; i < NAN_DE_MAX_SERVICE; i++) { + struct nan_de_service *srv = de->service[i]; + int srv_next; + + if (!srv) + continue; + + if (nan_de_srv_expired(srv, &now)) { + wpa_printf(MSG_DEBUG, "NAN: Service id %d expired", + srv->id); + nan_de_del_srv(de, srv, NAN_DE_REASON_TIMEOUT); + continue; + } + + if (os_reltime_initialized(&srv->next_publish_state) && + os_reltime_before(&srv->next_publish_state, &now)) + nan_de_start_new_publish_state(srv, false); + + if (srv->type == NAN_DE_PUBLISH && + os_reltime_initialized(&srv->pause_state_end) && + (os_reltime_before(&srv->pause_state_end, &now) || + (srv->publish.fsd && + os_reltime_initialized(&srv->last_followup) && + os_reltime_expired(&now, &srv->last_followup, 1)))) + nan_de_unpause_state(srv); + + srv_next = nan_de_srv_time_to_next(de, srv, &now); + if (srv_next >= 0 && (next == -1 || srv_next < next)) + next = srv_next; + + if (srv_next == 0 && !started && + de->listen_freq == 0 && de->ext_listen_freq == 0 && + de->tx_wait_end_freq == 0 && + nan_de_next_multicast(de, srv, &now) == 0) { + started = true; + nan_de_tx_multicast(de, srv, 0); + } + + if (!started && de->cb.listen && + de->listen_freq == 0 && de->ext_listen_freq == 0 && + de->tx_wait_end_freq == 0 && + ((srv->type == NAN_DE_PUBLISH && + !srv->publish.unsolicited && srv->publish.solicited) || + (srv->type == NAN_DE_SUBSCRIBE && + !srv->subscribe.active))) { + int duration = 1000; + + if (srv->type == NAN_DE_PUBLISH) { + nan_de_check_chan_change(srv); + duration = nan_de_time_to_next_chan_change(srv); + if (duration < 150) + duration = 150; + } + + started = true; + if (de->cb.listen(de->cb.ctx, srv->freq, duration) == 0) + de->listen_freq = srv->freq; + } + + } + + if (next < 0) + return; + + if (next == 0) + next = 1; + wpa_printf(MSG_DEBUG, "NAN: Next timer in %u ms", next); + eloop_register_timeout(next / 1000, (next % 1000) * 1000, nan_de_timer, + de, NULL); +} + + +static void nan_de_run_timer(struct nan_de *de) +{ + eloop_cancel_timeout(nan_de_timer, de, NULL); + eloop_register_timeout(0, 0, nan_de_timer, de, NULL); +} + + +void nan_de_deinit(struct nan_de *de) +{ + eloop_cancel_timeout(nan_de_timer, de, NULL); + nan_de_flush(de); + os_free(de); +} + + +void nan_de_listen_started(struct nan_de *de, unsigned int freq, + unsigned int duration) +{ + if (freq != de->listen_freq) + de->ext_listen_freq = freq; +} + + +void nan_de_listen_ended(struct nan_de *de, unsigned int freq) +{ + if (freq == de->ext_listen_freq) + de->ext_listen_freq = 0; + + if (freq == de->listen_freq) { + de->listen_freq = 0; + nan_de_run_timer(de); + } +} + + +void nan_de_tx_status(struct nan_de *de, unsigned int freq, const u8 *dst) +{ + if (freq == de->tx_wait_status_freq) + de->tx_wait_status_freq = 0; +} + + +void nan_de_tx_wait_ended(struct nan_de *de) +{ + de->tx_wait_end_freq = 0; + nan_de_run_timer(de); +} + + +static const u8 * +nan_de_get_attr(const u8 *buf, size_t len, enum nan_attr_id id, + unsigned int skip) +{ + const u8 *pos = buf, *end = buf + len; + + while (end - pos >= NAN_ATTR_HDR_LEN) { + const u8 *attr = pos; + u8 attr_id; + u16 attr_len; + + attr_id = *pos++; + attr_len = WPA_GET_LE16(pos); + pos += 2; + if (attr_len > end - pos) { + wpa_printf(MSG_DEBUG, + "NAN: Truncated attribute %u (len %u; left %zu)", + attr_id, attr_len, end - pos); + break; + } + + if (attr_id == id) { + if (skip == 0) + return attr; + skip--; + } + + pos += attr_len; + } + + return NULL; +} + + +static void nan_de_get_sdea(const u8 *buf, size_t len, u8 instance_id, + u16 *sdea_control, + enum nan_service_protocol_type *srv_proto_type, + const u8 **ssi, size_t *ssi_len) +{ + unsigned int skip; + const u8 *sdea, *end; + u16 sdea_len; + + for (skip = 0; ; skip++) { + sdea = nan_de_get_attr(buf, len, NAN_ATTR_SDEA, skip); + if (!sdea) + break; + + sdea++; + sdea_len = WPA_GET_LE16(sdea); + sdea += 2; + if (sdea_len < 1 + 2) + continue; + end = sdea + sdea_len; + + if (instance_id != *sdea++) + continue; /* Mismatching Instance ID */ + + *sdea_control = WPA_GET_LE16(sdea); + sdea += 2; + + if (*sdea_control & NAN_SDEA_CTRL_RANGE_LIMIT) { + if (end - sdea < 4) + continue; + sdea += 4; + } + + if (*sdea_control & NAN_SDEA_CTRL_SRV_UPD_INDIC) { + if (end - sdea < 1) + continue; + sdea++; + } + + if (end - sdea >= 2) { + u16 srv_info_len; + + srv_info_len = WPA_GET_LE16(sdea); + sdea += 2; + + if (srv_info_len > end - sdea) + continue; + + if (srv_info_len >= 4 && + WPA_GET_BE24(sdea) == OUI_WFA) { + *srv_proto_type = sdea[3]; + *ssi = sdea + 4; + *ssi_len = srv_info_len - 4; + } + } + } +} + + +static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv, + const u8 *peer_addr, u8 instance_id, + u8 req_instance_id, u16 sdea_control, + enum nan_service_protocol_type srv_proto_type, + const u8 *ssi, size_t ssi_len) +{ + /* Subscribe function processing of a receive Publish message */ + if (!os_reltime_initialized(&srv->first_discovered)) { + os_get_reltime(&srv->first_discovered); + srv->needs_fsd = sdea_control & NAN_SDEA_CTRL_FSD_REQ; + nan_de_run_timer(de); + } + + if (srv->subscribe.active && req_instance_id == 0) { + /* Active subscriber replies with a Subscribe message if it + * received a matching unsolicited Publish message. */ + nan_de_tx_multicast(de, srv, instance_id); + } + + if (!srv->subscribe.active && req_instance_id == 0) { + /* Passive subscriber replies with a Follow-up message without + * Service Specific Info field if it received a matching + * unsolicited Publish message. */ + nan_de_transmit(de, srv->id, NULL, NULL, peer_addr, + instance_id); + } + + if (de->cb.discovery_result) + de->cb.discovery_result( + de->cb.ctx, srv->id, srv_proto_type, + ssi, ssi_len, instance_id, + peer_addr, + sdea_control & NAN_SDEA_CTRL_FSD_REQ, + sdea_control & NAN_SDEA_CTRL_FSD_GAS); +} + + +static bool nan_de_filter_match(struct nan_de_service *srv, + const u8 *matching_filter, + size_t matching_filter_len) +{ + const u8 *pos, *end; + + /* Since we do not currently support matching_filter_rx values for the + * local Publish function, any matching filter with at least one + * pair with length larger than zero implies a mismatch. + */ + + if (!matching_filter) + return true; + + pos = matching_filter; + end = matching_filter + matching_filter_len; + + while (pos < end) { + u8 len; + + len = *pos++; + if (len > end - pos) + break; + if (len) { + /* A non-empty Matching Filter entry: no match since + * there is no local matching_filter_rx. */ + return false; + } + } + + return true; +} + + +static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv, + const u8 *peer_addr, u8 instance_id, + const u8 *matching_filter, + size_t matching_filter_len, + enum nan_service_protocol_type srv_proto_type, + const u8 *ssi, size_t ssi_len) +{ + struct wpabuf *buf; + size_t len = 0, sda_len, sdea_len; + u8 ctrl = 0; + u16 sdea_ctrl = 0; + + /* Publish function processing of a receive Subscribe message */ + + if (!nan_de_filter_match(srv, matching_filter, matching_filter_len)) + return; + + if (!srv->publish.solicited) + return; + + if (os_reltime_initialized(&srv->pause_state_end) && + (!ether_addr_equal(peer_addr, srv->sel_peer_addr) || + instance_id != srv->sel_peer_id)) { + wpa_printf(MSG_DEBUG, + "NAN: In pauseState - ignore Subscribe message from another subscriber"); + return; + } + + /* Reply with a solicited Publish message */ + /* Service Descriptor attribute */ + sda_len = NAN_SERVICE_ID_LEN + 1 + 1 + 1; + len += NAN_ATTR_HDR_LEN + sda_len; + + /* Service Descriptor Extension attribute */ + sdea_len = 1 + 2; + if (srv->ssi) + sdea_len += 2 + 4 + wpabuf_len(srv->ssi); + len += NAN_ATTR_HDR_LEN + sdea_len; + + /* Element Container attribute */ + if (srv->elems) + len += NAN_ATTR_HDR_LEN + 1 + wpabuf_len(srv->elems); + + buf = nan_de_alloc_sdf(len); + if (!buf) + return; + + /* Service Descriptor attribute */ + wpabuf_put_u8(buf, NAN_ATTR_SDA); + wpabuf_put_le16(buf, sda_len); + wpabuf_put_data(buf, srv->service_id, NAN_SERVICE_ID_LEN); + wpabuf_put_u8(buf, srv->id); /* Instance ID */ + wpabuf_put_u8(buf, instance_id); /* Requestor Instance ID */ + ctrl |= NAN_SRV_CTRL_PUBLISH; + wpabuf_put_u8(buf, ctrl); + + /* Service Descriptor Extension attribute */ + if (srv->type == NAN_DE_PUBLISH || srv->ssi) { + wpabuf_put_u8(buf, NAN_ATTR_SDEA); + wpabuf_put_le16(buf, sdea_len); + wpabuf_put_u8(buf, srv->id); /* Instance ID */ + if (srv->type == NAN_DE_PUBLISH) { + if (srv->publish.fsd) + sdea_ctrl |= NAN_SDEA_CTRL_FSD_REQ; + if (srv->publish.fsd_gas) + sdea_ctrl |= NAN_SDEA_CTRL_FSD_GAS; + } + wpabuf_put_le16(buf, sdea_ctrl); + if (srv->ssi) { + wpabuf_put_le16(buf, 4 + wpabuf_len(srv->ssi)); + wpabuf_put_be24(buf, OUI_WFA); + wpabuf_put_u8(buf, srv->srv_proto_type); + wpabuf_put_buf(buf, srv->ssi); + } + } + + /* Element Container attribute */ + if (srv->elems) { + wpabuf_put_u8(buf, NAN_ATTR_ELEM_CONTAINER); + wpabuf_put_le16(buf, 1 + wpabuf_len(srv->elems)); + wpabuf_put_u8(buf, 0); /* Map ID */ + wpabuf_put_buf(buf, srv->elems); + } + + /* Wi-Fi Aware specification v4.0 uses NAN Cluster ID as A3 for USD, + * but there is no synchronization in USD as as such, no NAN Cluster + * either. Use Wildcard BSSID instead. */ + nan_de_tx(de, srv->freq, 100, + srv->publish.solicited_multicast ? nan_network_id : peer_addr, + de->nmi, wildcard_bssid, buf); + wpabuf_free(buf); + + nan_de_pause_state(srv, peer_addr, instance_id); + + if (!srv->publish.disable_events && de->cb.replied) + de->cb.replied(de->cb.ctx, srv->id, peer_addr, instance_id, + srv_proto_type, ssi, ssi_len); +} + + +static void nan_de_rx_follow_up(struct nan_de *de, struct nan_de_service *srv, + const u8 *peer_addr, u8 instance_id, + const u8 *ssi, size_t ssi_len) +{ + /* Follow-up function processing of a receive Follow-up message for a + * Subscribe or Publish instance */ + + if (srv->type == NAN_DE_PUBLISH && + os_reltime_initialized(&srv->pause_state_end) && + (!ether_addr_equal(peer_addr, srv->sel_peer_addr) || + instance_id != srv->sel_peer_id || + !ssi)) { + wpa_printf(MSG_DEBUG, + "NAN: In pauseState - ignore Follow-up message from another subscriber or without ssi"); + return; + } + + os_get_reltime(&srv->last_followup); + + if (srv->type == NAN_DE_PUBLISH && !ssi) + nan_de_pause_state(srv, peer_addr, instance_id); + + if (de->cb.receive) + de->cb.receive(de->cb.ctx, srv->id, instance_id, ssi, ssi_len, + peer_addr); +} + + +static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr, + unsigned int freq, const u8 *buf, size_t len, + const u8 *sda, size_t sda_len) +{ + const u8 *service_id; + u8 instance_id, req_instance_id, ctrl; + u16 sdea_control = 0; + unsigned int i; + enum nan_service_control_type type = 0; + enum nan_service_protocol_type srv_proto_type = 0; + const u8 *ssi = NULL; + size_t ssi_len = 0; + bool first = true; + const u8 *end; + const u8 *matching_filter = NULL; + size_t matching_filter_len = 0; + + if (sda_len < NAN_SERVICE_ID_LEN + 1 + 1 + 1) + return; + end = sda + sda_len; + + service_id = sda; + sda += NAN_SERVICE_ID_LEN; + instance_id = *sda++; + req_instance_id = *sda++; + ctrl = *sda; + type = ctrl & NAN_SRV_CTRL_TYPE_MASK; + wpa_printf(MSG_DEBUG, + "NAN: SDA - Service ID %02x%02x%02x%02x%02x%02x Instance ID %u Requestor Instance ID %u Service Control 0x%x (Service Control Type %u)", + MAC2STR(service_id), instance_id, req_instance_id, + ctrl, type); + if (type != NAN_SRV_CTRL_PUBLISH && + type != NAN_SRV_CTRL_SUBSCRIBE && + type != NAN_SRV_CTRL_FOLLOW_UP) { + wpa_printf(MSG_DEBUG, + "NAN: Discard SDF with unknown Service Control Type %u", + type); + return; + } + + if (ctrl & NAN_SRV_CTRL_BINDING_BITMAP) { + if (end - sda < 2) + return; + sda += 2; + } + + if (ctrl & NAN_SRV_CTRL_MATCHING_FILTER) { + u8 flen; + + if (end - sda < 1) + return; + flen = *sda++; + if (end - sda < flen) + return; + matching_filter = sda; + matching_filter_len = flen; + sda += flen; + } + + if (ctrl & NAN_SRV_CTRL_RESP_FILTER) { + u8 flen; + + if (end - sda < 1) + return; + flen = *sda++; + if (end - sda < flen) + return; + sda += flen; + } + + if (ctrl & NAN_SRV_CTRL_SRV_INFO) { + u8 flen; + + if (end - sda < 1) + return; + flen = *sda++; + if (end - sda < flen) + return; + if (flen >= 4 && WPA_GET_BE24(sda) == OUI_WFA) { + srv_proto_type = sda[3]; + ssi = sda + 4; + ssi_len = flen - 4; + wpa_printf(MSG_DEBUG, "NAN: Service Protocol Type %d", + srv_proto_type); + wpa_hexdump(MSG_MSGDUMP, "NAN: ssi", ssi, ssi_len); + } + sda += flen; + } + + for (i = 0; i < NAN_DE_MAX_SERVICE; i++) { + struct nan_de_service *srv = de->service[i]; + + if (!srv) + continue; + if (os_memcmp(srv->service_id, service_id, + NAN_SERVICE_ID_LEN) != 0) + continue; + if (type == NAN_SRV_CTRL_PUBLISH) { + if (srv->type == NAN_DE_PUBLISH) + continue; + if (req_instance_id && srv->id != req_instance_id) + continue; + } + if (type == NAN_SRV_CTRL_SUBSCRIBE && + srv->type == NAN_DE_SUBSCRIBE) + continue; + wpa_printf(MSG_DEBUG, "NAN: Received SDF matches service ID %u", + i + 1); + + if (first) { + first = false; + nan_de_get_sdea(buf, len, instance_id, &sdea_control, + &srv_proto_type, &ssi, &ssi_len); + + if (ssi) { + wpa_printf(MSG_DEBUG, + "NAN: Service Protocol Type %d", + srv_proto_type); + wpa_hexdump(MSG_MSGDUMP, "NAN: ssi", + ssi, ssi_len); + } + } + + switch (type) { + case NAN_SRV_CTRL_PUBLISH: + nan_de_rx_publish(de, srv, peer_addr, instance_id, + req_instance_id, + sdea_control, srv_proto_type, + ssi, ssi_len); + break; + case NAN_SRV_CTRL_SUBSCRIBE: + nan_de_rx_subscribe(de, srv, peer_addr, instance_id, + matching_filter, + matching_filter_len, + srv_proto_type, + ssi, ssi_len); + break; + case NAN_SRV_CTRL_FOLLOW_UP: + nan_de_rx_follow_up(de, srv, peer_addr, instance_id, + ssi, ssi_len); + break; + } + } +} + + +void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, unsigned int freq, + const u8 *buf, size_t len) +{ + const u8 *sda; + u16 sda_len; + unsigned int skip; + + if (!de->num_service) + return; + + wpa_printf(MSG_DEBUG, "NAN: RX SDF from " MACSTR " freq=%u len=%zu", + MAC2STR(peer_addr), freq, len); + + wpa_hexdump(MSG_MSGDUMP, "NAN: SDF payload", buf, len); + + for (skip = 0; ; skip++) { + sda = nan_de_get_attr(buf, len, NAN_ATTR_SDA, skip); + if (!sda) + break; + + sda++; + sda_len = WPA_GET_LE16(sda); + sda += 2; + nan_de_rx_sda(de, peer_addr, freq, buf, len, sda, sda_len); + } +} + + +static int nan_de_get_handle(struct nan_de *de) +{ + int i = de->next_handle; + + if (de->num_service >= NAN_DE_MAX_SERVICE) + goto fail; + + do { + if (!de->service[i]) { + de->next_handle = (i + 1) % NAN_DE_MAX_SERVICE; + return i + 1; + } + i = (i + 1) % NAN_DE_MAX_SERVICE; + } while (i != de->next_handle); + +fail: + wpa_printf(MSG_DEBUG, "NAN: No more room for a new service"); + return -1; +} + + +static int nan_de_derive_service_id(struct nan_de_service *srv) +{ + u8 hash[SHA256_MAC_LEN]; + char *name, *pos; + int ret; + const u8 *addr[1]; + size_t len[1]; + + name = os_strdup(srv->service_name); + if (!name) + return -1; + pos = name; + while (*pos) { + *pos = tolower(*pos); + pos++; + } + + addr[0] = (u8 *) name; + len[0] = os_strlen(name); + ret = sha256_vector(1, addr, len, hash); + os_free(name); + if (ret == 0) + os_memcpy(srv->service_id, hash, NAN_SERVICE_ID_LEN); + + return ret; +} + + +int nan_de_publish(struct nan_de *de, const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, const struct wpabuf *elems, + struct nan_publish_params *params) +{ + int publish_id; + struct nan_de_service *srv; + + if (!service_name) { + wpa_printf(MSG_DEBUG, "NAN: Publish() - no service_name"); + return -1; + } + + publish_id = nan_de_get_handle(de); + if (publish_id < 1) + return -1; + + srv = os_zalloc(sizeof(*srv)); + if (!srv) + return -1; + srv->type = NAN_DE_PUBLISH; + srv->freq = srv->default_freq = params->freq; + srv->service_name = os_strdup(service_name); + if (!srv->service_name) + goto fail; + if (nan_de_derive_service_id(srv) < 0) + goto fail; + os_memcpy(&srv->publish, params, sizeof(*params)); + + if (params->freq_list) { + size_t len; + + len = (int_array_len(params->freq_list) + 1) * sizeof(int); + srv->freq_list = os_memdup(params->freq_list, len); + if (!srv->freq_list) + goto fail; + } + srv->publish.freq_list = NULL; + + srv->srv_proto_type = srv_proto_type; + if (ssi) { + srv->ssi = wpabuf_dup(ssi); + if (!srv->ssi) + goto fail; + } + if (elems) { + srv->elems = wpabuf_dup(elems); + if (!srv->elems) + goto fail; + } + + /* Prepare for single and multi-channel states; starting with + * single channel */ + srv->first_multi_chan = true; + nan_de_start_new_publish_state(srv, true); + + wpa_printf(MSG_DEBUG, "NAN: Assigned new publish handle %d for %s", + publish_id, service_name); + srv->id = publish_id; + nan_de_add_srv(de, srv); + nan_de_run_timer(de); + return publish_id; +fail: + nan_de_service_free(srv); + return -1; +} + + +void nan_de_cancel_publish(struct nan_de *de, int publish_id) +{ + struct nan_de_service *srv; + + wpa_printf(MSG_DEBUG, "NAN: CancelPublish(publish_id=%d)", publish_id); + + if (publish_id < 1 || publish_id > NAN_DE_MAX_SERVICE) + return; + srv = de->service[publish_id - 1]; + if (!srv || srv->type != NAN_DE_PUBLISH) + return; + nan_de_del_srv(de, srv, NAN_DE_REASON_USER_REQUEST); +} + + +int nan_de_update_publish(struct nan_de *de, int publish_id, + const struct wpabuf *ssi) +{ + struct nan_de_service *srv; + + wpa_printf(MSG_DEBUG, "NAN: UpdatePublish(publish_id=%d)", publish_id); + + if (publish_id < 1 || publish_id > NAN_DE_MAX_SERVICE) + return -1; + srv = de->service[publish_id - 1]; + if (!srv || srv->type != NAN_DE_PUBLISH) + return -1; + + wpabuf_free(srv->ssi); + srv->ssi = NULL; + if (!ssi) + return 0; + srv->ssi = wpabuf_dup(ssi); + if (!srv->ssi) + return -1; + return 0; +} + + +int nan_de_subscribe(struct nan_de *de, const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, const struct wpabuf *elems, + struct nan_subscribe_params *params) +{ + int subscribe_id; + struct nan_de_service *srv; + + if (!service_name) { + wpa_printf(MSG_DEBUG, "NAN: Subscribe() - no service_name"); + return -1; + } + + subscribe_id = nan_de_get_handle(de); + if (subscribe_id < 1) + return -1; + + srv = os_zalloc(sizeof(*srv)); + if (!srv) + return -1; + srv->type = NAN_DE_SUBSCRIBE; + srv->freq = params->freq; + srv->service_name = os_strdup(service_name); + if (!srv->service_name) + goto fail; + if (nan_de_derive_service_id(srv) < 0) + goto fail; + os_memcpy(&srv->subscribe, params, sizeof(*params)); + srv->srv_proto_type = srv_proto_type; + if (ssi) { + srv->ssi = wpabuf_dup(ssi); + if (!srv->ssi) + goto fail; + } + if (elems) { + srv->elems = wpabuf_dup(elems); + if (!srv->elems) + goto fail; + } + + wpa_printf(MSG_DEBUG, "NAN: Assigned new subscribe handle %d for %s", + subscribe_id, service_name); + srv->id = subscribe_id; + nan_de_add_srv(de, srv); + nan_de_run_timer(de); + return subscribe_id; +fail: + nan_de_service_free(srv); + return -1; +} + + +void nan_de_cancel_subscribe(struct nan_de *de, int subscribe_id) +{ + struct nan_de_service *srv; + + if (subscribe_id < 1 || subscribe_id > NAN_DE_MAX_SERVICE) + return; + srv = de->service[subscribe_id - 1]; + if (!srv || srv->type != NAN_DE_SUBSCRIBE) + return; + nan_de_del_srv(de, srv, NAN_DE_REASON_USER_REQUEST); +} + + +int nan_de_transmit(struct nan_de *de, int handle, + const struct wpabuf *ssi, const struct wpabuf *elems, + const u8 *peer_addr, u8 req_instance_id) +{ + struct nan_de_service *srv; + + if (handle < 1 || handle > NAN_DE_MAX_SERVICE) + return -1; + + srv = de->service[handle - 1]; + if (!srv) + return -1; + + nan_de_tx_sdf(de, srv, 100, NAN_SRV_CTRL_FOLLOW_UP, + peer_addr, req_instance_id, ssi); + + os_get_reltime(&srv->last_followup); + return 0; +} diff --git a/components/wpa_supplicant/src/common/nan_de.h b/components/wpa_supplicant/src/common/nan_de.h new file mode 100644 index 00000000000..62235064b07 --- /dev/null +++ b/components/wpa_supplicant/src/common/nan_de.h @@ -0,0 +1,145 @@ +/* + * NAN Discovery Engine + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef NAN_DE_H +#define NAN_DE_H + +#include "nan.h" + +/* Maximum number of active local publish and subscribe instances */ +#ifndef NAN_DE_MAX_SERVICE +#define NAN_DE_MAX_SERVICE 20 +#endif /* NAN_DE_MAX_SERVICE */ + +struct nan_de; + +enum nan_de_reason { + NAN_DE_REASON_TIMEOUT, + NAN_DE_REASON_USER_REQUEST, + NAN_DE_REASON_FAILURE, +}; + +struct nan_callbacks { + void *ctx; + + int (*tx)(void *ctx, unsigned int freq, unsigned int wait_time, + const u8 *dst, const u8 *src, const u8 *bssid, + const struct wpabuf *buf); + int (*listen)(void *ctx, unsigned int freq, unsigned int duration); + + /* NAN DE Events */ + void (*discovery_result)(void *ctx, int subscribe_id, + enum nan_service_protocol_type srv_proto_type, + const u8 *ssi, size_t ssi_len, + int peer_publish_id, + const u8 *peer_addr, bool fsd, bool fsd_gas); + + void (*replied)(void *ctx, int publish_id, const u8 *peer_addr, + int peer_subscribe_id, + enum nan_service_protocol_type srv_proto_type, + const u8 *ssi, size_t ssi_len); + + void (*publish_terminated)(void *ctx, int publish_id, + enum nan_de_reason reason); + + void (*subscribe_terminated)(void *ctx, int subscribe_id, + enum nan_de_reason reason); + + void (*receive)(void *ctx, int id, int peer_instance_id, + const u8 *ssi, size_t ssi_len, + const u8 *peer_addr); +}; + +struct nan_de * nan_de_init(const u8 *nmi, bool ap, + const struct nan_callbacks *cb); +void nan_de_flush(struct nan_de *de); +void nan_de_deinit(struct nan_de *de); + +void nan_de_listen_started(struct nan_de *de, unsigned int freq, + unsigned int duration); +void nan_de_listen_ended(struct nan_de *de, unsigned int freq); +void nan_de_tx_status(struct nan_de *de, unsigned int freq, const u8 *dst); +void nan_de_tx_wait_ended(struct nan_de *de); + +void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, unsigned int freq, + const u8 *buf, size_t len); + +struct nan_publish_params { + /* configuration_parameters */ + + /* Publish type */ + bool unsolicited; + bool solicited; + + /* Solicited transmission type */ + bool solicited_multicast; + + /* Time to live (in seconds); 0 = one TX only */ + unsigned int ttl; + + /* Event conditions */ + bool disable_events; + + /* Further Service Discovery flag */ + bool fsd; + + /* Further Service Discovery function */ + bool fsd_gas; + + /* Default frequency (defaultPublishChannel) */ + unsigned int freq; + + /* Multi-channel frequencies (publishChannelList) */ + const int *freq_list; + + /* Announcement period in ms; 0 = use default */ + unsigned int announcement_period; +}; + +/* Returns -1 on failure or >0 publish_id */ +int nan_de_publish(struct nan_de *de, const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, const struct wpabuf *elems, + struct nan_publish_params *params); + +void nan_de_cancel_publish(struct nan_de *de, int publish_id); + +int nan_de_update_publish(struct nan_de *de, int publish_id, + const struct wpabuf *ssi); + +struct nan_subscribe_params { + /* configuration_parameters */ + + /* Subscribe type */ + bool active; + + /* Time to live (in seconds); 0 = until first result */ + unsigned int ttl; + + /* Selected frequency */ + unsigned int freq; + + /* Query period in ms; 0 = use default */ + unsigned int query_period; +}; + +/* Returns -1 on failure or >0 subscribe_id */ +int nan_de_subscribe(struct nan_de *de, const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, const struct wpabuf *elems, + struct nan_subscribe_params *params); + +void nan_de_cancel_subscribe(struct nan_de *de, int subscribe_id); + +/* handle = publish_id or subscribe_id + * req_instance_id = peer publish_id or subscribe_id */ +int nan_de_transmit(struct nan_de *de, int handle, + const struct wpabuf *ssi, const struct wpabuf *elems, + const u8 *peer_addr, u8 req_instance_id); + +#endif /* NAN_DE_H */ From 35e508258dd2788d3474b23221edbf02d3d7ecd9 Mon Sep 17 00:00:00 2001 From: Chien Wong Date: Sat, 27 Apr 2024 16:19:44 +0800 Subject: [PATCH 03/24] NAN: Reject undefined publish type The Wi-Fi Aware Specification v4.0 only defines unsolicited transmissions only, solicited transmissions only and both unsolicited and solicited transmissions publish. The other possibility is undefined so we should reject it. Signed-off-by: Chien Wong --- components/wpa_supplicant/src/common/nan_de.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index e1999a06bec..12fad3112bd 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -1209,6 +1209,12 @@ int nan_de_publish(struct nan_de *de, const char *service_name, return -1; } + if (!params->unsolicited && !params->solicited) { + wpa_printf(MSG_INFO, + "NAN: Publish() - both unsolicited and solicited disabled is invalid"); + return -1; + } + publish_id = nan_de_get_handle(de); if (publish_id < 1) return -1; From 8173b5cc87358c9bd61144283e462a59a3ee1a1b Mon Sep 17 00:00:00 2001 From: Shivani Baranwal Date: Mon, 5 Aug 2024 15:02:59 +0530 Subject: [PATCH 04/24] NAN: Option to offload NAN DE for USD into the driver Support implementation architecture where the NAN discovery engine is located in the driver/firmware instead of wpa_supplicant. Signed-off-by: Shivani Baranwal --- components/wpa_supplicant/src/common/nan_de.c | 29 +++++++++++++++---- components/wpa_supplicant/src/common/nan_de.h | 3 +- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index 12fad3112bd..08351ce90d3 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -62,6 +62,7 @@ struct nan_de_service { struct nan_de { u8 nmi[ETH_ALEN]; + bool offload; bool ap; struct nan_callbacks cb; @@ -77,7 +78,7 @@ struct nan_de { }; -struct nan_de * nan_de_init(const u8 *nmi, bool ap, +struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap, const struct nan_callbacks *cb) { struct nan_de *de; @@ -87,6 +88,7 @@ struct nan_de * nan_de_init(const u8 *nmi, bool ap, return NULL; os_memcpy(de->nmi, nmi, ETH_ALEN); + de->offload = offload; de->ap = ap; os_memcpy(&de->cb, cb, sizeof(*cb)); @@ -590,7 +592,7 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx) if (srv_next >= 0 && (next == -1 || srv_next < next)) next = srv_next; - if (srv_next == 0 && !started && + if (srv_next == 0 && !started && !de->offload && de->listen_freq == 0 && de->ext_listen_freq == 0 && de->tx_wait_end_freq == 0 && nan_de_next_multicast(de, srv, &now) == 0) { @@ -598,7 +600,7 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx) nan_de_tx_multicast(de, srv, 0); } - if (!started && de->cb.listen && + if (!started && !de->offload && de->cb.listen && de->listen_freq == 0 && de->ext_listen_freq == 0 && de->tx_wait_end_freq == 0 && ((srv->type == NAN_DE_PUBLISH && @@ -787,13 +789,13 @@ static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv, nan_de_run_timer(de); } - if (srv->subscribe.active && req_instance_id == 0) { + if (!de->offload && srv->subscribe.active && req_instance_id == 0) { /* Active subscriber replies with a Subscribe message if it * received a matching unsolicited Publish message. */ nan_de_tx_multicast(de, srv, instance_id); } - if (!srv->subscribe.active && req_instance_id == 0) { + if (!de->offload && !srv->subscribe.active && req_instance_id == 0) { /* Passive subscriber replies with a Follow-up message without * Service Specific Info field if it received a matching * unsolicited Publish message. */ @@ -873,6 +875,9 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv, return; } + if (de->offload) + goto offload; + /* Reply with a solicited Publish message */ /* Service Descriptor attribute */ sda_len = NAN_SERVICE_ID_LEN + 1 + 1 + 1; @@ -939,6 +944,7 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv, nan_de_pause_state(srv, peer_addr, instance_id); +offload: if (!srv->publish.disable_events && de->cb.replied) de->cb.replied(de->cb.ctx, srv->id, peer_addr, instance_id, srv_proto_type, ssi, ssi_len); @@ -1196,6 +1202,19 @@ static int nan_de_derive_service_id(struct nan_de_service *srv) } +const u8 * nan_de_get_service_id(struct nan_de *de, int id) +{ + struct nan_de_service *srv; + + if (id < 1 || id > NAN_DE_MAX_SERVICE) + return NULL; + srv = de->service[id - 1]; + if (!srv) + return NULL; + return srv->service_id; +} + + int nan_de_publish(struct nan_de *de, const char *service_name, enum nan_service_protocol_type srv_proto_type, const struct wpabuf *ssi, const struct wpabuf *elems, diff --git a/components/wpa_supplicant/src/common/nan_de.h b/components/wpa_supplicant/src/common/nan_de.h index 62235064b07..ae77cf399db 100644 --- a/components/wpa_supplicant/src/common/nan_de.h +++ b/components/wpa_supplicant/src/common/nan_de.h @@ -55,7 +55,7 @@ struct nan_callbacks { const u8 *peer_addr); }; -struct nan_de * nan_de_init(const u8 *nmi, bool ap, +struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap, const struct nan_callbacks *cb); void nan_de_flush(struct nan_de *de); void nan_de_deinit(struct nan_de *de); @@ -68,6 +68,7 @@ void nan_de_tx_wait_ended(struct nan_de *de); void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, unsigned int freq, const u8 *buf, size_t len); +const u8 * nan_de_get_service_id(struct nan_de *de, int id); struct nan_publish_params { /* configuration_parameters */ From 59dfc2ec32a7aad2ebeb4fceeba6bd8237793fba Mon Sep 17 00:00:00 2001 From: Shivani Baranwal Date: Mon, 5 Aug 2024 15:03:00 +0530 Subject: [PATCH 05/24] P2P2: Allow P2P IE to be added into NAN SDFs Extend the NAN Subscribe and Publish methods to allow p2p=1 to be specified to include P2P attributes in a P2P IE to be added into the NAN Element Container attribute. In addition, use the P2P Device Address for the NAN SDFs for the P2P cases. Signed-off-by: Shivani Baranwal --- components/wpa_supplicant/src/common/nan_de.c | 7 +++++-- components/wpa_supplicant/src/common/nan_de.h | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index 08351ce90d3..c7294c59d5d 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -58,6 +58,7 @@ struct nan_de_service { struct os_reltime next_publish_state; struct os_reltime next_publish_chan; unsigned int next_publish_duration; + bool is_p2p; }; struct nan_de { @@ -1218,7 +1219,7 @@ const u8 * nan_de_get_service_id(struct nan_de *de, int id) int nan_de_publish(struct nan_de *de, const char *service_name, enum nan_service_protocol_type srv_proto_type, const struct wpabuf *ssi, const struct wpabuf *elems, - struct nan_publish_params *params) + struct nan_publish_params *params, bool p2p) { int publish_id; struct nan_de_service *srv; @@ -1280,6 +1281,7 @@ int nan_de_publish(struct nan_de *de, const char *service_name, wpa_printf(MSG_DEBUG, "NAN: Assigned new publish handle %d for %s", publish_id, service_name); srv->id = publish_id; + srv->is_p2p = p2p; nan_de_add_srv(de, srv); nan_de_run_timer(de); return publish_id; @@ -1331,7 +1333,7 @@ int nan_de_update_publish(struct nan_de *de, int publish_id, int nan_de_subscribe(struct nan_de *de, const char *service_name, enum nan_service_protocol_type srv_proto_type, const struct wpabuf *ssi, const struct wpabuf *elems, - struct nan_subscribe_params *params) + struct nan_subscribe_params *params, bool p2p) { int subscribe_id; struct nan_de_service *srv; @@ -1371,6 +1373,7 @@ int nan_de_subscribe(struct nan_de *de, const char *service_name, wpa_printf(MSG_DEBUG, "NAN: Assigned new subscribe handle %d for %s", subscribe_id, service_name); srv->id = subscribe_id; + srv->is_p2p = p2p; nan_de_add_srv(de, srv); nan_de_run_timer(de); return subscribe_id; diff --git a/components/wpa_supplicant/src/common/nan_de.h b/components/wpa_supplicant/src/common/nan_de.h index ae77cf399db..bdac284b4f7 100644 --- a/components/wpa_supplicant/src/common/nan_de.h +++ b/components/wpa_supplicant/src/common/nan_de.h @@ -106,7 +106,7 @@ struct nan_publish_params { int nan_de_publish(struct nan_de *de, const char *service_name, enum nan_service_protocol_type srv_proto_type, const struct wpabuf *ssi, const struct wpabuf *elems, - struct nan_publish_params *params); + struct nan_publish_params *params, bool p2p); void nan_de_cancel_publish(struct nan_de *de, int publish_id); @@ -133,7 +133,7 @@ struct nan_subscribe_params { int nan_de_subscribe(struct nan_de *de, const char *service_name, enum nan_service_protocol_type srv_proto_type, const struct wpabuf *ssi, const struct wpabuf *elems, - struct nan_subscribe_params *params); + struct nan_subscribe_params *params, bool p2p); void nan_de_cancel_subscribe(struct nan_de *de, int subscribe_id); From bbeb70d81b746624288c72abdd5c5d13c7f4ff19 Mon Sep 17 00:00:00 2001 From: Shivani Baranwal Date: Mon, 5 Aug 2024 15:03:04 +0530 Subject: [PATCH 06/24] NAN USD: Add publishChannelList option for Subscriber Add frequency list to active NAN USD Subscriber to search for a Publisher on multiple channels. This is the publish channel list used by the Subscriber to periodically search for a service on these channels. publishChannelList was already supported in the Publisher and this commit extends that to the Subscriber. This is needed for a P2P2 seeker that is an active subscriber looking for an advertiser on a list of publish channels. Signed-off-by: Shivani Baranwal --- components/wpa_supplicant/src/common/nan_de.c | 11 +++++++++++ components/wpa_supplicant/src/common/nan_de.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index c7294c59d5d..5e79b8c160c 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -1358,6 +1358,17 @@ int nan_de_subscribe(struct nan_de *de, const char *service_name, if (nan_de_derive_service_id(srv) < 0) goto fail; os_memcpy(&srv->subscribe, params, sizeof(*params)); + + if (params->freq_list) { + size_t len; + + len = (int_array_len(params->freq_list) + 1) * sizeof(int); + srv->freq_list = os_memdup(params->freq_list, len); + if (!srv->freq_list) + goto fail; + } + srv->subscribe.freq_list = NULL; + srv->srv_proto_type = srv_proto_type; if (ssi) { srv->ssi = wpabuf_dup(ssi); diff --git a/components/wpa_supplicant/src/common/nan_de.h b/components/wpa_supplicant/src/common/nan_de.h index bdac284b4f7..73f6c9c6136 100644 --- a/components/wpa_supplicant/src/common/nan_de.h +++ b/components/wpa_supplicant/src/common/nan_de.h @@ -125,6 +125,9 @@ struct nan_subscribe_params { /* Selected frequency */ unsigned int freq; + /* Multi-channel frequencies (publishChannelList) */ + const int *freq_list; + /* Query period in ms; 0 = use default */ unsigned int query_period; }; From cbb2ee7ba761847206e4fbd8d49b71535f95c140 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 13 Sep 2024 21:58:51 +0300 Subject: [PATCH 07/24] NAN: Process received NAN SDFs with NAN Network ID in A3 on AP hostapd did not accept NAN SDFs that used NAN Network ID instead of Wildcard BSSID in A3. Extend this to process NAN Network ID just like Wildcard BSSID for these frames to allow the specific group address to be used. Signed-off-by: Jouni Malinen --- components/wpa_supplicant/src/common/nan_de.c | 6 ++++++ components/wpa_supplicant/src/common/nan_de.h | 1 + 2 files changed, 7 insertions(+) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index 5e79b8c160c..638b6dae5c8 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -79,6 +79,12 @@ struct nan_de { }; +bool nan_de_is_nan_network_id(const u8 *addr) +{ + return ether_addr_equal(addr, nan_network_id); +} + + struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap, const struct nan_callbacks *cb) { diff --git a/components/wpa_supplicant/src/common/nan_de.h b/components/wpa_supplicant/src/common/nan_de.h index 73f6c9c6136..f58d67cc174 100644 --- a/components/wpa_supplicant/src/common/nan_de.h +++ b/components/wpa_supplicant/src/common/nan_de.h @@ -55,6 +55,7 @@ struct nan_callbacks { const u8 *peer_addr); }; +bool nan_de_is_nan_network_id(const u8 *addr); struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap, const struct nan_callbacks *cb); void nan_de_flush(struct nan_de *de); From 6fe979cad1bdcb5f7b69531470b0ba91c7beed7f Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 13 Sep 2024 21:58:51 +0300 Subject: [PATCH 08/24] NAN: Update A3 for USD to use NAN Network ID or NAN Cluster ID in A3 Wi-Fi Aware spec v4.0 was not clear on all cases and used a bit unclear definition of A3 use in Table 5 (Address field definiton for NAN SDF frames in USD). That resulted in the initial implementation using Wildcard BSSID to comply with the IEEE 802.11 rules on Public Action frame addressing. For USD to have chances of working with synchronized NNA devices, A3 needs to be set to the NAN Cluster ID when replying to a frame received from a synchronized NAN device. While there is no cluster ID for USD, this can be done by copying the A3 from the received frame. For the cases where sending out an unsolicited multicast frame, the NAN Network ID should be used instead of the Wildcard BSSID. While this behavior is not strictly speaking compliant with the IEEE 802.11 standard, this is the expected behavior for NAN devices, so update the USD implementation to match. Signed-off-by: Jouni Malinen --- components/wpa_supplicant/src/common/nan_de.c | 49 ++++++++++--------- components/wpa_supplicant/src/common/nan_de.h | 8 +-- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index 638b6dae5c8..91d1cc0cd4b 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -18,8 +18,6 @@ static const u8 nan_network_id[ETH_ALEN] = { 0x51, 0x6f, 0x9a, 0x01, 0x00, 0x00 }; -static const u8 wildcard_bssid[ETH_ALEN] = -{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; enum nan_de_service_type { NAN_DE_PUBLISH, @@ -212,7 +210,7 @@ static int nan_de_tx(struct nan_de *de, unsigned int freq, static void nan_de_tx_sdf(struct nan_de *de, struct nan_de_service *srv, unsigned int wait_time, enum nan_service_control_type type, - const u8 *dst, u8 req_instance_id, + const u8 *dst, const u8 *a3, u8 req_instance_id, const struct wpabuf *ssi) { struct wpabuf *buf; @@ -274,10 +272,7 @@ static void nan_de_tx_sdf(struct nan_de *de, struct nan_de_service *srv, wpabuf_put_buf(buf, srv->elems); } - /* Wi-Fi Aware specification v4.0 uses NAN Cluster ID as A3 for USD, - * but there is no synchronization in USD as as such, no NAN Cluster - * either. Use Wildcard BSSID instead. */ - nan_de_tx(de, srv->freq, wait_time, dst, de->nmi, wildcard_bssid, buf); + nan_de_tx(de, srv->freq, wait_time, dst, de->nmi, a3, buf); wpabuf_free(buf); } @@ -358,7 +353,7 @@ static void nan_de_tx_multicast(struct nan_de *de, struct nan_de_service *srv, return; } - nan_de_tx_sdf(de, srv, wait_time, type, nan_network_id, + nan_de_tx_sdf(de, srv, wait_time, type, nan_network_id, nan_network_id, req_instance_id, srv->ssi); os_get_reltime(&srv->last_multicast); } @@ -784,7 +779,7 @@ static void nan_de_get_sdea(const u8 *buf, size_t len, u8 instance_id, static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv, - const u8 *peer_addr, u8 instance_id, + const u8 *peer_addr, const u8 *a3, u8 instance_id, u8 req_instance_id, u16 sdea_control, enum nan_service_protocol_type srv_proto_type, const u8 *ssi, size_t ssi_len) @@ -806,7 +801,7 @@ static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv, /* Passive subscriber replies with a Follow-up message without * Service Specific Info field if it received a matching * unsolicited Publish message. */ - nan_de_transmit(de, srv->id, NULL, NULL, peer_addr, + nan_de_transmit(de, srv->id, NULL, NULL, peer_addr, a3, instance_id); } @@ -855,7 +850,8 @@ static bool nan_de_filter_match(struct nan_de_service *srv, static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv, - const u8 *peer_addr, u8 instance_id, + const u8 *peer_addr, const u8 *a3, + u8 instance_id, const u8 *matching_filter, size_t matching_filter_len, enum nan_service_protocol_type srv_proto_type, @@ -944,9 +940,12 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv, /* Wi-Fi Aware specification v4.0 uses NAN Cluster ID as A3 for USD, * but there is no synchronization in USD as as such, no NAN Cluster * either. Use Wildcard BSSID instead. */ + if (srv->publish.solicited_multicast || !a3) + a3 = nan_network_id; + nan_de_tx(de, srv->freq, 100, srv->publish.solicited_multicast ? nan_network_id : peer_addr, - de->nmi, wildcard_bssid, buf); + de->nmi, a3, buf); wpabuf_free(buf); nan_de_pause_state(srv, peer_addr, instance_id); @@ -959,8 +958,8 @@ offload: static void nan_de_rx_follow_up(struct nan_de *de, struct nan_de_service *srv, - const u8 *peer_addr, u8 instance_id, - const u8 *ssi, size_t ssi_len) + const u8 *peer_addr, const u8 *a3, + u8 instance_id, const u8 *ssi, size_t ssi_len) { /* Follow-up function processing of a receive Follow-up message for a * Subscribe or Publish instance */ @@ -982,11 +981,11 @@ static void nan_de_rx_follow_up(struct nan_de *de, struct nan_de_service *srv, if (de->cb.receive) de->cb.receive(de->cb.ctx, srv->id, instance_id, ssi, ssi_len, - peer_addr); + peer_addr, a3); } -static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr, +static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr, const u8 *a3, unsigned int freq, const u8 *buf, size_t len, const u8 *sda, size_t sda_len) { @@ -1111,20 +1110,20 @@ static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr, switch (type) { case NAN_SRV_CTRL_PUBLISH: - nan_de_rx_publish(de, srv, peer_addr, instance_id, + nan_de_rx_publish(de, srv, peer_addr, a3, instance_id, req_instance_id, sdea_control, srv_proto_type, ssi, ssi_len); break; case NAN_SRV_CTRL_SUBSCRIBE: - nan_de_rx_subscribe(de, srv, peer_addr, instance_id, + nan_de_rx_subscribe(de, srv, peer_addr, a3, instance_id, matching_filter, matching_filter_len, srv_proto_type, ssi, ssi_len); break; case NAN_SRV_CTRL_FOLLOW_UP: - nan_de_rx_follow_up(de, srv, peer_addr, instance_id, + nan_de_rx_follow_up(de, srv, peer_addr, a3, instance_id, ssi, ssi_len); break; } @@ -1132,8 +1131,8 @@ static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr, } -void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, unsigned int freq, - const u8 *buf, size_t len) +void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, const u8 *a3, + unsigned int freq, const u8 *buf, size_t len) { const u8 *sda; u16 sda_len; @@ -1155,7 +1154,7 @@ void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, unsigned int freq, sda++; sda_len = WPA_GET_LE16(sda); sda += 2; - nan_de_rx_sda(de, peer_addr, freq, buf, len, sda, sda_len); + nan_de_rx_sda(de, peer_addr, a3, freq, buf, len, sda, sda_len); } } @@ -1415,7 +1414,7 @@ void nan_de_cancel_subscribe(struct nan_de *de, int subscribe_id) int nan_de_transmit(struct nan_de *de, int handle, const struct wpabuf *ssi, const struct wpabuf *elems, - const u8 *peer_addr, u8 req_instance_id) + const u8 *peer_addr, const u8 *a3, u8 req_instance_id) { struct nan_de_service *srv; @@ -1426,8 +1425,10 @@ int nan_de_transmit(struct nan_de *de, int handle, if (!srv) return -1; + if (!a3) + a3 = nan_network_id; nan_de_tx_sdf(de, srv, 100, NAN_SRV_CTRL_FOLLOW_UP, - peer_addr, req_instance_id, ssi); + peer_addr, a3, req_instance_id, ssi); os_get_reltime(&srv->last_followup); return 0; diff --git a/components/wpa_supplicant/src/common/nan_de.h b/components/wpa_supplicant/src/common/nan_de.h index f58d67cc174..4d4f093b887 100644 --- a/components/wpa_supplicant/src/common/nan_de.h +++ b/components/wpa_supplicant/src/common/nan_de.h @@ -52,7 +52,7 @@ struct nan_callbacks { void (*receive)(void *ctx, int id, int peer_instance_id, const u8 *ssi, size_t ssi_len, - const u8 *peer_addr); + const u8 *peer_addr, const u8 *a3); }; bool nan_de_is_nan_network_id(const u8 *addr); @@ -67,8 +67,8 @@ void nan_de_listen_ended(struct nan_de *de, unsigned int freq); void nan_de_tx_status(struct nan_de *de, unsigned int freq, const u8 *dst); void nan_de_tx_wait_ended(struct nan_de *de); -void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, unsigned int freq, - const u8 *buf, size_t len); +void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, const u8 *a3, + unsigned int freq, const u8 *buf, size_t len); const u8 * nan_de_get_service_id(struct nan_de *de, int id); struct nan_publish_params { @@ -145,6 +145,6 @@ void nan_de_cancel_subscribe(struct nan_de *de, int subscribe_id); * req_instance_id = peer publish_id or subscribe_id */ int nan_de_transmit(struct nan_de *de, int handle, const struct wpabuf *ssi, const struct wpabuf *elems, - const u8 *peer_addr, u8 req_instance_id); + const u8 *peer_addr, const u8 *a3, u8 req_instance_id); #endif /* NAN_DE_H */ From aa433f46c98ccca31d1ac7876e7cbe2620ccf2af Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 14 Sep 2024 12:54:04 +0300 Subject: [PATCH 09/24] NAN: Handle A3 copying internally to simplify control interface There is no need to copy the A3 value for follow-up frames through the control interface events and commands since it can be handled internally in the service with sufficient accuracy. More parallel operations with multiple peers might need per-peer information, but that can be extended in the future, if that level of complexity is really needed in practice. Signed-off-by: Jouni Malinen --- components/wpa_supplicant/src/common/nan_de.c | 16 ++++++++++++---- components/wpa_supplicant/src/common/nan_de.h | 4 ++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index 91d1cc0cd4b..0b05b7fb78b 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -43,6 +43,8 @@ struct nan_de_service { unsigned int freq; unsigned int default_freq; int *freq_list; + u8 a3[ETH_ALEN]; + bool a3_set; /* pauseState information for Publish function */ struct os_reltime pause_state_end; @@ -801,7 +803,7 @@ static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv, /* Passive subscriber replies with a Follow-up message without * Service Specific Info field if it received a matching * unsolicited Publish message. */ - nan_de_transmit(de, srv->id, NULL, NULL, peer_addr, a3, + nan_de_transmit(de, srv->id, NULL, NULL, peer_addr, instance_id); } @@ -979,9 +981,12 @@ static void nan_de_rx_follow_up(struct nan_de *de, struct nan_de_service *srv, if (srv->type == NAN_DE_PUBLISH && !ssi) nan_de_pause_state(srv, peer_addr, instance_id); + os_memcpy(srv->a3, a3, ETH_ALEN); + srv->a3_set = true; + if (de->cb.receive) de->cb.receive(de->cb.ctx, srv->id, instance_id, ssi, ssi_len, - peer_addr, a3); + peer_addr); } @@ -1414,9 +1419,10 @@ void nan_de_cancel_subscribe(struct nan_de *de, int subscribe_id) int nan_de_transmit(struct nan_de *de, int handle, const struct wpabuf *ssi, const struct wpabuf *elems, - const u8 *peer_addr, const u8 *a3, u8 req_instance_id) + const u8 *peer_addr, u8 req_instance_id) { struct nan_de_service *srv; + const u8 *a3; if (handle < 1 || handle > NAN_DE_MAX_SERVICE) return -1; @@ -1425,7 +1431,9 @@ int nan_de_transmit(struct nan_de *de, int handle, if (!srv) return -1; - if (!a3) + if (srv->a3_set) + a3 = srv->a3; + else a3 = nan_network_id; nan_de_tx_sdf(de, srv, 100, NAN_SRV_CTRL_FOLLOW_UP, peer_addr, a3, req_instance_id, ssi); diff --git a/components/wpa_supplicant/src/common/nan_de.h b/components/wpa_supplicant/src/common/nan_de.h index 4d4f093b887..15c05ef9b1c 100644 --- a/components/wpa_supplicant/src/common/nan_de.h +++ b/components/wpa_supplicant/src/common/nan_de.h @@ -52,7 +52,7 @@ struct nan_callbacks { void (*receive)(void *ctx, int id, int peer_instance_id, const u8 *ssi, size_t ssi_len, - const u8 *peer_addr, const u8 *a3); + const u8 *peer_addr); }; bool nan_de_is_nan_network_id(const u8 *addr); @@ -145,6 +145,6 @@ void nan_de_cancel_subscribe(struct nan_de *de, int subscribe_id); * req_instance_id = peer publish_id or subscribe_id */ int nan_de_transmit(struct nan_de *de, int handle, const struct wpabuf *ssi, const struct wpabuf *elems, - const u8 *peer_addr, const u8 *a3, u8 req_instance_id); + const u8 *peer_addr, u8 req_instance_id); #endif /* NAN_DE_H */ From fd7b14af83db529fd406dbf05bd8df31a5ac45b9 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 4 Nov 2024 22:05:29 +0200 Subject: [PATCH 10/24] NAN: Do not unpause publisher on fixed Follow-up message timeout Do not unpause publisher if more than one second has passed from the last Follow-up message TX or RX. There is no such behavior described in the Wi-Fi Aware specification and it is possible for a service to need more time to generate Follow-up messages. Leave it to the service itself to force timeout, if desired, or terminate pauseState after the 60 second overall timeout. Signed-off-by: Jouni Malinen --- components/wpa_supplicant/src/common/nan_de.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index 0b05b7fb78b..cddc1373e63 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -38,7 +38,6 @@ struct nan_de_service { struct os_reltime end_time; struct os_reltime last_multicast; struct os_reltime first_discovered; - struct os_reltime last_followup; bool needs_fsd; unsigned int freq; unsigned int default_freq; @@ -401,9 +400,6 @@ static bool nan_de_srv_expired(struct nan_de_service *srv, return false; if (!srv->publish.fsd) return true; - if (os_reltime_initialized(&srv->last_followup) && - !os_reltime_expired(now, &srv->last_followup, 1)) - return false; if (os_reltime_expired(now, &srv->last_multicast, 1)) return true; } @@ -415,9 +411,6 @@ static bool nan_de_srv_expired(struct nan_de_service *srv, return false; if (!srv->needs_fsd) return true; - if (os_reltime_initialized(&srv->last_followup) && - !os_reltime_expired(now, &srv->last_followup, 1)) - return false; if (os_reltime_expired(now, &srv->first_discovered, 1)) return true; } @@ -586,10 +579,7 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx) if (srv->type == NAN_DE_PUBLISH && os_reltime_initialized(&srv->pause_state_end) && - (os_reltime_before(&srv->pause_state_end, &now) || - (srv->publish.fsd && - os_reltime_initialized(&srv->last_followup) && - os_reltime_expired(&now, &srv->last_followup, 1)))) + (os_reltime_before(&srv->pause_state_end, &now))) nan_de_unpause_state(srv); srv_next = nan_de_srv_time_to_next(de, srv, &now); @@ -976,8 +966,6 @@ static void nan_de_rx_follow_up(struct nan_de *de, struct nan_de_service *srv, return; } - os_get_reltime(&srv->last_followup); - if (srv->type == NAN_DE_PUBLISH && !ssi) nan_de_pause_state(srv, peer_addr, instance_id); @@ -1438,6 +1426,5 @@ int nan_de_transmit(struct nan_de *de, int handle, nan_de_tx_sdf(de, srv, 100, NAN_SRV_CTRL_FOLLOW_UP, peer_addr, a3, req_instance_id, ssi); - os_get_reltime(&srv->last_followup); return 0; } From 1c18f52de0971c5b78fdd21d7dd6a0c5d4be747e Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 4 Nov 2024 22:42:44 +0200 Subject: [PATCH 11/24] NAN: Make DE aware of maximum driver supported listen time This can be used to optimize listen operations to be as long as the driver supports instead of having to use a small enough value to work with all drivers. Signed-off-by: Jouni Malinen --- components/wpa_supplicant/src/common/nan_de.c | 3 +++ components/wpa_supplicant/src/common/nan_de.h | 1 + 2 files changed, 4 insertions(+) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index cddc1373e63..9c7cf64a34e 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -64,6 +64,7 @@ struct nan_de { u8 nmi[ETH_ALEN]; bool offload; bool ap; + unsigned int max_listen; struct nan_callbacks cb; struct nan_de_service *service[NAN_DE_MAX_SERVICE]; @@ -85,6 +86,7 @@ bool nan_de_is_nan_network_id(const u8 *addr) struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap, + unsigned int max_listen, const struct nan_callbacks *cb) { struct nan_de *de; @@ -96,6 +98,7 @@ struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap, os_memcpy(de->nmi, nmi, ETH_ALEN); de->offload = offload; de->ap = ap; + de->max_listen = max_listen ? max_listen : 1000; os_memcpy(&de->cb, cb, sizeof(*cb)); return de; diff --git a/components/wpa_supplicant/src/common/nan_de.h b/components/wpa_supplicant/src/common/nan_de.h index 15c05ef9b1c..c3bc9e898b2 100644 --- a/components/wpa_supplicant/src/common/nan_de.h +++ b/components/wpa_supplicant/src/common/nan_de.h @@ -57,6 +57,7 @@ struct nan_callbacks { bool nan_de_is_nan_network_id(const u8 *addr); struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap, + unsigned int max_listen, const struct nan_callbacks *cb); void nan_de_flush(struct nan_de *de); void nan_de_deinit(struct nan_de *de); From 7ba048a8c5da5ccbb38a171067eebaaebf090093 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 4 Nov 2024 22:43:44 +0200 Subject: [PATCH 12/24] NAN: Print a debug entry on TX wait time expiration This can be helpful for understanding NAN DE behavior. Signed-off-by: Jouni Malinen --- components/wpa_supplicant/src/common/nan_de.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index 9c7cf64a34e..50f2d8c7977 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -675,6 +675,10 @@ void nan_de_tx_status(struct nan_de *de, unsigned int freq, const u8 *dst) void nan_de_tx_wait_ended(struct nan_de *de) { + if (de->tx_wait_end_freq) + wpa_printf(MSG_DEBUG, + "NAN: TX wait for response ended (freq=%u)", + de->tx_wait_end_freq); de->tx_wait_end_freq = 0; nan_de_run_timer(de); } From 62e7fa86ab67232157229383c4fcc98bd909b4a7 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 4 Nov 2024 22:44:27 +0200 Subject: [PATCH 13/24] NAN: Limit pauseState to be within service lifetime If a publish service is configured with an explicit lifetime (ttl), do not allow pauseState duration to exceed that. Signed-off-by: Jouni Malinen --- components/wpa_supplicant/src/common/nan_de.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index 50f2d8c7977..bb184b046f9 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -160,6 +160,9 @@ static void nan_de_pause_state(struct nan_de_service *srv, const u8 *peer_addr, wpa_printf(MSG_DEBUG, "NAN: Start pauseState"); os_get_reltime(&srv->pause_state_end); srv->pause_state_end.sec += 60; + if (os_reltime_initialized(&srv->end_time) && + os_reltime_before(&srv->end_time, &srv->pause_state_end)) + srv->pause_state_end = srv->end_time; os_memcpy(srv->sel_peer_addr, peer_addr, ETH_ALEN); srv->sel_peer_id = peer_id; } From 63445ae0f7e17febc215326dc7d71b23b85d21c3 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 4 Nov 2024 22:45:26 +0200 Subject: [PATCH 14/24] NAN: Wait on the channel with publisher is in pauseState Remain waiting for additional Follow-up messages on a publisher that is in pauseState for a service that requires further service discovery. Signed-off-by: Jouni Malinen --- components/wpa_supplicant/src/common/nan_de.c | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index bb184b046f9..6e844d90a6e 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -483,6 +483,16 @@ static int nan_de_srv_time_to_next(struct nan_de *de, next = tmp; } + if (srv->type == NAN_DE_PUBLISH && + srv->publish.fsd && + os_reltime_initialized(&srv->pause_state_end)) { + os_reltime_sub(&srv->pause_state_end, now, &diff); + tmp = os_reltime_in_ms(&diff); + if (next == -1 || tmp < next) + next = tmp; + return next; + } + tmp = nan_de_next_multicast(de, srv, now); if (tmp >= 0 && (next == -1 || tmp < next)) next = tmp; @@ -592,6 +602,30 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx) if (srv_next >= 0 && (next == -1 || srv_next < next)) next = srv_next; + if (srv->type == NAN_DE_PUBLISH && + srv->publish.fsd && + os_reltime_initialized(&srv->pause_state_end) && + de->tx_wait_end_freq == 0 && + de->listen_freq == 0 && de->ext_listen_freq == 0) { + struct os_reltime diff; + int duration; + + os_reltime_sub(&srv->pause_state_end, &now, &diff); + duration = os_reltime_in_ms(&diff); + if (duration < 0) + continue; + if ((unsigned int) duration > de->max_listen) + duration = de->max_listen; + if (de->cb.listen(de->cb.ctx, srv->freq, duration) == + 0) { + wpa_printf(MSG_DEBUG, + "NAN: Publisher in pauseState - started listen on %u MHz", + srv->freq); + de->listen_freq = srv->freq; + return; + } + } + if (srv_next == 0 && !started && !de->offload && de->listen_freq == 0 && de->ext_listen_freq == 0 && de->tx_wait_end_freq == 0 && From 8489c48ddac815bbaa9ec453725b1e72e3a4ccf6 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 4 Nov 2024 23:03:19 +0200 Subject: [PATCH 15/24] NAN: Do not expire USD services based on last TX/RX message This behavior is not described in the Wi-Fi Aware specification, so remove it and instead, expect services to terminate USD explicitly when no further Follow-up messages are needed. Signed-off-by: Jouni Malinen --- components/wpa_supplicant/src/common/nan_de.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index 6e844d90a6e..84a723e94c3 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -406,8 +406,6 @@ static bool nan_de_srv_expired(struct nan_de_service *srv, return false; if (!srv->publish.fsd) return true; - if (os_reltime_expired(now, &srv->last_multicast, 1)) - return true; } if (srv->type == NAN_DE_SUBSCRIBE) { @@ -417,8 +415,6 @@ static bool nan_de_srv_expired(struct nan_de_service *srv, return false; if (!srv->needs_fsd) return true; - if (os_reltime_expired(now, &srv->first_discovered, 1)) - return true; } return false; From 105225be91c3f51cc6a9b2cad5b15d877a23ce15 Mon Sep 17 00:00:00 2001 From: Shivani Baranwal Date: Thu, 14 Nov 2024 14:07:34 +0530 Subject: [PATCH 16/24] NAN USD: Use different group address for P2P2 P2P2 uses USD with a different group address than the NAN Network ID defined in the Wi-Fi Aware specification. Select the group address based on whether USD is used with P2P2 or something else. This changes behavior only for the P2P2 cases. Signed-off-by: Shivani Baranwal --- components/wpa_supplicant/src/common/nan_de.c | 35 ++++++++++++++++--- components/wpa_supplicant/src/common/nan_de.h | 1 + 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index 84a723e94c3..1a0763fdaf4 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -24,6 +24,9 @@ enum nan_de_service_type { NAN_DE_SUBSCRIBE, }; +static const u8 p2p_network_id[ETH_ALEN] = +{ 0x51, 0x6f, 0x9a, 0x02, 0x00, 0x00 }; + struct nan_de_service { int id; enum nan_de_service_type type; @@ -85,6 +88,12 @@ bool nan_de_is_nan_network_id(const u8 *addr) } +bool nan_de_is_p2p_network_id(const u8 *addr) +{ + return ether_addr_equal(addr, p2p_network_id); +} + + struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap, unsigned int max_listen, const struct nan_callbacks *cb) @@ -343,6 +352,7 @@ static void nan_de_tx_multicast(struct nan_de *de, struct nan_de_service *srv, { enum nan_service_control_type type; unsigned int wait_time = 100; + const u8 *network_id; if (srv->type == NAN_DE_PUBLISH) { int ms; @@ -360,7 +370,12 @@ static void nan_de_tx_multicast(struct nan_de *de, struct nan_de_service *srv, return; } - nan_de_tx_sdf(de, srv, wait_time, type, nan_network_id, nan_network_id, + if (srv->is_p2p) + network_id = p2p_network_id; + else + network_id = nan_network_id; + + nan_de_tx_sdf(de, srv, wait_time, type, network_id, network_id, req_instance_id, srv->ssi); os_get_reltime(&srv->last_multicast); } @@ -893,6 +908,7 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv, size_t len = 0, sda_len, sdea_len; u8 ctrl = 0; u16 sdea_ctrl = 0; + const u8 *network_id; /* Publish function processing of a receive Subscribe message */ @@ -969,14 +985,19 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv, wpabuf_put_buf(buf, srv->elems); } + if (srv->is_p2p) + network_id = p2p_network_id; + else + network_id = nan_network_id; + /* Wi-Fi Aware specification v4.0 uses NAN Cluster ID as A3 for USD, * but there is no synchronization in USD as as such, no NAN Cluster * either. Use Wildcard BSSID instead. */ if (srv->publish.solicited_multicast || !a3) - a3 = nan_network_id; + a3 = network_id; nan_de_tx(de, srv->freq, 100, - srv->publish.solicited_multicast ? nan_network_id : peer_addr, + srv->publish.solicited_multicast ? network_id : peer_addr, de->nmi, a3, buf); wpabuf_free(buf); @@ -1451,6 +1472,7 @@ int nan_de_transmit(struct nan_de *de, int handle, { struct nan_de_service *srv; const u8 *a3; + const u8 *network_id; if (handle < 1 || handle > NAN_DE_MAX_SERVICE) return -1; @@ -1459,10 +1481,15 @@ int nan_de_transmit(struct nan_de *de, int handle, if (!srv) return -1; + if (srv->is_p2p) + network_id = p2p_network_id; + else + network_id = nan_network_id; + if (srv->a3_set) a3 = srv->a3; else - a3 = nan_network_id; + a3 = network_id; nan_de_tx_sdf(de, srv, 100, NAN_SRV_CTRL_FOLLOW_UP, peer_addr, a3, req_instance_id, ssi); diff --git a/components/wpa_supplicant/src/common/nan_de.h b/components/wpa_supplicant/src/common/nan_de.h index c3bc9e898b2..2c95829bcc7 100644 --- a/components/wpa_supplicant/src/common/nan_de.h +++ b/components/wpa_supplicant/src/common/nan_de.h @@ -56,6 +56,7 @@ struct nan_callbacks { }; bool nan_de_is_nan_network_id(const u8 *addr); +bool nan_de_is_p2p_network_id(const u8 *addr); struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap, unsigned int max_listen, const struct nan_callbacks *cb); From 706b211dbfdd6817754e7db8422ba5c59aa4eae4 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Thu, 19 Dec 2024 11:18:50 +0200 Subject: [PATCH 17/24] NAN: Fix A3 for multicast P2P2 USD According to the Wi-Fi Direct spec draft, address 3 in multicast USD frames shall be set to wildcard BSSID (i.e., this differs from the Wi-Fi Aware specification). Fix it. Signed-off-by: Andrei Otcheretianski --- components/wpa_supplicant/src/common/nan_de.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index 1a0763fdaf4..1266568a070 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -27,6 +27,9 @@ enum nan_de_service_type { static const u8 p2p_network_id[ETH_ALEN] = { 0x51, 0x6f, 0x9a, 0x02, 0x00, 0x00 }; +static const u8 wildcard_bssid[ETH_ALEN] = +{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + struct nan_de_service { int id; enum nan_de_service_type type; @@ -353,6 +356,7 @@ static void nan_de_tx_multicast(struct nan_de *de, struct nan_de_service *srv, enum nan_service_control_type type; unsigned int wait_time = 100; const u8 *network_id; + const u8 *bssid; if (srv->type == NAN_DE_PUBLISH) { int ms; @@ -370,12 +374,15 @@ static void nan_de_tx_multicast(struct nan_de *de, struct nan_de_service *srv, return; } - if (srv->is_p2p) + if (srv->is_p2p) { network_id = p2p_network_id; - else + bssid = wildcard_bssid; + } else { network_id = nan_network_id; + bssid = nan_network_id; + } - nan_de_tx_sdf(de, srv, wait_time, type, network_id, network_id, + nan_de_tx_sdf(de, srv, wait_time, type, network_id, bssid, req_instance_id, srv->ssi); os_get_reltime(&srv->last_multicast); } From a83d66cb883a267ab65961428fcba622d2d6bb50 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Thu, 19 Dec 2024 11:18:50 +0200 Subject: [PATCH 18/24] NAN: Fix A3 for unicast P2P2 USD According to the Wi-Fi Direct spec draft, address 3 in unicast USD frames shall be set to the P2P Device Address of the sender (i.e., this differs from the Wi-Fi Aware specification). Fix it. Signed-off-by: Andrei Otcheretianski --- components/wpa_supplicant/src/common/nan_de.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index 1266568a070..fa46309d621 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -1002,6 +1002,8 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv, * either. Use Wildcard BSSID instead. */ if (srv->publish.solicited_multicast || !a3) a3 = network_id; + else if (srv->is_p2p) + a3 = de->nmi; nan_de_tx(de, srv->freq, 100, srv->publish.solicited_multicast ? network_id : peer_addr, From 0ad3af78a66e8af300f7f4a05560bb54011f339c Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Tue, 26 Nov 2024 11:10:10 +0200 Subject: [PATCH 19/24] NAN: Remove excessive debug print about the next timer As it polutes the log too much. Signed-off-by: Andrei Otcheretianski --- components/wpa_supplicant/src/common/nan_de.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index fa46309d621..c03fa483c75 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -680,7 +680,7 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx) if (next == 0) next = 1; - wpa_printf(MSG_DEBUG, "NAN: Next timer in %u ms", next); + eloop_register_timeout(next / 1000, (next % 1000) * 1000, nan_de_timer, de, NULL); } From b1d1897547c4198246cc9ed0b00526cd3ca49223 Mon Sep 17 00:00:00 2001 From: Sarvesh Bodakhe Date: Tue, 4 Feb 2025 11:48:18 +0530 Subject: [PATCH 20/24] fix(wifi): Make sure that USD APIs do not alter the SSI information 1. Make sure that wpa_supplicant does not encapsulate user-given SSI info with WFA OUI. 2. USD component shall transfer the SSI given by user as it is, without any modification or encapsulation. 3. Note that this will break the compatibility of ESP USD implementation with a device running upstream wpa_supplicant as wpa_supplicant encapsulates the SSI information with WfA oui. For compatibility with wpa_supplicant, user needs to handle the SSI encapsulation/decapsulation. --- components/wpa_supplicant/src/common/nan_de.c | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index c03fa483c75..0098eb8a926 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -243,8 +243,13 @@ static void nan_de_tx_sdf(struct nan_de *de, struct nan_de_service *srv, /* Service Descriptor Extension attribute */ sdea_len = 1 + 2; +#ifdef ESP_SUPPLICANT + if (ssi) + sdea_len += 2 + wpabuf_len(ssi); +#else if (ssi) sdea_len += 2 + 4 + wpabuf_len(ssi); +#endif /* ESP_SUPPLICANT */ len += NAN_ATTR_HDR_LEN + sdea_len; /* Element Container attribute */ @@ -276,10 +281,15 @@ static void nan_de_tx_sdf(struct nan_de *de, struct nan_de_service *srv, } wpabuf_put_le16(buf, sdea_ctrl); if (ssi) { +#ifdef ESP_SUPPLICANT + wpabuf_put_le16(buf, wpabuf_len(ssi)); + wpabuf_put_buf(buf, ssi); +#else wpabuf_put_le16(buf, 4 + wpabuf_len(ssi)); wpabuf_put_be24(buf, OUI_WFA); wpabuf_put_u8(buf, srv->srv_proto_type); wpabuf_put_buf(buf, ssi); +#endif /* ESP_SUPPLICANT */ } } @@ -821,12 +831,19 @@ static void nan_de_get_sdea(const u8 *buf, size_t len, u8 instance_id, if (srv_info_len > end - sdea) continue; +#ifdef ESP_SUPPLICANT + if (srv_info_len > 0) { + *ssi = sdea; + *ssi_len = srv_info_len; + } +#else if (srv_info_len >= 4 && WPA_GET_BE24(sdea) == OUI_WFA) { *srv_proto_type = sdea[3]; *ssi = sdea + 4; *ssi_len = srv_info_len - 4; } +#endif /* ESP_SUPPLICANT */ } } } @@ -943,8 +960,14 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv, /* Service Descriptor Extension attribute */ sdea_len = 1 + 2; + +#ifdef ESP_SUPPLICANT + if (srv->ssi) + sdea_len += 2 + wpabuf_len(srv->ssi); +#else if (srv->ssi) sdea_len += 2 + 4 + wpabuf_len(srv->ssi); +#endif /* ESP_SUPPLICANT */ len += NAN_ATTR_HDR_LEN + sdea_len; /* Element Container attribute */ @@ -977,10 +1000,15 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv, } wpabuf_put_le16(buf, sdea_ctrl); if (srv->ssi) { +#ifdef ESP_SUPPLICANT + wpabuf_put_le16(buf, wpabuf_len(srv->ssi)); + wpabuf_put_buf(buf, srv->ssi); +#else wpabuf_put_le16(buf, 4 + wpabuf_len(srv->ssi)); wpabuf_put_be24(buf, OUI_WFA); wpabuf_put_u8(buf, srv->srv_proto_type); wpabuf_put_buf(buf, srv->ssi); +#endif /* ESP_SUPPLICANT */ } } @@ -1126,6 +1154,13 @@ static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr, const u8 *a3, flen = *sda++; if (end - sda < flen) return; +#ifdef ESP_SUPPLICANT + if (flen > 0) { + ssi = sda; + ssi_len = flen; + wpa_hexdump(MSG_MSGDUMP, "NAN: ssi", ssi, ssi_len); + } +#else if (flen >= 4 && WPA_GET_BE24(sda) == OUI_WFA) { srv_proto_type = sda[3]; ssi = sda + 4; @@ -1134,6 +1169,7 @@ static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr, const u8 *a3, srv_proto_type); wpa_hexdump(MSG_MSGDUMP, "NAN: ssi", ssi, ssi_len); } +#endif /* ESP_SUPPLICANT */ sda += flen; } From 6255a6765474e80f1e184797a150139604fff7a3 Mon Sep 17 00:00:00 2001 From: Sarvesh Bodakhe Date: Fri, 31 Jan 2025 12:37:20 +0530 Subject: [PATCH 21/24] fix(wifi): Add support to receive broadcast frames in ROC (Remain on Channel) This commit adds the support to receive broadcast frames in ROC Rx callback. Some use cases may need to receive broadcast packets for discovery of other peers. - This can be enabled/disabled through 'allow__broadcast' flag in 'wifi_roc_req_t' structure. - In default configration, broadcast packets will always be filtered out and will not be passed to the Rx callback to save CPU consumption. --- components/esp_wifi/include/esp_wifi_types_generic.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index 49fdb2e16ed..5b7e2cb363f 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -833,6 +833,10 @@ typedef struct { wifi_action_rx_cb_t rx_cb; /**< Rx Callback to receive any response */ uint8_t op_id; /**< ID of this specific ROC operation provided by wifi driver */ wifi_action_roc_done_cb_t done_cb; /**< Callback to function that will be called upon ROC done. If assigned, WIFI_EVENT_ROC_DONE event will not be posted */ + bool allow_broadcast; /**< If set to true, broadcast/multicast action frames will be received + in the ROC Rx callback, enabling peer discovery. + If false (default), broadcast/multicast action frames will be filtered out + and not passed to the Rx callback, reducing CPU usage. */ } wifi_roc_req_t; /** From 93347494b385fb6f2e53be08406f441454f3c275 Mon Sep 17 00:00:00 2001 From: Sarvesh Bodakhe Date: Tue, 30 Sep 2025 12:53:27 +0530 Subject: [PATCH 22/24] feat(wifi): Add support for Wi-Fi Aware: Unsynchronized Service Discover (USD) 1. Remove redundant fixes in upstream wpa_supplicant for USD - Upstream supplicant has mostly fixed the issues regarding the unnecessary resetting pauseStateTimeout. - Upstream supplicant still needs one fix to avoid resetting the pauseStateTimeout when subscribe message is received from the peer which had triggered the pauseStateTimeout previously. 2. Replace array-based channel list with bitmap for NaN-USD Use `wifi_scan_channel_bitmap_t` to represent the channel list for NaN-USD publisher and subscriber configurations. This replaces the previous approach that used a large array to store allowed channels. Also aligns with internal scan bitmap conventions across Wi-Fi stack. 3. call esp_wifi_nan_stop() after USD exchange or STA stop Ensure esp_wifi_nan_stop() is called after publish/subscribe activity completes or when WIFI_EVENT_STA_STOP is received. This prevents NAN stop errors due to inactive interface. NaN-USD currently uses STA interface for Tx/Rx. 4. Fix task watchdog timer triggered in active USD subscriber: As both USD supplicant and offchan TX component gets executed in the wifi task, it created a deadlock like scenario where offchan TX done callback was never getting executed and supplicant 'nan_de_timer' keeps running but failing to send any subscribe frame. 5. Make sure that device is able to recieve action management frames of size more than 1400 bytes. 6. Update proto field in SSI to match Wi-Fi Aware (NaN) spec format The 'proto' field in the 'wifi_nan_wfa_ssi_t' structure previously used an enum (wifi_nan_svc_proto_t), resulting in a 32-bit field. According to the Wi-Fi NAN Specification (Table 5.7), this field must be a single octet (8 bits). This commit updates the type to uint8_t to ensure compliance with the specification. This mismatch previously triggered warnings but did not cause functional errors. 7. Set `allow_broadcast` to true in USD Remain on channel This enables the peer discovery as USD uses NAN-Network Multicast BSSID as A3 address in publish frames. 8. Implement custom channel<->frequency conversion for NAN-USD NaN-USD only permits 20 MHz bandwidth channels in the 2.4 GHz and 5 GHz bands (as per section 4.5.3 of the Wi-Fi Aware Specification v4.0). To avoid linking a large portion of upstream supplicant code for frequency-to-channel and channel-to-frequency conversion, implement minimal custom helper functions. 9. Limit NAN_DE_MAX_SERVICE to 2 for ESP_SUPPLICANT 10. Note: Upstream clamps negative `os_reltime` deltas to zero in `nan_de_srv_time_to_next()`, but our ESP_SUPPLICANT port keeps `os_time_t` unsigned, so that guard just provokes a compiler warning. We skip it for now because the scheduling loop validates past timestamps before computing the diff. Co-authored-by: Shyamal Khachane --- components/esp_wifi/CMakeLists.txt | 2 +- components/esp_wifi/Kconfig | 6 + .../esp_wifi/include/esp_wifi_types_generic.h | 32 +- components/esp_wifi/lib | 2 +- .../wifi_apps/nan_app/include/esp_nan.h | 66 +- .../esp_wifi/wifi_apps/nan_app/src/nan_app.c | 365 ++++++++-- components/wpa_supplicant/CMakeLists.txt | 14 +- .../include/esp_private/esp_nan_usd.h | 56 ++ .../esp_supplicant/src/esp_nan_usd.c | 678 ++++++++++++++++++ components/wpa_supplicant/src/common/nan_de.c | 47 +- components/wpa_supplicant/src/common/nan_de.h | 8 + components/wpa_supplicant/src/utils/common.c | 17 + components/wpa_supplicant/src/utils/common.h | 7 + docs/en/api-guides/wifi.rst | 8 + examples/wifi/.build-test-rules.yml | 42 +- .../wifi_aware/usd_publisher/CMakeLists.txt | 6 + .../wifi/wifi_aware/usd_publisher/README.md | 2 + .../usd_publisher/main/CMakeLists.txt | 2 + .../usd_publisher/main/Kconfig.projbuild | 20 + .../main/usd_publisher_example_main.c | 127 ++++ .../usd_publisher/sdkconfig.defaults | 1 + .../wifi_aware/usd_subscriber/CMakeLists.txt | 6 + .../wifi/wifi_aware/usd_subscriber/README.md | 2 + .../usd_subscriber/main/CMakeLists.txt | 2 + .../usd_subscriber/main/Kconfig.projbuild | 28 + .../main/usd_subscriber_example_main.c | 151 ++++ .../usd_subscriber/sdkconfig.defaults | 1 + 27 files changed, 1606 insertions(+), 92 deletions(-) create mode 100644 components/wpa_supplicant/esp_supplicant/include/esp_private/esp_nan_usd.h create mode 100644 components/wpa_supplicant/esp_supplicant/src/esp_nan_usd.c create mode 100644 examples/wifi/wifi_aware/usd_publisher/CMakeLists.txt create mode 100644 examples/wifi/wifi_aware/usd_publisher/README.md create mode 100644 examples/wifi/wifi_aware/usd_publisher/main/CMakeLists.txt create mode 100644 examples/wifi/wifi_aware/usd_publisher/main/Kconfig.projbuild create mode 100644 examples/wifi/wifi_aware/usd_publisher/main/usd_publisher_example_main.c create mode 100644 examples/wifi/wifi_aware/usd_publisher/sdkconfig.defaults create mode 100644 examples/wifi/wifi_aware/usd_subscriber/CMakeLists.txt create mode 100644 examples/wifi/wifi_aware/usd_subscriber/README.md create mode 100644 examples/wifi/wifi_aware/usd_subscriber/main/CMakeLists.txt create mode 100644 examples/wifi/wifi_aware/usd_subscriber/main/Kconfig.projbuild create mode 100644 examples/wifi/wifi_aware/usd_subscriber/main/usd_subscriber_example_main.c create mode 100644 examples/wifi/wifi_aware/usd_subscriber/sdkconfig.defaults diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index 569bc2efb75..9886f0f07e7 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -48,7 +48,7 @@ if(CONFIG_ESP_WIFI_ENABLED OR CONFIG_ESP_HOST_WIFI_ENABLED) "src/smartconfig_ack.c") endif() - if(CONFIG_ESP_WIFI_NAN_ENABLE) + if(CONFIG_ESP_WIFI_NAN_ENABLE OR CONFIG_ESP_WIFI_NAN_USD_ENABLE) list(APPEND srcs "wifi_apps/nan_app/src/nan_app.c") endif() if(CONFIG_ESP_WIFI_ENABLE_ROAMING_APP) diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index c2fe6a2aeea..24cea7102bd 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -584,6 +584,12 @@ menu "Wi-Fi" help Enable WiFi Aware (NAN) feature. + config ESP_WIFI_NAN_USD_ENABLE + bool "Enable NAN USD" + default n + help + Enable NAN(WiFi Aware) Unsynchronized service discovery + config ESP_WIFI_MBEDTLS_CRYPTO bool "Use MbedTLS crypto APIs" default y diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index 5b7e2cb363f..6d9cdbd6bce 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -592,6 +592,7 @@ typedef struct { 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 discovery_flag; /**< False in case of NAN Synchronization, True in case of Unsynchronized service discovery (USD)*/ } wifi_nan_config_t; /** @@ -830,7 +831,7 @@ typedef struct { uint8_t channel; /**< Channel on which to perform ROC Operation */ wifi_second_chan_t sec_channel; /**< Secondary channel */ uint32_t wait_time_ms; /**< Duration to wait for on target channel */ - wifi_action_rx_cb_t rx_cb; /**< Rx Callback to receive any response */ + wifi_action_rx_cb_t rx_cb; /**< Rx Callback to receive action mgmt frames */ uint8_t op_id; /**< ID of this specific ROC operation provided by wifi driver */ wifi_action_roc_done_cb_t done_cb; /**< Callback to function that will be called upon ROC done. If assigned, WIFI_EVENT_ROC_DONE event will not be posted */ bool allow_broadcast; /**< If set to true, broadcast/multicast action frames will be received @@ -850,7 +851,7 @@ typedef struct { uint16_t burst_period; /**< Requested period between FTM bursts in 100's of milliseconds (allowed values 0(No pref) - 100) */ } wifi_ftm_initiator_cfg_t; -#define ESP_WIFI_NAN_MAX_SVC_SUPPORTED 2 /**< Maximum number of NAN services supported */ +#define ESP_WIFI_NAN_MAX_SVC_SUPPORTED 2 /**< Maximum number of NAN or NAN-USD services supported */ #define ESP_WIFI_NAN_DATAPATH_MAX_PEERS 2 /**< Maximum number of NAN datapath peers supported */ #define ESP_WIFI_NDP_ROLE_INITIATOR 1 /**< Initiator role for NAN Data Path */ @@ -882,7 +883,7 @@ typedef enum { */ typedef struct { uint8_t wfa_oui[WIFI_OUI_LEN]; /**< WFA OUI - 0x50, 0x6F, 0x9A */ - wifi_nan_svc_proto_t proto; /**< WFA defined protocol types */ + uint8_t proto; /**< WFA defined protocol of type wifi_nan_svc_proto_t */ uint8_t payload[0]; /**< Service Info payload */ } wifi_nan_wfa_ssi_t; @@ -897,6 +898,19 @@ typedef enum { NAN_SUBSCRIBE_PASSIVE, /**< Passively listens to Publish frames */ } wifi_nan_service_type_t; +/** + * @brief USD specific configuration parameters + * + */ +typedef struct { + uint8_t usd_default_channel; /**< If not specified, default channel 6 is used */ + wifi_scan_channel_bitmap_t usd_chan_bitmap; /**< Indicates publish channel list used in USD */ + uint8_t n_min; /**< Indicates minimum value of dwell period N used in the USD (Nmin) */ + uint8_t n_max; /**< Indicates maximum value of dwell period N used in the USD (Nmax) */ + uint8_t m_min; /**< Indicates minimum value of dwell period M used in the USD (Mmin) */ + uint8_t m_max; /**< Indicates maximum value of dwell period M used in the USD (Mmax)*/ +} wifi_nan_usd_config_t; + /** * @brief NAN Publish service configuration parameters * @@ -910,9 +924,13 @@ typedef struct { 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 ndp_resp_needed: 1; /**< 0 - Auto-Accept NDP Requests, 1 - Require explicit response with esp_wifi_nan_datapath_resp */ - uint8_t reserved: 3; /**< Reserved */ + uint8_t usd_discovery_flag: 1; /**< 0 - NAN Synchronization for Discovery, 1 - USD for Discovery. 'NAN Discovery flag' from specification */ + uint8_t reserved: 2; /**< Reserved */ 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 */ + 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. */ } wifi_nan_publish_cfg_t; /** @@ -927,9 +945,13 @@ 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: 4; /**< Reserved */ + uint8_t usd_discovery_flag: 1; /**< 0 - NAN Synchronization for Discovery, 1 - USD for Discovery. 'NAN Discovery flag' from specification */ + uint8_t reserved: 3; /**< Reserved */ 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 */ + 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. */ } wifi_nan_subscribe_cfg_t; /** diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 37a69947e1e..21eacc3229f 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 37a69947e1e7c1e98f63ddd3ce11b05aca036057 +Subproject commit 21eacc3229fba6ca5e2c8a92062184b53db65651 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 c370b76ac5e..2dd65d7fcce 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 @@ -20,6 +20,12 @@ extern "C" { .master_pref = 2, \ .scan_time = 3, \ .warm_up_sec = 5, \ + .discovery_flag = 0, \ +}; + +/* For USD, all parameters other than discovery_flag are ignored */ +#define WIFI_USD_NAN_CONFIG_DEFAULT() { \ + .discovery_flag = 1, \ }; #define NDP_STATUS_ACCEPTED 1 @@ -40,7 +46,7 @@ struct nan_peer_record { }; /** - * @brief Start NAN Discovery with provided configuration + * @brief Start NAN Discovery or Unsynchronized service discovery (USD) with provided configuration * * @attention This API should be called after esp_wifi_init(). * @@ -53,7 +59,10 @@ struct nan_peer_record { esp_err_t esp_wifi_nan_start(const wifi_nan_config_t *nan_cfg); /** - * @brief Stop NAN Discovery, end NAN Services and Datapaths + * @brief Stop NAN Discovery or USD and end publish/subscribe services + * + * @attention This API will end datapaths if any in NAN synchronization + * @attention This API will stop USD if discovery_flag is set to true, else it will stop NAN Discovery * * @return * - ESP_OK: succeed @@ -62,9 +71,13 @@ esp_err_t esp_wifi_nan_start(const wifi_nan_config_t *nan_cfg); esp_err_t esp_wifi_nan_stop(void); /** - * @brief Start Publishing a service to the NAN Peers in vicinity + * @brief Start Publishing a service to the NAN/USD Peers in vicinity * * @attention This API should be called after esp_wifi_nan_start(). + * @attention This API will start a publisher in USD if discovery_flag is true + * @attention A maximum of two services is allowed simultaneously + * (e.g., one publish and one subscribe, or two publish/subscribe). + * This limit is defined by the ESP_WIFI_NAN_MAX_SVC_SUPPORTED. * * @param publish_cfg Configuration parameters for publishing a service. * @@ -75,9 +88,13 @@ esp_err_t esp_wifi_nan_stop(void); uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg); /** - * @brief Subscribe for a service within the NAN cluster + * @brief Subscribe to a service published by a NAN peer within a cluster or a USD peer * * @attention This API should be called after esp_wifi_nan_start(). + * @attention This API will start a subscriber in USD if discovery_flag is true + * @attention A maximum of two services is allowed simultaneously + * (e.g., one publish and one subscribe, or two publish/subscribe). + * This limit is defined by the ESP_WIFI_NAN_MAX_SVC_SUPPORTED. * * @param subscribe_cfg Configuration parameters for subscribing for a service. * @@ -88,9 +105,9 @@ uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg); uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe_cfg); /** - * @brief Send a follow-up message to the NAN Peer with matched service + * @brief Send a follow-up message to a matched peer in NAN synchronization or USD * - * @attention This API should be called after a NAN service is discovered due to a match. + * @attention This API should be called after a NAN/USD service is discovered due to a match. * * @param fup_params Configuration parameters for sending a Follow-up message. * @@ -101,7 +118,7 @@ uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe esp_err_t esp_wifi_nan_send_message(wifi_nan_followup_params_t *fup_params); /** - * @brief Cancel a NAN service + * @brief Cancel a NAN synchronization or NAN-USD service * * @param service_id Publish/Subscribe service id to be cancelled. * @@ -198,6 +215,41 @@ esp_err_t esp_wifi_nan_get_peer_records(int *num_peer_records, uint8_t own_svc_i */ esp_err_t esp_wifi_nan_get_peer_info(char *svc_name, uint8_t *peer_mac, struct nan_peer_record *peer_info); +/** + * @brief Get default configuration for USD publish operation. + * + * @note This function returns a default configuration structure for initiating + * a USD (Unsynchronized Service Discovery) publish session. + * - The default channel is set to channel 6 (2.437 GHz) in the 2.4 GHz band. + * - The channel list will include all 20 MHz channels in the 2.4 GHz frequency band, + * as permitted by the regulatory domain of the current geographic location. + * - Default values for dwell periods are set as per Wi-Fi Aware Specification: + * - Nmin = 5, Nmax = 10 + * - Mmin = 5, Mmax = 10 + * + * @return wifi_nan_usd_config_t structure with pre-filled default values for publishing. + */ +wifi_nan_usd_config_t esp_wifi_usd_get_default_publish_cfg(void); + +/** + * @brief Get default configuration for USD subscribe operation. + * + * @note This function returns a default configuration structure for initiating + * a USD (Unsynchronized Service Discovery) subscribe session. + * - The default channel is set to channel 6 (2.437 GHz) in the 2.4 GHz band. + * - The channel list will include all 20 MHz channels in the 2.4 GHz frequency band, + * as permitted by the regulatory domain of the current geographic location. + * - Default values for dwell periods are set as per Wi-Fi Aware Specification: + * - Nmin = 5, Nmax = 10 + * - Mmin = 5, Mmax = 10 + * + * @warning Currently, the subscribe function operates only on the default channel. + * It does not alternate between the default channel and channels in the channel list. + * + * @return wifi_nan_usd_config_t structure with pre-filled default values for subscribing. + */ +wifi_nan_usd_config_t esp_wifi_usd_get_default_subscribe_cfg(void); + #ifdef __cplusplus } #endif 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 df08a10ad02..cfe32d10cf3 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 @@ -17,6 +17,9 @@ #include "os.h" #include "esp_nan.h" #include "utils/common.h" +#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE +#include "esp_private/esp_nan_usd.h" +#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ /* NAN States */ #define NAN_STARTED_BIT BIT0 @@ -42,18 +45,27 @@ /* Global Variables */ static const char *TAG = "nan_app"; +#ifdef CONFIG_ESP_WIFI_NAN_ENABLE static EventGroupHandle_t nan_event_group; static bool s_app_default_handlers_set = false; static uint8_t null_mac[MACADDR_LEN] = {0}; static void *s_nan_data_lock = NULL; -static const uint8_t s_wfa_oui[3] = {0x50, 0x6f, 0x9a}; static uint32_t s_fup_context; +#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ +#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE +#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ +static bool s_usd_in_progress = false; +static const uint8_t s_wfa_oui[3] = {0x50, 0x6f, 0x9a}; /* Definitions */ #define NAN_SDEA_CTRL_FSD_REQD BIT(0) #define NAN_SDEA_CTRL_FSD_GAS BIT(1) #define NAN_SDEA_CTRL_DATAPATH_REQD BIT(2) +#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#define NAN_DATA_LOCK() os_mutex_lock(s_nan_data_lock) +#define NAN_DATA_UNLOCK() os_mutex_unlock(s_nan_data_lock) + struct peer_svc_info { SLIST_ENTRY(peer_svc_info) next; uint8_t peer_svc_info[ESP_WIFI_MAX_SVC_INFO_LEN]; /**< Information for followup message */ @@ -782,11 +794,13 @@ void esp_nan_action_stop(void) os_event_group_set_bits(nan_event_group, NAN_STOPPED_BIT); } +#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ + esp_err_t esp_wifi_nan_start(const wifi_nan_config_t *nan_cfg) { wifi_mode_t mode; esp_err_t ret; - wifi_config_t config = {0}; + s_usd_in_progress = false; ret = esp_wifi_get_mode(&mode); if (ret == ESP_ERR_WIFI_NOT_INIT) { @@ -797,44 +811,89 @@ esp_err_t esp_wifi_nan_start(const wifi_nan_config_t *nan_cfg) return ret; } - if (!s_nan_data_lock) { - ESP_LOGE(TAG, "NAN Data lock doesn't exist"); +#if (!CONFIG_ESP_WIFI_NAN_ENABLE) + if (!nan_cfg->discovery_flag) { + ESP_LOGE(TAG, "discovery_flag must be set when" + "ESP_WIFI_NAN_USD_ENABLE is enabled"); return ESP_FAIL; } +#endif - NAN_DATA_LOCK(); - if (s_nan_ctx.state & NAN_STARTED_BIT) { - ESP_LOGI(TAG, "NAN already started"); - NAN_DATA_UNLOCK(); + /* XXX: For now, NAN-USD and NAN-Sync can not coexist. */ +#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE + if (nan_cfg->discovery_flag) { + /* NAN-USD Only */ + ESP_RETURN_ON_ERROR(esp_wifi_set_mode(WIFI_MODE_STA), "NAN-USD", "Setting STA mode failed"); + ESP_RETURN_ON_ERROR(esp_wifi_start(), "NAN-USD", "Starting WiFi failed"); + ESP_RETURN_ON_ERROR(esp_nan_usd_init(), "NAN-USD", "Failed to initialise NAN USD engine"); + s_usd_in_progress = true; + ESP_LOGI(TAG, "NaN-USD Started"); return ESP_OK; } - NAN_DATA_UNLOCK(); +#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ +#ifdef CONFIG_ESP_WIFI_NAN_ENABLE + else { + if (nan_cfg->discovery_flag) { + /* Should reach here only if ESP_WIFI_NAN_USD_ENABLE is disabled */ + ESP_LOGE(TAG, "Can not set discovery_flag without " + "ESP_WIFI_NAN_USD_ENABLE enabled"); + return ESP_FAIL; + } - ESP_RETURN_ON_ERROR(esp_wifi_set_mode(WIFI_MODE_NAN), TAG, "Set mode NAN failed"); + /* NAN-Synchronization Only */ + wifi_config_t config = {0}; + if (!s_nan_data_lock) { + ESP_LOGE(TAG, "NAN Data lock doesn't exist"); + return ESP_FAIL; + } - memcpy(&config.nan, nan_cfg, sizeof(wifi_nan_config_t)); - ESP_RETURN_ON_ERROR(esp_wifi_set_config(WIFI_IF_NAN, &config), TAG, "Setting NAN config failed"); - - if (esp_wifi_start() != ESP_OK) { - ESP_LOGE(TAG, "Starting wifi failed"); NAN_DATA_LOCK(); - s_nan_ctx.nan_netif = NULL; + if (s_nan_ctx.state & NAN_STARTED_BIT) { + ESP_LOGI(TAG, "NAN already started"); + NAN_DATA_UNLOCK(); + return ESP_OK; + } NAN_DATA_UNLOCK(); - return ESP_FAIL; - } - EventBits_t bits = os_event_group_wait_bits(nan_event_group, NAN_STARTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY); - if (!(bits & NAN_STARTED_BIT)) { - NAN_DATA_LOCK(); - s_nan_ctx.nan_netif = NULL; - NAN_DATA_UNLOCK(); - return ESP_FAIL; + ESP_RETURN_ON_ERROR(esp_wifi_set_mode(WIFI_MODE_NAN), TAG, "Set mode NAN failed"); + + memcpy(&config.nan, nan_cfg, sizeof(wifi_nan_config_t)); + ESP_RETURN_ON_ERROR(esp_wifi_set_config(WIFI_IF_NAN, &config), TAG, "Setting NAN config failed"); + + if (esp_wifi_start() != ESP_OK) { + ESP_LOGE(TAG, "Starting wifi failed"); + NAN_DATA_LOCK(); + s_nan_ctx.nan_netif = NULL; + NAN_DATA_UNLOCK(); + return ESP_FAIL; + } + + EventBits_t bits = os_event_group_wait_bits(nan_event_group, NAN_STARTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY); + if (!(bits & NAN_STARTED_BIT)) { + NAN_DATA_LOCK(); + s_nan_ctx.nan_netif = NULL; + NAN_DATA_UNLOCK(); + return ESP_FAIL; + } + return ESP_OK; } - return ESP_OK; +#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ + return ESP_FAIL; } esp_err_t esp_wifi_nan_stop(void) { +#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE + if (s_usd_in_progress) { + s_usd_in_progress = false; + esp_nan_usd_deinit(); + ESP_RETURN_ON_ERROR(esp_wifi_stop(), TAG, "Stopping NAN-USD failed"); + ESP_LOGI(TAG, "NaN-USD Stopped"); + return ESP_OK; + } +#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ + +#ifdef CONFIG_ESP_WIFI_NAN_ENABLE NAN_DATA_LOCK(); if (!(s_nan_ctx.state & NAN_STARTED_BIT)) { ESP_LOGE(TAG, "NAN isn't started"); @@ -871,43 +930,79 @@ esp_err_t esp_wifi_nan_stop(void) NAN_DATA_LOCK(); memset(&s_nan_ctx, 0, sizeof(nan_ctx_t)); NAN_DATA_UNLOCK(); +#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ return ESP_OK; } uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg) { - uint8_t pub_id; + int pub_id; + if (publish_cfg->usd_discovery_flag && !s_usd_in_progress) { + ESP_LOGE(TAG, "Can not start Publish function with USD Discovery " + "when USD is not enabled"); + return 0; + } + + if (!publish_cfg->usd_discovery_flag && s_usd_in_progress) { + // XXX Add support for NAN-Sync and NAN-USD concurrent discovery + ESP_LOGE(TAG, "Can not start Publish function with " + "NAN-Synchronization Discovery when USD is enabled"); + return 0; + } + + if ((publish_cfg->ssi_len && publish_cfg->ssi == NULL) || + (publish_cfg->ssi && + (!publish_cfg->ssi_len || + publish_cfg->ssi_len > ESP_WIFI_MAX_SVC_SSI_LEN))) { + ESP_LOGE(TAG, "Configured ssi and ssi_len(%d) incorrect", + publish_cfg->ssi_len); + return 0; + } + + if (publish_cfg->ssi && + !memcmp(publish_cfg->ssi, s_wfa_oui, sizeof(s_wfa_oui))) { + /* WFA defined Service Specific Info */ + wifi_nan_wfa_ssi_t *wfa_ssi = (wifi_nan_wfa_ssi_t *)publish_cfg->ssi; + if (wfa_ssi->proto >= WIFI_SVC_PROTO_MAX) { + ESP_LOGI(TAG, "Unrecognized WFA Defined SSI protocol (%d)", + wfa_ssi->proto); + } + } + +#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE + if (s_usd_in_progress) { + if ((pub_id = esp_nan_usd_publish(publish_cfg)) == -1) { + ESP_LOGE(TAG, "Failed to publish service '%s'", + publish_cfg->service_name); + return 0; + } + ESP_LOGI(TAG, "Started Publishing %s [Service ID - %u]", + publish_cfg->service_name, pub_id); + return pub_id; + } +#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ + +#ifdef CONFIG_ESP_WIFI_NAN_ENABLE NAN_DATA_LOCK(); if (!(s_nan_ctx.state & NAN_STARTED_BIT)) { ESP_LOGE(TAG, "NAN not started!"); goto fail; } + if (nan_services_limit_reached()) { ESP_LOGE(TAG, "Maximum services limit reached"); goto fail; } if (nan_find_own_svc_by_name(publish_cfg->service_name)) { - ESP_LOGE(TAG, "Service name %s already used!", publish_cfg->service_name); + ESP_LOGE(TAG, "Service name %s already used!", + publish_cfg->service_name); goto fail; } - if ((publish_cfg->ssi_len && publish_cfg->ssi == NULL) || - (publish_cfg->ssi && (!publish_cfg->ssi_len || publish_cfg->ssi_len > ESP_WIFI_MAX_SVC_SSI_LEN))) { - ESP_LOGE(TAG, "Configured ssi and ssi_len(%d) incorrect", publish_cfg->ssi_len); - goto fail; - } - if (publish_cfg->ssi && !memcmp(publish_cfg->ssi, s_wfa_oui, sizeof(s_wfa_oui))) { - /* WFA defined Service Specific Info */ - wifi_nan_wfa_ssi_t *wfa_ssi = (wifi_nan_wfa_ssi_t *)publish_cfg->ssi; - if (wfa_ssi->proto >= WIFI_SVC_PROTO_MAX) { - ESP_LOGI(TAG, "Unrecognized WFA Defined SSI protocol (%d)", wfa_ssi->proto); - } - } - - if (esp_nan_internal_publish_service(publish_cfg, &pub_id, false) != ESP_OK) { + if (esp_nan_internal_publish_service(publish_cfg, (uint8_t *) &pub_id, false) != ESP_OK) { ESP_LOGE(TAG, "Failed to publish service '%s'", publish_cfg->service_name); goto fail; } @@ -920,12 +1015,55 @@ uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg) fail: NAN_DATA_UNLOCK(); return 0; +#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ + return 0; } uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe_cfg) { - uint8_t sub_id; + int sub_id; + if (subscribe_cfg->usd_discovery_flag && !s_usd_in_progress) { + ESP_LOGE(TAG, "Can not start Subscribe function with USD Discovery " + "when USD is not enabled"); + return 0; + } + + if (!subscribe_cfg->usd_discovery_flag && s_usd_in_progress) { + // XXX Add support for NAN-Sync and NAN-USD concurrent discovery + ESP_LOGE(TAG, "Can not start Subscribe function with " + "NAN-Synchronization Discovery when USD is enabled"); + return 0; + } + + if ((subscribe_cfg->ssi_len && subscribe_cfg->ssi == NULL) || + (subscribe_cfg->ssi && (!subscribe_cfg->ssi_len || subscribe_cfg->ssi_len > ESP_WIFI_MAX_SVC_SSI_LEN))) { + ESP_LOGE(TAG, "Configured ssi and ssi_len(%d) incorrect", subscribe_cfg->ssi_len); + return 0; + } + + if (subscribe_cfg->ssi && !memcmp(subscribe_cfg->ssi, s_wfa_oui, sizeof(s_wfa_oui))) { + /* WFA defined Service Specific Info */ + wifi_nan_wfa_ssi_t *wfa_ssi = (wifi_nan_wfa_ssi_t *)subscribe_cfg->ssi; + if (wfa_ssi->proto >= WIFI_SVC_PROTO_MAX) { + ESP_LOGI(TAG, "Unrecognized WFA Defined SSI protocol (%d)", wfa_ssi->proto); + } + } + +#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE + if (s_usd_in_progress) { + if ((sub_id = esp_nan_usd_subscribe(subscribe_cfg)) == -1) { + ESP_LOGE(TAG, "Failed to subscribe to service '%s'", + subscribe_cfg->service_name); + return 0; + } + ESP_LOGI(TAG, "Started Subscribing to %s [Service ID - %u]", + subscribe_cfg->service_name, sub_id); + return sub_id; + } +#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ + +#ifdef CONFIG_ESP_WIFI_NAN_ENABLE NAN_DATA_LOCK(); if (!(s_nan_ctx.state & NAN_STARTED_BIT)) { ESP_LOGE(TAG, "NAN not started!"); @@ -941,63 +1079,70 @@ uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe goto fail; } - if ((subscribe_cfg->ssi_len && subscribe_cfg->ssi == NULL) || - (subscribe_cfg->ssi && (!subscribe_cfg->ssi_len || subscribe_cfg->ssi_len > ESP_WIFI_MAX_SVC_SSI_LEN))) { - ESP_LOGE(TAG, "Configured ssi and ssi_len(%d) incorrect", subscribe_cfg->ssi_len); - goto fail; - } - if (subscribe_cfg->ssi && !memcmp(subscribe_cfg->ssi, s_wfa_oui, sizeof(s_wfa_oui))) { - /* WFA defined Service Specific Info */ - wifi_nan_wfa_ssi_t *wfa_ssi = (wifi_nan_wfa_ssi_t *)subscribe_cfg->ssi; - if (wfa_ssi->proto >= WIFI_SVC_PROTO_MAX) { - ESP_LOGI(TAG, "Unrecognized WFA Defined SSI protocol (%d)", wfa_ssi->proto); - } - } - - if (esp_nan_internal_subscribe_service(subscribe_cfg, &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); goto fail; } ESP_LOGI(TAG, "Started Subscribing to %s [Service ID - %u]", subscribe_cfg->service_name, sub_id); - nan_record_own_svc(sub_id, ESP_NAN_SUBSCRIBE, subscribe_cfg->service_name, false); + nan_record_own_svc((uint8_t) sub_id, ESP_NAN_SUBSCRIBE, subscribe_cfg->service_name, false); NAN_DATA_UNLOCK(); return sub_id; fail: NAN_DATA_UNLOCK(); return 0; +#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ + return 0; } esp_err_t esp_wifi_nan_send_message(wifi_nan_followup_params_t *fup_params) { - struct peer_svc_info *p_peer_svc; esp_err_t ret = ESP_OK; + if ((fup_params->ssi_len && fup_params->ssi == NULL) || + (fup_params->ssi && + (!fup_params->ssi_len || + fup_params->ssi_len > ESP_WIFI_MAX_FUP_SSI_LEN))) { + ESP_LOGE(TAG, "Configured ssi and ssi_len(%d) incorrect", + fup_params->ssi_len); + return ESP_FAIL; + } + + if (fup_params->ssi && + !memcmp(fup_params->ssi, s_wfa_oui, sizeof(s_wfa_oui))) { + /* WFA defined Service Specific Info */ + wifi_nan_wfa_ssi_t *wfa_ssi = (wifi_nan_wfa_ssi_t *)fup_params->ssi; + if (wfa_ssi->proto >= WIFI_SVC_PROTO_MAX) { + ESP_LOGI(TAG, "Unrecognized WFA Defined SSI protocol (%d)", + wfa_ssi->proto); + } + } + +#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE + if (s_usd_in_progress) { + if (esp_nan_usd_transmit(fup_params->inst_id, fup_params->ssi, + fup_params->ssi_len, fup_params->peer_mac, + fup_params->peer_inst_id) != ESP_OK) { + ESP_LOGE(TAG, "Failed to send Follow-up message!"); + return ESP_FAIL; + } + return ESP_OK; + } +#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ + +#ifdef CONFIG_ESP_WIFI_NAN_ENABLE + struct peer_svc_info *p_peer_svc; NAN_DATA_LOCK(); - p_peer_svc = nan_find_peer_svc(fup_params->inst_id, fup_params->peer_inst_id, - fup_params->peer_mac); + p_peer_svc = nan_find_peer_svc(fup_params->inst_id, + fup_params->peer_inst_id, fup_params->peer_mac); if (!p_peer_svc) { ESP_LOGE(TAG, "Cannot send Follow-up, peer not found!"); NAN_DATA_UNLOCK(); return ESP_FAIL; } - if ((fup_params->ssi_len && fup_params->ssi == NULL) || - (fup_params->ssi && (!fup_params->ssi_len || fup_params->ssi_len > ESP_WIFI_MAX_FUP_SSI_LEN))) { - ESP_LOGE(TAG, "Configured ssi and ssi_len(%d) incorrect", fup_params->ssi_len); - return ESP_FAIL; - } - - if (fup_params->ssi && !memcmp(fup_params->ssi, s_wfa_oui, sizeof(s_wfa_oui))) { - /* WFA defined Service Specific Info */ - wifi_nan_wfa_ssi_t *wfa_ssi = (wifi_nan_wfa_ssi_t *)fup_params->ssi; - if (wfa_ssi->proto >= WIFI_SVC_PROTO_MAX) { - ESP_LOGI(TAG, "Unrecognized WFA Defined SSI protocol (%d)", wfa_ssi->proto); - } - } - if (!fup_params->inst_id) { fup_params->inst_id = p_peer_svc->own_svc_id; } @@ -1018,9 +1163,12 @@ esp_err_t esp_wifi_nan_send_message(wifi_nan_followup_params_t *fup_params) EventBits_t bits = os_event_group_wait_bits(nan_event_group, NAN_TX_SUCCESS | NAN_TX_FAILURE, pdFALSE, pdFALSE, pdMS_TO_TICKS(NAN_ACTION_TIMEOUT)); if (bits & NAN_TX_SUCCESS) { if (fup_params->ssi) { - ESP_LOGD(TAG, "Sent below payload to Peer "MACSTR" with Service ID %d", + ESP_LOGD(TAG, "Sent below payload in Follow-up message to Peer "MACSTR" with Service ID %d", MAC2STR(fup_params->peer_mac), fup_params->peer_inst_id); ESP_LOG_BUFFER_HEXDUMP(TAG, fup_params->ssi, fup_params->ssi_len, ESP_LOG_DEBUG); + } else { + ESP_LOGI(TAG, "Sent message to Peer "MACSTR" with Service ID %d", + MAC2STR(fup_params->peer_mac), fup_params->peer_inst_id); } ret = ESP_OK; } else if (bits & NAN_TX_FAILURE) { @@ -1030,12 +1178,20 @@ esp_err_t esp_wifi_nan_send_message(wifi_nan_followup_params_t *fup_params) ESP_LOGE(TAG, "Timeout, failed to send Follow-up message!"); ret = ESP_FAIL; } +#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ return ret; } esp_err_t esp_wifi_nan_cancel_service(uint8_t service_id) { +#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE + if (s_usd_in_progress) { + return esp_nan_usd_cancel_service(service_id); + } + else +#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ +#ifdef CONFIG_ESP_WIFI_NAN_ENABLE NAN_DATA_LOCK(); struct own_svc_info *p_own_svc = nan_find_own_svc(service_id); @@ -1067,8 +1223,12 @@ fail: done: NAN_DATA_UNLOCK(); return ESP_OK; +#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ + return ESP_FAIL; } + +#ifdef CONFIG_ESP_WIFI_NAN_ENABLE uint8_t esp_wifi_nan_datapath_req(wifi_nan_datapath_req_t *req) { uint8_t ndp_id = 0; @@ -1337,3 +1497,58 @@ esp_err_t esp_wifi_nan_get_peer_info(char *svc_name, uint8_t *peer_mac, struct n return ESP_FAIL; } } +#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ + +#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE +wifi_nan_usd_config_t esp_wifi_usd_get_default_publish_cfg(void) +{ + wifi_country_t country; + uint8_t start_chan, end_chan; + + wifi_nan_usd_config_t cfg = { + .usd_default_channel = 6, + .n_min = 5, + .n_max = 10, + .m_min = 5, + .m_max = 10, + }; + + esp_wifi_get_country(&country); + start_chan = country.schan; + end_chan = country.schan + country.nchan - 1; + for (uint8_t chan = start_chan; chan <= end_chan; chan++) { + cfg.usd_chan_bitmap.ghz_2_channels |= CHANNEL_TO_BIT(chan); + } +#if CONFIG_SOC_WIFI_SUPPORT_5G + cfg.usd_chan_bitmap.ghz_5_channels = country.wifi_5g_channel_mask; +#endif + + return cfg; +} + +wifi_nan_usd_config_t esp_wifi_usd_get_default_subscribe_cfg(void) +{ + wifi_country_t country; + uint8_t start_chan, end_chan; + + wifi_nan_usd_config_t cfg = { + .usd_default_channel = 6, + .n_min = 5, + .n_max = 10, + .m_min = 5, + .m_max = 10 + }; + + esp_wifi_get_country(&country); + start_chan = country.schan; + end_chan = country.schan + country.nchan - 1; + for (uint8_t chan = start_chan; chan <= end_chan; chan++) { + cfg.usd_chan_bitmap.ghz_2_channels |= CHANNEL_TO_BIT(chan); + } +#if CONFIG_SOC_WIFI_SUPPORT_5G + cfg.usd_chan_bitmap.ghz_5_channels = country.wifi_5g_channel_mask; +#endif + + return cfg; +} +#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index ff4659ee42e..3ebc9155bbb 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -240,12 +240,21 @@ else() set(wps_registrar_src "") endif() +if(CONFIG_ESP_WIFI_NAN_USD_ENABLE) + set(usd_src + "src/common/nan_de.c" + "esp_supplicant/src/esp_nan_usd.c") +else() + set(usd_src "") +endif() + idf_component_register(SRCS "${srcs}" "${esp_srcs}" "${tls_src}" "${roaming_src}" - "${crypto_src}" "${mbo_src}" "${dpp_src}" "${wps_registrar_src}" + "${crypto_src}" "${mbo_src}" "${dpp_src}" "${wps_registrar_src}" "${usd_src}" INCLUDE_DIRS include port/include esp_supplicant/include PRIV_INCLUDE_DIRS src src/utils esp_supplicant/src src/crypto ../esp_wifi/wifi_apps/roaming_app/include ../esp_wifi/wifi_apps/roaming_app/src + esp_supplicant/include/esp_private LDFRAGMENTS ${linker_fragments} PRIV_REQUIRES mbedtls esp_timer esp_wifi) @@ -349,6 +358,9 @@ endif() if(CONFIG_ESP_WIFI_EAP_TLS1_3) target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_TLSV13) endif() +if(CONFIG_ESP_WIFI_NAN_USD_ENABLE) + target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_NAN_USD) +endif() set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 3) target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/components/wpa_supplicant/esp_supplicant/include/esp_private/esp_nan_usd.h b/components/wpa_supplicant/esp_supplicant/include/esp_private/esp_nan_usd.h new file mode 100644 index 00000000000..fbb89146245 --- /dev/null +++ b/components/wpa_supplicant/esp_supplicant/include/esp_private/esp_nan_usd.h @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_err.h" +#include "esp_wifi_types.h" + +#define GLOBAL_OPERATING_CLASS_81 81 + +#define ESP_USD_SUBSCRIBE_DEFAULT_PARAMS() { \ + .active = false, \ + .ttl = 0, \ + .freq = NAN_USD_DEFAULT_FREQ, \ + .query_period = 0, \ +}; + +#define ESP_USD_PUBLISH_DEFAULT_PARAMS() { \ + .unsolicited = true, \ + .solicited = true, \ + .ttl = 100, \ + .fsd = true, \ + .freq = NAN_USD_DEFAULT_FREQ, \ + .freq_list = NULL, \ +}; + +/* Note: These NaN-USD APIs are intended for internal use only. + * For application development, use the public APIs provided in: + * 'wifi_apps/nan_app/include/esp_nan.h' + */ +esp_err_t esp_nan_usd_init(void); + +esp_err_t esp_nan_usd_deinit(void); + +int esp_nan_usd_publish(const wifi_nan_publish_cfg_t *publish_cfg); + +esp_err_t esp_nan_usd_cancel_publish(int publish_id); + +int esp_nan_usd_subscribe(const wifi_nan_subscribe_cfg_t *subscribe_cfg); + +esp_err_t esp_nan_usd_cancel_subscribe(int subscribe_id); + +esp_err_t esp_nan_usd_transmit(int handle, const uint8_t *ssi, uint16_t ssi_len, + const uint8_t *peer_addr, uint8_t req_instance_id); + +esp_err_t esp_nan_usd_cancel_service(int service_id); +#ifdef __cplusplus +} +#endif diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_nan_usd.c b/components/wpa_supplicant/esp_supplicant/src/esp_nan_usd.c new file mode 100644 index 00000000000..92a95a00ac6 --- /dev/null +++ b/components/wpa_supplicant/esp_supplicant/src/esp_nan_usd.c @@ -0,0 +1,678 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_wifi.h" +#include "esp_check.h" +#include "esp_nan_usd.h" +#include "common/nan_de.h" +#include "esp_wifi_driver.h" +#include "common/ieee802_11_common.h" +#include "utils/eloop.h" +#include "esp_nan.h" + +struct nan_de *g_nan_de = NULL; + +static void *s_nan_usd_data_lock = NULL; +#define NAN_USD_DATA_LOCK() os_mutex_lock(s_nan_usd_data_lock) +#define NAN_USD_DATA_UNLOCK() os_mutex_unlock(s_nan_usd_data_lock) + +#ifdef DEBUG_PRINT +static const char *nan_reason_txt(enum nan_de_reason reason) +{ + switch (reason) { + case NAN_DE_REASON_TIMEOUT: + return "timeout"; + case NAN_DE_REASON_USER_REQUEST: + return "user-request"; + case NAN_DE_REASON_FAILURE: + return "failure"; + } + + return "unknown"; +} +#endif /* DEBUG_PRINT */ +static void nan_sta_stop_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + if (event_id == WIFI_EVENT_STA_STOP) { + esp_wifi_nan_stop(); + } +} + +/* Per section 4.5.3 of the Wi-Fi Aware Specification v4.0 (NaN-USD), + * only 20 MHz bandwidth channels are permitted for NAN-USD operation + * in both the 2.4 GHz and 5 GHz frequency bands. + * */ +static int esp_nan_chan_to_freq(uint8_t chan) +{ + // 2.4 GHz band + if (chan >= 1 && chan <= 13) { + return 2407 + 5 * chan; + } else if (chan == 14) { + return 2414 + 5 * chan; + } + + // 5 GHz band — standard 20 MHz channel ranges + if ((chan >= 36 && chan <= 64) || + (chan >= 100 && chan <= 144) || + (chan >= 149 && chan <= 165)) { + return 5000 + chan * 5; + } + + return -1; +} + +static int esp_nan_freq_to_chan(int freq) +{ + // 2.4 GHz band + if (freq >= 2412 && freq <= 2472) { + return (freq - 2407) / 5; + } else if (freq == 2484) { + return 14; + } + + // 5 GHz band + if ((freq >= 5180 && freq <= 5240) || // Channels 36–64 + (freq >= 5500 && freq <= 5720) || // Channels 100–144 + (freq >= 5745 && freq <= 5825)) { // Channels 149–165 + return (freq - 5000) / 5; + } + return -1; +} + +static void nan_de_tx_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + if (event_id == WIFI_EVENT_ACTION_TX_STATUS) { + wifi_event_action_tx_status_t *evt = (wifi_event_action_tx_status_t *)event_data; + if (evt->status == WIFI_ACTION_TX_DONE) { + int freq = esp_nan_chan_to_freq(evt->channel); + if (freq == -1) { + wpa_printf(MSG_ERROR, "Invalid channel received from Action Tx handler"); + return; + } + NAN_USD_DATA_LOCK(); + nan_de_tx_status(g_nan_de, freq, NULL); + NAN_USD_DATA_UNLOCK(); + } else if (evt->status == WIFI_ACTION_TX_DURATION_COMPLETED) { + NAN_USD_DATA_LOCK(); + nan_de_tx_wait_ended(g_nan_de); + NAN_USD_DATA_UNLOCK(); + } + } else if (event_id == WIFI_EVENT_ROC_DONE) { + wifi_event_roc_done_t *evt = (wifi_event_roc_done_t *)event_data; + int freq = esp_nan_chan_to_freq(evt->channel); + if (freq == -1) { + wpa_printf(MSG_ERROR, "Invalid channel received from ROC done handler"); + } + NAN_USD_DATA_LOCK(); + nan_de_listen_ended(g_nan_de, freq); + NAN_USD_DATA_UNLOCK(); + } +} + +int esp_nan_de_rx_action(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel) +{ + struct ieee80211_hdr *rx_hdr = (struct ieee80211_hdr *)hdr; + int freq; + + if (len < 6) { + /* Frame too short for NAN-SDF frame */ + return ESP_FAIL; + } + /* NAN SDF + * Category code - 1 byte + * Public Action - 1 byte + * OUI - 3 bytes + * WFA subtype - 1 byte + * NAN PROTOCOL - Variable */ + + uint8_t category = *payload++; + uint8_t public_action = *payload++; + uint32_t oui_value = WPA_GET_BE24(payload); + payload += 3; + uint8_t oui_type = *payload++; + + if (category == WLAN_ACTION_PUBLIC && + public_action == WLAN_PA_VENDOR_SPECIFIC && + oui_value == OUI_WFA && + oui_type == NAN_OUI_TYPE) { + /* Received a valid NAN Service Discovery Frame */ + } else { + /* Frame is not a NAN SDF frame */ + return ESP_FAIL; + } + + freq = esp_nan_chan_to_freq(channel); + if (freq == -1) { + wpa_printf(MSG_ERROR, "Invalid channel from Rx action frame"); + return ESP_FAIL; + } + + NAN_USD_DATA_LOCK(); + nan_de_rx_sdf(g_nan_de, rx_hdr->addr2, rx_hdr->addr3, freq, payload, len - 6); + NAN_USD_DATA_UNLOCK(); + return ESP_OK; +} + +static int esp_nan_de_tx(void *ctx, unsigned int freq, unsigned int wait_time, + const u8 *dst, const u8 *src, const u8 *bssid, + const struct wpabuf *buf) +{ + int buf_len = buf->used; + int channel; + + wifi_action_tx_req_t *req = os_zalloc(sizeof(*req) + buf_len); + if (!req) { + wpa_printf(MSG_ERROR, "Allocation for tx request failed"); + return ESP_FAIL; + } + + req->ifx = WIFI_IF_STA; + req->type = WIFI_OFFCHAN_TX_REQ; + req->wait_time_ms = wait_time; + memcpy(req->dest_mac, dst, ETH_ALEN); + req->no_ack = false; + req->data_len = buf_len; + req->rx_cb = esp_nan_de_rx_action; + memcpy(req->data, buf->buf, buf_len); + + channel = esp_nan_freq_to_chan(freq); + if (channel == -1) { + wpa_printf(MSG_ERROR, "Could not determine channel for freq %d", freq); + os_free(req); + return ESP_FAIL; + } + req->channel = channel; + + if (esp_wifi_action_tx_req(req) != ESP_OK) { + wpa_printf(MSG_ERROR, "Offchannel tx request failed"); + os_free(req); + return ESP_FAIL; + } + + os_free(req); + return ESP_OK; +} + +static int esp_nan_de_listen(void *ctx, unsigned int freq, unsigned int duration) +{ + int channel; + + channel = esp_nan_freq_to_chan(freq); + if (channel == -1) { + wpa_printf(MSG_ERROR, "Could not determine channel for freq %d", freq); + return ESP_FAIL; + } + + wifi_roc_req_t *req = os_zalloc(sizeof(wifi_roc_req_t)); + if (req == NULL) { + wpa_printf(MSG_ERROR, "Failed to allocate for ROC request"); + return ESP_FAIL; + } + req->ifx = WIFI_IF_STA; + req->type = WIFI_ROC_REQ; + req->channel = channel; + req->wait_time_ms = duration; + req->rx_cb = esp_nan_de_rx_action; + req->done_cb = NULL; + req->allow_broadcast = true; + + if (esp_wifi_remain_on_channel(req) != ESP_OK) { + wpa_printf(MSG_ERROR, "ROC request failure"); + os_free(req); + return ESP_FAIL; + } + + NAN_USD_DATA_LOCK(); + nan_de_listen_started(g_nan_de, freq, duration); + NAN_USD_DATA_UNLOCK(); + os_free(req); + return ESP_OK; +} + +static void esp_nan_de_discovery_result(void *ctx, int subscribe_id, enum nan_service_protocol_type srv_proto_type, + const u8 *ssi, size_t ssi_len, int peer_publish_id, const u8 *peer_addr, bool fsd, bool fsd_gas) +{ + wpa_printf(MSG_INFO, "NAN_USD DISCOVERY_RESULT - subscribe_id = %d peer_publish_id = %d peer_address = "MACSTR" service_protocol_type = %d", + subscribe_id, peer_publish_id, MAC2STR(peer_addr), srv_proto_type); + + wifi_event_nan_svc_match_t *evt = os_zalloc(sizeof(wifi_event_nan_svc_match_t) + ssi_len); + if (evt == NULL) { + return; + } + evt->subscribe_id = subscribe_id; + evt->publish_id = peer_publish_id; + memcpy(evt->pub_if_mac, peer_addr, ETH_ALEN); + if (ssi && ssi_len) { + memcpy(evt->ssi, ssi, ssi_len); + evt->ssi_len = ssi_len; + } + esp_event_post(WIFI_EVENT, WIFI_EVENT_NAN_SVC_MATCH, evt, sizeof(wifi_event_nan_svc_match_t) + ssi_len, portMAX_DELAY); + os_free(evt); +} + +static void esp_nan_de_replied(void *ctx, int publish_id, const u8 *peer_addr, + int peer_subscribe_id, + enum nan_service_protocol_type srv_proto_type, + const u8 *ssi, size_t ssi_len) +{ + + wpa_printf(MSG_INFO, "NAN_USD REPLIED - publish_id = %d peer_subscribe_id = %d peer_address = "MACSTR" service_protocol_type = %d", + publish_id, peer_subscribe_id, MAC2STR(peer_addr), srv_proto_type); + + wifi_event_nan_replied_t *evt = os_zalloc(sizeof(wifi_event_nan_replied_t) + ssi_len); + if (evt == NULL) { + return; + } + evt->publish_id = publish_id; + evt->subscribe_id = peer_subscribe_id; + memcpy(evt->sub_if_mac, peer_addr, ETH_ALEN); + if (ssi && ssi_len) { + memcpy(evt->ssi, ssi, ssi_len); + evt->ssi_len = ssi_len; + } + esp_event_post(WIFI_EVENT, WIFI_EVENT_NAN_REPLIED, evt, sizeof(wifi_event_nan_replied_t) + ssi_len, portMAX_DELAY); + os_free(evt); +} + +static void esp_nan_de_publish_terminated(void *ctx, int publish_id, + enum nan_de_reason reason) +{ + wpa_printf(MSG_INFO, "NAN_USD PUBLISH_TERMINATED - publish_id = %d reason = %s", publish_id, nan_reason_txt(reason)); +} + +static void esp_nan_de_subscribe_terminated(void *ctx, int subscribe_id, + enum nan_de_reason reason) +{ + wpa_printf(MSG_INFO, "NAN_USD SUBSCRIBE_TERMINATED - subscribe_id = %d reason = %s", subscribe_id, nan_reason_txt(reason)); +} + +static void esp_nan_de_receive(void *ctx, int id, int peer_instance_id, + const u8 *ssi, size_t ssi_len, + const u8 *peer_addr) +{ + wpa_hexdump(MSG_INFO, "NAN_RECEIVE", ssi, ssi_len); + + wifi_event_nan_receive_t *evt = os_zalloc(sizeof(wifi_event_nan_receive_t) + ssi_len); + if (evt == NULL) { + return; + } + evt->inst_id = id; + evt->peer_inst_id = peer_instance_id; + memcpy(evt->peer_if_mac, peer_addr, ETH_ALEN); + if (ssi && ssi_len) { + memcpy(evt->ssi, ssi, ssi_len); + evt->ssi_len = ssi_len; + } + esp_event_post(WIFI_EVENT, WIFI_EVENT_NAN_RECEIVE, evt, sizeof(wifi_event_nan_receive_t) + ssi_len, portMAX_DELAY); + os_free(evt); +} + +esp_err_t esp_nan_usd_deinit() +{ + + NAN_USD_DATA_LOCK(); + if (!g_nan_de) { + NAN_USD_DATA_UNLOCK(); + return ESP_FAIL; + } + + nan_de_deinit(g_nan_de); + g_nan_de = NULL; + NAN_USD_DATA_UNLOCK(); + + if (s_nan_usd_data_lock) { + os_mutex_delete(s_nan_usd_data_lock); + s_nan_usd_data_lock = NULL; + } + + esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_ACTION_TX_STATUS, &nan_de_tx_event_handler); + esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_ROC_DONE, &nan_de_tx_event_handler); + esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_STOP, + &nan_sta_stop_handler); + + return ESP_OK; +} + +esp_err_t esp_nan_usd_init(void) +{ + struct nan_callbacks cb; + uint8_t mac[ETH_ALEN]; +#ifndef ESP_SUPPLICANT + bool offload = wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD; +#else + bool offload = false; +#endif + int max_listen = 1000; // default supplicant value; hardcoded for now + + os_memset(&cb, 0, sizeof(cb)); + cb.ctx = NULL; + cb.tx = esp_nan_de_tx; + cb.listen = esp_nan_de_listen; + cb.discovery_result = esp_nan_de_discovery_result; + cb.replied = esp_nan_de_replied; + cb.publish_terminated = esp_nan_de_publish_terminated; + cb.subscribe_terminated = esp_nan_de_subscribe_terminated; + cb.receive = esp_nan_de_receive; + + s_nan_usd_data_lock = os_recursive_mutex_create(); + if (!s_nan_usd_data_lock) { + ESP_LOGE("NAN-USD", "Failed to create NAN-USD data lock"); + return ESP_FAIL; + } + + ESP_RETURN_ON_ERROR(esp_wifi_get_mac(WIFI_IF_STA, mac), "NAN-USD", "Fetching MAC of STA ifx failed"); + g_nan_de = nan_de_init(mac, offload, false, max_listen, &cb); + if (!g_nan_de) { + return ESP_FAIL; + } + esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_ACTION_TX_STATUS, + &nan_de_tx_event_handler, NULL); + esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_ROC_DONE, + &nan_de_tx_event_handler, NULL); + esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_STOP, + &nan_sta_stop_handler, NULL); + + return ESP_OK; +} + +int esp_nan_get_freq_list(int *freq_list, const uint8_t *chan_list, uint8_t chan_list_len) +{ + int freq, freq_ind = 0; + for (int i = 0; i < chan_list_len; i++) { + freq = esp_nan_chan_to_freq(chan_list[i]); + if (freq != -1) { + freq_list[freq_ind++] = freq; + } + } + freq_list[freq_ind++] = 0; + return freq_ind; +} + +static int esp_nan_usd_publish_internal(const char *service_name, enum nan_service_protocol_type srv_proto_type, + unsigned int ttl, uint8_t *ssi, uint16_t ssi_len, uint8_t default_channel, + const wifi_scan_channel_bitmap_t channel_bitmap) +{ + int publish_id; + struct wpabuf *buf = NULL; + int freq, *freq_list = NULL; + struct nan_publish_params pub_params = ESP_USD_PUBLISH_DEFAULT_PARAMS(); + bool p2p = false; + uint8_t i = 0, chan_list_len; + uint8_t bitmap_idx_2g = 1; // BIT-0 is not used in channel bitmap + uint16_t channel_2ghz_bitmap; +#if CONFIG_SOC_WIFI_SUPPORT_5G + uint8_t bitmap_idx_5g = 1; // BIT-0 is not used in channel bitmap + uint32_t channel_5ghz_bitmap; +#endif + + NAN_USD_DATA_LOCK(); + if (!g_nan_de) { + goto fail; + } + + pub_params.ttl = ttl; + if (ssi && ssi_len) { + buf = wpabuf_alloc(ssi_len); + if (!buf) { + wpa_printf(MSG_ERROR, "Allocating memory failed for NaN-USD Publish"); + goto fail; + } + wpabuf_put_data(buf, ssi, ssi_len); + } + + freq = esp_nan_chan_to_freq(default_channel); + if (freq != -1) { + pub_params.freq = freq; + } else { + pub_params.freq = NAN_USD_DEFAULT_FREQ; + } + + channel_2ghz_bitmap = channel_bitmap.ghz_2_channels; + channel_2ghz_bitmap &= ~BIT(0); // BIT-0 is not used for channel + chan_list_len = __builtin_popcount(channel_2ghz_bitmap); + +#if CONFIG_SOC_WIFI_SUPPORT_5G + channel_5ghz_bitmap = channel_bitmap.ghz_5_channels; + channel_5ghz_bitmap &= ~BIT(0); // BIT-0 is not used for channel + chan_list_len += __builtin_popcount(channel_5ghz_bitmap); +#endif + + if (chan_list_len) { + uint8_t chan_list[chan_list_len]; + while (channel_2ghz_bitmap) { + bitmap_idx_2g = __builtin_ctz(channel_2ghz_bitmap); + uint8_t chan_num = BIT_NUMBER_TO_CHANNEL(bitmap_idx_2g, WIFI_BAND_2G); + if (chan_num != 0) { + chan_list[i++] = chan_num; + } + channel_2ghz_bitmap &= ~BIT(bitmap_idx_2g); + } +#if CONFIG_SOC_WIFI_SUPPORT_5G + while (channel_5ghz_bitmap) { + bitmap_idx_5g = __builtin_ctz(channel_5ghz_bitmap); + uint8_t chan_num = BIT_NUMBER_TO_CHANNEL(bitmap_idx_5g, WIFI_BAND_5G); + if (chan_num != 0) { + chan_list[i++] = chan_num; + } + channel_5ghz_bitmap &= ~BIT(bitmap_idx_5g); + } +#endif + + chan_list_len = i; + freq_list = (int *)os_malloc(sizeof(int) * (chan_list_len + 1)); + if (freq_list) { + esp_nan_get_freq_list(freq_list, chan_list, chan_list_len); + pub_params.freq_list = freq_list; + } else { + wpa_printf(MSG_ERROR, "Allocating memory failed for frequency list"); + wpabuf_free(buf); + goto fail; + } + } + + publish_id = nan_de_publish(g_nan_de, service_name, srv_proto_type, + buf, NULL, &pub_params, p2p); + + wpabuf_free(buf); + if (freq_list) { + os_free(freq_list); + } + NAN_USD_DATA_UNLOCK(); + return publish_id; +fail: + NAN_USD_DATA_UNLOCK(); + return -1; +} + +int esp_nan_usd_publish(const wifi_nan_publish_cfg_t *publish_cfg) +{ + return esp_nan_usd_publish_internal(publish_cfg->service_name, WIFI_SVC_PROTO_RESERVED, + publish_cfg->ttl, publish_cfg->ssi, + publish_cfg->ssi_len, publish_cfg->usd_publish_config.usd_default_channel, + publish_cfg->usd_publish_config.usd_chan_bitmap); +} + +esp_err_t esp_nan_usd_update_publish(int publish_id, uint8_t *ssi, uint16_t ssi_len) +{ + struct wpabuf *buf = NULL; + esp_err_t ret; + + NAN_USD_DATA_LOCK(); + if (!g_nan_de) { + goto fail; + } + + if (ssi && ssi_len) { + buf = wpabuf_alloc(ssi_len); + if (!buf) { + wpa_printf(MSG_ERROR, "Allocating memory failed for NaN-USD Update Publish"); + goto fail; + } + wpabuf_put_data(buf, ssi, ssi_len); + } + + ret = nan_de_update_publish(g_nan_de, publish_id, buf); + wpabuf_free(buf); + NAN_USD_DATA_UNLOCK(); + return ret; +fail: + NAN_USD_DATA_UNLOCK(); + return ESP_FAIL; +} + +esp_err_t esp_nan_usd_cancel_publish(int publish_id) +{ + NAN_USD_DATA_LOCK(); + if (!g_nan_de) { + NAN_USD_DATA_UNLOCK(); + return ESP_FAIL; + } + + nan_de_cancel_publish(g_nan_de, publish_id); + NAN_USD_DATA_UNLOCK(); + return ESP_OK; +} + +/* Note: Our USD implementation uses the Service Protocol Type provided in SSI. + * The 'srv_proto_type' parameter will be ignored. + */ +static int esp_nan_usd_subscribe_internal(const char *service_name, enum nan_service_protocol_type srv_proto_type, + unsigned int ttl, uint8_t default_channel, uint8_t *ssi, uint16_t ssi_len, + const wifi_scan_channel_bitmap_t channel_bitmap) +{ + int subscribe_id; + struct wpabuf *buf = NULL; + int freq, *freq_list = NULL; + /* USD Specification allows either active or passive mode for subscriber. + * By default USD-Subscriber will be in passive mode */ + struct nan_subscribe_params sub_params = ESP_USD_SUBSCRIBE_DEFAULT_PARAMS(); + bool p2p = false; + uint8_t i = 0, chan_list_len; + uint8_t bitmap_idx_2g = 1; // BIT-0 is not used in channel bitmap + uint16_t channel_2ghz_bitmap; + + NAN_USD_DATA_LOCK(); + if (!g_nan_de) { + goto fail; + } + + sub_params.ttl = ttl; + freq = esp_nan_chan_to_freq(default_channel); + if (freq != -1) { + sub_params.freq = freq; + } else { + sub_params.freq = NAN_USD_DEFAULT_FREQ; + } + + if (ssi && ssi_len) { + buf = wpabuf_alloc(ssi_len); + if (!buf) { + wpa_printf(MSG_ERROR, "Allocating memory failed for NaN-USD Subscribe"); + goto fail; + } + wpabuf_put_data(buf, ssi, ssi_len); + } + + channel_2ghz_bitmap = channel_bitmap.ghz_2_channels; + channel_2ghz_bitmap &= ~BIT(0); // BIT-0 is not used for channel + chan_list_len = __builtin_popcount(channel_2ghz_bitmap); + if (chan_list_len) { + uint8_t chan_list[chan_list_len]; + while (channel_2ghz_bitmap) { + bitmap_idx_2g = __builtin_ctz(channel_2ghz_bitmap); + uint8_t chan_num = BIT_NUMBER_TO_CHANNEL(bitmap_idx_2g, WIFI_BAND_2G); + if (chan_num != 0) { + chan_list[i++] = chan_num; + } + channel_2ghz_bitmap &= ~BIT(bitmap_idx_2g); + } + freq_list = (int *)os_malloc(sizeof(int) * (chan_list_len + 1)); + if (freq_list) { + esp_nan_get_freq_list(freq_list, chan_list, chan_list_len); + sub_params.freq_list = freq_list; + } else { + wpa_printf(MSG_ERROR, "Allocating memory failed for frequency list"); + wpabuf_free(buf); + goto fail; + } + } + + subscribe_id = nan_de_subscribe(g_nan_de, service_name, srv_proto_type, buf, NULL, &sub_params, p2p); + + wpabuf_free(buf); + if (freq_list) { + os_free(freq_list); + } + NAN_USD_DATA_UNLOCK(); + return subscribe_id; +fail: + NAN_USD_DATA_UNLOCK(); + return -1; +} + +int esp_nan_usd_subscribe(const wifi_nan_subscribe_cfg_t *subscribe_cfg) +{ + return esp_nan_usd_subscribe_internal(subscribe_cfg->service_name, WIFI_SVC_PROTO_RESERVED, subscribe_cfg->ttl, + subscribe_cfg->usd_subscribe_config.usd_default_channel, subscribe_cfg->ssi, subscribe_cfg->ssi_len, + subscribe_cfg->usd_subscribe_config.usd_chan_bitmap); +} + +esp_err_t esp_nan_usd_cancel_subscribe(int subscribe_id) +{ + NAN_USD_DATA_LOCK(); + if (!g_nan_de) { + NAN_USD_DATA_UNLOCK(); + return ESP_FAIL; + } + + nan_de_cancel_subscribe(g_nan_de, subscribe_id); + NAN_USD_DATA_UNLOCK(); + return ESP_OK; +} + +esp_err_t esp_nan_usd_cancel_service(int service_id) +{ + NAN_USD_DATA_LOCK(); + if (!g_nan_de) { + NAN_USD_DATA_UNLOCK(); + return ESP_FAIL; + } + + nan_de_cancel_service(g_nan_de, service_id); + NAN_USD_DATA_UNLOCK(); + return ESP_OK; +} + +esp_err_t esp_nan_usd_transmit(int handle, const uint8_t *ssi, uint16_t ssi_len, const u8 *peer_addr, u8 req_instance_id) +{ + struct wpabuf *buf = NULL; + esp_err_t ret; + + NAN_USD_DATA_LOCK(); + if (!g_nan_de || !peer_addr) { + goto fail; + } + + if (ssi && ssi_len) { + buf = wpabuf_alloc(ssi_len); + if (!buf) { + wpa_printf(MSG_ERROR, "Allocating memory failed for NaN-USD transmit"); + goto fail; + } + wpabuf_put_data(buf, ssi, ssi_len); + } + + ret = nan_de_transmit(g_nan_de, handle, buf, NULL, peer_addr, req_instance_id); + + wpabuf_free(buf); + NAN_USD_DATA_UNLOCK(); + return ret; +fail: + NAN_USD_DATA_UNLOCK(); + return ESP_FAIL; +} diff --git a/components/wpa_supplicant/src/common/nan_de.c b/components/wpa_supplicant/src/common/nan_de.c index 0098eb8a926..8afe7d96714 100644 --- a/components/wpa_supplicant/src/common/nan_de.c +++ b/components/wpa_supplicant/src/common/nan_de.c @@ -15,6 +15,7 @@ #include "ieee802_11_defs.h" #include "nan.h" #include "nan_de.h" +#include "ctype.h" static const u8 nan_network_id[ETH_ALEN] = { 0x51, 0x6f, 0x9a, 0x01, 0x00, 0x00 }; @@ -282,6 +283,12 @@ static void nan_de_tx_sdf(struct nan_de *de, struct nan_de_service *srv, wpabuf_put_le16(buf, sdea_ctrl); if (ssi) { #ifdef ESP_SUPPLICANT + /* Note: In our NaN-USD implementation, the user-provided SSI value must + * include both the OUI and the Service Protocol Type. + * This differs from the upstream wpa_supplicant implementation, where + * the USD supplicant driver constructs the SSI internally using the + * Wi-Fi OUI and a separately provided srv_proto_type. + */ wpabuf_put_le16(buf, wpabuf_len(ssi)); wpabuf_put_buf(buf, ssi); #else @@ -544,9 +551,11 @@ static int nan_de_srv_time_to_next(struct nan_de *de, if (os_reltime_initialized(&srv->next_publish_state)) { os_reltime_sub(&srv->next_publish_state, now, &diff); +#ifndef ESP_SUPPLICANT if (diff.sec < 0 || (diff.sec == 0 && diff.usec < 0)) tmp = 0; else +#endif /* ESP_SUPPLICANT */ tmp = os_reltime_in_ms(&diff); if (next == -1 || tmp < next) next = tmp; @@ -656,7 +665,9 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx) if (srv_next == 0 && !started && !de->offload && de->listen_freq == 0 && de->ext_listen_freq == 0 && +#ifndef ESP_SUPPLICANT de->tx_wait_end_freq == 0 && +#endif nan_de_next_multicast(de, srv, &now) == 0) { started = true; nan_de_tx_multicast(de, srv, 0); @@ -1001,6 +1012,12 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv, wpabuf_put_le16(buf, sdea_ctrl); if (srv->ssi) { #ifdef ESP_SUPPLICANT + /* Note: In our NaN-USD implementation, the SSI value must + * include both the OUI and the Service Protocol Type. + * This differs from the upstream wpa_supplicant implementation, where + * the USD supplicant driver constructs the SSI internally using the + * Wi-Fi OUI and a separately provided srv_proto_type. + */ wpabuf_put_le16(buf, wpabuf_len(srv->ssi)); wpabuf_put_buf(buf, srv->ssi); #else @@ -1038,7 +1055,18 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv, de->nmi, a3, buf); wpabuf_free(buf); - nan_de_pause_state(srv, peer_addr, instance_id); + if (!srv->is_p2p) { +#ifdef ESP_SUPPLICANT + if (os_reltime_initialized(&srv->pause_state_end) && + ether_addr_equal(peer_addr, srv->sel_peer_addr) && + instance_id == srv->sel_peer_id) { + wpa_printf(MSG_DEBUG, + "NAN: In pauseState - skipping pauseStateTimeout reset for" + " Subscribe message from selected peer"); + } else +#endif /* ESP_SUPPLICANT */ + nan_de_pause_state(srv, peer_addr, instance_id); + } offload: if (!srv->publish.disable_events && de->cb.replied) @@ -1540,3 +1568,20 @@ int nan_de_transmit(struct nan_de *de, int handle, return 0; } + +#ifdef ESP_SUPPLICANT +void nan_de_cancel_service(struct nan_de *de, int service_id) +{ + struct nan_de_service *srv; + + wpa_printf(MSG_DEBUG, "NAN: CancelService(service_id=%d)", service_id); + + if (service_id < 1 || service_id > NAN_DE_MAX_SERVICE) + return; + + srv = de->service[service_id - 1]; + if (!srv) + return; + nan_de_del_srv(de, srv, NAN_DE_REASON_USER_REQUEST); +} +#endif diff --git a/components/wpa_supplicant/src/common/nan_de.h b/components/wpa_supplicant/src/common/nan_de.h index 2c95829bcc7..fcbf5c9fc6b 100644 --- a/components/wpa_supplicant/src/common/nan_de.h +++ b/components/wpa_supplicant/src/common/nan_de.h @@ -10,10 +10,15 @@ #define NAN_DE_H #include "nan.h" +#include "utils/common.h" /* Maximum number of active local publish and subscribe instances */ #ifndef NAN_DE_MAX_SERVICE +#ifndef ESP_SUPPLICANT #define NAN_DE_MAX_SERVICE 20 +#else +#define NAN_DE_MAX_SERVICE 2 +#endif #endif /* NAN_DE_MAX_SERVICE */ struct nan_de; @@ -149,4 +154,7 @@ int nan_de_transmit(struct nan_de *de, int handle, const struct wpabuf *ssi, const struct wpabuf *elems, const u8 *peer_addr, u8 req_instance_id); +#ifdef ESP_SUPPLICANT +void nan_de_cancel_service(struct nan_de *de, int service_id); +#endif #endif /* NAN_DE_H */ diff --git a/components/wpa_supplicant/src/utils/common.c b/components/wpa_supplicant/src/utils/common.c index 51acf7d6f3d..ef36edc7dca 100644 --- a/components/wpa_supplicant/src/utils/common.c +++ b/components/wpa_supplicant/src/utils/common.c @@ -543,6 +543,23 @@ int os_reltime_initialized(struct os_reltime *t) return t->sec != 0 || t->usec != 0; } +void os_reltime_add_ms(struct os_reltime *ts, int ms) +{ + ts->usec += ms * 1000; + while (ts->usec >= 1000000) { + ts->sec++; + ts->usec -= 1000000; + } + while (ts->usec < 0) { + ts->sec--; + ts->usec += 1000000; + } +} + +int os_reltime_in_ms(struct os_reltime *ts) +{ + return ts->sec * 1000 + ts->usec / 1000; +} u8 rssi_to_rcpi(int rssi) { diff --git a/components/wpa_supplicant/src/utils/common.h b/components/wpa_supplicant/src/utils/common.h index 998870e90f4..4fa4e11798a 100644 --- a/components/wpa_supplicant/src/utils/common.h +++ b/components/wpa_supplicant/src/utils/common.h @@ -398,6 +398,8 @@ int os_reltime_expired(struct os_time *now, struct os_time *ts, os_time_t timeout_secs); int os_reltime_initialized(struct os_reltime *t); +void os_reltime_add_ms(struct os_reltime *ts, int ms); +int os_reltime_in_ms(struct os_reltime *ts); #ifdef CONFIG_NATIVE_WINDOWS void wpa_unicode2ascii_inplace(TCHAR *str); @@ -435,6 +437,11 @@ static inline int is_multicast_ether_addr(const u8 *a) return a[0] & 0x01; } +static inline bool ether_addr_equal(const u8 *a, const u8 *b) +{ + return os_memcmp(a, b, ETH_ALEN) == 0; +} + #define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff" diff --git a/docs/en/api-guides/wifi.rst b/docs/en/api-guides/wifi.rst index d3e759e3e90..ae655e788e5 100644 --- a/docs/en/api-guides/wifi.rst +++ b/docs/en/api-guides/wifi.rst @@ -2094,6 +2094,14 @@ Detailed information on creating certificates and how to run wpa2_enterprise exa Refer to ESP-IDF examples :idf_file:`examples/wifi/wifi_aware/nan_publisher/README.md` and :idf_file:`examples/wifi/wifi_aware/nan_subscriber/README.md` to setup a NAN Publisher and Subscriber. +Wi-Fi Aware\ :sup:`TM` (NAN): Unsynchronized Service Discovery (USD) +-------------------------------------------------------------------- +Unsynchronized Service Discovery (USD) is a mechanism for devices to discover the services that have been made discoverable on new devices that enter the RF environment, without requiring synchronization between the devices. + +USD uses Service Info field in the SDEA of a Publish and Follow-up message to convey the service specific information. + +Refer to ESP-IDF examples :idf_file:`examples/wifi/wifi_aware/usd_publisher/README.md` and :idf_file:`examples/wifi/wifi_aware/usd_subscriber/README.md` to setup a NAN-USD Publisher and Subscriber. + Wireless Network Management ---------------------------- diff --git a/examples/wifi/.build-test-rules.yml b/examples/wifi/.build-test-rules.yml index 2d379ddcfdb..3aa9f4c9083 100644 --- a/examples/wifi/.build-test-rules.yml +++ b/examples/wifi/.build-test-rules.yml @@ -98,7 +98,7 @@ examples/wifi/softap_sta: disable: - if: (SOC_WIFI_SUPPORTED != 1) and (SOC_WIRELESS_HOST_SUPPORTED != 1) -examples/wifi/wifi_aware: +examples/wifi/wifi_aware/nan_console: disable: - if: SOC_WIFI_NAN_SUPPORT != 1 reason: targets esp32c3, esp32s3, esp32c2 and esp32c6 are not supported @@ -114,3 +114,43 @@ examples/wifi/wifi_aware: - nvs_flash depends_filepatterns: - examples/system/console/advanced/components/**/* + +examples/wifi/wifi_aware/nan_publisher: + disable: + - if: SOC_WIFI_NAN_SUPPORT != 1 + reason: targets esp32c3, esp32s3, esp32c2 and esp32c6 are not supported + depends_components: + - esp_wifi + - esp_phy + - esp_netif + - lwip + - esp_event + - esp_coex + - wpa_supplicant + - mbedtls + - nvs_flash + +examples/wifi/wifi_aware/nan_subscriber: + disable: + - if: SOC_WIFI_NAN_SUPPORT != 1 + reason: targets esp32c3, esp32s3, esp32c2 and esp32c6 are not supported + depends_components: + - esp_wifi + - esp_phy + - esp_netif + - lwip + - esp_event + - esp_coex + - wpa_supplicant + - mbedtls + - nvs_flash + +examples/wifi/wifi_aware/usd_publisher: + <<: *wifi_depends_default + disable: + - if: SOC_WIFI_SUPPORTED != 1 + +examples/wifi/wifi_aware/usd_subscriber: + <<: *wifi_depends_default + disable: + - if: SOC_WIFI_SUPPORTED != 1 diff --git a/examples/wifi/wifi_aware/usd_publisher/CMakeLists.txt b/examples/wifi/wifi_aware/usd_publisher/CMakeLists.txt new file mode 100644 index 00000000000..95c1103419e --- /dev/null +++ b/examples/wifi/wifi_aware/usd_publisher/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(usd_publisher) diff --git a/examples/wifi/wifi_aware/usd_publisher/README.md b/examples/wifi/wifi_aware/usd_publisher/README.md new file mode 100644 index 00000000000..1c350929488 --- /dev/null +++ b/examples/wifi/wifi_aware/usd_publisher/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | diff --git a/examples/wifi/wifi_aware/usd_publisher/main/CMakeLists.txt b/examples/wifi/wifi_aware/usd_publisher/main/CMakeLists.txt new file mode 100644 index 00000000000..19b52737d14 --- /dev/null +++ b/examples/wifi/wifi_aware/usd_publisher/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "usd_publisher_example_main.c" + INCLUDE_DIRS ".") diff --git a/examples/wifi/wifi_aware/usd_publisher/main/Kconfig.projbuild b/examples/wifi/wifi_aware/usd_publisher/main/Kconfig.projbuild new file mode 100644 index 00000000000..d79aba9e76a --- /dev/null +++ b/examples/wifi/wifi_aware/usd_publisher/main/Kconfig.projbuild @@ -0,0 +1,20 @@ +menu "Example Configuration" + + config ESP_WIFI_USD_PUB_SVC_NAME + string "USD publish service name" + default "ESP-USD-TEST" + + config ESP_WIFI_USD_PUB_TTL + int "Time to live (in seconds)" + range 0 1000 + default 100 + help + Time to live of the Publish instance, in seconds. If TTL = 0, only one publish message is transmitted. + + config ESP_WIFI_USD_SVC_SPECIFIC_INFO + string "Service specific info to be transmitted in a followup message" + default "Welcome" + help + SSI to be transmitted in a followup frame + +endmenu diff --git a/examples/wifi/wifi_aware/usd_publisher/main/usd_publisher_example_main.c b/examples/wifi/wifi_aware/usd_publisher/main/usd_publisher_example_main.c new file mode 100644 index 00000000000..8426737e874 --- /dev/null +++ b/examples/wifi/wifi_aware/usd_publisher/main/usd_publisher_example_main.c @@ -0,0 +1,127 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_nan.h" +#include "esp_mac.h" +#include "esp_event.h" +#include "esp_check.h" +#include "esp_log.h" +#include "nvs_flash.h" + +#define MAC_ADDR_LEN 6 + +#define EXAMPLE_USD_SVC_NAME CONFIG_ESP_WIFI_USD_PUB_SVC_NAME +#define EXAMPLE_USD_TTL CONFIG_ESP_WIFI_USD_PUB_TTL +#define EXAMPLE_USD_SVC_INFO CONFIG_ESP_WIFI_USD_SVC_SPECIFIC_INFO + +static EventGroupHandle_t s_nan_event_group; +static int NAN_RECEIVE = BIT0; +const char *TAG = "usd_publisher"; +uint8_t g_peer_inst_id; +uint8_t g_peer_mac[MAC_ADDR_LEN]; +uint8_t g_publish_id; + +static void nan_receive_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + wifi_event_nan_receive_t *evt = (wifi_event_nan_receive_t *)event_data; + if (evt == NULL) { + return; + } + g_peer_inst_id = evt->peer_inst_id; + memcpy(g_peer_mac, evt->peer_if_mac, MAC_ADDR_LEN); + ESP_LOGI(TAG, "Received Follow-up message from peer with ID %d and MAC "MACSTR"", + evt->peer_inst_id, MAC2STR(evt->peer_if_mac)); + if (evt->ssi_len) { + ESP_LOG_BUFFER_HEXDUMP(TAG, evt->ssi, evt->ssi_len, ESP_LOG_INFO); + xEventGroupSetBits(s_nan_event_group, NAN_RECEIVE); + } else { + ESP_LOGI(TAG, "SSI - [NULL]"); + } +} + +void wifi_usd_publish(void) +{ + s_nan_event_group = xEventGroupCreate(); + esp_event_handler_instance_t instance_any_id; + + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + WIFI_EVENT_NAN_RECEIVE, + &nan_receive_event_handler, + NULL, + &instance_any_id)); + + /* Start USD-NAN Discovery */ + wifi_nan_config_t usd_nan_cfg = WIFI_USD_NAN_CONFIG_DEFAULT(); + ESP_RETURN_VOID_ON_ERROR(esp_wifi_nan_start(&usd_nan_cfg), TAG, "NAN-USD initialization failed"); + + wifi_nan_publish_cfg_t publish_cfg = { + .service_name = EXAMPLE_USD_SVC_NAME, + .ttl = EXAMPLE_USD_TTL, + .ssi = NULL, + .ssi_len = 0, + .usd_discovery_flag = 1, + .usd_publish_config = esp_wifi_usd_get_default_publish_cfg(), + }; + + g_publish_id = esp_wifi_nan_publish_service(&publish_cfg); + + + if (g_publish_id == 0) { + ESP_LOGE(TAG, "Publishing to %s failed", publish_cfg.service_name); + return; + } + + EventBits_t bits = xEventGroupWaitBits(s_nan_event_group, NAN_RECEIVE, pdFALSE, pdFALSE, pdMS_TO_TICKS(EXAMPLE_USD_TTL*1000)); + if (bits & NAN_RECEIVE) { + xEventGroupClearBits(s_nan_event_group, NAN_RECEIVE); + wifi_nan_followup_params_t fup_params = { + .inst_id = g_publish_id, + .peer_inst_id = g_peer_inst_id, + .ssi = (uint8_t *)EXAMPLE_USD_SVC_INFO, + .ssi_len = strlen(EXAMPLE_USD_SVC_INFO), + }; + memcpy(fup_params.peer_mac, g_peer_mac, MAC_ADDR_LEN); + + ESP_LOGI(TAG, "Sending message to the peer with ID %d", g_peer_inst_id); + if (fup_params.ssi_len) { + ESP_LOG_BUFFER_HEXDUMP(TAG, fup_params.ssi, fup_params.ssi_len, ESP_LOG_INFO); + } else { + ESP_LOGI(TAG, "SSI - [NULL]"); + } + ESP_RETURN_VOID_ON_ERROR(esp_wifi_nan_send_message(&fup_params), TAG, "Sending message to the peer with ID %d failed!", g_peer_inst_id); + } + + esp_wifi_nan_cancel_service(g_publish_id); + esp_wifi_nan_stop(); +} + +void initialise_wifi(void) +{ + ESP_ERROR_CHECK(esp_event_loop_create_default()); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM) ); +} + +void app_main(void) +{ + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + initialise_wifi(); + wifi_usd_publish(); + return; +} diff --git a/examples/wifi/wifi_aware/usd_publisher/sdkconfig.defaults b/examples/wifi/wifi_aware/usd_publisher/sdkconfig.defaults new file mode 100644 index 00000000000..47d739bb224 --- /dev/null +++ b/examples/wifi/wifi_aware/usd_publisher/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_ESP_WIFI_NAN_USD_ENABLE=y diff --git a/examples/wifi/wifi_aware/usd_subscriber/CMakeLists.txt b/examples/wifi/wifi_aware/usd_subscriber/CMakeLists.txt new file mode 100644 index 00000000000..75d5bab606e --- /dev/null +++ b/examples/wifi/wifi_aware/usd_subscriber/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(usd_subscriber) diff --git a/examples/wifi/wifi_aware/usd_subscriber/README.md b/examples/wifi/wifi_aware/usd_subscriber/README.md new file mode 100644 index 00000000000..1c350929488 --- /dev/null +++ b/examples/wifi/wifi_aware/usd_subscriber/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | diff --git a/examples/wifi/wifi_aware/usd_subscriber/main/CMakeLists.txt b/examples/wifi/wifi_aware/usd_subscriber/main/CMakeLists.txt new file mode 100644 index 00000000000..2c34987a324 --- /dev/null +++ b/examples/wifi/wifi_aware/usd_subscriber/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "usd_subscriber_example_main.c" + INCLUDE_DIRS ".") diff --git a/examples/wifi/wifi_aware/usd_subscriber/main/Kconfig.projbuild b/examples/wifi/wifi_aware/usd_subscriber/main/Kconfig.projbuild new file mode 100644 index 00000000000..7b00aa4015f --- /dev/null +++ b/examples/wifi/wifi_aware/usd_subscriber/main/Kconfig.projbuild @@ -0,0 +1,28 @@ +menu "Example Configuration" + + config ESP_WIFI_USD_SUB_SVC_NAME + string "USD subscribe service name" + default "ESP-USD-TEST" + + config ESP_WIFI_USD_SUB_TTL + int "Time to live (in seconds)" + range 0 1000 + default 100 + help + Time to live of the Subscribe instance, in seconds. If TTL = 0, + the subscriber listens until the first service match is reported. + + config ESP_WIFI_USD_DEFAULT_CHAN + int "Default Subscribe channel" + range 1 13 + default 6 + help + Default channel of subscriber + + config ESP_WIFI_USD_SVC_SPECIFIC_INFO + string "Service specific info to be transmitted in a followup message" + default "Hello" + help + SSI to be transmitted in a followup frame + +endmenu diff --git a/examples/wifi/wifi_aware/usd_subscriber/main/usd_subscriber_example_main.c b/examples/wifi/wifi_aware/usd_subscriber/main/usd_subscriber_example_main.c new file mode 100644 index 00000000000..af7a65b8bfa --- /dev/null +++ b/examples/wifi/wifi_aware/usd_subscriber/main/usd_subscriber_example_main.c @@ -0,0 +1,151 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_nan.h" +#include "esp_mac.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_check.h" +#include "nvs_flash.h" + +#define MAC_ADDR_LEN 6 + +#define EXAMPLE_USD_SVC_NAME CONFIG_ESP_WIFI_USD_SUB_SVC_NAME +#define EXAMPLE_USD_TTL CONFIG_ESP_WIFI_USD_SUB_TTL +#define EXAMPLE_USD_DEFAULT_SUB_CHANNEL CONFIG_ESP_WIFI_USD_DEFAULT_CHAN +#define EXAMPLE_USD_SVC_INFO CONFIG_ESP_WIFI_USD_SVC_SPECIFIC_INFO + +static EventGroupHandle_t s_nan_event_group; +static int NAN_RECEIVE = BIT0; +static int NAN_SRV_MATCH = BIT1; +const char *TAG = "usd_subscriber"; +uint8_t g_peer_inst_id; +uint8_t g_peer_mac[MAC_ADDR_LEN]; +uint8_t g_subscribe_id; + +static void nan_svc_match_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + wifi_event_nan_svc_match_t *evt = (wifi_event_nan_svc_match_t *)event_data; + if (evt == NULL) { + return; + } + g_peer_inst_id = evt->publish_id; + memcpy(g_peer_mac, evt->pub_if_mac, MAC_ADDR_LEN); + ESP_LOGI(TAG, "Service matched with peer_id %d peer mac "MACSTR"", evt->publish_id, MAC2STR(evt->pub_if_mac)); + if (evt->ssi_len) { + ESP_LOGI(TAG, "SSI -"); + ESP_LOG_BUFFER_HEXDUMP(TAG, evt->ssi, + evt->ssi_len, ESP_LOG_INFO); + } else { + ESP_LOGI(TAG, "SSI - [NULL]"); + } + xEventGroupSetBits(s_nan_event_group, NAN_SRV_MATCH); +} + +static void nan_receive_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + wifi_event_nan_receive_t *evt = (wifi_event_nan_receive_t *)event_data; + if (evt == NULL) { + return; + } + + ESP_LOGI(TAG, "Received Follow-up message from peer with ID %d and MAC "MACSTR"", + evt->peer_inst_id, MAC2STR(evt->peer_if_mac)); + if (evt->ssi_len) { + ESP_LOG_BUFFER_HEXDUMP(TAG, evt->ssi, evt->ssi_len, ESP_LOG_INFO); + } else { + ESP_LOGI(TAG, "SSI - [NULL]"); + } + xEventGroupSetBits(s_nan_event_group, NAN_RECEIVE); + esp_wifi_nan_cancel_service(g_subscribe_id); +} + +void wifi_usd_subscribe(void) +{ + s_nan_event_group = xEventGroupCreate(); + esp_event_handler_instance_t instance_any_id; + + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + WIFI_EVENT_NAN_SVC_MATCH, + &nan_svc_match_event_handler, + NULL, + &instance_any_id)); + + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + WIFI_EVENT_NAN_RECEIVE, + &nan_receive_event_handler, + NULL, + &instance_any_id)); + + /* Start NAN-USD Discovery */ + wifi_nan_config_t nan_usd_cfg = WIFI_USD_NAN_CONFIG_DEFAULT(); + esp_wifi_nan_start(&nan_usd_cfg); + + wifi_nan_subscribe_cfg_t subscribe_cfg = { + .service_name = EXAMPLE_USD_SVC_NAME, + .ttl = EXAMPLE_USD_TTL, + .ssi = NULL, + .ssi_len = 0, + .usd_discovery_flag = 1, + .usd_subscribe_config = esp_wifi_usd_get_default_subscribe_cfg(), + }; + subscribe_cfg.usd_subscribe_config.usd_default_channel = EXAMPLE_USD_DEFAULT_SUB_CHANNEL; + + g_subscribe_id = esp_wifi_nan_subscribe_service(&subscribe_cfg); + if (g_subscribe_id == 0) { + ESP_LOGE(TAG, "Subscribing to %s failed", subscribe_cfg.service_name); + return; + } + + EventBits_t bits = xEventGroupWaitBits(s_nan_event_group, NAN_SRV_MATCH, pdTRUE, pdFALSE, pdMS_TO_TICKS(EXAMPLE_USD_TTL*1000)); + if (bits & NAN_SRV_MATCH) { + wifi_nan_followup_params_t fup_params = { + .inst_id = g_subscribe_id, + .peer_inst_id = g_peer_inst_id, + .ssi = (uint8_t *)EXAMPLE_USD_SVC_INFO, + .ssi_len = strlen(EXAMPLE_USD_SVC_INFO), + }; + memcpy(fup_params.peer_mac, g_peer_mac, MAC_ADDR_LEN); + + ESP_LOGI(TAG, "Sending message to the peer with ID %d", g_peer_inst_id); + if (fup_params.ssi_len) { + ESP_LOG_BUFFER_HEXDUMP(TAG, fup_params.ssi, fup_params.ssi_len, ESP_LOG_INFO); + } else { + ESP_LOGI(TAG, "SSI - [NULL]"); + } + ESP_RETURN_VOID_ON_ERROR(esp_wifi_nan_send_message(&fup_params), TAG, "Sending message to the peer with ID %d failed!", g_peer_inst_id); + } + return; +} + +void initialise_wifi(void) +{ + ESP_ERROR_CHECK(esp_event_loop_create_default()); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM) ); +} + +void app_main(void) +{ + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + initialise_wifi(); + wifi_usd_subscribe(); + + return; +} diff --git a/examples/wifi/wifi_aware/usd_subscriber/sdkconfig.defaults b/examples/wifi/wifi_aware/usd_subscriber/sdkconfig.defaults new file mode 100644 index 00000000000..47d739bb224 --- /dev/null +++ b/examples/wifi/wifi_aware/usd_subscriber/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_ESP_WIFI_NAN_USD_ENABLE=y From a5f6bc639b084bf20a8266c579ebfad17bf40f6c Mon Sep 17 00:00:00 2001 From: Sarvesh Bodakhe Date: Tue, 30 Sep 2025 18:25:22 +0530 Subject: [PATCH 23/24] feat(wifi): Add support to set BSSID (A3) in esp_wifi_action_tx_req --- components/esp_wifi/include/esp_wifi_types_generic.h | 1 + components/wpa_supplicant/esp_supplicant/src/esp_nan_usd.c | 1 + 2 files changed, 2 insertions(+) diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index 6d9cdbd6bce..dcb0699e6c2 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -800,6 +800,7 @@ typedef struct { wifi_action_rx_cb_t rx_cb; /**< Rx Callback to receive action frames */ uint8_t op_id; /**< Unique Identifier for operation provided by wifi driver */ uint32_t data_len; /**< Length of the appended Data */ + uint8_t bssid[6]; /**< BSSID (A3) address. If all zeroes, broadcast address will be used */ uint8_t data[0]; /**< Appended Data payload */ } wifi_action_tx_req_t; diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_nan_usd.c b/components/wpa_supplicant/esp_supplicant/src/esp_nan_usd.c index 92a95a00ac6..bfa4e8076e5 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_nan_usd.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_nan_usd.c @@ -175,6 +175,7 @@ static int esp_nan_de_tx(void *ctx, unsigned int freq, unsigned int wait_time, req->type = WIFI_OFFCHAN_TX_REQ; req->wait_time_ms = wait_time; memcpy(req->dest_mac, dst, ETH_ALEN); + memcpy(req->bssid, bssid, ETH_ALEN); req->no_ack = false; req->data_len = buf_len; req->rx_cb = esp_nan_de_rx_action; From 4c3d6c129262128e1f2c1d70ca209d521347231d Mon Sep 17 00:00:00 2001 From: Sarvesh Bodakhe Date: Tue, 30 Sep 2025 14:46:56 +0530 Subject: [PATCH 24/24] fix(wifi): Add refactoring and migration guide for USD, Offchan_tx, ROC 1. fix(wifi): Rename old NAN configuration to NAN-Sync - Rename CONFIG_ESP_WIFI_NAN_ENABLE to CONFIG_ESP_WIFI_NAN_SYNC_ENABLE to indicate the support for Synchronized NAN (Wi-Fi Aware). - Because the original flag really controls the synchronized feature set, rename it to CONFIG_ESP_WIFI_NAN_SYNC_ENABLE so the NAN-Sync and NAN-USD paths can be selected independently without confusion. 2. Document esp_wifi_start requirement and fix USD examples 3. Rename nan_callbacks to nan_sync_callbacks 4. Remove the discovery_flag, clarify docs for sync vs USD flows, and add USD start/stop APIs 5. Require esp_wifi_start() before USD start 6. docs(nan): add NAN-USD application examples 7. add migration guide and hints for NAN-USD proto field 8. Improve allow_broadcast documentation 9. Add attention to the API esp_wifi_remain_on_channel 10. fix(wifi): align NAN API renames and docs for v6.0 - keep shared APIs under esp_wifi_nan_* while reserving sync/usd names for mode-specific entry points - clarify synchronized-cluster scope in headers, docs, and migration notes (EN/zh-CN) - update examples for renamed helpers and WIFI_NAN_SYNC_CONFIG_DEFAULT() - rename `wifi_nan_config_t` to `wifi_nan_sync_config_t` 11. Mark NAN-USD as esp-idf experimental feature --- components/esp_netif/esp_netif_defaults.c | 2 +- .../esp_netif/include/esp_netif_defaults.h | 12 +- components/esp_wifi/CMakeLists.txt | 2 +- components/esp_wifi/Kconfig | 11 +- .../esp_wifi/include/esp_private/wifi.h | 4 +- components/esp_wifi/include/esp_wifi.h | 2 + .../esp_wifi/include/esp_wifi_types_generic.h | 20 +- components/esp_wifi/sdkconfig.rename | 1 + components/esp_wifi/src/wifi_default.c | 26 +-- components/esp_wifi/src/wifi_init.c | 12 +- components/esp_wifi/src/wifi_netif.c | 4 +- .../bin_size_apsta/sdkconfig.ci.enable_nan | 2 +- .../include/apps_private/wifi_apps_private.h | 8 +- .../wifi_apps/nan_app/include/esp_nan.h | 220 +++++++++++------- .../esp_wifi/wifi_apps/nan_app/src/nan_app.c | 164 ++++++------- .../esp_supplicant/src/esp_nan_usd.c | 2 +- docs/en/api-reference/network/esp_nan.rst | 4 + .../migration-guides/release-6.x/6.0/wifi.rst | 16 +- .../migration-guides/release-6.x/6.0/wifi.rst | 15 +- .../wifi_aware/nan_console/main/nan_main.c | 6 +- .../wifi_aware/nan_console/sdkconfig.defaults | 2 +- .../nan_publisher/main/publisher_main.c | 4 +- .../nan_publisher/sdkconfig.defaults | 2 +- .../nan_subscriber/main/subscriber_main.c | 4 +- .../nan_subscriber/sdkconfig.defaults | 2 +- .../main/usd_publisher_example_main.c | 8 +- .../usd_publisher/sdkconfig.defaults | 1 + .../main/usd_subscriber_example_main.c | 6 +- .../usd_subscriber/sdkconfig.defaults | 1 + tools/idf_py_actions/hints.yml | 30 +++ 30 files changed, 342 insertions(+), 251 deletions(-) diff --git a/components/esp_netif/esp_netif_defaults.c b/components/esp_netif/esp_netif_defaults.c index e98105b1ae4..895594f0de1 100644 --- a/components/esp_netif/esp_netif_defaults.c +++ b/components/esp_netif/esp_netif_defaults.c @@ -28,7 +28,7 @@ const esp_netif_ip_info_t _g_esp_netif_soft_ap_ip = { const esp_netif_inherent_config_t _g_esp_netif_inherent_ap_config = ESP_NETIF_INHERENT_DEFAULT_WIFI_AP(); #endif -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE const esp_netif_inherent_config_t _g_esp_netif_inherent_nan_config = ESP_NETIF_INHERENT_DEFAULT_WIFI_NAN(); #endif diff --git a/components/esp_netif/include/esp_netif_defaults.h b/components/esp_netif/include/esp_netif_defaults.h index b215aca1dca..8bce84aea45 100644 --- a/components/esp_netif/include/esp_netif_defaults.h +++ b/components/esp_netif/include/esp_netif_defaults.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -158,7 +158,7 @@ extern "C" { } #endif -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE /** * @brief Default configuration reference of WIFI NAN */ @@ -204,7 +204,7 @@ extern "C" { #define ESP_NETIF_BASE_DEFAULT_WIFI_AP &_g_esp_netif_inherent_ap_config #endif -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE /** * @brief Default base config (esp-netif inherent) of WIFI NAN */ @@ -230,7 +230,7 @@ extern "C" { #ifdef CONFIG_ESP_WIFI_SOFTAP_SUPPORT #define ESP_NETIF_NETSTACK_DEFAULT_WIFI_AP _g_esp_netif_netstack_default_wifi_ap #endif -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE #define ESP_NETIF_NETSTACK_DEFAULT_WIFI_NAN _g_esp_netif_netstack_default_wifi_nan #endif #ifdef CONFIG_PPP_SUPPORT @@ -249,7 +249,7 @@ extern const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_sta #ifdef CONFIG_ESP_WIFI_SOFTAP_SUPPORT extern const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_ap; #endif -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE extern const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_nan; #endif #ifdef CONFIG_PPP_SUPPORT @@ -264,7 +264,7 @@ extern const esp_netif_inherent_config_t _g_esp_netif_inherent_sta_config; #ifdef CONFIG_ESP_WIFI_SOFTAP_SUPPORT extern const esp_netif_inherent_config_t _g_esp_netif_inherent_ap_config; #endif -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE extern const esp_netif_inherent_config_t _g_esp_netif_inherent_nan_config; #endif extern const esp_netif_inherent_config_t _g_esp_netif_inherent_eth_config; diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index 9886f0f07e7..1a9e8094ba1 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -48,7 +48,7 @@ if(CONFIG_ESP_WIFI_ENABLED OR CONFIG_ESP_HOST_WIFI_ENABLED) "src/smartconfig_ack.c") endif() - if(CONFIG_ESP_WIFI_NAN_ENABLE OR CONFIG_ESP_WIFI_NAN_USD_ENABLE) + if(CONFIG_ESP_WIFI_NAN_SYNC_ENABLE OR CONFIG_ESP_WIFI_NAN_USD_ENABLE) list(APPEND srcs "wifi_apps/nan_app/src/nan_app.c") endif() if(CONFIG_ESP_WIFI_ENABLE_ROAMING_APP) diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index 24cea7102bd..bceb21fe32a 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -576,19 +576,20 @@ menu "Wi-Fi" Maximum espnow encrypted peers number + maximum number of connections of SoftAP = Max hardware keys number. When using ESP mesh, this value should be set to a maximum of 6. - config ESP_WIFI_NAN_ENABLE - bool "WiFi Aware" + config ESP_WIFI_NAN_SYNC_ENABLE + bool "Enable Wi-Fi Aware: Synchronization (NAN-Sync)" default n depends on SOC_WIFI_NAN_SUPPORT select LWIP_IPV6 help - Enable WiFi Aware (NAN) feature. + Enable Wi-Fi Aware: Synchronization feature (NAN-Sync). config ESP_WIFI_NAN_USD_ENABLE - bool "Enable NAN USD" + bool "Enable Wi-Fi Aware: Unsynchronized service discovery (NAN-USD)" + depends on IDF_EXPERIMENTAL_FEATURES default n help - Enable NAN(WiFi Aware) Unsynchronized service discovery + Enable Wi-Fi Aware: Unsynchronized service discovery (NAN-USD) config ESP_WIFI_MBEDTLS_CRYPTO bool "Use MbedTLS crypto APIs" diff --git a/components/esp_wifi/include/esp_private/wifi.h b/components/esp_wifi/include/esp_private/wifi.h index aca83b7e4aa..e8e6dc2830d 100644 --- a/components/esp_wifi/include/esp_private/wifi.h +++ b/components/esp_wifi/include/esp_private/wifi.h @@ -39,7 +39,7 @@ typedef struct { void *storage; /**< storage for FreeRTOS queue */ } wifi_static_queue_t; -struct nan_callbacks { +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); @@ -780,7 +780,7 @@ esp_err_t esp_nan_internal_datapath_end(wifi_nan_datapath_end_req_t *req); * - ESP_OK: succeed * - others: failed */ -esp_err_t esp_nan_internal_register_callbacks(struct nan_callbacks *cb); +esp_err_t esp_nan_internal_register_callbacks(struct nan_sync_callbacks *cb); /** * @brief Connect WiFi station to the AP. diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index 7a50c8b0118..787ec9d9b33 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -1788,6 +1788,8 @@ esp_err_t esp_wifi_action_tx_req(wifi_action_tx_req_t *req); /** * @brief Remain on the target channel for required duration * + * @attention 1. The API returns ESP_ERR_INVALID_ARG when `req->allow_broadcast` is true and the device operates in AP+STA mode. + * * @param req roc request structure containing relevant fields * * @return diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index dcb0699e6c2..f5694c19cf8 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -592,8 +592,7 @@ typedef struct { 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 discovery_flag; /**< False in case of NAN Synchronization, True in case of Unsynchronized service discovery (USD)*/ -} wifi_nan_config_t; +} wifi_nan_sync_config_t; /** * @brief Configuration data for device's AP or STA or NAN. @@ -605,7 +604,7 @@ typedef struct { typedef union { wifi_ap_config_t ap; /**< Configuration of AP */ wifi_sta_config_t sta; /**< Configuration of STA */ - wifi_nan_config_t nan; /**< Configuration of NAN */ + wifi_nan_sync_config_t nan; /**< Configuration of NAN */ } wifi_config_t; /** @@ -799,8 +798,8 @@ typedef struct { bool no_ack; /**< Indicates no ack required */ wifi_action_rx_cb_t rx_cb; /**< Rx Callback to receive action frames */ uint8_t op_id; /**< Unique Identifier for operation provided by wifi driver */ - uint32_t data_len; /**< Length of the appended Data */ uint8_t bssid[6]; /**< BSSID (A3) address. If all zeroes, broadcast address will be used */ + uint32_t data_len; /**< Length of the appended Data */ uint8_t data[0]; /**< Appended Data payload */ } wifi_action_tx_req_t; @@ -835,10 +834,11 @@ typedef struct { wifi_action_rx_cb_t rx_cb; /**< Rx Callback to receive action mgmt frames */ uint8_t op_id; /**< ID of this specific ROC operation provided by wifi driver */ wifi_action_roc_done_cb_t done_cb; /**< Callback to function that will be called upon ROC done. If assigned, WIFI_EVENT_ROC_DONE event will not be posted */ - bool allow_broadcast; /**< If set to true, broadcast/multicast action frames will be received - in the ROC Rx callback, enabling peer discovery. - If false (default), broadcast/multicast action frames will be filtered out - and not passed to the Rx callback, reducing CPU usage. */ + bool allow_broadcast; /**< If set to true, broadcast/multicast action frames from any network (Address3/BSSID=ANY) + will be received in the ROC Rx callback, enabling peer discovery. + If false (default), broadcast/multicast action frames from other networks + will be filtered out in hardware and not passed to the Rx callback, reducing CPU usage. + Frames whose Address3/BSSID is already broadcast are always delivered. */ } wifi_roc_req_t; /** @@ -1125,8 +1125,8 @@ typedef enum { WIFI_EVENT_BTWT_SETUP, /**< bTWT setup */ WIFI_EVENT_BTWT_TEARDOWN, /**< bTWT teardown*/ - WIFI_EVENT_NAN_STARTED, /**< NAN Discovery has started */ - WIFI_EVENT_NAN_STOPPED, /**< NAN Discovery has stopped */ + WIFI_EVENT_NAN_SYNC_STARTED, /**< NAN Synchronization Discovery has started */ + WIFI_EVENT_NAN_SYNC_STOPPED, /**< NAN Synchronization Discovery has stopped */ WIFI_EVENT_NAN_SVC_MATCH, /**< NAN Service Discovery match found */ WIFI_EVENT_NAN_REPLIED, /**< Replied to a NAN peer with Service Discovery match */ WIFI_EVENT_NAN_RECEIVE, /**< Received a Follow-up message */ diff --git a/components/esp_wifi/sdkconfig.rename b/components/esp_wifi/sdkconfig.rename index 273b291fb56..c4b403e54bd 100644 --- a/components/esp_wifi/sdkconfig.rename +++ b/components/esp_wifi/sdkconfig.rename @@ -28,6 +28,7 @@ CONFIG_ESP32_WIFI_IRAM_OPT CONFIG_ESP_WIFI_IRAM_OPT CONFIG_ESP32_WIFI_RX_IRAM_OPT CONFIG_ESP_WIFI_RX_IRAM_OPT CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE CONFIG_ESP_WIFI_ENABLE_WPA3_SAE CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA +CONFIG_ESP_WIFI_NAN_ENABLE CONFIG_ESP_WIFI_NAN_SYNC_ENABLE # renaming supplicant kconfig to esp_wifi kconfig CONFIG_WPA_MBEDTLS_CRYPTO CONFIG_ESP_WIFI_MBEDTLS_CRYPTO diff --git a/components/esp_wifi/src/wifi_default.c b/components/esp_wifi/src/wifi_default.c index d5d07855e28..3773618cdfb 100644 --- a/components/esp_wifi/src/wifi_default.c +++ b/components/esp_wifi/src/wifi_default.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,7 +12,7 @@ #include "esp_wifi_netif.h" #include #include -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE #include "apps_private/wifi_apps_private.h" #endif #if CONFIG_ESP_WIFI_ENABLE_ROAMING_APP @@ -170,7 +170,7 @@ static void wifi_default_action_sta_got_ip(void *arg, esp_event_base_t base, int } } -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE static void wifi_default_action_nan_started(void *arg, esp_event_base_t base, int32_t event_id, void *data) { if (s_wifi_netifs[WIFI_IF_NAN] != NULL) { @@ -202,9 +202,9 @@ static esp_err_t clear_default_wifi_handlers(void) esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_AP_STOP, wifi_default_action_ap_stop); #endif esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_default_action_sta_got_ip); -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE - esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_NAN_STARTED, wifi_default_action_nan_started); - esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_NAN_STOPPED, wifi_default_action_nan_stopped); +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE + esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_NAN_SYNC_STARTED, wifi_default_action_nan_started); + esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_NAN_SYNC_STOPPED, wifi_default_action_nan_stopped); #endif esp_unregister_shutdown_handler((shutdown_handler_t)esp_wifi_stop); wifi_default_handlers_set = false; @@ -258,13 +258,13 @@ static esp_err_t set_default_wifi_handlers(void) goto fail; } -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE - err = esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_NAN_STARTED, wifi_default_action_nan_started, NULL); +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE + err = esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_NAN_SYNC_STARTED, wifi_default_action_nan_started, NULL); if (err != ESP_OK) { goto fail; } - err = esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_NAN_STOPPED, wifi_default_action_nan_stopped, NULL); + err = esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_NAN_SYNC_STOPPED, wifi_default_action_nan_stopped, NULL); if (err != ESP_OK) { goto fail; } @@ -364,7 +364,7 @@ static inline esp_err_t esp_netif_attach_wifi(esp_netif_t *esp_netif, wifi_inter #ifdef CONFIG_ESP_WIFI_SOFTAP_SUPPORT && wifi_if != WIFI_IF_AP #endif -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE && wifi_if != WIFI_IF_NAN #endif )) { @@ -386,7 +386,7 @@ esp_err_t esp_netif_attach_wifi_ap(esp_netif_t *esp_netif) } #endif -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE esp_err_t esp_netif_attach_wifi_nan(esp_netif_t *esp_netif) { return esp_netif_attach_wifi(esp_netif, WIFI_IF_NAN); @@ -425,7 +425,7 @@ esp_netif_t* esp_netif_create_default_wifi_sta(void) return netif; } -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE /** * @brief User init default NAN (official API) */ @@ -465,7 +465,7 @@ esp_netif_t* esp_netif_create_wifi(wifi_interface_t wifi_if, const esp_netif_inh } else if (wifi_if == WIFI_IF_AP) { cfg.stack = ESP_NETIF_NETSTACK_DEFAULT_WIFI_AP; #endif -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE } else if (wifi_if == WIFI_IF_NAN) { cfg.stack = ESP_NETIF_NETSTACK_DEFAULT_WIFI_NAN; #endif diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index ea050fe0abb..2bf79c6f9e4 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -27,7 +27,7 @@ #if __has_include("esp_psram.h") #include "esp_psram.h" #endif -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE #include "apps_private/wifi_apps_private.h" #endif #ifdef CONFIG_ESP_WIFI_FTM_ENABLE @@ -187,7 +187,7 @@ static esp_err_t wifi_deinit_internal(void) ESP_LOGW(TAG, "Failed to unregister Rx callbacks"); } -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE esp_nan_app_deinit(); #endif @@ -484,7 +484,7 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config) esp_wifi_config_info(); -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE esp_nan_app_init(); #endif @@ -649,7 +649,7 @@ void create_new_bss_for_sa_query_failed_sta(uint8_t arg) } #endif /* CONFIG_ESP_WIFI_SOFTAP_SUPPORT */ -#ifndef CONFIG_ESP_WIFI_NAN_ENABLE +#ifndef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE esp_err_t nan_start(void) { @@ -680,7 +680,7 @@ int wifi_create_nan(void) return 0; } -int wifi_nan_set_config_local(wifi_nan_config_t *p) +int wifi_nan_set_config_local(wifi_nan_sync_config_t *p) { /* Do not remove, stub to overwrite weak link in Wi-Fi Lib */ return 0; @@ -707,7 +707,7 @@ void nan_ndp_resp_timeout_process(void *p) { /* Do not remove, stub to overwrite weak link in Wi-Fi Lib */ } -#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ +#endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */ #if CONFIG_IDF_TARGET_ESP32C2 #if CONFIG_ESP32C2_REV_MIN_FULL < 200 diff --git a/components/esp_wifi/src/wifi_netif.c b/components/esp_wifi/src/wifi_netif.c index f42ff6bd52e..96d4135dd21 100644 --- a/components/esp_wifi/src/wifi_netif.c +++ b/components/esp_wifi/src/wifi_netif.c @@ -46,7 +46,7 @@ static esp_err_t wifi_ap_receive(void *buffer, uint16_t len, void *eb) } #endif -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE static esp_err_t wifi_nan_receive(void *buffer, uint16_t len, void *eb) { return s_wifi_rxcbs[WIFI_IF_NAN](s_wifi_netifs[WIFI_IF_NAN], buffer, len, eb); @@ -158,7 +158,7 @@ esp_err_t esp_wifi_register_if_rxcb(wifi_netif_driver_t ifx, esp_netif_receive_t break; #endif -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE case WIFI_IF_NAN: rxcb = wifi_nan_receive; break; diff --git a/components/esp_wifi/test_apps/bin_size_apsta/sdkconfig.ci.enable_nan b/components/esp_wifi/test_apps/bin_size_apsta/sdkconfig.ci.enable_nan index be625a880c8..3d8f4d46579 100644 --- a/components/esp_wifi/test_apps/bin_size_apsta/sdkconfig.ci.enable_nan +++ b/components/esp_wifi/test_apps/bin_size_apsta/sdkconfig.ci.enable_nan @@ -1 +1 @@ -CONFIG_ESP_WIFI_NAN_ENABLE=y +CONFIG_ESP_WIFI_NAN_SYNC_ENABLE=y diff --git a/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h b/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h index 5fe106f2894..df2b9883cf9 100644 --- a/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h +++ b/components/esp_wifi/wifi_apps/include/apps_private/wifi_apps_private.h @@ -15,7 +15,7 @@ extern "C" { #endif -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE /** * @brief Initialize the NAN App and required Data Structures @@ -35,7 +35,7 @@ void esp_nan_app_deinit(void); * @brief NAN App action handler for NAN Started event. Sets up other event handlers and * initializes NAN App context * - * @attention This API should be called in WIFI_EVENT_NAN_STARTED event handler + * @attention This API should be called in WIFI_EVENT_NAN_SYNC_STARTED event handler * * @param nan_netif Netif handle corresponding to NAN interface. */ @@ -45,11 +45,11 @@ void esp_nan_action_start(esp_netif_t *nan_netif); * @brief NAN App action handler for NAN Stopped event. Clears other event handlers and * resets NAN App context * - * @attention This API should be called in WIFI_EVENT_NAN_STOPPED event handler + * @attention This API should be called in WIFI_EVENT_NAN_SYNC_STOPPED event handler */ void esp_nan_action_stop(void); -#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ +#endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */ #ifdef __cplusplus } 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 2dd65d7fcce..98391602c0b 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 @@ -15,17 +15,12 @@ extern "C" { #endif -#define WIFI_NAN_CONFIG_DEFAULT() { \ +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE +#define WIFI_NAN_SYNC_CONFIG_DEFAULT() { \ .op_channel = 6, \ .master_pref = 2, \ .scan_time = 3, \ .warm_up_sec = 5, \ - .discovery_flag = 0, \ -}; - -/* For USD, all parameters other than discovery_flag are ignored */ -#define WIFI_USD_NAN_CONFIG_DEFAULT() { \ - .discovery_flag = 1, \ }; #define NDP_STATUS_ACCEPTED 1 @@ -46,7 +41,8 @@ struct nan_peer_record { }; /** - * @brief Start NAN Discovery or Unsynchronized service discovery (USD) with provided configuration + * @brief Start NAN Synchronization using the provided parameters. + * @note Discovery traffic begins only after publish/subscribe services are started. * * @attention This API should be called after esp_wifi_init(). * @@ -56,30 +52,132 @@ struct nan_peer_record { * - ESP_OK: succeed * - others: failed */ -esp_err_t esp_wifi_nan_start(const wifi_nan_config_t *nan_cfg); +esp_err_t esp_wifi_nan_sync_start(const wifi_nan_sync_config_t *nan_cfg); /** - * @brief Stop NAN Discovery or USD and end publish/subscribe services + * @brief Stop NAN Synchronization discovery and end publish/subscribe services * * @attention This API will end datapaths if any in NAN synchronization - * @attention This API will stop USD if discovery_flag is set to true, else it will stop NAN Discovery * * @return * - ESP_OK: succeed * - others: failed */ -esp_err_t esp_wifi_nan_stop(void); +esp_err_t esp_wifi_nan_sync_stop(void); /** - * @brief Start Publishing a service to the NAN/USD Peers in vicinity + * @brief Send a NAN datapath request to a matched publisher within the synchronized NAN cluster * - * @attention This API should be called after esp_wifi_nan_start(). - * @attention This API will start a publisher in USD if discovery_flag is true + * @attention This API should be called by the Subscriber after a match occurs with a Publisher. + * + * @param req NAN Datapath Request parameters. + * + * @return + * - non-zero NAN Datapath identifier: If NAN datapath req was accepted by publisher + * - zero: If NAN datapath req was rejected by publisher or a timeout occurs + */ +uint8_t esp_wifi_nan_datapath_req(wifi_nan_datapath_req_t *req); + +/** + * @brief Respond to a NAN datapath request within the synchronized NAN cluster + * + * @attention This API should be called if ndp_resp_needed is set 1 in wifi_nan_publish_cfg_t and + * a WIFI_EVENT_NDP_INDICATION event is received due to an incoming NDP request. + * + * @param resp NAN Datapath Response parameters. + * + * @return + * - ESP_OK: succeed + * - others: failed + */ +esp_err_t esp_wifi_nan_datapath_resp(wifi_nan_datapath_resp_t *resp); + +/** + * @brief Terminate an active NAN datapath within the synchronized NAN cluster + * + * @param req NAN Datapath end request parameters. + * + * @return + * - ESP_OK: succeed + * - others: failed + */ +esp_err_t esp_wifi_nan_datapath_end(wifi_nan_datapath_end_req_t *req); + +/** + * @brief Get IPv6 Link Local address using MAC address + * + * @param[out] ip6 Derived IPv6 Link Local address. + * @param[in] mac_addr Input MAC Address. + */ +void esp_wifi_nan_get_ipv6_linklocal_from_mac(ip6_addr_t *ip6, uint8_t *mac_addr); + +/** + * brief Get own Service information from Service ID OR Name. + * + * @attention If service information is to be fetched from service name, set own_svc_id as zero. + * @note Returns records discovered while participating in a synchronized NAN cluster. + * + * @param[inout] own_svc_id As input, it indicates Service ID to search for. + * As output, it indicates Service ID of the service found using Service Name. + * @param[inout] svc_name As input, it indicates Service Name to search for. + * As output, it indicates Service Name of the service found using Service ID. + * @param[out] num_peer_records Number of peers discovered by corresponding service. + * @return + * - ESP_OK: succeed + * - ESP_FAIL: failed + */ + +esp_err_t esp_wifi_nan_get_own_svc_info(uint8_t *own_svc_id, char *svc_name, int *num_peer_records); + +/** + * brief Get a list of Peers discovered by the given Service. + * + * @note Reports peers discovered via synchronized NAN operations. + * + * @param[inout] num_peer_records As input param, it stores max peers peer_record can hold. + * As output param, it specifies the actual number of peers this API returns. + * @param own_svc_id Service ID of own service. + * @param[out] peer_record Pointer to first peer record. + * @return + * - ESP_OK: succeed + * - ESP_FAIL: failed + */ + +esp_err_t esp_wifi_nan_get_peer_records(int *num_peer_records, uint8_t own_svc_id, struct nan_peer_record *peer_record); + +/** + * brief Find Peer's Service information using Peer MAC and optionally Service Name. + * + * @note Provides peer information available from synchronized NAN discovery. + * + * @param svc_name Service Name of the published/subscribed service. + * @param peer_mac Peer's NAN Management Interface MAC address. + * @param[out] peer_info Peer's service information structure. + * @return + * - ESP_OK: succeed + * - ESP_FAIL: failed + */ + +esp_err_t esp_wifi_nan_get_peer_info(char *svc_name, uint8_t *peer_mac, struct nan_peer_record *peer_info); + +#endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */ + +#if defined(CONFIG_ESP_WIFI_NAN_SYNC_ENABLE) || defined(CONFIG_ESP_WIFI_NAN_USD_ENABLE) +/** + * @brief Start publishing a service to NAN peers within a synchronized cluster or to NAN-USD peers + * + * @attention Call after `esp_wifi_nan_sync_start()` when operating in NAN-Sync, or after + * `esp_wifi_nan_usd_start()` when operating in NAN-USD. + * @attention When NAN-USD discovery is active the publish request is routed through the + * USD engine, otherwise it uses NAN synchronization. * @attention A maximum of two services is allowed simultaneously * (e.g., one publish and one subscribe, or two publish/subscribe). * This limit is defined by the ESP_WIFI_NAN_MAX_SVC_SUPPORTED. * * @param publish_cfg Configuration parameters for publishing a service. + * When operating in NAN-USD, populate `publish_cfg->usd_publish_config` + * (for example using `esp_wifi_usd_get_default_publish_cfg()`) to tune + * the USD dwell and channel parameters. * * @return * - non-zero: Publish service identifier @@ -88,15 +186,20 @@ esp_err_t esp_wifi_nan_stop(void); uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg); /** - * @brief Subscribe to a service published by a NAN peer within a cluster or a USD peer + * @brief Subscribe to a service published by a NAN peer within a synchronized cluster or by a NAN-USD peer * - * @attention This API should be called after esp_wifi_nan_start(). - * @attention This API will start a subscriber in USD if discovery_flag is true + * @attention Call after `esp_wifi_nan_sync_start()` when operating in NAN-Sync, or after + * `esp_wifi_nan_usd_start()` when operating in NAN-USD. + * @attention With NAN-USD discovery enabled the subscribe request is handled by the USD + * engine, otherwise it uses NAN synchronization. * @attention A maximum of two services is allowed simultaneously * (e.g., one publish and one subscribe, or two publish/subscribe). * This limit is defined by the ESP_WIFI_NAN_MAX_SVC_SUPPORTED. * * @param subscribe_cfg Configuration parameters for subscribing for a service. + * When operating in NAN-USD, populate `subscribe_cfg->usd_subscribe_config` + * (for example using `esp_wifi_usd_get_default_subscribe_cfg()`) to tune + * the USD dwell and channel parameters. * * @return * - non-zero: Subscribe service identifier @@ -128,92 +231,29 @@ esp_err_t esp_wifi_nan_send_message(wifi_nan_followup_params_t *fup_params); */ esp_err_t esp_wifi_nan_cancel_service(uint8_t service_id); -/** - * @brief Send NAN Datapath Request to a NAN Publisher with matched service - * - * @attention This API should be called by the Subscriber after a match occurs with a Publisher. - * - * @param req NAN Datapath Request parameters. - * - * @return - * - non-zero NAN Datapath identifier: If NAN datapath req was accepted by publisher - * - zero: If NAN datapath req was rejected by publisher or a timeout occurs - */ -uint8_t esp_wifi_nan_datapath_req(wifi_nan_datapath_req_t *req); +#endif /* NAN-Sync || NAN-USD */ +#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE /** - * @brief Respond to a NAN Datapath request with Accept or Reject + * @brief Start NAN Unsynchronized service discovery (USD) * - * @attention This API should be called if ndp_resp_needed is set 1 in wifi_nan_publish_cfg_t and - * a WIFI_EVENT_NDP_INDICATION event is received due to an incoming NDP request. - * - * @param resp NAN Datapath Response parameters. + * @attention This API should be called after esp_wifi_start(). + * @note USD currently operates over the Station interface; this may change in future releases. * * @return * - ESP_OK: succeed * - others: failed */ -esp_err_t esp_wifi_nan_datapath_resp(wifi_nan_datapath_resp_t *resp); +esp_err_t esp_wifi_nan_usd_start(void); /** - * @brief Terminate a NAN Datapath - * - * @param req NAN Datapath end request parameters. + * @brief Stop NAN Unsynchronized service discovery (USD) and end publish/subscribe services * * @return * - ESP_OK: succeed * - others: failed */ -esp_err_t esp_wifi_nan_datapath_end(wifi_nan_datapath_end_req_t *req); - -/** - * @brief Get IPv6 Link Local address using MAC address - * - * @param[out] ip6 Derived IPv6 Link Local address. - * @param[in] mac_addr Input MAC Address. - */ -void esp_wifi_nan_get_ipv6_linklocal_from_mac(ip6_addr_t *ip6, uint8_t *mac_addr); - -/** - * brief Get own Service information from Service ID OR Name. - * - * @attention If service information is to be fetched from service name, set own_svc_id as zero. - * - * @param[inout] own_svc_id As input, it indicates Service ID to search for. - * As output, it indicates Service ID of the service found using Service Name. - * @param[inout] svc_name As input, it indicates Service Name to search for. - * As output, it indicates Service Name of the service found using Service ID. - * @param[out] num_peer_records Number of peers discovered by corresponding service. - * @return - * - ESP_OK: succeed - * - ESP_FAIL: failed - */ -esp_err_t esp_wifi_nan_get_own_svc_info(uint8_t *own_svc_id, char *svc_name, int *num_peer_records); - -/** - * brief Get a list of Peers discovered by the given Service. - * - * @param[inout] num_peer_records As input param, it stores max peers peer_record can hold. - * As output param, it specifies the actual number of peers this API returns. - * @param own_svc_id Service ID of own service. - * @param[out] peer_record Pointer to first peer record. - * @return - * - ESP_OK: succeed - * - ESP_FAIL: failed - */ -esp_err_t esp_wifi_nan_get_peer_records(int *num_peer_records, uint8_t own_svc_id, struct nan_peer_record *peer_record); - -/** - * brief Find Peer's Service information using Peer MAC and optionally Service Name. - * - * @param svc_name Service Name of the published/subscribed service. - * @param peer_mac Peer's NAN Management Interface MAC address. - * @param[out] peer_info Peer's service information structure. - * @return - * - ESP_OK: succeed - * - ESP_FAIL: failed - */ -esp_err_t esp_wifi_nan_get_peer_info(char *svc_name, uint8_t *peer_mac, struct nan_peer_record *peer_info); +esp_err_t esp_wifi_nan_usd_stop(void); /** * @brief Get default configuration for USD publish operation. @@ -250,6 +290,8 @@ wifi_nan_usd_config_t esp_wifi_usd_get_default_publish_cfg(void); */ wifi_nan_usd_config_t esp_wifi_usd_get_default_subscribe_cfg(void); +#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ + #ifdef __cplusplus } #endif 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 cfe32d10cf3..be4818c62c0 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 @@ -45,13 +45,13 @@ /* Global Variables */ static const char *TAG = "nan_app"; -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE static EventGroupHandle_t nan_event_group; static bool s_app_default_handlers_set = false; static uint8_t null_mac[MACADDR_LEN] = {0}; static void *s_nan_data_lock = NULL; static uint32_t s_fup_context; -#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ +#endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */ #ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE #endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ static bool s_usd_in_progress = false; @@ -62,7 +62,7 @@ static const uint8_t s_wfa_oui[3] = {0x50, 0x6f, 0x9a}; #define NAN_SDEA_CTRL_FSD_GAS BIT(1) #define NAN_SDEA_CTRL_DATAPATH_REQD BIT(2) -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE #define NAN_DATA_LOCK() os_mutex_lock(s_nan_data_lock) #define NAN_DATA_UNLOCK() os_mutex_unlock(s_nan_data_lock) @@ -760,7 +760,7 @@ void esp_nan_action_start(esp_netif_t *nan_netif) s_nan_ctx.state = NAN_STARTED_BIT; NAN_DATA_UNLOCK(); - struct nan_callbacks nan_cb = { + struct nan_sync_callbacks nan_cb = { .service_match = nan_app_service_match_cb, .replied = nan_app_replied_cb, .receive = nan_app_receive_cb, @@ -794,13 +794,10 @@ void esp_nan_action_stop(void) os_event_group_set_bits(nan_event_group, NAN_STOPPED_BIT); } -#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ - -esp_err_t esp_wifi_nan_start(const wifi_nan_config_t *nan_cfg) +esp_err_t esp_wifi_nan_sync_start(const wifi_nan_sync_config_t *nan_cfg) { wifi_mode_t mode; esp_err_t ret; - s_usd_in_progress = false; ret = esp_wifi_get_mode(&mode); if (ret == ESP_ERR_WIFI_NOT_INIT) { @@ -811,89 +808,48 @@ esp_err_t esp_wifi_nan_start(const wifi_nan_config_t *nan_cfg) return ret; } -#if (!CONFIG_ESP_WIFI_NAN_ENABLE) - if (!nan_cfg->discovery_flag) { - ESP_LOGE(TAG, "discovery_flag must be set when" - "ESP_WIFI_NAN_USD_ENABLE is enabled"); - return ESP_FAIL; - } -#endif /* XXX: For now, NAN-USD and NAN-Sync can not coexist. */ -#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE - if (nan_cfg->discovery_flag) { - /* NAN-USD Only */ - ESP_RETURN_ON_ERROR(esp_wifi_set_mode(WIFI_MODE_STA), "NAN-USD", "Setting STA mode failed"); - ESP_RETURN_ON_ERROR(esp_wifi_start(), "NAN-USD", "Starting WiFi failed"); - ESP_RETURN_ON_ERROR(esp_nan_usd_init(), "NAN-USD", "Failed to initialise NAN USD engine"); - s_usd_in_progress = true; - ESP_LOGI(TAG, "NaN-USD Started"); - return ESP_OK; + /* NAN-Synchronization Only */ + wifi_config_t config = {0}; + if (!s_nan_data_lock) { + ESP_LOGE(TAG, "NAN Data lock doesn't exist"); + return ESP_FAIL; } -#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE - else { - if (nan_cfg->discovery_flag) { - /* Should reach here only if ESP_WIFI_NAN_USD_ENABLE is disabled */ - ESP_LOGE(TAG, "Can not set discovery_flag without " - "ESP_WIFI_NAN_USD_ENABLE enabled"); - return ESP_FAIL; - } - /* NAN-Synchronization Only */ - wifi_config_t config = {0}; - if (!s_nan_data_lock) { - ESP_LOGE(TAG, "NAN Data lock doesn't exist"); - return ESP_FAIL; - } - - NAN_DATA_LOCK(); - if (s_nan_ctx.state & NAN_STARTED_BIT) { - ESP_LOGI(TAG, "NAN already started"); - NAN_DATA_UNLOCK(); - return ESP_OK; - } + NAN_DATA_LOCK(); + if (s_nan_ctx.state & NAN_STARTED_BIT) { + ESP_LOGI(TAG, "NAN already started"); NAN_DATA_UNLOCK(); - - ESP_RETURN_ON_ERROR(esp_wifi_set_mode(WIFI_MODE_NAN), TAG, "Set mode NAN failed"); - - memcpy(&config.nan, nan_cfg, sizeof(wifi_nan_config_t)); - ESP_RETURN_ON_ERROR(esp_wifi_set_config(WIFI_IF_NAN, &config), TAG, "Setting NAN config failed"); - - if (esp_wifi_start() != ESP_OK) { - ESP_LOGE(TAG, "Starting wifi failed"); - NAN_DATA_LOCK(); - s_nan_ctx.nan_netif = NULL; - NAN_DATA_UNLOCK(); - return ESP_FAIL; - } - - EventBits_t bits = os_event_group_wait_bits(nan_event_group, NAN_STARTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY); - if (!(bits & NAN_STARTED_BIT)) { - NAN_DATA_LOCK(); - s_nan_ctx.nan_netif = NULL; - NAN_DATA_UNLOCK(); - return ESP_FAIL; - } return ESP_OK; } -#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ - return ESP_FAIL; + NAN_DATA_UNLOCK(); + + ESP_RETURN_ON_ERROR(esp_wifi_set_mode(WIFI_MODE_NAN), TAG, "Set mode NAN failed"); + + memcpy(&config.nan, nan_cfg, sizeof(wifi_nan_sync_config_t)); + ESP_RETURN_ON_ERROR(esp_wifi_set_config(WIFI_IF_NAN, &config), TAG, "Setting NAN config failed"); + + if (esp_wifi_start() != ESP_OK) { + ESP_LOGE(TAG, "Starting wifi failed"); + NAN_DATA_LOCK(); + s_nan_ctx.nan_netif = NULL; + NAN_DATA_UNLOCK(); + return ESP_FAIL; + } + + EventBits_t bits = os_event_group_wait_bits(nan_event_group, NAN_STARTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY); + if (!(bits & NAN_STARTED_BIT)) { + NAN_DATA_LOCK(); + s_nan_ctx.nan_netif = NULL; + NAN_DATA_UNLOCK(); + return ESP_FAIL; + } + return ESP_OK; } -esp_err_t esp_wifi_nan_stop(void) +esp_err_t esp_wifi_nan_sync_stop(void) { -#ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE - if (s_usd_in_progress) { - s_usd_in_progress = false; - esp_nan_usd_deinit(); - ESP_RETURN_ON_ERROR(esp_wifi_stop(), TAG, "Stopping NAN-USD failed"); - ESP_LOGI(TAG, "NaN-USD Stopped"); - return ESP_OK; - } -#endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ - -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE NAN_DATA_LOCK(); if (!(s_nan_ctx.state & NAN_STARTED_BIT)) { ESP_LOGE(TAG, "NAN isn't started"); @@ -930,9 +886,9 @@ esp_err_t esp_wifi_nan_stop(void) NAN_DATA_LOCK(); memset(&s_nan_ctx, 0, sizeof(nan_ctx_t)); NAN_DATA_UNLOCK(); -#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ return ESP_OK; } +#endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */ uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg) { @@ -983,7 +939,7 @@ uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg) } #endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE NAN_DATA_LOCK(); if (!(s_nan_ctx.state & NAN_STARTED_BIT)) { ESP_LOGE(TAG, "NAN not started!"); @@ -1015,7 +971,7 @@ uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg) fail: NAN_DATA_UNLOCK(); return 0; -#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ +#endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */ return 0; } @@ -1063,7 +1019,7 @@ uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe } #endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE NAN_DATA_LOCK(); if (!(s_nan_ctx.state & NAN_STARTED_BIT)) { ESP_LOGE(TAG, "NAN not started!"); @@ -1093,7 +1049,7 @@ uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe fail: NAN_DATA_UNLOCK(); return 0; -#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ +#endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */ return 0; } @@ -1132,7 +1088,7 @@ esp_err_t esp_wifi_nan_send_message(wifi_nan_followup_params_t *fup_params) } #endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE struct peer_svc_info *p_peer_svc; NAN_DATA_LOCK(); p_peer_svc = nan_find_peer_svc(fup_params->inst_id, @@ -1178,7 +1134,7 @@ esp_err_t esp_wifi_nan_send_message(wifi_nan_followup_params_t *fup_params) ESP_LOGE(TAG, "Timeout, failed to send Follow-up message!"); ret = ESP_FAIL; } -#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ +#endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */ return ret; } @@ -1189,9 +1145,8 @@ esp_err_t esp_wifi_nan_cancel_service(uint8_t service_id) if (s_usd_in_progress) { return esp_nan_usd_cancel_service(service_id); } - else #endif /* CONFIG_ESP_WIFI_NAN_USD_ENABLE */ -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE NAN_DATA_LOCK(); struct own_svc_info *p_own_svc = nan_find_own_svc(service_id); @@ -1223,12 +1178,12 @@ fail: done: NAN_DATA_UNLOCK(); return ESP_OK; -#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ +#endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */ return ESP_FAIL; } -#ifdef CONFIG_ESP_WIFI_NAN_ENABLE +#ifdef CONFIG_ESP_WIFI_NAN_SYNC_ENABLE uint8_t esp_wifi_nan_datapath_req(wifi_nan_datapath_req_t *req) { uint8_t ndp_id = 0; @@ -1497,9 +1452,32 @@ esp_err_t esp_wifi_nan_get_peer_info(char *svc_name, uint8_t *peer_mac, struct n return ESP_FAIL; } } -#endif /* CONFIG_ESP_WIFI_NAN_ENABLE */ +#endif /* CONFIG_ESP_WIFI_NAN_SYNC_ENABLE */ #ifdef CONFIG_ESP_WIFI_NAN_USD_ENABLE +esp_err_t esp_wifi_nan_usd_start(void) +{ + if (!s_usd_in_progress) { + ESP_RETURN_ON_ERROR(esp_wifi_set_mode(WIFI_MODE_STA), "NAN-USD", "Setting STA mode failed"); + ESP_RETURN_ON_ERROR(esp_nan_usd_init(), "NAN-USD", "Failed to initialise NAN USD engine"); + s_usd_in_progress = true; + ESP_LOGI(TAG, "NaN-USD Started"); + return ESP_OK; + } + return ESP_OK; +} + +esp_err_t esp_wifi_nan_usd_stop(void) +{ + if (s_usd_in_progress) { + s_usd_in_progress = false; + esp_nan_usd_deinit(); + ESP_LOGI(TAG, "NaN-USD Stopped"); + return ESP_OK; + } + return ESP_OK; +} + wifi_nan_usd_config_t esp_wifi_usd_get_default_publish_cfg(void) { wifi_country_t country; diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_nan_usd.c b/components/wpa_supplicant/esp_supplicant/src/esp_nan_usd.c index bfa4e8076e5..f4a4d941343 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_nan_usd.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_nan_usd.c @@ -38,7 +38,7 @@ static void nan_sta_stop_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { if (event_id == WIFI_EVENT_STA_STOP) { - esp_wifi_nan_stop(); + esp_wifi_nan_usd_stop(); } } diff --git a/docs/en/api-reference/network/esp_nan.rst b/docs/en/api-reference/network/esp_nan.rst index 56d2afa18be..42c7cdfd118 100644 --- a/docs/en/api-reference/network/esp_nan.rst +++ b/docs/en/api-reference/network/esp_nan.rst @@ -18,6 +18,10 @@ Application Examples - :example:`wifi/wifi_aware/nan_subscriber` demonstrates how to use the NAN protocol to discover other devices that publishes the required service in the proximity, and communicate with them either by sending a message or initiating a datapath. +- :example:`wifi/wifi_aware/usd_publisher` demonstrates how to use lightweight NAN Unsynchronized Service Discovery (NAN-USD) to advertise a service to nearby devices without forming NAN clusters. It walks through bringing up USD, publishing a service, responding to subscribers with follow-up messages, and returning to the idle state once discovery completes. + +- :example:`wifi/wifi_aware/usd_subscriber` demonstrates how to use the lightweight NAN Unsynchronized Service Discovery (NAN-USD) protocol to discover services advertised by nearby devices and interact with them. It covers enabling USD discovery, subscribing to services, handling follow-up exchanges, and terminating discovery after the session ends. + API Reference ------------- diff --git a/docs/en/migration-guides/release-6.x/6.0/wifi.rst b/docs/en/migration-guides/release-6.x/6.0/wifi.rst index 129eaf2c674..bf81351511f 100644 --- a/docs/en/migration-guides/release-6.x/6.0/wifi.rst +++ b/docs/en/migration-guides/release-6.x/6.0/wifi.rst @@ -46,4 +46,18 @@ The following Wi-Fi functions have been modified. - **WPS:** The function ``esp_wifi_wps_start`` no longer accepts a ``timeout_ms`` argument. It should now be called as ``esp_wifi_wps_start(void)``. -- **NAN:** The function argument ``ndp_resp_needed`` of ``esp_wifi_nan_publish_service`` has been moved to structure ``wifi_nan_publish_cfg_t``. +- **NAN:** + - NAN API's are modified so that they can be shared between two separate NAN modes of operation called NAN Synchronization (NAN-Sync) and NAN Unsynchronized Discovery (NAN-USD) roles: + - ``esp_wifi_nan_sync_start`` and ``esp_wifi_nan_sync_stop`` replace the previous ``esp_wifi_nan_start`` / ``esp_wifi_nan_stop`` pair. + - Functions starting with prefix ``esp_wifi_nan_*`` are shared by both NAN-Sync and NAN-USD modes (for example ``esp_wifi_nan_publish_service`` and ``esp_wifi_nan_subscribe_service``). + - Use ``WIFI_NAN_SYNC_CONFIG_DEFAULT()`` instead of the former ``WIFI_NAN_CONFIG_DEFAULT()`` macro when initialising synchronized NAN configuration. + - The structure ``wifi_nan_config_t`` has been renamed to ``wifi_nan_sync_config_t``; update declarations such as ``wifi_config_t.nan`` to use the new type. + - NAN datapath APIs and associated structures are valid for NAN Synchronization (NAN-Sync) clusters only. + - Wi-Fi events ``WIFI_EVENT_NAN_STARTED`` / ``WIFI_EVENT_NAN_STOPPED`` have been renamed to ``WIFI_EVENT_NAN_SYNC_STARTED`` / ``WIFI_EVENT_NAN_SYNC_STOPPED``. + - The function argument ``ndp_resp_needed`` of ``esp_wifi_nan_publish_service`` has been moved to structure ``wifi_nan_publish_cfg_t``. + - The structure ``wifi_nan_wfa_ssi_t`` now declares its ``proto`` field as ``uint8_t`` (previously ``wifi_nan_svc_proto_t``). Update code that stores pointers to this field or relies on its size to treat it as a single octet. + - The structures ``wifi_nan_publish_cfg_t`` and ``wifi_nan_subscribe_cfg_t`` now include a ``usd_discovery_flag`` bitfield together with corresponding ``wifi_nan_usd_config_t`` members. Add designated initialisers for these fields when constructing the structures to avoid accidental field shifts. + +- **Off-Channel Operations:** + - The structure :cpp:struct:`wifi_action_tx_req_t` now includes a ``bssid`` field that is placed in Address3 of the transmitted action frame. Initialise this field explicitly; leaving it all zeros retains the previous behaviour where the Wi-Fi driver inserts the broadcast address, so frames do not carry unintended BSSID values. + - The structure :cpp:struct:`wifi_roc_req_t` now includes an ``allow_broadcast`` flag that controls whether broadcast and multicast action frames are passed to the ``rx_cb`` callback during remain-on-channel operations. Existing applications should review the default ``false`` value and enable it when discovery of broadcast peers is required. Frames whose Address3/BSSID is already broadcast continue to reach the callback even when ``allow_broadcast`` remains ``false``. diff --git a/docs/zh_CN/migration-guides/release-6.x/6.0/wifi.rst b/docs/zh_CN/migration-guides/release-6.x/6.0/wifi.rst index 797a38bb2dd..68cb03ad4c4 100644 --- a/docs/zh_CN/migration-guides/release-6.x/6.0/wifi.rst +++ b/docs/zh_CN/migration-guides/release-6.x/6.0/wifi.rst @@ -46,5 +46,18 @@ Wi-Fi - **WPS:** 函数 ``esp_wifi_wps_start`` 不再接受 ``timeout_ms`` 参数。现在应调用为 ``esp_wifi_wps_start(void)``。 -- **NAN:** 函数 ``esp_wifi_nan_publish_service`` 的参数 ``ndp_resp_needed`` 已移至结构体 ``wifi_nan_publish_cfg_t``。 +- **NAN:** + - 已调整 NAN API,使其可在两个独立的 NAN 工作模式间共享:NAN 同步(NAN-Sync)与 NAN 非同步发现(NAN-USD): + - ``esp_wifi_nan_sync_start`` 与 ``esp_wifi_nan_sync_stop`` 取代原有的 ``esp_wifi_nan_start`` / ``esp_wifi_nan_stop``。 + - 以 ``esp_wifi_nan_*`` 为前缀的函数在 NAN-Sync 与 NAN 非同步发现(NAN-USD) 模式间通用(例如 ``esp_wifi_nan_publish_service``、``esp_wifi_nan_subscribe_service``)。 + - 初始化 NAN 同步配置时,请使用 ``WIFI_NAN_SYNC_CONFIG_DEFAULT()``,原 ``WIFI_NAN_CONFIG_DEFAULT()`` 已停用。 + - 结构体 ``wifi_nan_config_t`` 已重命名为 ``wifi_nan_sync_config_t``,例如需将 ``wifi_config_t.nan`` 等声明更新为新类型。 + - NAN 数据通道相关的 API 与结构体目前仅适用于 NAN 同步(NAN-Sync)集群。 + - Wi-Fi 事件 ``WIFI_EVENT_NAN_STARTED`` / ``WIFI_EVENT_NAN_STOPPED`` 已重命名为 ``WIFI_EVENT_NAN_SYNC_STARTED`` / ``WIFI_EVENT_NAN_SYNC_STOPPED``。 + - 函数 ``esp_wifi_nan_publish_service`` 的参数 ``ndp_resp_needed`` 已移至结构体 ``wifi_nan_publish_cfg_t``。 + - 结构体 ``wifi_nan_wfa_ssi_t`` 中的 ``proto`` 字段类型现为 ``uint8_t`` (之前为 ``wifi_nan_svc_proto_t``)。如果代码存储该字段的指针或依赖其大小,请按单个八位字节处理。 + - 结构体 ``wifi_nan_publish_cfg_t`` 和 ``wifi_nan_subscribe_cfg_t`` 新增 ``usd_discovery_flag`` 位域及对应的 ``wifi_nan_usd_config_t`` 成员。构造这些结构体时,请为新增字段提供指定初始化器,以避免字段偏移。 +- **离信道操作:** + - 结构体 :cpp:struct:`wifi_action_tx_req_t` 新增 ``bssid`` 字段,该字段会写入发送动作帧的 Address3。请显式初始化该字段;保持全零时将沿用之前的行为,由 Wi-Fi 驱动填入广播地址,从而避免帧携带意外的 BSSID。 + - 结构体 :cpp:struct:`wifi_roc_req_t` 新增 ``allow_broadcast`` 标志,用于控制在驻留信道期间是否将广播/组播动作帧传递给 ``rx_cb`` 回调。现有应用应结合默认值 ``false`` 评估是否需要启用该选项,以便在需要时进行广播节点发现。若动作帧的 Address3/BSSID 本身为广播地址,即便 ``allow_broadcast`` 保持 ``false``,回调仍会收到该帧。 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 b32f1db2880..8c91fcf09d1 100644 --- a/examples/wifi/wifi_aware/nan_console/main/nan_main.c +++ b/examples/wifi/wifi_aware/nan_console/main/nan_main.c @@ -234,7 +234,7 @@ static int wifi_cmd_nan_disc(int argc, char **argv) } if (nan_args.init->count) { - wifi_nan_config_t nan_cfg = WIFI_NAN_CONFIG_DEFAULT(); + wifi_nan_sync_config_t nan_cfg = WIFI_NAN_SYNC_CONFIG_DEFAULT(); if (nan_args.master_pref->count) { nan_cfg.master_pref = nan_args.master_pref->ival[0]; @@ -250,7 +250,7 @@ static int wifi_cmd_nan_disc(int argc, char **argv) g_nan_netif = esp_netif_create_default_wifi_nan(); } - if ((esp_wifi_nan_start(&nan_cfg)) != ESP_OK) { + if ((esp_wifi_nan_sync_start(&nan_cfg)) != ESP_OK) { ESP_LOGI(TAG, "Failed to start NAN"); esp_netif_destroy_default_wifi(g_nan_netif); g_nan_netif = NULL; @@ -266,7 +266,7 @@ static int wifi_cmd_nan_disc(int argc, char **argv) } if (nan_args.deinit->count) { - ret = esp_wifi_nan_stop(); + ret = esp_wifi_nan_sync_stop(); if (ret != ESP_OK) { ESP_LOGI(TAG, "Failed to stop NAN"); diff --git a/examples/wifi/wifi_aware/nan_console/sdkconfig.defaults b/examples/wifi/wifi_aware/nan_console/sdkconfig.defaults index be625a880c8..3d8f4d46579 100644 --- a/examples/wifi/wifi_aware/nan_console/sdkconfig.defaults +++ b/examples/wifi/wifi_aware/nan_console/sdkconfig.defaults @@ -1 +1 @@ -CONFIG_ESP_WIFI_NAN_ENABLE=y +CONFIG_ESP_WIFI_NAN_SYNC_ENABLE=y 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 7a7cad7cdc3..2ea6cd3cc4e 100644 --- a/examples/wifi/wifi_aware/nan_publisher/main/publisher_main.c +++ b/examples/wifi/wifi_aware/nan_publisher/main/publisher_main.c @@ -81,10 +81,10 @@ void wifi_nan_publish(void) &instance_any_id)); /* Start NAN Discovery */ - wifi_nan_config_t nan_cfg = WIFI_NAN_CONFIG_DEFAULT(); + wifi_nan_sync_config_t nan_cfg = WIFI_NAN_SYNC_CONFIG_DEFAULT(); esp_netif_create_default_wifi_nan(); - esp_wifi_nan_start(&nan_cfg); + esp_wifi_nan_sync_start(&nan_cfg); ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_NDP_INDICATION, diff --git a/examples/wifi/wifi_aware/nan_publisher/sdkconfig.defaults b/examples/wifi/wifi_aware/nan_publisher/sdkconfig.defaults index be625a880c8..3d8f4d46579 100644 --- a/examples/wifi/wifi_aware/nan_publisher/sdkconfig.defaults +++ b/examples/wifi/wifi_aware/nan_publisher/sdkconfig.defaults @@ -1 +1 @@ -CONFIG_ESP_WIFI_NAN_ENABLE=y +CONFIG_ESP_WIFI_NAN_SYNC_ENABLE=y 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 44aa622301d..88fbca9807d 100644 --- a/examples/wifi/wifi_aware/nan_subscriber/main/subscriber_main.c +++ b/examples/wifi/wifi_aware/nan_subscriber/main/subscriber_main.c @@ -177,10 +177,10 @@ void wifi_nan_subscribe(void) #endif /* Start NAN Discovery */ - wifi_nan_config_t nan_cfg = WIFI_NAN_CONFIG_DEFAULT(); + wifi_nan_sync_config_t nan_cfg = WIFI_NAN_SYNC_CONFIG_DEFAULT(); esp_netif_t *nan_netif = esp_netif_create_default_wifi_nan(); (void) nan_netif; - esp_wifi_nan_start(&nan_cfg); + esp_wifi_nan_sync_start(&nan_cfg); /* Subscribe a service */ uint8_t sub_id; diff --git a/examples/wifi/wifi_aware/nan_subscriber/sdkconfig.defaults b/examples/wifi/wifi_aware/nan_subscriber/sdkconfig.defaults index be625a880c8..3d8f4d46579 100644 --- a/examples/wifi/wifi_aware/nan_subscriber/sdkconfig.defaults +++ b/examples/wifi/wifi_aware/nan_subscriber/sdkconfig.defaults @@ -1 +1 @@ -CONFIG_ESP_WIFI_NAN_ENABLE=y +CONFIG_ESP_WIFI_NAN_SYNC_ENABLE=y diff --git a/examples/wifi/wifi_aware/usd_publisher/main/usd_publisher_example_main.c b/examples/wifi/wifi_aware/usd_publisher/main/usd_publisher_example_main.c index 8426737e874..09dec2dbded 100644 --- a/examples/wifi/wifi_aware/usd_publisher/main/usd_publisher_example_main.c +++ b/examples/wifi/wifi_aware/usd_publisher/main/usd_publisher_example_main.c @@ -59,9 +59,10 @@ void wifi_usd_publish(void) NULL, &instance_any_id)); + ESP_RETURN_VOID_ON_ERROR(esp_wifi_start(), TAG, "NAN-USD failed to start Wi-Fi"); + /* Start USD-NAN Discovery */ - wifi_nan_config_t usd_nan_cfg = WIFI_USD_NAN_CONFIG_DEFAULT(); - ESP_RETURN_VOID_ON_ERROR(esp_wifi_nan_start(&usd_nan_cfg), TAG, "NAN-USD initialization failed"); + ESP_RETURN_VOID_ON_ERROR(esp_wifi_nan_usd_start(), TAG, "NAN-USD initialization failed"); wifi_nan_publish_cfg_t publish_cfg = { .service_name = EXAMPLE_USD_SVC_NAME, @@ -101,7 +102,7 @@ void wifi_usd_publish(void) } esp_wifi_nan_cancel_service(g_publish_id); - esp_wifi_nan_stop(); + esp_wifi_nan_usd_stop(); } void initialise_wifi(void) @@ -110,6 +111,7 @@ void initialise_wifi(void) wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM) ); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL)); } void app_main(void) diff --git a/examples/wifi/wifi_aware/usd_publisher/sdkconfig.defaults b/examples/wifi/wifi_aware/usd_publisher/sdkconfig.defaults index 47d739bb224..d0ffed238ef 100644 --- a/examples/wifi/wifi_aware/usd_publisher/sdkconfig.defaults +++ b/examples/wifi/wifi_aware/usd_publisher/sdkconfig.defaults @@ -1 +1,2 @@ CONFIG_ESP_WIFI_NAN_USD_ENABLE=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y diff --git a/examples/wifi/wifi_aware/usd_subscriber/main/usd_subscriber_example_main.c b/examples/wifi/wifi_aware/usd_subscriber/main/usd_subscriber_example_main.c index af7a65b8bfa..32dc7132773 100644 --- a/examples/wifi/wifi_aware/usd_subscriber/main/usd_subscriber_example_main.c +++ b/examples/wifi/wifi_aware/usd_subscriber/main/usd_subscriber_example_main.c @@ -87,9 +87,10 @@ void wifi_usd_subscribe(void) NULL, &instance_any_id)); + ESP_RETURN_VOID_ON_ERROR(esp_wifi_start(), TAG, "NAN-USD failed to start Wi-Fi"); + /* Start NAN-USD Discovery */ - wifi_nan_config_t nan_usd_cfg = WIFI_USD_NAN_CONFIG_DEFAULT(); - esp_wifi_nan_start(&nan_usd_cfg); + ESP_RETURN_VOID_ON_ERROR(esp_wifi_nan_usd_start(), TAG, "NAN-USD initialization failed"); wifi_nan_subscribe_cfg_t subscribe_cfg = { .service_name = EXAMPLE_USD_SVC_NAME, @@ -134,6 +135,7 @@ void initialise_wifi(void) wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM) ); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL)); } void app_main(void) diff --git a/examples/wifi/wifi_aware/usd_subscriber/sdkconfig.defaults b/examples/wifi/wifi_aware/usd_subscriber/sdkconfig.defaults index 47d739bb224..d0ffed238ef 100644 --- a/examples/wifi/wifi_aware/usd_subscriber/sdkconfig.defaults +++ b/examples/wifi/wifi_aware/usd_subscriber/sdkconfig.defaults @@ -1 +1,2 @@ CONFIG_ESP_WIFI_NAN_USD_ENABLE=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y diff --git a/tools/idf_py_actions/hints.yml b/tools/idf_py_actions/hints.yml index ce4385d3666..c7af7f187d3 100644 --- a/tools/idf_py_actions/hints.yml +++ b/tools/idf_py_actions/hints.yml @@ -624,6 +624,10 @@ re: "error: implicit declaration of function 'esp_wifi_config_espnow_rate'" hint: "The function 'esp_wifi_config_espnow_rate' has been removed. Use 'esp_now_set_peer_rate_config' instead." +- + re: "(initialization|assignment) of 'wifi_nan_svc_proto_t \\*' from incompatible pointer type 'uint8_t \\*'" + hint: "The field 'proto' in structure 'wifi_nan_wfa_ssi_t' is now declared as 'uint8_t'. Update pointer usage accordingly, for example by using a 'uint8_t *' or copying the enum value into a separate variable." + - re: "error: too many arguments to function 'esp_wifi_wps_start'" hint: "The function 'esp_wifi_wps_start' no longer accepts a 'timeout_ms' argument." @@ -656,10 +660,36 @@ re: "error: 'peer_svc_info' undeclared" hint: "The field 'peer_svc_info' from structure 'wifi_event_nan_receive_t' has been removed. Please use the equivalent fields 'ssi' and 'ssi_len' instead." +- + re: "error: 'WIFI_EVENT_NAN_STARTED' undeclared" + hint: "The Wi-Fi NAN event 'WIFI_EVENT_NAN_STARTED' has been renamed to 'WIFI_EVENT_NAN_SYNC_STARTED'." + +- + re: "error: 'WIFI_EVENT_NAN_STOPPED' undeclared" + hint: "The Wi-Fi NAN event 'WIFI_EVENT_NAN_STOPPED' has been renamed to 'WIFI_EVENT_NAN_SYNC_STOPPED'." + - re: "error: too few arguments to function 'esp_wifi_nan_publish_service'" hint: "The function argument 'ndp_resp_needed' of 'esp_wifi_nan_publish_service' has been moved to structure 'wifi_nan_publish_cfg_t'." +- + re: "error: implicit declaration of function '{}'" + hint: "The NAN synchronization API '{}' has been renamed to '{}'." + variables: + - + re_variables: ['esp_wifi_nan_start'] + hint_variables: ['esp_wifi_nan_start', 'esp_wifi_nan_sync_start'] + - + re_variables: ['esp_wifi_nan_stop'] + hint_variables: ['esp_wifi_nan_stop', 'esp_wifi_nan_sync_stop'] + - + re_variables: ['WIFI_NAN_CONFIG_DEFAULT'] + hint_variables: ['WIFI_NAN_CONFIG_DEFAULT', 'WIFI_NAN_SYNC_CONFIG_DEFAULT'] + +- + re: "error: unknown type name 'wifi_nan_config_t'" + hint: "The structure 'wifi_nan_config_t' has been renamed to 'wifi_nan_sync_config_t'." + - re: "error: '(WIFI_REASON_ASSOC_EXPIRE|WIFI_REASON_NOT_AUTHED|WIFI_REASON_NOT_ASSOCED)' undeclared" hint: "The Wi-Fi disconnection reason codes '{0}' have been removed. Please use '{1}', '{2}', and '{3}' respectively."