Home | History | Annotate | Line # | Download | only in ap
      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 
     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 
     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
     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
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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