[RFC v2 25/99] NAN: Properly set the NDL status in a response and confirm
Andrei Otcheretianski
andrei.otcheretianski at intel.com
Tue Dec 23 03:51:29 PST 2025
From: Ilan Peer <ilan.peer at intel.com>
Validate the local schedule versus the peer's schedule,
and determine the status of the NDL setup:
- Check if the intersection of the local availability and the peer
availability is not empty and adheres to the peer QoS
requirements.
- Check if local NDC is a subset of the local schedule.
- Check if local NDC is identical to the peer NDC.
- Check if peer's immutable is covered by the local schedule.
If these conditions are met, accept the NDL. Otherwise:
- If the frame is a response frame, continue the NDL establishment.
- If the frame is a confirm frame, reject the NDL establishment.
Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
src/nan/nan_i.h | 16 +-
src/nan/nan_ndl.c | 459 ++++++++++++++++++++++++++++++++++++++++++++-
src/nan/nan_util.c | 253 ++++++++++++++++++++++---
3 files changed, 691 insertions(+), 37 deletions(-)
diff --git a/src/nan/nan_i.h b/src/nan/nan_i.h
index 6f3cfdb77b..edaf6910e2 100644
--- a/src/nan/nan_i.h
+++ b/src/nan/nan_i.h
@@ -446,8 +446,16 @@ bool nan_sched_covered_by_avail_entry(struct nan_data *nan,
struct nan_avail_entry *avail,
struct bitfield *sched_bf,
u8 map_id);
-int nan_sched_covered_by_avail_entries(struct nan_data *nan,
- struct dl_list *avail_entries,
- u8 *sched,
- u8 sched_len);
+bool nan_sched_covered_by_avail_entries(struct nan_data *nan,
+ struct dl_list *avail_entries,
+ u8 *sched, u8 sched_len);
+bool
+nan_sched_bf_covered_by_avail_entries_and_chan(struct nan_data *nan,
+ const struct dl_list *avail_entries,
+ struct bitfield *sched_bf,
+ u8 map_id,
+ u8 op_class, u16 cbm);
+struct bitfield * nan_avail_entries_to_bf(struct nan_data *nan,
+ const struct dl_list *avail_entries,
+ u8 op_class, u16 cbm, u16 pri_cbm);
#endif
diff --git a/src/nan/nan_ndl.c b/src/nan/nan_ndl.c
index 4b43c13077..cf95c5ebf4 100644
--- a/src/nan/nan_ndl.c
+++ b/src/nan/nan_ndl.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "common/ieee802_11_common.h"
#include "nan_i.h"
+#include "bitfield.h"
struct ndl_attr_params {
u8 dialog_token;
@@ -222,11 +223,454 @@ static int nan_ndl_validate_peer_avail(struct nan_data *nan,
}
-static enum nan_ndl_status nan_ndl_res_status(struct nan_data *nan,
- struct nan_peer *peer)
+/*
+ * nan_ndl_convert_chan_sched_to_bf - Convert channel schedule to bitfield
+ * and get the channel information.
+ *
+ * @nan: NAN module context from nan_init()
+ * @chan: Channel schedule to convert
+ * @avail_bf: On successful return would hold the availability bit map of the
+ * given channel schedule
+ * @map_id: On successful return would hold the map ID for the schedule
+ * @op_class: On successful return would hold the operating class for the
+ * schedule with the peer
+ * @cbm: On successful return holds the channel bitmap for the operating
+ * class
+ * @pcbm: On successful return holds the primary channel bitmap for the
+ * channel in case of bandwidth greater than 40 MHz
+ * Returns 0 on success; -1 on failure
+ */
+static int nan_ndl_convert_chan_sched_to_bf(struct nan_data *nan,
+ struct nan_chan_schedule *chan,
+ struct bitfield **avail_bf,
+ u8 *map_id, u8 *op_class,
+ u16 *cbm, u16 *pcbm)
{
- /* TODO: properly set the status */
- return NAN_NDL_STATUS_ACCEPTED;
+ struct bitfield *committed_bf, *conditional_bf;
+ int ret;
+
+ *op_class = 0;
+ *cbm = 0;
+ *pcbm = 0;
+ *map_id = chan->map_id;
+
+ ret = nan_get_chan_bm(nan, &chan->chan, op_class, cbm, pcbm);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: NDL: failed to convert channel info");
+ return -1;
+ }
+
+ committed_bf = nan_tbm_to_bf(nan, &chan->committed);
+ if (!committed_bf) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: NDL: failed to build committed bitfield");
+ return -1;
+ }
+
+ conditional_bf = nan_tbm_to_bf(nan, &chan->conditional);
+ if (!conditional_bf) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: NDL: failed to build conditional bitfield");
+ bitfield_free(committed_bf);
+ return -1;
+ }
+
+ *avail_bf = bitfield_union(committed_bf, conditional_bf);
+ bitfield_free(committed_bf);
+ bitfield_free(conditional_bf);
+
+ if (!*avail_bf) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: NDL: failed to unify committed and conditional bitfields");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "NAN: NDL: map_id=%u, op_class=%u, cbm=0x%x",
+ *map_id, *op_class, *cbm);
+ return 0;
+}
+
+
+/**
+ * enum nan_ndl_ver - Verdict of comparing local availability to given schedule
+ *
+ * @NAN_NDL_VER_SCHED_SUBSET_OF_LOCAL: The schedule is a subset of the local one
+ * @NAN_NDL_VER_SCHED_SUPERSET_OF_LOCAL: The schedule is a superset of the local
+ * one
+ * @NAN_NDL_VER_SCHED_IDENTICAL_OF_LOCAL: The schedule is identical to the local
+ * @NAN_NDL_VER_SCHED_NONE: None of the above. This means that there was no
+ * match or an error occurred.
+ */
+enum nan_ndl_ver {
+ NAN_NDL_VER_SCHED_SUBSET_OF_LOCAL,
+ NAN_NDL_VER_SCHED_SUPERSET_OF_LOCAL,
+ NAN_NDL_VER_SCHED_IDENTICAL_OF_LOCAL,
+ NAN_NDL_VER_SCHED_NONE,
+};
+
+
+/*
+ * nan_ndl_match_sched_vs_common - Compare the given schedule to the common
+ * availability of the local device and the peer device, comparing channel
+ * configuration and bitmap.
+ *
+ * @nan: NAN module context from nan_init()
+ * @avail_entries: Peer availability entries
+ * @sched: A byte array with 0 or more &struct nan_sched_entry entries
+ * @sched_len: Length of the &sched array
+ * @common_bf: Bitfield representing the intersection of local and peer
+ * availability
+ * @op_class: Local operating class
+ * @cbm: Local channel bitmap
+ *
+ * Returns one of enum nan_ndl_ver. In case of on an error
+ * NAN_NDL_VER_SCHED_NONE is returned.
+ *
+ * The function first verifies that the given schedule is covered by the peer
+ * availability. Then, the function verifies that the schedule is covered by
+ * the common availability between local and peer.
+ *
+ * The function can (and should be used) to check the schedule constraints of
+ * an NDC schedule and/or immutable schedule.
+ *
+ * Note: In case that &sched is NULL or &sched_len is 0, returns
+ * NAN_NDL_VER_SCHED_IDENTICAL_OF_LOCAL, meaning no constraints.
+ */
+static enum nan_ndl_ver
+nan_ndl_match_sched_vs_common(struct nan_data *nan,
+ struct dl_list *avail_entries,
+ u8 *sched, u8 sched_len,
+ struct bitfield *common_bf,
+ u8 op_class, u16 cbm)
+{
+ struct dl_list sched_entries;
+ struct bitfield *sched_bf;
+ u8 map_id;
+ enum nan_ndl_ver verdict;
+ int ret;
+
+ /* No constraints */
+ if (!sched || !sched_len)
+ return NAN_NDL_VER_SCHED_IDENTICAL_OF_LOCAL;
+
+ /* Convert the schedule entries to availability entries */
+ ret = nan_sched_entries_to_avail_entries(nan,
+ &sched_entries,
+ sched,
+ sched_len);
+ if (ret)
+ return NAN_NDL_VER_SCHED_NONE;
+
+ /* Convert the schedule availability entries to map ID and bitfield */
+ sched_bf = nan_sched_to_bf(nan, &sched_entries, &map_id);
+ nan_flush_avail_entries(&sched_entries);
+
+ /*
+ * Now that the schedule is represented as bitfield and the map ID is
+ * obtained, compare these against the peer availability entries and
+ * channel configuration. A successful match means that the schedule is
+ * covered by the peer availability entries for the given channel.
+ */
+ ret = nan_sched_bf_covered_by_avail_entries_and_chan(nan,
+ avail_entries,
+ sched_bf,
+ map_id,
+ op_class,
+ cbm);
+ if (ret) {
+ int ret2;
+
+ /*
+ * After validating the schedule against the peer availability,
+ * match the peer availability with the local one.
+ */
+ ret = bitfield_is_subset(common_bf, sched_bf);
+ ret2 = bitfield_is_subset(sched_bf, common_bf);
+
+ if (ret < 0 || ret2 < 0)
+ verdict = NAN_NDL_VER_SCHED_NONE;
+ else if (ret == 1 && ret2 == 1)
+ verdict = NAN_NDL_VER_SCHED_IDENTICAL_OF_LOCAL;
+ else if (ret == 1)
+ verdict = NAN_NDL_VER_SCHED_SUBSET_OF_LOCAL;
+ else
+ verdict = NAN_NDL_VER_SCHED_SUPERSET_OF_LOCAL;
+ } else {
+ verdict = NAN_NDL_VER_SCHED_NONE;
+ }
+
+ bitfield_free(sched_bf);
+ return verdict;
+}
+
+
+static enum nan_ndl_status nan_ndl_determine_status(struct nan_data *nan,
+ struct nan_peer *peer,
+ bool can_counter,
+ enum nan_reason *reason)
+{
+ struct nan_schedule *sched = &peer->ndl->sched;
+ struct bitfield *common_bf = NULL, *ndc_bf = NULL, *track_ndc_bf = NULL;
+ enum nan_ndl_ver verdict;
+ size_t size, max_latency, i;
+ u16 crbs;
+ int ret;
+
+ *reason = NAN_REASON_RESERVED;
+
+ ndc_bf = nan_tbm_to_bf(nan, &sched->ndc);
+ if (!ndc_bf) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: NDL: Failed to build NDC bitfield from schedule");
+
+ *reason = NAN_REASON_UNSPECIFIED_REASON;
+ return NAN_NDL_STATUS_REJECTED;
+ }
+
+ track_ndc_bf = bitfield_alloc(bitfield_size(ndc_bf));
+ if (!track_ndc_bf) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: NDL: Failed to allocate bitfield for tracking NDC");
+
+ bitfield_free(ndc_bf);
+ *reason = NAN_REASON_UNSPECIFIED_REASON;
+ return NAN_NDL_STATUS_REJECTED;
+ }
+
+ /*
+ * 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 intersect it with the local one:
+ *
+ * - Accumulate the intersection of the NDC bitmap with the bitmap all
+ * channels with the same map ID as the NDC, so later it can be
+ * verified that the NDC is covered by the local availability.
+ * - Accumulate the intersection of local and peer availability for
+ * all channels, so later the QoS requirements can be verified.
+ */
+ wpa_printf(MSG_DEBUG, "NAN: NDL: 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;
+
+ /* 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");
+
+ *reason = NAN_REASON_UNSPECIFIED_REASON;
+ ret = NAN_NDL_STATUS_REJECTED;
+ goto out;
+ }
+
+ if (sched->ndc_map_id == map_id) {
+ struct bitfield *tmp = bitfield_dup(ndc_bf);
+
+ if (tmp) {
+ bitfield_intersect_in_place(tmp, own_chan_bf);
+ bitfield_union_in_place(track_ndc_bf, tmp);
+ bitfield_free(tmp);
+ }
+ }
+
+ /* 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_intersect_in_place(own_chan_bf, peer_chan_bf);
+ bitfield_free(peer_chan_bf);
+ peer_chan_bf = NULL;
+
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: NDL: Failed to intersect own and peer chan bitfields");
+
+ bitfield_free(own_chan_bf);
+
+ *reason = NAN_REASON_INVALID_AVAILABILITY;
+ ret = NAN_NDL_STATUS_REJECTED;
+ goto out;
+ }
+
+ /*
+ * Accumulate schedule common for local and peer device, so it
+ * can later be used to verify QoS requirements etc.
+ */
+ if (common_bf) {
+ ret = bitfield_union_in_place(common_bf, own_chan_bf);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: NDL: Failed to unify own chan bitfields");
+
+ bitfield_free(own_chan_bf);
+
+ *reason = NAN_REASON_UNSPECIFIED_REASON;
+ ret = NAN_NDL_STATUS_REJECTED;
+ goto out;
+ }
+ } else {
+ common_bf = bitfield_dup(own_chan_bf);
+ if (!common_bf) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: NDL: Failed to dup own chan bitfield");
+
+ bitfield_free(own_chan_bf);
+
+ *reason = NAN_REASON_UNSPECIFIED_REASON;
+ ret = NAN_NDL_STATUS_REJECTED;
+ goto out;
+ }
+ }
+
+ bitfield_free(own_chan_bf);
+ own_chan_bf = NULL;
+ }
+
+ if (!common_bf) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: NDL: No common availability between local and peer");
+
+ *reason = NAN_REASON_INVALID_AVAILABILITY;
+ ret = NAN_NDL_STATUS_CONTINUED;
+ goto out;
+ }
+
+ /*
+ * Verify that the schedule NDC bitmap is covered by the local
+ * availability for the map used for the NDC.
+ */
+ if (!bitfield_is_subset(ndc_bf, track_ndc_bf)) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: NDL: NDC bitmap is not covered by local availability on NDC channel");
+
+ *reason = NAN_REASON_UNSPECIFIED_REASON;
+ ret = NAN_NDL_STATUS_REJECTED;
+ goto out;
+ }
+
+
+ bitfield_free(ndc_bf);
+ ndc_bf = track_ndc_bf;
+ track_ndc_bf = NULL;
+
+ /*
+ * In case the peer included an immutable, the immutable must be
+ * covered by the common schedule. If not reject.
+ */
+ verdict = nan_ndl_match_sched_vs_common(nan,
+ &peer->info.avail_entries,
+ peer->ndl->immut_sched,
+ peer->ndl->immut_sched_len,
+ common_bf, 0, 0);
+ if (verdict != NAN_NDL_VER_SCHED_IDENTICAL_OF_LOCAL &&
+ verdict != NAN_NDL_VER_SCHED_SUBSET_OF_LOCAL) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Schedule does not cover immutable. Reject");
+
+ *reason = NAN_REASON_IMMUTABLE_UNACCEPTABLE;
+ ret = NAN_NDL_STATUS_REJECTED;
+ goto out;
+ }
+
+ /*
+ * In case the peer included an NDC, check if it is identical to
+ * the locally generated one.
+ *
+ * Note: the list of peer availability entries needs to be iterated
+ * again, as the NDC map ID must also be matched.
+ */
+ verdict = nan_ndl_match_sched_vs_common(nan,
+ &peer->info.avail_entries,
+ peer->ndl->ndc_sched,
+ peer->ndl->ndc_sched_len,
+ ndc_bf, 0, 0);
+ if (verdict != NAN_NDL_VER_SCHED_IDENTICAL_OF_LOCAL) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Response NDC does not match req NDC");
+
+ *reason = NAN_REASON_INVALID_AVAILABILITY;
+ ret = NAN_NDL_STATUS_CONTINUED;
+ goto out;
+ }
+
+ /* No QoS requirements. Accept */
+ if (peer->ndl->peer_qos.min_slots == NAN_QOS_MIN_SLOTS_NO_PREF &&
+ peer->ndl->peer_qos.max_latency == NAN_QOS_MAX_LATENCY_NO_PREF) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: No QoS requirements from Peer. Accept");
+
+ ret = NAN_NDL_STATUS_ACCEPTED;
+ goto out;
+ }
+
+ size = bitfield_size(common_bf);
+ wpa_printf(MSG_DEBUG,
+ "NAN: size of avail intersection map=%zu", size);
+
+ for (i = 0, crbs = 0, max_latency = 0; i < size; i++) {
+ if (bitfield_is_set(common_bf, i)) {
+ crbs++;
+ max_latency = 0;
+ } else if (peer->ndl->peer_qos.max_latency !=
+ NAN_QOS_MAX_LATENCY_NO_PREF) {
+ max_latency++;
+ if (max_latency > peer->ndl->peer_qos.max_latency) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: failed to meet max latency");
+
+ *reason = NAN_REASON_QOS_UNACCEPTABLE;
+ ret = NAN_NDL_STATUS_CONTINUED;
+ goto out;
+ }
+ }
+ }
+
+ if (peer->ndl->peer_qos.min_slots != NAN_QOS_MIN_SLOTS_NO_PREF &&
+ peer->ndl->peer_qos.min_slots >= crbs) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: failed to meet min slots");
+
+ *reason = NAN_REASON_QOS_UNACCEPTABLE;
+ ret = NAN_NDL_STATUS_CONTINUED;
+ goto out;
+ }
+
+ ret = NAN_NDL_STATUS_ACCEPTED;
+out:
+ bitfield_free(common_bf);
+ bitfield_free(ndc_bf);
+ bitfield_free(track_ndc_bf);
+
+ wpa_printf(MSG_DEBUG,
+ "NAN: NDL: Response status=%s (%u)",
+ ret == NAN_NDL_STATUS_ACCEPTED ? "ACCEPTED" :
+ ret == NAN_NDL_STATUS_CONTINUED ? "CONTINUED" :
+ "REJECTED",
+ ret);
+
+ if (ret == NAN_NDL_STATUS_CONTINUED && !can_counter) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Cannot counter, change verdict to REJECTED");
+ ret = NAN_NDL_STATUS_REJECTED;
+ }
+
+ return ret;
}
@@ -328,7 +772,12 @@ int nan_ndl_setup(struct nan_data *nan, struct nan_peer *peer,
nan_ndl_set_state(nan, ndl, NAN_NDL_STATE_START);
ndl->status = NAN_NDL_STATUS_CONTINUED;
} else {
- ndl->status = nan_ndl_res_status(nan, peer);
+ ndl->status = nan_ndl_determine_status(nan, peer,
+ ndl->state ==
+ NAN_NDL_STATE_REQ_RECV,
+ &reason);
+ if (ndl->status == NAN_NDL_STATUS_REJECTED)
+ goto out_fail;
}
ndl->setup_reason = NAN_NDL_SETUP_REASON_NDP;
diff --git a/src/nan/nan_util.c b/src/nan/nan_util.c
index ced188fc47..096c7ad57f 100644
--- a/src/nan/nan_util.c
+++ b/src/nan/nan_util.c
@@ -1137,14 +1137,14 @@ bool nan_sched_covered_by_avail_entry(struct nan_data *nan,
}
-static int nan_sched_bf_covered_by_avail_entries(struct nan_data *nan,
- struct dl_list *avail_entries,
- struct bitfield *sched_bf,
- u8 map_id)
+static struct bitfield *
+nan_sched_bf_from_avail_and_chan(struct nan_data *nan,
+ const struct dl_list *avail_entries,
+ u8 map_id,
+ u8 op_class, u16 cbm)
{
struct nan_avail_entry *avail;
struct bitfield *res_bf = NULL;
- int ret = 0;
dl_list_for_each(avail, avail_entries, struct nan_avail_entry,
list) {
@@ -1158,12 +1158,19 @@ static int nan_sched_bf_covered_by_avail_entries(struct nan_data *nan,
avail->type != NAN_AVAIL_ENTRY_CTRL_TYPE_COND)
continue;
+ /* Now check channel, if it is given */
+ if (op_class && cbm) {
+ if (avail->n_band_chan < 1 ||
+ avail->band_chan_type != NAN_TYPE_CHANNEL ||
+ avail->band_chan[0].u.chan.op_class != op_class ||
+ !(avail->band_chan[0].u.chan.chan_bitmap & cbm))
+ continue;
+ }
+
/* convert the availability entry to bf */
avail_bf = nan_tbm_to_bf(nan, &avail->tbm);
- if (!avail_bf) {
- ret = -1;
+ if (!avail_bf)
goto fail;
- }
bitfield_dump(avail_bf, "NAN: Availability entry bitmap");
if (!res_bf) {
@@ -1174,22 +1181,18 @@ static int nan_sched_bf_covered_by_avail_entries(struct nan_data *nan,
tmp_bf = bitfield_union(res_bf, avail_bf);
bitfield_free(avail_bf);
- if (!tmp_bf) {
- ret = -1;
+ if (!tmp_bf)
goto fail;
- }
bitfield_free(res_bf);
res_bf = tmp_bf;
}
}
- ret = bitfield_is_subset(res_bf, sched_bf);
+ return res_bf;
fail:
- wpa_printf(MSG_DEBUG,
- "NAN: Is bitfield schedule subset of entries=%d", ret);
bitfield_free(res_bf);
- return ret;
+ return NULL;
}
@@ -1201,20 +1204,19 @@ fail:
* @avail_entries: A list of availability entries (see &struct nan_avail_entry)
* @sched: An array with 0 or more &struct nan_sched_entry entries
* @sched_len: Length of the &sched array
- * Returns 1 of schedule is covered by the entries; 0 if not and -1 on error
+ * Returns true if schedule is covered by the entries; otherwise false.
*/
-int nan_sched_covered_by_avail_entries(struct nan_data *nan,
- struct dl_list *avail_entries,
- u8 *sched,
- u8 sched_len)
+bool nan_sched_covered_by_avail_entries(struct nan_data *nan,
+ struct dl_list *avail_entries,
+ u8 *sched, u8 sched_len)
{
struct dl_list sched_entries;
- struct bitfield *sched_bf;
+ struct bitfield *sched_bf, *avail_bf;
u8 map_id;
- int ret;
+ bool ret = false;
if (!sched || !sched_len)
- return 1;
+ return true;
dl_list_init(&sched_entries);
ret = nan_sched_entries_to_avail_entries(nan,
@@ -1224,12 +1226,207 @@ int nan_sched_covered_by_avail_entries(struct nan_data *nan,
sched_bf = nan_sched_to_bf(nan, &sched_entries, &map_id);
nan_flush_avail_entries(&sched_entries);
- ret = nan_sched_bf_covered_by_avail_entries(nan, avail_entries,
- sched_bf, map_id);
+ avail_bf = nan_sched_bf_from_avail_and_chan(nan, avail_entries,
+ map_id, 0, 0);
+ if (avail_bf)
+ ret = bitfield_is_subset(avail_bf, sched_bf) ? true : false;
- wpa_printf(MSG_DEBUG,
- "NAN: NDC schedule is %s a subset of entries",
- ret == 1 ? "" : "NOT");
+ wpa_printf(MSG_DEBUG, "NAN: Schedule is %s a subset of entries",
+ ret ? "" : "NOT");
+
+ bitfield_free(avail_bf);
bitfield_free(sched_bf);
+
+ return ret;
+}
+
+
+/**
+ * nan_sched_bf_covered_by_avail_entries_and_chan - Check if schedule is covered
+ * by the list of availability attributes matching the channel configurations
+ *
+ * @nan: NAN module context from nan_init()
+ * @avail_entries: A list of availability entries. See &struct nan_avail_entry
+ * @sched_bf: the bitfield representing the schedule
+ * @map_id: Map ID associated with the schedule
+ * @op_class: Operating class to match against
+ * @cbm: Channel bit map to match against
+ * Returns true of schedule is covered by the entries; otherwise false
+ */
+bool
+nan_sched_bf_covered_by_avail_entries_and_chan(struct nan_data *nan,
+ const struct dl_list *avail_entries,
+ struct bitfield *sched_bf,
+ u8 map_id,
+ u8 op_class, u16 cbm)
+{
+ struct bitfield *avail_bf;
+ bool ret = false;
+
+ /*
+ * Build a schedule bitfield from all the availability entries matching
+ * the map id and channel configuration
+ */
+ avail_bf = nan_sched_bf_from_avail_and_chan(nan, avail_entries,
+ map_id,
+ op_class, cbm);
+
+ /*
+ * If there is such schedule, verify that it is a superset of the given
+ * schedule
+ */
+ if (avail_bf && bitfield_is_subset(avail_bf, sched_bf))
+ ret = true;
+
+ wpa_printf(MSG_DEBUG,
+ "NAN: Is schedule covered by entries and chan=%u", ret);
+
+ bitfield_free(avail_bf);
return ret;
}
+
+
+static int nan_get_control_channel(struct nan_data *nan, u8 op_class,
+ u16 cbm, u16 pri_cbm)
+{
+ const struct oper_class_map *op = get_oper_class(NULL, op_class);
+ int freq = 0, idx;
+ u8 chan_id;
+
+ if (!op || op_class > 130)
+ return -1;
+
+ idx = ffs(cbm) - 1;
+ if (idx < 0) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: No channel found in chan_bitmap 0x%04x for oper_class %u",
+ cbm, op_class);
+ return -1;
+ }
+
+ chan_id = op_class_idx_to_chan(op, idx);
+ if (!chan_id) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: No channel found for oper_class %u idx %u",
+ op_class, idx);
+ return -1;
+ }
+
+ freq = ieee80211_chan_to_freq(NULL, op_class, chan_id);
+
+ /*
+ * For operating classes with bandwidth < 80 the frequency is the
+ * control channel frequency. For operating classes with
+ * bandwidth >= 80, the frequency is the center frequency of the
+ * primary segment, so we need to derive the control channel frequency
+ * from the primary channel bitmap.
+ */
+ if (op->bw == BW20 || op->bw == BW40 ||
+ op->bw == BW40PLUS || op->bw == BW40MINUS)
+ return freq;
+
+ if (!pri_cbm) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: No primary channel bitmap provided for oper_class %u",
+ op_class);
+ return -1;
+ }
+
+ idx = ffs(pri_cbm) - 1;
+
+ if (op->bw == BW80 || op->bw == BW80P80)
+ return freq - 30 + idx * 20;
+
+ if (op->bw == BW160)
+ return freq - 70 + idx * 20;
+
+ return -1;
+}
+
+
+/**
+ * nan_avail_entries_to_bf - Convert availability entries that match the given
+ * channel configuration to a bitfield.
+ *
+ * @nan: NAN module context from nan_init()
+ * @avail_entries: A list of availability entries. See &struct nan_avail_entry
+ * @op_class: Operating class to match against
+ * @cbm: Channel bit map to match against
+ * @pri_cbm: Primary channel bit map to match against
+ * Returns NULL on error or no match; otherwise returns a bitfield describing
+ * all the available slots.
+ */
+struct bitfield * nan_avail_entries_to_bf(struct nan_data *nan,
+ const struct dl_list *avail_entries,
+ u8 op_class, u16 cbm, u16 pri_cbm)
+{
+ struct nan_avail_entry *avail;
+ struct bitfield *res_bf = NULL;
+
+ dl_list_for_each(avail, avail_entries, struct nan_avail_entry,
+ list) {
+ struct bitfield *avail_bf;
+
+ /* Schedule can only be covered by committed/conditional */
+ if (avail->type != NAN_AVAIL_ENTRY_CTRL_TYPE_COMMITTED &&
+ avail->type != NAN_AVAIL_ENTRY_CTRL_TYPE_COND)
+ continue;
+
+ /*
+ * Committed/conditional entries should only have a single
+ * channel entry
+ */
+ if (avail->n_band_chan != 1 ||
+ avail->band_chan_type != NAN_TYPE_CHANNEL)
+ continue;
+
+ /*
+ * Check that the availability entry channel matches. If it does
+ * not match, check if the channels are compatible, i.e., have
+ * the same control channel
+ */
+ if (avail->band_chan[0].u.chan.op_class != op_class ||
+ avail->band_chan[0].u.chan.chan_bitmap != cbm ||
+ avail->band_chan[0].u.chan.pri_chan_bitmap != pri_cbm) {
+ int freq1, freq2;
+
+ freq1 = nan_get_control_channel(nan, op_class,
+ cbm, pri_cbm);
+ freq2 = nan_get_control_channel(nan,
+ avail->band_chan[0].u.chan.op_class,
+ le_to_host16(avail->band_chan[0].u.chan.chan_bitmap),
+ le_to_host16(avail->band_chan[0].u.chan.pri_chan_bitmap));
+
+ if (freq2 == -1 || freq1 != freq2)
+ continue;
+
+ wpa_printf(MSG_DEBUG,
+ "NAN: Availability entry channel is compatible. Control channel freq=%d MHz",
+ freq1);
+ }
+
+ /* Convert the availability entry to bf */
+ avail_bf = nan_tbm_to_bf(nan, &avail->tbm);
+ if (!avail_bf)
+ goto fail;
+
+ if (!res_bf) {
+ res_bf = avail_bf;
+ } else {
+ struct bitfield *tmp_bf;
+
+ tmp_bf = bitfield_union(res_bf, avail_bf);
+ if (!tmp_bf)
+ goto fail;
+
+ bitfield_free(res_bf);
+ bitfield_free(avail_bf);
+ res_bf = tmp_bf;
+ }
+ }
+
+ return res_bf;
+fail:
+ bitfield_free(res_bf);
+ return NULL;
+}
--
2.49.0
More information about the Hostap
mailing list