[PATCH 3/7] NAN: Advertise services when Instant Communication is used

Andrei Otcheretianski andrei.otcheretianski at intel.com
Thu Oct 8 09:54:34 PDT 2026


From: Ilan Peer <ilan.peer at intel.com>

During Instant Communication, devices need to include the service
ID of services that they publish/subscribe in the NAN discovery
beacons.

Add the Service ID List attribute and the Subscriber Service ID List
attribute to the extra NAN attributes in the NAN configuration. The
attributes are only included when Instant Communication is enabled.

When services are added/removed trigger a NAN configuration
update (to update the attributes in the NAN discovery beacons).

The update is scheduled on a zero delay timeout as the discovery
engine reports the termination before it completes the removal of the
service, and to coalesce multiple notifications, e.g., when all
the services are flushed.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/common/nan_de.c             | 68 +++++++++++++++++++++++
 src/common/nan_de.h             |  1 +
 wpa_supplicant/nan_supplicant.c | 96 ++++++++++++++++++++++++++++++++-
 3 files changed, 163 insertions(+), 2 deletions(-)

diff --git a/src/common/nan_de.c b/src/common/nan_de.c
index 9210996fd7..ba691f137c 100644
--- a/src/common/nan_de.c
+++ b/src/common/nan_de.c
@@ -3145,6 +3145,74 @@ static int nan_de_derive_service_id(struct nan_de_service *srv)
 }
 
 
+static u8 * nan_de_add_service_id_list(struct nan_de *de, u8 *pos,
+				       enum nan_de_service_type type,
+				       enum nan_attr_id attr_id)
+{
+	size_t i, count = 0;
+
+	for (i = 0; i < NAN_DE_MAX_SERVICE && count < de->num_service; i++) {
+		struct nan_de_service *srv = de->service[i];
+
+		if (srv && srv->sync && srv->type == type)
+			count++;
+	}
+
+	if (!count)
+		return pos;
+
+	*pos++ = attr_id;
+	WPA_PUT_LE16(pos, count * NAN_SERVICE_ID_LEN);
+	pos += 2;
+
+	for (i = 0; i < NAN_DE_MAX_SERVICE; i++) {
+		struct nan_de_service *srv = de->service[i];
+
+		if (srv && srv->sync && srv->type == type) {
+			os_memcpy(pos, srv->service_id, NAN_SERVICE_ID_LEN);
+			pos += NAN_SERVICE_ID_LEN;
+		}
+	}
+
+	return pos;
+}
+
+
+/*
+ * nan_de_get_service_id_attrs - Get the Service ID List attributes
+ *
+ * @de: Pointer to the NAN DE context
+ * @len: Length of the returned buffer
+ * Returns an allocated buffer holding a Service ID List attribute with the
+ *	Service IDs of the published services and a Subscribed Service ID List
+ *	attribute with the Service IDs of the subscribed services, or %NULL if
+ *	there are no active services. The caller is responsible for freeing the
+ *	buffer.
+ */
+u8 * nan_de_get_service_id_attrs(struct nan_de *de, size_t *len)
+{
+	u8 *attrs, *pos;
+
+	*len = 0;
+
+	if (!de || !de->num_service)
+		return NULL;
+
+	attrs = os_malloc(2 * (1 + 2) +
+			  de->num_service * NAN_SERVICE_ID_LEN);
+	if (!attrs)
+		return NULL;
+
+	pos = nan_de_add_service_id_list(de, attrs, NAN_DE_PUBLISH,
+					 NAN_ATTR_NAN_ATTR_SERVICE_ID_LIST);
+	pos = nan_de_add_service_id_list(de, pos, NAN_DE_SUBSCRIBE,
+					 NAN_ATTR_SUBSC_SERVICE_ID_LIST);
+
+	*len = pos - attrs;
+	return attrs;
+}
+
+
 const u8 * nan_de_get_service_id(struct nan_de *de, int id)
 {
 	struct nan_de_service *srv;
diff --git a/src/common/nan_de.h b/src/common/nan_de.h
index 36d8a47951..40da54b8f0 100644
--- a/src/common/nan_de.h
+++ b/src/common/nan_de.h
@@ -126,6 +126,7 @@ bool nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, const u8 *a3,
 		   unsigned int freq, const u8 *buf, size_t len, int rssi,
 		   const u8 *orig_addr);
 const u8 * nan_de_get_service_id(struct nan_de *de, int id);
+u8 * nan_de_get_service_id_attrs(struct nan_de *de, size_t *len);
 
 struct nan_publish_params {
 	/* configuration_parameters */
diff --git a/wpa_supplicant/nan_supplicant.c b/wpa_supplicant/nan_supplicant.c
index a9ffab6172..d4534f5d7f 100644
--- a/wpa_supplicant/nan_supplicant.c
+++ b/wpa_supplicant/nan_supplicant.c
@@ -1662,13 +1662,57 @@ static bool wpas_nan_ndp_allowed(struct wpa_supplicant *wpa_s)
 }
 
 
+/*
+ * Instant communication requires advertising the active services in the
+ * Discovery Beacons
+ */
+static void wpas_nan_set_extra_attrs(struct wpa_supplicant *wpa_s)
+{
+	struct nan_cluster_config *config = &wpa_s->nan_cluster_config;
+
+	if (!config->instant_comm)
+		return;
+
+	config->extra_nan_attrs =
+		nan_de_get_service_id_attrs(wpa_s->nan_de,
+					    &config->extra_nan_attrs_len);
+}
+
+
+static void wpas_nan_clear_extra_attrs(struct wpa_supplicant *wpa_s)
+{
+	struct nan_cluster_config *config = &wpa_s->nan_cluster_config;
+
+	os_free((u8 *)config->extra_nan_attrs);
+	config->extra_nan_attrs = NULL;
+	config->extra_nan_attrs_len = 0;
+}
+
+
+static void wpas_nan_update_conf_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	wpas_nan_update_conf(wpa_s);
+}
+
+
 /* Join a cluster using current configuration */
 int wpas_nan_start(struct wpa_supplicant *wpa_s)
 {
+	int ret;
+
 	if (!wpas_nan_ready(wpa_s))
 		return -1;
 
-	return nan_start(wpa_s->nan, &wpa_s->nan_cluster_config);
+	/* The configuration used here supersedes a pending update */
+	eloop_cancel_timeout(wpas_nan_update_conf_timeout, wpa_s, NULL);
+
+	wpas_nan_set_extra_attrs(wpa_s);
+	ret = nan_start(wpa_s->nan, &wpa_s->nan_cluster_config);
+	wpas_nan_clear_extra_attrs(wpa_s);
+
+	return ret;
 }
 
 
@@ -2246,13 +2290,41 @@ int wpas_nan_set(struct wpa_supplicant *wpa_s, char *cmd)
 }
 
 
+/*
+ * The active services are advertised when instant communication is used
+ */
+static void wpas_nan_services_changed(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->nan_cluster_config.instant_comm)
+		return;
+
+	/*
+	 * Coalesce the updates and avoid reentrancy from the DE callbacks
+	 */
+	eloop_cancel_timeout(wpas_nan_update_conf_timeout, wpa_s, NULL);
+	eloop_register_timeout(0, 0, wpas_nan_update_conf_timeout, wpa_s, NULL);
+}
+
+
 int wpas_nan_update_conf(struct wpa_supplicant *wpa_s)
 {
+	int ret;
+
 	if (!wpas_nan_ready(wpa_s))
 		return -1;
 
 	wpa_printf(MSG_DEBUG, "NAN: Update NAN configuration");
-	return nan_update_config(wpa_s->nan, &wpa_s->nan_cluster_config);
+
+	/*
+	 * An explicit update supersedes a pending one
+	 */
+	eloop_cancel_timeout(wpas_nan_update_conf_timeout, wpa_s, NULL);
+
+	wpas_nan_set_extra_attrs(wpa_s);
+	ret = nan_update_config(wpa_s->nan, &wpa_s->nan_cluster_config);
+	wpas_nan_clear_extra_attrs(wpa_s);
+
+	return ret;
 }
 
 
@@ -4913,6 +4985,9 @@ static void wpas_nan_de_publish_terminated(void *ctx, int publish_id,
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
+#ifdef CONFIG_NAN
+	wpas_nan_services_changed(wpa_s);
+#endif /* CONFIG_NAN */
 	wpas_notify_nan_publish_terminated(wpa_s, publish_id, reason);
 }
 
@@ -4931,6 +5006,9 @@ static void wpas_nan_de_subscribe_terminated(void *ctx, int subscribe_id,
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
+#ifdef CONFIG_NAN
+	wpas_nan_services_changed(wpa_s);
+#endif /* CONFIG_NAN */
 	wpas_notify_nan_subscribe_terminated(wpa_s, subscribe_id, reason);
 }
 
@@ -5064,6 +5142,12 @@ void wpas_nan_de_deinit(struct wpa_supplicant *wpa_s)
 			     wpa_s, ELOOP_ALL_CTX);
 	nan_de_deinit(wpa_s->nan_de);
 	wpa_s->nan_de = NULL;
+#ifdef CONFIG_NAN
+	/*
+	 * The service termination callbacks can request a configuration update
+	 */
+	eloop_cancel_timeout(wpas_nan_update_conf_timeout, wpa_s, NULL);
+#endif /* CONFIG_NAN */
 }
 
 
@@ -5211,6 +5295,10 @@ int wpas_nan_publish(struct wpa_supplicant *wpa_s, const char *service_name,
 		nan_de_cancel_publish(wpa_s->nan_de, publish_id);
 		publish_id = -1;
 	}
+#ifdef CONFIG_NAN
+	if (publish_id >= 1 && params->sync)
+		wpas_nan_services_changed(wpa_s);
+#endif /* CONFIG_NAN */
 #ifdef CONFIG_AP
 	if (publish_id >= 1 && wpa_s->ap_iface && wpa_s->ap_iface->bss[0]) {
 		wpa_printf(MSG_DEBUG, "NAN: Linking nan_de for AP interface");
@@ -5388,6 +5476,10 @@ int wpas_nan_subscribe(struct wpa_supplicant *wpa_s,
 		nan_de_cancel_subscribe(wpa_s->nan_de, subscribe_id);
 		subscribe_id = -1;
 	}
+#ifdef CONFIG_NAN
+	if (subscribe_id >= 1 && params->sync)
+		wpas_nan_services_changed(wpa_s);
+#endif /* CONFIG_NAN */
 #ifdef CONFIG_AP
 	if (subscribe_id >= 1 && wpa_s->ap_iface && wpa_s->ap_iface->bss[0]) {
 		wpa_printf(MSG_DEBUG, "NAN: Linking nan_de for AP interface");
-- 
2.53.0




More information about the Hostap mailing list