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