[RFC v2 91/99] NAN: Configure peer NMI station and schedule

Andrei Otcheretianski andrei.otcheretianski at intel.com
Tue Dec 23 03:52:35 PST 2025


Add a new callback for peer schedule configuration and call it during
NDL establishment (as peer schedule may change while NDL is being
negotiated).

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
 src/nan/nan.c              | 78 ++++++++++++++++++++++++++++++++++++--
 src/nan/nan.h              | 20 ++++++++++
 src/nan/nan_i.h            |  2 +
 src/nan/nan_module_tests.c | 45 ++++++++++++++++++++--
 src/nan/nan_ndl.c          |  7 ++++
 5 files changed, 145 insertions(+), 7 deletions(-)

diff --git a/src/nan/nan.c b/src/nan/nan.c
index d64ae71aee..8703572794 100644
--- a/src/nan/nan.c
+++ b/src/nan/nan.c
@@ -1141,7 +1141,8 @@ static bool nan_ndp_supported(struct nan_data *nan)
 	if (nan->cfg->ndp_action_notif && nan->cfg->ndp_connected &&
 	    nan->cfg->ndp_disconnected &&
 	    nan->cfg->send_naf && nan->cfg->get_chans &&
-	    nan->cfg->is_valid_publish_id)
+	    nan->cfg->is_valid_publish_id &&
+	    nan->cfg->set_peer_schedule)
 		return true;
 
 	wpa_printf(MSG_DEBUG, "NAN: NDP operations are not supported");
@@ -1149,6 +1150,56 @@ static bool nan_ndp_supported(struct nan_data *nan)
 }
 
 
+static void nan_peer_get_committed_avail(struct nan_data *nan,
+					 struct nan_peer *peer,
+					 struct nan_peer_schedule *sched);
+
+
+static int nan_configure_peer_schedule(struct nan_data *nan,
+				       struct nan_peer *peer)
+{
+	int ret;
+	struct nan_dev_capa_entry *cur;
+	struct nan_device_capabilities *capa = NULL;
+	struct nan_peer_schedule sched;
+
+	wpa_printf(MSG_DEBUG, "NAN: Configure peer schedule");
+
+	dl_list_for_each(cur, &peer->info.dev_capa,
+			 struct nan_dev_capa_entry, list) {
+		/*
+		 * Take the first one, as both CDW and channel switch time are
+		 * identical across all attributes
+		 */
+		capa = &cur->capa;
+		break;
+	}
+
+	if (!capa) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Cannot configure peer NMI STA - no device capabilities");
+		return -1;
+	}
+
+	os_memset(&sched, 0, sizeof(sched));
+	nan_peer_get_committed_avail(nan, peer, &sched);
+
+	ret = nan->cfg->set_peer_schedule(nan->cfg->cb_ctx, peer->nmi_addr,
+					  !peer->configured, capa->cdw_info,
+					  peer->info.seq_id,
+					  capa->channel_switch_time, &sched,
+					  NULL);
+	if (ret) {
+		wpa_printf(MSG_DEBUG,
+			   "NAN: Failed to set peer schedule");
+		return ret;
+	}
+
+	peer->configured = true;
+	return 0;
+}
+
+
 static void nan_peer_state_timeout(void *eloop_ctx, void *timeout_ctx)
 {
 	struct nan_data *nan = eloop_ctx;
@@ -1381,8 +1432,8 @@ static int nan_action_rx_ndp(struct nan_data *nan, struct nan_peer *peer,
 	if (peer->ndp_setup.state == NAN_NDP_STATE_DONE &&
 	    peer->ndl->state == NAN_NDL_STATE_DONE) {
 		wpa_printf(MSG_DEBUG, "NAN: NAF: NDP setup done");
-
-		if (nan_ndp_connected(nan, peer))
+		if (nan_configure_peer_schedule(nan, peer) ||
+		    nan_ndp_connected(nan, peer))
 			nan_ndp_disconnected(nan, peer,
 					     NAN_REASON_UNSPECIFIED_REASON);
 		return 0;
@@ -1561,7 +1612,8 @@ int nan_tx_status(struct nan_data *nan, const u8 *dst, const u8 *data,
 	    peer->ndl->state == NAN_NDL_STATE_DONE) {
 		wpa_printf(MSG_DEBUG, "NAN: TX status:  NDP setup done");
 
-		if (nan_ndp_connected(nan, peer))
+		if (nan_configure_peer_schedule(nan, peer) ||
+		    nan_ndp_connected(nan, peer))
 			nan_ndp_disconnected(nan, peer,
 					     NAN_REASON_UNSPECIFIED_REASON);
 	}
@@ -1601,6 +1653,12 @@ int nan_handle_ndp_setup(struct nan_data *nan, struct nan_ndp_params *params)
 
 		naf_oui = NAN_SUBTYPE_DATA_PATH_REQUEST;
 		timeout = NAN_NDP_SETUP_TIMEOUT_LONG;
+		ret = nan_configure_peer_schedule(nan, peer);
+		if (ret) {
+			nan_ndp_setup_stop(nan, peer);
+			return ret;
+		}
+
 		break;
 	case NAN_NDP_ACTION_RESP:
 		/*
@@ -1616,6 +1674,12 @@ int nan_handle_ndp_setup(struct nan_data *nan, struct nan_ndp_params *params)
 
 		if (peer->ndp_setup.status != NAN_NDP_STATUS_REJECTED) {
 			ret = nan_ndl_setup(nan, peer, params);
+			if (!ret) {
+				ret = nan_configure_peer_schedule(nan, peer);
+				if (ret)
+					peer->ndl->send_naf_on_error = 1;
+			}
+
 			if (ret) {
 				if (peer->ndl && peer->ndl->send_naf_on_error) {
 					nan_ndp_setup_failure(nan, peer,
@@ -1635,6 +1699,12 @@ int nan_handle_ndp_setup(struct nan_data *nan, struct nan_ndp_params *params)
 		break;
 	case NAN_NDP_ACTION_CONF:
 		ret = nan_ndl_setup(nan, peer, params);
+		if (!ret) {
+			ret = nan_configure_peer_schedule(nan, peer);
+			if (ret)
+				peer->ndl->send_naf_on_error = 1;
+		}
+
 		if (ret) {
 			if (peer->ndl && peer->ndl->send_naf_on_error) {
 				nan_ndp_setup_failure(nan, peer,
diff --git a/src/nan/nan.h b/src/nan/nan.h
index 40d870e46c..14b8525ca7 100644
--- a/src/nan/nan.h
+++ b/src/nan/nan.h
@@ -501,6 +501,26 @@ struct nan_config {
 	 * instance ID
 	 */
 	bool (*is_valid_publish_id)(void *ctx, u8 instance_id, u8 *service_id);
+
+	/**
+	 * set_peer_schedule - Configure peer schedule
+	 *
+	 * @ctx: Callback context from cb_ctx
+	 * @nmi_addr: NAN Management Interface address of the peer
+	 * @new_sta: Indicates whether this is a new STA (true) or an existing
+	 *     STA that is being re-configured (false).
+	 * @cdw: Committed DW information (from device capabilities)
+	 * @sequence_id: Schedule sequence ID
+	 * @max_channel_switch_time: Maximum channel switch time
+	 * @sched: Peer schedule information; can be NULL
+	 * @ulw_elems: ULW elements buffer; can be NULL
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_peer_schedule)(void *ctx, const u8 *nmi_addr, bool new_sta,
+				 u16 cdw, u8 sequence_id,
+				 u16 max_channel_switch_time,
+				 const struct nan_peer_schedule *sched,
+				 const struct wpabuf *ulw_elems);
 };
 
 struct nan_data * nan_init(const struct nan_config *cfg);
diff --git a/src/nan/nan_i.h b/src/nan/nan_i.h
index fec1f6cfcd..aa34b6658f 100644
--- a/src/nan/nan_i.h
+++ b/src/nan/nan_i.h
@@ -403,6 +403,7 @@ struct nan_ndl {
  * struct nan_peer - Represents a known NAN peer
  * @list: List node for linking peers.
  * @nmi_addr: NAN MAC address of the peer.
+ * @configured: Indicates if the peer has been configured to the device.
  * @last_seen: Timestamp of the last time this peer was seen.
  * @info: Information about the peer.
  * @ndps: List of NDPs associated with this peer.
@@ -413,6 +414,7 @@ struct nan_ndl {
 struct nan_peer {
 	struct dl_list list;
 	u8 nmi_addr[ETH_ALEN];
+	bool configured;
 	struct os_reltime last_seen;
 	struct nan_peer_info info;
 
diff --git a/src/nan/nan_module_tests.c b/src/nan/nan_module_tests.c
index 164982b5d3..7d86ffaebc 100644
--- a/src/nan/nan_module_tests.c
+++ b/src/nan/nan_module_tests.c
@@ -863,6 +863,28 @@ static bool nan_test_is_valid_publish_id_cb(void *ctx, u8 instance_id,
 	return true;
 }
 
+/*
+ * nan_test_set_peer_schedule_cb - Set peer schedule callback
+ *
+ * @ctx: Pointer to &struct nan_device
+ * @sched: Pointer to &struct nan_peer_schedule to be filled
+ */
+static int
+nan_test_set_peer_schedule_cb(void *ctx, const u8 *nmi_addr, bool new_sta,
+			      u16 cdw, u8 sequence_id,
+			      u16 max_channel_switch_time,
+			      const struct nan_peer_schedule *sched,
+			      const struct wpabuf *ulw_elems)
+{
+	struct nan_device *dev = (struct nan_device *)ctx;
+
+	DEV_NOT_INIT_ERR(dev);
+
+	wpa_printf(MSG_INFO, "%s: %s: Enter", dev->name, __func__);
+	wpa_printf(MSG_INFO, "%s: nmi_addr=" MACSTR " new_sta=%d cdw=%u sequence_id=%u max_channel_switch_time=%u",
+		   dev->name, MAC2STR(nmi_addr), new_sta, cdw, sequence_id, max_channel_switch_time);
+	return 0;
+}
 
 /*
  * nan_test_dev_init - Initialize a test device instance
@@ -885,6 +907,7 @@ static int nan_test_dev_init(struct nan_device *dev)
 	nan.send_naf = nan_test_send_naf_cb;
 	nan.get_chans = nan_test_get_chans_cb;
 	nan.is_valid_publish_id = nan_test_is_valid_publish_id_cb;
+	nan.set_peer_schedule = nan_test_set_peer_schedule_cb;
 
 	/* Awake on every DW on 2 GHz and 5 GHz */
 	nan.dev_capa.cdw_info = 0x9;
@@ -982,7 +1005,23 @@ nan_test_setup_devices(struct nan_test_global *global,
 		.master_pref = 2,
 		.dual_band = 1,
 	};
-	const u8 pot_avail[] = {
+	/*
+	 * Device attributes containing:
+	 * 1. Device capability attribute (ID=0x0F, len=10):
+	 *    - map_id=0
+	 *    - cdw_info=0x0009 (awake on every DW on 2G and 5G)
+	 *    - supported_bands=0x07 (2G, 5G, 6G)
+	 *    - op_mode=0x01
+	 *    - n_antennas=0x22
+	 *    - channel_switch_time=0x000a (10)
+	 *    - capa=0x00
+	 * 2. Availability attribute (ID=0x12, len=12)
+	 */
+	const u8 attrs[] = {
+		/* Device capability attribute */
+		0x0f, 0x09, 0x00, 0x00, 0x09, 0x00, 0x07, 0x01,
+		0x22, 0x0a, 0x00, 0x00,
+		/* Availability attribute */
 		0x12, 0x0c, 0x00, 0x01, 0x20, 0x00, 0x07, 0x00,
 		0x1a, 0x00, 0x11, 0x51, 0xff, 0x07, 0x00,
 	};
@@ -1001,8 +1040,8 @@ nan_test_setup_devices(struct nan_test_global *global,
 	if (!sub)
 		goto fail;
 
-	nan_add_peer(pub->nan, sub_nmi, pot_avail, sizeof(pot_avail));
-	nan_add_peer(sub->nan, pub_nmi, pot_avail, sizeof(pot_avail));
+	nan_add_peer(pub->nan, sub_nmi, attrs, sizeof(attrs));
+	nan_add_peer(sub->nan, pub_nmi, attrs, sizeof(attrs));
 
 	wpa_printf(MSG_INFO, "\n%s: Done\n", __func__);
 	return sub;
diff --git a/src/nan/nan_ndl.c b/src/nan/nan_ndl.c
index 4609ba65b8..8fb7cd7405 100644
--- a/src/nan/nan_ndl.c
+++ b/src/nan/nan_ndl.c
@@ -118,6 +118,13 @@ static void nan_ndl_clear(struct nan_data *nan, struct nan_peer *peer)
 		   MAC2STR(peer->nmi_addr),
 		   nan_ndl_state_str(peer->ndl->state), peer->ndl->state);
 
+	if (peer->configured) {
+		nan->cfg->set_peer_schedule(nan->cfg->cb_ctx, peer->nmi_addr,
+					    false, 0, 0, 0, NULL,
+					    NULL);
+		peer->configured = false;
+	}
+
 	os_free(ndl->ndc_sched);
 	ndl->ndc_sched = NULL;
 	ndl->ndc_sched_len = 0;
-- 
2.49.0




More information about the Hostap mailing list