[PATCH 1/5] USD: Support suspending USD operations

Andrei Otcheretianski andrei.otcheretianski at intel.com
Thu Oct 23 03:45:29 PDT 2025


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

Based on the USD specification, the device should always be either on
the default channel or one of the configured channels. However, to
allow operation of other interfaces, configure the NAN Discovery
Engine (DE) to relax the USD availability requirements:

- Allow to configure N-Min and N-Max to different values than the
  default ones, to increase availability for the other interfaces
  (by configuring lower values).
- Allow to configure a suspend cycle, where after a certain amount of
  time that USD is active, it would be suspended for a certain amount
  of time.

While this might reduce the availability of USD, it allows the
operation of other interfaces that share the same radio.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/common/nan_de.c | 139 +++++++++++++++++++++++++++++++++++++++-----
 src/common/nan_de.h |  12 ++++
 2 files changed, 137 insertions(+), 14 deletions(-)

diff --git a/src/common/nan_de.c b/src/common/nan_de.c
index 69175224de..8efa3f3dc5 100644
--- a/src/common/nan_de.c
+++ b/src/common/nan_de.c
@@ -67,6 +67,9 @@ struct nan_de_service {
 	bool is_pr;
 };
 
+#define NAN_DE_N_MIN 5
+#define NAN_DE_N_MAX 10
+
 struct nan_de {
 	u8 nmi[ETH_ALEN];
 	bool offload;
@@ -83,6 +86,9 @@ struct nan_de {
 	unsigned int listen_freq;
 	unsigned int tx_wait_status_freq;
 	unsigned int tx_wait_end_freq;
+
+	struct nan_de_cfg cfg;
+	struct os_reltime suspend_cycle_start;
 };
 
 
@@ -114,6 +120,8 @@ struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap,
 	de->max_listen = max_listen ? max_listen : 1000;
 	os_memcpy(&de->cb, cb, sizeof(*cb));
 
+	de->cfg.n_min = NAN_DE_N_MIN;
+	de->cfg.n_max = NAN_DE_N_MAX;
 	return de;
 }
 
@@ -547,7 +555,8 @@ static int nan_de_srv_time_to_next(struct nan_de *de,
 }
 
 
-static void nan_de_start_new_publish_state(struct nan_de_service *srv,
+static void nan_de_start_new_publish_state(struct nan_de *de,
+					   struct nan_de_service *srv,
 					   bool force_single)
 {
 	unsigned int n;
@@ -557,9 +566,8 @@ static void nan_de_start_new_publish_state(struct nan_de_service *srv,
 	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;
+	/* Use same values for N and M. */
+	n = de->cfg.n_min + os_random() % (de->cfg.n_max - de->cfg.n_min);
 	srv->next_publish_duration = n * 100;
 
 	nan_de_set_publish_times(srv);
@@ -584,6 +592,25 @@ static void nan_de_start_new_publish_state(struct nan_de_service *srv,
 }
 
 
+static u32 nan_de_listen_duration(struct nan_de *de, struct nan_de_service *srv)
+{
+	u32 duration = 1000;
+	u32 max_duration = de->max_listen;
+
+	/* limit the listen duration based on the maximal 'N' value */
+	if (de->cfg.n_max)
+		max_duration = de->cfg.n_max * 100;
+
+	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;
+	}
+
+	return duration > max_duration ? max_duration : duration;
+}
+
 static void nan_de_timer(void *eloop_ctx, void *timeout_ctx)
 {
 	struct nan_de *de = eloop_ctx;
@@ -594,6 +621,55 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx)
 
 	os_get_reltime(&now);
 
+	/* Based on the USD specification, the device should always be either on
+	 * the default channel or one of the configured channels. However, to
+	 * allow operation of other interfaces, suspend the USD functionality
+	 * based on the cycle and suspend parameters. This would lower the
+	 * probability of service discovery, but would allow functionality of
+	 * other interfaces.
+	 */
+	if (!de->listen_freq && de->cfg.cycle) {
+		struct os_reltime diff;
+		u32 diff_ms;
+
+		if (os_reltime_initialized(&de->suspend_cycle_start)) {
+			os_reltime_sub(&now, &de->suspend_cycle_start, &diff);
+			diff_ms = os_reltime_in_ms(&diff);
+		} else {
+			/* we want to start a new cycle */
+			diff_ms = de->cfg.cycle;
+		}
+
+		if (diff_ms < de->cfg.suspend) {
+			wpa_printf(MSG_DEBUG,
+				   "NAN: USD: Suspend in progress: diff_ms=%u",
+				   diff_ms);
+
+			/* set the timer to fire at the end of the suspend */
+			diff_ms = de->cfg.suspend - diff_ms;
+		} else if (diff_ms >= de->cfg.cycle) {
+			wpa_printf(MSG_DEBUG,
+				   "NAN: suspend USD for %u ms (passed=%u ms)",
+				   de->cfg.suspend, diff_ms);
+			de->suspend_cycle_start = now;
+
+			/* set the timer to fire at the end of the suspend */
+			diff_ms = de->cfg.suspend;
+		} else {
+			diff_ms = 0;
+		}
+
+		if (diff_ms) {
+			wpa_printf(MSG_DEBUG, "NAN: diff_ms=%u ms", diff_ms);
+
+			eloop_register_timeout(diff_ms / 1000,
+					       (diff_ms % 1000) * 1000,
+					       nan_de_timer,
+					       de, NULL);
+			return;
+		}
+	}
+
 	for (i = 0; i < NAN_DE_MAX_SERVICE; i++) {
 		struct nan_de_service *srv = de->service[i];
 		int srv_next;
@@ -618,7 +694,7 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx)
 
 		if (os_reltime_initialized(&srv->next_publish_state) &&
 		    os_reltime_before(&srv->next_publish_state, &now))
-			nan_de_start_new_publish_state(srv, false);
+			nan_de_start_new_publish_state(de, srv, false);
 
 		if (srv->type == NAN_DE_PUBLISH &&
 		    os_reltime_initialized(&srv->pause_state_end) &&
@@ -668,14 +744,7 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx)
 		      !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;
-			}
+			u32 duration = nan_de_listen_duration(de, srv);
 
 			started = true;
 			if (de->cb.listen(de->cb.ctx, srv->freq, duration) == 0)
@@ -1405,7 +1474,7 @@ int nan_de_publish(struct nan_de *de, const char *service_name,
 	/* Prepare for single and multi-channel states; starting with
 	 * single channel */
 	srv->first_multi_chan = true;
-	nan_de_start_new_publish_state(srv, true);
+	nan_de_start_new_publish_state(de, srv, true);
 
 	wpa_printf(MSG_DEBUG, "NAN: Assigned new publish handle %d for %s",
 		   publish_id, service_name ? service_name : "Ranging");
@@ -1606,3 +1675,45 @@ int nan_de_transmit(struct nan_de *de, int handle,
 
 	return 0;
 }
+
+
+int nan_de_config(struct nan_de *de, struct nan_de_cfg *cfg)
+{
+	if (!de || !cfg)
+		return -1;
+
+	 /* no change in configuration */
+	if (de->cfg.n_min == cfg->n_min && de->cfg.n_max == cfg->n_max &&
+	    de->cfg.cycle == cfg->cycle && de->cfg.suspend == cfg->suspend)
+		return 0;
+
+	wpa_printf(MSG_DEBUG,
+		   "NAN: Configuring NAN DE: n=(%u, %u), suspend=%u, cycle=%u",
+		   cfg->n_min, cfg->n_max, cfg->suspend, cfg->cycle);
+
+	if (!cfg->n_min && !cfg->n_max) {
+		cfg->n_min = NAN_DE_N_MIN;
+		cfg->n_max = NAN_DE_N_MAX;
+	} else if (cfg->n_min < 1 || cfg->n_max < cfg->n_min) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Invalid configuration parameters: N");
+		return -1;
+	}
+
+	if (((!!cfg->suspend) ^ (!!cfg->cycle)) ||
+	    (cfg->cycle && cfg->suspend >= cfg->cycle)) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Invalid configuration parameters: cycle");
+		return -1;
+	}
+
+	de->cfg = *cfg;
+
+	os_memset(&de->suspend_cycle_start, 0,
+		  sizeof(de->suspend_cycle_start));
+
+	if (!de->listen_freq)
+		nan_de_run_timer(de);
+
+	return 0;
+}
diff --git a/src/common/nan_de.h b/src/common/nan_de.h
index b423544649..004829d8d5 100644
--- a/src/common/nan_de.h
+++ b/src/common/nan_de.h
@@ -170,4 +170,16 @@ 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_cfg {
+	/* N and M minimal and maximal values */
+	u32 n_min, n_max;
+
+	/* When not in pause state, stop the DE radio usage for 'suspend' ms
+	 * every 'cycle' ms
+	 */
+	u32 suspend, cycle;
+};
+
+int nan_de_config(struct nan_de *de, struct nan_de_cfg *cfg);
+
 #endif /* NAN_DE_H */
-- 
2.49.0




More information about the Hostap mailing list