[PATCH 19/35] NAN: Support synchronized SDF transmissions

Andrei Otcheretianski andrei.otcheretianski at intel.com
Mon Oct 20 05:27:54 PDT 2025


Handle DW notification and trigger transmission of multicast unsolicited
publish or active subscribe frames.
Skip USD specific logic for synchronized services.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
 src/common/nan_de.c             | 104 +++++++++++++++++++++++++++++---
 src/common/nan_de.h             |   7 +++
 wpa_supplicant/nan_supplicant.c |   7 ++-
 3 files changed, 107 insertions(+), 11 deletions(-)

diff --git a/src/common/nan_de.c b/src/common/nan_de.c
index d4d9d1e6ed..bee2e5bcfb 100644
--- a/src/common/nan_de.c
+++ b/src/common/nan_de.c
@@ -65,6 +65,7 @@ struct nan_de_service {
 	unsigned int next_publish_duration;
 	bool is_p2p;
 	bool is_pr;
+	bool sync;
 };
 
 struct nan_de {
@@ -85,6 +86,8 @@ struct nan_de {
 	unsigned int listen_freq;
 	unsigned int tx_wait_status_freq;
 	unsigned int tx_wait_end_freq;
+
+	int dw_freq;
 };
 
 
@@ -366,11 +369,14 @@ static void nan_de_tx_multicast(struct nan_de *de, struct nan_de_service *srv,
 
 		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;
+		if (!srv->sync) {
+			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 {
@@ -385,6 +391,17 @@ static void nan_de_tx_multicast(struct nan_de *de, struct nan_de_service *srv,
 		bssid = nan_network_id;
 	}
 
+	if (srv->sync) {
+		if (!de->cluster_id_set || !de->dw_freq) {
+			wpa_printf(MSG_DEBUG,
+				   "NAN: Cluster ID or DW frequency are not set. Skip sync TX");
+			return;
+		}
+
+		wait_time = 0;
+		bssid = de->cluster_id;
+	}
+
 	nan_de_tx_sdf(de, srv, wait_time, type, network_id, bssid,
 		      req_instance_id, srv->ssi);
 	os_get_reltime(&srv->last_multicast);
@@ -554,6 +571,9 @@ static void nan_de_start_new_publish_state(struct nan_de_service *srv,
 {
 	unsigned int n;
 
+	if (srv->sync)
+		return;
+
 	if (force_single || !srv->freq_list || srv->freq_list[0] == 0)
 		srv->in_multi_chan = false;
 	else
@@ -618,6 +638,9 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx)
 			continue;
 		}
 
+		if (srv->sync)
+			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);
@@ -887,6 +910,10 @@ static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv,
 			      enum nan_service_protocol_type srv_proto_type,
 			      const u8 *ssi, size_t ssi_len)
 {
+	/* Skip USD logic */
+	if (srv->sync)
+		goto send_event;
+
 	/* Subscribe function processing of a receive Publish message */
 	if (!os_reltime_initialized(&srv->first_discovered)) {
 		os_get_reltime(&srv->first_discovered);
@@ -908,6 +935,7 @@ static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv,
 				instance_id);
 	}
 
+send_event:
 	if (de->cb.discovery_result)
 		de->cb.discovery_result(
 			de->cb.ctx, srv->id, srv_proto_type,
@@ -1051,12 +1079,12 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv,
 	else if (srv->is_p2p)
 		a3 = de->nmi;
 
-	nan_de_tx(de, srv->freq, 100,
+	nan_de_tx(de, srv->sync ? 0 : srv->freq, srv->sync ? 0 : 100,
 		  srv->publish.solicited_multicast ? network_id : peer_addr,
 		  de->nmi, a3, buf);
 	wpabuf_free(buf);
 
-	if (!srv->is_p2p)
+	if (!srv->is_p2p && !srv->sync)
 		nan_de_pause_state(srv, peer_addr, instance_id);
 
 offload:
@@ -1083,7 +1111,7 @@ static void nan_de_rx_follow_up(struct nan_de *de, struct nan_de_service *srv,
 		return;
 	}
 
-	if (srv->type == NAN_DE_PUBLISH && !ssi)
+	if (srv->type == NAN_DE_PUBLISH && !ssi && !srv->sync)
 		nan_de_pause_state(srv, peer_addr, instance_id);
 
 	os_memcpy(srv->a3, a3, ETH_ALEN);
@@ -1359,6 +1387,18 @@ int nan_de_publish(struct nan_de *de, const char *service_name,
 		return -1;
 	}
 
+	if (params->sync && !de->cluster_id_set) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Publish() - can't publish sync, cluster id is not set");
+		return -1;
+	}
+
+	if (p2p && params->sync) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Publish() - P2P is not supported with sync");
+		return -1;
+	}
+
 	publish_id = nan_de_get_handle(de);
 	if (publish_id < 1)
 		return -1;
@@ -1404,6 +1444,8 @@ int nan_de_publish(struct nan_de *de, const char *service_name,
 			goto fail;
 	}
 
+	srv->sync = params->sync;
+
 	/* Prepare for single and multi-channel states; starting with
 	 * single channel */
 	srv->first_multi_chan = true;
@@ -1506,6 +1548,18 @@ int nan_de_subscribe(struct nan_de *de, const char *service_name,
 			   "NAN: Unable to fetch proximity ranging params");
 		return -1;
 	}
+	
+	if (params->sync && !de->cluster_id_set) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Subscribe() - can't publish sync, cluster id is not set");
+		return -1;
+	}
+
+	if (p2p && params->sync) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Subscribe() - P2P is not supported with sync");
+		return -1;
+	}
 
 	subscribe_id = nan_de_get_handle(de);
 	if (subscribe_id < 1)
@@ -1557,6 +1611,7 @@ int nan_de_subscribe(struct nan_de *de, const char *service_name,
 	srv->id = subscribe_id;
 	srv->is_p2p = p2p;
 	srv->is_pr = params->proximity_ranging && params->active;
+	srv->sync = params->sync;
 	nan_de_add_srv(de, srv);
 	nan_de_run_timer(de);
 	return subscribe_id;
@@ -1610,6 +1665,39 @@ int nan_de_transmit(struct nan_de *de, int handle,
 }
 
 
+void nan_de_dw_trigger(struct nan_de *de, int freq)
+{
+	int i;
+	struct os_reltime now;
+
+	de->dw_freq = freq;
+
+	if (!de->cluster_id_set) {
+		wpa_printf(MSG_DEBUG, "NAN: Skip DW, cluster ID not set");
+		return;
+	}
+
+	os_get_reltime(&now);
+	for (i = 0; i < NAN_DE_MAX_SERVICE; i++) {
+		struct nan_de_service *srv = de->service[i];
+
+		if (!srv || !srv->sync)
+			continue;
+
+		if (nan_de_srv_expired(srv, &now)) {
+			nan_de_del_srv(de, srv, NAN_DE_REASON_TIMEOUT);
+			continue;
+		}
+
+		if ((srv->type == NAN_DE_PUBLISH &&
+		     srv->publish.unsolicited) ||
+		    (srv->type == NAN_DE_SUBSCRIBE && srv->subscribe.active)) {
+			nan_de_tx_multicast(de, srv, 0);
+		}
+	}
+}
+
+
 void nan_de_set_cluster_id(struct nan_de *de, const u8 *cluster_id)
 {
 	if (cluster_id) {
diff --git a/src/common/nan_de.h b/src/common/nan_de.h
index 89238dd484..4b360907e2 100644
--- a/src/common/nan_de.h
+++ b/src/common/nan_de.h
@@ -118,6 +118,9 @@ struct nan_publish_params {
 
 	/* Proximity ranging flag */
 	bool proximity_ranging;
+
+	/* Synchronized discovery */
+	bool sync;
 };
 
 /* Returns -1 on failure or >0 publish_id */
@@ -154,6 +157,9 @@ struct nan_subscribe_params {
 
 	/* Proximity ranging flag */
 	bool proximity_ranging;
+
+	/* Synchronized discovery */
+	bool sync;
 };
 
 /* Returns -1 on failure or >0 subscribe_id */
@@ -169,6 +175,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);
+void nan_de_dw_trigger(struct nan_de *de, int freq);
 void nan_de_set_cluster_id(struct nan_de *de, const u8 *cluster_id);
 
 #endif /* NAN_DE_H */
diff --git a/wpa_supplicant/nan_supplicant.c b/wpa_supplicant/nan_supplicant.c
index a3b9bf6c20..b2b70bb6d8 100644
--- a/wpa_supplicant/nan_supplicant.c
+++ b/wpa_supplicant/nan_supplicant.c
@@ -135,8 +135,9 @@ void wpas_nan_cluster_join(struct wpa_supplicant *wpa_s,
 void wpas_nan_next_dw(struct wpa_supplicant *wpa_s, u32 freq)
 {
 	if (!wpas_nan_ready(wpa_s))
-	return;
+		return;
 
-	/* TODO: Handle DW notification */
 	wpa_printf(MSG_DEBUG, "NAN: Next DW notification freq=%d", freq);
-}
\ No newline at end of file
+	nan_de_dw_trigger(wpa_s->nan_de, freq);
+}
+
-- 
2.49.0




More information about the Hostap mailing list