blob: 1125f950f882e081fb018b13386933431e7c2f70 [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 Ravic0f5d412024-09-11 22:12:49 +0000324 wpa_s->nan_de = nan_de_init(wpa_s->own_addr, offload, false, &cb);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000325 if (!wpa_s->nan_de)
326 return -1;
327 return 0;
328}
329
330
331void wpas_nan_usd_deinit(struct wpa_supplicant *wpa_s)
332{
333 nan_de_deinit(wpa_s->nan_de);
334 wpa_s->nan_de = NULL;
335}
336
337
338void wpas_nan_usd_rx_sdf(struct wpa_supplicant *wpa_s, const u8 *src,
339 unsigned int freq, const u8 *buf, size_t len)
340{
341 if (!wpa_s->nan_de)
342 return;
343 nan_de_rx_sdf(wpa_s->nan_de, src, freq, buf, len);
344}
345
346
347void wpas_nan_usd_flush(struct wpa_supplicant *wpa_s)
348{
349 if (!wpa_s->nan_de)
350 return;
351 nan_de_flush(wpa_s->nan_de);
Sunil Ravic0f5d412024-09-11 22:12:49 +0000352 if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD)
353 wpas_drv_nan_flush(wpa_s);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000354}
355
356
357int wpas_nan_usd_publish(struct wpa_supplicant *wpa_s, const char *service_name,
358 enum nan_service_protocol_type srv_proto_type,
359 const struct wpabuf *ssi,
Sunil Ravic0f5d412024-09-11 22:12:49 +0000360 struct nan_publish_params *params, bool p2p)
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000361{
362 int publish_id;
363 struct wpabuf *elems = NULL;
Sunil Ravic0f5d412024-09-11 22:12:49 +0000364 const u8 *addr;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000365
366 if (!wpa_s->nan_de)
367 return -1;
368
Sunil Ravic0f5d412024-09-11 22:12:49 +0000369 if (p2p) {
370 elems = wpas_p2p_usd_elems(wpa_s);
371 addr = wpa_s->global->p2p_dev_addr;
372 } else {
373 addr = wpa_s->own_addr;
374 }
375
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000376 publish_id = nan_de_publish(wpa_s->nan_de, service_name, srv_proto_type,
Sunil Ravic0f5d412024-09-11 22:12:49 +0000377 ssi, elems, params, p2p);
378 if (publish_id >= 1 &&
379 (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) &&
380 wpas_drv_nan_publish(wpa_s, addr, publish_id, service_name,
381 nan_de_get_service_id(wpa_s->nan_de,
382 publish_id),
383 srv_proto_type, ssi, elems, params) < 0) {
384 nan_de_cancel_publish(wpa_s->nan_de, publish_id);
385 publish_id = -1;
386 }
387
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000388 wpabuf_free(elems);
389 return publish_id;
390}
391
392
393void wpas_nan_usd_cancel_publish(struct wpa_supplicant *wpa_s, int publish_id)
394{
395 if (!wpa_s->nan_de)
396 return;
397 nan_de_cancel_publish(wpa_s->nan_de, publish_id);
Sunil Ravic0f5d412024-09-11 22:12:49 +0000398 if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD)
399 wpas_drv_nan_cancel_publish(wpa_s, publish_id);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000400}
401
402
403int wpas_nan_usd_update_publish(struct wpa_supplicant *wpa_s, int publish_id,
404 const struct wpabuf *ssi)
405{
Sunil Ravic0f5d412024-09-11 22:12:49 +0000406 int ret;
407
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000408 if (!wpa_s->nan_de)
409 return -1;
Sunil Ravic0f5d412024-09-11 22:12:49 +0000410 ret = nan_de_update_publish(wpa_s->nan_de, publish_id, ssi);
411 if (ret == 0 && (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) &&
412 wpas_drv_nan_cancel_publish(wpa_s, publish_id) < 0)
413 return -1;
414 return ret;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000415}
416
417
418int 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,
Sunil Ravic0f5d412024-09-11 22:12:49 +0000422 struct nan_subscribe_params *params, bool p2p)
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000423{
424 int subscribe_id;
425 struct wpabuf *elems = NULL;
Sunil Ravic0f5d412024-09-11 22:12:49 +0000426 const u8 *addr;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000427
428 if (!wpa_s->nan_de)
429 return -1;
430
Sunil Ravic0f5d412024-09-11 22:12:49 +0000431 if (p2p) {
432 elems = wpas_p2p_usd_elems(wpa_s);
433 addr = wpa_s->global->p2p_dev_addr;
434 } else {
435 addr = wpa_s->own_addr;
436 }
437
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000438 subscribe_id = nan_de_subscribe(wpa_s->nan_de, service_name,
Sunil Ravic0f5d412024-09-11 22:12:49 +0000439 srv_proto_type, ssi, elems, params,
440 p2p);
441 if (subscribe_id >= 1 &&
442 (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) &&
443 wpas_drv_nan_subscribe(wpa_s, addr, subscribe_id, service_name,
444 nan_de_get_service_id(wpa_s->nan_de,
445 subscribe_id),
446 srv_proto_type, ssi, elems, params) < 0) {
447 nan_de_cancel_subscribe(wpa_s->nan_de, subscribe_id);
448 subscribe_id = -1;
449 }
450
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000451 wpabuf_free(elems);
452 return subscribe_id;
453}
454
455
456void wpas_nan_usd_cancel_subscribe(struct wpa_supplicant *wpa_s,
457 int subscribe_id)
458{
459 if (!wpa_s->nan_de)
460 return;
461 nan_de_cancel_subscribe(wpa_s->nan_de, subscribe_id);
Sunil Ravic0f5d412024-09-11 22:12:49 +0000462 if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD)
463 wpas_drv_nan_cancel_subscribe(wpa_s, subscribe_id);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000464}
465
466
467int wpas_nan_usd_transmit(struct wpa_supplicant *wpa_s, int handle,
468 const struct wpabuf *ssi, const struct wpabuf *elems,
469 const u8 *peer_addr, u8 req_instance_id)
470{
471 if (!wpa_s->nan_de)
472 return -1;
473 return nan_de_transmit(wpa_s->nan_de, handle, ssi, elems, peer_addr,
474 req_instance_id);
475}
476
477
478void wpas_nan_usd_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
479 unsigned int freq, unsigned int duration)
480{
481 wpas_nan_usd_listen_work_done(wpa_s);
482
483 if (wpa_s->nan_de)
484 nan_de_listen_started(wpa_s->nan_de, freq, duration);
485}
486
487
488void wpas_nan_usd_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
489 unsigned int freq)
490{
491 if (wpa_s->nan_de)
492 nan_de_listen_ended(wpa_s->nan_de, freq);
493}
494
495
496void wpas_nan_usd_tx_wait_expire(struct wpa_supplicant *wpa_s)
497{
498 wpas_nan_usd_tx_work_done(wpa_s);
499
500 if (wpa_s->nan_de)
501 nan_de_tx_wait_ended(wpa_s->nan_de);
502}
503
504
505int * wpas_nan_usd_all_freqs(struct wpa_supplicant *wpa_s)
506{
507 int i, j;
508 int *freqs = NULL;
509
510 if (!wpa_s->hw.modes)
511 return NULL;
512
513 for (i = 0; i < wpa_s->hw.num_modes; i++) {
514 struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
515
516 for (j = 0; j < mode->num_channels; j++) {
517 struct hostapd_channel_data *chan = &mode->channels[j];
518
519 /* All 20 MHz channels on 2.4 and 5 GHz band */
520 if (chan->freq < 2412 || chan->freq > 5900)
521 continue;
522
523 /* that allow frames to be transmitted */
524 if (chan->flag & (HOSTAPD_CHAN_DISABLED |
525 HOSTAPD_CHAN_NO_IR |
526 HOSTAPD_CHAN_RADAR))
527 continue;
528
529 int_array_add_unique(&freqs, chan->freq);
530 }
531 }
532
533 return freqs;
534}