1 /* $NetBSD: bwfm.c,v 1.29 2020/07/22 17:23:52 riastradh Exp $ */ 2 /* $OpenBSD: bwfm.c,v 1.5 2017/10/16 22:27:16 patrick Exp $ */ 3 /* 4 * Copyright (c) 2010-2016 Broadcom Corporation 5 * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se> 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/types.h> 22 23 #include <sys/buf.h> 24 #include <sys/device.h> 25 #include <sys/kernel.h> 26 #include <sys/kmem.h> 27 #include <sys/pool.h> 28 #include <sys/queue.h> 29 #include <sys/socket.h> 30 #include <sys/systm.h> 31 #include <sys/workqueue.h> 32 33 #include <net/bpf.h> 34 #include <net/if.h> 35 #include <net/if_dl.h> 36 #include <net/if_ether.h> 37 #include <net/if_media.h> 38 39 #include <netinet/in.h> 40 41 #include <net80211/ieee80211_var.h> 42 43 #include <dev/firmload.h> 44 45 #include <dev/ic/bwfmreg.h> 46 #include <dev/ic/bwfmvar.h> 47 48 /* #define BWFM_DEBUG */ 49 #ifdef BWFM_DEBUG 50 #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0) 51 #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0) 52 static int bwfm_debug = 1; 53 #else 54 #define DPRINTF(x) do { ; } while (0) 55 #define DPRINTFN(n, x) do { ; } while (0) 56 #endif 57 58 #define DEVNAME(sc) device_xname((sc)->sc_dev) 59 60 void bwfm_start(struct ifnet *); 61 int bwfm_init(struct ifnet *); 62 void bwfm_stop(struct ifnet *, int); 63 void bwfm_watchdog(struct ifnet *); 64 int bwfm_ioctl(struct ifnet *, u_long, void *); 65 int bwfm_media_change(struct ifnet *); 66 67 int bwfm_send_mgmt(struct ieee80211com *, struct ieee80211_node *, 68 int, int); 69 void bwfm_recv_mgmt(struct ieee80211com *, struct mbuf *, 70 struct ieee80211_node *, int, int, uint32_t); 71 int bwfm_key_set(struct ieee80211com *, const struct ieee80211_key *, 72 const uint8_t *); 73 int bwfm_key_delete(struct ieee80211com *, const struct ieee80211_key *); 74 int bwfm_newstate(struct ieee80211com *, enum ieee80211_state, int); 75 void bwfm_newstate_cb(struct bwfm_softc *, struct bwfm_cmd_newstate *); 76 void bwfm_newassoc(struct ieee80211_node *, int); 77 void bwfm_task(struct work *, void *); 78 79 int bwfm_chip_attach(struct bwfm_softc *); 80 int bwfm_chip_detach(struct bwfm_softc *, int); 81 struct bwfm_core *bwfm_chip_get_core(struct bwfm_softc *, int); 82 struct bwfm_core *bwfm_chip_get_pmu(struct bwfm_softc *); 83 int bwfm_chip_ai_isup(struct bwfm_softc *, struct bwfm_core *); 84 void bwfm_chip_ai_disable(struct bwfm_softc *, struct bwfm_core *, 85 uint32_t, uint32_t); 86 void bwfm_chip_ai_reset(struct bwfm_softc *, struct bwfm_core *, 87 uint32_t, uint32_t, uint32_t); 88 void bwfm_chip_dmp_erom_scan(struct bwfm_softc *); 89 int bwfm_chip_dmp_get_regaddr(struct bwfm_softc *, uint32_t *, 90 uint32_t *, uint32_t *); 91 int bwfm_chip_cr4_set_active(struct bwfm_softc *, const uint32_t); 92 void bwfm_chip_cr4_set_passive(struct bwfm_softc *); 93 int bwfm_chip_ca7_set_active(struct bwfm_softc *, const uint32_t); 94 void bwfm_chip_ca7_set_passive(struct bwfm_softc *); 95 int bwfm_chip_cm3_set_active(struct bwfm_softc *); 96 void bwfm_chip_cm3_set_passive(struct bwfm_softc *); 97 void bwfm_chip_socram_ramsize(struct bwfm_softc *, struct bwfm_core *); 98 void bwfm_chip_sysmem_ramsize(struct bwfm_softc *, struct bwfm_core *); 99 void bwfm_chip_tcm_ramsize(struct bwfm_softc *, struct bwfm_core *); 100 void bwfm_chip_tcm_rambase(struct bwfm_softc *); 101 102 int bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *, int, 103 int, char *, size_t *); 104 int bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *, int, 105 int, char *, size_t); 106 107 int bwfm_fwvar_cmd_get_data(struct bwfm_softc *, int, void *, size_t); 108 int bwfm_fwvar_cmd_set_data(struct bwfm_softc *, int, void *, size_t); 109 int bwfm_fwvar_cmd_get_int(struct bwfm_softc *, int, uint32_t *); 110 int bwfm_fwvar_cmd_set_int(struct bwfm_softc *, int, uint32_t); 111 int bwfm_fwvar_var_get_data(struct bwfm_softc *, const char *, void *, size_t); 112 int bwfm_fwvar_var_set_data(struct bwfm_softc *, const char *, void *, size_t); 113 int bwfm_fwvar_var_get_int(struct bwfm_softc *, const char *, uint32_t *); 114 int bwfm_fwvar_var_set_int(struct bwfm_softc *, const char *, uint32_t); 115 116 struct ieee80211_channel *bwfm_bss2chan(struct bwfm_softc *, struct bwfm_bss_info *); 117 void bwfm_scan(struct bwfm_softc *); 118 void bwfm_connect(struct bwfm_softc *); 119 void bwfm_get_sta_info(struct bwfm_softc *, struct ifmediareq *); 120 121 void bwfm_rx(struct bwfm_softc *, struct mbuf *); 122 void bwfm_rx_event(struct bwfm_softc *, struct mbuf *); 123 void bwfm_rx_event_cb(struct bwfm_softc *, struct mbuf *); 124 void bwfm_scan_node(struct bwfm_softc *, struct bwfm_bss_info *, size_t); 125 126 static const uint8_t bwfm_2ghz_channels[] = { 127 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 128 }; 129 static const uint8_t bwfm_5ghz_channels[] = { 130 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, 100, 104, 108, 112, 131 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, 132 }; 133 134 const struct bwfm_proto_ops bwfm_proto_bcdc_ops = { 135 .proto_query_dcmd = bwfm_proto_bcdc_query_dcmd, 136 .proto_set_dcmd = bwfm_proto_bcdc_set_dcmd, 137 }; 138 139 static const struct { 140 const char *suffix; 141 const char *description; 142 } bwfm_firmware_filetypes[] = { 143 [BWFM_FILETYPE_UCODE] = { 144 .suffix = "bin", 145 .description = "Firmware", 146 }, 147 [BWFM_FILETYPE_NVRAM] = { 148 .suffix = "txt", 149 .description = "NVRAM", 150 }, 151 [BWFM_FILETYPE_CLM] = { 152 .suffix = "clm_blob", 153 .description = "CLM", 154 }, 155 }; 156 157 static void 158 bwfm_firmware_read_file(struct bwfm_softc * const sc, 159 const struct bwfm_firmware_selector * const fwp, 160 struct bwfm_firmware_context * const ctx, 161 unsigned int const which) 162 { 163 firmware_handle_t fwh; 164 char *names[2]; 165 int i, error; 166 167 names[1] = kmem_asprintf("%s.%s", fwp->fwsel_basename, 168 bwfm_firmware_filetypes[which].suffix); 169 if (ctx->ctx_model) 170 names[0] = ctx->ctx_model ? kmem_asprintf("%s.%s.%s", 171 fwp->fwsel_basename, ctx->ctx_model, 172 bwfm_firmware_filetypes[which].suffix) : NULL; 173 174 aprint_verbose_dev(sc->sc_dev, "%s file default: %s\n", 175 bwfm_firmware_filetypes[which].description, names[1]); 176 if (names[0]) { 177 aprint_verbose_dev(sc->sc_dev, "%s file model-spec: %s\n", 178 bwfm_firmware_filetypes[which].description, names[0]); 179 } 180 181 for (i = 0; i < 2; i++) { 182 if (names[i] == NULL) 183 continue; 184 error = firmware_open("if_bwfm", names[i], &fwh); 185 if (error == 0) 186 break; 187 } 188 if (i == 2) 189 goto out; 190 191 aprint_verbose_dev(sc->sc_dev, "Found %s file: %s\n", 192 bwfm_firmware_filetypes[which].description, names[i]); 193 194 size_t size = firmware_get_size(fwh); 195 void *data = firmware_malloc(size); 196 if (data == NULL) { 197 aprint_error_dev(sc->sc_dev, 198 "unable to allocate %zu bytes for %s image\n", size, 199 bwfm_firmware_filetypes[which].description); 200 firmware_close(fwh); 201 goto out; 202 } 203 error = firmware_read(fwh, 0, data, size); 204 firmware_close(fwh); 205 if (error) { 206 aprint_error_dev(sc->sc_dev, 207 "failed to read %s file, error %d\n", 208 bwfm_firmware_filetypes[which].description, 209 error); 210 firmware_free(data, size); 211 goto out; 212 } 213 214 ctx->ctx_file[which].ctx_f_data = data; 215 ctx->ctx_file[which].ctx_f_size = size; 216 out: 217 for (i = 0; i < 2; i++) { 218 if (names[i]) 219 kmem_free(names[i], strlen(names[i])+1); 220 } 221 } 222 223 void 224 bwfm_firmware_context_init(struct bwfm_firmware_context * const ctx, 225 uint32_t const chip, uint32_t const chiprev, const char * const model, 226 uint32_t req) 227 { 228 memset(ctx, 0, sizeof(*ctx)); 229 ctx->ctx_chip = chip; 230 ctx->ctx_chiprev = chiprev; 231 ctx->ctx_model = model; 232 233 /* all devices require ucode */ 234 ctx->ctx_req = req | BWFM_FWREQ(BWFM_FILETYPE_UCODE); 235 } 236 237 bool 238 bwfm_firmware_open(struct bwfm_softc * const sc, 239 const struct bwfm_firmware_selector * const fwtab, 240 struct bwfm_firmware_context * const ctx) 241 { 242 const struct bwfm_firmware_selector *fwp; 243 unsigned int i; 244 245 KASSERT(fwtab != NULL); 246 KASSERT(ctx != NULL); 247 248 /* First locate the appropriate entry for this chip / rev. */ 249 for (fwp = fwtab; fwp->fwsel_basename != NULL; fwp++) { 250 if (fwp->fwsel_chip == ctx->ctx_chip && 251 fwp->fwsel_revmask & __BIT(ctx->ctx_chiprev)) 252 break; 253 } 254 if (fwp->fwsel_basename == NULL) { 255 aprint_error_dev(sc->sc_dev, 256 "No firmware entry for chip 0x%x/%u rev %u model %s\n", 257 ctx->ctx_chip, ctx->ctx_chip, ctx->ctx_chiprev, 258 ctx->ctx_model); 259 return false; 260 } 261 262 bool rv = true; 263 264 /* 265 * Read in each file that the front-end has requested as 266 * either required or optional. 267 */ 268 for (i = 0; i < BWFM_NFILETYPES; i++) { 269 if (ctx->ctx_req & (BWFM_FWREQ(i) | BWFM_FWOPT(i))) 270 bwfm_firmware_read_file(sc, fwp, ctx, i); 271 if ((ctx->ctx_req & BWFM_FWREQ(i)) && 272 ctx->ctx_file[i].ctx_f_data == NULL) { 273 aprint_error_dev(sc->sc_dev, 274 "%s file not available\n", 275 bwfm_firmware_filetypes[i].description); 276 rv = false; 277 } 278 } 279 280 if (rv == false) 281 bwfm_firmware_close(ctx); 282 283 return rv; 284 } 285 286 void 287 bwfm_firmware_close(struct bwfm_firmware_context * const ctx) 288 { 289 for (int i = 0; i < BWFM_NFILETYPES; i++) { 290 if (ctx->ctx_file[i].ctx_f_data == NULL) 291 continue; 292 firmware_free(ctx->ctx_file[i].ctx_f_data, 293 ctx->ctx_file[i].ctx_f_size); 294 ctx->ctx_file[i].ctx_f_data = NULL; 295 } 296 } 297 298 void * 299 bwfm_firmware_data(struct bwfm_firmware_context * const ctx, 300 unsigned int const which, size_t *sizep) 301 { 302 KASSERT(which < BWFM_NFILETYPES); 303 KASSERT(sizep != NULL); 304 305 *sizep = ctx->ctx_file[which].ctx_f_size; 306 return ctx->ctx_file[which].ctx_f_data; 307 } 308 309 const char * 310 bwfm_firmware_description(unsigned int const which) 311 { 312 KASSERT(which < BWFM_NFILETYPES); 313 314 return bwfm_firmware_filetypes[which].description; 315 } 316 317 void 318 bwfm_attach(struct bwfm_softc *sc) 319 { 320 struct ieee80211com *ic = &sc->sc_ic; 321 struct ifnet *ifp = &sc->sc_if; 322 char fw_version[BWFM_DCMD_SMLEN]; 323 uint32_t bandlist[3]; 324 uint32_t tmp; 325 int i, j, error; 326 327 error = workqueue_create(&sc->sc_taskq, DEVNAME(sc), 328 bwfm_task, sc, PRI_NONE, IPL_NET, 0); 329 if (error != 0) { 330 printf("%s: could not create workqueue\n", DEVNAME(sc)); 331 return; 332 } 333 sc->sc_freetask = pool_cache_init(sizeof(struct bwfm_task), 0, 0, 0, 334 "bwfmtask", NULL, IPL_NET /* XXX IPL_SOFTNET? */, 335 NULL, NULL, NULL); 336 pool_cache_prime(sc->sc_freetask, BWFM_TASK_COUNT); 337 338 /* Stop the device in case it was previously initialized */ 339 bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1); 340 341 if (bwfm_fwvar_cmd_get_int(sc, BWFM_C_GET_VERSION, &tmp)) { 342 printf("%s: could not read io type\n", DEVNAME(sc)); 343 return; 344 } else 345 sc->sc_io_type = tmp; 346 if (bwfm_fwvar_var_get_data(sc, "cur_etheraddr", ic->ic_myaddr, 347 sizeof(ic->ic_myaddr))) { 348 printf("%s: could not read mac address\n", DEVNAME(sc)); 349 return; 350 } 351 352 memset(fw_version, 0, sizeof(fw_version)); 353 if (bwfm_fwvar_var_get_data(sc, "ver", fw_version, sizeof(fw_version)) == 0) 354 printf("%s: %s", DEVNAME(sc), fw_version); 355 printf("%s: address %s\n", DEVNAME(sc), ether_sprintf(ic->ic_myaddr)); 356 357 ic->ic_ifp = ifp; 358 ic->ic_phytype = IEEE80211_T_OFDM; 359 ic->ic_opmode = IEEE80211_M_STA; 360 ic->ic_state = IEEE80211_S_INIT; 361 362 ic->ic_caps = 363 IEEE80211_C_WEP | 364 IEEE80211_C_TKIP | 365 IEEE80211_C_AES | 366 IEEE80211_C_AES_CCM | 367 #if notyet 368 IEEE80211_C_MONITOR | /* monitor mode supported */ 369 IEEE80211_C_IBSS | 370 IEEE80211_C_TXPMGT | 371 IEEE80211_C_WME | 372 #endif 373 IEEE80211_C_SHSLOT | /* short slot time supported */ 374 IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 375 IEEE80211_C_WPA | /* 802.11i */ 376 /* IEEE80211_C_WPA_4WAY */0; /* WPA 4-way handshake in hw */ 377 378 /* IBSS channel undefined for now. */ 379 ic->ic_ibss_chan = &ic->ic_channels[0]; 380 381 if (bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_BANDLIST, bandlist, 382 sizeof(bandlist))) { 383 printf("%s: couldn't get supported band list\n", DEVNAME(sc)); 384 return; 385 } 386 const u_int nbands = le32toh(bandlist[0]); 387 for (i = 1; i <= MIN(nbands, __arraycount(bandlist) - 1); i++) { 388 switch (le32toh(bandlist[i])) { 389 case BWFM_BAND_2G: 390 ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; 391 ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g; 392 393 for (j = 0; j < __arraycount(bwfm_2ghz_channels); j++) { 394 uint8_t chan = bwfm_2ghz_channels[j]; 395 ic->ic_channels[chan].ic_freq = 396 ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ); 397 ic->ic_channels[chan].ic_flags = 398 IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | 399 IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; 400 } 401 break; 402 case BWFM_BAND_5G: 403 ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a; 404 405 for (j = 0; j < __arraycount(bwfm_5ghz_channels); j++) { 406 uint8_t chan = bwfm_5ghz_channels[j]; 407 ic->ic_channels[chan].ic_freq = 408 ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ); 409 ic->ic_channels[chan].ic_flags = 410 IEEE80211_CHAN_A; 411 } 412 break; 413 } 414 } 415 416 ifp->if_softc = sc; 417 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 418 ifp->if_init = bwfm_init; 419 ifp->if_ioctl = bwfm_ioctl; 420 ifp->if_start = bwfm_start; 421 ifp->if_stop = bwfm_stop; 422 ifp->if_watchdog = bwfm_watchdog; 423 IFQ_SET_READY(&ifp->if_snd); 424 memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); 425 426 error = if_initialize(ifp); 427 if (error != 0) { 428 printf("%s: if_initialize failed(%d)\n", DEVNAME(sc), error); 429 pool_cache_destroy(sc->sc_freetask); 430 workqueue_destroy(sc->sc_taskq); 431 432 return; /* Error */ 433 } 434 435 ieee80211_ifattach(ic); 436 sc->sc_newstate = ic->ic_newstate; 437 ic->ic_newstate = bwfm_newstate; 438 ic->ic_newassoc = bwfm_newassoc; 439 ic->ic_send_mgmt = bwfm_send_mgmt; 440 ic->ic_recv_mgmt = bwfm_recv_mgmt; 441 ic->ic_crypto.cs_key_set = bwfm_key_set; 442 ic->ic_crypto.cs_key_delete = bwfm_key_delete; 443 444 ifp->if_percpuq = if_percpuq_create(ifp); 445 if_deferred_start_init(ifp, NULL); 446 if_register(ifp); 447 ieee80211_media_init(ic, bwfm_media_change, ieee80211_media_status); 448 449 ieee80211_announce(ic); 450 451 sc->sc_if_attached = true; 452 } 453 454 int 455 bwfm_detach(struct bwfm_softc *sc, int flags) 456 { 457 struct ieee80211com *ic = &sc->sc_ic; 458 struct ifnet *ifp = ic->ic_ifp; 459 460 if (sc->sc_if_attached) { 461 bpf_detach(ifp); 462 ieee80211_ifdetach(ic); 463 if_detach(ifp); 464 } 465 466 if (sc->sc_taskq) 467 workqueue_destroy(sc->sc_taskq); 468 if (sc->sc_freetask) 469 pool_cache_destroy(sc->sc_freetask); 470 471 return 0; 472 } 473 474 void 475 bwfm_start(struct ifnet *ifp) 476 { 477 struct bwfm_softc *sc = ifp->if_softc; 478 struct ieee80211com *ic = &sc->sc_ic; 479 struct mbuf *m; 480 int error; 481 482 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) 483 return; 484 485 /* TODO: return if no link? */ 486 487 for (;;) { 488 /* Discard management packets (fw handles this for us) */ 489 IF_DEQUEUE(&ic->ic_mgtq, m); 490 if (m != NULL) { 491 m_freem(m); 492 continue; 493 } 494 495 if (sc->sc_bus_ops->bs_txcheck(sc)) { 496 ifp->if_flags |= IFF_OACTIVE; 497 break; 498 } 499 500 IFQ_DEQUEUE(&ifp->if_snd, m); 501 if (m == NULL) 502 break; 503 504 error = sc->sc_bus_ops->bs_txdata(sc, &m); 505 if (error == ENOBUFS) { 506 IF_PREPEND(&ifp->if_snd, m); 507 ifp->if_flags |= IFF_OACTIVE; 508 break; 509 } 510 if (error != 0) { 511 if_statinc(ifp, if_oerrors); 512 m_freem(m); 513 continue; 514 } 515 516 bpf_mtap(ifp, m, BPF_D_OUT); 517 } 518 } 519 520 int 521 bwfm_init(struct ifnet *ifp) 522 { 523 struct bwfm_softc *sc = ifp->if_softc; 524 struct ieee80211com *ic = &sc->sc_ic; 525 uint8_t evmask[BWFM_EVENT_MASK_LEN]; 526 struct bwfm_join_pref_params join_pref[2]; 527 int pm; 528 529 if (bwfm_fwvar_var_set_int(sc, "mpc", 1)) { 530 printf("%s: could not set mpc\n", DEVNAME(sc)); 531 return EIO; 532 } 533 534 /* Select target by RSSI (boost on 5GHz) */ 535 join_pref[0].type = BWFM_JOIN_PREF_RSSI_DELTA; 536 join_pref[0].len = 2; 537 join_pref[0].rssi_gain = BWFM_JOIN_PREF_RSSI_BOOST; 538 join_pref[0].band = BWFM_JOIN_PREF_BAND_5G; 539 join_pref[1].type = BWFM_JOIN_PREF_RSSI; 540 join_pref[1].len = 2; 541 join_pref[1].rssi_gain = 0; 542 join_pref[1].band = 0; 543 if (bwfm_fwvar_var_set_data(sc, "join_pref", join_pref, 544 sizeof(join_pref))) { 545 printf("%s: could not set join pref\n", DEVNAME(sc)); 546 return EIO; 547 } 548 549 memset(evmask, 0, sizeof(evmask)); 550 551 #define ENABLE_EVENT(e) evmask[(e) / 8] |= 1 << ((e) % 8) 552 /* Events used to drive the state machine */ 553 switch (ic->ic_opmode) { 554 case IEEE80211_M_STA: 555 ENABLE_EVENT(BWFM_E_IF); 556 ENABLE_EVENT(BWFM_E_LINK); 557 ENABLE_EVENT(BWFM_E_AUTH); 558 ENABLE_EVENT(BWFM_E_ASSOC); 559 ENABLE_EVENT(BWFM_E_DEAUTH); 560 ENABLE_EVENT(BWFM_E_DISASSOC); 561 ENABLE_EVENT(BWFM_E_SET_SSID); 562 ENABLE_EVENT(BWFM_E_ESCAN_RESULT); 563 break; 564 #ifndef IEEE80211_STA_ONLY 565 case IEEE80211_M_HOSTAP: 566 ENABLE_EVENT(BWFM_E_AUTH_IND); 567 ENABLE_EVENT(BWFM_E_ASSOC_IND); 568 ENABLE_EVENT(BWFM_E_REASSOC_IND); 569 ENABLE_EVENT(BWFM_E_DEAUTH_IND); 570 ENABLE_EVENT(BWFM_E_DISASSOC_IND); 571 ENABLE_EVENT(BWFM_E_ESCAN_RESULT); 572 ENABLE_EVENT(BWFM_E_ESCAN_RESULT); 573 break; 574 #endif 575 default: 576 break; 577 } 578 #undef ENABLE_EVENT 579 580 #ifdef BWFM_DEBUG 581 memset(evmask, 0xff, sizeof(evmask)); 582 #endif 583 584 if (bwfm_fwvar_var_set_data(sc, "event_msgs", evmask, sizeof(evmask))) { 585 printf("%s: could not set event mask\n", DEVNAME(sc)); 586 return EIO; 587 } 588 589 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_CHANNEL_TIME, 590 BWFM_DEFAULT_SCAN_CHANNEL_TIME)) { 591 printf("%s: could not set scan channel time\n", DEVNAME(sc)); 592 return EIO; 593 } 594 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_UNASSOC_TIME, 595 BWFM_DEFAULT_SCAN_UNASSOC_TIME)) { 596 printf("%s: could not set scan unassoc time\n", DEVNAME(sc)); 597 return EIO; 598 } 599 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_PASSIVE_TIME, 600 BWFM_DEFAULT_SCAN_PASSIVE_TIME)) { 601 printf("%s: could not set scan passive time\n", DEVNAME(sc)); 602 return EIO; 603 } 604 605 /* 606 * Use CAM (constantly awake) when we are running as AP 607 * otherwise use fast power saving. 608 */ 609 pm = BWFM_PM_FAST_PS; 610 #ifndef IEEE80211_STA_ONLY 611 if (ic->ic_opmode == IEEE80211_M_HOSTAP) 612 pm = BWFM_PM_CAM; 613 #endif 614 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, pm)) { 615 printf("%s: could not set power\n", DEVNAME(sc)); 616 return EIO; 617 } 618 619 bwfm_fwvar_var_set_int(sc, "txbf", 1); 620 bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 0); 621 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 1); 622 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0); 623 624 /* Disable all offloading (ARP, NDP, TCP/UDP cksum). */ 625 bwfm_fwvar_var_set_int(sc, "arp_ol", 0); 626 bwfm_fwvar_var_set_int(sc, "arpoe", 0); 627 bwfm_fwvar_var_set_int(sc, "ndoe", 0); 628 bwfm_fwvar_var_set_int(sc, "toe", 0); 629 630 /* Accept all multicast frames. */ 631 bwfm_fwvar_var_set_int(sc, "allmulti", 1); 632 633 /* Setup promiscuous mode */ 634 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PROMISC, 635 (ifp->if_flags & IFF_PROMISC) ? 1 : 0); 636 637 /* 638 * Tell the firmware supplicant that we are going to handle the 639 * WPA handshake ourselves. 640 */ 641 bwfm_fwvar_var_set_int(sc, "sup_wpa", 0); 642 643 ifp->if_flags |= IFF_RUNNING; 644 ifp->if_flags &= ~IFF_OACTIVE; 645 646 if (ic->ic_opmode != IEEE80211_M_MONITOR) { 647 if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) 648 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 649 } else { 650 ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 651 } 652 653 return 0; 654 } 655 656 void 657 bwfm_stop(struct ifnet *ifp, int disable) 658 { 659 struct bwfm_softc *sc = ifp->if_softc; 660 struct ieee80211com *ic = &sc->sc_ic; 661 struct bwfm_join_params join; 662 663 sc->sc_tx_timer = 0; 664 ifp->if_timer = 0; 665 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 666 667 memset(&join, 0, sizeof(join)); 668 bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, sizeof(join)); 669 bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1); 670 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, 0); 671 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0); 672 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 0); 673 bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 1); 674 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, BWFM_PM_FAST_PS); 675 676 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 677 678 if (sc->sc_bus_ops->bs_stop) 679 sc->sc_bus_ops->bs_stop(sc); 680 } 681 682 void 683 bwfm_watchdog(struct ifnet *ifp) 684 { 685 struct bwfm_softc *sc = ifp->if_softc; 686 struct ieee80211com *ic = &sc->sc_ic; 687 688 ifp->if_timer = 0; 689 690 if (sc->sc_tx_timer > 0) { 691 if (--sc->sc_tx_timer == 0) { 692 printf("%s: device timeout\n", DEVNAME(sc)); 693 if_statinc(ifp, if_oerrors); 694 return; 695 } 696 ifp->if_timer = 1; 697 } 698 ieee80211_watchdog(ic); 699 } 700 701 int 702 bwfm_ioctl(struct ifnet *ifp, u_long cmd, void *data) 703 { 704 struct bwfm_softc *sc = ifp->if_softc; 705 struct ieee80211com *ic = &sc->sc_ic; 706 int s, error = 0; 707 708 s = splnet(); 709 710 switch (cmd) { 711 case SIOCSIFFLAGS: 712 if ((error = ifioctl_common(ifp, cmd, data)) != 0) 713 break; 714 switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { 715 case IFF_UP | IFF_RUNNING: 716 break; 717 case IFF_UP: 718 bwfm_init(ifp); 719 break; 720 case IFF_RUNNING: 721 bwfm_stop(ifp, 1); 722 break; 723 case 0: 724 break; 725 } 726 break; 727 728 case SIOCADDMULTI: 729 case SIOCDELMULTI: 730 if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { 731 /* setup multicast filter, etc */ 732 error = 0; 733 } 734 break; 735 736 case SIOCGIFMEDIA: 737 error = ieee80211_ioctl(ic, cmd, data); 738 if (error == 0 && ic->ic_state == IEEE80211_S_RUN) 739 bwfm_get_sta_info(sc, (struct ifmediareq *)data); 740 break; 741 742 default: 743 error = ieee80211_ioctl(ic, cmd, data); 744 } 745 746 if (error == ENETRESET) { 747 if ((ifp->if_flags & IFF_UP) != 0 && 748 (ifp->if_flags & IFF_RUNNING) != 0 && 749 ic->ic_roaming != IEEE80211_ROAMING_MANUAL) { 750 bwfm_init(ifp); 751 } 752 error = 0; 753 } 754 755 splx(s); 756 757 return error; 758 } 759 760 int 761 bwfm_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, 762 int type, int arg) 763 { 764 return 0; 765 } 766 767 void 768 bwfm_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, 769 struct ieee80211_node *ni, int subtype, int rssi, uint32_t rstamp) 770 { 771 } 772 773 int 774 bwfm_key_set(struct ieee80211com *ic, const struct ieee80211_key *wk, 775 const uint8_t mac[IEEE80211_ADDR_LEN]) 776 { 777 struct bwfm_softc *sc = ic->ic_ifp->if_softc; 778 struct bwfm_task *t; 779 780 t = pool_cache_get(sc->sc_freetask, PR_NOWAIT); 781 if (t == NULL) { 782 printf("%s: no free tasks\n", DEVNAME(sc)); 783 return 0; 784 } 785 786 t->t_sc = sc; 787 t->t_cmd = BWFM_TASK_KEY_SET; 788 t->t_key.key = wk; 789 memcpy(t->t_key.mac, mac, sizeof(t->t_key.mac)); 790 workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL); 791 return 1; 792 } 793 794 static void 795 bwfm_key_set_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck) 796 { 797 const struct ieee80211_key *wk = ck->key; 798 const uint8_t *mac = ck->mac; 799 struct bwfm_wsec_key wsec_key; 800 uint32_t wsec_enable, wsec; 801 bool ext_key; 802 803 #ifdef BWFM_DEBUG 804 printf("key_set: key cipher %s len %d: ", wk->wk_cipher->ic_name, wk->wk_keylen); 805 for (int j = 0; j < sizeof(wk->wk_key); j++) 806 printf("%02x", wk->wk_key[j]); 807 #endif 808 809 if ((wk->wk_flags & IEEE80211_KEY_GROUP) == 0 && 810 wk->wk_cipher->ic_cipher != IEEE80211_CIPHER_WEP) { 811 ext_key = true; 812 } else { 813 ext_key = false; 814 } 815 816 #ifdef BWFM_DEBUG 817 printf(", ext_key = %d", ext_key); 818 printf(", mac = %02x:%02x:%02x:%02x:%02x:%02x", 819 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 820 printf("\n"); 821 #endif 822 823 memset(&wsec_key, 0, sizeof(wsec_key)); 824 if (ext_key && !IEEE80211_IS_MULTICAST(mac)) 825 memcpy(wsec_key.ea, mac, sizeof(wsec_key.ea)); 826 wsec_key.index = htole32(wk->wk_keyix); 827 wsec_key.len = htole32(wk->wk_keylen); 828 memcpy(wsec_key.data, wk->wk_key, sizeof(wsec_key.data)); 829 if (!ext_key) 830 wsec_key.flags = htole32(BWFM_WSEC_PRIMARY_KEY); 831 832 switch (wk->wk_cipher->ic_cipher) { 833 case IEEE80211_CIPHER_WEP: 834 if (wk->wk_keylen == 5) 835 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP1); 836 else if (wk->wk_keylen == 13) 837 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP128); 838 else 839 return; 840 wsec_enable = BWFM_WSEC_WEP; 841 break; 842 case IEEE80211_CIPHER_TKIP: 843 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_TKIP); 844 wsec_enable = BWFM_WSEC_TKIP; 845 break; 846 case IEEE80211_CIPHER_AES_CCM: 847 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_AES_CCM); 848 wsec_enable = BWFM_WSEC_AES; 849 break; 850 default: 851 printf("%s: %s: cipher %s not supported\n", DEVNAME(sc), 852 __func__, wk->wk_cipher->ic_name); 853 return; 854 } 855 856 if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key))) 857 return; 858 859 bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_WPA2_PSK); 860 861 bwfm_fwvar_var_get_int(sc, "wsec", &wsec); 862 wsec |= wsec_enable; 863 bwfm_fwvar_var_set_int(sc, "wsec", wsec); 864 } 865 866 int 867 bwfm_key_delete(struct ieee80211com *ic, const struct ieee80211_key *wk) 868 { 869 struct bwfm_softc *sc = ic->ic_ifp->if_softc; 870 struct bwfm_task *t; 871 872 t = pool_cache_get(sc->sc_freetask, PR_NOWAIT); 873 if (t == NULL) { 874 printf("%s: no free tasks\n", DEVNAME(sc)); 875 return 0; 876 } 877 878 t->t_sc = sc; 879 t->t_cmd = BWFM_TASK_KEY_DELETE; 880 t->t_key.key = wk; 881 memset(t->t_key.mac, 0, sizeof(t->t_key.mac)); 882 workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL); 883 884 return 1; 885 } 886 887 static void 888 bwfm_key_delete_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck) 889 { 890 const struct ieee80211_key *wk = ck->key; 891 struct bwfm_wsec_key wsec_key; 892 893 memset(&wsec_key, 0, sizeof(wsec_key)); 894 wsec_key.index = htole32(wk->wk_keyix); 895 wsec_key.flags = htole32(BWFM_WSEC_PRIMARY_KEY); 896 897 if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key))) 898 return; 899 } 900 901 int 902 bwfm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 903 { 904 struct bwfm_softc *sc = ic->ic_ifp->if_softc; 905 struct bwfm_task *t; 906 907 t = pool_cache_get(sc->sc_freetask, PR_NOWAIT); 908 if (t == NULL) { 909 printf("%s: no free tasks\n", DEVNAME(sc)); 910 return EIO; 911 } 912 913 t->t_sc = sc; 914 t->t_cmd = BWFM_TASK_NEWSTATE; 915 t->t_newstate.state = nstate; 916 t->t_newstate.arg = arg; 917 workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL); 918 919 return 0; 920 } 921 922 void 923 bwfm_newstate_cb(struct bwfm_softc *sc, struct bwfm_cmd_newstate *cmd) 924 { 925 struct ieee80211com *ic = &sc->sc_ic; 926 enum ieee80211_state ostate = ic->ic_state; 927 enum ieee80211_state nstate = cmd->state; 928 int s; 929 930 DPRINTF(("%s: newstate %d -> %d\n", DEVNAME(sc), ostate, nstate)); 931 932 s = splnet(); 933 934 switch (nstate) { 935 case IEEE80211_S_INIT: 936 break; 937 938 case IEEE80211_S_SCAN: 939 if (ostate != IEEE80211_S_SCAN) { 940 /* Start of scanning */ 941 bwfm_scan(sc); 942 } 943 break; 944 945 case IEEE80211_S_AUTH: 946 bwfm_connect(sc); 947 break; 948 949 case IEEE80211_S_ASSOC: 950 break; 951 952 case IEEE80211_S_RUN: 953 break; 954 } 955 956 sc->sc_newstate(ic, nstate, cmd->arg); 957 958 splx(s); 959 } 960 961 void 962 bwfm_newassoc(struct ieee80211_node *ni, int isnew) 963 { 964 /* Firmware handles rate adaptation for us */ 965 ni->ni_txrate = 0; 966 } 967 968 void 969 bwfm_task(struct work *wk, void *arg) 970 { 971 struct bwfm_task *t = (struct bwfm_task *)wk; 972 struct bwfm_softc *sc = t->t_sc; 973 974 switch (t->t_cmd) { 975 case BWFM_TASK_NEWSTATE: 976 bwfm_newstate_cb(sc, &t->t_newstate); 977 break; 978 case BWFM_TASK_KEY_SET: 979 bwfm_key_set_cb(sc, &t->t_key); 980 break; 981 case BWFM_TASK_KEY_DELETE: 982 bwfm_key_delete_cb(sc, &t->t_key); 983 break; 984 case BWFM_TASK_RX_EVENT: 985 bwfm_rx_event_cb(sc, t->t_mbuf); 986 break; 987 default: 988 panic("bwfm: unknown task command %d", t->t_cmd); 989 } 990 991 pool_cache_put(sc->sc_freetask, t); 992 } 993 994 int 995 bwfm_media_change(struct ifnet *ifp) 996 { 997 return 0; 998 } 999 1000 /* Chip initialization (SDIO, PCIe) */ 1001 int 1002 bwfm_chip_attach(struct bwfm_softc *sc) 1003 { 1004 struct bwfm_core *core; 1005 int need_socram = 0; 1006 int has_socram = 0; 1007 int cpu_found = 0; 1008 uint32_t val; 1009 1010 LIST_INIT(&sc->sc_chip.ch_list); 1011 1012 if (sc->sc_buscore_ops->bc_prepare(sc) != 0) { 1013 printf("%s: failed buscore prepare\n", DEVNAME(sc)); 1014 return 1; 1015 } 1016 1017 val = sc->sc_buscore_ops->bc_read(sc, 1018 BWFM_CHIP_BASE + BWFM_CHIP_REG_CHIPID); 1019 sc->sc_chip.ch_chip = BWFM_CHIP_CHIPID_ID(val); 1020 sc->sc_chip.ch_chiprev = BWFM_CHIP_CHIPID_REV(val); 1021 1022 if ((sc->sc_chip.ch_chip > 0xa000) || (sc->sc_chip.ch_chip < 0x4000)) 1023 snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name), 1024 "%d", sc->sc_chip.ch_chip); 1025 else 1026 snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name), 1027 "%x", sc->sc_chip.ch_chip); 1028 1029 switch (BWFM_CHIP_CHIPID_TYPE(val)) 1030 { 1031 case BWFM_CHIP_CHIPID_TYPE_SOCI_SB: 1032 printf("%s: SoC interconnect SB not implemented\n", 1033 DEVNAME(sc)); 1034 return 1; 1035 case BWFM_CHIP_CHIPID_TYPE_SOCI_AI: 1036 sc->sc_chip.ch_core_isup = bwfm_chip_ai_isup; 1037 sc->sc_chip.ch_core_disable = bwfm_chip_ai_disable; 1038 sc->sc_chip.ch_core_reset = bwfm_chip_ai_reset; 1039 bwfm_chip_dmp_erom_scan(sc); 1040 break; 1041 default: 1042 printf("%s: SoC interconnect %d unknown\n", 1043 DEVNAME(sc), BWFM_CHIP_CHIPID_TYPE(val)); 1044 return 1; 1045 } 1046 1047 LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) { 1048 DPRINTF(("%s: 0x%x:%-2d base 0x%08x wrap 0x%08x\n", 1049 DEVNAME(sc), core->co_id, core->co_rev, 1050 core->co_base, core->co_wrapbase)); 1051 1052 switch (core->co_id) { 1053 case BWFM_AGENT_CORE_ARM_CM3: 1054 need_socram = true; 1055 /* FALLTHROUGH */ 1056 case BWFM_AGENT_CORE_ARM_CR4: 1057 case BWFM_AGENT_CORE_ARM_CA7: 1058 cpu_found = true; 1059 break; 1060 case BWFM_AGENT_INTERNAL_MEM: 1061 has_socram = true; 1062 break; 1063 default: 1064 break; 1065 } 1066 } 1067 1068 if (!cpu_found) { 1069 printf("%s: CPU core not detected\n", DEVNAME(sc)); 1070 return 1; 1071 } 1072 if (need_socram && !has_socram) { 1073 printf("%s: RAM core not provided\n", DEVNAME(sc)); 1074 return 1; 1075 } 1076 1077 bwfm_chip_set_passive(sc); 1078 1079 if (sc->sc_buscore_ops->bc_reset) { 1080 sc->sc_buscore_ops->bc_reset(sc); 1081 bwfm_chip_set_passive(sc); 1082 } 1083 1084 if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4)) != NULL) { 1085 bwfm_chip_tcm_ramsize(sc, core); 1086 bwfm_chip_tcm_rambase(sc); 1087 } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_SYS_MEM)) != NULL) { 1088 bwfm_chip_sysmem_ramsize(sc, core); 1089 bwfm_chip_tcm_rambase(sc); 1090 } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM)) != NULL) { 1091 bwfm_chip_socram_ramsize(sc, core); 1092 } 1093 1094 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); 1095 sc->sc_chip.ch_cc_caps = sc->sc_buscore_ops->bc_read(sc, 1096 core->co_base + BWFM_CHIP_REG_CAPABILITIES); 1097 sc->sc_chip.ch_cc_caps_ext = sc->sc_buscore_ops->bc_read(sc, 1098 core->co_base + BWFM_CHIP_REG_CAPABILITIES_EXT); 1099 1100 core = bwfm_chip_get_pmu(sc); 1101 if (sc->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU) { 1102 sc->sc_chip.ch_pmucaps = sc->sc_buscore_ops->bc_read(sc, 1103 core->co_base + BWFM_CHIP_REG_PMUCAPABILITIES); 1104 sc->sc_chip.ch_pmurev = sc->sc_chip.ch_pmucaps & 1105 BWFM_CHIP_REG_PMUCAPABILITIES_REV_MASK; 1106 } 1107 1108 if (sc->sc_buscore_ops->bc_setup) 1109 sc->sc_buscore_ops->bc_setup(sc); 1110 1111 return 0; 1112 } 1113 1114 struct bwfm_core * 1115 bwfm_chip_get_core(struct bwfm_softc *sc, int id) 1116 { 1117 struct bwfm_core *core; 1118 1119 LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) { 1120 if (core->co_id == id) 1121 return core; 1122 } 1123 1124 return NULL; 1125 } 1126 1127 struct bwfm_core * 1128 bwfm_chip_get_pmu(struct bwfm_softc *sc) 1129 { 1130 struct bwfm_core *cc, *pmu; 1131 1132 cc = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); 1133 if (cc->co_rev >= 35 && sc->sc_chip.ch_cc_caps_ext & 1134 BWFM_CHIP_REG_CAPABILITIES_EXT_AOB_PRESENT) { 1135 pmu = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_PMU); 1136 if (pmu) 1137 return pmu; 1138 } 1139 1140 return cc; 1141 } 1142 1143 /* Functions for the AI interconnect */ 1144 int 1145 bwfm_chip_ai_isup(struct bwfm_softc *sc, struct bwfm_core *core) 1146 { 1147 uint32_t ioctl, reset; 1148 1149 ioctl = sc->sc_buscore_ops->bc_read(sc, 1150 core->co_wrapbase + BWFM_AGENT_IOCTL); 1151 reset = sc->sc_buscore_ops->bc_read(sc, 1152 core->co_wrapbase + BWFM_AGENT_RESET_CTL); 1153 1154 if (((ioctl & (BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK)) == 1155 BWFM_AGENT_IOCTL_CLK) && 1156 ((reset & BWFM_AGENT_RESET_CTL_RESET) == 0)) 1157 return 1; 1158 1159 return 0; 1160 } 1161 1162 void 1163 bwfm_chip_ai_disable(struct bwfm_softc *sc, struct bwfm_core *core, 1164 uint32_t prereset, uint32_t reset) 1165 { 1166 uint32_t val; 1167 int i; 1168 1169 val = sc->sc_buscore_ops->bc_read(sc, 1170 core->co_wrapbase + BWFM_AGENT_RESET_CTL); 1171 if ((val & BWFM_AGENT_RESET_CTL_RESET) == 0) { 1172 1173 sc->sc_buscore_ops->bc_write(sc, 1174 core->co_wrapbase + BWFM_AGENT_IOCTL, 1175 prereset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK); 1176 sc->sc_buscore_ops->bc_read(sc, 1177 core->co_wrapbase + BWFM_AGENT_IOCTL); 1178 1179 sc->sc_buscore_ops->bc_write(sc, 1180 core->co_wrapbase + BWFM_AGENT_RESET_CTL, 1181 BWFM_AGENT_RESET_CTL_RESET); 1182 delay(20); 1183 1184 for (i = 300; i > 0; i--) { 1185 if (sc->sc_buscore_ops->bc_read(sc, 1186 core->co_wrapbase + BWFM_AGENT_RESET_CTL) == 1187 BWFM_AGENT_RESET_CTL_RESET) 1188 break; 1189 } 1190 if (i == 0) 1191 printf("%s: timeout on core reset\n", DEVNAME(sc)); 1192 } 1193 1194 sc->sc_buscore_ops->bc_write(sc, 1195 core->co_wrapbase + BWFM_AGENT_IOCTL, 1196 reset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK); 1197 sc->sc_buscore_ops->bc_read(sc, 1198 core->co_wrapbase + BWFM_AGENT_IOCTL); 1199 } 1200 1201 void 1202 bwfm_chip_ai_reset(struct bwfm_softc *sc, struct bwfm_core *core, 1203 uint32_t prereset, uint32_t reset, uint32_t postreset) 1204 { 1205 int i; 1206 1207 bwfm_chip_ai_disable(sc, core, prereset, reset); 1208 1209 for (i = 50; i > 0; i--) { 1210 if ((sc->sc_buscore_ops->bc_read(sc, 1211 core->co_wrapbase + BWFM_AGENT_RESET_CTL) & 1212 BWFM_AGENT_RESET_CTL_RESET) == 0) 1213 break; 1214 sc->sc_buscore_ops->bc_write(sc, 1215 core->co_wrapbase + BWFM_AGENT_RESET_CTL, 0); 1216 delay(60); 1217 } 1218 if (i == 0) 1219 printf("%s: timeout on core reset\n", DEVNAME(sc)); 1220 1221 sc->sc_buscore_ops->bc_write(sc, 1222 core->co_wrapbase + BWFM_AGENT_IOCTL, 1223 postreset | BWFM_AGENT_IOCTL_CLK); 1224 sc->sc_buscore_ops->bc_read(sc, 1225 core->co_wrapbase + BWFM_AGENT_IOCTL); 1226 } 1227 1228 void 1229 bwfm_chip_dmp_erom_scan(struct bwfm_softc *sc) 1230 { 1231 uint32_t erom, val, base, wrap; 1232 uint8_t type = 0; 1233 uint16_t id; 1234 uint8_t nmw, nsw, rev; 1235 struct bwfm_core *core; 1236 1237 erom = sc->sc_buscore_ops->bc_read(sc, 1238 BWFM_CHIP_BASE + BWFM_CHIP_REG_EROMPTR); 1239 while (type != BWFM_DMP_DESC_EOT) { 1240 val = sc->sc_buscore_ops->bc_read(sc, erom); 1241 type = val & BWFM_DMP_DESC_MASK; 1242 erom += 4; 1243 1244 if (type != BWFM_DMP_DESC_COMPONENT) 1245 continue; 1246 1247 id = (val & BWFM_DMP_COMP_PARTNUM) 1248 >> BWFM_DMP_COMP_PARTNUM_S; 1249 1250 val = sc->sc_buscore_ops->bc_read(sc, erom); 1251 type = val & BWFM_DMP_DESC_MASK; 1252 erom += 4; 1253 1254 if (type != BWFM_DMP_DESC_COMPONENT) { 1255 printf("%s: not component descriptor\n", DEVNAME(sc)); 1256 return; 1257 } 1258 1259 nmw = (val & BWFM_DMP_COMP_NUM_MWRAP) 1260 >> BWFM_DMP_COMP_NUM_MWRAP_S; 1261 nsw = (val & BWFM_DMP_COMP_NUM_SWRAP) 1262 >> BWFM_DMP_COMP_NUM_SWRAP_S; 1263 rev = (val & BWFM_DMP_COMP_REVISION) 1264 >> BWFM_DMP_COMP_REVISION_S; 1265 1266 if (nmw + nsw == 0 && id != BWFM_AGENT_CORE_PMU) 1267 continue; 1268 1269 if (bwfm_chip_dmp_get_regaddr(sc, &erom, &base, &wrap)) 1270 continue; 1271 1272 core = kmem_alloc(sizeof(*core), KM_SLEEP); 1273 core->co_id = id; 1274 core->co_base = base; 1275 core->co_wrapbase = wrap; 1276 core->co_rev = rev; 1277 LIST_INSERT_HEAD(&sc->sc_chip.ch_list, core, co_link); 1278 } 1279 } 1280 1281 int 1282 bwfm_chip_dmp_get_regaddr(struct bwfm_softc *sc, uint32_t *erom, 1283 uint32_t *base, uint32_t *wrap) 1284 { 1285 uint8_t type = 0, mpnum __unused = 0; 1286 uint8_t stype, sztype, wraptype; 1287 uint32_t val; 1288 1289 *base = 0; 1290 *wrap = 0; 1291 1292 val = sc->sc_buscore_ops->bc_read(sc, *erom); 1293 type = val & BWFM_DMP_DESC_MASK; 1294 if (type == BWFM_DMP_DESC_MASTER_PORT) { 1295 mpnum = (val & BWFM_DMP_MASTER_PORT_NUM) 1296 >> BWFM_DMP_MASTER_PORT_NUM_S; 1297 wraptype = BWFM_DMP_SLAVE_TYPE_MWRAP; 1298 *erom += 4; 1299 } else if ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) == 1300 BWFM_DMP_DESC_ADDRESS) 1301 wraptype = BWFM_DMP_SLAVE_TYPE_SWRAP; 1302 else 1303 return 1; 1304 1305 do { 1306 do { 1307 val = sc->sc_buscore_ops->bc_read(sc, *erom); 1308 type = val & BWFM_DMP_DESC_MASK; 1309 if (type == BWFM_DMP_DESC_COMPONENT) 1310 return 0; 1311 if (type == BWFM_DMP_DESC_EOT) 1312 return 1; 1313 *erom += 4; 1314 } while ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) != 1315 BWFM_DMP_DESC_ADDRESS); 1316 1317 if (type & BWFM_DMP_DESC_ADDRSIZE_GT32) 1318 *erom += 4; 1319 1320 sztype = (val & BWFM_DMP_SLAVE_SIZE_TYPE) 1321 >> BWFM_DMP_SLAVE_SIZE_TYPE_S; 1322 if (sztype == BWFM_DMP_SLAVE_SIZE_DESC) { 1323 val = sc->sc_buscore_ops->bc_read(sc, *erom); 1324 type = val & BWFM_DMP_DESC_MASK; 1325 if (type & BWFM_DMP_DESC_ADDRSIZE_GT32) 1326 *erom += 8; 1327 else 1328 *erom += 4; 1329 } 1330 if (sztype != BWFM_DMP_SLAVE_SIZE_4K) 1331 continue; 1332 1333 stype = (val & BWFM_DMP_SLAVE_TYPE) >> BWFM_DMP_SLAVE_TYPE_S; 1334 if (*base == 0 && stype == BWFM_DMP_SLAVE_TYPE_SLAVE) 1335 *base = val & BWFM_DMP_SLAVE_ADDR_BASE; 1336 if (*wrap == 0 && stype == wraptype) 1337 *wrap = val & BWFM_DMP_SLAVE_ADDR_BASE; 1338 } while (*base == 0 || *wrap == 0); 1339 1340 return 0; 1341 } 1342 1343 /* Core configuration */ 1344 int 1345 bwfm_chip_set_active(struct bwfm_softc *sc, const uint32_t rstvec) 1346 { 1347 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) 1348 return bwfm_chip_cr4_set_active(sc, rstvec); 1349 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) 1350 return bwfm_chip_ca7_set_active(sc, rstvec); 1351 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) 1352 return bwfm_chip_cm3_set_active(sc); 1353 return 1; 1354 } 1355 1356 void 1357 bwfm_chip_set_passive(struct bwfm_softc *sc) 1358 { 1359 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) { 1360 bwfm_chip_cr4_set_passive(sc); 1361 return; 1362 } 1363 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) { 1364 bwfm_chip_ca7_set_passive(sc); 1365 return; 1366 } 1367 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) { 1368 bwfm_chip_cm3_set_passive(sc); 1369 return; 1370 } 1371 } 1372 1373 int 1374 bwfm_chip_cr4_set_active(struct bwfm_softc *sc, const uint32_t rstvec) 1375 { 1376 struct bwfm_core *core; 1377 1378 sc->sc_buscore_ops->bc_activate(sc, rstvec); 1379 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4); 1380 sc->sc_chip.ch_core_reset(sc, core, 1381 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0); 1382 1383 return 0; 1384 } 1385 1386 void 1387 bwfm_chip_cr4_set_passive(struct bwfm_softc *sc) 1388 { 1389 struct bwfm_core *core; 1390 uint32_t val; 1391 1392 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4); 1393 val = sc->sc_buscore_ops->bc_read(sc, 1394 core->co_wrapbase + BWFM_AGENT_IOCTL); 1395 sc->sc_chip.ch_core_reset(sc, core, 1396 val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 1397 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 1398 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT); 1399 1400 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); 1401 sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | 1402 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, 1403 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); 1404 } 1405 1406 int 1407 bwfm_chip_ca7_set_active(struct bwfm_softc *sc, const uint32_t rstvec) 1408 { 1409 struct bwfm_core *core; 1410 1411 sc->sc_buscore_ops->bc_activate(sc, rstvec); 1412 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7); 1413 sc->sc_chip.ch_core_reset(sc, core, 1414 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0); 1415 1416 return 0; 1417 } 1418 1419 void 1420 bwfm_chip_ca7_set_passive(struct bwfm_softc *sc) 1421 { 1422 struct bwfm_core *core; 1423 uint32_t val; 1424 1425 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7); 1426 val = sc->sc_buscore_ops->bc_read(sc, 1427 core->co_wrapbase + BWFM_AGENT_IOCTL); 1428 sc->sc_chip.ch_core_reset(sc, core, 1429 val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 1430 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 1431 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT); 1432 1433 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); 1434 sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | 1435 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, 1436 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); 1437 } 1438 1439 int 1440 bwfm_chip_cm3_set_active(struct bwfm_softc *sc) 1441 { 1442 struct bwfm_core *core; 1443 1444 core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM); 1445 if (!sc->sc_chip.ch_core_isup(sc, core)) 1446 return 1; 1447 1448 sc->sc_buscore_ops->bc_activate(sc, 0); 1449 1450 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3); 1451 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); 1452 1453 return 0; 1454 } 1455 1456 void 1457 bwfm_chip_cm3_set_passive(struct bwfm_softc *sc) 1458 { 1459 struct bwfm_core *core; 1460 1461 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3); 1462 sc->sc_chip.ch_core_disable(sc, core, 0, 0); 1463 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); 1464 sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | 1465 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, 1466 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); 1467 core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM); 1468 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); 1469 1470 if (sc->sc_chip.ch_chip == BRCM_CC_43430_CHIP_ID) { 1471 sc->sc_buscore_ops->bc_write(sc, 1472 core->co_base + BWFM_SOCRAM_BANKIDX, 3); 1473 sc->sc_buscore_ops->bc_write(sc, 1474 core->co_base + BWFM_SOCRAM_BANKPDA, 0); 1475 } 1476 } 1477 1478 int 1479 bwfm_chip_sr_capable(struct bwfm_softc *sc) 1480 { 1481 struct bwfm_core *core; 1482 uint32_t reg; 1483 1484 if (sc->sc_chip.ch_pmurev < 17) 1485 return 0; 1486 1487 switch (sc->sc_chip.ch_chip) { 1488 case BRCM_CC_4345_CHIP_ID: 1489 case BRCM_CC_4354_CHIP_ID: 1490 case BRCM_CC_4356_CHIP_ID: 1491 core = bwfm_chip_get_pmu(sc); 1492 sc->sc_buscore_ops->bc_write(sc, core->co_base + 1493 BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3); 1494 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + 1495 BWFM_CHIP_REG_CHIPCONTROL_DATA); 1496 return (reg & (1 << 2)) != 0; 1497 case BRCM_CC_43241_CHIP_ID: 1498 case BRCM_CC_4335_CHIP_ID: 1499 case BRCM_CC_4339_CHIP_ID: 1500 core = bwfm_chip_get_pmu(sc); 1501 sc->sc_buscore_ops->bc_write(sc, core->co_base + 1502 BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3); 1503 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + 1504 BWFM_CHIP_REG_CHIPCONTROL_DATA); 1505 return reg != 0; 1506 case BRCM_CC_43430_CHIP_ID: 1507 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); 1508 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + 1509 BWFM_CHIP_REG_SR_CONTROL1); 1510 return reg != 0; 1511 default: 1512 core = bwfm_chip_get_pmu(sc); 1513 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + 1514 BWFM_CHIP_REG_PMUCAPABILITIES_EXT); 1515 if ((reg & BWFM_CHIP_REG_PMUCAPABILITIES_SR_SUPP) == 0) 1516 return 0; 1517 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + 1518 BWFM_CHIP_REG_RETENTION_CTL); 1519 return (reg & (BWFM_CHIP_REG_RETENTION_CTL_MACPHY_DIS | 1520 BWFM_CHIP_REG_RETENTION_CTL_LOGIC_DIS)) == 0; 1521 } 1522 } 1523 1524 /* RAM size helpers */ 1525 void 1526 bwfm_chip_socram_ramsize(struct bwfm_softc *sc, struct bwfm_core *core) 1527 { 1528 uint32_t coreinfo, nb, lss, banksize, bankinfo; 1529 uint32_t ramsize = 0, srsize = 0; 1530 int i; 1531 1532 if (!sc->sc_chip.ch_core_isup(sc, core)) 1533 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); 1534 1535 coreinfo = sc->sc_buscore_ops->bc_read(sc, 1536 core->co_base + BWFM_SOCRAM_COREINFO); 1537 nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK) 1538 >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT; 1539 1540 if (core->co_rev <= 7 || core->co_rev == 12) { 1541 banksize = coreinfo & BWFM_SOCRAM_COREINFO_SRBSZ_MASK; 1542 lss = (coreinfo & BWFM_SOCRAM_COREINFO_LSS_MASK) 1543 >> BWFM_SOCRAM_COREINFO_LSS_SHIFT; 1544 if (lss != 0) 1545 nb--; 1546 ramsize = nb * (1 << (banksize + BWFM_SOCRAM_COREINFO_SRBSZ_BASE)); 1547 if (lss != 0) 1548 ramsize += (1 << ((lss - 1) + BWFM_SOCRAM_COREINFO_SRBSZ_BASE)); 1549 } else { 1550 for (i = 0; i < nb; i++) { 1551 sc->sc_buscore_ops->bc_write(sc, 1552 core->co_base + BWFM_SOCRAM_BANKIDX, 1553 (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM << 1554 BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i); 1555 bankinfo = sc->sc_buscore_ops->bc_read(sc, 1556 core->co_base + BWFM_SOCRAM_BANKINFO); 1557 banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1) 1558 * BWFM_SOCRAM_BANKINFO_SZBASE; 1559 ramsize += banksize; 1560 if (bankinfo & BWFM_SOCRAM_BANKINFO_RETNTRAM_MASK) 1561 srsize += banksize; 1562 } 1563 } 1564 1565 switch (sc->sc_chip.ch_chip) { 1566 case BRCM_CC_4334_CHIP_ID: 1567 if (sc->sc_chip.ch_chiprev < 2) 1568 srsize = 32 * 1024; 1569 break; 1570 case BRCM_CC_43430_CHIP_ID: 1571 srsize = 64 * 1024; 1572 break; 1573 default: 1574 break; 1575 } 1576 1577 sc->sc_chip.ch_ramsize = ramsize; 1578 sc->sc_chip.ch_srsize = srsize; 1579 } 1580 1581 void 1582 bwfm_chip_sysmem_ramsize(struct bwfm_softc *sc, struct bwfm_core *core) 1583 { 1584 uint32_t coreinfo, nb, banksize, bankinfo; 1585 uint32_t ramsize = 0; 1586 int i; 1587 1588 if (!sc->sc_chip.ch_core_isup(sc, core)) 1589 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); 1590 1591 coreinfo = sc->sc_buscore_ops->bc_read(sc, 1592 core->co_base + BWFM_SOCRAM_COREINFO); 1593 nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK) 1594 >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT; 1595 1596 for (i = 0; i < nb; i++) { 1597 sc->sc_buscore_ops->bc_write(sc, 1598 core->co_base + BWFM_SOCRAM_BANKIDX, 1599 (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM << 1600 BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i); 1601 bankinfo = sc->sc_buscore_ops->bc_read(sc, 1602 core->co_base + BWFM_SOCRAM_BANKINFO); 1603 banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1) 1604 * BWFM_SOCRAM_BANKINFO_SZBASE; 1605 ramsize += banksize; 1606 } 1607 1608 sc->sc_chip.ch_ramsize = ramsize; 1609 } 1610 1611 void 1612 bwfm_chip_tcm_ramsize(struct bwfm_softc *sc, struct bwfm_core *core) 1613 { 1614 uint32_t cap, nab, nbb, totb, bxinfo, ramsize = 0; 1615 int i; 1616 1617 cap = sc->sc_buscore_ops->bc_read(sc, core->co_base + BWFM_ARMCR4_CAP); 1618 nab = (cap & BWFM_ARMCR4_CAP_TCBANB_MASK) >> BWFM_ARMCR4_CAP_TCBANB_SHIFT; 1619 nbb = (cap & BWFM_ARMCR4_CAP_TCBBNB_MASK) >> BWFM_ARMCR4_CAP_TCBBNB_SHIFT; 1620 totb = nab + nbb; 1621 1622 for (i = 0; i < totb; i++) { 1623 sc->sc_buscore_ops->bc_write(sc, 1624 core->co_base + BWFM_ARMCR4_BANKIDX, i); 1625 bxinfo = sc->sc_buscore_ops->bc_read(sc, 1626 core->co_base + BWFM_ARMCR4_BANKINFO); 1627 ramsize += ((bxinfo & BWFM_ARMCR4_BANKINFO_BSZ_MASK) + 1) * 1628 BWFM_ARMCR4_BANKINFO_BSZ_MULT; 1629 } 1630 1631 sc->sc_chip.ch_ramsize = ramsize; 1632 } 1633 1634 void 1635 bwfm_chip_tcm_rambase(struct bwfm_softc *sc) 1636 { 1637 switch (sc->sc_chip.ch_chip) { 1638 case BRCM_CC_4345_CHIP_ID: 1639 sc->sc_chip.ch_rambase = 0x198000; 1640 break; 1641 case BRCM_CC_4335_CHIP_ID: 1642 case BRCM_CC_4339_CHIP_ID: 1643 case BRCM_CC_4350_CHIP_ID: 1644 case BRCM_CC_4354_CHIP_ID: 1645 case BRCM_CC_4356_CHIP_ID: 1646 case BRCM_CC_43567_CHIP_ID: 1647 case BRCM_CC_43569_CHIP_ID: 1648 case BRCM_CC_43570_CHIP_ID: 1649 case BRCM_CC_4358_CHIP_ID: 1650 case BRCM_CC_4359_CHIP_ID: 1651 case BRCM_CC_43602_CHIP_ID: 1652 case BRCM_CC_4371_CHIP_ID: 1653 sc->sc_chip.ch_rambase = 0x180000; 1654 break; 1655 case BRCM_CC_43465_CHIP_ID: 1656 case BRCM_CC_43525_CHIP_ID: 1657 case BRCM_CC_4365_CHIP_ID: 1658 case BRCM_CC_4366_CHIP_ID: 1659 sc->sc_chip.ch_rambase = 0x200000; 1660 break; 1661 case CY_CC_4373_CHIP_ID: 1662 sc->sc_chip.ch_rambase = 0x160000; 1663 break; 1664 default: 1665 printf("%s: unknown chip: %d\n", DEVNAME(sc), 1666 sc->sc_chip.ch_chip); 1667 break; 1668 } 1669 } 1670 1671 /* BCDC protocol implementation */ 1672 int 1673 bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *sc, int ifidx, 1674 int cmd, char *buf, size_t *len) 1675 { 1676 struct bwfm_proto_bcdc_dcmd *dcmd; 1677 size_t size = sizeof(dcmd->hdr) + *len; 1678 int reqid; 1679 int ret = 1; 1680 1681 reqid = sc->sc_bcdc_reqid++; 1682 1683 dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP); 1684 if (*len > sizeof(dcmd->buf)) 1685 goto err; 1686 1687 dcmd->hdr.cmd = htole32(cmd); 1688 dcmd->hdr.len = htole32(*len); 1689 dcmd->hdr.flags |= BWFM_BCDC_DCMD_GET; 1690 dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid); 1691 dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx); 1692 dcmd->hdr.flags = htole32(dcmd->hdr.flags); 1693 memcpy(&dcmd->buf, buf, *len); 1694 1695 if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd, 1696 sizeof(dcmd->hdr) + *len)) { 1697 DPRINTF(("%s: tx failed\n", DEVNAME(sc))); 1698 goto err; 1699 } 1700 1701 do { 1702 if (sc->sc_bus_ops->bs_rxctl(sc, (void *)dcmd, &size)) { 1703 DPRINTF(("%s: rx failed\n", DEVNAME(sc))); 1704 goto err; 1705 } 1706 dcmd->hdr.cmd = le32toh(dcmd->hdr.cmd); 1707 dcmd->hdr.len = le32toh(dcmd->hdr.len); 1708 dcmd->hdr.flags = le32toh(dcmd->hdr.flags); 1709 dcmd->hdr.status = le32toh(dcmd->hdr.status); 1710 } while (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid); 1711 1712 if (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid) { 1713 printf("%s: unexpected request id\n", DEVNAME(sc)); 1714 goto err; 1715 } 1716 1717 if (buf) { 1718 if (size < *len) 1719 *len = size; 1720 memcpy(buf, dcmd->buf, *len); 1721 } 1722 1723 if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR) 1724 ret = dcmd->hdr.status; 1725 else 1726 ret = 0; 1727 err: 1728 kmem_free(dcmd, sizeof(*dcmd)); 1729 return ret; 1730 } 1731 1732 int 1733 bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *sc, int ifidx, 1734 int cmd, char *buf, size_t len) 1735 { 1736 struct bwfm_proto_bcdc_dcmd *dcmd; 1737 size_t size = sizeof(dcmd->hdr) + len; 1738 int ret = 1, reqid; 1739 1740 reqid = sc->sc_bcdc_reqid++; 1741 1742 dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP); 1743 if (len > sizeof(dcmd->buf)) 1744 goto err; 1745 1746 dcmd->hdr.cmd = htole32(cmd); 1747 dcmd->hdr.len = htole32(len); 1748 dcmd->hdr.flags |= BWFM_BCDC_DCMD_SET; 1749 dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid); 1750 dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx); 1751 dcmd->hdr.flags = htole32(dcmd->hdr.flags); 1752 memcpy(&dcmd->buf, buf, len); 1753 1754 if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd, size)) { 1755 DPRINTF(("%s: tx failed\n", DEVNAME(sc))); 1756 goto err; 1757 } 1758 1759 do { 1760 if (sc->sc_bus_ops->bs_rxctl(sc, (void *)dcmd, &size)) { 1761 DPRINTF(("%s: rx failed\n", DEVNAME(sc))); 1762 goto err; 1763 } 1764 dcmd->hdr.cmd = le32toh(dcmd->hdr.cmd); 1765 dcmd->hdr.len = le32toh(dcmd->hdr.len); 1766 dcmd->hdr.flags = le32toh(dcmd->hdr.flags); 1767 dcmd->hdr.status = le32toh(dcmd->hdr.status); 1768 } while (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid); 1769 1770 if (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid) { 1771 printf("%s: unexpected request id\n", DEVNAME(sc)); 1772 goto err; 1773 } 1774 1775 if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR) 1776 return dcmd->hdr.status; 1777 1778 ret = 0; 1779 err: 1780 kmem_free(dcmd, sizeof(*dcmd)); 1781 return ret; 1782 } 1783 1784 /* FW Variable code */ 1785 int 1786 bwfm_fwvar_cmd_get_data(struct bwfm_softc *sc, int cmd, void *data, size_t len) 1787 { 1788 return sc->sc_proto_ops->proto_query_dcmd(sc, 0, cmd, data, &len); 1789 } 1790 1791 int 1792 bwfm_fwvar_cmd_set_data(struct bwfm_softc *sc, int cmd, void *data, size_t len) 1793 { 1794 return sc->sc_proto_ops->proto_set_dcmd(sc, 0, cmd, data, len); 1795 } 1796 1797 int 1798 bwfm_fwvar_cmd_get_int(struct bwfm_softc *sc, int cmd, uint32_t *data) 1799 { 1800 int ret; 1801 ret = bwfm_fwvar_cmd_get_data(sc, cmd, data, sizeof(*data)); 1802 *data = le32toh(*data); 1803 return ret; 1804 } 1805 1806 int 1807 bwfm_fwvar_cmd_set_int(struct bwfm_softc *sc, int cmd, uint32_t data) 1808 { 1809 data = htole32(data); 1810 return bwfm_fwvar_cmd_set_data(sc, cmd, &data, sizeof(data)); 1811 } 1812 1813 int 1814 bwfm_fwvar_var_get_data(struct bwfm_softc *sc, const char *name, void *data, size_t len) 1815 { 1816 char *buf; 1817 int ret; 1818 1819 buf = kmem_alloc(strlen(name) + 1 + len, KM_SLEEP); 1820 memcpy(buf, name, strlen(name) + 1); 1821 memcpy(buf + strlen(name) + 1, data, len); 1822 ret = bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_VAR, 1823 buf, strlen(name) + 1 + len); 1824 memcpy(data, buf, len); 1825 kmem_free(buf, strlen(name) + 1 + len); 1826 return ret; 1827 } 1828 1829 int 1830 bwfm_fwvar_var_set_data(struct bwfm_softc *sc, const char *name, void *data, size_t len) 1831 { 1832 char *buf; 1833 int ret; 1834 1835 buf = kmem_alloc(strlen(name) + 1 + len, KM_SLEEP); 1836 memcpy(buf, name, strlen(name) + 1); 1837 memcpy(buf + strlen(name) + 1, data, len); 1838 ret = bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_VAR, 1839 buf, strlen(name) + 1 + len); 1840 kmem_free(buf, strlen(name) + 1 + len); 1841 return ret; 1842 } 1843 1844 int 1845 bwfm_fwvar_var_get_int(struct bwfm_softc *sc, const char *name, uint32_t *data) 1846 { 1847 int ret; 1848 ret = bwfm_fwvar_var_get_data(sc, name, data, sizeof(*data)); 1849 *data = le32toh(*data); 1850 return ret; 1851 } 1852 1853 int 1854 bwfm_fwvar_var_set_int(struct bwfm_softc *sc, const char *name, uint32_t data) 1855 { 1856 data = htole32(data); 1857 return bwfm_fwvar_var_set_data(sc, name, &data, sizeof(data)); 1858 } 1859 1860 /* 802.11 code */ 1861 void 1862 bwfm_scan(struct bwfm_softc *sc) 1863 { 1864 struct bwfm_escan_params *params; 1865 uint32_t nssid = 0, nchannel = 0; 1866 size_t params_size; 1867 1868 #if 0 1869 /* Active scan is used for scanning for an SSID */ 1870 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PASSIVE_SCAN, 0); 1871 #endif 1872 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PASSIVE_SCAN, 1); 1873 1874 params_size = sizeof(*params); 1875 params_size += sizeof(uint32_t) * ((nchannel + 1) / 2); 1876 params_size += sizeof(struct bwfm_ssid) * nssid; 1877 1878 params = kmem_zalloc(params_size, KM_SLEEP); 1879 memset(params->scan_params.bssid, 0xff, 1880 sizeof(params->scan_params.bssid)); 1881 params->scan_params.bss_type = 2; 1882 params->scan_params.nprobes = htole32(-1); 1883 params->scan_params.active_time = htole32(-1); 1884 params->scan_params.passive_time = htole32(-1); 1885 params->scan_params.home_time = htole32(-1); 1886 params->version = htole32(BWFM_ESCAN_REQ_VERSION); 1887 params->action = htole16(WL_ESCAN_ACTION_START); 1888 params->sync_id = htole16(0x1234); 1889 1890 #if 0 1891 /* Scan a specific channel */ 1892 params->scan_params.channel_list[0] = htole16( 1893 (1 & 0xff) << 0 | 1894 (3 & 0x3) << 8 | 1895 (2 & 0x3) << 10 | 1896 (2 & 0x3) << 12 1897 ); 1898 params->scan_params.channel_num = htole32( 1899 (1 & 0xffff) << 0 1900 ); 1901 #endif 1902 1903 bwfm_fwvar_var_set_data(sc, "escan", params, params_size); 1904 kmem_free(params, params_size); 1905 } 1906 1907 static __inline int 1908 bwfm_iswpaoui(const uint8_t *frm) 1909 { 1910 return frm[1] > 3 && le32dec(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); 1911 } 1912 1913 /* 1914 * Derive wireless security settings from WPA/RSN IE. 1915 */ 1916 static uint32_t 1917 bwfm_get_wsec(struct bwfm_softc *sc) 1918 { 1919 struct ieee80211com *ic = &sc->sc_ic; 1920 uint8_t *wpa = ic->ic_opt_ie; 1921 1922 KASSERT(ic->ic_opt_ie_len > 0); 1923 1924 if (wpa[0] != IEEE80211_ELEMID_RSN) { 1925 if (ic->ic_opt_ie_len < 12) 1926 return BWFM_WSEC_NONE; 1927 1928 /* non-RSN IE, expect that we are doing WPA1 */ 1929 if ((ic->ic_flags & IEEE80211_F_WPA1) == 0) 1930 return BWFM_WSEC_NONE; 1931 1932 /* Must contain WPA OUI */ 1933 if (!bwfm_iswpaoui(wpa)) 1934 return BWFM_WSEC_NONE; 1935 1936 switch (le32dec(wpa + 8)) { 1937 case ((WPA_CSE_TKIP<<24)|WPA_OUI): 1938 return BWFM_WSEC_TKIP; 1939 case ((WPA_CSE_CCMP<<24)|WPA_OUI): 1940 return BWFM_WSEC_AES; 1941 default: 1942 return BWFM_WSEC_NONE; 1943 } 1944 } else { 1945 if (ic->ic_opt_ie_len < 14) 1946 return BWFM_WSEC_NONE; 1947 1948 /* RSN IE, expect that we are doing WPA2 */ 1949 if ((ic->ic_flags & IEEE80211_F_WPA2) == 0) 1950 return BWFM_WSEC_NONE; 1951 1952 switch (le32dec(wpa + 10)) { 1953 case ((RSN_CSE_TKIP<<24)|RSN_OUI): 1954 return BWFM_WSEC_TKIP; 1955 case ((RSN_CSE_CCMP<<24)|RSN_OUI): 1956 return BWFM_WSEC_AES; 1957 default: 1958 return BWFM_WSEC_NONE; 1959 } 1960 } 1961 } 1962 1963 void 1964 bwfm_connect(struct bwfm_softc *sc) 1965 { 1966 struct ieee80211com *ic = &sc->sc_ic; 1967 struct ieee80211_node *ni = ic->ic_bss; 1968 struct bwfm_ext_join_params *params; 1969 1970 if (ic->ic_flags & IEEE80211_F_WPA) { 1971 uint32_t wsec = 0; 1972 uint32_t wpa = 0; 1973 1974 if (ic->ic_opt_ie_len) 1975 bwfm_fwvar_var_set_data(sc, "wpaie", ic->ic_opt_ie, ic->ic_opt_ie_len); 1976 1977 if (ic->ic_flags & IEEE80211_F_WPA1) 1978 wpa |= BWFM_WPA_AUTH_WPA_PSK; 1979 if (ic->ic_flags & IEEE80211_F_WPA2) 1980 wpa |= BWFM_WPA_AUTH_WPA2_PSK; 1981 1982 wsec |= bwfm_get_wsec(sc); 1983 1984 DPRINTF(("%s: WPA enabled, ic_flags = 0x%x, wpa 0x%x, wsec 0x%x\n", 1985 DEVNAME(sc), ic->ic_flags, wpa, wsec)); 1986 1987 bwfm_fwvar_var_set_int(sc, "wpa_auth", wpa); 1988 bwfm_fwvar_var_set_int(sc, "wsec", wsec); 1989 } else { 1990 bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_DISABLED); 1991 bwfm_fwvar_var_set_int(sc, "wsec", BWFM_WSEC_NONE); 1992 } 1993 1994 bwfm_fwvar_var_set_int(sc, "auth", BWFM_AUTH_OPEN); 1995 bwfm_fwvar_var_set_int(sc, "mfp", BWFM_MFP_NONE); 1996 1997 if (ni->ni_esslen && ni->ni_esslen < BWFM_MAX_SSID_LEN) { 1998 params = kmem_zalloc(sizeof(*params), KM_SLEEP); 1999 memcpy(params->ssid.ssid, ni->ni_essid, ni->ni_esslen); 2000 params->ssid.len = htole32(ni->ni_esslen); 2001 memcpy(params->assoc.bssid, ni->ni_bssid, sizeof(params->assoc.bssid)); 2002 params->scan.scan_type = -1; 2003 params->scan.nprobes = htole32(-1); 2004 params->scan.active_time = htole32(-1); 2005 params->scan.passive_time = htole32(-1); 2006 params->scan.home_time = htole32(-1); 2007 if (bwfm_fwvar_var_set_data(sc, "join", params, sizeof(*params))) { 2008 struct bwfm_join_params join; 2009 memset(&join, 0, sizeof(join)); 2010 memcpy(join.ssid.ssid, ni->ni_essid, ni->ni_esslen); 2011 join.ssid.len = htole32(ni->ni_esslen); 2012 memcpy(join.assoc.bssid, ni->ni_bssid, sizeof(join.assoc.bssid)); 2013 bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, 2014 sizeof(join)); 2015 } 2016 kmem_free(params, sizeof(*params)); 2017 } 2018 } 2019 2020 void 2021 bwfm_get_sta_info(struct bwfm_softc *sc, struct ifmediareq *ifmr) 2022 { 2023 struct ieee80211com *ic = &sc->sc_ic; 2024 struct ieee80211_node *ni = ic->ic_bss; 2025 struct bwfm_sta_info sta; 2026 uint32_t flags, txrate; 2027 2028 memset(&sta, 0, sizeof(sta)); 2029 memcpy(&sta, ni->ni_macaddr, sizeof(ni->ni_macaddr)); 2030 2031 if (bwfm_fwvar_var_get_data(sc, "sta_info", &sta, sizeof(sta))) 2032 return; 2033 2034 if (!IEEE80211_ADDR_EQ(ni->ni_macaddr, sta.ea)) 2035 return; 2036 2037 if (le16toh(sta.ver) < 4) 2038 return; 2039 2040 flags = le32toh(sta.flags); 2041 if ((flags & BWFM_STA_SCBSTATS) == 0) 2042 return; 2043 2044 txrate = le32toh(sta.tx_rate); 2045 if (txrate == 0xffffffff) 2046 return; 2047 2048 if ((flags & BWFM_STA_VHT_CAP) != 0) { 2049 ifmr->ifm_active &= ~IFM_TMASK; 2050 ifmr->ifm_active |= IFM_IEEE80211_VHT; 2051 ifmr->ifm_active &= ~IFM_MMASK; 2052 ifmr->ifm_active |= IFM_IEEE80211_11AC; 2053 } else if ((flags & BWFM_STA_N_CAP) != 0) { 2054 ifmr->ifm_active &= ~IFM_TMASK; 2055 ifmr->ifm_active |= IFM_IEEE80211_MCS; 2056 ifmr->ifm_active &= ~IFM_MMASK; 2057 if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) 2058 ifmr->ifm_active |= IFM_IEEE80211_11NG; 2059 else 2060 ifmr->ifm_active |= IFM_IEEE80211_11NA; 2061 } 2062 } 2063 2064 void 2065 bwfm_rx(struct bwfm_softc *sc, struct mbuf *m) 2066 { 2067 struct ieee80211com *ic = &sc->sc_ic; 2068 struct ifnet *ifp = ic->ic_ifp; 2069 struct bwfm_event *e = mtod(m, struct bwfm_event *); 2070 2071 if (m->m_len >= sizeof(e->ehdr) && 2072 ntohs(e->ehdr.ether_type) == BWFM_ETHERTYPE_LINK_CTL && 2073 memcmp(BWFM_BRCM_OUI, e->hdr.oui, sizeof(e->hdr.oui)) == 0 && 2074 ntohs(e->hdr.usr_subtype) == BWFM_BRCM_SUBTYPE_EVENT) { 2075 bwfm_rx_event(sc, m); 2076 // m_freem(m); 2077 return; 2078 } 2079 2080 m_set_rcvif(m, ifp); 2081 if_percpuq_enqueue(ifp->if_percpuq, m); 2082 } 2083 2084 void 2085 bwfm_rx_event(struct bwfm_softc *sc, struct mbuf *m) 2086 { 2087 struct bwfm_task *t; 2088 2089 t = pool_cache_get(sc->sc_freetask, PR_NOWAIT); 2090 if (t == NULL) { 2091 m_freem(m); 2092 printf("%s: no free tasks\n", DEVNAME(sc)); 2093 return; 2094 } 2095 2096 t->t_sc = sc; 2097 t->t_cmd = BWFM_TASK_RX_EVENT; 2098 t->t_mbuf = m; 2099 workqueue_enqueue(sc->sc_taskq, (struct work*)t, NULL); 2100 } 2101 2102 void 2103 bwfm_rx_event_cb(struct bwfm_softc *sc, struct mbuf *m) 2104 { 2105 struct ieee80211com *ic = &sc->sc_ic; 2106 struct bwfm_event *e = mtod(m, void *); 2107 size_t len = m->m_len; 2108 int s; 2109 2110 DPRINTF(("%s: event %p len %lu datalen %u code %u status %u" 2111 " reason %u\n", __func__, e, len, ntohl(e->msg.datalen), 2112 ntohl(e->msg.event_type), ntohl(e->msg.status), 2113 ntohl(e->msg.reason))); 2114 2115 if (ntohl(e->msg.event_type) >= BWFM_E_LAST) { 2116 m_freem(m); 2117 return; 2118 } 2119 2120 switch (ntohl(e->msg.event_type)) { 2121 case BWFM_E_ESCAN_RESULT: { 2122 struct bwfm_escan_results *res = (void *)&e[1]; 2123 struct bwfm_bss_info *bss; 2124 int i; 2125 if (ntohl(e->msg.status) != BWFM_E_STATUS_PARTIAL) { 2126 /* Scan complete */ 2127 s = splnet(); 2128 if (ic->ic_opmode != IEEE80211_M_MONITOR) 2129 ieee80211_end_scan(ic); 2130 splx(s); 2131 break; 2132 } 2133 len -= sizeof(*e); 2134 if (len < sizeof(*res) || len < le32toh(res->buflen)) { 2135 m_freem(m); 2136 printf("%s: results too small\n", DEVNAME(sc)); 2137 return; 2138 } 2139 len -= sizeof(*res); 2140 if (len < le16toh(res->bss_count) * sizeof(struct bwfm_bss_info)) { 2141 m_freem(m); 2142 printf("%s: results too small\n", DEVNAME(sc)); 2143 return; 2144 } 2145 bss = &res->bss_info[0]; 2146 for (i = 0; i < le16toh(res->bss_count); i++) { 2147 /* Fix alignment of bss_info */ 2148 if (len > sizeof(sc->sc_bss_buf)) { 2149 printf("%s: bss_info buffer too big\n", DEVNAME(sc)); 2150 } else { 2151 memcpy(&sc->sc_bss_buf, &res->bss_info[i], len); 2152 bwfm_scan_node(sc, &sc->sc_bss_buf.bss_info, 2153 len); 2154 } 2155 len -= sizeof(*bss) + le32toh(bss->length); 2156 bss = (void *)(((uintptr_t)bss) + le32toh(bss->length)); 2157 if (len <= 0) 2158 break; 2159 } 2160 break; 2161 } 2162 2163 case BWFM_E_SET_SSID: 2164 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS) { 2165 ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 2166 } else { 2167 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 2168 } 2169 break; 2170 2171 case BWFM_E_ASSOC: 2172 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS) { 2173 ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1); 2174 } else { 2175 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 2176 } 2177 break; 2178 2179 case BWFM_E_LINK: 2180 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS && 2181 ntohl(e->msg.reason) == 0) 2182 break; 2183 2184 /* Link status has changed */ 2185 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 2186 break; 2187 2188 default: 2189 break; 2190 } 2191 2192 m_freem(m); 2193 } 2194 2195 void 2196 bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_info *bss, size_t len) 2197 { 2198 struct ieee80211com *ic = &sc->sc_ic; 2199 struct ieee80211_frame wh; 2200 struct ieee80211_scanparams scan; 2201 uint8_t rates[sizeof(bss->rates) + 2]; 2202 uint8_t ssid[sizeof(bss->ssid) + 2]; 2203 uint8_t *frm, *sfrm, *efrm; 2204 uint64_t tsf; 2205 2206 tsf = 0; 2207 sfrm = ((uint8_t *)bss) + le16toh(bss->ie_offset); 2208 efrm = sfrm + le32toh(bss->ie_length); 2209 2210 /* Fake a wireless header with the scan result's BSSID */ 2211 memset(&wh, 0, sizeof(wh)); 2212 IEEE80211_ADDR_COPY(wh.i_addr2, bss->bssid); 2213 IEEE80211_ADDR_COPY(wh.i_addr3, bss->bssid); 2214 2215 if (efrm - sfrm < 12) { 2216 ic->ic_stats.is_rx_elem_toosmall++; 2217 return; 2218 } 2219 2220 rates[0] = 0; 2221 rates[1] = le32toh(bss->nrates); 2222 memcpy(&rates[2], bss->rates, sizeof(bss->rates)); 2223 2224 ssid[0] = 0; 2225 ssid[1] = bss->ssid_len; 2226 memcpy(&ssid[2], bss->ssid, sizeof(bss->ssid)); 2227 2228 /* Build scan result */ 2229 memset(&scan, 0, sizeof(scan)); 2230 scan.sp_tstamp = (uint8_t *)&tsf; 2231 scan.sp_bintval = le16toh(bss->beacon_period); 2232 scan.sp_capinfo = le16toh(bss->capability); 2233 scan.sp_bchan = ieee80211_chan2ieee(ic, ic->ic_curchan); 2234 scan.sp_chan = scan.sp_bchan; 2235 scan.sp_rates = rates; 2236 scan.sp_ssid = ssid; 2237 2238 for (frm = sfrm; frm < efrm; frm += frm[1] + 2) { 2239 switch (frm[0]) { 2240 case IEEE80211_ELEMID_COUNTRY: 2241 scan.sp_country = frm; 2242 break; 2243 case IEEE80211_ELEMID_FHPARMS: 2244 if (ic->ic_phytype == IEEE80211_T_FH) { 2245 if (frm + 6 >= efrm) 2246 break; 2247 scan.sp_fhdwell = le16dec(&frm[2]); 2248 scan.sp_chan = IEEE80211_FH_CHAN(frm[4], frm[5]); 2249 scan.sp_fhindex = frm[6]; 2250 } 2251 break; 2252 case IEEE80211_ELEMID_DSPARMS: 2253 if (ic->ic_phytype != IEEE80211_T_FH) { 2254 if (frm + 2 >= efrm) 2255 break; 2256 scan.sp_chan = frm[2]; 2257 } 2258 break; 2259 case IEEE80211_ELEMID_TIM: 2260 scan.sp_tim = frm; 2261 scan.sp_timoff = frm - sfrm; 2262 break; 2263 case IEEE80211_ELEMID_XRATES: 2264 scan.sp_xrates = frm; 2265 break; 2266 case IEEE80211_ELEMID_ERP: 2267 if (frm + 1 >= efrm) 2268 break; 2269 if (frm[1] != 1) { 2270 ic->ic_stats.is_rx_elem_toobig++; 2271 break; 2272 } 2273 scan.sp_erp = frm[2]; 2274 break; 2275 case IEEE80211_ELEMID_RSN: 2276 scan.sp_wpa = frm; 2277 break; 2278 case IEEE80211_ELEMID_VENDOR: 2279 if (frm + 1 >= efrm) 2280 break; 2281 if (frm + frm[1] + 2 >= efrm) 2282 break; 2283 if (bwfm_iswpaoui(frm)) 2284 scan.sp_wpa = frm; 2285 break; 2286 } 2287 if (frm + 1 >= efrm) 2288 break; 2289 } 2290 2291 if (ic->ic_flags & IEEE80211_F_SCAN) 2292 ieee80211_add_scan(ic, &scan, &wh, IEEE80211_FC0_SUBTYPE_BEACON, 2293 le32toh(bss->rssi), 0); 2294 } 2295