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