xref: /freebsd/contrib/wpa/wpa_supplicant/nan_usd.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1 /*
2  * NAN unsynchronized service discovery (USD)
3  * Copyright (c) 2024, Qualcomm Innovation Center, Inc.
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "utils/includes.h"
10 
11 #include "utils/common.h"
12 #include "common/nan_de.h"
13 #include "wpa_supplicant_i.h"
14 #include "offchannel.h"
15 #include "driver_i.h"
16 #include "nan_usd.h"
17 
18 
19 static const char *
tx_status_result_txt(enum offchannel_send_action_result result)20 tx_status_result_txt(enum offchannel_send_action_result result)
21 {
22 	switch (result) {
23 	case OFFCHANNEL_SEND_ACTION_SUCCESS:
24 		return "success";
25 	case OFFCHANNEL_SEND_ACTION_NO_ACK:
26 		return "no-ack";
27 	case OFFCHANNEL_SEND_ACTION_FAILED:
28 		return "failed";
29 	}
30 
31 	return "?";
32 }
33 
34 
wpas_nan_de_tx_status(struct wpa_supplicant * wpa_s,unsigned int freq,const u8 * dst,const u8 * src,const u8 * bssid,const u8 * data,size_t data_len,enum offchannel_send_action_result result)35 static void wpas_nan_de_tx_status(struct wpa_supplicant *wpa_s,
36 				  unsigned int freq, const u8 *dst,
37 				  const u8 *src, const u8 *bssid,
38 				  const u8 *data, size_t data_len,
39 				  enum offchannel_send_action_result result)
40 {
41 	if (!wpa_s->nan_de)
42 		return;
43 
44 	wpa_printf(MSG_DEBUG, "NAN: TX status A1=" MACSTR " A2=" MACSTR
45 		   " A3=" MACSTR " freq=%d len=%zu result=%s",
46 		   MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), freq,
47 		   data_len, tx_status_result_txt(result));
48 
49 	nan_de_tx_status(wpa_s->nan_de, freq, dst);
50 }
51 
52 
53 struct wpas_nan_usd_tx_work {
54 	unsigned int freq;
55 	unsigned int wait_time;
56 	u8 dst[ETH_ALEN];
57 	u8 src[ETH_ALEN];
58 	u8 bssid[ETH_ALEN];
59 	struct wpabuf *buf;
60 };
61 
62 
wpas_nan_usd_tx_work_free(struct wpas_nan_usd_tx_work * twork)63 static void wpas_nan_usd_tx_work_free(struct wpas_nan_usd_tx_work *twork)
64 {
65 	if (!twork)
66 		return;
67 	wpabuf_free(twork->buf);
68 	os_free(twork);
69 }
70 
71 
wpas_nan_usd_tx_work_done(struct wpa_supplicant * wpa_s)72 static void wpas_nan_usd_tx_work_done(struct wpa_supplicant *wpa_s)
73 {
74 	struct wpas_nan_usd_tx_work *twork;
75 
76 	if (!wpa_s->nan_usd_tx_work)
77 		return;
78 
79 	twork = wpa_s->nan_usd_tx_work->ctx;
80 	wpas_nan_usd_tx_work_free(twork);
81 	radio_work_done(wpa_s->nan_usd_tx_work);
82 	wpa_s->nan_usd_tx_work = NULL;
83 }
84 
85 
wpas_nan_de_tx_send(struct wpa_supplicant * wpa_s,unsigned int freq,unsigned int wait_time,const u8 * dst,const u8 * src,const u8 * bssid,const struct wpabuf * buf)86 static int wpas_nan_de_tx_send(struct wpa_supplicant *wpa_s, unsigned int freq,
87 			       unsigned int wait_time, const u8 *dst,
88 			       const u8 *src, const u8 *bssid,
89 			       const struct wpabuf *buf)
90 {
91 	wpa_printf(MSG_DEBUG, "NAN: TX NAN SDF A1=" MACSTR " A2=" MACSTR
92 		   " A3=" MACSTR " freq=%d len=%zu",
93 		   MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), freq,
94 		   wpabuf_len(buf));
95 
96 	return offchannel_send_action(wpa_s, freq, dst, src, bssid,
97 				      wpabuf_head(buf), wpabuf_len(buf),
98 				      wait_time, wpas_nan_de_tx_status, 1);
99 }
100 
101 
wpas_nan_usd_start_tx_cb(struct wpa_radio_work * work,int deinit)102 static void wpas_nan_usd_start_tx_cb(struct wpa_radio_work *work, int deinit)
103 {
104 	struct wpa_supplicant *wpa_s = work->wpa_s;
105 	struct wpas_nan_usd_tx_work *twork = work->ctx;
106 
107 	if (deinit) {
108 		if (work->started) {
109 			wpa_s->nan_usd_tx_work = NULL;
110 			offchannel_send_action_done(wpa_s);
111 		}
112 		wpas_nan_usd_tx_work_free(twork);
113 		return;
114 	}
115 
116 	wpa_s->nan_usd_tx_work = work;
117 
118 	if (wpas_nan_de_tx_send(wpa_s, twork->freq, twork->wait_time,
119 				twork->dst, twork->src, twork->bssid,
120 				twork->buf) < 0)
121 		wpas_nan_usd_tx_work_done(wpa_s);
122 }
123 
124 
wpas_nan_de_tx(void * ctx,unsigned int freq,unsigned int wait_time,const u8 * dst,const u8 * src,const u8 * bssid,const struct wpabuf * buf)125 static int wpas_nan_de_tx(void *ctx, unsigned int freq, unsigned int wait_time,
126 			  const u8 *dst, const u8 *src, const u8 *bssid,
127 			  const struct wpabuf *buf)
128 {
129 	struct wpa_supplicant *wpa_s = ctx;
130 	struct wpas_nan_usd_tx_work *twork;
131 
132 	if (wpa_s->nan_usd_tx_work || wpa_s->nan_usd_listen_work) {
133 		/* Reuse ongoing radio work */
134 		return wpas_nan_de_tx_send(wpa_s, freq, wait_time, dst, src,
135 					   bssid, buf);
136 	}
137 
138 	twork = os_zalloc(sizeof(*twork));
139 	if (!twork)
140 		return -1;
141 	twork->freq = freq;
142 	twork->wait_time = wait_time;
143 	os_memcpy(twork->dst, dst, ETH_ALEN);
144 	os_memcpy(twork->src, src, ETH_ALEN);
145 	os_memcpy(twork->bssid, bssid, ETH_ALEN);
146 	twork->buf = wpabuf_dup(buf);
147 	if (!twork->buf) {
148 		wpas_nan_usd_tx_work_free(twork);
149 		return -1;
150 	}
151 
152 	if (radio_add_work(wpa_s, freq, "nan-usd-tx", 0,
153 			   wpas_nan_usd_start_tx_cb, twork) < 0) {
154 		wpas_nan_usd_tx_work_free(twork);
155 		return -1;
156 	}
157 
158 	return 0;
159 }
160 
161 
162 struct wpas_nan_usd_listen_work {
163 	unsigned int freq;
164 	unsigned int duration;
165 };
166 
167 
wpas_nan_usd_listen_work_done(struct wpa_supplicant * wpa_s)168 static void wpas_nan_usd_listen_work_done(struct wpa_supplicant *wpa_s)
169 {
170 	struct wpas_nan_usd_listen_work *lwork;
171 
172 	if (!wpa_s->nan_usd_listen_work)
173 		return;
174 
175 	lwork = wpa_s->nan_usd_listen_work->ctx;
176 	os_free(lwork);
177 	radio_work_done(wpa_s->nan_usd_listen_work);
178 	wpa_s->nan_usd_listen_work = NULL;
179 }
180 
181 
wpas_nan_usd_start_listen_cb(struct wpa_radio_work * work,int deinit)182 static void wpas_nan_usd_start_listen_cb(struct wpa_radio_work *work,
183 					 int deinit)
184 {
185 	struct wpa_supplicant *wpa_s = work->wpa_s;
186 	struct wpas_nan_usd_listen_work *lwork = work->ctx;
187 	unsigned int duration;
188 
189 	if (deinit) {
190 		if (work->started) {
191 			wpa_s->nan_usd_listen_work = NULL;
192 			wpa_drv_cancel_remain_on_channel(wpa_s);
193 		}
194 		os_free(lwork);
195 		return;
196 	}
197 
198 	wpa_s->nan_usd_listen_work = work;
199 
200 	duration = lwork->duration;
201 	if (duration > wpa_s->max_remain_on_chan)
202 		duration = wpa_s->max_remain_on_chan;
203 	wpa_printf(MSG_DEBUG, "NAN: Start listen on %u MHz for %u ms",
204 		   lwork->freq, duration);
205 	if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, duration) < 0) {
206 		wpa_printf(MSG_DEBUG,
207 			   "NAN: Failed to request the driver to remain on channel (%u MHz) for listen",
208 			   lwork->freq);
209 		wpas_nan_usd_listen_work_done(wpa_s);
210 		return;
211 	}
212 }
213 
214 
wpas_nan_de_listen(void * ctx,unsigned int freq,unsigned int duration)215 static int wpas_nan_de_listen(void *ctx, unsigned int freq,
216 			      unsigned int duration)
217 {
218 	struct wpa_supplicant *wpa_s = ctx;
219 	struct wpas_nan_usd_listen_work *lwork;
220 
221 	lwork = os_zalloc(sizeof(*lwork));
222 	if (!lwork)
223 		return -1;
224 	lwork->freq = freq;
225 	lwork->duration = duration;
226 
227 	if (radio_add_work(wpa_s, freq, "nan-usd-listen", 0,
228 			   wpas_nan_usd_start_listen_cb, lwork) < 0) {
229 		os_free(lwork);
230 		return -1;
231 	}
232 
233 	return 0;
234 }
235 
236 
237 static void
wpas_nan_de_discovery_result(void * ctx,int subscribe_id,enum nan_service_protocol_type srv_proto_type,const u8 * ssi,size_t ssi_len,int peer_publish_id,const u8 * peer_addr,bool fsd,bool fsd_gas)238 wpas_nan_de_discovery_result(void *ctx, int subscribe_id,
239 			     enum nan_service_protocol_type srv_proto_type,
240 			     const u8 *ssi, size_t ssi_len, int peer_publish_id,
241 			     const u8 *peer_addr, bool fsd, bool fsd_gas)
242 {
243 	struct wpa_supplicant *wpa_s = ctx;
244 	char *ssi_hex;
245 
246 	ssi_hex = os_zalloc(2 * ssi_len + 1);
247 	if (!ssi_hex)
248 		return;
249 	if (ssi)
250 		wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
251 	wpa_msg(wpa_s, MSG_INFO, NAN_DISCOVERY_RESULT
252 		"subscribe_id=%d publish_id=%d address=" MACSTR
253 		" fsd=%d fsd_gas=%d srv_proto_type=%u ssi=%s",
254 		subscribe_id, peer_publish_id, MAC2STR(peer_addr),
255 		fsd, fsd_gas, srv_proto_type, ssi_hex);
256 	os_free(ssi_hex);
257 }
258 
259 
wpas_nan_de_replied(void * ctx,int publish_id,const u8 * peer_addr,int peer_subscribe_id,enum nan_service_protocol_type srv_proto_type,const u8 * ssi,size_t ssi_len)260 static void wpas_nan_de_replied(void *ctx, int publish_id, const u8 *peer_addr,
261 				int peer_subscribe_id,
262 				enum nan_service_protocol_type srv_proto_type,
263 				const u8 *ssi, size_t ssi_len)
264 {
265 	struct wpa_supplicant *wpa_s = ctx;
266 	char *ssi_hex;
267 
268 	ssi_hex = os_zalloc(2 * ssi_len + 1);
269 	if (!ssi_hex)
270 		return;
271 	if (ssi)
272 		wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
273 	wpa_msg(wpa_s, MSG_INFO, NAN_REPLIED
274 		"publish_id=%d address=" MACSTR
275 		" subscribe_id=%d srv_proto_type=%u ssi=%s",
276 		publish_id, MAC2STR(peer_addr), peer_subscribe_id,
277 		srv_proto_type, ssi_hex);
278 	os_free(ssi_hex);
279 }
280 
281 
nan_reason_txt(enum nan_de_reason reason)282 static const char * nan_reason_txt(enum nan_de_reason reason)
283 {
284 	switch (reason) {
285 	case NAN_DE_REASON_TIMEOUT:
286 		return "timeout";
287 	case NAN_DE_REASON_USER_REQUEST:
288 		return "user-request";
289 	case NAN_DE_REASON_FAILURE:
290 		return "failure";
291 	}
292 
293 	return "unknown";
294 }
295 
296 
wpas_nan_de_publish_terminated(void * ctx,int publish_id,enum nan_de_reason reason)297 static void wpas_nan_de_publish_terminated(void *ctx, int publish_id,
298 					   enum nan_de_reason reason)
299 {
300 	struct wpa_supplicant *wpa_s = ctx;
301 
302 	wpa_msg(wpa_s, MSG_INFO, NAN_PUBLISH_TERMINATED
303 		"publish_id=%d reason=%s",
304 		publish_id, nan_reason_txt(reason));
305 }
306 
307 
wpas_nan_de_subscribe_terminated(void * ctx,int subscribe_id,enum nan_de_reason reason)308 static void wpas_nan_de_subscribe_terminated(void *ctx, int subscribe_id,
309 					     enum nan_de_reason reason)
310 {
311 	struct wpa_supplicant *wpa_s = ctx;
312 
313 	wpa_msg(wpa_s, MSG_INFO, NAN_SUBSCRIBE_TERMINATED
314 		"subscribe_id=%d reason=%s",
315 		subscribe_id, nan_reason_txt(reason));
316 }
317 
318 
wpas_nan_de_receive(void * ctx,int id,int peer_instance_id,const u8 * ssi,size_t ssi_len,const u8 * peer_addr)319 static void wpas_nan_de_receive(void *ctx, int id, int peer_instance_id,
320 				const u8 *ssi, size_t ssi_len,
321 				const u8 *peer_addr)
322 {
323 	struct wpa_supplicant *wpa_s = ctx;
324 	char *ssi_hex;
325 
326 	ssi_hex = os_zalloc(2 * ssi_len + 1);
327 	if (!ssi_hex)
328 		return;
329 	if (ssi)
330 		wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
331 	wpa_msg(wpa_s, MSG_INFO, NAN_RECEIVE
332 		"id=%d peer_instance_id=%d address=" MACSTR " ssi=%s",
333 		id, peer_instance_id, MAC2STR(peer_addr), ssi_hex);
334 	os_free(ssi_hex);
335 }
336 
337 
wpas_nan_usd_init(struct wpa_supplicant * wpa_s)338 int wpas_nan_usd_init(struct wpa_supplicant *wpa_s)
339 {
340 	struct nan_callbacks cb;
341 
342 	os_memset(&cb, 0, sizeof(cb));
343 	cb.ctx = wpa_s;
344 	cb.tx = wpas_nan_de_tx;
345 	cb.listen = wpas_nan_de_listen;
346 	cb.discovery_result = wpas_nan_de_discovery_result;
347 	cb.replied = wpas_nan_de_replied;
348 	cb.publish_terminated = wpas_nan_de_publish_terminated;
349 	cb.subscribe_terminated = wpas_nan_de_subscribe_terminated;
350 	cb.receive = wpas_nan_de_receive;
351 
352 	wpa_s->nan_de = nan_de_init(wpa_s->own_addr, false, &cb);
353 	if (!wpa_s->nan_de)
354 		return -1;
355 	return 0;
356 }
357 
358 
wpas_nan_usd_deinit(struct wpa_supplicant * wpa_s)359 void wpas_nan_usd_deinit(struct wpa_supplicant *wpa_s)
360 {
361 	nan_de_deinit(wpa_s->nan_de);
362 	wpa_s->nan_de = NULL;
363 }
364 
365 
wpas_nan_usd_rx_sdf(struct wpa_supplicant * wpa_s,const u8 * src,unsigned int freq,const u8 * buf,size_t len)366 void wpas_nan_usd_rx_sdf(struct wpa_supplicant *wpa_s, const u8 *src,
367 			 unsigned int freq, const u8 *buf, size_t len)
368 {
369 	if (!wpa_s->nan_de)
370 		return;
371 	nan_de_rx_sdf(wpa_s->nan_de, src, freq, buf, len);
372 }
373 
374 
wpas_nan_usd_flush(struct wpa_supplicant * wpa_s)375 void wpas_nan_usd_flush(struct wpa_supplicant *wpa_s)
376 {
377 	if (!wpa_s->nan_de)
378 		return;
379 	nan_de_flush(wpa_s->nan_de);
380 }
381 
382 
wpas_nan_usd_publish(struct wpa_supplicant * wpa_s,const char * service_name,enum nan_service_protocol_type srv_proto_type,const struct wpabuf * ssi,struct nan_publish_params * params)383 int wpas_nan_usd_publish(struct wpa_supplicant *wpa_s, const char *service_name,
384 			 enum nan_service_protocol_type srv_proto_type,
385 			 const struct wpabuf *ssi,
386 			 struct nan_publish_params *params)
387 {
388 	int publish_id;
389 	struct wpabuf *elems = NULL;
390 
391 	if (!wpa_s->nan_de)
392 		return -1;
393 
394 	publish_id = nan_de_publish(wpa_s->nan_de, service_name, srv_proto_type,
395 				    ssi, elems, params);
396 	wpabuf_free(elems);
397 	return publish_id;
398 }
399 
400 
wpas_nan_usd_cancel_publish(struct wpa_supplicant * wpa_s,int publish_id)401 void wpas_nan_usd_cancel_publish(struct wpa_supplicant *wpa_s, int publish_id)
402 {
403 	if (!wpa_s->nan_de)
404 		return;
405 	nan_de_cancel_publish(wpa_s->nan_de, publish_id);
406 }
407 
408 
wpas_nan_usd_update_publish(struct wpa_supplicant * wpa_s,int publish_id,const struct wpabuf * ssi)409 int wpas_nan_usd_update_publish(struct wpa_supplicant *wpa_s, int publish_id,
410 				const struct wpabuf *ssi)
411 {
412 	if (!wpa_s->nan_de)
413 		return -1;
414 	return nan_de_update_publish(wpa_s->nan_de, publish_id, ssi);
415 }
416 
417 
wpas_nan_usd_subscribe(struct wpa_supplicant * wpa_s,const char * service_name,enum nan_service_protocol_type srv_proto_type,const struct wpabuf * ssi,struct nan_subscribe_params * params)418 int wpas_nan_usd_subscribe(struct wpa_supplicant *wpa_s,
419 			   const char *service_name,
420 			   enum nan_service_protocol_type srv_proto_type,
421 			   const struct wpabuf *ssi,
422 			   struct nan_subscribe_params *params)
423 {
424 	int subscribe_id;
425 	struct wpabuf *elems = NULL;
426 
427 	if (!wpa_s->nan_de)
428 		return -1;
429 
430 	subscribe_id = nan_de_subscribe(wpa_s->nan_de, service_name,
431 					srv_proto_type, ssi, elems, params);
432 	wpabuf_free(elems);
433 	return subscribe_id;
434 }
435 
436 
wpas_nan_usd_cancel_subscribe(struct wpa_supplicant * wpa_s,int subscribe_id)437 void wpas_nan_usd_cancel_subscribe(struct wpa_supplicant *wpa_s,
438 				   int subscribe_id)
439 {
440 	if (!wpa_s->nan_de)
441 		return;
442 	nan_de_cancel_subscribe(wpa_s->nan_de, subscribe_id);
443 }
444 
445 
wpas_nan_usd_transmit(struct wpa_supplicant * wpa_s,int handle,const struct wpabuf * ssi,const struct wpabuf * elems,const u8 * peer_addr,u8 req_instance_id)446 int wpas_nan_usd_transmit(struct wpa_supplicant *wpa_s, int handle,
447 			  const struct wpabuf *ssi, const struct wpabuf *elems,
448 			  const u8 *peer_addr, u8 req_instance_id)
449 {
450 	if (!wpa_s->nan_de)
451 		return -1;
452 	return nan_de_transmit(wpa_s->nan_de, handle, ssi, elems, peer_addr,
453 			       req_instance_id);
454 }
455 
456 
wpas_nan_usd_remain_on_channel_cb(struct wpa_supplicant * wpa_s,unsigned int freq,unsigned int duration)457 void wpas_nan_usd_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
458 				       unsigned int freq, unsigned int duration)
459 {
460 	wpas_nan_usd_listen_work_done(wpa_s);
461 
462 	if (wpa_s->nan_de)
463 		nan_de_listen_started(wpa_s->nan_de, freq, duration);
464 }
465 
466 
wpas_nan_usd_cancel_remain_on_channel_cb(struct wpa_supplicant * wpa_s,unsigned int freq)467 void wpas_nan_usd_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
468 					      unsigned int freq)
469 {
470 	if (wpa_s->nan_de)
471 		nan_de_listen_ended(wpa_s->nan_de, freq);
472 }
473 
474 
wpas_nan_usd_tx_wait_expire(struct wpa_supplicant * wpa_s)475 void wpas_nan_usd_tx_wait_expire(struct wpa_supplicant *wpa_s)
476 {
477 	wpas_nan_usd_tx_work_done(wpa_s);
478 
479 	if (wpa_s->nan_de)
480 		nan_de_tx_wait_ended(wpa_s->nan_de);
481 }
482 
483 
wpas_nan_usd_all_freqs(struct wpa_supplicant * wpa_s)484 int * wpas_nan_usd_all_freqs(struct wpa_supplicant *wpa_s)
485 {
486 	int i, j;
487 	int *freqs = NULL;
488 
489 	if (!wpa_s->hw.modes)
490 		return NULL;
491 
492 	for (i = 0; i < wpa_s->hw.num_modes; i++) {
493 		struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
494 
495 		for (j = 0; j < mode->num_channels; j++) {
496 			struct hostapd_channel_data *chan = &mode->channels[j];
497 
498 			/* All 20 MHz channels on 2.4 and 5 GHz band */
499 			if (chan->freq < 2412 || chan->freq > 5900)
500 				continue;
501 
502 			/* that allow frames to be transmitted */
503 			if (chan->flag & (HOSTAPD_CHAN_DISABLED |
504 					  HOSTAPD_CHAN_NO_IR |
505 					  HOSTAPD_CHAN_RADAR))
506 				continue;
507 
508 			int_array_add_unique(&freqs, chan->freq);
509 		}
510 	}
511 
512 	return freqs;
513 }
514