1 /*
2 * Wi-Fi Aware - NAN module utils
3 * Copyright (C) 2025 Intel Corporation
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "includes.h"
10 #include "common.h"
11 #include "utils/bitfield.h"
12 #include "common/wpa_common.h"
13 #include "common/ieee802_11_common.h"
14 #include "nan_i.h"
15
16
nan_attrs_clear_list(struct nan_data * nan,struct dl_list * list)17 static void nan_attrs_clear_list(struct nan_data *nan,
18 struct dl_list *list)
19 {
20 struct nan_attrs_entry *entry, *pentry;
21
22 dl_list_for_each_safe(entry, pentry, list, struct nan_attrs_entry,
23 list) {
24 dl_list_del(&entry->list);
25 os_free(entry);
26 }
27 }
28
29
30 /*
31 * nan_attrs_clear - Free data from NAN parsing
32 * @nan: NAN module context from nan_init()
33 * @attrs: Parsed nan_attrs
34 */
nan_attrs_clear(struct nan_data * nan,struct nan_attrs * attrs)35 void nan_attrs_clear(struct nan_data *nan, struct nan_attrs *attrs)
36 {
37 nan_attrs_clear_list(nan, &attrs->serv_desc_ext);
38 nan_attrs_clear_list(nan, &attrs->avail);
39 nan_attrs_clear_list(nan, &attrs->ndc);
40 nan_attrs_clear_list(nan, &attrs->ulw);
41 nan_attrs_clear_list(nan, &attrs->dev_capa);
42 nan_attrs_clear_list(nan, &attrs->element_container);
43
44 os_memset(attrs, 0, sizeof(*attrs));
45 }
46
47
48 /*
49 * nan_parse_attrs - Parse NAN attributes
50 * @nan: NAN module context from nan_init()
51 * @data: Buffer holding the attributes
52 * @len: Length of &data
53 * @attrs: On return would hold the parsed attributes
54 * Returns: 0 on success; positive or negative indicate an error
55 *
56 * Note: In case of success, the caller must free temporary memory allocations
57 * by calling nan_attrs_clear() when the parsed data is not needed anymore.
58 */
nan_parse_attrs(struct nan_data * nan,const u8 * data,size_t len,struct nan_attrs * attrs)59 int nan_parse_attrs(struct nan_data *nan, const u8 *data, size_t len,
60 struct nan_attrs *attrs)
61 {
62 struct nan_attrs_entry *entry;
63 const u8 *pos = data;
64 const u8 *end = pos + len;
65
66 os_memset(attrs, 0, sizeof(*attrs));
67
68 dl_list_init(&attrs->serv_desc_ext);
69 dl_list_init(&attrs->avail);
70 dl_list_init(&attrs->ndc);
71 dl_list_init(&attrs->ulw);
72 dl_list_init(&attrs->dev_capa);
73 dl_list_init(&attrs->element_container);
74
75 while (end - pos > 3) {
76 u8 id = *pos++;
77 u16 attr_len = WPA_GET_LE16(pos);
78
79 pos += 2;
80 if (attr_len > end - pos)
81 goto fail;
82
83 switch (id) {
84 case NAN_ATTR_SDEA:
85 entry = os_zalloc(sizeof(*entry));
86 if (!entry)
87 goto fail;
88
89 entry->ptr = pos;
90 entry->len = attr_len;
91 dl_list_add_tail(&attrs->serv_desc_ext, &entry->list);
92 break;
93 case NAN_ATTR_DEVICE_CAPABILITY:
94 /* Validate Device Capability attribute length */
95 if (attr_len < sizeof(struct nan_device_capa))
96 break;
97
98 entry = os_zalloc(sizeof(*entry));
99 if (!entry)
100 goto fail;
101
102 entry->ptr = pos;
103 entry->len = attr_len;
104 dl_list_add_tail(&attrs->dev_capa, &entry->list);
105 break;
106 case NAN_ATTR_NDP:
107 /* Validate minimal NDP attribute length */
108 if (attr_len < sizeof(struct ieee80211_ndp))
109 break;
110
111 attrs->ndp = pos;
112 attrs->ndp_len = attr_len;
113 break;
114 case NAN_ATTR_NAN_AVAILABILITY:
115 /* Validate minimal Availability attribute length */
116 if (attr_len < sizeof(struct nan_avail))
117 break;
118
119 entry = os_zalloc(sizeof(*entry));
120 if (!entry)
121 goto fail;
122
123 entry->ptr = pos;
124 entry->len = attr_len;
125 dl_list_add_tail(&attrs->avail, &entry->list);
126 break;
127 case NAN_ATTR_NDC:
128 /* Validate minimal NDC attribute length */
129 if (attr_len < sizeof(struct ieee80211_ndc))
130 break;
131
132 entry = os_zalloc(sizeof(*entry));
133 if (!entry)
134 goto fail;
135
136 entry->ptr = pos;
137 entry->len = attr_len;
138 dl_list_add_tail(&attrs->ndc, &entry->list);
139 break;
140 case NAN_ATTR_UNALIGNED_SCHEDULE:
141 if (attr_len < sizeof(struct nan_unaligned_sched))
142 break;
143
144 entry = os_malloc(sizeof(*entry));
145 if (!entry)
146 goto fail;
147
148 entry->ptr = pos;
149 entry->len = attr_len;
150 dl_list_add_tail(&attrs->ulw, &entry->list);
151 break;
152 case NAN_ATTR_NDL:
153 /* Validate minimal NDL attribute length */
154 if (attr_len < sizeof(struct ieee80211_ndl))
155 break;
156
157 attrs->ndl = pos;
158 attrs->ndl_len = attr_len;
159 break;
160 case NAN_ATTR_NDL_QOS:
161 /* Validate QoS attribute length */
162 if (attr_len < sizeof(struct ieee80211_nan_qos))
163 break;
164
165 attrs->ndl_qos = pos;
166 attrs->ndl_qos_len = attr_len;
167 break;
168 case NAN_ATTR_ELEM_CONTAINER:
169 /* Validate minimal Element Container attribute length
170 */
171 if (attr_len < 1)
172 break;
173
174 entry = os_zalloc(sizeof(*entry));
175 if (!entry)
176 goto fail;
177
178 entry->ptr = pos;
179 entry->len = attr_len;
180 dl_list_add_tail(&attrs->element_container,
181 &entry->list);
182 break;
183 case NAN_ATTR_CSIA:
184 if (attr_len < sizeof(struct nan_cipher_suite_info) +
185 sizeof(struct nan_cipher_suite))
186 break;
187
188 attrs->cipher_suite_info = pos;
189 attrs->cipher_suite_info_len = attr_len;
190 break;
191 case NAN_ATTR_SCIA:
192 if (attr_len < sizeof(struct nan_sec_ctxt))
193 break;
194
195 attrs->sec_ctxt_info = pos;
196 attrs->sec_ctxt_info_len = attr_len;
197 break;
198 case NAN_ATTR_SHARED_KEY_DESCR:
199 if (attr_len < sizeof(struct nan_shared_key) +
200 sizeof(struct wpa_eapol_key))
201 break;
202
203 attrs->shared_key_desc = pos;
204 attrs->shared_key_desc_len = attr_len;
205 break;
206 case NAN_ATTR_DCEA:
207 attrs->dev_capa_ext = pos;
208 attrs->dev_capa_ext_len = attr_len;
209 break;
210 case NAN_ATTR_NPBA:
211 /*
212 * Validate minimal NPBA length: Dialog Token (1) +
213 * Type and Statuss (1) + Reason Code (1) +
214 * Pairing Bootstrapping Method (2)
215 */
216 if (attr_len < 5)
217 break;
218 attrs->npba = pos;
219 attrs->npba_len = attr_len;
220 break;
221 case NAN_ATTR_NIRA:
222 if (pos[0] != NAN_NIRA_CIPHER_VER_128)
223 break;
224
225 /* Cipher Version (1) + Nonce (8) + Tag (8) */
226 if (attr_len !=
227 1 + NAN_NIRA_NONCE_LEN + NAN_NIRA_TAG_LEN)
228 break;
229
230 attrs->nira = pos;
231 attrs->nira_len = attr_len;
232 break;
233 case NAN_ATTR_NDP_EXT:
234 /*
235 * Validate minimal NDPE attribute length. NDP and NDPE
236 * attributes have the common structure and thus the
237 * same minimal length requirement based on the common
238 * fields (see struct ieee80211_ndp).
239 */
240 if (attr_len < sizeof(struct ieee80211_ndp))
241 break;
242
243 attrs->ndpe = pos;
244 attrs->ndpe_len = attr_len;
245 break;
246 case NAN_ATTR_MASTER_INDICATION:
247 case NAN_ATTR_CLUSTER:
248 case NAN_ATTR_NAN_ATTR_SERVICE_ID_LIST:
249 case NAN_ATTR_SDA:
250 case NAN_ATTR_CONN_CAPA:
251 case NAN_ATTR_WLAN_INFRA:
252 case NAN_ATTR_P2P_OPER:
253 case NAN_ATTR_IBSS:
254 case NAN_ATTR_MESH:
255 case NAN_ATTR_FURTHER_NAN_SD:
256 case NAN_ATTR_FURTHER_AVAIL_MAP:
257 case NAN_ATTR_COUNTRY_CODE:
258 case NAN_ATTR_RANGING:
259 case NAN_ATTR_CLUSTER_DISCOVERY:
260 case NAN_ATTR_RANGING_INFO:
261 case NAN_ATTR_RANGING_SETUP:
262 case NAN_ATTR_FTM_RANGING_REPORT:
263 case NAN_ATTR_EXT_WLAN_INFRA:
264 case NAN_ATTR_EXT_P2P_OPER:
265 case NAN_ATTR_EXT_IBSS:
266 case NAN_ATTR_EXT_MESH:
267 case NAN_ATTR_PUBLIC_AVAILABILITY:
268 case NAN_ATTR_SUBSC_SERVICE_ID_LIST:
269 case NAN_ATTR_S3:
270 case NAN_ATTR_TPEA:
271 case NAN_ATTR_VENDOR_SPECIFIC:
272 wpa_printf(MSG_DEBUG, "NAN: ignore attr=%u", id);
273 break;
274 default:
275 wpa_printf(MSG_DEBUG, "NAN: unknown attr=%u", id);
276 break;
277 }
278
279 pos += attr_len;
280 }
281
282 /* Parsing is considered success only if all attributes were consumed */
283 if (pos == end)
284 return 0;
285
286 fail:
287 nan_attrs_clear(nan, attrs);
288 return -1;
289 }
290
291
292 /*
293 * nan_is_naf - Check if a given frame is a NAN Action frame
294 * @mgmt: NAN Action frame
295 * @len: Length of the Management frame in octets
296 * Returns: true if NAF; otherwise false
297 */
nan_is_naf(const struct ieee80211_mgmt * mgmt,size_t len)298 bool nan_is_naf(const struct ieee80211_mgmt *mgmt, size_t len)
299 {
300 u8 subtype;
301
302 /*
303 * 802.11 header + category + NAN Action frame minimal + subtype (1)
304 */
305 if (len < IEEE80211_MIN_ACTION_LEN(naf)) {
306 wpa_printf(MSG_DEBUG, "NAN: Too short NAN frame");
307 return false;
308 }
309
310 if (mgmt->u.action.u.naf.action != WLAN_PA_VENDOR_SPECIFIC ||
311 WPA_GET_BE24(mgmt->u.action.u.naf.oui) != OUI_WFA ||
312 mgmt->u.action.u.naf.oui_type != NAN_NAF_OUI_TYPE)
313 return false;
314
315 subtype = mgmt->u.action.u.naf.subtype;
316
317 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
318 !(subtype >= NAN_SUBTYPE_DATA_PATH_REQUEST &&
319 subtype <= NAN_SUBTYPE_DATA_PATH_TERMINATION &&
320 mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL)) {
321 wpa_printf(MSG_DEBUG, "NAN: Invalid action category for NAF");
322 return false;
323 }
324
325 return true;
326 }
327
328
329 /*
330 * nan_parse_naf - Parse a NAN Action frame content
331 * @nan: NAN module context from nan_init()
332 * @mgmt: NAN action frame
333 * @len: Length of the management frame in octets
334 * @msg: Buffer for returning parsed attributes
335 * Returns: 0 on success; positive or negative indicate an error
336 *
337 * Note: in case of success, the caller must free temporary memory allocations
338 * by calling nan_attrs_clear() when the parsed data is not needed anymore. In
339 * addition, as the &mgmt is referenced from the returned structure, the caller
340 * must ensure that the frame buffer remains valid and unmodified as long as the
341 * &msg object is used.
342 */
nan_parse_naf(struct nan_data * nan,const struct ieee80211_mgmt * mgmt,size_t len,struct nan_msg * msg)343 int nan_parse_naf(struct nan_data *nan, const struct ieee80211_mgmt *mgmt,
344 size_t len, struct nan_msg *msg)
345 {
346 if (!nan_is_naf(mgmt, len))
347 return -1;
348
349 wpa_printf(MSG_DEBUG, "NAN: Parse NAF");
350
351 msg->oui_type = mgmt->u.action.u.naf.oui_type;
352 msg->oui_subtype = mgmt->u.action.u.naf.subtype;
353
354 msg->mgmt = mgmt;
355 msg->len = len;
356
357 return nan_parse_attrs(nan,
358 mgmt->u.action.u.naf.variable,
359 len - IEEE80211_MIN_ACTION_LEN(naf),
360 &msg->attrs);
361 }
362
363
364 /*
365 * nan_add_dev_capa_attr - Add Device Capability attribute
366 * @nan: NAN module context from nan_init()
367 * @buf: wpabuf to which the attribute would be added
368 */
nan_add_dev_capa_attr(struct nan_data * nan,struct wpabuf * buf)369 void nan_add_dev_capa_attr(struct nan_data *nan, struct wpabuf *buf)
370 {
371 wpabuf_put_u8(buf, NAN_ATTR_DEVICE_CAPABILITY);
372 wpabuf_put_le16(buf, sizeof(struct nan_device_capa));
373
374 /* Device capabilities apply to the device, so set map ID = 0 */
375 wpabuf_put_u8(buf, 0);
376 wpabuf_put_le16(buf, nan->cfg->dev_capa.cdw_info);
377 wpabuf_put_u8(buf, nan->cfg->dev_capa.supported_bands);
378 wpabuf_put_u8(buf, nan->cfg->dev_capa.op_mode);
379 wpabuf_put_u8(buf, nan->cfg->dev_capa.n_antennas);
380 wpabuf_put_le16(buf, nan->cfg->dev_capa.channel_switch_time);
381 wpabuf_put_u8(buf, nan->cfg->dev_capa.capa);
382 }
383
384
385 /*
386 * nan_add_csia - Add Cipher Suite Information Attribute (CSIA) to a buffer
387 * @buf: Buffer to add the attribute to
388 * @capab: Capabilities field (1 octet)
389 * @cs_list_len: Number of cipher suites in the list
390 * @cs_list: Array of cipher suite structures
391 *
392 * This function constructs and appends a NAN Cipher Suite Information Attribute
393 * to the provided buffer.
394 *
395 * Returns: 0 on success, -1 on failure (insufficient buffer space)
396 */
nan_add_csia(struct wpabuf * buf,u8 capab,size_t cs_list_len,const struct nan_cipher_suite * cs_list)397 int nan_add_csia(struct wpabuf *buf, u8 capab, size_t cs_list_len,
398 const struct nan_cipher_suite *cs_list)
399 {
400 size_t i;
401 /* Capabilities (1 octet) + Cipher Suite List */
402 size_t attr_len = sizeof(capab) + cs_list_len * sizeof(*cs_list);
403
404 if (wpabuf_tailroom(buf) <
405 (size_t) (NAN_ATTR_HDR_LEN + attr_len)) {
406 wpa_printf(MSG_DEBUG,
407 "NAN: Not enough space to add CSIA attribute");
408 return -1;
409 }
410
411 wpabuf_put_u8(buf, NAN_ATTR_CSIA);
412 wpabuf_put_le16(buf, attr_len);
413 wpabuf_put_u8(buf, capab);
414
415 for (i = 0; i < cs_list_len; i++) {
416 wpabuf_put_u8(buf, cs_list[i].csid);
417 wpabuf_put_u8(buf, cs_list[i].instance_id);
418 }
419
420 return 0;
421 }
422
423
424 /**
425 * nan_add_dev_capa_ext_attr - Add NAN Device Capability Extension attribute
426 * @nan: NAN module context from nan_init()
427 * @buf: wpabuf to which the attribute would be added
428 */
nan_add_dev_capa_ext_attr(struct nan_data * nan,struct wpabuf * buf)429 void nan_add_dev_capa_ext_attr(struct nan_data *nan, struct wpabuf *buf)
430 {
431 u8 pairing_and_npk_caching = 0;
432
433 if (nan->cfg->pairing_cfg.pairing_setup)
434 pairing_and_npk_caching |=
435 NAN_DEV_CAPA_EXT_INFO_1_PAIRING_SETUP;
436 if (nan->cfg->pairing_cfg.npk_caching)
437 pairing_and_npk_caching |=
438 NAN_DEV_CAPA_EXT_INFO_1_NPK_NIK_CACHING;
439
440 if (!nan->cfg->dev_capa_ext_reg_info &&
441 !pairing_and_npk_caching)
442 return;
443
444 wpabuf_put_u8(buf, NAN_ATTR_DCEA);
445 wpabuf_put_le16(buf, 2);
446 wpabuf_put_u8(buf, nan->cfg->dev_capa_ext_reg_info);
447 wpabuf_put_u8(buf, pairing_and_npk_caching);
448 }
449
450
451 /**
452 * nan_add_nira - Add NIRA (NAN Identity Resolution Attribute) to a buffer
453 * @buf: Buffer to which the NIRA is appended
454 * @tag: Pointer to NIRA tag data (NAN_NIRA_TAG_LEN bytes)
455 * @nonce: Pointer to NIRA nonce data (NAN_NIRA_NONCE_LEN bytes)
456 * Returns: 0 on success, -1 if there is insufficient space in the buffer
457 *
458 * This function constructs and appends a NAN Identity Resolution Attribute
459 * (NIRA) to the provided buffer.
460 */
nan_add_nira(struct wpabuf * buf,const u8 * tag,const u8 * nonce)461 int nan_add_nira(struct wpabuf *buf, const u8 *tag, const u8 *nonce)
462 {
463 u16 attr_len = 1 + NAN_NIRA_NONCE_LEN + NAN_NIRA_TAG_LEN;
464
465 if (wpabuf_tailroom(buf) < (size_t) (NAN_ATTR_HDR_LEN + attr_len)) {
466 wpa_printf(MSG_INFO, "NAN: Not enough space to add NIRA");
467 return -1;
468 }
469
470 wpabuf_put_u8(buf, NAN_ATTR_NIRA);
471 wpabuf_put_le16(buf, attr_len);
472 wpabuf_put_u8(buf, NAN_NIRA_CIPHER_VER_128);
473 wpabuf_put_data(buf, nonce, NAN_NIRA_NONCE_LEN);
474 wpabuf_put_data(buf, tag, NAN_NIRA_TAG_LEN);
475
476 return 0;
477 }
478
479
480 /**
481 * nan_chan_to_chan_idx_map - Convert an op_class and chan to channel bitmap
482 * @nan: NAN module context from nan_init()
483 * @op_class: the operating class
484 * @channel: channel number
485 * @chan_idx_map: On success, would hold the channel index bitmap
486 * Returns: 0 on success, otherwise a negative value
487 */
nan_chan_to_chan_idx_map(struct nan_data * nan,u8 op_class,u8 channel,u16 * chan_idx_map)488 int nan_chan_to_chan_idx_map(struct nan_data *nan,
489 u8 op_class, u8 channel, u16 *chan_idx_map)
490 {
491 int ret;
492 const struct oper_class_map *op_c;
493
494 if (!chan_idx_map)
495 return -1;
496
497 op_c = get_oper_class(NULL, op_class);
498 if (!op_c)
499 return -1;
500
501 ret = op_class_chan_to_idx(op_c, channel);
502 if (ret < 0)
503 return ret;
504
505 if ((size_t) ret >= (sizeof(*chan_idx_map) * 8))
506 return -1;
507
508 *chan_idx_map = BIT(ret);
509 return 0;
510 }
511
512
nan_add_avail_entry(struct nan_data * nan,struct nan_time_bitmap * tbm,u8 type,u8 op_class,u16 chan_bm,u8 prim_chan_bm,struct wpabuf * buf)513 static u16 nan_add_avail_entry(struct nan_data *nan,
514 struct nan_time_bitmap *tbm,
515 u8 type, u8 op_class, u16 chan_bm,
516 u8 prim_chan_bm, struct wpabuf *buf)
517 {
518 u16 ctrl;
519 u8 chan_ctrl;
520 u8 *len_ptr;
521 u8 nss = BITS(nan->cfg->dev_capa.n_antennas, NAN_DEV_CAPA_RX_ANT_MASK,
522 NAN_DEV_CAPA_RX_ANT_POS);
523
524 len_ptr = wpabuf_put(buf, 2);
525
526 /* Potential availability entries are handled separately */
527 if (type != NAN_AVAIL_ENTRY_CTRL_TYPE_COMMITTED &&
528 type != NAN_AVAIL_ENTRY_CTRL_TYPE_COND) {
529 wpa_printf(MSG_DEBUG,
530 "NAN: Cannot add non committed/conditional entry");
531 return 0;
532 }
533
534 /*
535 * Add the entry control field
536 * - usage preference is not set for committed and conditional
537 * - utilization is max.
538 */
539 ctrl = type;
540 ctrl |= NAN_AVAIL_ENTRY_DEF_UTIL << NAN_AVAIL_ENTRY_CTRL_UTIL_POS;
541 ctrl |= nss << NAN_AVAIL_ENTRY_CTRL_RX_NSS_POS;
542 ctrl |= NAN_AVAIL_ENTRY_CTRL_TBM_PRESENT;
543 wpabuf_put_le16(buf, ctrl);
544
545 /* Add the time bitmap control field */
546 ctrl = tbm->duration << NAN_TIME_BM_CTRL_BIT_DURATION_POS;
547 ctrl |= tbm->period << NAN_TIME_BM_CTRL_PERIOD_POS;
548 ctrl |= tbm->offset << NAN_TIME_BM_CTRL_START_OFFSET_POS;
549 wpabuf_put_le16(buf, ctrl);
550
551 wpabuf_put_u8(buf, tbm->len);
552 wpabuf_put_data(buf, tbm->bitmap, tbm->len);
553
554 /* Add the channel entry: single contiguous channel entry */
555 chan_ctrl = NAN_BAND_CHAN_CTRL_TYPE;
556 chan_ctrl |= 1 << NAN_BAND_CHAN_CTRL_NUM_ENTRIES_POS;
557 wpabuf_put_u8(buf, chan_ctrl);
558 wpabuf_put_u8(buf, op_class);
559 wpabuf_put_le16(buf, chan_bm);
560 wpabuf_put_u8(buf, prim_chan_bm);
561
562 WPA_PUT_LE16(len_ptr, (u8 *) wpabuf_put(buf, 0) - len_ptr - 2);
563 return (u8 *) wpabuf_put(buf, 0) - len_ptr;
564 }
565
566
nan_get_chan_bm(struct nan_data * nan,const struct nan_sched_chan * chan,u8 * op_class,u16 * chan_bm,u16 * pri_chan_bm)567 int nan_get_chan_bm(struct nan_data *nan, const struct nan_sched_chan *chan,
568 u8 *op_class, u16 *chan_bm, u16 *pri_chan_bm)
569 {
570 u8 channel;
571 enum hostapd_hw_mode mode;
572 int ret, sec_channel_offset;
573 int freq_offsset = chan->freq - chan->center_freq1;
574 u32 idx;
575 enum oper_chan_width bandwidth;
576
577 switch (chan->bandwidth) {
578 case 20:
579 case 40:
580 default:
581 *pri_chan_bm = 0;
582 bandwidth = CONF_OPER_CHWIDTH_USE_HT;
583 break;
584 case 80:
585 bandwidth = CONF_OPER_CHWIDTH_80MHZ;
586
587 idx = (freq_offsset + 30) / 20;
588 *pri_chan_bm = BIT(idx);
589 break;
590 case 160:
591 if (chan->center_freq2) {
592 bandwidth = CONF_OPER_CHWIDTH_80P80MHZ;
593
594 /* TODO: Need to support auxiliary channel bitmap */
595 idx = (freq_offsset + 30) / 20;
596 *pri_chan_bm = BIT(idx);
597 } else {
598 bandwidth = CONF_OPER_CHWIDTH_160MHZ;
599 idx = (freq_offsset + 70) / 20;
600 *pri_chan_bm = BIT(idx);
601 }
602 break;
603 }
604
605 if (freq_offsset > 0)
606 sec_channel_offset = 1;
607 else if (freq_offsset < 0)
608 sec_channel_offset = -1;
609 else
610 sec_channel_offset = 0;
611
612 wpa_printf(MSG_DEBUG,
613 "NAN: Get chan bm: freq=%d, center_freq1=%d, bandwidth=%u, sec_channel_offset=%d",
614 chan->freq, chan->center_freq1, chan->bandwidth,
615 freq_offsset);
616
617 /* For bandwidths >= 80 need to use the center frequency */
618 mode = ieee80211_freq_to_channel_ext(bandwidth ==
619 CONF_OPER_CHWIDTH_USE_HT ?
620 chan->freq : chan->center_freq1,
621 sec_channel_offset,
622 bandwidth, op_class, &channel);
623 if (mode == NUM_HOSTAPD_MODES) {
624 wpa_printf(MSG_DEBUG,
625 "NAN: Cannot get channel and op_class");
626 return -1;
627 }
628
629 wpa_printf(MSG_DEBUG, "NAN: Derived op_class=%u, channel=%u",
630 *op_class, channel);
631
632 ret = nan_chan_to_chan_idx_map(nan, *op_class, channel, chan_bm);
633 if (ret) {
634 wpa_printf(MSG_DEBUG, "NAN: Failed to derive channel bitmap");
635 return -1;
636 }
637
638 return 0;
639 }
640
641
nan_add_pot_avail_entry(struct nan_data * nan,struct nan_chan_entry * entries,unsigned int n_entries,u8 pref,struct wpabuf * buf)642 static void nan_add_pot_avail_entry(struct nan_data *nan,
643 struct nan_chan_entry *entries,
644 unsigned int n_entries, u8 pref,
645 struct wpabuf *buf)
646 {
647 u16 ctrl;
648 u8 chan_ctrl;
649 size_t i;
650 u8 nss = BITS(nan->cfg->dev_capa.n_antennas, NAN_DEV_CAPA_RX_ANT_MASK,
651 NAN_DEV_CAPA_RX_ANT_POS);
652
653 wpa_printf(MSG_DEBUG, "NAN: Adding potential entry: n_entries=%u",
654 n_entries);
655
656 if (!n_entries)
657 return;
658
659 /* The number of channel entries can be too big for the buffer */
660 if (wpabuf_tailroom(buf) < 2 + 2 + 1 + n_entries * 4) {
661 n_entries = (wpabuf_tailroom(buf) - 5) / 4;
662
663 wpa_printf(MSG_DEBUG,
664 "NAN: Not enough space to add potential entries, reduce to %u",
665 n_entries);
666 }
667
668 /*
669 * ctrl (2) + chan control (1) + n_entries * (nan_chan_entry without
670 * the aux bitmap).
671 */
672 wpabuf_put_le16(buf, 3 + n_entries * 4);
673
674 ctrl = NAN_AVAIL_ENTRY_CTRL_TYPE_POTENTIAL;
675 ctrl |= NAN_AVAIL_ENTRY_DEF_UTIL << NAN_AVAIL_ENTRY_CTRL_UTIL_POS;
676 ctrl |= nss << NAN_AVAIL_ENTRY_CTRL_RX_NSS_POS;
677 ctrl |= pref << NAN_AVAIL_ENTRY_CTRL_USAGE_PREF_POS;
678 wpabuf_put_le16(buf, ctrl);
679
680 /* Add all channel entries */
681 chan_ctrl = NAN_BAND_CHAN_CTRL_TYPE;
682 chan_ctrl |= n_entries << NAN_BAND_CHAN_CTRL_NUM_ENTRIES_POS;
683 wpabuf_put_u8(buf, chan_ctrl);
684
685 for (i = 0; i < n_entries; i++) {
686 struct nan_chan_entry *cur = &entries[i];
687
688 wpabuf_put_u8(buf, cur->op_class);
689 wpabuf_put_le16(buf, cur->chan_bitmap);
690 wpabuf_put_u8(buf, 0);
691 }
692 }
693
694
695 static void
nan_build_pot_avail_entry_with_chans(struct nan_data * nan,const struct nan_channels * pot_chans,struct wpabuf * buf,u8 map_id)696 nan_build_pot_avail_entry_with_chans(struct nan_data *nan,
697 const struct nan_channels *pot_chans,
698 struct wpabuf *buf, u8 map_id)
699 {
700 struct nan_chan_entry chan_entries[global_op_class_size];
701 size_t i, n_entries;
702
703 os_memset(chan_entries, 0, sizeof(chan_entries));
704 n_entries = 0;
705
706 wpa_printf(MSG_DEBUG, "NAN: Adding potential entries: n_chans=%u",
707 pot_chans->n_chans);
708
709 for (i = 0; i < pot_chans->n_chans; i++) {
710 struct nan_channel_info *chan = &pot_chans->chans[i];
711 struct nan_chan_entry *cur;
712 u16 cbm = 0;
713 size_t j;
714 int ret;
715
716 if (i > 0 && pot_chans->chans[i - 1].pref != chan->pref) {
717 nan_add_pot_avail_entry(nan, chan_entries, n_entries,
718 pot_chans->chans[i - 1].pref,
719 buf);
720
721 os_memset(chan_entries, 0, sizeof(chan_entries));
722 n_entries = 0;
723 }
724
725 ret = nan_chan_to_chan_idx_map(nan, chan->op_class,
726 chan->channel, &cbm);
727 if (ret)
728 continue;
729
730 /* Try to find and entry that matches the operating class */
731 for (j = 0, cur = NULL; j < n_entries; j++) {
732 cur = &chan_entries[j];
733
734 if (!cur->op_class || cur->op_class == chan->op_class)
735 break;
736 }
737
738 if (!n_entries)
739 cur = &chan_entries[n_entries++];
740 else if (j == n_entries && n_entries < global_op_class_size)
741 cur = &chan_entries[n_entries++];
742 else if (!cur)
743 continue;
744
745 cur->op_class = chan->op_class;
746 cur->chan_bitmap |= cbm;
747 }
748
749 if (n_entries)
750 nan_add_pot_avail_entry(nan, chan_entries, n_entries,
751 pot_chans->chans[i - 1].pref, buf);
752
753 wpa_printf(MSG_DEBUG, "NAN: Added potential entries: done");
754 }
755
756
nan_build_pot_avail_entry(struct nan_data * nan,struct wpabuf * buf,u8 map_id)757 static void nan_build_pot_avail_entry(struct nan_data *nan, struct wpabuf *buf,
758 u8 map_id)
759 {
760 struct nan_channels pot_chans;
761
762 os_memset(&pot_chans, 0, sizeof(pot_chans));
763
764 if (!nan->cfg->get_chans ||
765 nan->cfg->get_chans(nan->cfg->cb_ctx, map_id, &pot_chans) < 0) {
766 wpa_printf(MSG_DEBUG,
767 "NAN: Failed to get channels. Not adding potential");
768 return;
769 }
770
771 if (pot_chans.n_chans != 0)
772 nan_build_pot_avail_entry_with_chans(nan, &pot_chans, buf,
773 map_id);
774 else
775 wpa_printf(MSG_DEBUG,
776 "NAN: No channels available. Not adding potential: map_id=%u",
777 map_id);
778
779 os_free(pot_chans.chans);
780 }
781
782
783 /**
784 * nan_add_avail_attrs - Add NAN availability attributes
785 * @nan: NAN module context from nan_init()
786 * @sequence_id: Sequence ID to be used in the availability attributes
787 * @map_ids_bitmap: Bitmap of map IDs to be included in the availability
788 * attributes
789 * @type_for_conditional: Type field to be used for conditional entries
790 * @n_chans: Number of channels in chans
791 * @chans: Channel schedules
792 * @buf: Frame buffer to which the attribute would be added
793 * @include_potential: Whether to add potential availability entries
794 * Returns: 0 on success, negative on failure.
795 *
796 * An availability attribute is added for each map (identified by map ID) in the
797 * schedule. All channels with the same map ID are added to the same
798 * availability attribute. Each attribute will hold an availability entry for
799 * committed slots and an availability entry for conditional slots.
800 */
nan_add_avail_attrs(struct nan_data * nan,u8 sequence_id,u32 map_ids_bitmap,u8 type_for_conditional,size_t n_chans,struct nan_chan_schedule * chans,struct wpabuf * buf,bool include_potential)801 int nan_add_avail_attrs(struct nan_data *nan, u8 sequence_id,
802 u32 map_ids_bitmap, u8 type_for_conditional,
803 size_t n_chans, struct nan_chan_schedule *chans,
804 struct wpabuf *buf, bool include_potential)
805 {
806 u8 last_map_id = NAN_INVALID_MAP_ID;
807 u32 handled_map_ids = 0;
808 u8 *len_ptr = NULL;
809 u8 i;
810
811 wpa_printf(MSG_DEBUG, "NAN: Add availability attrs. n_chans=%zu",
812 n_chans);
813
814 for (i = 0; i < n_chans; i++) {
815 struct nan_chan_schedule *chan = &chans[i];
816 u8 op_class;
817 u16 chan_bm, pri_chan_bm;
818 int ret;
819
820 if (!chan->conditional.len && !chan->committed.len) {
821 wpa_printf(MSG_DEBUG,
822 "NAN: committed and conditional are empty");
823 continue;
824 }
825
826 ret = nan_get_chan_bm(nan, &chan->chan, &op_class,
827 &chan_bm, &pri_chan_bm);
828 if (ret)
829 continue;
830
831 /*
832 * All channels with the same map ID should be added to the same
833 * availability attribute, so verify that the map IDs are
834 * sorted.
835 */
836 if (last_map_id != NAN_INVALID_MAP_ID &&
837 last_map_id > chan->map_id) {
838 wpa_printf(MSG_DEBUG,
839 "NAN: Map IDs not sorted properly");
840 return -1;
841 }
842
843 if (!(map_ids_bitmap & BIT(chan->map_id))) {
844 wpa_printf(MSG_DEBUG,
845 "NAN: Skip adding availability for map_id=%u",
846 chan->map_id);
847 continue;
848 }
849
850 if (last_map_id != chan->map_id) {
851 u16 ctrl;
852
853 if (last_map_id != NAN_INVALID_MAP_ID) {
854 wpa_printf(MSG_DEBUG,
855 "NAN: Add avail attr done: map_id=%u",
856 last_map_id);
857
858 if (include_potential)
859 nan_build_pot_avail_entry(nan, buf,
860 last_map_id);
861 WPA_PUT_LE16(len_ptr,
862 (u8 *) wpabuf_put(buf, 0) -
863 len_ptr - 2);
864 }
865
866 last_map_id = chan->map_id;
867 handled_map_ids |= BIT(last_map_id);
868
869 wpa_printf(MSG_DEBUG, "NAN: Add avail attr map_id=%u",
870 last_map_id);
871
872 wpabuf_put_u8(buf, NAN_ATTR_NAN_AVAILABILITY);
873 len_ptr = wpabuf_put(buf, 2);
874 wpabuf_put_u8(buf, sequence_id);
875
876 ctrl = last_map_id << NAN_AVAIL_CTRL_MAP_ID_POS;
877
878 /*
879 * The spec states that this bit should be set if the
880 * committed changed or if conditional is included. Set
881 * it anyway, as it is not known what information the
882 * peer has on our schedule. Similarly, always set the
883 * potential changed bit.
884 */
885 ctrl |= NAN_AVAIL_CTRL_COMMITTED_CHANGED |
886 NAN_AVAIL_CTRL_POTENTIAL_CHANGED;
887 wpabuf_put_le16(buf, ctrl);
888 }
889
890 /* TODO: handle primary channel configuration */
891 if (chan->committed.len)
892 nan_add_avail_entry(nan, &chan->committed,
893 NAN_AVAIL_ENTRY_CTRL_TYPE_COMMITTED,
894 op_class, chan_bm, pri_chan_bm,
895 buf);
896
897 if (chan->conditional.len)
898 nan_add_avail_entry(nan, &chan->conditional,
899 type_for_conditional,
900 op_class, chan_bm, pri_chan_bm,
901 buf);
902 }
903
904 if (last_map_id != NAN_INVALID_MAP_ID) {
905 if (include_potential)
906 nan_build_pot_avail_entry(nan, buf, last_map_id);
907 WPA_PUT_LE16(len_ptr, (u8 *) wpabuf_put(buf, 0) - len_ptr - 2);
908
909 wpa_printf(MSG_DEBUG, "NAN: Add avail attr done: map_id=%u",
910 last_map_id);
911 } else {
912 wpa_printf(MSG_DEBUG,
913 "NAN: No committed/conditional entries were added");
914 }
915
916 if (!include_potential)
917 return 0;
918
919 /*
920 * Add NAN availability attributes with a single potential availability
921 * entry for map IDs that are not included in the schedule.
922 */
923 map_ids_bitmap &= ~handled_map_ids;
924 wpa_printf(MSG_DEBUG,
925 "NAN: Add avail attrs for remaining map IDs: bitmap=0x%x",
926 map_ids_bitmap);
927
928 while (map_ids_bitmap) {
929 struct nan_channels pot_chans;
930 u8 map_id = ffs(map_ids_bitmap) - 1;
931 u16 ctrl = map_id << NAN_AVAIL_CTRL_MAP_ID_POS |
932 NAN_AVAIL_CTRL_POTENTIAL_CHANGED;
933
934 map_ids_bitmap &= ~BIT(map_id);
935
936 wpa_printf(MSG_DEBUG, "NAN: Add avail attr for map_id=%u",
937 map_id);
938
939 os_memset(&pot_chans, 0, sizeof(pot_chans));
940
941 if (!nan->cfg->get_chans ||
942 nan->cfg->get_chans(nan->cfg->cb_ctx, map_id,
943 &pot_chans) < 0 ||
944 !pot_chans.chans) {
945 wpa_printf(MSG_DEBUG,
946 "NAN: No channels available. Not adding potential: map_id=%u",
947 map_id);
948 continue;
949 }
950
951 wpabuf_put_u8(buf, NAN_ATTR_NAN_AVAILABILITY);
952 len_ptr = wpabuf_put(buf, 2);
953 wpabuf_put_u8(buf, sequence_id);
954 wpabuf_put_le16(buf, ctrl);
955
956 nan_build_pot_avail_entry_with_chans(nan, &pot_chans, buf,
957 map_id);
958 os_free(pot_chans.chans);
959
960 WPA_PUT_LE16(len_ptr, (u8 *) wpabuf_put(buf, 0) - len_ptr - 2);
961 }
962
963 return 0;
964 }
965
966
967 /**
968 * nan_del_avail_entry - Delete an availability entry
969 * @entry: The availability entry to delete
970 */
nan_del_avail_entry(struct nan_avail_entry * entry)971 void nan_del_avail_entry(struct nan_avail_entry *entry)
972 {
973 if (!entry)
974 return;
975 os_free(entry->band_chan);
976 os_free(entry);
977 }
978
979
980 /**
981 * nan_flush_avail_entries - Flush a list of availability entries
982 * @avail_entries: List of availability entries
983 */
nan_flush_avail_entries(struct dl_list * avail_entries)984 void nan_flush_avail_entries(struct dl_list *avail_entries)
985 {
986 struct nan_avail_entry *cur, *next;
987
988 dl_list_for_each_safe(cur, next, avail_entries,
989 struct nan_avail_entry, list) {
990 dl_list_del(&cur->list);
991 nan_del_avail_entry(cur);
992 }
993 }
994
995
996 /**
997 * nan_sched_entries_to_avail_entries - Convert NAN schedule entries to NAN
998 * availability entries
999 *
1000 * @nan: NAN module context from nan_init()
1001 * @avail_entries: On successful return would hold a valid list of availability
1002 * entries
1003 * @sched_entries: Buffer holding the schedule entries, each of type
1004 * &struct nan_sched_entry
1005 * @sched_entries_len: Length of the sched_entries buffer
1006 */
nan_sched_entries_to_avail_entries(struct nan_data * nan,struct dl_list * avail_entries,const u8 * sched_entries,u16 sched_entries_len)1007 int nan_sched_entries_to_avail_entries(struct nan_data *nan,
1008 struct dl_list *avail_entries,
1009 const u8 *sched_entries,
1010 u16 sched_entries_len)
1011 {
1012 dl_list_init(avail_entries);
1013
1014 if (!sched_entries || !sched_entries_len)
1015 return 0;
1016
1017 if (sched_entries_len < sizeof(struct nan_sched_entry)) {
1018 wpa_printf(MSG_DEBUG, "NAN: Schedule entry too short=%u",
1019 sched_entries_len);
1020 return -1;
1021 }
1022
1023 while (sched_entries_len > 0) {
1024 const struct nan_sched_entry *sched_entry =
1025 (const struct nan_sched_entry *) sched_entries;
1026 struct nan_avail_entry *avail_entry;
1027 u16 ctrl;
1028 size_t elen;
1029
1030 if (sched_entries_len < sizeof(struct nan_sched_entry))
1031 goto fail;
1032 elen = sizeof(struct nan_sched_entry) + sched_entry->len;
1033 if (sched_entries_len < elen) {
1034 wpa_printf(MSG_DEBUG,
1035 "NAN: Invalid schedule entry len=%u",
1036 sched_entry->len);
1037 goto fail;
1038 }
1039
1040 if (sched_entry->len > NAN_TIME_BITMAP_MAX_LEN)
1041 goto fail;
1042
1043 avail_entry = os_zalloc(sizeof(struct nan_avail_entry));
1044 if (!avail_entry)
1045 goto fail;
1046
1047 avail_entry->map_id = sched_entry->map_id;
1048 ctrl = le_to_host16(sched_entry->control);
1049
1050 avail_entry->tbm.duration =
1051 BITS(ctrl,
1052 NAN_TIME_BM_CTRL_BIT_DURATION_MASK,
1053 NAN_TIME_BM_CTRL_BIT_DURATION_POS);
1054 avail_entry->tbm.period =
1055 BITS(ctrl,
1056 NAN_TIME_BM_CTRL_PERIOD_MASK,
1057 NAN_TIME_BM_CTRL_PERIOD_POS);
1058 avail_entry->tbm.offset =
1059 BITS(ctrl,
1060 NAN_TIME_BM_CTRL_START_OFFSET_MASK,
1061 NAN_TIME_BM_CTRL_START_OFFSET_POS);
1062
1063 avail_entry->tbm.len = sched_entry->len;
1064 os_memcpy(avail_entry->tbm.bitmap, sched_entry->bm,
1065 sched_entry->len);
1066
1067 dl_list_init(&avail_entry->list);
1068 dl_list_add(avail_entries, &avail_entry->list);
1069
1070 sched_entries_len -= elen;
1071 sched_entries += elen;
1072 }
1073
1074 return 0;
1075
1076 fail:
1077 nan_flush_avail_entries(avail_entries);
1078 return -1;
1079 }
1080
1081
1082 /**
1083 * nan_tbm_to_bf - Convert a time bitmap to bitfield
1084 * @nan: NAN module context from nan_init()
1085 * @tbm: Time bitmap
1086 * Returns: The converted bitfield on success; otherwise, NULL
1087 *
1088 * The function takes a time bitmap and converts it to a bitfield that
1089 * represents a time bitmap with 16 TUs slots that covers a period of 8192 TUs.
1090 * The conversion takes into account the duration, period, and offset fields of
1091 * the time bitmap.
1092 */
nan_tbm_to_bf(struct nan_data * nan,const struct nan_time_bitmap * tbm)1093 struct bitfield * nan_tbm_to_bf(struct nan_data *nan,
1094 const struct nan_time_bitmap *tbm)
1095 {
1096 struct bitfield *bf, *base;
1097 u32 slot_duration, period, len;
1098 u32 dur_factor, i, j, iter, max_iter;
1099
1100 wpa_printf(MSG_DEBUG,
1101 "NAN: Convert time bitmap: len=%u, dur=%u, period=%u, offset=%u",
1102 tbm->len, tbm->duration, tbm->period, tbm->offset);
1103
1104 /* Calculate the length and make sure it is less than the period */
1105 dur_factor = 1 << tbm->duration;
1106 slot_duration = 16 * dur_factor;
1107
1108 if (tbm->period == 0)
1109 period = tbm->len * 8 * slot_duration;
1110 else
1111 period = 128 * (1 << (tbm->period - 1));
1112
1113 len = tbm->len;
1114 if (tbm->len * 8 * slot_duration > period) {
1115 wpa_printf(MSG_DEBUG,
1116 "NAN: Time bitmap length is bigger than duration. Chop it");
1117 len = period / slot_duration / 8;
1118 }
1119
1120 /* The 'base' bitfield holds the original bitmap */
1121 base = bitfield_alloc_data(tbm->bitmap, tbm->len);
1122 if (!base) {
1123 wpa_printf(MSG_DEBUG, "NAN: Failed to allocate base bitmap");
1124 return NULL;
1125 }
1126
1127 if (!len) {
1128 wpa_printf(MSG_DEBUG, "NAN: Empty time bitmap");
1129 return base;
1130 }
1131
1132 /* Allocate a time bitmap to cover a 8192 TUs period */
1133 bf = bitfield_alloc(NAN_MAX_TIME_BITMAP_SLOTS);
1134 if (!bf) {
1135 bitfield_free(base);
1136 return NULL;
1137 }
1138
1139 /*
1140 * Convert the original map to a map of 16 TU slots taking into account
1141 * the time bitmap offset and the period. Note that during availability
1142 * attribute parsing, it was verified that offset is smaller than the
1143 * period.
1144 */
1145 max_iter = NAN_MAX_PERIOD_TUS / period;
1146 for (iter = 0; iter < max_iter; iter++) {
1147 u32 start_slot = tbm->offset + iter * (period / 16);
1148
1149 for (i = 0; i < len * 8; i++) {
1150 bool slot_set = bitfield_is_set(base, i);
1151
1152 for (j = 0; j < dur_factor; j++) {
1153 u32 target_slot =
1154 start_slot + (i * dur_factor + j);
1155
1156 if (target_slot >= NAN_MAX_TIME_BITMAP_SLOTS)
1157 goto done;
1158
1159 if (slot_set)
1160 bitfield_set(bf, target_slot);
1161 }
1162 }
1163 }
1164
1165 done:
1166 bitfield_free(base);
1167
1168 wpa_printf(MSG_DEBUG, "NAN: Done converting bitmap");
1169
1170 return bf;
1171 }
1172
1173
1174 /**
1175 * nan_sched_to_bf - Convert schedule to bitfield
1176 * @nan: NAN module context from nan_init()
1177 * @sched: List of availability entries representing the schedule entries
1178 * @map_id: On return holds the map_id covered by the schedule entries
1179 * @reason: In case of failure contains the reason
1180 * Returns: A bitfield representing the schedule on success; otherwise NULL
1181 *
1182 * Note: The function only supports converting a schedule where all map IDs are
1183 * identical. There is no support for a schedule that uses different maps.
1184 */
nan_sched_to_bf(struct nan_data * nan,struct dl_list * sched,u8 * map_id,enum nan_reason * reason)1185 struct bitfield * nan_sched_to_bf(struct nan_data *nan, struct dl_list *sched,
1186 u8 *map_id, enum nan_reason *reason)
1187 {
1188 struct bitfield *sched_bf = NULL;
1189 struct nan_avail_entry *cur;
1190
1191 *map_id = NAN_INVALID_MAP_ID;
1192
1193 /* Convert all schedule availability entries to bf */
1194 dl_list_for_each(cur, sched, struct nan_avail_entry, list) {
1195 struct bitfield *tmp;
1196
1197 if (*map_id == NAN_INVALID_MAP_ID) {
1198 *map_id = cur->map_id;
1199 } else if (cur->map_id != *map_id) {
1200 wpa_printf(MSG_DEBUG,
1201 "NAN: No support for multiple maps");
1202 *reason = NAN_REASON_RESOURCE_LIMITATION;
1203 goto fail;
1204 }
1205
1206 tmp = nan_tbm_to_bf(nan, &cur->tbm);
1207 if (!tmp) {
1208 wpa_printf(MSG_DEBUG,
1209 "NAN: Failed to convert sched to bf");
1210 *reason = NAN_REASON_UNSPECIFIED_REASON;
1211 goto fail;
1212 }
1213
1214 bitfield_dump(tmp, "NAN: Schedule entry bitmap");
1215
1216 if (!sched_bf) {
1217 sched_bf = tmp;
1218 } else {
1219 int res;
1220
1221 if (bitfield_intersects(sched_bf, tmp)) {
1222 wpa_printf(MSG_DEBUG,
1223 "NAN: Invalid availability: TBMs intersect");
1224 *reason = NAN_REASON_INVALID_AVAILABILITY;
1225 bitfield_free(tmp);
1226 goto fail;
1227 }
1228
1229 res = bitfield_union_in_place(sched_bf, tmp);
1230 bitfield_free(tmp);
1231 if (res) {
1232 wpa_printf(MSG_DEBUG,
1233 "NAN: Failed to union sched bf");
1234 *reason = NAN_REASON_UNSPECIFIED_REASON;
1235 goto fail;
1236 }
1237 }
1238 }
1239
1240 return sched_bf;
1241
1242 fail:
1243 bitfield_free(sched_bf);
1244 *map_id = NAN_INVALID_MAP_ID;
1245 return NULL;
1246 }
1247
1248
1249 /**
1250 * nan_sched_covered_by_avail_entry - Check if schedule is covered by the
1251 * availability entry
1252 *
1253 * @nan: NAN module context from nan_init()
1254 * @avail: Availability entry
1255 * @sched_bf: A bitfield representing the schedule
1256 * @map_id: Map ID corresponding to the schedule
1257 * Returns true of schedule is covered by the entry; false otherwise
1258 */
nan_sched_covered_by_avail_entry(struct nan_data * nan,struct nan_avail_entry * avail,struct bitfield * sched_bf,u8 map_id)1259 bool nan_sched_covered_by_avail_entry(struct nan_data *nan,
1260 struct nan_avail_entry *avail,
1261 struct bitfield *sched_bf, u8 map_id)
1262 {
1263 struct bitfield *avail_bf = NULL;
1264 int ret;
1265
1266 /* No schedule entries, avail_entry is good.. */
1267 if (!sched_bf)
1268 return true;
1269
1270 wpa_printf(MSG_DEBUG,
1271 "NAN: Check if schedule covered by availability entry");
1272
1273 /* Schedule can only be covered by committed/conditional */
1274 if (avail->type != NAN_AVAIL_ENTRY_CTRL_TYPE_COMMITTED &&
1275 avail->type != NAN_AVAIL_ENTRY_CTRL_TYPE_COND)
1276 return false;
1277
1278 if (avail->map_id != map_id)
1279 return false;
1280
1281 /* Convert the availability entry to bf */
1282 avail_bf = nan_tbm_to_bf(nan, &avail->tbm);
1283 if (!avail_bf)
1284 return false;
1285
1286 bitfield_dump(avail_bf, "NAN: Availability entry bitmap");
1287
1288 ret = bitfield_is_subset(avail_bf, sched_bf);
1289 wpa_printf(MSG_DEBUG, "NAN: Is schedule subset of entry=%d", ret);
1290
1291 bitfield_free(avail_bf);
1292
1293 return ret == 1;
1294 }
1295
1296
1297 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)1298 nan_sched_bf_from_avail_and_chan(struct nan_data *nan,
1299 const struct dl_list *avail_entries,
1300 u8 map_id, u8 op_class, u16 cbm)
1301 {
1302 struct nan_avail_entry *avail;
1303 struct bitfield *res_bf = NULL;
1304
1305 dl_list_for_each(avail, avail_entries, struct nan_avail_entry,
1306 list) {
1307 struct bitfield *avail_bf;
1308
1309 if (avail->map_id != map_id)
1310 continue;
1311
1312 /* Schedule can only be covered by committed/conditional */
1313 if (avail->type != NAN_AVAIL_ENTRY_CTRL_TYPE_COMMITTED &&
1314 avail->type != NAN_AVAIL_ENTRY_CTRL_TYPE_COND)
1315 continue;
1316
1317 /* Now check channel, if it is given */
1318 if (op_class && cbm &&
1319 (avail->n_band_chan < 1 ||
1320 avail->band_chan_type != NAN_TYPE_CHANNEL ||
1321 avail->band_chan[0].u.chan.op_class != op_class ||
1322 !(avail->band_chan[0].u.chan.chan_bitmap & cbm)))
1323 continue;
1324
1325 /* Convert the availability entry to bitfield */
1326 avail_bf = nan_tbm_to_bf(nan, &avail->tbm);
1327 if (!avail_bf)
1328 goto fail;
1329
1330 bitfield_dump(avail_bf, "NAN: Availability entry bitmap");
1331 if (!res_bf) {
1332 res_bf = avail_bf;
1333 } else {
1334 struct bitfield *tmp_bf;
1335
1336 tmp_bf = bitfield_union(res_bf, avail_bf);
1337 bitfield_free(avail_bf);
1338
1339 if (!tmp_bf)
1340 goto fail;
1341
1342 bitfield_free(res_bf);
1343 res_bf = tmp_bf;
1344 }
1345 }
1346
1347 return res_bf;
1348
1349 fail:
1350 bitfield_free(res_bf);
1351 return NULL;
1352 }
1353
1354
1355 /**
1356 * nan_sched_covered_by_avail_entries - Check if schedule is covered by the
1357 * list of availability attributes
1358 *
1359 * @nan: NAN module context from nan_init()
1360 * @avail_entries: A list of availability entries (see &struct nan_avail_entry)
1361 * @sched: An array with 0 or more &struct nan_sched_entry entries
1362 * @sched_len: Length of the &sched array
1363 * Returns: true if schedule is covered by the entries; otherwise false.
1364 */
nan_sched_covered_by_avail_entries(struct nan_data * nan,struct dl_list * avail_entries,const u8 * sched,size_t sched_len)1365 bool nan_sched_covered_by_avail_entries(struct nan_data *nan,
1366 struct dl_list *avail_entries,
1367 const u8 *sched, size_t sched_len)
1368 {
1369 struct dl_list sched_entries;
1370 struct bitfield *sched_bf, *avail_bf;
1371 u8 map_id;
1372 bool ret = false;
1373 enum nan_reason reason;
1374
1375 if (!sched || !sched_len)
1376 return true;
1377
1378 dl_list_init(&sched_entries);
1379 if (nan_sched_entries_to_avail_entries(nan,
1380 &sched_entries,
1381 sched, sched_len))
1382 return false;
1383
1384 sched_bf = nan_sched_to_bf(nan, &sched_entries, &map_id, &reason);
1385 if (!sched_bf) {
1386 nan_flush_avail_entries(&sched_entries);
1387 return false;
1388 }
1389
1390 nan_flush_avail_entries(&sched_entries);
1391
1392 avail_bf = nan_sched_bf_from_avail_and_chan(nan, avail_entries,
1393 map_id, 0, 0);
1394 if (avail_bf)
1395 ret = bitfield_is_subset(avail_bf, sched_bf) ? true : false;
1396
1397 wpa_printf(MSG_DEBUG, "NAN: Schedule is %sa subset of entries",
1398 ret ? "" : "NOT ");
1399
1400 bitfield_free(avail_bf);
1401 bitfield_free(sched_bf);
1402
1403 return ret;
1404 }
1405
1406
1407 /**
1408 * nan_sched_bf_covered_by_avail_entries_and_chan - Check if schedule is covered
1409 * by the list of availability attributes matching the channel configurations
1410 *
1411 * @nan: NAN module context from nan_init()
1412 * @avail_entries: A list of availability entries. See &struct nan_avail_entry
1413 * @sched_bf: the bitfield representing the schedule
1414 * @map_id: Map ID associated with the schedule
1415 * @op_class: Operating class to match against
1416 * @cbm: Channel bitmap to match against
1417 * Returns: true of schedule is covered by the entries; otherwise false
1418 */
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)1419 bool nan_sched_bf_covered_by_avail_entries_and_chan(
1420 struct nan_data *nan, const struct dl_list *avail_entries,
1421 struct bitfield *sched_bf, u8 map_id, u8 op_class, u16 cbm)
1422 {
1423 struct bitfield *avail_bf;
1424 bool ret = false;
1425
1426 /*
1427 * Build a schedule bitfield from all the availability entries matching
1428 * the map ID and channel configuration.
1429 */
1430 avail_bf = nan_sched_bf_from_avail_and_chan(nan, avail_entries,
1431 map_id, op_class, cbm);
1432
1433 /*
1434 * If there is such a schedule, verify that it is a superset of the
1435 * given schedule.
1436 */
1437 if (avail_bf && bitfield_is_subset(avail_bf, sched_bf))
1438 ret = true;
1439
1440 wpa_printf(MSG_DEBUG,
1441 "NAN: Is schedule covered by entries and chan=%u", ret);
1442
1443 bitfield_free(avail_bf);
1444 return ret;
1445 }
1446
1447
nan_get_control_channel(struct nan_data * nan,u8 op_class,u16 cbm,u16 pri_cbm)1448 static int nan_get_control_channel(struct nan_data *nan, u8 op_class,
1449 u16 cbm, u16 pri_cbm)
1450 {
1451 const struct oper_class_map *op = get_oper_class(NULL, op_class);
1452 int freq = 0, idx;
1453 u8 chan_id;
1454
1455 if (!op || op_class > 130)
1456 return -1;
1457
1458 idx = ffs(cbm) - 1;
1459 if (idx < 0) {
1460 wpa_printf(MSG_DEBUG,
1461 "NAN: No channel found in chan_bitmap 0x%04x for oper_class %u",
1462 cbm, op_class);
1463 return -1;
1464 }
1465
1466 chan_id = op_class_idx_to_chan(op, idx);
1467 if (!chan_id) {
1468 wpa_printf(MSG_DEBUG,
1469 "NAN: No channel found for oper_class %u idx %u",
1470 op_class, idx);
1471 return -1;
1472 }
1473
1474 freq = ieee80211_chan_to_freq(NULL, op_class, chan_id);
1475
1476 /*
1477 * For operating classes with bandwidth < 80 MHz, the frequency is the
1478 * control channel frequency. For operating classes with
1479 * bandwidth >= 80 MHz, the frequency is the center frequency of the
1480 * primary segment, so we need to derive the control channel frequency
1481 * from the primary channel bitmap.
1482 */
1483 if (op->bw == BW20 || op->bw == BW40 ||
1484 op->bw == BW40PLUS || op->bw == BW40MINUS)
1485 return freq;
1486
1487 if (!pri_cbm) {
1488 wpa_printf(MSG_DEBUG,
1489 "NAN: No primary channel bitmap provided for oper_class %u",
1490 op_class);
1491 return -1;
1492 }
1493
1494 idx = ffs(pri_cbm) - 1;
1495
1496 if (op->bw == BW80 || op->bw == BW80P80)
1497 return freq - 30 + idx * 20;
1498
1499 if (op->bw == BW160)
1500 return freq - 70 + idx * 20;
1501
1502 return -1;
1503 }
1504
1505
1506 /**
1507 * nan_avail_entries_to_bf - Convert availability entries that match the given
1508 * channel configuration to a bitfield.
1509 *
1510 * @nan: NAN module context from nan_init()
1511 * @avail_entries: A list of availability entries. See &struct nan_avail_entry
1512 * @op_class: Operating class to match against
1513 * @cbm: Channel bitmap to match against
1514 * @pri_cbm: Primary channel bitmap to match against
1515 * Returns: NULL on error or no match; otherwise returns a bitfield describing
1516 * all the available slots.
1517 */
nan_avail_entries_to_bf(struct nan_data * nan,const struct dl_list * avail_entries,u8 op_class,u16 cbm,u16 pri_cbm)1518 struct bitfield * nan_avail_entries_to_bf(struct nan_data *nan,
1519 const struct dl_list *avail_entries,
1520 u8 op_class, u16 cbm, u16 pri_cbm)
1521 {
1522 struct nan_avail_entry *avail;
1523 struct bitfield *res_bf = NULL;
1524
1525 dl_list_for_each(avail, avail_entries, struct nan_avail_entry,
1526 list) {
1527 struct bitfield *avail_bf;
1528
1529 /* Schedule can only be covered by committed/conditional. */
1530 if (avail->type != NAN_AVAIL_ENTRY_CTRL_TYPE_COMMITTED &&
1531 avail->type != NAN_AVAIL_ENTRY_CTRL_TYPE_COND)
1532 continue;
1533
1534 /*
1535 * Committed/conditional entries should have only a single
1536 * channel entry.
1537 */
1538 if (avail->n_band_chan != 1 ||
1539 avail->band_chan_type != NAN_TYPE_CHANNEL)
1540 continue;
1541
1542 /*
1543 * Check that the availability entry channel matches. If it does
1544 * not match, check if the channels are compatible, i.e., have
1545 * the same control channel.
1546 */
1547 if (avail->band_chan[0].u.chan.op_class != op_class ||
1548 avail->band_chan[0].u.chan.chan_bitmap != cbm ||
1549 avail->band_chan[0].u.chan.pri_chan_bitmap != pri_cbm) {
1550 int freq1, freq2;
1551 u16 chan_bitmap, pri_chan_bitmap;
1552
1553 freq1 = nan_get_control_channel(nan, op_class,
1554 cbm, pri_cbm);
1555
1556 chan_bitmap = le_to_host16(
1557 avail->band_chan[0].u.chan.chan_bitmap);
1558 pri_chan_bitmap = le_to_host16(
1559 avail->band_chan[0].u.chan.pri_chan_bitmap);
1560 freq2 = nan_get_control_channel(
1561 nan, avail->band_chan[0].u.chan.op_class,
1562 chan_bitmap, pri_chan_bitmap);
1563
1564 if (freq2 == -1 || freq1 != freq2)
1565 continue;
1566
1567 wpa_printf(MSG_DEBUG,
1568 "NAN: Availability entry channel is compatible. Control channel freq=%d MHz",
1569 freq1);
1570 }
1571
1572 /* Convert the availability entry to a bitfield */
1573 avail_bf = nan_tbm_to_bf(nan, &avail->tbm);
1574 if (!avail_bf)
1575 goto fail;
1576
1577 if (!res_bf) {
1578 res_bf = avail_bf;
1579 } else {
1580 struct bitfield *tmp_bf;
1581
1582 tmp_bf = bitfield_union(res_bf, avail_bf);
1583 if (!tmp_bf)
1584 goto fail;
1585
1586 bitfield_free(res_bf);
1587 bitfield_free(avail_bf);
1588 res_bf = tmp_bf;
1589 }
1590 }
1591
1592 return res_bf;
1593
1594 fail:
1595 bitfield_free(res_bf);
1596 return NULL;
1597 }
1598
1599
1600 /**
1601 * nan_peer_dump_sched_to_buf - Dump peer schedule to a buffer
1602 * @sched: Peer schedule
1603 * @buf: Output buffer
1604 * @buflen: The length of &buf in bytes
1605 *
1606 * Returns: The number of characters written to the buffer, or -1 on error,
1607 * which indicates that the buffer was too small.
1608 */
nan_peer_dump_sched_to_buf(struct nan_peer_schedule * sched,char * buf,size_t buflen)1609 int nan_peer_dump_sched_to_buf(struct nan_peer_schedule *sched,
1610 char *buf, size_t buflen)
1611 {
1612 int i, j, ret;
1613 char *pos = buf;
1614 char *end = buf + buflen;
1615
1616 for (i = 0; i < sched->n_maps; i++) {
1617 struct nan_map *map = &sched->maps[i];
1618
1619 ret = wpa_scnprintf(pos, end - pos,
1620 "MAP [%u]\n\tmap_id=%u\n\tn_chans=%u\n",
1621 i, map->map_id, map->n_chans);
1622 if (os_snprintf_error(end - pos, ret))
1623 goto err;
1624 pos += ret;
1625
1626 for (j = 0; j < map->n_chans; j++) {
1627 struct nan_map_chan *chan = &map->chans[j];
1628
1629 ret = wpa_scnprintf(pos, end - pos,
1630 "\tchannel[%u]: committed=%u rx_nss=%u freq=%u bw=%u cfreq1=%u cfreq2=%u\n",
1631 j, chan->committed, chan->rx_nss,
1632 chan->chan.freq,
1633 chan->chan.bandwidth,
1634 chan->chan.center_freq1,
1635 chan->chan.center_freq2);
1636 if (os_snprintf_error(end - pos, ret))
1637 goto err;
1638 pos += ret;
1639
1640 ret = wpa_scnprintf(pos, end - pos,
1641 "\t\tbitmap: period=%u duration=%u offset=%u ",
1642 BIT(6 + chan->tbm.period),
1643 BIT(4 + chan->tbm.duration),
1644 16 * chan->tbm.offset);
1645 if (os_snprintf_error(end - pos, ret))
1646 goto err;
1647 pos += ret;
1648
1649 ret = wpa_scnprintf(pos, end - pos, "bitmap=");
1650 if (os_snprintf_error(end - pos, ret))
1651 goto err;
1652 pos += ret;
1653
1654 ret = wpa_snprintf_hex(pos, end - pos, chan->tbm.bitmap,
1655 chan->tbm.len);
1656 if (os_snprintf_error(end - pos, ret))
1657 goto err;
1658 pos += ret;
1659
1660 ret = wpa_scnprintf(pos, end - pos, "\n");
1661 if (os_snprintf_error(end - pos, ret))
1662 goto err;
1663 pos += ret;
1664 }
1665
1666 ret = wpa_scnprintf(pos, end - pos,
1667 "\tndc: period=%u duration=%u offset=%u bitmap=",
1668 BIT(6 + map->ndc.period),
1669 BIT(4 + map->ndc.duration),
1670 16 * map->ndc.offset);
1671 if (os_snprintf_error(end - pos, ret))
1672 goto err;
1673 pos += ret;
1674
1675 ret = wpa_snprintf_hex(pos, end - pos, map->ndc.bitmap,
1676 map->ndc.len);
1677 if (os_snprintf_error(end - pos, ret))
1678 goto err;
1679 pos += ret;
1680
1681 ret = wpa_scnprintf(pos, end - pos,
1682 "\n\timmutable: period=%u duration=%u offset=%u bitmap=",
1683 1 << (6 + map->immutable.period),
1684 1 << (4 + map->immutable.duration),
1685 16 * map->immutable.offset);
1686 if (os_snprintf_error(end - pos, ret))
1687 goto err;
1688 pos += ret;
1689
1690 ret = wpa_snprintf_hex(pos, end - pos, map->immutable.bitmap,
1691 map->immutable.len);
1692 if (os_snprintf_error(end - pos, ret))
1693 goto err;
1694 pos += ret;
1695
1696 ret = wpa_scnprintf(pos, end - pos, "\n");
1697 if (os_snprintf_error(end - pos, ret))
1698 goto err;
1699 pos += ret;
1700 }
1701
1702 ret = wpa_scnprintf(pos, end - pos, "max_idle_period=%u",
1703 sched->max_idle_period);
1704
1705 if (os_snprintf_error(end - pos, ret))
1706 goto err;
1707
1708 pos += ret;
1709
1710 return pos - buf;
1711
1712 err:
1713 wpa_printf(MSG_DEBUG, "NAN: Buffer too small to dump peer schedule");
1714 return -1;
1715 }
1716
1717
1718 /**
1719 * nan_peer_dump_pot_avail_to_buf - Dump peer potential availability to a text
1720 * buffer
1721 *
1722 * @pot_avail: Peer potential availability
1723 * @buf: Output buffer
1724 * @buflen: Length of &buf in bytes
1725 *
1726 * Returns: The number of characters written to the buffer, or -1 on error,
1727 * which indicates that the buffer was too small.
1728 */
nan_peer_dump_pot_avail_to_buf(struct nan_peer_potential_avail * pot_avail,char * buf,size_t buflen)1729 int nan_peer_dump_pot_avail_to_buf(struct nan_peer_potential_avail *pot_avail,
1730 char *buf, size_t buflen)
1731 {
1732 unsigned int i, j;
1733 int ret;
1734 char *pos = buf;
1735 char *end = buf + buflen;
1736
1737 for (i = 0; i < pot_avail->n_maps; i++) {
1738 struct pot_entry *pot = &pot_avail->maps[i];
1739
1740 ret = wpa_scnprintf(pos, end - pos,
1741 "entry[%u]: rx_nss=%u pref=%u util=%u\n",
1742 i, pot->rx_nss, pot->preference,
1743 pot->utilization);
1744 if (os_snprintf_error(end - pos, ret))
1745 goto err;
1746 pos += ret;
1747
1748 for (j = 0; j < pot->n_band_chan; j++) {
1749 if (pot->is_band) {
1750 ret = wpa_scnprintf(pos, end - pos,
1751 "\tband[%u]: band_id=%u\n",
1752 j, pot->entries[j].band_id);
1753 } else {
1754 ret = wpa_scnprintf(
1755 pos, end - pos,
1756 "\tchan[%u]: op_class=%u chan_bitmap=0x%04x\n",
1757 j, pot->entries[j].op_class,
1758 pot->entries[j].chan_bitmap);
1759 }
1760 if (os_snprintf_error(end - pos, ret))
1761 goto err;
1762 pos += ret;
1763 }
1764 }
1765
1766 return pos - buf;
1767
1768 err:
1769 wpa_printf(MSG_DEBUG,
1770 "NAN: Buffer too small to dump peer potential availability");
1771 return -1;
1772 }
1773
1774
1775 /**
1776 * nan_get_peer_ndc_freq - Get peer NDC frequency from schedule
1777 * @nan: Pointer to NAN data struct
1778 * @peer_sched: Pointer to peer schedule struct
1779 * @map_idx: Index of the availability map to check
1780 * Returns: Frequency of the peer channel that intersects with NDC,
1781 * or -1 on failure or if no intersection found
1782 *
1783 * In case NDC bitmap spans across multiple channels, only one channel is
1784 * returned (that corresponds to the first NDC bit).
1785 */
nan_get_peer_ndc_freq(struct nan_data * nan,const struct nan_peer_schedule * peer_sched,u8 map_idx)1786 int nan_get_peer_ndc_freq(struct nan_data *nan,
1787 const struct nan_peer_schedule *peer_sched,
1788 u8 map_idx)
1789 {
1790 struct bitfield *ndc_bf;
1791 int i;
1792
1793 if (map_idx >= peer_sched->n_maps) {
1794 wpa_printf(MSG_DEBUG,
1795 "NAN: Invalid map index %u for peer schedule",
1796 map_idx);
1797 return -1;
1798 }
1799
1800 ndc_bf = nan_tbm_to_bf(nan, &peer_sched->maps[map_idx].ndc);
1801 if (!ndc_bf)
1802 return -1;
1803
1804 for (i = 0; i < peer_sched->maps[map_idx].n_chans; i++) {
1805 struct bitfield *peer_chan_map;
1806
1807 /*
1808 * Check all peer channel entries (committed or conditional).
1809 * Potential entries are not part of the peer schedule.
1810 */
1811 peer_chan_map =
1812 nan_tbm_to_bf(nan,
1813 &peer_sched->maps[map_idx].chans[i].tbm);
1814 if (!peer_chan_map) {
1815 wpa_printf(MSG_DEBUG,
1816 "NAN: Failed to convert peer channel TBM to bitfield");
1817 bitfield_free(ndc_bf);
1818 return -1;
1819 }
1820
1821 if (bitfield_intersects(ndc_bf, peer_chan_map)) {
1822 bitfield_free(ndc_bf);
1823 bitfield_free(peer_chan_map);
1824 return peer_sched->maps[map_idx].chans[i].chan.freq;
1825 }
1826
1827 bitfield_free(peer_chan_map);
1828 }
1829
1830 bitfield_free(ndc_bf);
1831 return -1;
1832 }
1833
1834
1835 /**
1836 * nan_get_chan_entry - Get channel entry for a given NAN scheduled channel
1837 * @nan: NAN module context from nan_init()
1838 * @chan: NAN scheduled channel
1839 * @chan_entry: On successful return holds the channel entry.
1840 * Returns: 0 on success; otherwise -1
1841 */
nan_get_chan_entry(struct nan_data * nan,const struct nan_sched_chan * chan,struct nan_chan_entry * chan_entry)1842 int nan_get_chan_entry(struct nan_data *nan, const struct nan_sched_chan *chan,
1843 struct nan_chan_entry *chan_entry)
1844 {
1845 u8 op_class;
1846 u16 chan_bm, pri_chan_bm;
1847 int ret;
1848
1849 if (!chan || !chan_entry)
1850 return -1;
1851
1852 ret = nan_get_chan_bm(nan, chan, &op_class, &chan_bm, &pri_chan_bm);
1853 if (ret)
1854 return ret;
1855
1856 os_memset(chan_entry, 0, sizeof(*chan_entry));
1857 chan_entry->op_class = op_class;
1858 chan_entry->chan_bitmap = host_to_le16(chan_bm);
1859 chan_entry->pri_chan_bitmap = pri_chan_bm & 0xff;
1860
1861 return 0;
1862 }
1863
1864
1865 /**
1866 * nan_convert_chan_sched_to_bf - Convert channel schedule to bitfield
1867 * and get the channel information.
1868 *
1869 * @nan: NAN module context from nan_init()
1870 * @chan: Channel schedule to convert
1871 * @avail_bf: On successful return holds the availability bitmap of the given
1872 * channel schedule
1873 * @map_id: On successful return holds the map ID for the schedule
1874 * @op_class: On successful return holds the operating class for the schedule
1875 * with the peer
1876 * @cbm: On successful return holds the channel bitmap for the operating class
1877 * @pcbm: On successful return holds the primary channel bitmap for the
1878 * channel in case of bandwidth greater than 40 MHz
1879 * Returns: 0 on success; -1 on failure
1880 */
nan_convert_chan_sched_to_bf(struct nan_data * nan,const struct nan_chan_schedule * chan,struct bitfield ** avail_bf,u8 * map_id,u8 * op_class,u16 * cbm,u16 * pcbm)1881 int nan_convert_chan_sched_to_bf(struct nan_data *nan,
1882 const struct nan_chan_schedule *chan,
1883 struct bitfield **avail_bf, u8 *map_id,
1884 u8 *op_class, u16 *cbm, u16 *pcbm)
1885 {
1886 struct bitfield *committed_bf, *conditional_bf;
1887 int ret;
1888
1889 *op_class = 0;
1890 *cbm = 0;
1891 *pcbm = 0;
1892 *map_id = chan->map_id;
1893
1894 ret = nan_get_chan_bm(nan, &chan->chan, op_class, cbm, pcbm);
1895 if (ret) {
1896 wpa_printf(MSG_DEBUG,
1897 "NAN: NDL: Failed to convert channel info");
1898 return -1;
1899 }
1900
1901 committed_bf = nan_tbm_to_bf(nan, &chan->committed);
1902 if (!committed_bf) {
1903 wpa_printf(MSG_DEBUG,
1904 "NAN: NDL: Failed to build committed bitfield");
1905 return -1;
1906 }
1907
1908 conditional_bf = nan_tbm_to_bf(nan, &chan->conditional);
1909 if (!conditional_bf) {
1910 wpa_printf(MSG_DEBUG,
1911 "NAN: NDL: Failed to build conditional bitfield");
1912 bitfield_free(committed_bf);
1913 return -1;
1914 }
1915
1916 *avail_bf = bitfield_union(committed_bf, conditional_bf);
1917 bitfield_free(committed_bf);
1918 bitfield_free(conditional_bf);
1919
1920 if (!*avail_bf) {
1921 wpa_printf(MSG_DEBUG,
1922 "NAN: NDL: Failed to unify committed and conditional bitfields");
1923 return -1;
1924 }
1925
1926 wpa_printf(MSG_DEBUG, "NAN: NDL: map_id=%u, op_class=%u, cbm=0x%x",
1927 *map_id, *op_class, *cbm);
1928 return 0;
1929 }
1930
1931
1932 /**
1933 * nan_peer_schedule_intersection - Get local and peer schedules intersection
1934 * @nan: NAN module context from nan_init()
1935 * @peer: The peer with whom to intersect the schedule
1936 * @sched: Local device schedule
1937 * Returns: A bitfield representing the intersection of schedules, or NULL if
1938 * no intersection
1939 *
1940 * The function checks if the local device schedule intersects with the peer
1941 * device schedule and returns a bitfield representing the intersection, or
1942 * NULL if no intersection.
1943 */
nan_peer_schedule_intersection(struct nan_data * nan,const struct nan_peer * peer,const struct nan_schedule * sched)1944 struct bitfield * nan_peer_schedule_intersection(
1945 struct nan_data *nan, const struct nan_peer *peer,
1946 const struct nan_schedule *sched)
1947 {
1948 size_t i;
1949 struct bitfield *common_bf = NULL;
1950 bool intersects = false;
1951
1952 /*
1953 * Iterate over all the channels included in the local schedule. For
1954 * each channel convert the committed and conditional slots to a
1955 * bitfield object and extract the operating class and channel bitmap.
1956 *
1957 * Using the operating class and channel bitmap find the peer
1958 * availability on that channel and check if it intersect with the
1959 * local one.
1960 */
1961 wpa_printf(MSG_DEBUG, "NAN: n_chans=%u, ndc_map_id=%u",
1962 sched->n_chans, sched->ndc_map_id);
1963
1964 for (i = 0; i < sched->n_chans; i++) {
1965 struct bitfield *own_chan_bf = NULL, *peer_chan_bf = NULL;
1966 u16 cbm, pri_cbm;
1967 u8 map_id, op_class;
1968 int ret;
1969
1970 /* Convert the schedule for the current channel to bitfield */
1971 ret = nan_convert_chan_sched_to_bf(nan, &sched->chans[i],
1972 &own_chan_bf, &map_id,
1973 &op_class, &cbm, &pri_cbm);
1974 if (ret) {
1975 wpa_printf(MSG_DEBUG,
1976 "NAN: NDL: Failed to convert chan sched to bitfield");
1977 return NULL;
1978 }
1979
1980 /* Get the peer availability for the current channel */
1981 peer_chan_bf =
1982 nan_avail_entries_to_bf(nan,
1983 &peer->info.avail_entries,
1984 op_class, cbm, pri_cbm);
1985 if (!peer_chan_bf) {
1986 bitfield_free(own_chan_bf);
1987 continue;
1988 }
1989
1990 intersects |= bitfield_intersects(own_chan_bf, peer_chan_bf);
1991
1992 ret = bitfield_intersect_in_place(own_chan_bf, peer_chan_bf);
1993 if (ret < 0) {
1994 wpa_printf(MSG_DEBUG,
1995 "NAN: Failed to intersect own and peer chan bitfields");
1996 bitfield_free(own_chan_bf);
1997 bitfield_free(peer_chan_bf);
1998 bitfield_free(common_bf);
1999 return NULL;
2000 }
2001
2002 bitfield_free(peer_chan_bf);
2003
2004 if (common_bf) {
2005 ret = bitfield_union_in_place(common_bf, own_chan_bf);
2006 if (ret) {
2007 wpa_printf(MSG_DEBUG,
2008 "NAN: Failed to unify own chan bitfields");
2009
2010 bitfield_free(own_chan_bf);
2011 bitfield_free(common_bf);
2012 return NULL;
2013 }
2014 } else {
2015 common_bf = bitfield_dup(own_chan_bf);
2016 if (!common_bf) {
2017 wpa_printf(MSG_DEBUG,
2018 "NAN: Failed to dup own chan bitfield");
2019
2020 bitfield_free(own_chan_bf);
2021 bitfield_free(common_bf);
2022 return NULL;
2023 }
2024 }
2025
2026 bitfield_free(own_chan_bf);
2027 }
2028
2029 if (!intersects) {
2030 bitfield_free(common_bf);
2031 return NULL;
2032 }
2033
2034 return common_bf;
2035 }
2036
2037
nan_add_kde_hdr(struct wpabuf * buf,u32 kde,size_t data_len)2038 void nan_add_kde_hdr(struct wpabuf *buf, u32 kde, size_t data_len)
2039 {
2040 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
2041 wpabuf_put_u8(buf, RSN_SELECTOR_LEN + data_len);
2042 RSN_SELECTOR_PUT(wpabuf_put(buf, RSN_SELECTOR_LEN), kde);
2043 }
2044