[RFC v2 94/99] wpa_supplicant: Implement NAN peer configuration and scheduling

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


Create a station for each new NMI peer. Configure peer schedule if
provided.
If the schedule is NULL, remove the schedule and the peer.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
 wpa_supplicant/nan_supplicant.c | 137 ++++++++++++++++++++++++++++++++
 1 file changed, 137 insertions(+)

diff --git a/wpa_supplicant/nan_supplicant.c b/wpa_supplicant/nan_supplicant.c
index 784d6ee8e1..0cf3faf0fa 100644
--- a/wpa_supplicant/nan_supplicant.c
+++ b/wpa_supplicant/nan_supplicant.c
@@ -171,6 +171,142 @@ static void wpas_nan_stop_cb(void *ctx)
 }
 
 
+static int wpas_nan_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 wpa_supplicant *wpa_s = ctx;
+	struct nan_peer_schedule_config peer_sched;
+	int i, j, ret;
+
+	wpa_printf(MSG_DEBUG, "NAN: Set peer schedule - nmi_addr=" MACSTR
+		   " new_sta=%d cdw=%u seq_id=%u max_chan_switch_time=%u",
+		   MAC2STR(nmi_addr), new_sta, cdw, sequence_id,
+		   max_channel_switch_time);
+
+	if (new_sta) {
+		struct hostapd_sta_add_params sta_params;
+
+		wpa_printf(MSG_DEBUG, "NAN: New NMI station");
+		os_memset(&sta_params, 0, sizeof(sta_params));
+		sta_params.addr = nmi_addr;
+		sta_params.flags = WPA_STA_AUTHENTICATED | WPA_STA_ASSOCIATED;
+		sta_params.flags_mask = sta_params.flags;
+		ret = wpa_drv_sta_add(wpa_s, &sta_params);
+		if (ret) {
+			wpa_printf(MSG_ERROR,
+				   "NAN: Failed to add NMI station");
+			return ret;
+		}
+	}
+
+	os_memset(&peer_sched, 0, sizeof(peer_sched));
+	if (sched) {
+		wpa_printf(MSG_DEBUG, "NAN: Peer schedule info:");
+		wpa_printf(MSG_DEBUG, "  n_maps=%u", sched->n_maps);
+
+		peer_sched.n_maps = sched->n_maps;
+		for (i = 0; i < sched->n_maps && i < MAX_NUM_NAN_MAPS; i++) {
+			struct nan_schedule_config *sched_cfg =
+				&peer_sched.maps[i].sched;
+
+			wpa_printf(MSG_DEBUG, "  Map %d: map_id=%u",
+				   i, sched->maps[i].map_id);
+
+			peer_sched.maps[i].map_id = sched->maps[i].map_id;
+			sched_cfg->num_channels = 0;
+
+			for (j = 0; j < sched->maps[i].n_chans &&
+			     sched_cfg->num_channels < MAX_NUM_NAN_SCHEDULE_CHANNELS;
+			     j++) {
+				const struct nan_map_chan *src_chan =
+					&sched->maps[i].chans[j];
+				struct nan_chan_entry *chan_entry;
+				int ch_idx;
+
+				if (!src_chan->committed)
+					continue;
+
+				wpa_printf(MSG_DEBUG,
+					   "    Channel freq=%d",
+					   sched->maps[i].chans[j].chan.freq);
+				wpa_hexdump(MSG_DEBUG, "      committed_bitmap",
+					    sched->maps[i].chans[j].tbm.bitmap,
+					    sched->maps[i].chans[j].tbm.len);
+
+				ch_idx = sched_cfg->num_channels;
+				sched_cfg->channels[ch_idx].freq =
+					src_chan->chan.freq;
+				sched_cfg->channels[ch_idx].center_freq1 =
+					src_chan->chan.center_freq1;
+				sched_cfg->channels[ch_idx].center_freq2 =
+					src_chan->chan.center_freq2;
+				sched_cfg->channels[ch_idx].bandwidth =
+					src_chan->chan.bandwidth;
+				sched_cfg->channels[ch_idx].rx_nss =
+					src_chan->rx_nss;
+				chan_entry = (void *)sched_cfg->channels[ch_idx].chan_entry;
+
+				ret = nan_get_chan_entry(wpa_s->nan,
+							 &src_chan->chan,
+							 chan_entry);
+				if (ret) {
+					wpa_printf(MSG_ERROR,
+						   "NAN: Failed to get chan entry for freq %d",
+						   src_chan->chan.freq);
+					goto out;
+				}
+
+				/* Copy time bitmap */
+				if (src_chan->tbm.len > 0) {
+					sched_cfg->channels[ch_idx].time_bitmap =
+						wpabuf_alloc_copy(
+							src_chan->tbm.bitmap,
+							src_chan->tbm.len);
+				}
+
+				sched_cfg->num_channels++;
+			}
+		}
+	}
+
+	ret = wpa_drv_nan_config_peer_schedule(wpa_s, nmi_addr,
+					       cdw, sequence_id,
+					       max_channel_switch_time,
+					       ulw_elems, &peer_sched);
+
+	/* Only print an error without returning, so we attempt to remove
+	 * the STA if needed (sched == NULL)
+	 */
+	if (ret)
+		wpa_printf(MSG_ERROR,
+			   "NAN: Failed to configure peer schedule");
+
+	if (!sched && !new_sta) {
+		/* TODO: Should we maybe keep that NMI station? */
+		wpa_printf(MSG_DEBUG, "NAN: Remove NMI station");
+		ret = wpa_drv_sta_remove(wpa_s, nmi_addr);
+		if (ret)
+			wpa_printf(MSG_ERROR,
+				   "NAN: Failed to remove NMI station");
+	}
+
+out:
+	/* Free allocated time bitmaps */
+	for (i = 0; i < peer_sched.n_maps; i++) {
+		struct nan_schedule_config *sched_cfg =
+			&peer_sched.maps[i].sched;
+
+		for (j = 0; j < sched_cfg->num_channels; j++)
+			wpabuf_free(sched_cfg->channels[j].time_bitmap);
+	}
+
+	return ret;
+}
+
+
 static void wpas_nan_ndp_action_notif_cb(void *ctx,
 					 struct nan_ndp_action_notif_params *params)
 {
@@ -444,6 +580,7 @@ int wpas_nan_init(struct wpa_supplicant *wpa_s)
 	nan.send_naf = wpas_nan_send_naf_cb;
 	nan.get_chans = wpas_nan_get_chans_cb;
 	nan.is_valid_publish_id = wpas_nan_is_valid_publish_id_cb;
+	nan.set_peer_schedule = wpas_nan_set_peer_schedule_cb;
 
 	/*
 	 * TODO: Set the device capabilities based on configuration and driver
-- 
2.49.0




More information about the Hostap mailing list