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/nan_de.h" 13*a90b9d01SCy Schubert #include "wpa_supplicant_i.h" 14*a90b9d01SCy Schubert #include "offchannel.h" 15*a90b9d01SCy Schubert #include "driver_i.h" 16*a90b9d01SCy Schubert #include "nan_usd.h" 17*a90b9d01SCy Schubert 18*a90b9d01SCy Schubert 19*a90b9d01SCy Schubert static const char * 20*a90b9d01SCy Schubert tx_status_result_txt(enum offchannel_send_action_result result) 21*a90b9d01SCy Schubert { 22*a90b9d01SCy Schubert switch (result) { 23*a90b9d01SCy Schubert case OFFCHANNEL_SEND_ACTION_SUCCESS: 24*a90b9d01SCy Schubert return "success"; 25*a90b9d01SCy Schubert case OFFCHANNEL_SEND_ACTION_NO_ACK: 26*a90b9d01SCy Schubert return "no-ack"; 27*a90b9d01SCy Schubert case OFFCHANNEL_SEND_ACTION_FAILED: 28*a90b9d01SCy Schubert return "failed"; 29*a90b9d01SCy Schubert } 30*a90b9d01SCy Schubert 31*a90b9d01SCy Schubert return "?"; 32*a90b9d01SCy Schubert } 33*a90b9d01SCy Schubert 34*a90b9d01SCy Schubert 35*a90b9d01SCy Schubert static void wpas_nan_de_tx_status(struct wpa_supplicant *wpa_s, 36*a90b9d01SCy Schubert unsigned int freq, const u8 *dst, 37*a90b9d01SCy Schubert const u8 *src, const u8 *bssid, 38*a90b9d01SCy Schubert const u8 *data, size_t data_len, 39*a90b9d01SCy Schubert enum offchannel_send_action_result result) 40*a90b9d01SCy Schubert { 41*a90b9d01SCy Schubert if (!wpa_s->nan_de) 42*a90b9d01SCy Schubert return; 43*a90b9d01SCy Schubert 44*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "NAN: TX status A1=" MACSTR " A2=" MACSTR 45*a90b9d01SCy Schubert " A3=" MACSTR " freq=%d len=%zu result=%s", 46*a90b9d01SCy Schubert MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), freq, 47*a90b9d01SCy Schubert data_len, tx_status_result_txt(result)); 48*a90b9d01SCy Schubert 49*a90b9d01SCy Schubert nan_de_tx_status(wpa_s->nan_de, freq, dst); 50*a90b9d01SCy Schubert } 51*a90b9d01SCy Schubert 52*a90b9d01SCy Schubert 53*a90b9d01SCy Schubert struct wpas_nan_usd_tx_work { 54*a90b9d01SCy Schubert unsigned int freq; 55*a90b9d01SCy Schubert unsigned int wait_time; 56*a90b9d01SCy Schubert u8 dst[ETH_ALEN]; 57*a90b9d01SCy Schubert u8 src[ETH_ALEN]; 58*a90b9d01SCy Schubert u8 bssid[ETH_ALEN]; 59*a90b9d01SCy Schubert struct wpabuf *buf; 60*a90b9d01SCy Schubert }; 61*a90b9d01SCy Schubert 62*a90b9d01SCy Schubert 63*a90b9d01SCy Schubert static void wpas_nan_usd_tx_work_free(struct wpas_nan_usd_tx_work *twork) 64*a90b9d01SCy Schubert { 65*a90b9d01SCy Schubert if (!twork) 66*a90b9d01SCy Schubert return; 67*a90b9d01SCy Schubert wpabuf_free(twork->buf); 68*a90b9d01SCy Schubert os_free(twork); 69*a90b9d01SCy Schubert } 70*a90b9d01SCy Schubert 71*a90b9d01SCy Schubert 72*a90b9d01SCy Schubert static void wpas_nan_usd_tx_work_done(struct wpa_supplicant *wpa_s) 73*a90b9d01SCy Schubert { 74*a90b9d01SCy Schubert struct wpas_nan_usd_tx_work *twork; 75*a90b9d01SCy Schubert 76*a90b9d01SCy Schubert if (!wpa_s->nan_usd_tx_work) 77*a90b9d01SCy Schubert return; 78*a90b9d01SCy Schubert 79*a90b9d01SCy Schubert twork = wpa_s->nan_usd_tx_work->ctx; 80*a90b9d01SCy Schubert wpas_nan_usd_tx_work_free(twork); 81*a90b9d01SCy Schubert radio_work_done(wpa_s->nan_usd_tx_work); 82*a90b9d01SCy Schubert wpa_s->nan_usd_tx_work = NULL; 83*a90b9d01SCy Schubert } 84*a90b9d01SCy Schubert 85*a90b9d01SCy Schubert 86*a90b9d01SCy Schubert static int wpas_nan_de_tx_send(struct wpa_supplicant *wpa_s, unsigned int freq, 87*a90b9d01SCy Schubert unsigned int wait_time, const u8 *dst, 88*a90b9d01SCy Schubert const u8 *src, const u8 *bssid, 89*a90b9d01SCy Schubert const struct wpabuf *buf) 90*a90b9d01SCy Schubert { 91*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "NAN: TX NAN SDF A1=" MACSTR " A2=" MACSTR 92*a90b9d01SCy Schubert " A3=" MACSTR " freq=%d len=%zu", 93*a90b9d01SCy Schubert MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), freq, 94*a90b9d01SCy Schubert wpabuf_len(buf)); 95*a90b9d01SCy Schubert 96*a90b9d01SCy Schubert return offchannel_send_action(wpa_s, freq, dst, src, bssid, 97*a90b9d01SCy Schubert wpabuf_head(buf), wpabuf_len(buf), 98*a90b9d01SCy Schubert wait_time, wpas_nan_de_tx_status, 1); 99*a90b9d01SCy Schubert } 100*a90b9d01SCy Schubert 101*a90b9d01SCy Schubert 102*a90b9d01SCy Schubert static void wpas_nan_usd_start_tx_cb(struct wpa_radio_work *work, int deinit) 103*a90b9d01SCy Schubert { 104*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = work->wpa_s; 105*a90b9d01SCy Schubert struct wpas_nan_usd_tx_work *twork = work->ctx; 106*a90b9d01SCy Schubert 107*a90b9d01SCy Schubert if (deinit) { 108*a90b9d01SCy Schubert if (work->started) { 109*a90b9d01SCy Schubert wpa_s->nan_usd_tx_work = NULL; 110*a90b9d01SCy Schubert offchannel_send_action_done(wpa_s); 111*a90b9d01SCy Schubert } 112*a90b9d01SCy Schubert wpas_nan_usd_tx_work_free(twork); 113*a90b9d01SCy Schubert return; 114*a90b9d01SCy Schubert } 115*a90b9d01SCy Schubert 116*a90b9d01SCy Schubert wpa_s->nan_usd_tx_work = work; 117*a90b9d01SCy Schubert 118*a90b9d01SCy Schubert if (wpas_nan_de_tx_send(wpa_s, twork->freq, twork->wait_time, 119*a90b9d01SCy Schubert twork->dst, twork->src, twork->bssid, 120*a90b9d01SCy Schubert twork->buf) < 0) 121*a90b9d01SCy Schubert wpas_nan_usd_tx_work_done(wpa_s); 122*a90b9d01SCy Schubert } 123*a90b9d01SCy Schubert 124*a90b9d01SCy Schubert 125*a90b9d01SCy Schubert static int wpas_nan_de_tx(void *ctx, unsigned int freq, unsigned int wait_time, 126*a90b9d01SCy Schubert const u8 *dst, const u8 *src, const u8 *bssid, 127*a90b9d01SCy Schubert const struct wpabuf *buf) 128*a90b9d01SCy Schubert { 129*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = ctx; 130*a90b9d01SCy Schubert struct wpas_nan_usd_tx_work *twork; 131*a90b9d01SCy Schubert 132*a90b9d01SCy Schubert if (wpa_s->nan_usd_tx_work || wpa_s->nan_usd_listen_work) { 133*a90b9d01SCy Schubert /* Reuse ongoing radio work */ 134*a90b9d01SCy Schubert return wpas_nan_de_tx_send(wpa_s, freq, wait_time, dst, src, 135*a90b9d01SCy Schubert bssid, buf); 136*a90b9d01SCy Schubert } 137*a90b9d01SCy Schubert 138*a90b9d01SCy Schubert twork = os_zalloc(sizeof(*twork)); 139*a90b9d01SCy Schubert if (!twork) 140*a90b9d01SCy Schubert return -1; 141*a90b9d01SCy Schubert twork->freq = freq; 142*a90b9d01SCy Schubert twork->wait_time = wait_time; 143*a90b9d01SCy Schubert os_memcpy(twork->dst, dst, ETH_ALEN); 144*a90b9d01SCy Schubert os_memcpy(twork->src, src, ETH_ALEN); 145*a90b9d01SCy Schubert os_memcpy(twork->bssid, bssid, ETH_ALEN); 146*a90b9d01SCy Schubert twork->buf = wpabuf_dup(buf); 147*a90b9d01SCy Schubert if (!twork->buf) { 148*a90b9d01SCy Schubert wpas_nan_usd_tx_work_free(twork); 149*a90b9d01SCy Schubert return -1; 150*a90b9d01SCy Schubert } 151*a90b9d01SCy Schubert 152*a90b9d01SCy Schubert if (radio_add_work(wpa_s, freq, "nan-usd-tx", 0, 153*a90b9d01SCy Schubert wpas_nan_usd_start_tx_cb, twork) < 0) { 154*a90b9d01SCy Schubert wpas_nan_usd_tx_work_free(twork); 155*a90b9d01SCy Schubert return -1; 156*a90b9d01SCy Schubert } 157*a90b9d01SCy Schubert 158*a90b9d01SCy Schubert return 0; 159*a90b9d01SCy Schubert } 160*a90b9d01SCy Schubert 161*a90b9d01SCy Schubert 162*a90b9d01SCy Schubert struct wpas_nan_usd_listen_work { 163*a90b9d01SCy Schubert unsigned int freq; 164*a90b9d01SCy Schubert unsigned int duration; 165*a90b9d01SCy Schubert }; 166*a90b9d01SCy Schubert 167*a90b9d01SCy Schubert 168*a90b9d01SCy Schubert static void wpas_nan_usd_listen_work_done(struct wpa_supplicant *wpa_s) 169*a90b9d01SCy Schubert { 170*a90b9d01SCy Schubert struct wpas_nan_usd_listen_work *lwork; 171*a90b9d01SCy Schubert 172*a90b9d01SCy Schubert if (!wpa_s->nan_usd_listen_work) 173*a90b9d01SCy Schubert return; 174*a90b9d01SCy Schubert 175*a90b9d01SCy Schubert lwork = wpa_s->nan_usd_listen_work->ctx; 176*a90b9d01SCy Schubert os_free(lwork); 177*a90b9d01SCy Schubert radio_work_done(wpa_s->nan_usd_listen_work); 178*a90b9d01SCy Schubert wpa_s->nan_usd_listen_work = NULL; 179*a90b9d01SCy Schubert } 180*a90b9d01SCy Schubert 181*a90b9d01SCy Schubert 182*a90b9d01SCy Schubert static void wpas_nan_usd_start_listen_cb(struct wpa_radio_work *work, 183*a90b9d01SCy Schubert int deinit) 184*a90b9d01SCy Schubert { 185*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = work->wpa_s; 186*a90b9d01SCy Schubert struct wpas_nan_usd_listen_work *lwork = work->ctx; 187*a90b9d01SCy Schubert unsigned int duration; 188*a90b9d01SCy Schubert 189*a90b9d01SCy Schubert if (deinit) { 190*a90b9d01SCy Schubert if (work->started) { 191*a90b9d01SCy Schubert wpa_s->nan_usd_listen_work = NULL; 192*a90b9d01SCy Schubert wpa_drv_cancel_remain_on_channel(wpa_s); 193*a90b9d01SCy Schubert } 194*a90b9d01SCy Schubert os_free(lwork); 195*a90b9d01SCy Schubert return; 196*a90b9d01SCy Schubert } 197*a90b9d01SCy Schubert 198*a90b9d01SCy Schubert wpa_s->nan_usd_listen_work = work; 199*a90b9d01SCy Schubert 200*a90b9d01SCy Schubert duration = lwork->duration; 201*a90b9d01SCy Schubert if (duration > wpa_s->max_remain_on_chan) 202*a90b9d01SCy Schubert duration = wpa_s->max_remain_on_chan; 203*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "NAN: Start listen on %u MHz for %u ms", 204*a90b9d01SCy Schubert lwork->freq, duration); 205*a90b9d01SCy Schubert if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, duration) < 0) { 206*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 207*a90b9d01SCy Schubert "NAN: Failed to request the driver to remain on channel (%u MHz) for listen", 208*a90b9d01SCy Schubert lwork->freq); 209*a90b9d01SCy Schubert wpas_nan_usd_listen_work_done(wpa_s); 210*a90b9d01SCy Schubert return; 211*a90b9d01SCy Schubert } 212*a90b9d01SCy Schubert } 213*a90b9d01SCy Schubert 214*a90b9d01SCy Schubert 215*a90b9d01SCy Schubert static int wpas_nan_de_listen(void *ctx, unsigned int freq, 216*a90b9d01SCy Schubert unsigned int duration) 217*a90b9d01SCy Schubert { 218*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = ctx; 219*a90b9d01SCy Schubert struct wpas_nan_usd_listen_work *lwork; 220*a90b9d01SCy Schubert 221*a90b9d01SCy Schubert lwork = os_zalloc(sizeof(*lwork)); 222*a90b9d01SCy Schubert if (!lwork) 223*a90b9d01SCy Schubert return -1; 224*a90b9d01SCy Schubert lwork->freq = freq; 225*a90b9d01SCy Schubert lwork->duration = duration; 226*a90b9d01SCy Schubert 227*a90b9d01SCy Schubert if (radio_add_work(wpa_s, freq, "nan-usd-listen", 0, 228*a90b9d01SCy Schubert wpas_nan_usd_start_listen_cb, lwork) < 0) { 229*a90b9d01SCy Schubert os_free(lwork); 230*a90b9d01SCy Schubert return -1; 231*a90b9d01SCy Schubert } 232*a90b9d01SCy Schubert 233*a90b9d01SCy Schubert return 0; 234*a90b9d01SCy Schubert } 235*a90b9d01SCy Schubert 236*a90b9d01SCy Schubert 237*a90b9d01SCy Schubert static void 238*a90b9d01SCy Schubert wpas_nan_de_discovery_result(void *ctx, int subscribe_id, 239*a90b9d01SCy Schubert enum nan_service_protocol_type srv_proto_type, 240*a90b9d01SCy Schubert const u8 *ssi, size_t ssi_len, int peer_publish_id, 241*a90b9d01SCy Schubert const u8 *peer_addr, bool fsd, bool fsd_gas) 242*a90b9d01SCy Schubert { 243*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = ctx; 244*a90b9d01SCy Schubert char *ssi_hex; 245*a90b9d01SCy Schubert 246*a90b9d01SCy Schubert ssi_hex = os_zalloc(2 * ssi_len + 1); 247*a90b9d01SCy Schubert if (!ssi_hex) 248*a90b9d01SCy Schubert return; 249*a90b9d01SCy Schubert if (ssi) 250*a90b9d01SCy Schubert wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len); 251*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, NAN_DISCOVERY_RESULT 252*a90b9d01SCy Schubert "subscribe_id=%d publish_id=%d address=" MACSTR 253*a90b9d01SCy Schubert " fsd=%d fsd_gas=%d srv_proto_type=%u ssi=%s", 254*a90b9d01SCy Schubert subscribe_id, peer_publish_id, MAC2STR(peer_addr), 255*a90b9d01SCy Schubert fsd, fsd_gas, srv_proto_type, ssi_hex); 256*a90b9d01SCy Schubert os_free(ssi_hex); 257*a90b9d01SCy Schubert } 258*a90b9d01SCy Schubert 259*a90b9d01SCy Schubert 260*a90b9d01SCy Schubert static void wpas_nan_de_replied(void *ctx, int publish_id, const u8 *peer_addr, 261*a90b9d01SCy Schubert int peer_subscribe_id, 262*a90b9d01SCy Schubert enum nan_service_protocol_type srv_proto_type, 263*a90b9d01SCy Schubert const u8 *ssi, size_t ssi_len) 264*a90b9d01SCy Schubert { 265*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = ctx; 266*a90b9d01SCy Schubert char *ssi_hex; 267*a90b9d01SCy Schubert 268*a90b9d01SCy Schubert ssi_hex = os_zalloc(2 * ssi_len + 1); 269*a90b9d01SCy Schubert if (!ssi_hex) 270*a90b9d01SCy Schubert return; 271*a90b9d01SCy Schubert if (ssi) 272*a90b9d01SCy Schubert wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len); 273*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, NAN_REPLIED 274*a90b9d01SCy Schubert "publish_id=%d address=" MACSTR 275*a90b9d01SCy Schubert " subscribe_id=%d srv_proto_type=%u ssi=%s", 276*a90b9d01SCy Schubert publish_id, MAC2STR(peer_addr), peer_subscribe_id, 277*a90b9d01SCy Schubert srv_proto_type, ssi_hex); 278*a90b9d01SCy Schubert os_free(ssi_hex); 279*a90b9d01SCy Schubert } 280*a90b9d01SCy Schubert 281*a90b9d01SCy Schubert 282*a90b9d01SCy Schubert static const char * nan_reason_txt(enum nan_de_reason reason) 283*a90b9d01SCy Schubert { 284*a90b9d01SCy Schubert switch (reason) { 285*a90b9d01SCy Schubert case NAN_DE_REASON_TIMEOUT: 286*a90b9d01SCy Schubert return "timeout"; 287*a90b9d01SCy Schubert case NAN_DE_REASON_USER_REQUEST: 288*a90b9d01SCy Schubert return "user-request"; 289*a90b9d01SCy Schubert case NAN_DE_REASON_FAILURE: 290*a90b9d01SCy Schubert return "failure"; 291*a90b9d01SCy Schubert } 292*a90b9d01SCy Schubert 293*a90b9d01SCy Schubert return "unknown"; 294*a90b9d01SCy Schubert } 295*a90b9d01SCy Schubert 296*a90b9d01SCy Schubert 297*a90b9d01SCy Schubert static void wpas_nan_de_publish_terminated(void *ctx, int publish_id, 298*a90b9d01SCy Schubert enum nan_de_reason reason) 299*a90b9d01SCy Schubert { 300*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = ctx; 301*a90b9d01SCy Schubert 302*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, NAN_PUBLISH_TERMINATED 303*a90b9d01SCy Schubert "publish_id=%d reason=%s", 304*a90b9d01SCy Schubert publish_id, nan_reason_txt(reason)); 305*a90b9d01SCy Schubert } 306*a90b9d01SCy Schubert 307*a90b9d01SCy Schubert 308*a90b9d01SCy Schubert static void wpas_nan_de_subscribe_terminated(void *ctx, int subscribe_id, 309*a90b9d01SCy Schubert enum nan_de_reason reason) 310*a90b9d01SCy Schubert { 311*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = ctx; 312*a90b9d01SCy Schubert 313*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, NAN_SUBSCRIBE_TERMINATED 314*a90b9d01SCy Schubert "subscribe_id=%d reason=%s", 315*a90b9d01SCy Schubert subscribe_id, nan_reason_txt(reason)); 316*a90b9d01SCy Schubert } 317*a90b9d01SCy Schubert 318*a90b9d01SCy Schubert 319*a90b9d01SCy Schubert static void wpas_nan_de_receive(void *ctx, int id, int peer_instance_id, 320*a90b9d01SCy Schubert const u8 *ssi, size_t ssi_len, 321*a90b9d01SCy Schubert const u8 *peer_addr) 322*a90b9d01SCy Schubert { 323*a90b9d01SCy Schubert struct wpa_supplicant *wpa_s = ctx; 324*a90b9d01SCy Schubert char *ssi_hex; 325*a90b9d01SCy Schubert 326*a90b9d01SCy Schubert ssi_hex = os_zalloc(2 * ssi_len + 1); 327*a90b9d01SCy Schubert if (!ssi_hex) 328*a90b9d01SCy Schubert return; 329*a90b9d01SCy Schubert if (ssi) 330*a90b9d01SCy Schubert wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len); 331*a90b9d01SCy Schubert wpa_msg(wpa_s, MSG_INFO, NAN_RECEIVE 332*a90b9d01SCy Schubert "id=%d peer_instance_id=%d address=" MACSTR " ssi=%s", 333*a90b9d01SCy Schubert id, peer_instance_id, MAC2STR(peer_addr), ssi_hex); 334*a90b9d01SCy Schubert os_free(ssi_hex); 335*a90b9d01SCy Schubert } 336*a90b9d01SCy Schubert 337*a90b9d01SCy Schubert 338*a90b9d01SCy Schubert int wpas_nan_usd_init(struct wpa_supplicant *wpa_s) 339*a90b9d01SCy Schubert { 340*a90b9d01SCy Schubert struct nan_callbacks cb; 341*a90b9d01SCy Schubert 342*a90b9d01SCy Schubert os_memset(&cb, 0, sizeof(cb)); 343*a90b9d01SCy Schubert cb.ctx = wpa_s; 344*a90b9d01SCy Schubert cb.tx = wpas_nan_de_tx; 345*a90b9d01SCy Schubert cb.listen = wpas_nan_de_listen; 346*a90b9d01SCy Schubert cb.discovery_result = wpas_nan_de_discovery_result; 347*a90b9d01SCy Schubert cb.replied = wpas_nan_de_replied; 348*a90b9d01SCy Schubert cb.publish_terminated = wpas_nan_de_publish_terminated; 349*a90b9d01SCy Schubert cb.subscribe_terminated = wpas_nan_de_subscribe_terminated; 350*a90b9d01SCy Schubert cb.receive = wpas_nan_de_receive; 351*a90b9d01SCy Schubert 352*a90b9d01SCy Schubert wpa_s->nan_de = nan_de_init(wpa_s->own_addr, false, &cb); 353*a90b9d01SCy Schubert if (!wpa_s->nan_de) 354*a90b9d01SCy Schubert return -1; 355*a90b9d01SCy Schubert return 0; 356*a90b9d01SCy Schubert } 357*a90b9d01SCy Schubert 358*a90b9d01SCy Schubert 359*a90b9d01SCy Schubert void wpas_nan_usd_deinit(struct wpa_supplicant *wpa_s) 360*a90b9d01SCy Schubert { 361*a90b9d01SCy Schubert nan_de_deinit(wpa_s->nan_de); 362*a90b9d01SCy Schubert wpa_s->nan_de = NULL; 363*a90b9d01SCy Schubert } 364*a90b9d01SCy Schubert 365*a90b9d01SCy Schubert 366*a90b9d01SCy Schubert void wpas_nan_usd_rx_sdf(struct wpa_supplicant *wpa_s, const u8 *src, 367*a90b9d01SCy Schubert unsigned int freq, const u8 *buf, size_t len) 368*a90b9d01SCy Schubert { 369*a90b9d01SCy Schubert if (!wpa_s->nan_de) 370*a90b9d01SCy Schubert return; 371*a90b9d01SCy Schubert nan_de_rx_sdf(wpa_s->nan_de, src, freq, buf, len); 372*a90b9d01SCy Schubert } 373*a90b9d01SCy Schubert 374*a90b9d01SCy Schubert 375*a90b9d01SCy Schubert void wpas_nan_usd_flush(struct wpa_supplicant *wpa_s) 376*a90b9d01SCy Schubert { 377*a90b9d01SCy Schubert if (!wpa_s->nan_de) 378*a90b9d01SCy Schubert return; 379*a90b9d01SCy Schubert nan_de_flush(wpa_s->nan_de); 380*a90b9d01SCy Schubert } 381*a90b9d01SCy Schubert 382*a90b9d01SCy Schubert 383*a90b9d01SCy Schubert int wpas_nan_usd_publish(struct wpa_supplicant *wpa_s, const char *service_name, 384*a90b9d01SCy Schubert enum nan_service_protocol_type srv_proto_type, 385*a90b9d01SCy Schubert const struct wpabuf *ssi, 386*a90b9d01SCy Schubert struct nan_publish_params *params) 387*a90b9d01SCy Schubert { 388*a90b9d01SCy Schubert int publish_id; 389*a90b9d01SCy Schubert struct wpabuf *elems = NULL; 390*a90b9d01SCy Schubert 391*a90b9d01SCy Schubert if (!wpa_s->nan_de) 392*a90b9d01SCy Schubert return -1; 393*a90b9d01SCy Schubert 394*a90b9d01SCy Schubert publish_id = nan_de_publish(wpa_s->nan_de, service_name, srv_proto_type, 395*a90b9d01SCy Schubert ssi, elems, params); 396*a90b9d01SCy Schubert wpabuf_free(elems); 397*a90b9d01SCy Schubert return publish_id; 398*a90b9d01SCy Schubert } 399*a90b9d01SCy Schubert 400*a90b9d01SCy Schubert 401*a90b9d01SCy Schubert void wpas_nan_usd_cancel_publish(struct wpa_supplicant *wpa_s, int publish_id) 402*a90b9d01SCy Schubert { 403*a90b9d01SCy Schubert if (!wpa_s->nan_de) 404*a90b9d01SCy Schubert return; 405*a90b9d01SCy Schubert nan_de_cancel_publish(wpa_s->nan_de, publish_id); 406*a90b9d01SCy Schubert } 407*a90b9d01SCy Schubert 408*a90b9d01SCy Schubert 409*a90b9d01SCy Schubert int wpas_nan_usd_update_publish(struct wpa_supplicant *wpa_s, int publish_id, 410*a90b9d01SCy Schubert const struct wpabuf *ssi) 411*a90b9d01SCy Schubert { 412*a90b9d01SCy Schubert if (!wpa_s->nan_de) 413*a90b9d01SCy Schubert return -1; 414*a90b9d01SCy Schubert return nan_de_update_publish(wpa_s->nan_de, publish_id, ssi); 415*a90b9d01SCy Schubert } 416*a90b9d01SCy Schubert 417*a90b9d01SCy Schubert 418*a90b9d01SCy Schubert int wpas_nan_usd_subscribe(struct wpa_supplicant *wpa_s, 419*a90b9d01SCy Schubert const char *service_name, 420*a90b9d01SCy Schubert enum nan_service_protocol_type srv_proto_type, 421*a90b9d01SCy Schubert const struct wpabuf *ssi, 422*a90b9d01SCy Schubert struct nan_subscribe_params *params) 423*a90b9d01SCy Schubert { 424*a90b9d01SCy Schubert int subscribe_id; 425*a90b9d01SCy Schubert struct wpabuf *elems = NULL; 426*a90b9d01SCy Schubert 427*a90b9d01SCy Schubert if (!wpa_s->nan_de) 428*a90b9d01SCy Schubert return -1; 429*a90b9d01SCy Schubert 430*a90b9d01SCy Schubert subscribe_id = nan_de_subscribe(wpa_s->nan_de, service_name, 431*a90b9d01SCy Schubert srv_proto_type, ssi, elems, params); 432*a90b9d01SCy Schubert wpabuf_free(elems); 433*a90b9d01SCy Schubert return subscribe_id; 434*a90b9d01SCy Schubert } 435*a90b9d01SCy Schubert 436*a90b9d01SCy Schubert 437*a90b9d01SCy Schubert void wpas_nan_usd_cancel_subscribe(struct wpa_supplicant *wpa_s, 438*a90b9d01SCy Schubert int subscribe_id) 439*a90b9d01SCy Schubert { 440*a90b9d01SCy Schubert if (!wpa_s->nan_de) 441*a90b9d01SCy Schubert return; 442*a90b9d01SCy Schubert nan_de_cancel_subscribe(wpa_s->nan_de, subscribe_id); 443*a90b9d01SCy Schubert } 444*a90b9d01SCy Schubert 445*a90b9d01SCy Schubert 446*a90b9d01SCy Schubert int wpas_nan_usd_transmit(struct wpa_supplicant *wpa_s, int handle, 447*a90b9d01SCy Schubert const struct wpabuf *ssi, const struct wpabuf *elems, 448*a90b9d01SCy Schubert const u8 *peer_addr, u8 req_instance_id) 449*a90b9d01SCy Schubert { 450*a90b9d01SCy Schubert if (!wpa_s->nan_de) 451*a90b9d01SCy Schubert return -1; 452*a90b9d01SCy Schubert return nan_de_transmit(wpa_s->nan_de, handle, ssi, elems, peer_addr, 453*a90b9d01SCy Schubert req_instance_id); 454*a90b9d01SCy Schubert } 455*a90b9d01SCy Schubert 456*a90b9d01SCy Schubert 457*a90b9d01SCy Schubert void wpas_nan_usd_remain_on_channel_cb(struct wpa_supplicant *wpa_s, 458*a90b9d01SCy Schubert unsigned int freq, unsigned int duration) 459*a90b9d01SCy Schubert { 460*a90b9d01SCy Schubert wpas_nan_usd_listen_work_done(wpa_s); 461*a90b9d01SCy Schubert 462*a90b9d01SCy Schubert if (wpa_s->nan_de) 463*a90b9d01SCy Schubert nan_de_listen_started(wpa_s->nan_de, freq, duration); 464*a90b9d01SCy Schubert } 465*a90b9d01SCy Schubert 466*a90b9d01SCy Schubert 467*a90b9d01SCy Schubert void wpas_nan_usd_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, 468*a90b9d01SCy Schubert unsigned int freq) 469*a90b9d01SCy Schubert { 470*a90b9d01SCy Schubert if (wpa_s->nan_de) 471*a90b9d01SCy Schubert nan_de_listen_ended(wpa_s->nan_de, freq); 472*a90b9d01SCy Schubert } 473*a90b9d01SCy Schubert 474*a90b9d01SCy Schubert 475*a90b9d01SCy Schubert void wpas_nan_usd_tx_wait_expire(struct wpa_supplicant *wpa_s) 476*a90b9d01SCy Schubert { 477*a90b9d01SCy Schubert wpas_nan_usd_tx_work_done(wpa_s); 478*a90b9d01SCy Schubert 479*a90b9d01SCy Schubert if (wpa_s->nan_de) 480*a90b9d01SCy Schubert nan_de_tx_wait_ended(wpa_s->nan_de); 481*a90b9d01SCy Schubert } 482*a90b9d01SCy Schubert 483*a90b9d01SCy Schubert 484*a90b9d01SCy Schubert int * wpas_nan_usd_all_freqs(struct wpa_supplicant *wpa_s) 485*a90b9d01SCy Schubert { 486*a90b9d01SCy Schubert int i, j; 487*a90b9d01SCy Schubert int *freqs = NULL; 488*a90b9d01SCy Schubert 489*a90b9d01SCy Schubert if (!wpa_s->hw.modes) 490*a90b9d01SCy Schubert return NULL; 491*a90b9d01SCy Schubert 492*a90b9d01SCy Schubert for (i = 0; i < wpa_s->hw.num_modes; i++) { 493*a90b9d01SCy Schubert struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i]; 494*a90b9d01SCy Schubert 495*a90b9d01SCy Schubert for (j = 0; j < mode->num_channels; j++) { 496*a90b9d01SCy Schubert struct hostapd_channel_data *chan = &mode->channels[j]; 497*a90b9d01SCy Schubert 498*a90b9d01SCy Schubert /* All 20 MHz channels on 2.4 and 5 GHz band */ 499*a90b9d01SCy Schubert if (chan->freq < 2412 || chan->freq > 5900) 500*a90b9d01SCy Schubert continue; 501*a90b9d01SCy Schubert 502*a90b9d01SCy Schubert /* that allow frames to be transmitted */ 503*a90b9d01SCy Schubert if (chan->flag & (HOSTAPD_CHAN_DISABLED | 504*a90b9d01SCy Schubert HOSTAPD_CHAN_NO_IR | 505*a90b9d01SCy Schubert HOSTAPD_CHAN_RADAR)) 506*a90b9d01SCy Schubert continue; 507*a90b9d01SCy Schubert 508*a90b9d01SCy Schubert int_array_add_unique(&freqs, chan->freq); 509*a90b9d01SCy Schubert } 510*a90b9d01SCy Schubert } 511*a90b9d01SCy Schubert 512*a90b9d01SCy Schubert return freqs; 513*a90b9d01SCy Schubert } 514