[PATCH 36/71] NAN: Configure peer NMI station and schedule
Andrei Otcheretianski
andrei.otcheretianski at intel.com
Wed Apr 1 15:01:45 PDT 2026
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 | 84 ++++++++++++++++++++++++++++++++++++--
src/nan/nan.h | 20 +++++++++
src/nan/nan_i.h | 4 ++
src/nan/nan_module_tests.c | 45 ++++++++++++++++++--
src/nan/nan_ndl.c | 81 ++++++++++++++++++++++++++++++++++++
5 files changed, 227 insertions(+), 7 deletions(-)
diff --git a/src/nan/nan.c b/src/nan/nan.c
index 6b0bd2b6fd..487e5a8ba5 100644
--- a/src/nan/nan.c
+++ b/src/nan/nan.c
@@ -1177,7 +1177,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");
@@ -1185,6 +1186,62 @@ static bool nan_ndp_supported(struct nan_data *nan)
}
+static void nan_peer_get_committed_avail(const struct nan_data *nan,
+ const 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");
+
+ if (!nan_ndl_peer_schedule_intersects(nan, peer)) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Cannot configure peer NMI STA - no intersecting schedule");
+ return 0;
+ }
+
+ 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;
@@ -1416,8 +1473,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;
@@ -1591,7 +1648,8 @@ int nan_tx_status(struct nan_data *nan, const u8 *dst, const u8 *data,
if (peer->ndp_setup.state == NAN_NDP_STATE_DONE &&
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);
}
@@ -1631,6 +1689,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:
/*
@@ -1646,6 +1710,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(
@@ -1665,6 +1735,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(
diff --git a/src/nan/nan.h b/src/nan/nan.h
index c6f06382c3..1906d2eed2 100644
--- a/src/nan/nan.h
+++ b/src/nan/nan.h
@@ -494,6 +494,26 @@ struct nan_config {
* instance ID; false otherse
*/
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 b7be2efa3c..701d98f773 100644
--- a/src/nan/nan_i.h
+++ b/src/nan/nan_i.h
@@ -406,6 +406,7 @@ struct nan_ndl {
* struct nan_peer - Represents a known NAN peer
* @list: List node for linking peers
* @nmi_addr: NMI 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
@@ -416,6 +417,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;
@@ -565,6 +567,8 @@ int nan_ndl_add_avail_attrs(struct nan_data *nan, const struct nan_peer *peer,
void nan_ndl_add_elem_container_attr(const struct nan_data *nan,
const struct nan_peer *peer,
struct wpabuf *buf);
+bool nan_ndl_peer_schedule_intersects(struct nan_data *nan,
+ struct nan_peer *peer);
int nan_get_chan_bm(struct nan_data *nan, struct nan_sched_chan *chan,
u8 *op_class, u16 *chan_bm, u16 *pri_chan_bm);
int nan_add_avail_attrs(struct nan_data *nan, u8 sequence_id,
diff --git a/src/nan/nan_module_tests.c b/src/nan/nan_module_tests.c
index 9fc0064308..b3369ea19e 100644
--- a/src/nan/nan_module_tests.c
+++ b/src/nan/nan_module_tests.c
@@ -850,6 +850,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
@@ -871,6 +893,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;
@@ -970,7 +993,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,
};
@@ -989,8 +1028,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 64689bcbe7..701aed18e0 100644
--- a/src/nan/nan_ndl.c
+++ b/src/nan/nan_ndl.c
@@ -119,6 +119,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;
@@ -1751,3 +1758,77 @@ void nan_ndl_add_elem_container_attr(const struct nan_data *nan,
wpabuf_put_u8(buf, 0);
wpabuf_put_buf(buf, ndl->sched.elems);
}
+
+
+/*
+ * nan_ndl_peer_schedule_intersects - Check if local and peer schedules
+ * intersect
+ *
+ * @nan: NAN module context from nan_init()
+ * @peer: The peer with whom the NDL is being setup
+ * Returns: True if schedules intersect, false otherwise
+ *
+ * The function checks if the local device schedule intersects with the peer
+ * device schedule.
+ */
+bool nan_ndl_peer_schedule_intersects(struct nan_data *nan,
+ struct nan_peer *peer)
+{
+ struct nan_schedule *sched;
+ size_t i;
+
+ if (!peer->ndl)
+ return false;
+
+ sched = &peer->ndl->sched;
+
+ /*
+ * Iterate over all the channels included in the local schedule. For
+ * each channel convert the committed and conditional slots to a
+ * bitfield object and extract the operating class and channel bitmap.
+ *
+ * Using the operating class and channel bitmap find the peer
+ * availability on that channel and check if it intersect with the
+ * local one.
+ */
+ wpa_printf(MSG_DEBUG, "NAN: n_chans=%u, ndc_map_id=%u",
+ sched->n_chans, sched->ndc_map_id);
+
+ for (i = 0; i < sched->n_chans; i++) {
+ struct bitfield *own_chan_bf = NULL, *peer_chan_bf = NULL;
+ u16 cbm, pri_cbm;
+ u8 map_id, op_class;
+ int ret;
+
+ /* Convert the schedule for the current channel to bitfield */
+ ret = nan_ndl_convert_chan_sched_to_bf(nan, &sched->chans[i],
+ &own_chan_bf, &map_id,
+ &op_class, &cbm,
+ &pri_cbm);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: NDL: Failed to convert chan sched to bitfield");
+ return false;
+ }
+
+ /* Get the peer availability for the current channel */
+ peer_chan_bf =
+ nan_avail_entries_to_bf(nan,
+ &peer->info.avail_entries,
+ op_class, cbm, pri_cbm);
+ if (!peer_chan_bf) {
+ bitfield_free(own_chan_bf);
+ continue;
+ }
+
+ ret = bitfield_intersects(own_chan_bf, peer_chan_bf);
+
+ bitfield_free(peer_chan_bf);
+ bitfield_free(own_chan_bf);
+
+ if (ret == 1)
+ return true;
+ }
+
+ return false;
+}
--
2.53.0
More information about the Hostap
mailing list