blob: 577c8ac2f6940277eb3de0f5acaba130a8ad8ac9 [file] [log] [blame]
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001/*
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"
Sunil Ravic0f5d412024-09-11 22:12:49 +000016#include "notify.h"
17#include "p2p_supplicant.h"
Sunil Ravib0ac25f2024-07-12 01:42:03 +000018#include "nan_usd.h"
19
20
21static const char *
22tx_status_result_txt(enum offchannel_send_action_result result)
23{
24 switch (result) {
25 case OFFCHANNEL_SEND_ACTION_SUCCESS:
26 return "success";
27 case OFFCHANNEL_SEND_ACTION_NO_ACK:
28 return "no-ack";
29 case OFFCHANNEL_SEND_ACTION_FAILED:
30 return "failed";
31 }
32
33 return "?";
34}
35
36
37static void wpas_nan_de_tx_status(struct wpa_supplicant *wpa_s,
38 unsigned int freq, const u8 *dst,
39 const u8 *src, const u8 *bssid,
40 const u8 *data, size_t data_len,
41 enum offchannel_send_action_result result)
42{
43 if (!wpa_s->nan_de)
44 return;
45
46 wpa_printf(MSG_DEBUG, "NAN: TX status A1=" MACSTR " A2=" MACSTR
47 " A3=" MACSTR " freq=%d len=%zu result=%s",
48 MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), freq,
49 data_len, tx_status_result_txt(result));
50
51 nan_de_tx_status(wpa_s->nan_de, freq, dst);
52}
53
54
55struct wpas_nan_usd_tx_work {
56 unsigned int freq;
57 unsigned int wait_time;
58 u8 dst[ETH_ALEN];
59 u8 src[ETH_ALEN];
60 u8 bssid[ETH_ALEN];
61 struct wpabuf *buf;
62};
63
64
65static void wpas_nan_usd_tx_work_free(struct wpas_nan_usd_tx_work *twork)
66{
67 if (!twork)
68 return;
69 wpabuf_free(twork->buf);
70 os_free(twork);
71}
72
73
74static void wpas_nan_usd_tx_work_done(struct wpa_supplicant *wpa_s)
75{
76 struct wpas_nan_usd_tx_work *twork;
77
78 if (!wpa_s->nan_usd_tx_work)
79 return;
80
81 twork = wpa_s->nan_usd_tx_work->ctx;
82 wpas_nan_usd_tx_work_free(twork);
83 radio_work_done(wpa_s->nan_usd_tx_work);
84 wpa_s->nan_usd_tx_work = NULL;
85}
86
87
88static int wpas_nan_de_tx_send(struct wpa_supplicant *wpa_s, unsigned int freq,
89 unsigned int wait_time, const u8 *dst,
90 const u8 *src, const u8 *bssid,
91 const struct wpabuf *buf)
92{
93 wpa_printf(MSG_DEBUG, "NAN: TX NAN SDF A1=" MACSTR " A2=" MACSTR
94 " A3=" MACSTR " freq=%d len=%zu",
95 MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), freq,
96 wpabuf_len(buf));
97
98 return offchannel_send_action(wpa_s, freq, dst, src, bssid,
99 wpabuf_head(buf), wpabuf_len(buf),
100 wait_time, wpas_nan_de_tx_status, 1);
101}
102
103
104static void wpas_nan_usd_start_tx_cb(struct wpa_radio_work *work, int deinit)
105{
106 struct wpa_supplicant *wpa_s = work->wpa_s;
107 struct wpas_nan_usd_tx_work *twork = work->ctx;
108
109 if (deinit) {
110 if (work->started) {
111 wpa_s->nan_usd_tx_work = NULL;
112 offchannel_send_action_done(wpa_s);
113 }
114 wpas_nan_usd_tx_work_free(twork);
115 return;
116 }
117
118 wpa_s->nan_usd_tx_work = work;
119
120 if (wpas_nan_de_tx_send(wpa_s, twork->freq, twork->wait_time,
121 twork->dst, twork->src, twork->bssid,
122 twork->buf) < 0)
123 wpas_nan_usd_tx_work_done(wpa_s);
124}
125
126
127static int wpas_nan_de_tx(void *ctx, unsigned int freq, unsigned int wait_time,
128 const u8 *dst, const u8 *src, const u8 *bssid,
129 const struct wpabuf *buf)
130{
131 struct wpa_supplicant *wpa_s = ctx;
132 struct wpas_nan_usd_tx_work *twork;
133
134 if (wpa_s->nan_usd_tx_work || wpa_s->nan_usd_listen_work) {
135 /* Reuse ongoing radio work */
136 return wpas_nan_de_tx_send(wpa_s, freq, wait_time, dst, src,
137 bssid, buf);
138 }
139
140 twork = os_zalloc(sizeof(*twork));
141 if (!twork)
142 return -1;
143 twork->freq = freq;
144 twork->wait_time = wait_time;
145 os_memcpy(twork->dst, dst, ETH_ALEN);
146 os_memcpy(twork->src, src, ETH_ALEN);
147 os_memcpy(twork->bssid, bssid, ETH_ALEN);
148 twork->buf = wpabuf_dup(buf);
149 if (!twork->buf) {
150 wpas_nan_usd_tx_work_free(twork);
151 return -1;
152 }
153
154 if (radio_add_work(wpa_s, freq, "nan-usd-tx", 0,
155 wpas_nan_usd_start_tx_cb, twork) < 0) {
156 wpas_nan_usd_tx_work_free(twork);
157 return -1;
158 }
159
160 return 0;
161}
162
163
164struct wpas_nan_usd_listen_work {
165 unsigned int freq;
166 unsigned int duration;
167};
168
169
170static void wpas_nan_usd_listen_work_done(struct wpa_supplicant *wpa_s)
171{
172 struct wpas_nan_usd_listen_work *lwork;
173
174 if (!wpa_s->nan_usd_listen_work)
175 return;
176
177 lwork = wpa_s->nan_usd_listen_work->ctx;
178 os_free(lwork);
179 radio_work_done(wpa_s->nan_usd_listen_work);
180 wpa_s->nan_usd_listen_work = NULL;
181}
182
183
184static void wpas_nan_usd_start_listen_cb(struct wpa_radio_work *work,
185 int deinit)
186{
187 struct wpa_supplicant *wpa_s = work->wpa_s;
188 struct wpas_nan_usd_listen_work *lwork = work->ctx;
189 unsigned int duration;
190
191 if (deinit) {
192 if (work->started) {
193 wpa_s->nan_usd_listen_work = NULL;
194 wpa_drv_cancel_remain_on_channel(wpa_s);
195 }
196 os_free(lwork);
197 return;
198 }
199
200 wpa_s->nan_usd_listen_work = work;
201
202 duration = lwork->duration;
203 if (duration > wpa_s->max_remain_on_chan)
204 duration = wpa_s->max_remain_on_chan;
205 wpa_printf(MSG_DEBUG, "NAN: Start listen on %u MHz for %u ms",
206 lwork->freq, duration);
207 if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, duration) < 0) {
208 wpa_printf(MSG_DEBUG,
209 "NAN: Failed to request the driver to remain on channel (%u MHz) for listen",
210 lwork->freq);
211 wpas_nan_usd_listen_work_done(wpa_s);
212 return;
213 }
214}
215
216
217static int wpas_nan_de_listen(void *ctx, unsigned int freq,
218 unsigned int duration)
219{
220 struct wpa_supplicant *wpa_s = ctx;
221 struct wpas_nan_usd_listen_work *lwork;
222
223 lwork = os_zalloc(sizeof(*lwork));
224 if (!lwork)
225 return -1;
226 lwork->freq = freq;
227 lwork->duration = duration;
228
229 if (radio_add_work(wpa_s, freq, "nan-usd-listen", 0,
230 wpas_nan_usd_start_listen_cb, lwork) < 0) {
231 os_free(lwork);
232 return -1;
233 }
234
235 return 0;
236}
237
238
239static void
240wpas_nan_de_discovery_result(void *ctx, int subscribe_id,
241 enum nan_service_protocol_type srv_proto_type,
242 const u8 *ssi, size_t ssi_len, int peer_publish_id,
243 const u8 *peer_addr, bool fsd, bool fsd_gas)
244{
245 struct wpa_supplicant *wpa_s = ctx;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000246
Sunil Ravic0f5d412024-09-11 22:12:49 +0000247 wpas_notify_nan_discovery_result(wpa_s, srv_proto_type, subscribe_id,
248 peer_publish_id, peer_addr, fsd,
249 fsd_gas, ssi, ssi_len);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000250}
251
252
253static void wpas_nan_de_replied(void *ctx, int publish_id, const u8 *peer_addr,
254 int peer_subscribe_id,
255 enum nan_service_protocol_type srv_proto_type,
256 const u8 *ssi, size_t ssi_len)
257{
258 struct wpa_supplicant *wpa_s = ctx;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000259
Sunil Ravic0f5d412024-09-11 22:12:49 +0000260 wpas_notify_nan_replied(wpa_s, srv_proto_type, publish_id,
261 peer_subscribe_id, peer_addr, ssi, ssi_len);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000262}
263
264
265static void wpas_nan_de_publish_terminated(void *ctx, int publish_id,
266 enum nan_de_reason reason)
267{
268 struct wpa_supplicant *wpa_s = ctx;
269
Sunil Ravic0f5d412024-09-11 22:12:49 +0000270 wpas_notify_nan_publish_terminated(wpa_s, publish_id, reason);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000271}
272
273
274static void wpas_nan_de_subscribe_terminated(void *ctx, int subscribe_id,
275 enum nan_de_reason reason)
276{
277 struct wpa_supplicant *wpa_s = ctx;
278
Sunil Ravic0f5d412024-09-11 22:12:49 +0000279 wpas_notify_nan_subscribe_terminated(wpa_s, subscribe_id, reason);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000280}
281
282
283static void wpas_nan_de_receive(void *ctx, int id, int peer_instance_id,
284 const u8 *ssi, size_t ssi_len,
285 const u8 *peer_addr)
286{
287 struct wpa_supplicant *wpa_s = ctx;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000288
Sunil Ravic0f5d412024-09-11 22:12:49 +0000289 wpas_notify_nan_receive(wpa_s, id, peer_instance_id, peer_addr,
290 ssi, ssi_len);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000291}
292
293
Sunil Ravic0f5d412024-09-11 22:12:49 +0000294#ifdef CONFIG_P2P
295static void wpas_nan_process_p2p_usd_elems(void *ctx, const u8 *buf,
296 u16 buf_len, const u8 *peer_addr,
297 unsigned int freq)
298{
299 struct wpa_supplicant *wpa_s = ctx;
300
301 wpas_p2p_process_usd_elems(wpa_s, buf, buf_len, peer_addr, freq);
302}
303#endif /* CONFIG_P2P */
304
305
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000306int wpas_nan_usd_init(struct wpa_supplicant *wpa_s)
307{
308 struct nan_callbacks cb;
Sunil Ravic0f5d412024-09-11 22:12:49 +0000309 bool offload = wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000310
311 os_memset(&cb, 0, sizeof(cb));
312 cb.ctx = wpa_s;
313 cb.tx = wpas_nan_de_tx;
314 cb.listen = wpas_nan_de_listen;
315 cb.discovery_result = wpas_nan_de_discovery_result;
316 cb.replied = wpas_nan_de_replied;
317 cb.publish_terminated = wpas_nan_de_publish_terminated;
318 cb.subscribe_terminated = wpas_nan_de_subscribe_terminated;
319 cb.receive = wpas_nan_de_receive;
Sunil Ravic0f5d412024-09-11 22:12:49 +0000320#ifdef CONFIG_P2P
321 cb.process_p2p_usd_elems = wpas_nan_process_p2p_usd_elems;
322#endif /* CONFIG_P2P */
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000323
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000324 wpa_s->nan_de = nan_de_init(wpa_s->own_addr, offload, false,
325 wpa_s->max_remain_on_chan, &cb);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000326 if (!wpa_s->nan_de)
327 return -1;
328 return 0;
329}
330
331
332void wpas_nan_usd_deinit(struct wpa_supplicant *wpa_s)
333{
334 nan_de_deinit(wpa_s->nan_de);
335 wpa_s->nan_de = NULL;
336}
337
338
339void wpas_nan_usd_rx_sdf(struct wpa_supplicant *wpa_s, const u8 *src,
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000340 const u8 *a3,
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000341 unsigned int freq, const u8 *buf, size_t len)
342{
343 if (!wpa_s->nan_de)
344 return;
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000345 nan_de_rx_sdf(wpa_s->nan_de, src, a3, freq, buf, len);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000346}
347
348
349void wpas_nan_usd_flush(struct wpa_supplicant *wpa_s)
350{
351 if (!wpa_s->nan_de)
352 return;
353 nan_de_flush(wpa_s->nan_de);
Sunil Ravic0f5d412024-09-11 22:12:49 +0000354 if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD)
355 wpas_drv_nan_flush(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000356}
357
358
359int wpas_nan_usd_publish(struct wpa_supplicant *wpa_s, const char *service_name,
360 enum nan_service_protocol_type srv_proto_type,
361 const struct wpabuf *ssi,
Sunil Ravic0f5d412024-09-11 22:12:49 +0000362 struct nan_publish_params *params, bool p2p)
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000363{
364 int publish_id;
365 struct wpabuf *elems = NULL;
Sunil Ravic0f5d412024-09-11 22:12:49 +0000366 const u8 *addr;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000367
368 if (!wpa_s->nan_de)
369 return -1;
370
Sunil Ravic0f5d412024-09-11 22:12:49 +0000371 if (p2p) {
372 elems = wpas_p2p_usd_elems(wpa_s);
373 addr = wpa_s->global->p2p_dev_addr;
374 } else {
375 addr = wpa_s->own_addr;
376 }
377
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000378 publish_id = nan_de_publish(wpa_s->nan_de, service_name, srv_proto_type,
Sunil Ravic0f5d412024-09-11 22:12:49 +0000379 ssi, elems, params, p2p);
380 if (publish_id >= 1 &&
381 (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) &&
382 wpas_drv_nan_publish(wpa_s, addr, publish_id, service_name,
383 nan_de_get_service_id(wpa_s->nan_de,
384 publish_id),
385 srv_proto_type, ssi, elems, params) < 0) {
386 nan_de_cancel_publish(wpa_s->nan_de, publish_id);
387 publish_id = -1;
388 }
389
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000390 wpabuf_free(elems);
391 return publish_id;
392}
393
394
395void wpas_nan_usd_cancel_publish(struct wpa_supplicant *wpa_s, int publish_id)
396{
397 if (!wpa_s->nan_de)
398 return;
399 nan_de_cancel_publish(wpa_s->nan_de, publish_id);
Sunil Ravic0f5d412024-09-11 22:12:49 +0000400 if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD)
401 wpas_drv_nan_cancel_publish(wpa_s, publish_id);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000402}
403
404
405int wpas_nan_usd_update_publish(struct wpa_supplicant *wpa_s, int publish_id,
406 const struct wpabuf *ssi)
407{
Sunil Ravic0f5d412024-09-11 22:12:49 +0000408 int ret;
409
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000410 if (!wpa_s->nan_de)
411 return -1;
Sunil Ravic0f5d412024-09-11 22:12:49 +0000412 ret = nan_de_update_publish(wpa_s->nan_de, publish_id, ssi);
413 if (ret == 0 && (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) &&
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000414 wpas_drv_nan_update_publish(wpa_s, publish_id, ssi) < 0)
Sunil Ravic0f5d412024-09-11 22:12:49 +0000415 return -1;
416 return ret;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000417}
418
419
420int wpas_nan_usd_subscribe(struct wpa_supplicant *wpa_s,
421 const char *service_name,
422 enum nan_service_protocol_type srv_proto_type,
423 const struct wpabuf *ssi,
Sunil Ravic0f5d412024-09-11 22:12:49 +0000424 struct nan_subscribe_params *params, bool p2p)
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000425{
426 int subscribe_id;
427 struct wpabuf *elems = NULL;
Sunil Ravic0f5d412024-09-11 22:12:49 +0000428 const u8 *addr;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000429
430 if (!wpa_s->nan_de)
431 return -1;
432
Sunil Ravic0f5d412024-09-11 22:12:49 +0000433 if (p2p) {
434 elems = wpas_p2p_usd_elems(wpa_s);
435 addr = wpa_s->global->p2p_dev_addr;
436 } else {
437 addr = wpa_s->own_addr;
438 }
439
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000440 subscribe_id = nan_de_subscribe(wpa_s->nan_de, service_name,
Sunil Ravic0f5d412024-09-11 22:12:49 +0000441 srv_proto_type, ssi, elems, params,
442 p2p);
443 if (subscribe_id >= 1 &&
444 (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) &&
445 wpas_drv_nan_subscribe(wpa_s, addr, subscribe_id, service_name,
446 nan_de_get_service_id(wpa_s->nan_de,
447 subscribe_id),
448 srv_proto_type, ssi, elems, params) < 0) {
449 nan_de_cancel_subscribe(wpa_s->nan_de, subscribe_id);
450 subscribe_id = -1;
451 }
452
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000453 wpabuf_free(elems);
454 return subscribe_id;
455}
456
457
458void wpas_nan_usd_cancel_subscribe(struct wpa_supplicant *wpa_s,
459 int subscribe_id)
460{
461 if (!wpa_s->nan_de)
462 return;
463 nan_de_cancel_subscribe(wpa_s->nan_de, subscribe_id);
Sunil Ravic0f5d412024-09-11 22:12:49 +0000464 if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD)
465 wpas_drv_nan_cancel_subscribe(wpa_s, subscribe_id);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000466}
467
468
469int wpas_nan_usd_transmit(struct wpa_supplicant *wpa_s, int handle,
470 const struct wpabuf *ssi, const struct wpabuf *elems,
471 const u8 *peer_addr, u8 req_instance_id)
472{
473 if (!wpa_s->nan_de)
474 return -1;
475 return nan_de_transmit(wpa_s->nan_de, handle, ssi, elems, peer_addr,
476 req_instance_id);
477}
478
479
480void wpas_nan_usd_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
481 unsigned int freq, unsigned int duration)
482{
483 wpas_nan_usd_listen_work_done(wpa_s);
484
485 if (wpa_s->nan_de)
486 nan_de_listen_started(wpa_s->nan_de, freq, duration);
487}
488
489
490void wpas_nan_usd_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
491 unsigned int freq)
492{
493 if (wpa_s->nan_de)
494 nan_de_listen_ended(wpa_s->nan_de, freq);
495}
496
497
498void wpas_nan_usd_tx_wait_expire(struct wpa_supplicant *wpa_s)
499{
500 wpas_nan_usd_tx_work_done(wpa_s);
501
502 if (wpa_s->nan_de)
503 nan_de_tx_wait_ended(wpa_s->nan_de);
504}
505
506
507int * wpas_nan_usd_all_freqs(struct wpa_supplicant *wpa_s)
508{
509 int i, j;
510 int *freqs = NULL;
511
512 if (!wpa_s->hw.modes)
513 return NULL;
514
515 for (i = 0; i < wpa_s->hw.num_modes; i++) {
516 struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
517
518 for (j = 0; j < mode->num_channels; j++) {
519 struct hostapd_channel_data *chan = &mode->channels[j];
520
521 /* All 20 MHz channels on 2.4 and 5 GHz band */
522 if (chan->freq < 2412 || chan->freq > 5900)
523 continue;
524
525 /* that allow frames to be transmitted */
526 if (chan->flag & (HOSTAPD_CHAN_DISABLED |
527 HOSTAPD_CHAN_NO_IR |
528 HOSTAPD_CHAN_RADAR))
529 continue;
530
531 int_array_add_unique(&freqs, chan->freq);
532 }
533 }
534
535 return freqs;
536}