[PATCH 08/18] NAN: Store and report NDCs advertised by peers
Andrei Otcheretianski
andrei.otcheretianski at intel.com
Mon Oct 12 08:46:42 PDT 2026
A peer may advertise NDCs it participates in outside of an NDL
negotiation, e.g. in a Publish SDF.
Parse and expose it in the peer schedule dump.
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
src/nan/nan.c | 126 +++++++++++++++++++++++++++++++++++++++++----
src/nan/nan.h | 11 +++-
src/nan/nan_i.h | 17 ++++++
src/nan/nan_util.c | 53 +++++++++----------
4 files changed, 167 insertions(+), 40 deletions(-)
diff --git a/src/nan/nan.c b/src/nan/nan.c
index ef35646782..929e8ea7cf 100644
--- a/src/nan/nan.c
+++ b/src/nan/nan.c
@@ -129,6 +129,18 @@ static void nan_peer_flush_ulw(struct nan_peer_info *info)
}
+static void nan_peer_flush_ndc(struct nan_peer_info *info)
+{
+ struct nan_ndc_entry *cur, *next;
+
+ dl_list_for_each_safe(cur, next, &info->ndc,
+ struct nan_ndc_entry, list) {
+ dl_list_del(&cur->list);
+ os_free(cur);
+ }
+}
+
+
static struct wpabuf *
nan_peer_build_ulw_attrs(const struct nan_peer_info *info)
{
@@ -265,6 +277,7 @@ static void nan_del_peer(struct nan_data *nan, struct nan_peer *peer)
nan_peer_flush_ulw(&peer->info);
nan_peer_flush_dev_capa(&peer->info);
nan_peer_flush_elem_container(&peer->info);
+ nan_peer_flush_ndc(&peer->info);
nan_remove_group_keys(nan, peer);
nan_ndl_reset(nan, peer);
@@ -1108,6 +1121,7 @@ static void nan_merge_peer_info(struct nan_data *nan, struct nan_peer *peer,
struct nan_peer_info *old,
struct nan_peer_info *new)
{
+ struct nan_ndc_entry *ndc, *tmp_ndc;
bool schedule_changed = false;
if (!dl_list_empty(&new->avail_entries)) {
@@ -1142,6 +1156,15 @@ static void nan_merge_peer_info(struct nan_data *nan, struct nan_peer *peer,
old->last_seen = new->last_seen;
+ /* NDCs the peer only advertises are informational, so just store them */
+ nan_peer_flush_ndc(old);
+
+ dl_list_for_each_safe(ndc, tmp_ndc, &new->ndc,
+ struct nan_ndc_entry, list) {
+ dl_list_del(&ndc->list);
+ dl_list_add(&old->ndc, &ndc->list);
+ }
+
if (!schedule_changed)
return;
@@ -1367,6 +1390,51 @@ static int nan_parse_peer_ulw(const struct nan_attrs *attrs,
}
+/*
+ * Selected NDCs are tracked via NDL negotiation instead; this is only for
+ * NDCs a peer merely advertises, e.g. in a Publish SDF.
+ */
+static int nan_parse_peer_ndc(const struct nan_attrs *attrs,
+ struct nan_peer_info *info)
+{
+ const struct nan_attrs_entry *attr;
+
+ dl_list_for_each(attr, &attrs->ndc, struct nan_attrs_entry, list) {
+ const struct ieee80211_ndc *ndc_attr;
+ struct nan_ndc_entry *entry;
+ u16 sched_len;
+
+ if (attr->len < sizeof(*ndc_attr))
+ continue;
+
+ ndc_attr = (const struct ieee80211_ndc *) attr->ptr;
+
+ if (ndc_attr->ctrl & NAN_NDC_CTRL_SELECTED)
+ continue;
+
+ sched_len = attr->len - sizeof(*ndc_attr);
+ if (sched_len <= sizeof(struct nan_sched_entry))
+ continue;
+
+ entry = os_zalloc(sizeof(*entry) + sched_len);
+ if (!entry) {
+ wpa_printf(MSG_INFO,
+ "NAN: Failed to allocate NDC entry");
+ nan_peer_flush_ndc(info);
+ return -1;
+ }
+
+ dl_list_init(&entry->list);
+ dl_list_add(&info->ndc, &entry->list);
+ os_memcpy(entry->ndc_id, ndc_attr->ndc_id, ETH_ALEN);
+ entry->len = sched_len;
+ os_memcpy(entry->sched, ndc_attr + 1, sched_len);
+ }
+
+ return 0;
+}
+
+
void nan_parse_peer_dev_capa_ext(struct nan_data *nan, struct nan_peer *peer,
struct nan_attrs *attrs)
{
@@ -1493,6 +1561,7 @@ int nan_parse_device_attrs(struct nan_data *nan, struct nan_peer *peer,
os_memset(&info, 0, sizeof(info));
dl_list_init(&info.avail_entries);
dl_list_init(&info.ulw);
+ dl_list_init(&info.ndc);
os_get_reltime(&info.last_seen);
if (nan_parse_attrs(nan, attrs_data, attrs_len, &attrs)) {
@@ -1512,6 +1581,11 @@ int nan_parse_device_attrs(struct nan_data *nan, struct nan_peer *peer,
goto out;
}
+ if (nan_parse_peer_ndc(&attrs, &info)) {
+ ret = -1;
+ goto out;
+ }
+
nan_merge_peer_info(nan, peer, &peer->info, &info);
if (attrs.conn_capa_valid) {
peer->info.conn_capa = attrs.conn_capa;
@@ -1535,6 +1609,7 @@ int nan_parse_device_attrs(struct nan_data *nan, struct nan_peer *peer,
out:
nan_peer_flush_avail(&info);
nan_peer_flush_ulw(&info);
+ nan_peer_flush_ndc(&info);
nan_attrs_clear(nan, &attrs);
return ret;
}
@@ -1580,6 +1655,7 @@ static struct nan_peer * nan_alloc_peer(struct nan_data *nan)
dl_list_init(&peer->info.dev_capa);
dl_list_init(&peer->info.element_container);
dl_list_init(&peer->info.sec);
+ dl_list_init(&peer->info.ndc);
dl_list_add(&nan->peer_list, &peer->list);
dl_list_init(&peer->ndps);
@@ -3326,10 +3402,16 @@ nan_peer_get_committed_avail(const struct nan_data *nan,
}
+enum nan_map_sched_dest {
+ NAN_MAP_SCHED_NDC,
+ NAN_MAP_SCHED_NDC_ADVERTISED,
+ NAN_MAP_SCHED_IMMUTABLE,
+};
+
static void nan_peer_set_sched(struct nan_data *nan, struct nan_peer *peer,
struct nan_peer_schedule *sched,
const u8 *sched_buf, size_t sched_buf_len,
- bool ndc)
+ enum nan_map_sched_dest dest, const u8 *ndc_id)
{
struct dl_list sched_entries;
struct nan_avail_entry *cur;
@@ -3378,10 +3460,29 @@ static void nan_peer_set_sched(struct nan_data *nan, struct nan_peer *peer,
continue;
}
- if (ndc)
+ switch (dest) {
+ case NAN_MAP_SCHED_NDC:
os_memcpy(&map->ndc, &cur->tbm, sizeof(cur->tbm));
- else
+ break;
+ case NAN_MAP_SCHED_IMMUTABLE:
os_memcpy(&map->immutable, &cur->tbm, sizeof(cur->tbm));
+ break;
+ case NAN_MAP_SCHED_NDC_ADVERTISED: {
+ struct nan_advertised_ndc *adv;
+
+ if (map->n_ndc_advertised >= NAN_MAX_NDC_ADVERTISED) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Too many advertised NDCs for map_id=%u",
+ map->map_id);
+ break;
+ }
+
+ adv = &map->ndc_advertised[map->n_ndc_advertised++];
+ os_memcpy(adv->id, ndc_id, ETH_ALEN);
+ os_memcpy(&adv->tbm, &cur->tbm, sizeof(cur->tbm));
+ break;
+ }
+ }
}
nan_flush_avail_entries(&sched_entries);
@@ -3392,12 +3493,18 @@ static void nan_peer_get_ndc_sched(struct nan_data *nan,
struct nan_peer *peer,
struct nan_peer_schedule *sched)
{
- if (!peer->ndl)
- return;
+ struct nan_ndc_entry *entry;
- nan_peer_set_sched(nan, peer, sched,
- peer->ndl->ndc_sched,
- peer->ndl->ndc_sched_len, true);
+ if (peer->ndl)
+ nan_peer_set_sched(nan, peer, sched,
+ peer->ndl->ndc_sched,
+ peer->ndl->ndc_sched_len,
+ NAN_MAP_SCHED_NDC, NULL);
+
+ /* Also dump any NDCs the peer merely advertises */
+ dl_list_for_each(entry, &peer->info.ndc, struct nan_ndc_entry, list)
+ nan_peer_set_sched(nan, peer, sched, entry->sched, entry->len,
+ NAN_MAP_SCHED_NDC_ADVERTISED, entry->ndc_id);
}
@@ -3410,7 +3517,8 @@ static void nan_peer_get_immut_sched(struct nan_data *nan,
nan_peer_set_sched(nan, peer, sched,
peer->ndl->immut_sched,
- peer->ndl->immut_sched_len, false);
+ peer->ndl->immut_sched_len,
+ NAN_MAP_SCHED_IMMUTABLE, NULL);
}
diff --git a/src/nan/nan.h b/src/nan/nan.h
index 088f98019c..36e7a2ddd7 100644
--- a/src/nan/nan.h
+++ b/src/nan/nan.h
@@ -374,6 +374,7 @@ struct nan_ndp_action_notif_params {
#define NAN_MAX_MAPS 8
#define NAN_MAX_CHAN_ENTRIES 16
+#define NAN_MAX_NDC_ADVERTISED 4
/**
* struct nan_peer_schedule - NAN peer schedule information
@@ -387,7 +388,10 @@ struct nan_ndp_action_notif_params {
* channel
* @chan: Channel information
* @tbm: Time bitmap for the channel
- * @ndc: NDC time bitmap for the map
+ * @ndc: Negotiated NDC time bitmap for the map, if any
+ * @n_ndc_advertised: Number of entries in @ndc_advertised
+ * @ndc_advertised: NDCs the peer merely advertised for the map, each with its
+ * ID and time bitmap
* @immutable: Immutable time bitmap for the map
* @max_idle_period: Maximal NDL idle period in seconds that the peer indicated
*/
@@ -404,6 +408,11 @@ struct nan_peer_schedule {
} chans[NAN_MAX_CHAN_ENTRIES];
struct nan_time_bitmap ndc;
+ u8 n_ndc_advertised;
+ struct nan_advertised_ndc {
+ u8 id[ETH_ALEN];
+ struct nan_time_bitmap tbm;
+ } ndc_advertised[NAN_MAX_NDC_ADVERTISED];
struct nan_time_bitmap immutable;
} maps[NAN_MAX_MAPS];
diff --git a/src/nan/nan_i.h b/src/nan/nan_i.h
index 09f33db23b..2fa012d826 100644
--- a/src/nan/nan_i.h
+++ b/src/nan/nan_i.h
@@ -305,6 +305,20 @@ struct nan_ulw_entry {
u8 data[];
};
+/**
+ * struct nan_ndc_entry - A NDC a peer merely advertised, e.g. in a Publish SDF
+ * @list: Linked in struct nan_peer_info::ndc
+ * @ndc_id: NDC ID, for information only
+ * @len: Length of @sched
+ * @sched: Schedule entries payload
+ */
+struct nan_ndc_entry {
+ struct dl_list list;
+ u8 ndc_id[ETH_ALEN];
+ u16 len;
+ u8 sched[];
+};
+
/**
* struct nan_peer_sec_info_entry - NAN peer security information entry
*
@@ -350,6 +364,8 @@ struct nan_peer_sec_info_entry {
* (struct nan_elem_container_entry::list entries)
* @sec: List of security information entries of the peer
* (struct nan_peer_sec_info_entry::list entries)
+ * @ndc: List of NDC attributes seen in the peer's SDFs
+ * (struct nan_ndc_entry::list entries)
*/
struct nan_peer_info {
struct os_reltime last_seen;
@@ -361,6 +377,7 @@ struct nan_peer_info {
struct dl_list dev_capa;
struct dl_list element_container;
struct dl_list sec;
+ struct dl_list ndc;
};
/**
diff --git a/src/nan/nan_util.c b/src/nan/nan_util.c
index 954c3ade00..e04325e469 100644
--- a/src/nan/nan_util.c
+++ b/src/nan/nan_util.c
@@ -1697,6 +1697,19 @@ fail:
}
+/* Dump a labeled time bitmap of a map, advancing the output position */
+static void nan_dump_tbm_to_buf(char **pos, char *end, const char *label,
+ const struct nan_time_bitmap *tbm)
+{
+ *pos += wpa_scnprintf(*pos, end - *pos,
+ "\t%s: period=%u duration=%u offset=%u bitmap=",
+ label, BIT(6 + tbm->period),
+ BIT(4 + tbm->duration), 16 * tbm->offset);
+ *pos += wpa_snprintf_hex(*pos, end - *pos, tbm->bitmap, tbm->len);
+ *pos += wpa_scnprintf(*pos, end - *pos, "\n");
+}
+
+
/**
* nan_peer_dump_sched_to_buf - Dump peer schedule to a buffer
* @sched: Peer schedule
@@ -1763,40 +1776,20 @@ int nan_peer_dump_sched_to_buf(struct nan_peer_schedule *sched,
pos += ret;
}
- ret = wpa_scnprintf(pos, end - pos,
- "\tndc: period=%u duration=%u offset=%u bitmap=",
- BIT(6 + map->ndc.period),
- BIT(4 + map->ndc.duration),
- 16 * map->ndc.offset);
- if (os_snprintf_error(end - pos, ret))
- goto err;
- pos += ret;
+ nan_dump_tbm_to_buf(&pos, end, "ndc", &map->ndc);
- ret = wpa_snprintf_hex(pos, end - pos, map->ndc.bitmap,
- map->ndc.len);
- if (os_snprintf_error(end - pos, ret))
- goto err;
- pos += ret;
+ for (j = 0; j < map->n_ndc_advertised; j++) {
+ char label[64];
- ret = wpa_scnprintf(pos, end - pos,
- "\n\timmutable: period=%u duration=%u offset=%u bitmap=",
- 1 << (6 + map->immutable.period),
- 1 << (4 + map->immutable.duration),
- 16 * map->immutable.offset);
- if (os_snprintf_error(end - pos, ret))
- goto err;
- pos += ret;
+ os_snprintf(label, sizeof(label),
+ "ndc_advertised[%u] id=" MACSTR, j,
+ MAC2STR(map->ndc_advertised[j].id));
- ret = wpa_snprintf_hex(pos, end - pos, map->immutable.bitmap,
- map->immutable.len);
- if (os_snprintf_error(end - pos, ret))
- goto err;
- pos += ret;
+ nan_dump_tbm_to_buf(&pos, end, label,
+ &map->ndc_advertised[j].tbm);
+ }
- ret = wpa_scnprintf(pos, end - pos, "\n");
- if (os_snprintf_error(end - pos, ret))
- goto err;
- pos += ret;
+ nan_dump_tbm_to_buf(&pos, end, "immutable", &map->immutable);
}
ret = wpa_scnprintf(pos, end - pos, "max_idle_period=%u",
--
2.53.0
More information about the Hostap
mailing list