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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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