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