[PATCH 16/18] NAN: Keep the NDC across local schedule updates
Andrei Otcheretianski
andrei.otcheretianski at intel.com
Mon Oct 12 08:46:50 PDT 2026
Configuring new local schedule that doesn't include the NDC schedule
would break existing NDLs. Don't allow that.
A proper way to do that is by using 3-way NDL schedule update
negotiation, but this is not supported yet.
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
src/nan/nan.h | 2 +
src/nan/nan_util.c | 35 +++++++++++++
wpa_supplicant/nan_supplicant.c | 93 +++++++++++++++++++++++++++------
3 files changed, 113 insertions(+), 17 deletions(-)
diff --git a/src/nan/nan.h b/src/nan/nan.h
index d44d5f51ba..23a19b6254 100644
--- a/src/nan/nan.h
+++ b/src/nan/nan.h
@@ -960,6 +960,8 @@ bool nan_peer_sched_conflicts_with_ndc(struct nan_data *nan,
const struct nan_peer_schedule *peer_sched,
int freq,
const struct nan_time_bitmap *ndc);
+bool nan_tbm_covers(struct nan_data *nan, const struct nan_time_bitmap *a,
+ const struct nan_time_bitmap *b);
bool nan_tbm_equal(struct nan_data *nan, const struct nan_time_bitmap *a,
const struct nan_time_bitmap *b);
void nan_write_ndc_attr(struct wpabuf *buf, const u8 *ndc_id, u8 map_id,
diff --git a/src/nan/nan_util.c b/src/nan/nan_util.c
index 77e01f6a5f..3ea284cbd1 100644
--- a/src/nan/nan_util.c
+++ b/src/nan/nan_util.c
@@ -1984,6 +1984,41 @@ bool nan_peer_sched_conflicts_with_ndc(struct nan_data *nan,
}
+/**
+ * nan_tbm_covers - Check if a time bitmap covers all slots of another one
+ * @nan: Pointer to NAN data struct
+ * @a: The covering time bitmap
+ * @b: The time bitmap that has to be covered
+ * Returns: true if every slot set in @b is also set in @a
+ *
+ * Different duration, period, offset and length combinations can describe the
+ * same slots, so the comparison is done on the normalized bitmaps.
+ */
+bool nan_tbm_covers(struct nan_data *nan, const struct nan_time_bitmap *a,
+ const struct nan_time_bitmap *b)
+{
+ struct bitfield *a_bf, *b_bf;
+ bool covers = false;
+
+ /* An empty bitmap is not a schedule, so never report it as a match */
+ if (!a->len || !b->len)
+ return false;
+
+ a_bf = nan_tbm_to_bf(nan, a);
+ b_bf = nan_tbm_to_bf(nan, b);
+
+ if (a_bf && b_bf)
+ covers = bitfield_is_subset(a_bf, b_bf) == 1;
+ else
+ wpa_printf(MSG_DEBUG,
+ "NAN: Failed to convert time bitmap for comparison");
+
+ bitfield_free(a_bf);
+ bitfield_free(b_bf);
+ return covers;
+}
+
+
/**
* nan_tbm_equal - Check if two time bitmaps describe the same slots
* @nan: Pointer to NAN data struct
diff --git a/wpa_supplicant/nan_supplicant.c b/wpa_supplicant/nan_supplicant.c
index 46cae9df97..a74ad4ec9d 100644
--- a/wpa_supplicant/nan_supplicant.c
+++ b/wpa_supplicant/nan_supplicant.c
@@ -2617,6 +2617,62 @@ static void wpas_nan_update_local_schedule(struct wpa_supplicant *wpa_s)
}
+/* The configured bitmaps use the slot duration and period of the local capa */
+static int wpas_nan_chan_to_tbm(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *bitmap,
+ struct nan_time_bitmap *tbm)
+{
+ size_t len = wpabuf_len(bitmap);
+
+ if (len > NAN_TIME_BITMAP_MAX_LEN) {
+ wpa_printf(MSG_INFO,
+ "NAN: Time bitmap length %zu exceeds maximum %d",
+ len, NAN_TIME_BITMAP_MAX_LEN);
+ return -1;
+ }
+
+ os_memset(tbm, 0, sizeof(*tbm));
+ tbm->duration = wpa_s->nan_capa.slot_duration >> 5;
+ tbm->period = ffs(wpa_s->nan_capa.schedule_period) - 7;
+ tbm->offset = 0;
+ tbm->len = len;
+ os_memcpy(tbm->bitmap, wpabuf_head(bitmap), len);
+
+ return 0;
+}
+
+
+/*
+ * The NDC is the part of the schedule the connected peers rely on, so it must
+ * survive a local schedule update. Only a 3-way renegotiation, which is not
+ * supported, could move it.
+ */
+static bool wpas_nan_sched_covers_ndc(struct wpa_supplicant *wpa_s, u8 map_id,
+ const struct nan_schedule_config *sched)
+{
+ int i;
+
+ if (!wpa_s->nan_ndc.valid || wpa_s->nan_ndc.map_id != map_id)
+ return true;
+
+ for (i = 0; i < sched->num_channels; i++) {
+ struct nan_time_bitmap tbm;
+
+ if (sched->channels[i].freq != wpa_s->nan_ndc.freq ||
+ !sched->channels[i].time_bitmap)
+ continue;
+
+ if (wpas_nan_chan_to_tbm(wpa_s, sched->channels[i].time_bitmap,
+ &tbm))
+ return false;
+
+ return nan_tbm_covers(wpa_s->nan, &tbm, &wpa_s->nan_ndc.tbm);
+ }
+
+ return false;
+}
+
+
/* Parse format NAN_SCHED_CONFIG_MAP map_id=<id> [freq:bitmap_hex]..
* If no bitmaps provided - clear the map */
int wpas_nan_sched_config_map(struct wpa_supplicant *wpa_s, const char *cmd)
@@ -2677,6 +2733,14 @@ int wpas_nan_sched_config_map(struct wpa_supplicant *wpa_s, const char *cmd)
if (!pos) {
wpa_printf(MSG_INFO,
"NAN: Missing freq:timebitmap pairs - cleanup schedule");
+
+ if (wpa_s->nan_ndc.valid && wpa_s->nan_ndc.map_id == map_id) {
+ wpa_printf(MSG_INFO,
+ "NAN: Cannot clear map %u - it holds the established NDC",
+ map_id);
+ return -1;
+ }
+
ret = wpa_drv_nan_config_schedule(wpa_s, map_id, sched_cfg);
if (!ret) {
clear_sched_config(&wpa_s->nan_sched[map_id - 1]);
@@ -2836,6 +2900,13 @@ int wpas_nan_sched_config_map(struct wpa_supplicant *wpa_s, const char *cmd)
}
}
+ if (!wpas_nan_sched_covers_ndc(wpa_s, map_id, sched_cfg)) {
+ wpa_printf(MSG_INFO,
+ "NAN: New schedule for map %u doesn't cover the established NDC",
+ map_id);
+ goto out;
+ }
+
sched_cfg->avail_attr = wpabuf_alloc(NAN_AVAIL_ATTR_MAX_LEN);
if (!sched_cfg->avail_attr) {
wpa_printf(MSG_INFO,
@@ -3000,9 +3071,7 @@ wpas_nan_fill_ndp_schedule_chan(struct wpa_supplicant *wpa_s,
const struct nan_schedule_channel *chan)
{
struct nan_chan_schedule *chan_sched;
- struct nan_time_bitmap *tbm;
- const u8 *bitmap_data;
- size_t bitmap_len;
+ struct nan_time_bitmap tbm, *dst;
/* None of these should happen */
if (!chan->time_bitmap) {
@@ -3012,14 +3081,8 @@ wpas_nan_fill_ndp_schedule_chan(struct wpa_supplicant *wpa_s,
return -1;
}
- bitmap_len = wpabuf_len(chan->time_bitmap);
- bitmap_data = wpabuf_head(chan->time_bitmap);
- if (bitmap_len > NAN_TIME_BITMAP_MAX_LEN) {
- wpa_printf(MSG_INFO,
- "NAN: Time bitmap length %zu exceeds maximum %d",
- bitmap_len, NAN_TIME_BITMAP_MAX_LEN);
+ if (wpas_nan_chan_to_tbm(wpa_s, chan->time_bitmap, &tbm))
return -1;
- }
chan_sched = &sched->chans[sched->n_chans++];
chan_sched->map_id = map_id + 1;
@@ -3028,20 +3091,16 @@ wpas_nan_fill_ndp_schedule_chan(struct wpa_supplicant *wpa_s,
chan_sched->chan.center_freq2 = chan->center_freq2;
chan_sched->chan.bandwidth = chan->bandwidth;
- tbm = &chan_sched->committed;
+ dst = &chan_sched->committed;
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_s->nan_force_conditional_sched) {
wpa_printf(MSG_DEBUG,
"NAN: Using conditional TBM for schedule channel");
- tbm = &chan_sched->conditional;
+ dst = &chan_sched->conditional;
}
#endif /* CONFIG_TESTING_OPTIONS */
- tbm->duration = wpa_s->nan_capa.slot_duration >> 5;
- tbm->period = ffs(wpa_s->nan_capa.schedule_period) - 7;
- tbm->offset = 0;
- tbm->len = bitmap_len;
- os_memcpy(tbm->bitmap, bitmap_data, bitmap_len);
+ os_memcpy(dst, &tbm, sizeof(*dst));
wpa_printf(MSG_DEBUG,
"NAN: NDP schedule channel added: map_id=%d freq=%d center_freq1=%d center_freq2=%d bandwidth=%d",
--
2.53.0
More information about the Hostap
mailing list