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