xref: /freebsd/contrib/wpa/src/ap/nan_usd_ap.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
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/wpa_ctrl.h"
13*a90b9d01SCy Schubert #include "common/nan_de.h"
14*a90b9d01SCy Schubert #include "hostapd.h"
15*a90b9d01SCy Schubert #include "ap_drv_ops.h"
16*a90b9d01SCy Schubert #include "nan_usd_ap.h"
17*a90b9d01SCy Schubert 
18*a90b9d01SCy Schubert 
hostapd_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)19*a90b9d01SCy Schubert static int hostapd_nan_de_tx(void *ctx, unsigned int freq,
20*a90b9d01SCy Schubert 			     unsigned int wait_time,
21*a90b9d01SCy Schubert 			     const u8 *dst, const u8 *src, const u8 *bssid,
22*a90b9d01SCy Schubert 			     const struct wpabuf *buf)
23*a90b9d01SCy Schubert {
24*a90b9d01SCy Schubert 	struct hostapd_data *hapd = ctx;
25*a90b9d01SCy Schubert 
26*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "NAN: TX NAN SDF A1=" MACSTR " A2=" MACSTR
27*a90b9d01SCy Schubert 		   " A3=" MACSTR " len=%zu",
28*a90b9d01SCy Schubert 		   MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
29*a90b9d01SCy Schubert 		   wpabuf_len(buf));
30*a90b9d01SCy Schubert 
31*a90b9d01SCy Schubert 	/* TODO: Force use of OFDM */
32*a90b9d01SCy Schubert 	return hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
33*a90b9d01SCy Schubert 				       wpabuf_head(buf), wpabuf_len(buf));
34*a90b9d01SCy Schubert }
35*a90b9d01SCy Schubert 
36*a90b9d01SCy Schubert 
hostapd_nan_de_listen(void * ctx,unsigned int freq,unsigned int duration)37*a90b9d01SCy Schubert static int hostapd_nan_de_listen(void *ctx, unsigned int freq,
38*a90b9d01SCy Schubert 			      unsigned int duration)
39*a90b9d01SCy Schubert {
40*a90b9d01SCy Schubert 	return 0;
41*a90b9d01SCy Schubert }
42*a90b9d01SCy Schubert 
43*a90b9d01SCy Schubert 
44*a90b9d01SCy Schubert static void
hostapd_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)45*a90b9d01SCy Schubert hostapd_nan_de_discovery_result(void *ctx, int subscribe_id,
46*a90b9d01SCy Schubert 				enum nan_service_protocol_type srv_proto_type,
47*a90b9d01SCy Schubert 				const u8 *ssi, size_t ssi_len,
48*a90b9d01SCy Schubert 				int peer_publish_id, const u8 *peer_addr,
49*a90b9d01SCy Schubert 				bool fsd, bool fsd_gas)
50*a90b9d01SCy Schubert {
51*a90b9d01SCy Schubert 	struct hostapd_data *hapd = ctx;
52*a90b9d01SCy Schubert 	char *ssi_hex;
53*a90b9d01SCy Schubert 
54*a90b9d01SCy Schubert 	ssi_hex = os_zalloc(2 * ssi_len + 1);
55*a90b9d01SCy Schubert 	if (!ssi_hex)
56*a90b9d01SCy Schubert 		return;
57*a90b9d01SCy Schubert 	if (ssi)
58*a90b9d01SCy Schubert 		wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
59*a90b9d01SCy Schubert 	wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_DISCOVERY_RESULT
60*a90b9d01SCy Schubert 		"subscribe_id=%d publish_id=%d address=" MACSTR
61*a90b9d01SCy Schubert 		" fsd=%d fsd_gas=%d srv_proto_type=%u ssi=%s",
62*a90b9d01SCy Schubert 		subscribe_id, peer_publish_id, MAC2STR(peer_addr),
63*a90b9d01SCy Schubert 		fsd, fsd_gas, srv_proto_type, ssi_hex);
64*a90b9d01SCy Schubert 	os_free(ssi_hex);
65*a90b9d01SCy Schubert }
66*a90b9d01SCy Schubert 
67*a90b9d01SCy Schubert 
68*a90b9d01SCy Schubert static void
hostapd_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)69*a90b9d01SCy Schubert hostapd_nan_de_replied(void *ctx, int publish_id, const u8 *peer_addr,
70*a90b9d01SCy Schubert 		       int peer_subscribe_id,
71*a90b9d01SCy Schubert 		       enum nan_service_protocol_type srv_proto_type,
72*a90b9d01SCy Schubert 		       const u8 *ssi, size_t ssi_len)
73*a90b9d01SCy Schubert {
74*a90b9d01SCy Schubert 	struct hostapd_data *hapd = ctx;
75*a90b9d01SCy Schubert 	char *ssi_hex;
76*a90b9d01SCy Schubert 
77*a90b9d01SCy Schubert 	ssi_hex = os_zalloc(2 * ssi_len + 1);
78*a90b9d01SCy Schubert 	if (!ssi_hex)
79*a90b9d01SCy Schubert 		return;
80*a90b9d01SCy Schubert 	if (ssi)
81*a90b9d01SCy Schubert 		wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
82*a90b9d01SCy Schubert 	wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_REPLIED
83*a90b9d01SCy Schubert 		"publish_id=%d address=" MACSTR
84*a90b9d01SCy Schubert 		" subscribe_id=%d srv_proto_type=%u ssi=%s",
85*a90b9d01SCy Schubert 		publish_id, MAC2STR(peer_addr), peer_subscribe_id,
86*a90b9d01SCy Schubert 		srv_proto_type, ssi_hex);
87*a90b9d01SCy Schubert 	os_free(ssi_hex);
88*a90b9d01SCy Schubert }
89*a90b9d01SCy Schubert 
90*a90b9d01SCy Schubert 
nan_reason_txt(enum nan_de_reason reason)91*a90b9d01SCy Schubert static const char * nan_reason_txt(enum nan_de_reason reason)
92*a90b9d01SCy Schubert {
93*a90b9d01SCy Schubert 	switch (reason) {
94*a90b9d01SCy Schubert 	case NAN_DE_REASON_TIMEOUT:
95*a90b9d01SCy Schubert 		return "timeout";
96*a90b9d01SCy Schubert 	case NAN_DE_REASON_USER_REQUEST:
97*a90b9d01SCy Schubert 		return "user-request";
98*a90b9d01SCy Schubert 	case NAN_DE_REASON_FAILURE:
99*a90b9d01SCy Schubert 		return "failure";
100*a90b9d01SCy Schubert 	}
101*a90b9d01SCy Schubert 
102*a90b9d01SCy Schubert 	return "unknown";
103*a90b9d01SCy Schubert }
104*a90b9d01SCy Schubert 
105*a90b9d01SCy Schubert 
hostapd_nan_de_publish_terminated(void * ctx,int publish_id,enum nan_de_reason reason)106*a90b9d01SCy Schubert static void hostapd_nan_de_publish_terminated(void *ctx, int publish_id,
107*a90b9d01SCy Schubert 					      enum nan_de_reason reason)
108*a90b9d01SCy Schubert {
109*a90b9d01SCy Schubert 	struct hostapd_data *hapd = ctx;
110*a90b9d01SCy Schubert 
111*a90b9d01SCy Schubert 	wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_PUBLISH_TERMINATED
112*a90b9d01SCy Schubert 		"publish_id=%d reason=%s",
113*a90b9d01SCy Schubert 		publish_id, nan_reason_txt(reason));
114*a90b9d01SCy Schubert }
115*a90b9d01SCy Schubert 
116*a90b9d01SCy Schubert 
hostapd_nan_de_subscribe_terminated(void * ctx,int subscribe_id,enum nan_de_reason reason)117*a90b9d01SCy Schubert static void hostapd_nan_de_subscribe_terminated(void *ctx, int subscribe_id,
118*a90b9d01SCy Schubert 						enum nan_de_reason reason)
119*a90b9d01SCy Schubert {
120*a90b9d01SCy Schubert 	struct hostapd_data *hapd = ctx;
121*a90b9d01SCy Schubert 
122*a90b9d01SCy Schubert 	wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_SUBSCRIBE_TERMINATED
123*a90b9d01SCy Schubert 		"subscribe_id=%d reason=%s",
124*a90b9d01SCy Schubert 		subscribe_id, nan_reason_txt(reason));
125*a90b9d01SCy Schubert }
126*a90b9d01SCy Schubert 
127*a90b9d01SCy Schubert 
hostapd_nan_de_receive(void * ctx,int id,int peer_instance_id,const u8 * ssi,size_t ssi_len,const u8 * peer_addr)128*a90b9d01SCy Schubert static void hostapd_nan_de_receive(void *ctx, int id, int peer_instance_id,
129*a90b9d01SCy Schubert 				   const u8 *ssi, size_t ssi_len,
130*a90b9d01SCy Schubert 				   const u8 *peer_addr)
131*a90b9d01SCy Schubert {
132*a90b9d01SCy Schubert 	struct hostapd_data *hapd = ctx;
133*a90b9d01SCy Schubert 	char *ssi_hex;
134*a90b9d01SCy Schubert 
135*a90b9d01SCy Schubert 	ssi_hex = os_zalloc(2 * ssi_len + 1);
136*a90b9d01SCy Schubert 	if (!ssi_hex)
137*a90b9d01SCy Schubert 		return;
138*a90b9d01SCy Schubert 	if (ssi)
139*a90b9d01SCy Schubert 		wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
140*a90b9d01SCy Schubert 	wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_RECEIVE
141*a90b9d01SCy Schubert 		"id=%d peer_instance_id=%d address=" MACSTR " ssi=%s",
142*a90b9d01SCy Schubert 		id, peer_instance_id, MAC2STR(peer_addr), ssi_hex);
143*a90b9d01SCy Schubert 	os_free(ssi_hex);
144*a90b9d01SCy Schubert }
145*a90b9d01SCy Schubert 
146*a90b9d01SCy Schubert 
hostapd_nan_usd_init(struct hostapd_data * hapd)147*a90b9d01SCy Schubert int hostapd_nan_usd_init(struct hostapd_data *hapd)
148*a90b9d01SCy Schubert {
149*a90b9d01SCy Schubert 	struct nan_callbacks cb;
150*a90b9d01SCy Schubert 
151*a90b9d01SCy Schubert 	os_memset(&cb, 0, sizeof(cb));
152*a90b9d01SCy Schubert 	cb.ctx = hapd;
153*a90b9d01SCy Schubert 	cb.tx = hostapd_nan_de_tx;
154*a90b9d01SCy Schubert 	cb.listen = hostapd_nan_de_listen;
155*a90b9d01SCy Schubert 	cb.discovery_result = hostapd_nan_de_discovery_result;
156*a90b9d01SCy Schubert 	cb.replied = hostapd_nan_de_replied;
157*a90b9d01SCy Schubert 	cb.publish_terminated = hostapd_nan_de_publish_terminated;
158*a90b9d01SCy Schubert 	cb.subscribe_terminated = hostapd_nan_de_subscribe_terminated;
159*a90b9d01SCy Schubert 	cb.receive = hostapd_nan_de_receive;
160*a90b9d01SCy Schubert 
161*a90b9d01SCy Schubert 	hapd->nan_de = nan_de_init(hapd->own_addr, true, &cb);
162*a90b9d01SCy Schubert 	if (!hapd->nan_de)
163*a90b9d01SCy Schubert 		return -1;
164*a90b9d01SCy Schubert 	return 0;
165*a90b9d01SCy Schubert }
166*a90b9d01SCy Schubert 
167*a90b9d01SCy Schubert 
hostapd_nan_usd_deinit(struct hostapd_data * hapd)168*a90b9d01SCy Schubert void hostapd_nan_usd_deinit(struct hostapd_data *hapd)
169*a90b9d01SCy Schubert {
170*a90b9d01SCy Schubert 	nan_de_deinit(hapd->nan_de);
171*a90b9d01SCy Schubert 	hapd->nan_de = NULL;
172*a90b9d01SCy Schubert }
173*a90b9d01SCy Schubert 
174*a90b9d01SCy Schubert 
hostapd_nan_usd_rx_sdf(struct hostapd_data * hapd,const u8 * src,unsigned int freq,const u8 * buf,size_t len)175*a90b9d01SCy Schubert void hostapd_nan_usd_rx_sdf(struct hostapd_data *hapd, const u8 *src,
176*a90b9d01SCy Schubert 			    unsigned int freq, const u8 *buf, size_t len)
177*a90b9d01SCy Schubert {
178*a90b9d01SCy Schubert 	if (!hapd->nan_de)
179*a90b9d01SCy Schubert 		return;
180*a90b9d01SCy Schubert 	nan_de_rx_sdf(hapd->nan_de, src, freq, buf, len);
181*a90b9d01SCy Schubert }
182*a90b9d01SCy Schubert 
183*a90b9d01SCy Schubert 
hostapd_nan_usd_flush(struct hostapd_data * hapd)184*a90b9d01SCy Schubert void hostapd_nan_usd_flush(struct hostapd_data *hapd)
185*a90b9d01SCy Schubert {
186*a90b9d01SCy Schubert 	if (!hapd->nan_de)
187*a90b9d01SCy Schubert 		return;
188*a90b9d01SCy Schubert 	nan_de_flush(hapd->nan_de);
189*a90b9d01SCy Schubert }
190*a90b9d01SCy Schubert 
191*a90b9d01SCy Schubert 
hostapd_nan_usd_publish(struct hostapd_data * hapd,const char * service_name,enum nan_service_protocol_type srv_proto_type,const struct wpabuf * ssi,struct nan_publish_params * params)192*a90b9d01SCy Schubert int hostapd_nan_usd_publish(struct hostapd_data *hapd, const char *service_name,
193*a90b9d01SCy Schubert 			    enum nan_service_protocol_type srv_proto_type,
194*a90b9d01SCy Schubert 			    const struct wpabuf *ssi,
195*a90b9d01SCy Schubert 			    struct nan_publish_params *params)
196*a90b9d01SCy Schubert {
197*a90b9d01SCy Schubert 	int publish_id;
198*a90b9d01SCy Schubert 	struct wpabuf *elems = NULL;
199*a90b9d01SCy Schubert 
200*a90b9d01SCy Schubert 	if (!hapd->nan_de)
201*a90b9d01SCy Schubert 		return -1;
202*a90b9d01SCy Schubert 
203*a90b9d01SCy Schubert 	publish_id = nan_de_publish(hapd->nan_de, service_name, srv_proto_type,
204*a90b9d01SCy Schubert 				    ssi, elems, params);
205*a90b9d01SCy Schubert 	wpabuf_free(elems);
206*a90b9d01SCy Schubert 	return publish_id;
207*a90b9d01SCy Schubert }
208*a90b9d01SCy Schubert 
209*a90b9d01SCy Schubert 
hostapd_nan_usd_cancel_publish(struct hostapd_data * hapd,int publish_id)210*a90b9d01SCy Schubert void hostapd_nan_usd_cancel_publish(struct hostapd_data *hapd, int publish_id)
211*a90b9d01SCy Schubert {
212*a90b9d01SCy Schubert 	if (!hapd->nan_de)
213*a90b9d01SCy Schubert 		return;
214*a90b9d01SCy Schubert 	nan_de_cancel_publish(hapd->nan_de, publish_id);
215*a90b9d01SCy Schubert }
216*a90b9d01SCy Schubert 
217*a90b9d01SCy Schubert 
hostapd_nan_usd_update_publish(struct hostapd_data * hapd,int publish_id,const struct wpabuf * ssi)218*a90b9d01SCy Schubert int hostapd_nan_usd_update_publish(struct hostapd_data *hapd, int publish_id,
219*a90b9d01SCy Schubert 				   const struct wpabuf *ssi)
220*a90b9d01SCy Schubert {
221*a90b9d01SCy Schubert 	int ret;
222*a90b9d01SCy Schubert 
223*a90b9d01SCy Schubert 	if (!hapd->nan_de)
224*a90b9d01SCy Schubert 		return -1;
225*a90b9d01SCy Schubert 	ret = nan_de_update_publish(hapd->nan_de, publish_id, ssi);
226*a90b9d01SCy Schubert 	return ret;
227*a90b9d01SCy Schubert }
228*a90b9d01SCy Schubert 
229*a90b9d01SCy Schubert 
hostapd_nan_usd_subscribe(struct hostapd_data * hapd,const char * service_name,enum nan_service_protocol_type srv_proto_type,const struct wpabuf * ssi,struct nan_subscribe_params * params)230*a90b9d01SCy Schubert int hostapd_nan_usd_subscribe(struct hostapd_data *hapd,
231*a90b9d01SCy Schubert 			      const char *service_name,
232*a90b9d01SCy Schubert 			      enum nan_service_protocol_type srv_proto_type,
233*a90b9d01SCy Schubert 			      const struct wpabuf *ssi,
234*a90b9d01SCy Schubert 			      struct nan_subscribe_params *params)
235*a90b9d01SCy Schubert {
236*a90b9d01SCy Schubert 	int subscribe_id;
237*a90b9d01SCy Schubert 	struct wpabuf *elems = NULL;
238*a90b9d01SCy Schubert 
239*a90b9d01SCy Schubert 	if (!hapd->nan_de)
240*a90b9d01SCy Schubert 		return -1;
241*a90b9d01SCy Schubert 
242*a90b9d01SCy Schubert 	subscribe_id = nan_de_subscribe(hapd->nan_de, service_name,
243*a90b9d01SCy Schubert 					srv_proto_type, ssi, elems, params);
244*a90b9d01SCy Schubert 	wpabuf_free(elems);
245*a90b9d01SCy Schubert 	return subscribe_id;
246*a90b9d01SCy Schubert }
247*a90b9d01SCy Schubert 
248*a90b9d01SCy Schubert 
hostapd_nan_usd_cancel_subscribe(struct hostapd_data * hapd,int subscribe_id)249*a90b9d01SCy Schubert void hostapd_nan_usd_cancel_subscribe(struct hostapd_data *hapd,
250*a90b9d01SCy Schubert 				      int subscribe_id)
251*a90b9d01SCy Schubert {
252*a90b9d01SCy Schubert 	if (!hapd->nan_de)
253*a90b9d01SCy Schubert 		return;
254*a90b9d01SCy Schubert 	nan_de_cancel_subscribe(hapd->nan_de, subscribe_id);
255*a90b9d01SCy Schubert }
256*a90b9d01SCy Schubert 
257*a90b9d01SCy Schubert 
hostapd_nan_usd_transmit(struct hostapd_data * hapd,int handle,const struct wpabuf * ssi,const struct wpabuf * elems,const u8 * peer_addr,u8 req_instance_id)258*a90b9d01SCy Schubert int hostapd_nan_usd_transmit(struct hostapd_data *hapd, int handle,
259*a90b9d01SCy Schubert 			     const struct wpabuf *ssi,
260*a90b9d01SCy Schubert 			     const struct wpabuf *elems,
261*a90b9d01SCy Schubert 			     const u8 *peer_addr, u8 req_instance_id)
262*a90b9d01SCy Schubert {
263*a90b9d01SCy Schubert 	if (!hapd->nan_de)
264*a90b9d01SCy Schubert 		return -1;
265*a90b9d01SCy Schubert 	return nan_de_transmit(hapd->nan_de, handle, ssi, elems, peer_addr,
266*a90b9d01SCy Schubert 			       req_instance_id);
267*a90b9d01SCy Schubert }
268