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