1 /* $NetBSD: bwfm.c,v 1.10 2018/01/16 18:42:43 maxv 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/systm.h> 22 #include <sys/buf.h> 23 #include <sys/kernel.h> 24 #include <sys/malloc.h> 25 #include <sys/device.h> 26 #include <sys/queue.h> 27 #include <sys/socket.h> 28 #include <sys/kmem.h> 29 #include <sys/workqueue.h> 30 #include <sys/pcq.h> 31 32 #include <net/bpf.h> 33 #include <net/if.h> 34 #include <net/if_dl.h> 35 #include <net/if_media.h> 36 #include <net/if_ether.h> 37 38 #include <netinet/in.h> 39 40 #include <net80211/ieee80211_var.h> 41 42 #include <dev/ic/bwfmvar.h> 43 #include <dev/ic/bwfmreg.h> 44 45 /* #define BWFM_DEBUG */ 46 #ifdef BWFM_DEBUG 47 #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0) 48 #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0) 49 static int bwfm_debug = 1; 50 #else 51 #define DPRINTF(x) do { ; } while (0) 52 #define DPRINTFN(n, x) do { ; } while (0) 53 #endif 54 55 #define DEVNAME(sc) device_xname((sc)->sc_dev) 56 57 void bwfm_start(struct ifnet *); 58 int bwfm_init(struct ifnet *); 59 void bwfm_stop(struct ifnet *, int); 60 void bwfm_watchdog(struct ifnet *); 61 int bwfm_ioctl(struct ifnet *, u_long, void *); 62 int bwfm_media_change(struct ifnet *); 63 64 int bwfm_send_mgmt(struct ieee80211com *, struct ieee80211_node *, 65 int, int); 66 void bwfm_recv_mgmt(struct ieee80211com *, struct mbuf *, 67 struct ieee80211_node *, int, int, uint32_t); 68 int bwfm_key_set(struct ieee80211com *, const struct ieee80211_key *, 69 const uint8_t *); 70 int bwfm_key_delete(struct ieee80211com *, const struct ieee80211_key *); 71 int bwfm_newstate(struct ieee80211com *, enum ieee80211_state, int); 72 void bwfm_newstate_cb(struct bwfm_softc *, struct bwfm_cmd_newstate *); 73 void bwfm_newassoc(struct ieee80211_node *, int); 74 void bwfm_task(struct work *, void *); 75 76 int bwfm_chip_attach(struct bwfm_softc *); 77 int bwfm_chip_detach(struct bwfm_softc *, int); 78 struct bwfm_core *bwfm_chip_get_core(struct bwfm_softc *, int); 79 struct bwfm_core *bwfm_chip_get_pmu(struct bwfm_softc *); 80 int bwfm_chip_ai_isup(struct bwfm_softc *, struct bwfm_core *); 81 void bwfm_chip_ai_disable(struct bwfm_softc *, struct bwfm_core *, 82 uint32_t, uint32_t); 83 void bwfm_chip_ai_reset(struct bwfm_softc *, struct bwfm_core *, 84 uint32_t, uint32_t, uint32_t); 85 void bwfm_chip_dmp_erom_scan(struct bwfm_softc *); 86 int bwfm_chip_dmp_get_regaddr(struct bwfm_softc *, uint32_t *, 87 uint32_t *, uint32_t *); 88 void bwfm_chip_cr4_set_passive(struct bwfm_softc *); 89 void bwfm_chip_ca7_set_passive(struct bwfm_softc *); 90 void bwfm_chip_cm3_set_passive(struct bwfm_softc *); 91 92 int bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *, int, 93 int, char *, size_t *); 94 int bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *, int, 95 int, char *, size_t); 96 97 int bwfm_fwvar_cmd_get_data(struct bwfm_softc *, int, void *, size_t); 98 int bwfm_fwvar_cmd_set_data(struct bwfm_softc *, int, void *, size_t); 99 int bwfm_fwvar_cmd_get_int(struct bwfm_softc *, int, uint32_t *); 100 int bwfm_fwvar_cmd_set_int(struct bwfm_softc *, int, uint32_t); 101 int bwfm_fwvar_var_get_data(struct bwfm_softc *, const char *, void *, size_t); 102 int bwfm_fwvar_var_set_data(struct bwfm_softc *, const char *, void *, size_t); 103 int bwfm_fwvar_var_get_int(struct bwfm_softc *, const char *, uint32_t *); 104 int bwfm_fwvar_var_set_int(struct bwfm_softc *, const char *, uint32_t); 105 106 struct ieee80211_channel *bwfm_bss2chan(struct bwfm_softc *, struct bwfm_bss_info *); 107 void bwfm_scan(struct bwfm_softc *); 108 void bwfm_connect(struct bwfm_softc *); 109 110 void bwfm_rx(struct bwfm_softc *, char *, size_t); 111 void bwfm_rx_event(struct bwfm_softc *, char *, size_t); 112 void bwfm_scan_node(struct bwfm_softc *, struct bwfm_bss_info *, size_t); 113 114 uint8_t bwfm_2ghz_channels[] = { 115 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 116 }; 117 uint8_t bwfm_5ghz_channels[] = { 118 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, 100, 104, 108, 112, 119 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, 120 }; 121 122 struct bwfm_proto_ops bwfm_proto_bcdc_ops = { 123 .proto_query_dcmd = bwfm_proto_bcdc_query_dcmd, 124 .proto_set_dcmd = bwfm_proto_bcdc_set_dcmd, 125 }; 126 127 void 128 bwfm_attach(struct bwfm_softc *sc) 129 { 130 struct ieee80211com *ic = &sc->sc_ic; 131 struct ifnet *ifp = &sc->sc_if; 132 struct bwfm_task *t; 133 char fw_version[BWFM_DCMD_SMLEN]; 134 uint32_t bandlist[3]; 135 uint32_t tmp; 136 int i, error; 137 138 error = workqueue_create(&sc->sc_taskq, DEVNAME(sc), 139 bwfm_task, sc, PRI_NONE, IPL_NET, 0); 140 if (error != 0) { 141 printf("%s: could not create workqueue\n", DEVNAME(sc)); 142 return; 143 } 144 sc->sc_freetask = pcq_create(BWFM_TASK_COUNT, KM_SLEEP); 145 for (i = 0; i < BWFM_TASK_COUNT; i++) { 146 t = &sc->sc_task[i]; 147 t->t_sc = sc; 148 pcq_put(sc->sc_freetask, t); 149 } 150 151 /* Stop the device in case it was previously initialized */ 152 bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1); 153 154 if (bwfm_fwvar_cmd_get_int(sc, BWFM_C_GET_VERSION, &tmp)) { 155 printf("%s: could not read io type\n", DEVNAME(sc)); 156 return; 157 } else 158 sc->sc_io_type = tmp; 159 if (bwfm_fwvar_var_get_data(sc, "cur_etheraddr", ic->ic_myaddr, 160 sizeof(ic->ic_myaddr))) { 161 printf("%s: could not read mac address\n", DEVNAME(sc)); 162 return; 163 } 164 165 memset(fw_version, 0, sizeof(fw_version)); 166 if (bwfm_fwvar_var_get_data(sc, "ver", fw_version, sizeof(fw_version)) == 0) 167 printf("%s: %s", DEVNAME(sc), fw_version); 168 printf("%s: address %s\n", DEVNAME(sc), ether_sprintf(ic->ic_myaddr)); 169 170 ic->ic_ifp = ifp; 171 ic->ic_phytype = IEEE80211_T_OFDM; 172 ic->ic_opmode = IEEE80211_M_STA; 173 ic->ic_state = IEEE80211_S_INIT; 174 175 ic->ic_caps = 176 IEEE80211_C_WEP | 177 IEEE80211_C_TKIP | 178 IEEE80211_C_AES | 179 IEEE80211_C_AES_CCM | 180 #if notyet 181 IEEE80211_C_MONITOR | /* monitor mode suported */ 182 IEEE80211_C_IBSS | 183 IEEE80211_C_TXPMGT | 184 IEEE80211_C_WME | 185 #endif 186 IEEE80211_C_SHSLOT | /* short slot time supported */ 187 IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 188 IEEE80211_C_WPA | /* 802.11i */ 189 /* IEEE80211_C_WPA_4WAY */0; /* WPA 4-way handshake in hw */ 190 191 /* IBSS channel undefined for now. */ 192 ic->ic_ibss_chan = &ic->ic_channels[0]; 193 194 if (bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_BANDLIST, bandlist, 195 sizeof(bandlist))) { 196 printf("%s: couldn't get supported band list\n", DEVNAME(sc)); 197 return; 198 } 199 const u_int nbands = le32toh(bandlist[0]); 200 for (i = 1; i <= MIN(nbands, __arraycount(bandlist) - 1); i++) { 201 switch (le32toh(bandlist[i])) { 202 case BWFM_BAND_2G: 203 ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; 204 ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g; 205 206 for (i = 0; i < __arraycount(bwfm_2ghz_channels); i++) { 207 uint8_t chan = bwfm_2ghz_channels[i]; 208 ic->ic_channels[chan].ic_freq = 209 ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ); 210 ic->ic_channels[chan].ic_flags = 211 IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | 212 IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; 213 } 214 break; 215 case BWFM_BAND_5G: 216 ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a; 217 218 for (i = 0; i < __arraycount(bwfm_5ghz_channels); i++) { 219 uint8_t chan = bwfm_5ghz_channels[i]; 220 ic->ic_channels[chan].ic_freq = 221 ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ); 222 ic->ic_channels[chan].ic_flags = 223 IEEE80211_CHAN_A; 224 } 225 break; 226 } 227 } 228 229 ifp->if_softc = sc; 230 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 231 ifp->if_init = bwfm_init; 232 ifp->if_ioctl = bwfm_ioctl; 233 ifp->if_start = bwfm_start; 234 ifp->if_watchdog = bwfm_watchdog; 235 IFQ_SET_READY(&ifp->if_snd); 236 memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); 237 238 error = if_initialize(ifp); 239 if (error != 0) { 240 printf("%s: if_initialize failed(%d)\n", DEVNAME(sc), error); 241 pcq_destroy(sc->sc_freetask); 242 workqueue_destroy(sc->sc_taskq); 243 244 return; /* Error */ 245 } 246 247 ieee80211_ifattach(ic); 248 ifp->if_percpuq = if_percpuq_create(ifp); 249 if_deferred_start_init(ifp, NULL); 250 if_register(ifp); 251 252 sc->sc_newstate = ic->ic_newstate; 253 ic->ic_newstate = bwfm_newstate; 254 ic->ic_newassoc = bwfm_newassoc; 255 ic->ic_send_mgmt = bwfm_send_mgmt; 256 ic->ic_recv_mgmt = bwfm_recv_mgmt; 257 ic->ic_crypto.cs_key_set = bwfm_key_set; 258 ic->ic_crypto.cs_key_delete = bwfm_key_delete; 259 ieee80211_media_init(ic, bwfm_media_change, ieee80211_media_status); 260 261 ieee80211_announce(ic); 262 263 sc->sc_if_attached = true; 264 } 265 266 int 267 bwfm_detach(struct bwfm_softc *sc, int flags) 268 { 269 struct ieee80211com *ic = &sc->sc_ic; 270 struct ifnet *ifp = ic->ic_ifp; 271 272 if (sc->sc_if_attached) { 273 bpf_detach(ifp); 274 ieee80211_ifdetach(ic); 275 if_detach(ifp); 276 } 277 278 if (sc->sc_taskq) 279 workqueue_destroy(sc->sc_taskq); 280 if (sc->sc_freetask) 281 pcq_destroy(sc->sc_freetask); 282 283 return 0; 284 } 285 286 void 287 bwfm_start(struct ifnet *ifp) 288 { 289 struct bwfm_softc *sc = ifp->if_softc; 290 struct ieee80211com *ic = &sc->sc_ic; 291 struct mbuf *m; 292 int error; 293 294 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) 295 return; 296 297 /* TODO: return if no link? */ 298 299 for (;;) { 300 struct ieee80211_node *ni; 301 struct ether_header *eh; 302 303 /* Discard management packets (fw handles this for us) */ 304 IF_DEQUEUE(&ic->ic_mgtq, m); 305 if (m != NULL) { 306 m_freem(m); 307 continue; 308 } 309 310 IFQ_DEQUEUE(&ifp->if_snd, m); 311 if (m == NULL) 312 break; 313 314 eh = mtod(m, struct ether_header *); 315 ni = ieee80211_find_txnode(ic, eh->ether_dhost); 316 if (ni == NULL) { 317 ifp->if_oerrors++; 318 m_freem(m); 319 continue; 320 } 321 322 if (ieee80211_classify(ic, m, ni) != 0) { 323 ifp->if_oerrors++; 324 m_freem(m); 325 ieee80211_free_node(ni); 326 continue; 327 } 328 329 error = sc->sc_bus_ops->bs_txdata(sc, m); 330 if (error == ENOBUFS) { 331 IF_PREPEND(&ifp->if_snd, m); 332 ifp->if_flags |= IFF_OACTIVE; 333 break; 334 } 335 336 if (error != 0) { 337 ifp->if_oerrors++; 338 m_freem(m); 339 if (ni != NULL) 340 ieee80211_free_node(ni); 341 } else { 342 bpf_mtap3(ic->ic_rawbpf, m); 343 } 344 } 345 } 346 347 int 348 bwfm_init(struct ifnet *ifp) 349 { 350 struct bwfm_softc *sc = ifp->if_softc; 351 struct ieee80211com *ic = &sc->sc_ic; 352 uint8_t evmask[BWFM_EVENT_MASK_LEN]; 353 struct bwfm_join_pref_params join_pref[2]; 354 355 if (bwfm_fwvar_var_set_int(sc, "mpc", 1)) { 356 printf("%s: could not set mpc\n", DEVNAME(sc)); 357 return EIO; 358 } 359 360 /* Select target by RSSI (boost on 5GHz) */ 361 join_pref[0].type = BWFM_JOIN_PREF_RSSI_DELTA; 362 join_pref[0].len = 2; 363 join_pref[0].rssi_gain = BWFM_JOIN_PREF_RSSI_BOOST; 364 join_pref[0].band = BWFM_JOIN_PREF_BAND_5G; 365 join_pref[1].type = BWFM_JOIN_PREF_RSSI; 366 join_pref[1].len = 2; 367 join_pref[1].rssi_gain = 0; 368 join_pref[1].band = 0; 369 if (bwfm_fwvar_var_set_data(sc, "join_pref", join_pref, 370 sizeof(join_pref))) { 371 printf("%s: could not set join pref\n", DEVNAME(sc)); 372 return EIO; 373 } 374 375 memset(evmask, 0, sizeof(evmask)); 376 377 #define ENABLE_EVENT(e) evmask[(e) / 8] |= 1 << ((e) % 8) 378 /* Events used to drive the state machine */ 379 ENABLE_EVENT(BWFM_E_ASSOC); 380 ENABLE_EVENT(BWFM_E_ESCAN_RESULT); 381 ENABLE_EVENT(BWFM_E_SET_SSID); 382 ENABLE_EVENT(BWFM_E_LINK); 383 #undef ENABLE_EVENT 384 385 #ifdef BWFM_DEBUG 386 memset(evmask, 0xff, sizeof(evmask)); 387 #endif 388 389 if (bwfm_fwvar_var_set_data(sc, "event_msgs", evmask, sizeof(evmask))) { 390 printf("%s: could not set event mask\n", DEVNAME(sc)); 391 return EIO; 392 } 393 394 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_CHANNEL_TIME, 395 BWFM_DEFAULT_SCAN_CHANNEL_TIME)) { 396 printf("%s: could not set scan channel time\n", DEVNAME(sc)); 397 return EIO; 398 } 399 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_UNASSOC_TIME, 400 BWFM_DEFAULT_SCAN_UNASSOC_TIME)) { 401 printf("%s: could not set scan unassoc time\n", DEVNAME(sc)); 402 return EIO; 403 } 404 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_PASSIVE_TIME, 405 BWFM_DEFAULT_SCAN_PASSIVE_TIME)) { 406 printf("%s: could not set scan passive time\n", DEVNAME(sc)); 407 return EIO; 408 } 409 410 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, 2)) { 411 printf("%s: could not set power\n", DEVNAME(sc)); 412 return EIO; 413 } 414 415 bwfm_fwvar_var_set_int(sc, "txbf", 1); 416 bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 0); 417 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 1); 418 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0); 419 420 /* Disable all offloading (ARP, NDP, TCP/UDP cksum). */ 421 bwfm_fwvar_var_set_int(sc, "arp_ol", 0); 422 bwfm_fwvar_var_set_int(sc, "arpoe", 0); 423 bwfm_fwvar_var_set_int(sc, "ndoe", 0); 424 bwfm_fwvar_var_set_int(sc, "toe", 0); 425 426 /* Accept all multicast frames. */ 427 bwfm_fwvar_var_set_int(sc, "allmulti", 1); 428 429 /* Setup promiscuous mode */ 430 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PROMISC, 431 (ifp->if_flags & IFF_PROMISC) ? 1 : 0); 432 433 /* 434 * Tell the firmware supplicant that we are going to handle the 435 * WPA handshake ourselves. 436 */ 437 bwfm_fwvar_var_set_int(sc, "sup_wpa", 0); 438 439 ifp->if_flags |= IFF_RUNNING; 440 ifp->if_flags &= ~IFF_OACTIVE; 441 442 if (ic->ic_opmode != IEEE80211_M_MONITOR) { 443 if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) 444 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 445 } else { 446 ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 447 } 448 449 return 0; 450 } 451 452 void 453 bwfm_stop(struct ifnet *ifp, int disable) 454 { 455 struct bwfm_softc *sc = ifp->if_softc; 456 struct ieee80211com *ic = &sc->sc_ic; 457 458 sc->sc_tx_timer = 0; 459 ifp->if_timer = 0; 460 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 461 462 bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1); 463 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, 0); 464 465 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 466 } 467 468 void 469 bwfm_watchdog(struct ifnet *ifp) 470 { 471 struct bwfm_softc *sc = ifp->if_softc; 472 struct ieee80211com *ic = &sc->sc_ic; 473 474 ifp->if_timer = 0; 475 476 if (sc->sc_tx_timer > 0) { 477 if (--sc->sc_tx_timer == 0) { 478 printf("%s: device timeout\n", DEVNAME(sc)); 479 ifp->if_oerrors++; 480 return; 481 } 482 ifp->if_timer = 1; 483 } 484 ieee80211_watchdog(ic); 485 } 486 487 int 488 bwfm_ioctl(struct ifnet *ifp, u_long cmd, void *data) 489 { 490 struct bwfm_softc *sc = ifp->if_softc; 491 struct ieee80211com *ic = &sc->sc_ic; 492 int s, error = 0; 493 494 s = splnet(); 495 496 switch (cmd) { 497 case SIOCSIFFLAGS: 498 if ((error = ifioctl_common(ifp, cmd, data)) != 0) 499 break; 500 switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { 501 case IFF_UP | IFF_RUNNING: 502 break; 503 case IFF_UP: 504 bwfm_init(ifp); 505 break; 506 case IFF_RUNNING: 507 bwfm_stop(ifp, 1); 508 break; 509 case 0: 510 break; 511 } 512 break; 513 514 case SIOCADDMULTI: 515 case SIOCDELMULTI: 516 if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { 517 /* setup multicast filter, etc */ 518 error = 0; 519 } 520 break; 521 522 default: 523 error = ieee80211_ioctl(ic, cmd, data); 524 } 525 526 if (error == ENETRESET) { 527 if ((ifp->if_flags & IFF_UP) != 0 && 528 (ifp->if_flags & IFF_RUNNING) != 0 && 529 ic->ic_roaming != IEEE80211_ROAMING_MANUAL) { 530 bwfm_init(ifp); 531 } 532 error = 0; 533 } 534 535 splx(s); 536 537 return error; 538 } 539 540 int 541 bwfm_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, 542 int type, int arg) 543 { 544 return 0; 545 } 546 547 void 548 bwfm_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, 549 struct ieee80211_node *ni, int subtype, int rssi, uint32_t rstamp) 550 { 551 } 552 553 int 554 bwfm_key_set(struct ieee80211com *ic, const struct ieee80211_key *wk, 555 const uint8_t mac[IEEE80211_ADDR_LEN]) 556 { 557 struct bwfm_softc *sc = ic->ic_ifp->if_softc; 558 struct bwfm_task *t; 559 560 t = pcq_get(sc->sc_freetask); 561 if (t == NULL) { 562 printf("%s: no free tasks\n", DEVNAME(sc)); 563 return 0; 564 } 565 566 t->t_cmd = BWFM_TASK_KEY_SET; 567 t->t_key.key = wk; 568 memcpy(t->t_key.mac, mac, sizeof(t->t_key.mac)); 569 workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL); 570 return 1; 571 } 572 573 static void 574 bwfm_key_set_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck) 575 { 576 const struct ieee80211_key *wk = ck->key; 577 const uint8_t *mac = ck->mac; 578 struct bwfm_wsec_key wsec_key; 579 uint32_t wsec_enable, wsec; 580 bool ext_key; 581 582 #ifdef BWFM_DEBUG 583 printf("key_set: key cipher %s len %d: ", wk->wk_cipher->ic_name, wk->wk_keylen); 584 for (int j = 0; j < sizeof(wk->wk_key); j++) 585 printf("%02x", wk->wk_key[j]); 586 #endif 587 588 if ((wk->wk_flags & IEEE80211_KEY_GROUP) == 0 && 589 wk->wk_cipher->ic_cipher != IEEE80211_CIPHER_WEP) { 590 ext_key = true; 591 } else { 592 ext_key = false; 593 } 594 595 #ifdef BWFM_DEBUG 596 printf(", ext_key = %d", ext_key); 597 printf(", mac = %02x:%02x:%02x:%02x:%02x:%02x", 598 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 599 printf("\n"); 600 #endif 601 602 memset(&wsec_key, 0, sizeof(wsec_key)); 603 if (ext_key && !IEEE80211_IS_MULTICAST(mac)) 604 memcpy(wsec_key.ea, mac, sizeof(wsec_key.ea)); 605 wsec_key.index = htole32(wk->wk_keyix); 606 wsec_key.len = htole32(wk->wk_keylen); 607 memcpy(wsec_key.data, wk->wk_key, sizeof(wsec_key.data)); 608 if (!ext_key) 609 wsec_key.flags = htole32(BWFM_PRIMARY_KEY); 610 611 switch (wk->wk_cipher->ic_cipher) { 612 case IEEE80211_CIPHER_WEP: 613 if (wk->wk_keylen == 5) 614 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP1); 615 else if (wk->wk_keylen == 13) 616 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP128); 617 else 618 return; 619 wsec_enable = BWFM_WSEC_WEP; 620 break; 621 case IEEE80211_CIPHER_TKIP: 622 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_TKIP); 623 wsec_enable = BWFM_WSEC_TKIP; 624 break; 625 case IEEE80211_CIPHER_AES_CCM: 626 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_AES_CCM); 627 wsec_enable = BWFM_WSEC_AES; 628 break; 629 default: 630 printf("%s: %s: cipher %s not supported\n", DEVNAME(sc), 631 __func__, wk->wk_cipher->ic_name); 632 return; 633 } 634 635 if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key))) 636 return; 637 638 bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_WPA2_PSK); 639 640 bwfm_fwvar_var_get_int(sc, "wsec", &wsec); 641 wsec |= wsec_enable; 642 bwfm_fwvar_var_set_int(sc, "wsec", wsec); 643 } 644 645 int 646 bwfm_key_delete(struct ieee80211com *ic, const struct ieee80211_key *wk) 647 { 648 struct bwfm_softc *sc = ic->ic_ifp->if_softc; 649 struct bwfm_task *t; 650 651 t = pcq_get(sc->sc_freetask); 652 if (t == NULL) { 653 printf("%s: no free tasks\n", DEVNAME(sc)); 654 return 0; 655 } 656 657 t->t_cmd = BWFM_TASK_KEY_DELETE; 658 t->t_key.key = wk; 659 memset(t->t_key.mac, 0, sizeof(t->t_key.mac)); 660 workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL); 661 662 return 1; 663 } 664 665 static void 666 bwfm_key_delete_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck) 667 { 668 const struct ieee80211_key *wk = ck->key; 669 struct bwfm_wsec_key wsec_key; 670 671 memset(&wsec_key, 0, sizeof(wsec_key)); 672 wsec_key.index = htole32(wk->wk_keyix); 673 wsec_key.flags = htole32(BWFM_PRIMARY_KEY); 674 675 if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key))) 676 return; 677 } 678 679 int 680 bwfm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 681 { 682 struct bwfm_softc *sc = ic->ic_ifp->if_softc; 683 struct bwfm_task *t; 684 685 t = pcq_get(sc->sc_freetask); 686 if (t == NULL) { 687 printf("%s: no free tasks\n", DEVNAME(sc)); 688 return EIO; 689 } 690 691 t->t_cmd = BWFM_TASK_NEWSTATE; 692 t->t_newstate.state = nstate; 693 t->t_newstate.arg = arg; 694 workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL); 695 696 return 0; 697 } 698 699 void 700 bwfm_newstate_cb(struct bwfm_softc *sc, struct bwfm_cmd_newstate *cmd) 701 { 702 struct ieee80211com *ic = &sc->sc_ic; 703 enum ieee80211_state ostate = ic->ic_state; 704 enum ieee80211_state nstate = cmd->state; 705 int s; 706 707 DPRINTF(("%s: newstate %d -> %d\n", DEVNAME(sc), ostate, nstate)); 708 709 s = splnet(); 710 711 switch (nstate) { 712 case IEEE80211_S_INIT: 713 break; 714 715 case IEEE80211_S_SCAN: 716 if (ostate != IEEE80211_S_SCAN) { 717 /* Start of scanning */ 718 bwfm_scan(sc); 719 } 720 break; 721 722 case IEEE80211_S_AUTH: 723 bwfm_connect(sc); 724 break; 725 726 case IEEE80211_S_ASSOC: 727 break; 728 729 case IEEE80211_S_RUN: 730 break; 731 } 732 733 sc->sc_newstate(ic, nstate, cmd->arg); 734 735 splx(s); 736 } 737 738 void 739 bwfm_newassoc(struct ieee80211_node *ni, int isnew) 740 { 741 /* Firmware handles rate adaptation for us */ 742 ni->ni_txrate = 0; 743 } 744 745 void 746 bwfm_task(struct work *wk, void *arg) 747 { 748 struct bwfm_task *t = (struct bwfm_task *)wk; 749 struct bwfm_softc *sc = t->t_sc; 750 751 switch (t->t_cmd) { 752 case BWFM_TASK_NEWSTATE: 753 bwfm_newstate_cb(sc, &t->t_newstate); 754 break; 755 case BWFM_TASK_KEY_SET: 756 bwfm_key_set_cb(sc, &t->t_key); 757 break; 758 case BWFM_TASK_KEY_DELETE: 759 bwfm_key_delete_cb(sc, &t->t_key); 760 break; 761 default: 762 panic("bwfm: unknown task command %d", t->t_cmd); 763 } 764 765 pcq_put(sc->sc_freetask, t); 766 } 767 768 int 769 bwfm_media_change(struct ifnet *ifp) 770 { 771 return 0; 772 } 773 774 /* Chip initialization (SDIO, PCIe) */ 775 int 776 bwfm_chip_attach(struct bwfm_softc *sc) 777 { 778 struct bwfm_core *core; 779 int need_socram = 0; 780 int has_socram = 0; 781 int cpu_found = 0; 782 uint32_t val; 783 784 LIST_INIT(&sc->sc_chip.ch_list); 785 786 if (sc->sc_buscore_ops->bc_prepare(sc) != 0) { 787 printf("%s: failed buscore prepare\n", DEVNAME(sc)); 788 return 1; 789 } 790 791 val = sc->sc_buscore_ops->bc_read(sc, 792 BWFM_CHIP_BASE + BWFM_CHIP_REG_CHIPID); 793 sc->sc_chip.ch_chip = BWFM_CHIP_CHIPID_ID(val); 794 sc->sc_chip.ch_chiprev = BWFM_CHIP_CHIPID_REV(val); 795 796 if ((sc->sc_chip.ch_chip > 0xa000) || (sc->sc_chip.ch_chip < 0x4000)) 797 snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name), 798 "%d", sc->sc_chip.ch_chip); 799 else 800 snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name), 801 "%x", sc->sc_chip.ch_chip); 802 803 switch (BWFM_CHIP_CHIPID_TYPE(val)) 804 { 805 case BWFM_CHIP_CHIPID_TYPE_SOCI_SB: 806 printf("%s: SoC interconnect SB not implemented\n", 807 DEVNAME(sc)); 808 return 1; 809 case BWFM_CHIP_CHIPID_TYPE_SOCI_AI: 810 sc->sc_chip.ch_core_isup = bwfm_chip_ai_isup; 811 sc->sc_chip.ch_core_disable = bwfm_chip_ai_disable; 812 sc->sc_chip.ch_core_reset = bwfm_chip_ai_reset; 813 bwfm_chip_dmp_erom_scan(sc); 814 break; 815 default: 816 printf("%s: SoC interconnect %d unknown\n", 817 DEVNAME(sc), BWFM_CHIP_CHIPID_TYPE(val)); 818 return 1; 819 } 820 821 LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) { 822 DPRINTF(("%s: 0x%x:%-2d base 0x%08x wrap 0x%08x\n", 823 DEVNAME(sc), core->co_id, core->co_rev, 824 core->co_base, core->co_wrapbase)); 825 826 switch (core->co_id) { 827 case BWFM_AGENT_CORE_ARM_CM3: 828 need_socram = true; 829 /* FALLTHROUGH */ 830 case BWFM_AGENT_CORE_ARM_CR4: 831 case BWFM_AGENT_CORE_ARM_CA7: 832 cpu_found = true; 833 break; 834 case BWFM_AGENT_INTERNAL_MEM: 835 has_socram = true; 836 break; 837 default: 838 break; 839 } 840 } 841 842 if (!cpu_found) { 843 printf("%s: CPU core not detected\n", DEVNAME(sc)); 844 return 1; 845 } 846 if (need_socram && !has_socram) { 847 printf("%s: RAM core not provided\n", DEVNAME(sc)); 848 return 1; 849 } 850 851 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) 852 bwfm_chip_cr4_set_passive(sc); 853 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) 854 bwfm_chip_ca7_set_passive(sc); 855 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) 856 bwfm_chip_cm3_set_passive(sc); 857 858 if (sc->sc_buscore_ops->bc_reset) { 859 sc->sc_buscore_ops->bc_reset(sc); 860 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) 861 bwfm_chip_cr4_set_passive(sc); 862 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) 863 bwfm_chip_ca7_set_passive(sc); 864 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) 865 bwfm_chip_cm3_set_passive(sc); 866 } 867 868 /* TODO: get raminfo */ 869 870 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); 871 sc->sc_chip.ch_cc_caps = sc->sc_buscore_ops->bc_read(sc, 872 core->co_base + BWFM_CHIP_REG_CAPABILITIES); 873 sc->sc_chip.ch_cc_caps_ext = sc->sc_buscore_ops->bc_read(sc, 874 core->co_base + BWFM_CHIP_REG_CAPABILITIES_EXT); 875 876 core = bwfm_chip_get_pmu(sc); 877 if (sc->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU) { 878 sc->sc_chip.ch_pmucaps = sc->sc_buscore_ops->bc_read(sc, 879 core->co_base + BWFM_CHIP_REG_PMUCAPABILITIES); 880 sc->sc_chip.ch_pmurev = sc->sc_chip.ch_pmucaps & 881 BWFM_CHIP_REG_PMUCAPABILITIES_REV_MASK; 882 } 883 884 if (sc->sc_buscore_ops->bc_setup) 885 sc->sc_buscore_ops->bc_setup(sc); 886 887 return 0; 888 } 889 890 struct bwfm_core * 891 bwfm_chip_get_core(struct bwfm_softc *sc, int id) 892 { 893 struct bwfm_core *core; 894 895 LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) { 896 if (core->co_id == id) 897 return core; 898 } 899 900 return NULL; 901 } 902 903 struct bwfm_core * 904 bwfm_chip_get_pmu(struct bwfm_softc *sc) 905 { 906 struct bwfm_core *cc, *pmu; 907 908 cc = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); 909 if (cc->co_rev >= 35 && sc->sc_chip.ch_cc_caps_ext & 910 BWFM_CHIP_REG_CAPABILITIES_EXT_AOB_PRESENT) { 911 pmu = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_PMU); 912 if (pmu) 913 return pmu; 914 } 915 916 return cc; 917 } 918 919 /* Functions for the AI interconnect */ 920 int 921 bwfm_chip_ai_isup(struct bwfm_softc *sc, struct bwfm_core *core) 922 { 923 uint32_t ioctl, reset; 924 925 ioctl = sc->sc_buscore_ops->bc_read(sc, 926 core->co_wrapbase + BWFM_AGENT_IOCTL); 927 reset = sc->sc_buscore_ops->bc_read(sc, 928 core->co_wrapbase + BWFM_AGENT_RESET_CTL); 929 930 if (((ioctl & (BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK)) == 931 BWFM_AGENT_IOCTL_CLK) && 932 ((reset & BWFM_AGENT_RESET_CTL_RESET) == 0)) 933 return 1; 934 935 return 0; 936 } 937 938 void 939 bwfm_chip_ai_disable(struct bwfm_softc *sc, struct bwfm_core *core, 940 uint32_t prereset, uint32_t reset) 941 { 942 uint32_t val; 943 int i; 944 945 val = sc->sc_buscore_ops->bc_read(sc, 946 core->co_wrapbase + BWFM_AGENT_RESET_CTL); 947 if ((val & BWFM_AGENT_RESET_CTL_RESET) == 0) { 948 949 sc->sc_buscore_ops->bc_write(sc, 950 core->co_wrapbase + BWFM_AGENT_IOCTL, 951 prereset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK); 952 sc->sc_buscore_ops->bc_read(sc, 953 core->co_wrapbase + BWFM_AGENT_IOCTL); 954 955 sc->sc_buscore_ops->bc_write(sc, 956 core->co_wrapbase + BWFM_AGENT_RESET_CTL, 957 BWFM_AGENT_RESET_CTL_RESET); 958 delay(20); 959 960 for (i = 300; i > 0; i--) { 961 if (sc->sc_buscore_ops->bc_read(sc, 962 core->co_wrapbase + BWFM_AGENT_RESET_CTL) == 963 BWFM_AGENT_RESET_CTL_RESET) 964 break; 965 } 966 if (i == 0) 967 printf("%s: timeout on core reset\n", DEVNAME(sc)); 968 } 969 970 sc->sc_buscore_ops->bc_write(sc, 971 core->co_wrapbase + BWFM_AGENT_IOCTL, 972 reset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK); 973 sc->sc_buscore_ops->bc_read(sc, 974 core->co_wrapbase + BWFM_AGENT_IOCTL); 975 } 976 977 void 978 bwfm_chip_ai_reset(struct bwfm_softc *sc, struct bwfm_core *core, 979 uint32_t prereset, uint32_t reset, uint32_t postreset) 980 { 981 int i; 982 983 bwfm_chip_ai_disable(sc, core, prereset, reset); 984 985 for (i = 50; i > 0; i--) { 986 if ((sc->sc_buscore_ops->bc_read(sc, 987 core->co_wrapbase + BWFM_AGENT_RESET_CTL) & 988 BWFM_AGENT_RESET_CTL_RESET) == 0) 989 break; 990 sc->sc_buscore_ops->bc_write(sc, 991 core->co_wrapbase + BWFM_AGENT_RESET_CTL, 0); 992 delay(60); 993 } 994 if (i == 0) 995 printf("%s: timeout on core reset\n", DEVNAME(sc)); 996 997 sc->sc_buscore_ops->bc_write(sc, 998 core->co_wrapbase + BWFM_AGENT_IOCTL, 999 postreset | BWFM_AGENT_IOCTL_CLK); 1000 sc->sc_buscore_ops->bc_read(sc, 1001 core->co_wrapbase + BWFM_AGENT_IOCTL); 1002 } 1003 1004 void 1005 bwfm_chip_dmp_erom_scan(struct bwfm_softc *sc) 1006 { 1007 uint32_t erom, val, base, wrap; 1008 uint8_t type = 0; 1009 uint16_t id; 1010 uint8_t nmw, nsw, rev; 1011 struct bwfm_core *core; 1012 1013 erom = sc->sc_buscore_ops->bc_read(sc, 1014 BWFM_CHIP_BASE + BWFM_CHIP_REG_EROMPTR); 1015 while (type != BWFM_DMP_DESC_EOT) { 1016 val = sc->sc_buscore_ops->bc_read(sc, erom); 1017 type = val & BWFM_DMP_DESC_MASK; 1018 erom += 4; 1019 1020 if (type != BWFM_DMP_DESC_COMPONENT) 1021 continue; 1022 1023 id = (val & BWFM_DMP_COMP_PARTNUM) 1024 >> BWFM_DMP_COMP_PARTNUM_S; 1025 1026 val = sc->sc_buscore_ops->bc_read(sc, erom); 1027 type = val & BWFM_DMP_DESC_MASK; 1028 erom += 4; 1029 1030 if (type != BWFM_DMP_DESC_COMPONENT) { 1031 printf("%s: not component descriptor\n", DEVNAME(sc)); 1032 return; 1033 } 1034 1035 nmw = (val & BWFM_DMP_COMP_NUM_MWRAP) 1036 >> BWFM_DMP_COMP_NUM_MWRAP_S; 1037 nsw = (val & BWFM_DMP_COMP_NUM_SWRAP) 1038 >> BWFM_DMP_COMP_NUM_SWRAP_S; 1039 rev = (val & BWFM_DMP_COMP_REVISION) 1040 >> BWFM_DMP_COMP_REVISION_S; 1041 1042 if (nmw + nsw == 0 && id != BWFM_AGENT_CORE_PMU) 1043 continue; 1044 1045 if (bwfm_chip_dmp_get_regaddr(sc, &erom, &base, &wrap)) 1046 continue; 1047 1048 core = kmem_alloc(sizeof(*core), KM_SLEEP); 1049 core->co_id = id; 1050 core->co_base = base; 1051 core->co_wrapbase = wrap; 1052 core->co_rev = rev; 1053 LIST_INSERT_HEAD(&sc->sc_chip.ch_list, core, co_link); 1054 } 1055 } 1056 1057 int 1058 bwfm_chip_dmp_get_regaddr(struct bwfm_softc *sc, uint32_t *erom, 1059 uint32_t *base, uint32_t *wrap) 1060 { 1061 uint8_t type = 0, mpnum __unused = 0; 1062 uint8_t stype, sztype, wraptype; 1063 uint32_t val; 1064 1065 *base = 0; 1066 *wrap = 0; 1067 1068 val = sc->sc_buscore_ops->bc_read(sc, *erom); 1069 type = val & BWFM_DMP_DESC_MASK; 1070 if (type == BWFM_DMP_DESC_MASTER_PORT) { 1071 mpnum = (val & BWFM_DMP_MASTER_PORT_NUM) 1072 >> BWFM_DMP_MASTER_PORT_NUM_S; 1073 wraptype = BWFM_DMP_SLAVE_TYPE_MWRAP; 1074 *erom += 4; 1075 } else if ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) == 1076 BWFM_DMP_DESC_ADDRESS) 1077 wraptype = BWFM_DMP_SLAVE_TYPE_SWRAP; 1078 else 1079 return 1; 1080 1081 do { 1082 do { 1083 val = sc->sc_buscore_ops->bc_read(sc, *erom); 1084 type = val & BWFM_DMP_DESC_MASK; 1085 if (type == BWFM_DMP_DESC_COMPONENT) 1086 return 0; 1087 if (type == BWFM_DMP_DESC_EOT) 1088 return 1; 1089 *erom += 4; 1090 } while ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) != 1091 BWFM_DMP_DESC_ADDRESS); 1092 1093 if (type & BWFM_DMP_DESC_ADDRSIZE_GT32) 1094 *erom += 4; 1095 1096 sztype = (val & BWFM_DMP_SLAVE_SIZE_TYPE) 1097 >> BWFM_DMP_SLAVE_SIZE_TYPE_S; 1098 if (sztype == BWFM_DMP_SLAVE_SIZE_DESC) { 1099 val = sc->sc_buscore_ops->bc_read(sc, *erom); 1100 type = val & BWFM_DMP_DESC_MASK; 1101 if (type & BWFM_DMP_DESC_ADDRSIZE_GT32) 1102 *erom += 8; 1103 else 1104 *erom += 4; 1105 } 1106 if (sztype != BWFM_DMP_SLAVE_SIZE_4K) 1107 continue; 1108 1109 stype = (val & BWFM_DMP_SLAVE_TYPE) >> BWFM_DMP_SLAVE_TYPE_S; 1110 if (*base == 0 && stype == BWFM_DMP_SLAVE_TYPE_SLAVE) 1111 *base = val & BWFM_DMP_SLAVE_ADDR_BASE; 1112 if (*wrap == 0 && stype == wraptype) 1113 *wrap = val & BWFM_DMP_SLAVE_ADDR_BASE; 1114 } while (*base == 0 || *wrap == 0); 1115 1116 return 0; 1117 } 1118 1119 /* Core configuration */ 1120 void 1121 bwfm_chip_cr4_set_passive(struct bwfm_softc *sc) 1122 { 1123 panic("%s: CR4 not supported", DEVNAME(sc)); 1124 } 1125 1126 void 1127 bwfm_chip_ca7_set_passive(struct bwfm_softc *sc) 1128 { 1129 panic("%s: CA7 not supported", DEVNAME(sc)); 1130 } 1131 1132 void 1133 bwfm_chip_cm3_set_passive(struct bwfm_softc *sc) 1134 { 1135 struct bwfm_core *core; 1136 1137 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3); 1138 sc->sc_chip.ch_core_disable(sc, core, 0, 0); 1139 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); 1140 sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | 1141 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, 1142 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); 1143 core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM); 1144 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); 1145 1146 if (sc->sc_chip.ch_chip == BRCM_CC_43430_CHIP_ID) { 1147 sc->sc_buscore_ops->bc_write(sc, 1148 core->co_base + BWFM_SOCRAM_BANKIDX, 3); 1149 sc->sc_buscore_ops->bc_write(sc, 1150 core->co_base + BWFM_SOCRAM_BANKPDA, 0); 1151 } 1152 } 1153 1154 /* BCDC protocol implementation */ 1155 int 1156 bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *sc, int ifidx, 1157 int cmd, char *buf, size_t *len) 1158 { 1159 struct bwfm_proto_bcdc_dcmd *dcmd; 1160 size_t size = sizeof(dcmd->hdr) + *len; 1161 static int reqid = 0; 1162 int ret = 1; 1163 1164 reqid++; 1165 1166 dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP); 1167 if (*len > sizeof(dcmd->buf)) 1168 goto err; 1169 1170 dcmd->hdr.cmd = htole32(cmd); 1171 dcmd->hdr.len = htole32(*len); 1172 dcmd->hdr.flags |= BWFM_BCDC_DCMD_GET; 1173 dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid); 1174 dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx); 1175 dcmd->hdr.flags = htole32(dcmd->hdr.flags); 1176 memcpy(&dcmd->buf, buf, *len); 1177 1178 if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd, 1179 sizeof(dcmd->hdr) + *len)) { 1180 DPRINTF(("%s: tx failed\n", DEVNAME(sc))); 1181 goto err; 1182 } 1183 1184 do { 1185 if (sc->sc_bus_ops->bs_rxctl(sc, (void *)dcmd, &size)) { 1186 DPRINTF(("%s: rx failed\n", DEVNAME(sc))); 1187 goto err; 1188 } 1189 dcmd->hdr.cmd = le32toh(dcmd->hdr.cmd); 1190 dcmd->hdr.len = le32toh(dcmd->hdr.len); 1191 dcmd->hdr.flags = le32toh(dcmd->hdr.flags); 1192 dcmd->hdr.status = le32toh(dcmd->hdr.status); 1193 } while (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid); 1194 1195 if (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid) { 1196 printf("%s: unexpected request id\n", DEVNAME(sc)); 1197 goto err; 1198 } 1199 1200 if (buf) { 1201 if (size > *len) 1202 size = *len; 1203 if (size < *len) 1204 *len = size; 1205 memcpy(buf, dcmd->buf, *len); 1206 } 1207 1208 if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR) 1209 ret = dcmd->hdr.status; 1210 else 1211 ret = 0; 1212 err: 1213 kmem_free(dcmd, sizeof(*dcmd)); 1214 return ret; 1215 } 1216 1217 int 1218 bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *sc, int ifidx, 1219 int cmd, char *buf, size_t len) 1220 { 1221 struct bwfm_proto_bcdc_dcmd *dcmd; 1222 size_t size = sizeof(dcmd->hdr) + len; 1223 int reqid = 0; 1224 int ret = 1; 1225 1226 reqid++; 1227 1228 dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP); 1229 if (len > sizeof(dcmd->buf)) 1230 goto err; 1231 1232 dcmd->hdr.cmd = htole32(cmd); 1233 dcmd->hdr.len = htole32(len); 1234 dcmd->hdr.flags |= BWFM_BCDC_DCMD_SET; 1235 dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid); 1236 dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx); 1237 dcmd->hdr.flags = htole32(dcmd->hdr.flags); 1238 memcpy(&dcmd->buf, buf, len); 1239 1240 if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd, size)) { 1241 DPRINTF(("%s: tx failed\n", DEVNAME(sc))); 1242 goto err; 1243 } 1244 1245 do { 1246 if (sc->sc_bus_ops->bs_rxctl(sc, (void *)dcmd, &size)) { 1247 DPRINTF(("%s: rx failed\n", DEVNAME(sc))); 1248 goto err; 1249 } 1250 dcmd->hdr.cmd = le32toh(dcmd->hdr.cmd); 1251 dcmd->hdr.len = le32toh(dcmd->hdr.len); 1252 dcmd->hdr.flags = le32toh(dcmd->hdr.flags); 1253 dcmd->hdr.status = le32toh(dcmd->hdr.status); 1254 } while (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid); 1255 1256 if (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid) { 1257 printf("%s: unexpected request id\n", DEVNAME(sc)); 1258 goto err; 1259 } 1260 1261 if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR) 1262 return dcmd->hdr.status; 1263 1264 ret = 0; 1265 err: 1266 kmem_free(dcmd, sizeof(*dcmd)); 1267 return ret; 1268 } 1269 1270 /* FW Variable code */ 1271 int 1272 bwfm_fwvar_cmd_get_data(struct bwfm_softc *sc, int cmd, void *data, size_t len) 1273 { 1274 return sc->sc_proto_ops->proto_query_dcmd(sc, 0, cmd, data, &len); 1275 } 1276 1277 int 1278 bwfm_fwvar_cmd_set_data(struct bwfm_softc *sc, int cmd, void *data, size_t len) 1279 { 1280 return sc->sc_proto_ops->proto_set_dcmd(sc, 0, cmd, data, len); 1281 } 1282 1283 int 1284 bwfm_fwvar_cmd_get_int(struct bwfm_softc *sc, int cmd, uint32_t *data) 1285 { 1286 int ret; 1287 ret = bwfm_fwvar_cmd_get_data(sc, cmd, data, sizeof(*data)); 1288 *data = le32toh(*data); 1289 return ret; 1290 } 1291 1292 int 1293 bwfm_fwvar_cmd_set_int(struct bwfm_softc *sc, int cmd, uint32_t data) 1294 { 1295 data = htole32(data); 1296 return bwfm_fwvar_cmd_set_data(sc, cmd, &data, sizeof(data)); 1297 } 1298 1299 int 1300 bwfm_fwvar_var_get_data(struct bwfm_softc *sc, const char *name, void *data, size_t len) 1301 { 1302 char *buf; 1303 int ret; 1304 1305 buf = kmem_alloc(strlen(name) + 1 + len, KM_SLEEP); 1306 memcpy(buf, name, strlen(name) + 1); 1307 memcpy(buf + strlen(name) + 1, data, len); 1308 ret = bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_VAR, 1309 buf, strlen(name) + 1 + len); 1310 memcpy(data, buf, len); 1311 kmem_free(buf, strlen(name) + 1 + len); 1312 return ret; 1313 } 1314 1315 int 1316 bwfm_fwvar_var_set_data(struct bwfm_softc *sc, const char *name, void *data, size_t len) 1317 { 1318 char *buf; 1319 int ret; 1320 1321 buf = kmem_alloc(strlen(name) + 1 + len, KM_SLEEP); 1322 memcpy(buf, name, strlen(name) + 1); 1323 memcpy(buf + strlen(name) + 1, data, len); 1324 ret = bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_VAR, 1325 buf, strlen(name) + 1 + len); 1326 kmem_free(buf, strlen(name) + 1 + len); 1327 return ret; 1328 } 1329 1330 int 1331 bwfm_fwvar_var_get_int(struct bwfm_softc *sc, const char *name, uint32_t *data) 1332 { 1333 int ret; 1334 ret = bwfm_fwvar_var_get_data(sc, name, data, sizeof(*data)); 1335 *data = le32toh(*data); 1336 return ret; 1337 } 1338 1339 int 1340 bwfm_fwvar_var_set_int(struct bwfm_softc *sc, const char *name, uint32_t data) 1341 { 1342 data = htole32(data); 1343 return bwfm_fwvar_var_set_data(sc, name, &data, sizeof(data)); 1344 } 1345 1346 /* 802.11 code */ 1347 void 1348 bwfm_scan(struct bwfm_softc *sc) 1349 { 1350 struct bwfm_escan_params *params; 1351 uint32_t nssid = 0, nchannel = 0; 1352 size_t params_size; 1353 1354 #if 0 1355 /* Active scan is used for scanning for an SSID */ 1356 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PASSIVE_SCAN, 0); 1357 #endif 1358 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PASSIVE_SCAN, 1); 1359 1360 params_size = sizeof(*params); 1361 params_size += sizeof(uint32_t) * ((nchannel + 1) / 2); 1362 params_size += sizeof(struct bwfm_ssid) * nssid; 1363 1364 params = kmem_zalloc(params_size, KM_SLEEP); 1365 memset(params->scan_params.bssid, 0xff, 1366 sizeof(params->scan_params.bssid)); 1367 params->scan_params.bss_type = 2; 1368 params->scan_params.nprobes = htole32(-1); 1369 params->scan_params.active_time = htole32(-1); 1370 params->scan_params.passive_time = htole32(-1); 1371 params->scan_params.home_time = htole32(-1); 1372 params->version = htole32(BWFM_ESCAN_REQ_VERSION); 1373 params->action = htole16(WL_ESCAN_ACTION_START); 1374 params->sync_id = htole16(0x1234); 1375 1376 #if 0 1377 /* Scan a specific channel */ 1378 params->scan_params.channel_list[0] = htole16( 1379 (1 & 0xff) << 0 | 1380 (3 & 0x3) << 8 | 1381 (2 & 0x3) << 10 | 1382 (2 & 0x3) << 12 1383 ); 1384 params->scan_params.channel_num = htole32( 1385 (1 & 0xffff) << 0 1386 ); 1387 #endif 1388 1389 bwfm_fwvar_var_set_data(sc, "escan", params, params_size); 1390 kmem_free(params, params_size); 1391 } 1392 1393 static __inline int 1394 bwfm_iswpaoui(const uint8_t *frm) 1395 { 1396 return frm[1] > 3 && le32dec(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); 1397 } 1398 1399 /* 1400 * Derive wireless security settings from WPA/RSN IE. 1401 */ 1402 static uint32_t 1403 bwfm_get_wsec(struct bwfm_softc *sc) 1404 { 1405 struct ieee80211com *ic = &sc->sc_ic; 1406 uint8_t *wpa = ic->ic_opt_ie; 1407 1408 KASSERT(ic->ic_opt_ie_len > 0); 1409 1410 if (wpa[0] != IEEE80211_ELEMID_RSN) { 1411 if (ic->ic_opt_ie_len < 12) 1412 return BWFM_WSEC_NONE; 1413 1414 /* non-RSN IE, expect that we are doing WPA1 */ 1415 if ((ic->ic_flags & IEEE80211_F_WPA1) == 0) 1416 return BWFM_WSEC_NONE; 1417 1418 /* Must contain WPA OUI */ 1419 if (!bwfm_iswpaoui(wpa)) 1420 return BWFM_WSEC_NONE; 1421 1422 switch (le32dec(wpa + 8)) { 1423 case ((WPA_CSE_TKIP<<24)|WPA_OUI): 1424 return BWFM_WSEC_TKIP; 1425 case ((WPA_CSE_CCMP<<24)|WPA_OUI): 1426 return BWFM_WSEC_AES; 1427 default: 1428 return BWFM_WSEC_NONE; 1429 } 1430 } else { 1431 if (ic->ic_opt_ie_len < 14) 1432 return BWFM_WSEC_NONE; 1433 1434 /* RSN IE, expect that we are doing WPA2 */ 1435 if ((ic->ic_flags & IEEE80211_F_WPA2) == 0) 1436 return BWFM_WSEC_NONE; 1437 1438 switch (le32dec(wpa + 10)) { 1439 case ((RSN_CSE_TKIP<<24)|RSN_OUI): 1440 return BWFM_WSEC_TKIP; 1441 case ((RSN_CSE_CCMP<<24)|RSN_OUI): 1442 return BWFM_WSEC_AES; 1443 default: 1444 return BWFM_WSEC_NONE; 1445 } 1446 } 1447 } 1448 1449 void 1450 bwfm_connect(struct bwfm_softc *sc) 1451 { 1452 struct ieee80211com *ic = &sc->sc_ic; 1453 struct ieee80211_node *ni = ic->ic_bss; 1454 struct bwfm_ext_join_params *params; 1455 1456 if (ic->ic_flags & IEEE80211_F_WPA) { 1457 uint32_t wsec = 0; 1458 uint32_t wpa = 0; 1459 1460 if (ic->ic_opt_ie_len) 1461 bwfm_fwvar_var_set_data(sc, "wpaie", ic->ic_opt_ie, ic->ic_opt_ie_len); 1462 1463 if (ic->ic_flags & IEEE80211_F_WPA1) 1464 wpa |= BWFM_WPA_AUTH_WPA_PSK; 1465 if (ic->ic_flags & IEEE80211_F_WPA2) 1466 wpa |= BWFM_WPA_AUTH_WPA2_PSK; 1467 1468 wsec |= bwfm_get_wsec(sc); 1469 1470 DPRINTF(("%s: WPA enabled, ic_flags = 0x%x, wpa 0x%x, wsec 0x%x\n", 1471 DEVNAME(sc), ic->ic_flags, wpa, wsec)); 1472 1473 bwfm_fwvar_var_set_int(sc, "wpa_auth", wpa); 1474 bwfm_fwvar_var_set_int(sc, "wsec", wsec); 1475 } else { 1476 bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_DISABLED); 1477 bwfm_fwvar_var_set_int(sc, "wsec", BWFM_WSEC_NONE); 1478 } 1479 1480 bwfm_fwvar_var_set_int(sc, "auth", BWFM_AUTH_OPEN); 1481 bwfm_fwvar_var_set_int(sc, "mfp", BWFM_MFP_NONE); 1482 1483 if (ni->ni_esslen && ni->ni_esslen < BWFM_MAX_SSID_LEN) { 1484 params = kmem_zalloc(sizeof(*params), KM_SLEEP); 1485 memcpy(params->ssid.ssid, ni->ni_essid, ni->ni_esslen); 1486 params->ssid.len = htole32(ni->ni_esslen); 1487 memcpy(params->assoc.bssid, ni->ni_bssid, sizeof(params->assoc.bssid)); 1488 params->scan.scan_type = -1; 1489 params->scan.nprobes = htole32(-1); 1490 params->scan.active_time = htole32(-1); 1491 params->scan.passive_time = htole32(-1); 1492 params->scan.home_time = htole32(-1); 1493 if (bwfm_fwvar_var_set_data(sc, "join", params, sizeof(*params))) { 1494 struct bwfm_join_params join; 1495 memset(&join, 0, sizeof(join)); 1496 memcpy(join.ssid.ssid, ni->ni_essid, ni->ni_esslen); 1497 join.ssid.len = htole32(ni->ni_esslen); 1498 memcpy(join.assoc.bssid, ni->ni_bssid, sizeof(join.assoc.bssid)); 1499 bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, 1500 sizeof(join)); 1501 } 1502 kmem_free(params, sizeof(*params)); 1503 } 1504 } 1505 1506 void 1507 bwfm_rx(struct bwfm_softc *sc, char *buf, size_t len) 1508 { 1509 struct ieee80211com *ic = &sc->sc_ic; 1510 struct ifnet *ifp = ic->ic_ifp; 1511 struct bwfm_event *e = (void *)buf; 1512 struct mbuf *m; 1513 char *mb; 1514 int s; 1515 1516 DPRINTF(("%s: buf %p len %lu\n", __func__, buf, len)); 1517 1518 if (len >= sizeof(e->ehdr) && 1519 ntohs(e->ehdr.ether_type) == BWFM_ETHERTYPE_LINK_CTL && 1520 memcmp(BWFM_BRCM_OUI, e->hdr.oui, sizeof(e->hdr.oui)) == 0 && 1521 ntohs(e->hdr.usr_subtype) == BWFM_BRCM_SUBTYPE_EVENT) 1522 bwfm_rx_event(sc, buf, len); 1523 1524 if (__predict_false(len > MCLBYTES || len == 0)) 1525 return; 1526 MGETHDR(m, M_DONTWAIT, MT_DATA); 1527 if (__predict_false(m == NULL)) 1528 return; 1529 if (len > MHLEN) { 1530 MCLGET(m, M_DONTWAIT); 1531 if (!(m->m_flags & M_EXT)) { 1532 m_free(m); 1533 return; 1534 } 1535 } 1536 1537 s = splnet(); 1538 1539 if ((ifp->if_flags & IFF_RUNNING) != 0) { 1540 mb = mtod(m, char *); 1541 memcpy(mb, buf, len); 1542 m->m_pkthdr.len = m->m_len = len; 1543 m_set_rcvif(m, ifp); 1544 1545 if_percpuq_enqueue(ifp->if_percpuq, m); 1546 } 1547 1548 splx(s); 1549 } 1550 1551 void 1552 bwfm_rx_event(struct bwfm_softc *sc, char *buf, size_t len) 1553 { 1554 struct ieee80211com *ic = &sc->sc_ic; 1555 struct bwfm_event *e = (void *)buf; 1556 int s; 1557 1558 DPRINTF(("%s: buf %p len %lu datalen %u code %u status %u" 1559 " reason %u\n", __func__, buf, len, ntohl(e->msg.datalen), 1560 ntohl(e->msg.event_type), ntohl(e->msg.status), 1561 ntohl(e->msg.reason))); 1562 1563 if (ntohl(e->msg.event_type) >= BWFM_E_LAST) 1564 return; 1565 1566 switch (ntohl(e->msg.event_type)) { 1567 case BWFM_E_ESCAN_RESULT: { 1568 struct bwfm_escan_results *res = (void *)(buf + sizeof(*e)); 1569 struct bwfm_bss_info *bss; 1570 int i; 1571 if (ntohl(e->msg.status) != BWFM_E_STATUS_PARTIAL) { 1572 /* Scan complete */ 1573 s = splnet(); 1574 if (ic->ic_opmode != IEEE80211_M_MONITOR) 1575 ieee80211_end_scan(ic); 1576 splx(s); 1577 break; 1578 } 1579 len -= sizeof(*e); 1580 if (len < sizeof(*res) || len < le32toh(res->buflen)) { 1581 printf("%s: results too small\n", DEVNAME(sc)); 1582 return; 1583 } 1584 len -= sizeof(*res); 1585 if (len < le16toh(res->bss_count) * sizeof(struct bwfm_bss_info)) { 1586 printf("%s: results too small\n", DEVNAME(sc)); 1587 return; 1588 } 1589 bss = &res->bss_info[0]; 1590 for (i = 0; i < le16toh(res->bss_count); i++) { 1591 /* Fix alignment of bss_info */ 1592 union { 1593 struct bwfm_bss_info bss_info; 1594 uint8_t padding[BWFM_BSS_INFO_BUFLEN]; 1595 } bss_buf; 1596 if (len > sizeof(bss_buf)) { 1597 printf("%s: bss_info buffer too big\n", DEVNAME(sc)); 1598 } else { 1599 memcpy(&bss_buf, &res->bss_info[i], len); 1600 bwfm_scan_node(sc, &bss_buf.bss_info, len); 1601 } 1602 len -= sizeof(*bss) + le32toh(bss->length); 1603 bss = (void *)(((uintptr_t)bss) + le32toh(bss->length)); 1604 if (len <= 0) 1605 break; 1606 } 1607 break; 1608 } 1609 1610 case BWFM_E_SET_SSID: 1611 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS) { 1612 ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 1613 } else { 1614 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 1615 } 1616 break; 1617 1618 case BWFM_E_ASSOC: 1619 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS) { 1620 ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1); 1621 } else { 1622 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 1623 } 1624 break; 1625 1626 case BWFM_E_LINK: 1627 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS && 1628 ntohl(e->msg.reason) == 0) 1629 break; 1630 1631 /* Link status has changed */ 1632 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 1633 break; 1634 1635 default: 1636 break; 1637 } 1638 } 1639 1640 void 1641 bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_info *bss, size_t len) 1642 { 1643 struct ieee80211com *ic = &sc->sc_ic; 1644 struct ieee80211_frame wh; 1645 struct ieee80211_scanparams scan; 1646 uint8_t rates[sizeof(bss->rates) + 2]; 1647 uint8_t ssid[sizeof(bss->ssid) + 2]; 1648 uint8_t *frm, *sfrm, *efrm; 1649 uint64_t tsf; 1650 1651 tsf = 0; 1652 sfrm = ((uint8_t *)bss) + le16toh(bss->ie_offset); 1653 efrm = sfrm + le32toh(bss->ie_length); 1654 1655 /* Fake a wireless header with the scan result's BSSID */ 1656 memset(&wh, 0, sizeof(wh)); 1657 IEEE80211_ADDR_COPY(wh.i_addr2, bss->bssid); 1658 IEEE80211_ADDR_COPY(wh.i_addr3, bss->bssid); 1659 1660 if (efrm - sfrm < 12) { 1661 ic->ic_stats.is_rx_elem_toosmall++; 1662 return; 1663 } 1664 1665 rates[0] = 0; 1666 rates[1] = le32toh(bss->nrates); 1667 memcpy(&rates[2], bss->rates, sizeof(bss->rates)); 1668 1669 ssid[0] = 0; 1670 ssid[1] = bss->ssid_len; 1671 memcpy(&ssid[2], bss->ssid, sizeof(bss->ssid)); 1672 1673 /* Build scan result */ 1674 memset(&scan, 0, sizeof(scan)); 1675 scan.sp_tstamp = (uint8_t *)&tsf; 1676 scan.sp_bintval = le16toh(bss->beacon_period); 1677 scan.sp_capinfo = le16toh(bss->capability); 1678 scan.sp_bchan = ieee80211_chan2ieee(ic, ic->ic_curchan); 1679 scan.sp_chan = scan.sp_bchan; 1680 scan.sp_rates = rates; 1681 scan.sp_ssid = ssid; 1682 1683 for (frm = sfrm; frm < efrm; frm += frm[1] + 2) { 1684 switch (frm[0]) { 1685 case IEEE80211_ELEMID_COUNTRY: 1686 scan.sp_country = frm; 1687 break; 1688 case IEEE80211_ELEMID_FHPARMS: 1689 if (ic->ic_phytype == IEEE80211_T_FH) { 1690 if (frm + 6 >= efrm) 1691 break; 1692 scan.sp_fhdwell = le16dec(&frm[2]); 1693 scan.sp_chan = IEEE80211_FH_CHAN(frm[4], frm[5]); 1694 scan.sp_fhindex = frm[6]; 1695 } 1696 break; 1697 case IEEE80211_ELEMID_DSPARMS: 1698 if (ic->ic_phytype != IEEE80211_T_FH) { 1699 if (frm + 2 >= efrm) 1700 break; 1701 scan.sp_chan = frm[2]; 1702 } 1703 break; 1704 case IEEE80211_ELEMID_TIM: 1705 scan.sp_tim = frm; 1706 scan.sp_timoff = frm - sfrm; 1707 break; 1708 case IEEE80211_ELEMID_XRATES: 1709 scan.sp_xrates = frm; 1710 break; 1711 case IEEE80211_ELEMID_ERP: 1712 if (frm + 1 >= efrm) 1713 break; 1714 if (frm[1] != 1) { 1715 ic->ic_stats.is_rx_elem_toobig++; 1716 break; 1717 } 1718 scan.sp_erp = frm[2]; 1719 break; 1720 case IEEE80211_ELEMID_RSN: 1721 scan.sp_wpa = frm; 1722 break; 1723 case IEEE80211_ELEMID_VENDOR: 1724 if (frm + 1 >= efrm) 1725 break; 1726 if (frm + frm[1] + 2 >= efrm) 1727 break; 1728 if (bwfm_iswpaoui(frm)) 1729 scan.sp_wpa = frm; 1730 break; 1731 } 1732 if (frm + 1 >= efrm) 1733 break; 1734 } 1735 1736 if (ic->ic_flags & IEEE80211_F_SCAN) 1737 ieee80211_add_scan(ic, &scan, &wh, IEEE80211_FC0_SUBTYPE_BEACON, 1738 le32toh(bss->rssi), 0); 1739 } 1740