xref: /freebsd/contrib/wpa/src/nan/nan_util.c (revision 71e72c9e91c4b8007a4292e09669e8b549c29e97)
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