[PATCH 77/97] NAN: Update peer schedule when ULW attributes change
Andrei Otcheretianski
andrei.otcheretianski at intel.com
Tue Apr 28 13:06:18 PDT 2026
From: Avraham Stern <avraham.stern at intel.com>
Add a list of ULW attributes to the peer info. When the peer sends
new ULW attribute with a higher sequence ID than the last ULW, update
the peer schedule with the new ULW attributes.
Signed-off-by: Avraham Stern <avraham.stern at intel.com>
---
src/nan/nan.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++--
src/nan/nan_i.h | 15 ++++++
2 files changed, 147 insertions(+), 4 deletions(-)
diff --git a/src/nan/nan.c b/src/nan/nan.c
index 0d7110c98a..dafc59e250 100644
--- a/src/nan/nan.c
+++ b/src/nan/nan.c
@@ -103,6 +103,48 @@ static void nan_peer_flush_elem_container(struct nan_peer_info *info)
}
+static void nan_peer_flush_ulw(struct nan_peer_info *info)
+{
+ struct nan_ulw_entry *cur, *next;
+
+ dl_list_for_each_safe(cur, next, &info->ulw,
+ struct nan_ulw_entry, list) {
+ dl_list_del(&cur->list);
+ os_free(cur);
+ }
+}
+
+
+static struct wpabuf *
+nan_peer_build_ulw_attrs(const struct nan_peer_info *info)
+{
+ struct nan_ulw_entry *entry;
+ struct wpabuf *buf;
+ size_t len = 0;
+
+ if (dl_list_empty(&info->ulw))
+ return NULL;
+
+ dl_list_for_each(entry, &info->ulw, struct nan_ulw_entry, list)
+ len += NAN_ATTR_HDR_LEN + entry->len;
+
+ buf = wpabuf_alloc(len);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Failed to allocate buffer for ULW attrs");
+ return NULL;
+ }
+
+ dl_list_for_each(entry, &info->ulw, struct nan_ulw_entry, list) {
+ wpabuf_put_u8(buf, NAN_ATTR_UNALIGNED_SCHEDULE);
+ wpabuf_put_le16(buf, entry->len);
+ wpabuf_put_data(buf, entry->data, entry->len);
+ }
+
+ return buf;
+}
+
+
static void nan_ndp_setup_stop(struct nan_data *nan, struct nan_peer *peer)
{
eloop_cancel_timeout(nan_peer_state_timeout, nan, peer);
@@ -204,6 +246,7 @@ static void nan_del_peer(struct nan_data *nan, struct nan_peer *peer)
nan_bootstrap_reset(nan, peer);
dl_list_del(&peer->list);
nan_peer_flush_avail(&peer->info);
+ nan_peer_flush_ulw(&peer->info);
nan_peer_flush_dev_capa(&peer->info);
nan_peer_flush_elem_container(&peer->info);
nan_remove_group_keys(nan, peer);
@@ -1018,11 +1061,14 @@ static void nan_peer_update_schedule(struct nan_data *nan,
* Update the old peer info with information from the new peer info.
* Information that is available in the old peer info but is not available
* in the new peer info will not be changed.
+ * Peer schedule may be updated if the peer availabilty or ULW changed.
*/
static void nan_merge_peer_info(struct nan_data *nan, struct nan_peer *peer,
struct nan_peer_info *old,
struct nan_peer_info *new)
{
+ bool schedule_changed = false;
+
if (!dl_list_empty(&new->avail_entries)) {
struct nan_avail_entry *avail, *tmp;
@@ -1035,14 +1081,30 @@ static void nan_merge_peer_info(struct nan_data *nan, struct nan_peer *peer,
dl_list_add(&old->avail_entries, &avail->list);
}
old->seq_id = new->seq_id;
+ schedule_changed = true;
+ }
- if (peer->ndl && peer->ndl->state == NAN_NDL_STATE_DONE)
- nan_peer_update_schedule(nan, peer, &nan->sched);
+ if (!dl_list_empty(&new->ulw)) {
+ struct nan_ulw_entry *entry, *tmp;
+
+ nan_peer_flush_ulw(old);
+ dl_list_init(&old->ulw);
+
+ dl_list_for_each_safe(entry, tmp, &new->ulw,
+ struct nan_ulw_entry, list) {
+ dl_list_del(&entry->list);
+ dl_list_add(&old->ulw, &entry->list);
+ }
+
+ schedule_changed = true;
}
old->last_seen = new->last_seen;
-}
+ if (schedule_changed && peer->ndl &&
+ peer->ndl->state == NAN_NDL_STATE_DONE)
+ nan_peer_update_schedule(nan, peer, &nan->sched);
+}
static int nan_avail_info(struct nan_data *nan, struct nan_peer *peer,
struct nan_attrs *attrs, struct nan_peer_info *info)
@@ -1198,6 +1260,59 @@ static void nan_parse_peer_elem_container(struct nan_data *nan,
}
+static int nan_parse_peer_ulw(const struct nan_attrs *attrs,
+ const struct nan_peer_info *cur_info,
+ struct nan_peer_info *info)
+{
+ struct nan_ulw_entry *cur;
+ struct nan_attrs_entry *attr;
+ u8 max_seq_id = 0;
+ bool max_seq_id_valid = false;
+
+ if (dl_list_empty(&attrs->ulw))
+ return 0;
+
+ dl_list_for_each(cur, &cur_info->ulw, struct nan_ulw_entry, list) {
+ const struct nan_unaligned_sched *ulw;
+
+ ulw = (const struct nan_unaligned_sched *)cur->data;
+ if (!max_seq_id_valid || ulw->seq_id > max_seq_id) {
+ max_seq_id = ulw->seq_id;
+ max_seq_id_valid = true;
+ }
+ }
+
+ dl_list_for_each(attr, &attrs->ulw, struct nan_attrs_entry, list) {
+ struct nan_ulw_entry *entry;
+ const struct nan_unaligned_sched *ulw =
+ (const struct nan_unaligned_sched *)attr->ptr;
+
+ if (max_seq_id_valid && ulw->seq_id <= max_seq_id) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Skip old ULW entry with seq_id=%u",
+ ulw->seq_id);
+ continue;
+ }
+
+ entry = os_zalloc(sizeof(*entry) + attr->len);
+ if (!entry) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Failed to allocate ULW entry");
+ nan_peer_flush_ulw(info);
+ return -1;
+ }
+
+ dl_list_init(&entry->list);
+ dl_list_add(&info->ulw, &entry->list);
+
+ entry->len = attr->len;
+ os_memcpy(entry->data, attr->ptr, entry->len);
+ }
+
+ return 0;
+}
+
+
void nan_parse_peer_dev_capa_ext(struct nan_data *nan, struct nan_peer *peer,
struct nan_attrs *attrs)
{
@@ -1268,6 +1383,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);
os_get_reltime(&info.last_seen);
if (nan_parse_attrs(nan, attrs_data, attrs_len, &attrs)) {
@@ -1282,6 +1398,11 @@ int nan_parse_device_attrs(struct nan_data *nan, struct nan_peer *peer,
goto out;
}
+ if (nan_parse_peer_ulw(&attrs, &peer->info, &info)) {
+ ret = -1;
+ goto out;
+ }
+
nan_merge_peer_info(nan, peer, &peer->info, &info);
nan_parse_peer_device_capa(nan, peer, &attrs);
nan_parse_peer_elem_container(nan, peer, &attrs);
@@ -1292,6 +1413,8 @@ int nan_parse_device_attrs(struct nan_data *nan, struct nan_peer *peer,
nan_peer_dump(nan, peer);
ret = 0;
out:
+ nan_peer_flush_avail(&info);
+ nan_peer_flush_ulw(&info);
nan_attrs_clear(nan, &attrs);
return ret;
}
@@ -1333,6 +1456,7 @@ static struct nan_peer * nan_alloc_peer(struct nan_data *nan)
return NULL;
dl_list_init(&peer->info.avail_entries);
+ dl_list_init(&peer->info.ulw);
dl_list_init(&peer->info.dev_capa);
dl_list_init(&peer->info.element_container);
dl_list_init(&peer->info.sec);
@@ -1516,6 +1640,7 @@ int nan_configure_peer_schedule(struct nan_data *nan, struct nan_peer *peer,
struct nan_device_capabilities *capa = NULL;
struct nan_peer_schedule sched;
struct bitfield *common_bf;
+ struct wpabuf *ulw_elems;
wpa_printf(MSG_DEBUG, "NAN: Configure peer schedule for " MACSTR,
MAC2STR(peer->nmi_addr));
@@ -1552,11 +1677,14 @@ int nan_configure_peer_schedule(struct nan_data *nan, struct nan_peer *peer,
return -1;
}
+ ulw_elems = nan_peer_build_ulw_attrs(&peer->info);
+
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);
+ ulw_elems);
+ wpabuf_free(ulw_elems);
if (ret) {
wpa_printf(MSG_DEBUG, "NAN: Failed to set peer schedule");
return ret;
diff --git a/src/nan/nan_i.h b/src/nan/nan_i.h
index 264eaa0131..9ce0b99789 100644
--- a/src/nan/nan_i.h
+++ b/src/nan/nan_i.h
@@ -295,6 +295,19 @@ struct nan_elem_container_entry {
u8 data[];
};
+/**
+ * struct nan_ulw_entry - NAN Unaligned Schedule attribute entry
+ *
+ * @list: Used for linking in the ULW entries list
+ * @len: Length of the ULW attribute payload
+ * @data: Pointer to the ULW attribute payload
+ */
+struct nan_ulw_entry {
+ struct dl_list list;
+ u16 len;
+ u8 data[];
+};
+
/**
* struct nan_peer_sec_info_entry - NAN peer security information entry
*
@@ -330,6 +343,7 @@ struct nan_peer_sec_info_entry {
* @last_seen: Timestamp of the last update of the peer info
* @seq_id: Sequence id of the last availability update
* @avail_entries: List of availability entries of the peer
+ * @ulw: List of Unaligned Schedule attribute payloads of the peer
* @dev_capa: List of device capabilities of the peer
* (struct nan_dev_capa_entry::list entries)
* @element_container: List of element container entries of the peer
@@ -341,6 +355,7 @@ struct nan_peer_info {
struct os_reltime last_seen;
u8 seq_id;
struct dl_list avail_entries;
+ struct dl_list ulw;
struct dl_list dev_capa;
struct dl_list element_container;
struct dl_list sec;
--
2.53.0
More information about the Hostap
mailing list