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