xref: /freebsd/contrib/wpa/src/nan/nan_bootstrap.c (revision 71e72c9e91c4b8007a4292e09669e8b549c29e97)
1 /*
2  * Wi-Fi Aware - NAN Bootstrap
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/eloop.h"
12 #include "nan_i.h"
13 
14 #define NAN_BOOTSTRAP_RETRY_TIMEOUT_US (1 * 1000 * 1000) /* 1 second */
15 #define NAN_BOOTSTRAP_COOKIE_LEN 4
16 
17 static void nan_bootstrap_timeout(void *eloop_data, void *user_ctx);
18 
19 
20 /**
21  * nan_complement_pbm - Get complement pairing bootstrapping method
22  * @pbm: Pairing bootstrapping method
23  * Returns: Complement pairing bootstrapping method
24  */
nan_complement_pbm(u16 pbm)25 static u16 nan_complement_pbm(u16 pbm)
26 {
27 	if (pbm == NAN_PBA_METHOD_OPPORTUNISTIC)
28 		return NAN_PBA_METHOD_OPPORTUNISTIC;
29 	if (pbm == NAN_PBA_METHOD_PIN_DISPLAY)
30 		return NAN_PBA_METHOD_PIN_KEYPAD;
31 	if (pbm == NAN_PBA_METHOD_PASSPHRASE_DISPLAY)
32 		return NAN_PBA_METHOD_PASSPHRASE_KEYPAD;
33 	if (pbm == NAN_PBA_METHOD_QR_DISPLAY)
34 		return NAN_PBA_METHOD_QR_SCAN;
35 	if (pbm == NAN_PBA_METHOD_NFC_TAG)
36 		return NAN_PBA_METHOD_NFC_READER;
37 	if (pbm == NAN_PBA_METHOD_PIN_KEYPAD)
38 		return NAN_PBA_METHOD_PIN_DISPLAY;
39 	if (pbm == NAN_PBA_METHOD_PASSPHRASE_KEYPAD)
40 		return NAN_PBA_METHOD_PASSPHRASE_DISPLAY;
41 	if (pbm == NAN_PBA_METHOD_QR_SCAN)
42 		return NAN_PBA_METHOD_QR_DISPLAY;
43 	if (pbm == NAN_PBA_METHOD_NFC_READER)
44 		return NAN_PBA_METHOD_NFC_TAG;
45 	if (pbm == NAN_PBA_METHOD_SERVICE_MANAGED)
46 		return NAN_PBA_METHOD_SERVICE_MANAGED;
47 	if (pbm == NAN_PBA_METHOD_HANDSHAKE_SKIPPED)
48 		return NAN_PBA_METHOD_HANDSHAKE_SKIPPED;
49 
50 	return 0;
51 }
52 
53 
54 /**
55  * nan_bootstrap_reset - Reset bootstrap state
56  * @nan: NAN module context from nan_init()
57  * @peer: Peer to reset bootstrap state
58  */
nan_bootstrap_reset(struct nan_data * nan,struct nan_peer * peer)59 void nan_bootstrap_reset(struct nan_data *nan, struct nan_peer *peer)
60 {
61 	wpa_printf(MSG_DEBUG, "NAN: Bootstrap: Reset state");
62 
63 	eloop_cancel_timeout(nan_bootstrap_timeout, nan, peer);
64 	os_free(peer->bootstrap.cookie);
65 
66 	/*
67 	 * Do not use memset to reset all data to preserve the peer's
68 	 * supported bootstrap methods and the NPBA buffer if present.
69 	 */
70 	peer->bootstrap.cookie = NULL;
71 	peer->bootstrap.cookie_len = 0;
72 	peer->bootstrap.initiator = false;
73 	peer->bootstrap.dialog_token = 0;
74 	peer->bootstrap.requested_pbm = 0;
75 	peer->bootstrap.authorized = 0;
76 	peer->bootstrap.status = 0;
77 	peer->bootstrap.comeback_required = false;
78 	peer->bootstrap.in_progress = false;
79 	peer->bootstrap.reason_code = 0;
80 	peer->bootstrap.handle = -1;
81 	peer->bootstrap.req_instance_id = 0;
82 }
83 
84 
85 /**
86  * nan_bootstrap_build_npba - Build NAN Pairing Bootstrap attribute
87  * @nan: NAN module context from nan_init()
88  * @peer: Peer for which to build the attribute
89  * Returns: The constructed NPBA or %NULL on failure
90  */
nan_bootstrap_build_npba(struct nan_data * nan,struct nan_peer * peer)91 static struct wpabuf * nan_bootstrap_build_npba(struct nan_data *nan,
92 						struct nan_peer *peer)
93 {
94 	struct wpabuf *buf;
95 	u16 pbm = peer->bootstrap.requested_pbm;
96 	u8 type_and_status;
97 	u8 *len;
98 
99 	/*
100 	 * Allocate max possible size: header (3) + Dialog Token (1) + Type and
101 	 * Status (1) + Reason (1) + Comeback (2 + 1 + Comeback Token) + pbm (2)
102 	 */
103 	buf = wpabuf_alloc(11 + peer->bootstrap.cookie_len);
104 	if (!buf)
105 		return NULL;
106 
107 	wpa_printf(MSG_DEBUG, "NAN: Bootstrap: Build NPBA");
108 
109 	if (peer->bootstrap.initiator) {
110 		type_and_status = NAN_PBA_TYPE_RESPONSE;
111 		if (peer->bootstrap.status)
112 			pbm = 0;
113 	} else {
114 		type_and_status = NAN_PBA_TYPE_REQUEST;
115 	}
116 
117 	type_and_status |= peer->bootstrap.status << NAN_PBA_STATUS_POS;
118 
119 	wpabuf_put_u8(buf, NAN_ATTR_NPBA);
120 	len = wpabuf_put(buf, 2);
121 
122 	wpabuf_put_u8(buf, peer->bootstrap.dialog_token);
123 	wpabuf_put_u8(buf, type_and_status);
124 	wpabuf_put_u8(buf, peer->bootstrap.reason_code);
125 
126 	if (peer->bootstrap.status == NAN_PBA_STATUS_COMEBACK) {
127 		if (peer->bootstrap.initiator)
128 			wpabuf_put_le16(buf, peer->bootstrap.comeback_after);
129 
130 		wpabuf_put_u8(buf, peer->bootstrap.cookie_len);
131 		if (peer->bootstrap.cookie)
132 			wpabuf_put_data(buf, peer->bootstrap.cookie,
133 					peer->bootstrap.cookie_len);
134 	}
135 
136 	wpabuf_put_le16(buf, pbm);
137 	WPA_PUT_LE16(len, wpabuf_len(buf) - 3);
138 
139 	return buf;
140 }
141 
142 
143 /**
144  * nan_bootstrap_timeout - Bootstrap timeout handler
145  * @eloop_data: NAN module context from nan_init()
146  * @user_ctx: Peer for which the timeout occurred
147  */
nan_bootstrap_timeout(void * eloop_data,void * user_ctx)148 static void nan_bootstrap_timeout(void *eloop_data, void *user_ctx)
149 {
150 	struct nan_data *nan = eloop_data;
151 	struct nan_peer *peer = user_ctx;
152 	struct wpabuf *attr;
153 
154 	wpa_printf(MSG_DEBUG, "NAN: Bootstrap: timeout. status=%u",
155 		   peer->bootstrap.status);
156 
157 	attr = nan_bootstrap_build_npba(nan, peer);
158 	if (!attr) {
159 		wpa_printf(MSG_DEBUG,
160 			   "NAN: Bootstrap: Failed to build attribute");
161 
162 		nan_bootstrap_reset(nan, peer);
163 
164 		nan->cfg->bootstrap_completed(nan->cfg->cb_ctx, peer->nmi_addr,
165 					      0, false,
166 					      NAN_REASON_UNSPECIFIED_REASON,
167 					      -1, 0);
168 		return;
169 	}
170 
171 	if (nan->cfg->transmit_followup(nan->cfg->cb_ctx, peer->nmi_addr, attr,
172 					peer->bootstrap.handle,
173 					peer->bootstrap.req_instance_id)) {
174 		wpa_printf(MSG_DEBUG,
175 			   "NAN: Bootstrap: Failed to transmit followup");
176 
177 		nan_bootstrap_reset(nan, peer);
178 
179 		nan->cfg->bootstrap_completed(nan->cfg->cb_ctx, peer->nmi_addr,
180 					      0, false,
181 					      NAN_REASON_UNSPECIFIED_REASON,
182 					      peer->bootstrap.handle,
183 					      peer->bootstrap.req_instance_id);
184 	}
185 
186 	wpabuf_free(attr);
187 
188 	/* If the peer didn't reply, try again */
189 	if (peer->bootstrap.status != NAN_PBA_STATUS_COMEBACK)
190 		eloop_register_timeout(0, NAN_BOOTSTRAP_RETRY_TIMEOUT_US,
191 				       nan_bootstrap_timeout, nan, peer);
192 }
193 
194 
195 /**
196  * nan_bootstrap_handle_rx_request - Process received bootstrap request
197  * @nan: NAN module context from nan_init()
198  * @peer: Peer from which the request was received
199  * @dialog_token: Dialog token from the request
200  * @pbm: Pairing bootstrapping method bitmap from the request
201  * @cookie: Comeback cookie from the request (if any)
202  * @cookie_len: Length of the comeback cookie
203  * @status: Status field from the request
204  * @handle: Follow-up handle
205  * @req_instance_id: Follow-up instance ID
206  * @npba: NPBA from the request
207  * @npba_len: Length of the NPBA
208  */
nan_bootstrap_handle_rx_request(struct nan_data * nan,struct nan_peer * peer,u8 dialog_token,u16 pbm,const u8 * cookie,u8 cookie_len,u8 status,int handle,u8 req_instance_id,const u8 * npba,u16 npba_len)209 static void nan_bootstrap_handle_rx_request(struct nan_data *nan,
210 					    struct nan_peer *peer,
211 					    u8 dialog_token, u16 pbm,
212 					    const u8 *cookie,
213 					    u8 cookie_len, u8 status,
214 					    int handle, u8 req_instance_id,
215 					    const u8 *npba, u16 npba_len)
216 {
217 	struct wpabuf *attr = NULL;
218 	u16 supported_methods;
219 
220 	wpa_printf(MSG_DEBUG, "NAN: Bootstrap: RX request");
221 
222 	if (peer->bootstrap.initiator && peer->bootstrap.comeback_required) {
223 		if (status != NAN_PBA_STATUS_COMEBACK) {
224 			wpa_printf(MSG_DEBUG,
225 				   "NAN: Bootstrap: Missing comeback cookie. Ignore");
226 			return;
227 		}
228 
229 		if (cookie_len != peer->bootstrap.cookie_len ||
230 		    !!cookie ^ !!peer->bootstrap.cookie ||
231 		    (cookie && os_memcmp(cookie, peer->bootstrap.cookie,
232 					 cookie_len) != 0)) {
233 			wpa_printf(MSG_DEBUG,
234 				   "NAN: Bootstrap: Invalid comeback cookie. Ignore");
235 			return;
236 		}
237 
238 		if (dialog_token != peer->bootstrap.dialog_token) {
239 			wpa_printf(MSG_DEBUG,
240 				   "NAN: Bootstrap: Invalid dialog token. Ignore");
241 			return;
242 		}
243 
244 		if (handle != peer->bootstrap.handle ||
245 		    req_instance_id != peer->bootstrap.req_instance_id) {
246 			wpa_printf(MSG_DEBUG,
247 				   "NAN: Bootstrap: Invalid handle or instance ID");
248 			return;
249 		}
250 
251 		wpa_printf(MSG_DEBUG,
252 			   "NAN: Bootstrap: Valid comeback request(pbm=0x%04x) authorized=0x%04x",
253 			   pbm, peer->bootstrap.authorized);
254 
255 		if (peer->bootstrap.authorized == nan_complement_pbm(pbm)) {
256 			wpa_printf(MSG_DEBUG,
257 				   "NAN: Bootstrap: Peer bootstrap authorized. Accept.");
258 
259 			peer->bootstrap.status = NAN_PBA_STATUS_ACCEPTED;
260 			peer->bootstrap.reason_code = 0;
261 			peer->bootstrap.comeback_required = false;
262 			peer->bootstrap.requested_pbm = nan_complement_pbm(pbm);
263 		}
264 
265 		goto send_response;
266 	}
267 
268 	wpa_printf(MSG_DEBUG,
269 		   "NAN: Bootstrap: New bootstrap request. pbm=0x%04x", pbm);
270 
271 	nan_bootstrap_reset(nan, peer);
272 
273 	peer->bootstrap.initiator = true;
274 	peer->bootstrap.dialog_token = dialog_token;
275 	peer->bootstrap.requested_pbm = nan_complement_pbm(pbm);
276 	peer->bootstrap.in_progress = true;
277 	peer->bootstrap.handle = handle;
278 	peer->bootstrap.req_instance_id = req_instance_id;
279 	supported_methods =
280 		nan->cfg->get_supported_bootstrap_methods(nan->cfg->cb_ctx,
281 							  handle);
282 
283 	if (!(supported_methods & peer->bootstrap.requested_pbm)) {
284 		wpa_printf(MSG_DEBUG,
285 			   "NAN: Bootstrap: No supported bootstrap methods in request");
286 
287 		peer->bootstrap.status = NAN_PBA_STATUS_REJECTED;
288 		peer->bootstrap.reason_code =
289 			NAN_REASON_PAIR_BOOTSTRAP_REJECTED;
290 		goto send_response;
291 	}
292 
293 	if (peer->bootstrap.requested_pbm &
294 	    nan->cfg->auto_accept_bootstrap_methods) {
295 		peer->bootstrap.authorized = peer->bootstrap.requested_pbm;
296 		peer->bootstrap.status = NAN_PBA_STATUS_ACCEPTED;
297 		goto send_response;
298 	}
299 
300 	peer->bootstrap.status = NAN_PBA_STATUS_COMEBACK;
301 	peer->bootstrap.comeback_required = true;
302 	peer->bootstrap.cookie_len = NAN_BOOTSTRAP_COOKIE_LEN;
303 	peer->bootstrap.cookie = os_malloc(peer->bootstrap.cookie_len);
304 
305 	if (peer->bootstrap.cookie) {
306 		if (os_get_random(peer->bootstrap.cookie,
307 				  peer->bootstrap.cookie_len) < 0) {
308 			nan_bootstrap_reset(nan, peer);
309 			return;
310 		}
311 	} else {
312 		peer->bootstrap.cookie_len = 0;
313 	}
314 
315 	peer->bootstrap.comeback_after = nan->cfg->bootstrap_comeback_timeout;
316 
317 	if (nan->cfg->bootstrap_request)
318 		nan->cfg->bootstrap_request(nan->cfg->cb_ctx, peer->nmi_addr,
319 					    peer->bootstrap.requested_pbm,
320 					    handle, req_instance_id);
321 
322 send_response:
323 	attr = nan_bootstrap_build_npba(nan, peer);
324 	if (!attr) {
325 		wpa_printf(MSG_DEBUG,
326 			   "NAN: Bootstrap: Failed to build bootstrap attribute");
327 		goto done;
328 	}
329 
330 	if (nan->cfg->transmit_followup(nan->cfg->cb_ctx, peer->nmi_addr, attr,
331 					handle, req_instance_id)) {
332 		wpa_printf(MSG_DEBUG,
333 			   "NAN: Bootstrap: Failed to transmit bootstrap followup");
334 
335 		nan->cfg->bootstrap_completed(nan->cfg->cb_ctx, peer->nmi_addr,
336 					      0, false,
337 					      NAN_REASON_UNSPECIFIED_REASON,
338 					      handle, req_instance_id);
339 		goto done;
340 	}
341 
342 	if (peer->bootstrap.status == NAN_PBA_STATUS_COMEBACK) {
343 		wpa_printf(MSG_DEBUG,
344 			   "NAN: Bootstrap: Wait for comeback bootstrap request");
345 
346 		wpabuf_free(attr);
347 		return;
348 	}
349 
350 	if (peer->bootstrap.status == NAN_PBA_STATUS_ACCEPTED) {
351 		wpabuf_free(peer->bootstrap.npba);
352 		peer->bootstrap.npba = wpabuf_alloc(3 + npba_len);
353 		if (peer->bootstrap.npba) {
354 			wpabuf_put_u8(peer->bootstrap.npba, NAN_ATTR_NPBA);
355 			wpabuf_put_le16(peer->bootstrap.npba, npba_len);
356 			wpabuf_put_data(peer->bootstrap.npba, npba, npba_len);
357 		} else {
358 			wpa_printf(MSG_INFO,
359 				   "NAN: Bootstrap: Failed to store NPBA");
360 		}
361 	}
362 
363 	nan->cfg->bootstrap_completed(nan->cfg->cb_ctx,
364 				      peer->nmi_addr,
365 				      peer->bootstrap.requested_pbm,
366 				      peer->bootstrap.status ==
367 				      NAN_PBA_STATUS_ACCEPTED,
368 				      peer->bootstrap.reason_code,
369 				      peer->bootstrap.handle,
370 				      peer->bootstrap.req_instance_id);
371 done:
372 	wpabuf_free(attr);
373 	nan_bootstrap_reset(nan, peer);
374 }
375 
376 
377 /**
378  * nan_bootstrap_supported - Check if bootstrap operations are supported
379  * @nan: NAN module context from nan_init()
380  * Returns: Whether all required bootstrap operations are supported
381  */
nan_bootstrap_supported(struct nan_data * nan)382 static bool nan_bootstrap_supported(struct nan_data *nan)
383 {
384 	return nan->cfg->bootstrap_completed &&
385 		nan->cfg->bootstrap_request &&
386 		nan->cfg->transmit_followup &&
387 		nan->cfg->get_supported_bootstrap_methods;
388 }
389 
390 
391 /**
392  * nan_bootstrap_handle_rx - Process received bootstrap follow-up
393  * @nan: NAN module context from nan_init()
394  * @peer_nmi: Peer address from which the follow-up was received
395  * @npba: Pointer to the NPBA in the follow-up
396  * @npba_len: Length of the NPBA
397  * @buf: Complete Follow-up frame
398  * @len: Length of the complete Follow-up frame
399  * @handle: Follow up handle
400  * @req_instance_id: Follow-up instance ID
401  * Returns: true if the follow up was processed, false on error
402  */
nan_bootstrap_handle_rx(struct nan_data * nan,const u8 * peer_nmi,const u8 * npba,u16 npba_len,const u8 * buf,size_t len,int handle,u8 req_instance_id)403 bool nan_bootstrap_handle_rx(struct nan_data *nan, const u8 *peer_nmi,
404 			     const u8 *npba, u16 npba_len,
405 			     const u8 *buf, size_t len,
406 			     int handle, u8 req_instance_id)
407 {
408 	const u8 *cookie = NULL;
409 	u8 dialog_token, type, status, reason_code, cookie_len = 0;
410 	u16 pbm, comeback_after = 0;
411 	struct nan_peer *peer;
412 	const u8 *orig_npba = npba;
413 	u16 orig_npba_len = npba_len;
414 
415 	if (!nan_bootstrap_supported(nan)) {
416 		wpa_printf(MSG_DEBUG,
417 			   "NAN: Bootstrap: Not all bootstrap operations are supported. Ignore");
418 		return false;
419 	}
420 
421 	if (npba_len < 3)
422 		return false;
423 	dialog_token = *npba++;
424 	type = *npba & NAN_PBA_TYPE_MASK;
425 	status = (*npba++ >> NAN_PBA_STATUS_POS) & NAN_PBA_STATUS_MASK;
426 	reason_code = *npba++;
427 	npba_len -= 3;
428 
429 	if (type == NAN_PBA_TYPE_ADVERTISE) {
430 		wpa_printf(MSG_DEBUG,
431 			   "NAN: Bootstrap: type == Advertise. Ignore");
432 		return false;
433 	}
434 
435 	if (type != NAN_PBA_TYPE_REQUEST &&
436 	    type != NAN_PBA_TYPE_RESPONSE) {
437 		wpa_printf(MSG_DEBUG,
438 			   "NAN: Bootstrap: Unknown NPBA type %u", type);
439 		return false;
440 	}
441 
442 	if (status == NAN_PBA_STATUS_COMEBACK) {
443 		if (type == NAN_PBA_TYPE_RESPONSE) {
444 			if (npba_len < 2) {
445 				wpa_printf(MSG_DEBUG,
446 					   "NAN: Bootstrap: Response too short for comeback after");
447 				return false;
448 			}
449 
450 			comeback_after = WPA_GET_LE16(npba);
451 			npba += 2;
452 			npba_len -= 2;
453 		}
454 
455 		if (npba_len < 1) {
456 			wpa_printf(MSG_DEBUG,
457 				   "NAN: Bootstrap: Response too short for comeback cookie length");
458 			return false;
459 		}
460 
461 		cookie_len = *npba++;
462 		npba_len--;
463 		if (cookie_len > npba_len) {
464 			wpa_printf(MSG_DEBUG,
465 				   "NAN: Bootstrap: Comeback field is too long");
466 			return false;
467 		}
468 
469 		cookie = npba;
470 		npba += cookie_len;
471 		npba_len -= cookie_len;
472 	}
473 
474 	if (npba_len < 2) {
475 		wpa_printf(MSG_DEBUG,
476 			   "NAN: Bootstrap: Buffer too short for PBM");
477 		return false;
478 	}
479 
480 	pbm = WPA_GET_LE16(npba);
481 	peer = nan_get_peer(nan, peer_nmi);
482 
483 	/* Handle NAN bootstrap request */
484 	if (type == NAN_PBA_TYPE_REQUEST) {
485 		if (!peer) {
486 			nan_add_peer(nan, peer_nmi, buf, len);
487 			peer = nan_get_peer(nan, peer_nmi);
488 			if (!peer) {
489 				wpa_printf(MSG_DEBUG,
490 					   "NAN: Bootstrap: Failed alloc peer from bootstrap request");
491 				return false;
492 			}
493 		}
494 
495 		nan_bootstrap_handle_rx_request(nan, peer, dialog_token,
496 						pbm, cookie, cookie_len,
497 						status, handle,
498 						req_instance_id,
499 						orig_npba, orig_npba_len);
500 		return true;
501 	}
502 
503 	/* Handle NAN bootstrap response */
504 	if (!peer || !peer->bootstrap.in_progress ||
505 	    peer->bootstrap.initiator) {
506 		wpa_printf(MSG_DEBUG,
507 			   "NAN: Bootstrap: Unexpected bootstrap response");
508 		return false;
509 	}
510 
511 	if (dialog_token != peer->bootstrap.dialog_token) {
512 		wpa_printf(MSG_DEBUG,
513 			   "NAN: Bootstrap: Response with invalid dialog token. Ignore");
514 		return false;
515 	}
516 
517 	if (handle != peer->bootstrap.handle ||
518 	    req_instance_id != peer->bootstrap.req_instance_id) {
519 		wpa_printf(MSG_DEBUG,
520 			   "NAN: Bootstrap: Response with invalid handle or instance ID. Ignore");
521 		return false;
522 	}
523 
524 	peer->bootstrap.status = status;
525 	peer->bootstrap.reason_code = reason_code;
526 	peer->bootstrap.comeback_required = status == NAN_PBA_STATUS_COMEBACK;
527 	peer->bootstrap.comeback_after = comeback_after;
528 
529 	if (cookie && cookie_len) {
530 		os_free(peer->bootstrap.cookie);
531 		peer->bootstrap.cookie = os_memdup(cookie, cookie_len);
532 		if (!peer->bootstrap.cookie) {
533 			nan_bootstrap_reset(nan, peer);
534 			return false;
535 		}
536 		peer->bootstrap.cookie_len = cookie_len;
537 	}
538 
539 	if (status == NAN_PBA_STATUS_ACCEPTED &&
540 	    nan_complement_pbm(pbm) == peer->bootstrap.requested_pbm) {
541 		wpa_printf(MSG_DEBUG, "NAN: Bootstrap: Accepted. Complete.");
542 
543 		nan->cfg->bootstrap_completed(nan->cfg->cb_ctx,
544 					      peer->nmi_addr,
545 					      peer->bootstrap.requested_pbm,
546 					      true, 0,
547 					      peer->bootstrap.handle,
548 					      peer->bootstrap.req_instance_id);
549 		nan_bootstrap_reset(nan, peer);
550 	} else if (status == NAN_PBA_STATUS_REJECTED) {
551 		wpa_printf(MSG_DEBUG, "NAN: Bootstrap: Rejected. Complete");
552 
553 		nan->cfg->bootstrap_completed(nan->cfg->cb_ctx, peer->nmi_addr,
554 					      0, false, reason_code,
555 					      peer->bootstrap.handle,
556 					      peer->bootstrap.req_instance_id);
557 		nan_bootstrap_reset(nan, peer);
558 	} else if (status == NAN_PBA_STATUS_COMEBACK) {
559 		wpa_printf(MSG_DEBUG,
560 			   "NAN: Bootstrap: Comeback required. Schedule timeout for %u TU",
561 			   peer->bootstrap.comeback_after);
562 
563 		eloop_cancel_timeout(nan_bootstrap_timeout, nan, peer);
564 		eloop_register_timeout(peer->bootstrap.comeback_after / 1024,
565 				       (peer->bootstrap.comeback_after % 1024) *
566 				       1000,
567 				       nan_bootstrap_timeout, nan, peer);
568 	} else {
569 		wpa_printf(MSG_DEBUG,
570 			   "NAN: Bootstrap: Unknown status=%u. Abort.",
571 			   status);
572 
573 		nan->cfg->bootstrap_completed(nan->cfg->cb_ctx, peer->nmi_addr,
574 					      0, false,
575 					      NAN_REASON_UNSPECIFIED_REASON,
576 					      peer->bootstrap.handle,
577 					      peer->bootstrap.req_instance_id);
578 		nan_bootstrap_reset(nan, peer);
579 	}
580 
581 	return true;
582 }
583 
584 
585 /**
586  * nan_bootstrap_request - Initiate NAN bootstrap request to a peer
587  * @nan: NAN module context from nan_init()
588  * @handle: Follow up handle
589  * @peer_nmi: Peer address to which to send the bootstrap request
590  * @req_instance_id: Follow up instance ID
591  * @pbm: Pairing bootstrapping method bitmap to use
592  * @auth: If true, authorize the bootstrap request for the peer instead of
593  *        sending the request
594  * Returns: 0 on success, -1 on failure
595  */
nan_bootstrap_request(struct nan_data * nan,int handle,const u8 * peer_nmi,u8 req_instance_id,u16 pbm,bool auth)596 int nan_bootstrap_request(struct nan_data *nan, int handle,
597 			  const u8 *peer_nmi, u8 req_instance_id, u16 pbm,
598 			  bool auth)
599 {
600 	struct nan_peer *peer;
601 	int ret;
602 
603 	if (!nan || !nan->nan_started)
604 		return -1;
605 
606 	if (!nan_bootstrap_supported(nan)) {
607 		wpa_printf(MSG_DEBUG,
608 			   "NAN: Bootstrap: Not all bootstrap operations are supported. Ignore");
609 		return -1;
610 	}
611 
612 	wpa_printf(MSG_DEBUG,
613 		   "NAN: Bootstrap: Request bootstrap to peer " MACSTR
614 		   " pbm=0x%x auth=%d",
615 		   MAC2STR(peer_nmi), pbm, auth);
616 
617 	peer = nan_get_peer(nan, peer_nmi);
618 	if (!peer) {
619 		wpa_printf(MSG_DEBUG,
620 			   "NAN: Bootstrap: Request for unknown peer");
621 		return -1;
622 	}
623 
624 	if (!(pbm & nan->cfg->supported_bootstrap_methods)) {
625 		wpa_printf(MSG_DEBUG,
626 			   "NAN: Bootstrap: Unsupported method=0x%x (local support=0x%x)",
627 			   pbm, nan->cfg->supported_bootstrap_methods);
628 		return -1;
629 	}
630 
631 	if (pbm & (pbm - 1)) {
632 		wpa_printf(MSG_DEBUG,
633 			   "NAN: Bootstrap: Multiple bootstrap methods=0x%x in request",
634 			   pbm);
635 		return -1;
636 	}
637 
638 	if (auth) {
639 		wpa_printf(MSG_DEBUG, "NAN: Bootstrap: Authorize request");
640 
641 		peer->bootstrap.authorized = pbm;
642 		return 0;
643 	}
644 
645 	if (peer->bootstrap.in_progress) {
646 		wpa_printf(MSG_DEBUG,
647 			   "NAN: Bootstrap: already in progress with the peer");
648 		return -1;
649 	}
650 
651 	if (!(nan_complement_pbm(pbm) & peer->bootstrap.supported_methods)) {
652 		wpa_printf(MSG_DEBUG,
653 			   "NAN: Bootstrap: Peer doesn't support method=0x%x",
654 			   pbm);
655 		return -1;
656 	}
657 
658 	wpa_printf(MSG_DEBUG, "NAN: Prepare bootstrap request");
659 
660 	nan_bootstrap_reset(nan, peer);
661 
662 	peer->bootstrap.dialog_token = nan_get_next_dialog_token(nan);
663 	peer->bootstrap.requested_pbm = pbm;
664 	peer->bootstrap.in_progress = true;
665 	peer->bootstrap.handle = handle;
666 	peer->bootstrap.req_instance_id = req_instance_id;
667 
668 	peer->bootstrap.npba = nan_bootstrap_build_npba(nan, peer);
669 	if (!peer->bootstrap.npba) {
670 		nan_bootstrap_reset(nan, peer);
671 		return -1;
672 	}
673 
674 	ret = nan->cfg->transmit_followup(nan->cfg->cb_ctx, peer->nmi_addr,
675 					  peer->bootstrap.npba, handle,
676 					  req_instance_id);
677 	if (ret) {
678 		wpa_printf(MSG_DEBUG,
679 			   "NAN: Bootstrap: Failed to transmit follow-up");
680 
681 		nan_bootstrap_reset(nan, peer);
682 		return -1;
683 	}
684 
685 	eloop_register_timeout(0, NAN_BOOTSTRAP_RETRY_TIMEOUT_US,
686 			       nan_bootstrap_timeout, nan, peer);
687 	return ret;
688 }
689 
690 
691 /**
692  * nan_bootstrap_peer_reset - Reset bootstrap state for a peer
693  * @nan: NAN module context from nan_init()
694  * @peer_nmi: Peer address for which to reset the bootstrap state
695  * Returns: 0 on success, -1 on failure
696  */
nan_bootstrap_peer_reset(struct nan_data * nan,const u8 * peer_nmi)697 int nan_bootstrap_peer_reset(struct nan_data *nan, const u8 *peer_nmi)
698 {
699 	struct nan_peer *peer;
700 
701 	if (!nan || !nan->nan_started)
702 		return -1;
703 
704 	peer = nan_get_peer(nan, peer_nmi);
705 	if (!peer) {
706 		wpa_printf(MSG_DEBUG, "NAN: Bootstrap: Reset for unknown peer");
707 		return -1;
708 	}
709 
710 	nan_bootstrap_reset(nan, peer);
711 	return 0;
712 }
713 
714 
715 /**
716  * nan_bootstrap_get_supported_methods - Get supported bootstrap methods for a peer
717  *
718  * @nan: NAN module context from nan_init()
719  * @peer_nmi: Peer address
720  * @supported_methods: Pointer to store the supported methods bitmap
721  * Returns: 0 on success, -1 on failure
722  */
nan_bootstrap_get_supported_methods(struct nan_data * nan,const u8 * peer_nmi,u16 * supported_methods)723 int nan_bootstrap_get_supported_methods(struct nan_data *nan,
724 					const u8 *peer_nmi,
725 					u16 *supported_methods)
726 {
727 	struct nan_peer *peer;
728 
729 	if (!nan || !nan->nan_started || !supported_methods)
730 		return -1;
731 
732 	peer = nan_get_peer(nan, peer_nmi);
733 	if (!peer) {
734 		wpa_printf(MSG_DEBUG,
735 			   "NAN: Bootstrap: Get supported methods for unknown peer");
736 		return -1;
737 	}
738 
739 	*supported_methods = peer->bootstrap.supported_methods;
740 	return 0;
741 }
742