1 /* $OpenBSD: bwfm.c,v 1.84 2021/04/22 22:14:30 patrick Exp $ */ 2 /* 3 * Copyright (c) 2010-2016 Broadcom Corporation 4 * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include "bpfilter.h" 20 21 #include <sys/param.h> 22 #include <sys/systm.h> 23 #include <sys/buf.h> 24 #include <sys/kernel.h> 25 #include <sys/malloc.h> 26 #include <sys/device.h> 27 #include <sys/queue.h> 28 #include <sys/socket.h> 29 #include <sys/sockio.h> 30 31 #if defined(__HAVE_FDT) 32 #include <machine/fdt.h> 33 #include <dev/ofw/openfirm.h> 34 #endif 35 36 #if NBPFILTER > 0 37 #include <net/bpf.h> 38 #endif 39 #include <net/if.h> 40 #include <net/if_dl.h> 41 #include <net/if_media.h> 42 43 #include <netinet/in.h> 44 #include <netinet/if_ether.h> 45 46 #include <net80211/ieee80211_var.h> 47 48 #include <dev/ic/bwfmvar.h> 49 #include <dev/ic/bwfmreg.h> 50 51 /* #define BWFM_DEBUG */ 52 #ifdef BWFM_DEBUG 53 #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0) 54 #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0) 55 static int bwfm_debug = 1; 56 #else 57 #define DPRINTF(x) do { ; } while (0) 58 #define DPRINTFN(n, x) do { ; } while (0) 59 #endif 60 61 #define DEVNAME(sc) ((sc)->sc_dev.dv_xname) 62 63 void bwfm_start(struct ifnet *); 64 void bwfm_init(struct ifnet *); 65 void bwfm_stop(struct ifnet *); 66 void bwfm_iff(struct bwfm_softc *); 67 void bwfm_watchdog(struct ifnet *); 68 void bwfm_update_node(void *, struct ieee80211_node *); 69 void bwfm_update_nodes(struct bwfm_softc *); 70 int bwfm_ioctl(struct ifnet *, u_long, caddr_t); 71 int bwfm_media_change(struct ifnet *); 72 73 void bwfm_process_clm_blob(struct bwfm_softc *); 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_idx(struct bwfm_softc *, int, 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 int bwfm_chip_cr4_set_active(struct bwfm_softc *, uint32_t); 89 void bwfm_chip_cr4_set_passive(struct bwfm_softc *); 90 int bwfm_chip_ca7_set_active(struct bwfm_softc *, uint32_t); 91 void bwfm_chip_ca7_set_passive(struct bwfm_softc *); 92 int bwfm_chip_cm3_set_active(struct bwfm_softc *); 93 void bwfm_chip_cm3_set_passive(struct bwfm_softc *); 94 void bwfm_chip_socram_ramsize(struct bwfm_softc *, struct bwfm_core *); 95 void bwfm_chip_sysmem_ramsize(struct bwfm_softc *, struct bwfm_core *); 96 void bwfm_chip_tcm_ramsize(struct bwfm_softc *, struct bwfm_core *); 97 void bwfm_chip_tcm_rambase(struct bwfm_softc *); 98 99 int bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *, int, 100 int, char *, size_t *); 101 int bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *, int, 102 int, char *, size_t); 103 void bwfm_proto_bcdc_rx(struct bwfm_softc *, struct mbuf *, 104 struct mbuf_list *); 105 int bwfm_proto_bcdc_txctl(struct bwfm_softc *, int, char *, size_t *); 106 void bwfm_proto_bcdc_rxctl(struct bwfm_softc *, char *, size_t); 107 108 int bwfm_fwvar_cmd_get_data(struct bwfm_softc *, int, void *, size_t); 109 int bwfm_fwvar_cmd_set_data(struct bwfm_softc *, int, void *, size_t); 110 int bwfm_fwvar_cmd_get_int(struct bwfm_softc *, int, uint32_t *); 111 int bwfm_fwvar_cmd_set_int(struct bwfm_softc *, int, uint32_t); 112 int bwfm_fwvar_var_get_data(struct bwfm_softc *, char *, void *, size_t); 113 int bwfm_fwvar_var_set_data(struct bwfm_softc *, char *, void *, size_t); 114 int bwfm_fwvar_var_get_int(struct bwfm_softc *, char *, uint32_t *); 115 int bwfm_fwvar_var_set_int(struct bwfm_softc *, char *, uint32_t); 116 117 uint32_t bwfm_chan2spec(struct bwfm_softc *, struct ieee80211_channel *); 118 uint32_t bwfm_chan2spec_d11n(struct bwfm_softc *, struct ieee80211_channel *); 119 uint32_t bwfm_chan2spec_d11ac(struct bwfm_softc *, struct ieee80211_channel *); 120 uint32_t bwfm_spec2chan(struct bwfm_softc *, uint32_t); 121 uint32_t bwfm_spec2chan_d11n(struct bwfm_softc *, uint32_t); 122 uint32_t bwfm_spec2chan_d11ac(struct bwfm_softc *, uint32_t); 123 124 void bwfm_connect(struct bwfm_softc *); 125 #ifndef IEEE80211_STA_ONLY 126 void bwfm_hostap(struct bwfm_softc *); 127 #endif 128 void bwfm_scan(struct bwfm_softc *); 129 void bwfm_scan_abort(struct bwfm_softc *); 130 131 void bwfm_task(void *); 132 void bwfm_do_async(struct bwfm_softc *, 133 void (*)(struct bwfm_softc *, void *), void *, int); 134 135 int bwfm_set_key(struct ieee80211com *, struct ieee80211_node *, 136 struct ieee80211_key *); 137 void bwfm_delete_key(struct ieee80211com *, struct ieee80211_node *, 138 struct ieee80211_key *); 139 int bwfm_send_mgmt(struct ieee80211com *, struct ieee80211_node *, 140 int, int, int); 141 int bwfm_newstate(struct ieee80211com *, enum ieee80211_state, int); 142 143 void bwfm_set_key_cb(struct bwfm_softc *, void *); 144 void bwfm_delete_key_cb(struct bwfm_softc *, void *); 145 void bwfm_rx_event_cb(struct bwfm_softc *, struct mbuf *); 146 147 struct mbuf *bwfm_newbuf(void); 148 #ifndef IEEE80211_STA_ONLY 149 void bwfm_rx_auth_ind(struct bwfm_softc *, struct bwfm_event *, size_t); 150 void bwfm_rx_assoc_ind(struct bwfm_softc *, struct bwfm_event *, size_t, int); 151 void bwfm_rx_deauth_ind(struct bwfm_softc *, struct bwfm_event *, size_t); 152 void bwfm_rx_disassoc_ind(struct bwfm_softc *, struct bwfm_event *, size_t); 153 void bwfm_rx_leave_ind(struct bwfm_softc *, struct bwfm_event *, size_t, int); 154 #endif 155 void bwfm_rx_event(struct bwfm_softc *, struct mbuf *); 156 void bwfm_scan_node(struct bwfm_softc *, struct bwfm_bss_info *, size_t); 157 158 extern void ieee80211_node2req(struct ieee80211com *, 159 const struct ieee80211_node *, struct ieee80211_nodereq *); 160 extern void ieee80211_req2node(struct ieee80211com *, 161 const struct ieee80211_nodereq *, struct ieee80211_node *); 162 163 uint8_t bwfm_2ghz_channels[] = { 164 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 165 }; 166 uint8_t bwfm_5ghz_channels[] = { 167 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, 100, 104, 108, 112, 168 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, 169 }; 170 171 struct bwfm_proto_ops bwfm_proto_bcdc_ops = { 172 .proto_query_dcmd = bwfm_proto_bcdc_query_dcmd, 173 .proto_set_dcmd = bwfm_proto_bcdc_set_dcmd, 174 .proto_rx = bwfm_proto_bcdc_rx, 175 .proto_rxctl = bwfm_proto_bcdc_rxctl, 176 }; 177 178 struct cfdriver bwfm_cd = { 179 NULL, "bwfm", DV_IFNET 180 }; 181 182 void 183 bwfm_attach(struct bwfm_softc *sc) 184 { 185 struct ieee80211com *ic = &sc->sc_ic; 186 struct ifnet *ifp = &ic->ic_if; 187 188 TAILQ_INIT(&sc->sc_bcdc_rxctlq); 189 190 /* Init host async commands ring. */ 191 sc->sc_cmdq.cur = sc->sc_cmdq.next = sc->sc_cmdq.queued = 0; 192 sc->sc_taskq = taskq_create(DEVNAME(sc), 1, IPL_SOFTNET, 0); 193 task_set(&sc->sc_task, bwfm_task, sc); 194 ml_init(&sc->sc_evml); 195 196 ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 197 ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 198 ic->ic_state = IEEE80211_S_INIT; 199 200 ic->ic_caps = 201 #ifndef IEEE80211_STA_ONLY 202 IEEE80211_C_HOSTAP | /* Access Point */ 203 #endif 204 IEEE80211_C_RSN | /* WPA/RSN */ 205 IEEE80211_C_SCANALL | /* device scans all channels at once */ 206 IEEE80211_C_SCANALLBAND; /* device scans all bands at once */ 207 208 /* IBSS channel undefined for now. */ 209 ic->ic_ibss_chan = &ic->ic_channels[0]; 210 211 ifp->if_softc = sc; 212 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 213 ifp->if_ioctl = bwfm_ioctl; 214 ifp->if_start = bwfm_start; 215 ifp->if_watchdog = bwfm_watchdog; 216 memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); 217 218 if_attach(ifp); 219 ieee80211_ifattach(ifp); 220 221 sc->sc_newstate = ic->ic_newstate; 222 ic->ic_newstate = bwfm_newstate; 223 ic->ic_send_mgmt = bwfm_send_mgmt; 224 ic->ic_set_key = bwfm_set_key; 225 ic->ic_delete_key = bwfm_delete_key; 226 227 ieee80211_media_init(ifp, bwfm_media_change, ieee80211_media_status); 228 } 229 230 void 231 bwfm_attachhook(struct device *self) 232 { 233 struct bwfm_softc *sc = (struct bwfm_softc *)self; 234 235 if (sc->sc_bus_ops->bs_preinit != NULL && 236 sc->sc_bus_ops->bs_preinit(sc)) 237 return; 238 if (bwfm_preinit(sc)) 239 return; 240 sc->sc_initialized = 1; 241 } 242 243 int 244 bwfm_preinit(struct bwfm_softc *sc) 245 { 246 struct ieee80211com *ic = &sc->sc_ic; 247 struct ifnet *ifp = &ic->ic_if; 248 int i, j, nbands, nmode, vhtmode; 249 uint32_t bandlist[3], tmp; 250 251 if (sc->sc_initialized) 252 return 0; 253 254 if (bwfm_fwvar_cmd_get_int(sc, BWFM_C_GET_VERSION, &tmp)) { 255 printf("%s: could not read io type\n", DEVNAME(sc)); 256 return 1; 257 } else 258 sc->sc_io_type = tmp; 259 if (bwfm_fwvar_var_get_data(sc, "cur_etheraddr", ic->ic_myaddr, 260 sizeof(ic->ic_myaddr))) { 261 printf("%s: could not read mac address\n", DEVNAME(sc)); 262 return 1; 263 } 264 265 printf("%s: address %s\n", DEVNAME(sc), ether_sprintf(ic->ic_myaddr)); 266 267 bwfm_process_clm_blob(sc); 268 269 if (bwfm_fwvar_var_get_int(sc, "nmode", &nmode)) 270 nmode = 0; 271 if (bwfm_fwvar_var_get_int(sc, "vhtmode", &vhtmode)) 272 vhtmode = 0; 273 if (bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_BANDLIST, bandlist, 274 sizeof(bandlist))) { 275 printf("%s: couldn't get supported band list\n", DEVNAME(sc)); 276 return 1; 277 } 278 nbands = letoh32(bandlist[0]); 279 for (i = 1; i <= nbands && i < nitems(bandlist); i++) { 280 switch (letoh32(bandlist[i])) { 281 case BWFM_BAND_2G: 282 DPRINTF(("%s: 2G HT %d VHT %d\n", 283 DEVNAME(sc), nmode, vhtmode)); 284 ic->ic_sup_rates[IEEE80211_MODE_11B] = 285 ieee80211_std_rateset_11b; 286 ic->ic_sup_rates[IEEE80211_MODE_11G] = 287 ieee80211_std_rateset_11g; 288 289 for (j = 0; j < nitems(bwfm_2ghz_channels); j++) { 290 uint8_t chan = bwfm_2ghz_channels[j]; 291 ic->ic_channels[chan].ic_freq = 292 ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ); 293 ic->ic_channels[chan].ic_flags = 294 IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | 295 IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; 296 if (nmode) 297 ic->ic_channels[chan].ic_flags |= 298 IEEE80211_CHAN_HT; 299 /* VHT is 5GHz only */ 300 } 301 break; 302 case BWFM_BAND_5G: 303 DPRINTF(("%s: 5G HT %d VHT %d\n", 304 DEVNAME(sc), nmode, vhtmode)); 305 ic->ic_sup_rates[IEEE80211_MODE_11A] = 306 ieee80211_std_rateset_11a; 307 308 for (j = 0; j < nitems(bwfm_5ghz_channels); j++) { 309 uint8_t chan = bwfm_5ghz_channels[j]; 310 ic->ic_channels[chan].ic_freq = 311 ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ); 312 ic->ic_channels[chan].ic_flags = 313 IEEE80211_CHAN_A; 314 if (nmode) 315 ic->ic_channels[chan].ic_flags |= 316 IEEE80211_CHAN_HT; 317 if (vhtmode) 318 ic->ic_channels[chan].ic_flags |= 319 IEEE80211_CHAN_VHT; 320 } 321 break; 322 default: 323 printf("%s: unsupported band 0x%x\n", DEVNAME(sc), 324 letoh32(bandlist[i])); 325 break; 326 } 327 } 328 329 /* Configure channel information obtained from firmware. */ 330 ieee80211_channel_init(ifp); 331 332 /* Configure MAC address. */ 333 if (if_setlladdr(ifp, ic->ic_myaddr)) 334 printf("%s: could not set MAC address\n", DEVNAME(sc)); 335 336 ieee80211_media_init(ifp, bwfm_media_change, ieee80211_media_status); 337 return 0; 338 } 339 340 int 341 bwfm_detach(struct bwfm_softc *sc, int flags) 342 { 343 struct ieee80211com *ic = &sc->sc_ic; 344 struct ifnet *ifp = &ic->ic_if; 345 task_del(sc->sc_taskq, &sc->sc_task); 346 taskq_destroy(sc->sc_taskq); 347 ieee80211_ifdetach(ifp); 348 if_detach(ifp); 349 return 0; 350 } 351 352 void 353 bwfm_start(struct ifnet *ifp) 354 { 355 struct bwfm_softc *sc = ifp->if_softc; 356 struct mbuf *m; 357 358 if (!(ifp->if_flags & IFF_RUNNING)) 359 return; 360 if (ifq_is_oactive(&ifp->if_snd)) 361 return; 362 if (ifq_empty(&ifp->if_snd)) 363 return; 364 365 /* TODO: return if no link? */ 366 367 for (;;) { 368 if (sc->sc_bus_ops->bs_txcheck(sc)) { 369 ifq_set_oactive(&ifp->if_snd); 370 break; 371 } 372 373 m = ifq_dequeue(&ifp->if_snd); 374 if (m == NULL) 375 break; 376 377 if (sc->sc_bus_ops->bs_txdata(sc, m) != 0) { 378 ifp->if_oerrors++; 379 m_freem(m); 380 continue; 381 } 382 383 #if NBPFILTER > 0 384 if (ifp->if_bpf) 385 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 386 #endif 387 } 388 } 389 390 void 391 bwfm_init(struct ifnet *ifp) 392 { 393 struct bwfm_softc *sc = ifp->if_softc; 394 struct ieee80211com *ic = &sc->sc_ic; 395 uint8_t evmask[BWFM_EVENT_MASK_LEN]; 396 struct bwfm_join_pref_params join_pref[2]; 397 int pm; 398 399 if (!sc->sc_initialized) { 400 if (sc->sc_bus_ops->bs_preinit != NULL && 401 sc->sc_bus_ops->bs_preinit(sc)) { 402 printf("%s: could not init bus\n", DEVNAME(sc)); 403 return; 404 } 405 if (bwfm_preinit(sc)) { 406 printf("%s: could not init\n", DEVNAME(sc)); 407 return; 408 } 409 sc->sc_initialized = 1; 410 } 411 412 /* Select default channel */ 413 ic->ic_bss->ni_chan = ic->ic_ibss_chan; 414 415 if (bwfm_fwvar_var_set_int(sc, "mpc", 1)) { 416 printf("%s: could not set mpc\n", DEVNAME(sc)); 417 return; 418 } 419 420 /* Select target by RSSI (boost on 5GHz) */ 421 join_pref[0].type = BWFM_JOIN_PREF_RSSI_DELTA; 422 join_pref[0].len = 2; 423 join_pref[0].rssi_gain = BWFM_JOIN_PREF_RSSI_BOOST; 424 join_pref[0].band = BWFM_JOIN_PREF_BAND_5G; 425 join_pref[1].type = BWFM_JOIN_PREF_RSSI; 426 join_pref[1].len = 2; 427 join_pref[1].rssi_gain = 0; 428 join_pref[1].band = 0; 429 if (bwfm_fwvar_var_set_data(sc, "join_pref", join_pref, 430 sizeof(join_pref))) { 431 printf("%s: could not set join pref\n", DEVNAME(sc)); 432 return; 433 } 434 435 #define BWFM_EVENT(event) evmask[(event) / 8] |= 1 << ((event) % 8) 436 memset(evmask, 0, sizeof(evmask)); 437 switch (ic->ic_opmode) { 438 case IEEE80211_M_STA: 439 BWFM_EVENT(BWFM_E_IF); 440 BWFM_EVENT(BWFM_E_LINK); 441 BWFM_EVENT(BWFM_E_AUTH); 442 BWFM_EVENT(BWFM_E_ASSOC); 443 BWFM_EVENT(BWFM_E_DEAUTH); 444 BWFM_EVENT(BWFM_E_DISASSOC); 445 BWFM_EVENT(BWFM_E_ESCAN_RESULT); 446 break; 447 #ifndef IEEE80211_STA_ONLY 448 case IEEE80211_M_HOSTAP: 449 BWFM_EVENT(BWFM_E_AUTH_IND); 450 BWFM_EVENT(BWFM_E_ASSOC_IND); 451 BWFM_EVENT(BWFM_E_REASSOC_IND); 452 BWFM_EVENT(BWFM_E_DEAUTH_IND); 453 BWFM_EVENT(BWFM_E_DISASSOC_IND); 454 BWFM_EVENT(BWFM_E_ESCAN_RESULT); 455 break; 456 #endif 457 default: 458 break; 459 } 460 #undef BWFM_EVENT 461 462 if (bwfm_fwvar_var_set_data(sc, "event_msgs", evmask, sizeof(evmask))) { 463 printf("%s: could not set event mask\n", DEVNAME(sc)); 464 return; 465 } 466 467 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_CHANNEL_TIME, 468 BWFM_DEFAULT_SCAN_CHANNEL_TIME)) { 469 printf("%s: could not set scan channel time\n", DEVNAME(sc)); 470 return; 471 } 472 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_UNASSOC_TIME, 473 BWFM_DEFAULT_SCAN_UNASSOC_TIME)) { 474 printf("%s: could not set scan unassoc time\n", DEVNAME(sc)); 475 return; 476 } 477 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_PASSIVE_TIME, 478 BWFM_DEFAULT_SCAN_PASSIVE_TIME)) { 479 printf("%s: could not set scan passive time\n", DEVNAME(sc)); 480 return; 481 } 482 483 /* 484 * Use CAM (constantly awake) when we are running as AP, 485 * otherwise use fast power saving. 486 */ 487 pm = BWFM_PM_FAST_PS; 488 #ifndef IEEE80211_STA_ONLY 489 if (ic->ic_opmode == IEEE80211_M_HOSTAP) 490 pm = BWFM_PM_CAM; 491 #endif 492 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, pm)) { 493 printf("%s: could not set power\n", DEVNAME(sc)); 494 return; 495 } 496 497 bwfm_fwvar_var_set_int(sc, "txbf", 1); 498 bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 0); 499 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 1); 500 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0); 501 502 /* Disable all offloading (ARP, NDP, TCP/UDP cksum). */ 503 bwfm_fwvar_var_set_int(sc, "arp_ol", 0); 504 bwfm_fwvar_var_set_int(sc, "arpoe", 0); 505 bwfm_fwvar_var_set_int(sc, "ndoe", 0); 506 bwfm_fwvar_var_set_int(sc, "toe", 0); 507 508 /* 509 * The firmware supplicant can handle the WPA handshake for 510 * us, but we honestly want to do this ourselves, so disable 511 * the firmware supplicant and let our stack handle it. 512 */ 513 bwfm_fwvar_var_set_int(sc, "sup_wpa", 0); 514 515 bwfm_iff(sc); 516 517 ifp->if_flags |= IFF_RUNNING; 518 ifq_clr_oactive(&ifp->if_snd); 519 520 ieee80211_begin_scan(ifp); 521 } 522 523 void 524 bwfm_stop(struct ifnet *ifp) 525 { 526 struct bwfm_softc *sc = ifp->if_softc; 527 struct ieee80211com *ic = &sc->sc_ic; 528 struct bwfm_join_params join; 529 530 sc->sc_tx_timer = 0; 531 ifp->if_timer = 0; 532 ifp->if_flags &= ~IFF_RUNNING; 533 ifq_clr_oactive(&ifp->if_snd); 534 535 ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 536 537 memset(&join, 0, sizeof(join)); 538 bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, sizeof(join)); 539 bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1); 540 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0); 541 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 0); 542 bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 1); 543 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, BWFM_PM_FAST_PS); 544 545 if (sc->sc_bus_ops->bs_stop) 546 sc->sc_bus_ops->bs_stop(sc); 547 } 548 549 void 550 bwfm_iff(struct bwfm_softc *sc) 551 { 552 struct arpcom *ac = &sc->sc_ic.ic_ac; 553 struct ifnet *ifp = &ac->ac_if; 554 struct ether_multi *enm; 555 struct ether_multistep step; 556 size_t mcastlen; 557 char *mcast; 558 int i = 0; 559 560 mcastlen = sizeof(uint32_t) + ac->ac_multicnt * ETHER_ADDR_LEN; 561 mcast = malloc(mcastlen, M_TEMP, M_WAITOK); 562 htolem32((uint32_t *)mcast, ac->ac_multicnt); 563 564 ifp->if_flags &= ~IFF_ALLMULTI; 565 if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) { 566 ifp->if_flags |= IFF_ALLMULTI; 567 } else { 568 ETHER_FIRST_MULTI(step, ac, enm); 569 while (enm != NULL) { 570 memcpy(mcast + sizeof(uint32_t) + i * ETHER_ADDR_LEN, 571 enm->enm_addrlo, ETHER_ADDR_LEN); 572 ETHER_NEXT_MULTI(step, enm); 573 i++; 574 } 575 } 576 577 bwfm_fwvar_var_set_data(sc, "mcast_list", mcast, mcastlen); 578 bwfm_fwvar_var_set_int(sc, "allmulti", 579 !!(ifp->if_flags & IFF_ALLMULTI)); 580 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PROMISC, 581 !!(ifp->if_flags & IFF_PROMISC)); 582 583 free(mcast, M_TEMP, mcastlen); 584 } 585 586 void 587 bwfm_watchdog(struct ifnet *ifp) 588 { 589 struct bwfm_softc *sc = ifp->if_softc; 590 591 ifp->if_timer = 0; 592 593 if (sc->sc_tx_timer > 0) { 594 if (--sc->sc_tx_timer == 0) { 595 printf("%s: device timeout\n", DEVNAME(sc)); 596 ifp->if_oerrors++; 597 return; 598 } 599 ifp->if_timer = 1; 600 } 601 ieee80211_watchdog(ifp); 602 } 603 604 /* 605 * Tx-rate to MCS conversion might lie since some rates map to multiple MCS. 606 * But this is the best we can do given that firmware only reports kbit/s. 607 */ 608 609 void 610 bwfm_rate2vhtmcs(int *mcs, int *ss, uint32_t txrate) 611 { 612 const struct ieee80211_vht_rateset *rs; 613 int i, j; 614 615 *mcs = -1; 616 *ss = -1; 617 /* TODO: Select specific ratesets based on BSS channel width. */ 618 for (i = 0; i < IEEE80211_VHT_NUM_RATESETS; i++) { 619 rs = &ieee80211_std_ratesets_11ac[i]; 620 for (j = 0; j < rs->nrates; j++) { 621 if (rs->rates[j] == txrate / 500) { 622 *mcs = j; 623 *ss = rs->num_ss; 624 return; 625 } 626 } 627 } 628 } 629 630 int 631 bwfm_rate2htmcs(uint32_t txrate) 632 { 633 const struct ieee80211_ht_rateset *rs; 634 int i, j; 635 636 /* TODO: Select specific ratesets based on BSS channel width. */ 637 for (i = 0; i < IEEE80211_HT_NUM_RATESETS; i++) { 638 rs = &ieee80211_std_ratesets_11n[i]; 639 for (j = 0; j < rs->nrates; j++) { 640 if (rs->rates[j] == txrate / 500) 641 return rs->min_mcs + j; 642 } 643 } 644 645 return -1; 646 } 647 648 void 649 bwfm_update_node(void *arg, struct ieee80211_node *ni) 650 { 651 struct bwfm_softc *sc = arg; 652 struct ieee80211com *ic = &sc->sc_ic; 653 struct bwfm_sta_info sta; 654 uint32_t flags; 655 int8_t rssi; 656 uint32_t txrate; 657 int i; 658 659 memset(&sta, 0, sizeof(sta)); 660 memcpy((uint8_t *)&sta, ni->ni_macaddr, sizeof(ni->ni_macaddr)); 661 662 if (bwfm_fwvar_var_get_data(sc, "sta_info", &sta, sizeof(sta))) 663 return; 664 665 if (!IEEE80211_ADDR_EQ(ni->ni_macaddr, sta.ea)) 666 return; 667 668 if (le16toh(sta.ver) < 4) 669 return; 670 671 flags = le32toh(sta.flags); 672 if ((flags & BWFM_STA_SCBSTATS) == 0) 673 return; 674 675 rssi = 0; 676 for (i = 0; i < BWFM_ANT_MAX; i++) { 677 if (sta.rssi[i] >= 0) 678 continue; 679 if (rssi == 0 || sta.rssi[i] > rssi) 680 rssi = sta.rssi[i]; 681 } 682 if (rssi) 683 ni->ni_rssi = rssi; 684 685 txrate = le32toh(sta.tx_rate); /* in kbit/s */ 686 if (txrate == 0xffffffff) /* Seen this happening during association. */ 687 return; 688 689 if ((le32toh(sta.flags) & BWFM_STA_VHT_CAP)) { 690 int mcs, ss; 691 /* Tell net80211 that firmware has negotiated 11ac. */ 692 ni->ni_flags |= IEEE80211_NODE_VHT; 693 ni->ni_flags |= IEEE80211_NODE_HT; /* VHT implies HT support */ 694 if (ic->ic_curmode < IEEE80211_MODE_11AC) 695 ieee80211_setmode(ic, IEEE80211_MODE_11AC); 696 bwfm_rate2vhtmcs(&mcs, &ss, txrate); 697 if (mcs >= 0) { 698 ni->ni_txmcs = mcs; 699 ni->ni_vht_ss = ss; 700 } else { 701 ni->ni_txmcs = 0; 702 ni->ni_vht_ss = 1; 703 } 704 } else if ((le32toh(sta.flags) & BWFM_STA_N_CAP)) { 705 int mcs; 706 /* Tell net80211 that firmware has negotiated 11n. */ 707 ni->ni_flags |= IEEE80211_NODE_HT; 708 if (ic->ic_curmode < IEEE80211_MODE_11N) 709 ieee80211_setmode(ic, IEEE80211_MODE_11N); 710 mcs = bwfm_rate2htmcs(txrate); 711 ni->ni_txmcs = (mcs >= 0 ? mcs : 0); 712 } else { 713 /* We're in 11a/g mode. Map to a legacy rate. */ 714 for (i = 0; i < ni->ni_rates.rs_nrates; i++) { 715 uint8_t rate = ni->ni_rates.rs_rates[i]; 716 rate &= IEEE80211_RATE_VAL; 717 if (rate == txrate / 500) { 718 ni->ni_txrate = i; 719 break; 720 } 721 } 722 } 723 } 724 725 void 726 bwfm_update_nodes(struct bwfm_softc *sc) 727 { 728 struct ieee80211com *ic = &sc->sc_ic; 729 struct ieee80211_node *ni; 730 731 switch (ic->ic_opmode) { 732 case IEEE80211_M_STA: 733 bwfm_update_node(sc, ic->ic_bss); 734 /* Update cached copy in the nodes tree as well. */ 735 ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr); 736 if (ni) { 737 ni->ni_rssi = ic->ic_bss->ni_rssi; 738 } 739 break; 740 #ifndef IEEE80211_STA_ONLY 741 case IEEE80211_M_HOSTAP: 742 ieee80211_iterate_nodes(ic, bwfm_update_node, sc); 743 break; 744 #endif 745 default: 746 break; 747 } 748 } 749 750 int 751 bwfm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 752 { 753 struct bwfm_softc *sc = ifp->if_softc; 754 struct ieee80211com *ic = &sc->sc_ic; 755 struct ifreq *ifr; 756 int s, error = 0; 757 758 s = splnet(); 759 switch (cmd) { 760 case SIOCSIFADDR: 761 ifp->if_flags |= IFF_UP; 762 /* FALLTHROUGH */ 763 case SIOCSIFFLAGS: 764 if (ifp->if_flags & IFF_UP) { 765 if (!(ifp->if_flags & IFF_RUNNING)) 766 bwfm_init(ifp); 767 } else { 768 if (ifp->if_flags & IFF_RUNNING) 769 bwfm_stop(ifp); 770 } 771 break; 772 case SIOCADDMULTI: 773 case SIOCDELMULTI: 774 ifr = (struct ifreq *)data; 775 error = (cmd == SIOCADDMULTI) ? 776 ether_addmulti(ifr, &ic->ic_ac) : 777 ether_delmulti(ifr, &ic->ic_ac); 778 if (error == ENETRESET) { 779 bwfm_iff(sc); 780 error = 0; 781 } 782 break; 783 case SIOCGIFMEDIA: 784 case SIOCG80211NODE: 785 case SIOCG80211ALLNODES: 786 if (ic->ic_state == IEEE80211_S_RUN) 787 bwfm_update_nodes(sc); 788 /* fall through */ 789 default: 790 error = ieee80211_ioctl(ifp, cmd, data); 791 } 792 if (error == ENETRESET) { 793 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == 794 (IFF_UP | IFF_RUNNING)) { 795 bwfm_stop(ifp); 796 bwfm_init(ifp); 797 } 798 error = 0; 799 } 800 splx(s); 801 return error; 802 } 803 804 int 805 bwfm_media_change(struct ifnet *ifp) 806 { 807 int error; 808 809 error = ieee80211_media_change(ifp); 810 if (error != ENETRESET) 811 return error; 812 813 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == 814 (IFF_UP | IFF_RUNNING)) { 815 bwfm_stop(ifp); 816 bwfm_init(ifp); 817 } 818 return error; 819 } 820 821 /* Chip initialization (SDIO, PCIe) */ 822 int 823 bwfm_chip_attach(struct bwfm_softc *sc) 824 { 825 struct bwfm_core *core; 826 int need_socram = 0; 827 int has_socram = 0; 828 int cpu_found = 0; 829 uint32_t val; 830 831 LIST_INIT(&sc->sc_chip.ch_list); 832 833 if (sc->sc_buscore_ops->bc_prepare(sc) != 0) { 834 printf("%s: failed buscore prepare\n", DEVNAME(sc)); 835 return 1; 836 } 837 838 val = sc->sc_buscore_ops->bc_read(sc, 839 BWFM_CHIP_BASE + BWFM_CHIP_REG_CHIPID); 840 sc->sc_chip.ch_chip = BWFM_CHIP_CHIPID_ID(val); 841 sc->sc_chip.ch_chiprev = BWFM_CHIP_CHIPID_REV(val); 842 843 if ((sc->sc_chip.ch_chip > 0xa000) || (sc->sc_chip.ch_chip < 0x4000)) 844 snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name), 845 "%d", sc->sc_chip.ch_chip); 846 else 847 snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name), 848 "%x", sc->sc_chip.ch_chip); 849 850 switch (BWFM_CHIP_CHIPID_TYPE(val)) 851 { 852 case BWFM_CHIP_CHIPID_TYPE_SOCI_SB: 853 printf("%s: SoC interconnect SB not implemented\n", 854 DEVNAME(sc)); 855 return 1; 856 case BWFM_CHIP_CHIPID_TYPE_SOCI_AI: 857 sc->sc_chip.ch_core_isup = bwfm_chip_ai_isup; 858 sc->sc_chip.ch_core_disable = bwfm_chip_ai_disable; 859 sc->sc_chip.ch_core_reset = bwfm_chip_ai_reset; 860 bwfm_chip_dmp_erom_scan(sc); 861 break; 862 default: 863 printf("%s: SoC interconnect %d unknown\n", 864 DEVNAME(sc), BWFM_CHIP_CHIPID_TYPE(val)); 865 return 1; 866 } 867 868 LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) { 869 DPRINTF(("%s: 0x%x:%-2d base 0x%08x wrap 0x%08x\n", 870 DEVNAME(sc), core->co_id, core->co_rev, 871 core->co_base, core->co_wrapbase)); 872 873 switch (core->co_id) { 874 case BWFM_AGENT_CORE_ARM_CM3: 875 need_socram = 1; 876 /* FALLTHROUGH */ 877 case BWFM_AGENT_CORE_ARM_CR4: 878 case BWFM_AGENT_CORE_ARM_CA7: 879 cpu_found = 1; 880 break; 881 case BWFM_AGENT_INTERNAL_MEM: 882 has_socram = 1; 883 break; 884 default: 885 break; 886 } 887 } 888 889 if (!cpu_found) { 890 printf("%s: CPU core not detected\n", DEVNAME(sc)); 891 return 1; 892 } 893 if (need_socram && !has_socram) { 894 printf("%s: RAM core not provided\n", DEVNAME(sc)); 895 return 1; 896 } 897 898 bwfm_chip_set_passive(sc); 899 900 if (sc->sc_buscore_ops->bc_reset) { 901 sc->sc_buscore_ops->bc_reset(sc); 902 bwfm_chip_set_passive(sc); 903 } 904 905 if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4)) != NULL) { 906 bwfm_chip_tcm_ramsize(sc, core); 907 bwfm_chip_tcm_rambase(sc); 908 } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_SYS_MEM)) != NULL) { 909 bwfm_chip_sysmem_ramsize(sc, core); 910 bwfm_chip_tcm_rambase(sc); 911 } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM)) != NULL) { 912 bwfm_chip_socram_ramsize(sc, core); 913 } 914 915 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); 916 sc->sc_chip.ch_cc_caps = sc->sc_buscore_ops->bc_read(sc, 917 core->co_base + BWFM_CHIP_REG_CAPABILITIES); 918 sc->sc_chip.ch_cc_caps_ext = sc->sc_buscore_ops->bc_read(sc, 919 core->co_base + BWFM_CHIP_REG_CAPABILITIES_EXT); 920 921 core = bwfm_chip_get_pmu(sc); 922 if (sc->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU) { 923 sc->sc_chip.ch_pmucaps = sc->sc_buscore_ops->bc_read(sc, 924 core->co_base + BWFM_CHIP_REG_PMUCAPABILITIES); 925 sc->sc_chip.ch_pmurev = sc->sc_chip.ch_pmucaps & 926 BWFM_CHIP_REG_PMUCAPABILITIES_REV_MASK; 927 } 928 929 if (sc->sc_buscore_ops->bc_setup) 930 sc->sc_buscore_ops->bc_setup(sc); 931 932 return 0; 933 } 934 935 struct bwfm_core * 936 bwfm_chip_get_core_idx(struct bwfm_softc *sc, int id, int idx) 937 { 938 struct bwfm_core *core; 939 940 LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) { 941 if (core->co_id == id && idx-- == 0) 942 return core; 943 } 944 945 return NULL; 946 } 947 948 struct bwfm_core * 949 bwfm_chip_get_core(struct bwfm_softc *sc, int id) 950 { 951 return bwfm_chip_get_core_idx(sc, id, 0); 952 } 953 954 struct bwfm_core * 955 bwfm_chip_get_pmu(struct bwfm_softc *sc) 956 { 957 struct bwfm_core *cc, *pmu; 958 959 cc = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); 960 if (cc->co_rev >= 35 && sc->sc_chip.ch_cc_caps_ext & 961 BWFM_CHIP_REG_CAPABILITIES_EXT_AOB_PRESENT) { 962 pmu = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_PMU); 963 if (pmu) 964 return pmu; 965 } 966 967 return cc; 968 } 969 970 /* Functions for the AI interconnect */ 971 int 972 bwfm_chip_ai_isup(struct bwfm_softc *sc, struct bwfm_core *core) 973 { 974 uint32_t ioctl, reset; 975 976 ioctl = sc->sc_buscore_ops->bc_read(sc, 977 core->co_wrapbase + BWFM_AGENT_IOCTL); 978 reset = sc->sc_buscore_ops->bc_read(sc, 979 core->co_wrapbase + BWFM_AGENT_RESET_CTL); 980 981 if (((ioctl & (BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK)) == 982 BWFM_AGENT_IOCTL_CLK) && 983 ((reset & BWFM_AGENT_RESET_CTL_RESET) == 0)) 984 return 1; 985 986 return 0; 987 } 988 989 void 990 bwfm_chip_ai_disable(struct bwfm_softc *sc, struct bwfm_core *core, 991 uint32_t prereset, uint32_t reset) 992 { 993 uint32_t val; 994 int i; 995 996 val = sc->sc_buscore_ops->bc_read(sc, 997 core->co_wrapbase + BWFM_AGENT_RESET_CTL); 998 if ((val & BWFM_AGENT_RESET_CTL_RESET) == 0) { 999 1000 sc->sc_buscore_ops->bc_write(sc, 1001 core->co_wrapbase + BWFM_AGENT_IOCTL, 1002 prereset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK); 1003 sc->sc_buscore_ops->bc_read(sc, 1004 core->co_wrapbase + BWFM_AGENT_IOCTL); 1005 1006 sc->sc_buscore_ops->bc_write(sc, 1007 core->co_wrapbase + BWFM_AGENT_RESET_CTL, 1008 BWFM_AGENT_RESET_CTL_RESET); 1009 delay(20); 1010 1011 for (i = 300; i > 0; i--) { 1012 if (sc->sc_buscore_ops->bc_read(sc, 1013 core->co_wrapbase + BWFM_AGENT_RESET_CTL) == 1014 BWFM_AGENT_RESET_CTL_RESET) 1015 break; 1016 } 1017 if (i == 0) 1018 printf("%s: timeout on core reset\n", DEVNAME(sc)); 1019 } 1020 1021 sc->sc_buscore_ops->bc_write(sc, 1022 core->co_wrapbase + BWFM_AGENT_IOCTL, 1023 reset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK); 1024 sc->sc_buscore_ops->bc_read(sc, 1025 core->co_wrapbase + BWFM_AGENT_IOCTL); 1026 } 1027 1028 void 1029 bwfm_chip_ai_reset(struct bwfm_softc *sc, struct bwfm_core *core, 1030 uint32_t prereset, uint32_t reset, uint32_t postreset) 1031 { 1032 struct bwfm_core *core2 = NULL; 1033 int i; 1034 1035 if (core->co_id == BWFM_AGENT_CORE_80211) 1036 core2 = bwfm_chip_get_core_idx(sc, BWFM_AGENT_CORE_80211, 1); 1037 1038 bwfm_chip_ai_disable(sc, core, prereset, reset); 1039 if (core2) 1040 bwfm_chip_ai_disable(sc, core2, prereset, reset); 1041 1042 for (i = 50; i > 0; i--) { 1043 if ((sc->sc_buscore_ops->bc_read(sc, 1044 core->co_wrapbase + BWFM_AGENT_RESET_CTL) & 1045 BWFM_AGENT_RESET_CTL_RESET) == 0) 1046 break; 1047 sc->sc_buscore_ops->bc_write(sc, 1048 core->co_wrapbase + BWFM_AGENT_RESET_CTL, 0); 1049 delay(60); 1050 } 1051 if (i == 0) 1052 printf("%s: timeout on core reset\n", DEVNAME(sc)); 1053 if (core2) { 1054 for (i = 50; i > 0; i--) { 1055 if ((sc->sc_buscore_ops->bc_read(sc, 1056 core2->co_wrapbase + BWFM_AGENT_RESET_CTL) & 1057 BWFM_AGENT_RESET_CTL_RESET) == 0) 1058 break; 1059 sc->sc_buscore_ops->bc_write(sc, 1060 core2->co_wrapbase + BWFM_AGENT_RESET_CTL, 0); 1061 delay(60); 1062 } 1063 if (i == 0) 1064 printf("%s: timeout on core reset\n", DEVNAME(sc)); 1065 } 1066 1067 sc->sc_buscore_ops->bc_write(sc, 1068 core->co_wrapbase + BWFM_AGENT_IOCTL, 1069 postreset | BWFM_AGENT_IOCTL_CLK); 1070 sc->sc_buscore_ops->bc_read(sc, 1071 core->co_wrapbase + BWFM_AGENT_IOCTL); 1072 if (core2) { 1073 sc->sc_buscore_ops->bc_write(sc, 1074 core2->co_wrapbase + BWFM_AGENT_IOCTL, 1075 postreset | BWFM_AGENT_IOCTL_CLK); 1076 sc->sc_buscore_ops->bc_read(sc, 1077 core2->co_wrapbase + BWFM_AGENT_IOCTL); 1078 } 1079 } 1080 1081 void 1082 bwfm_chip_dmp_erom_scan(struct bwfm_softc *sc) 1083 { 1084 uint32_t erom, val, base, wrap; 1085 uint8_t type = 0; 1086 uint16_t id; 1087 uint8_t nmw, nsw, rev; 1088 struct bwfm_core *core; 1089 1090 erom = sc->sc_buscore_ops->bc_read(sc, 1091 BWFM_CHIP_BASE + BWFM_CHIP_REG_EROMPTR); 1092 while (type != BWFM_DMP_DESC_EOT) { 1093 val = sc->sc_buscore_ops->bc_read(sc, erom); 1094 type = val & BWFM_DMP_DESC_MASK; 1095 erom += 4; 1096 1097 if (type != BWFM_DMP_DESC_COMPONENT) 1098 continue; 1099 1100 id = (val & BWFM_DMP_COMP_PARTNUM) 1101 >> BWFM_DMP_COMP_PARTNUM_S; 1102 1103 val = sc->sc_buscore_ops->bc_read(sc, erom); 1104 type = val & BWFM_DMP_DESC_MASK; 1105 erom += 4; 1106 1107 if (type != BWFM_DMP_DESC_COMPONENT) { 1108 printf("%s: not component descriptor\n", DEVNAME(sc)); 1109 return; 1110 } 1111 1112 nmw = (val & BWFM_DMP_COMP_NUM_MWRAP) 1113 >> BWFM_DMP_COMP_NUM_MWRAP_S; 1114 nsw = (val & BWFM_DMP_COMP_NUM_SWRAP) 1115 >> BWFM_DMP_COMP_NUM_SWRAP_S; 1116 rev = (val & BWFM_DMP_COMP_REVISION) 1117 >> BWFM_DMP_COMP_REVISION_S; 1118 1119 if (nmw + nsw == 0 && id != BWFM_AGENT_CORE_PMU && 1120 id != BWFM_AGENT_CORE_GCI) 1121 continue; 1122 1123 if (bwfm_chip_dmp_get_regaddr(sc, &erom, &base, &wrap)) 1124 continue; 1125 1126 core = malloc(sizeof(*core), M_DEVBUF, M_WAITOK); 1127 core->co_id = id; 1128 core->co_base = base; 1129 core->co_wrapbase = wrap; 1130 core->co_rev = rev; 1131 LIST_INSERT_HEAD(&sc->sc_chip.ch_list, core, co_link); 1132 } 1133 } 1134 1135 int 1136 bwfm_chip_dmp_get_regaddr(struct bwfm_softc *sc, uint32_t *erom, 1137 uint32_t *base, uint32_t *wrap) 1138 { 1139 uint8_t type = 0, mpnum = 0; 1140 uint8_t stype, sztype, wraptype; 1141 uint32_t val; 1142 1143 *base = 0; 1144 *wrap = 0; 1145 1146 val = sc->sc_buscore_ops->bc_read(sc, *erom); 1147 type = val & BWFM_DMP_DESC_MASK; 1148 if (type == BWFM_DMP_DESC_MASTER_PORT) { 1149 mpnum = (val & BWFM_DMP_MASTER_PORT_NUM) 1150 >> BWFM_DMP_MASTER_PORT_NUM_S; 1151 wraptype = BWFM_DMP_SLAVE_TYPE_MWRAP; 1152 *erom += 4; 1153 } else if ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) == 1154 BWFM_DMP_DESC_ADDRESS) 1155 wraptype = BWFM_DMP_SLAVE_TYPE_SWRAP; 1156 else 1157 return 1; 1158 1159 do { 1160 do { 1161 val = sc->sc_buscore_ops->bc_read(sc, *erom); 1162 type = val & BWFM_DMP_DESC_MASK; 1163 if (type == BWFM_DMP_DESC_COMPONENT) 1164 return 0; 1165 if (type == BWFM_DMP_DESC_EOT) 1166 return 1; 1167 *erom += 4; 1168 } while ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) != 1169 BWFM_DMP_DESC_ADDRESS); 1170 1171 if (type & BWFM_DMP_DESC_ADDRSIZE_GT32) 1172 *erom += 4; 1173 1174 sztype = (val & BWFM_DMP_SLAVE_SIZE_TYPE) 1175 >> BWFM_DMP_SLAVE_SIZE_TYPE_S; 1176 if (sztype == BWFM_DMP_SLAVE_SIZE_DESC) { 1177 val = sc->sc_buscore_ops->bc_read(sc, *erom); 1178 type = val & BWFM_DMP_DESC_MASK; 1179 if (type & BWFM_DMP_DESC_ADDRSIZE_GT32) 1180 *erom += 8; 1181 else 1182 *erom += 4; 1183 } 1184 if (sztype != BWFM_DMP_SLAVE_SIZE_4K && 1185 sztype != BWFM_DMP_SLAVE_SIZE_8K) 1186 continue; 1187 1188 stype = (val & BWFM_DMP_SLAVE_TYPE) >> BWFM_DMP_SLAVE_TYPE_S; 1189 if (*base == 0 && stype == BWFM_DMP_SLAVE_TYPE_SLAVE) 1190 *base = val & BWFM_DMP_SLAVE_ADDR_BASE; 1191 if (*wrap == 0 && stype == wraptype) 1192 *wrap = val & BWFM_DMP_SLAVE_ADDR_BASE; 1193 } while (*base == 0 || *wrap == 0); 1194 1195 return 0; 1196 } 1197 1198 /* Core configuration */ 1199 int 1200 bwfm_chip_set_active(struct bwfm_softc *sc, uint32_t rstvec) 1201 { 1202 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) 1203 return bwfm_chip_cr4_set_active(sc, rstvec); 1204 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) 1205 return bwfm_chip_ca7_set_active(sc, rstvec); 1206 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) 1207 return bwfm_chip_cm3_set_active(sc); 1208 return 1; 1209 } 1210 1211 void 1212 bwfm_chip_set_passive(struct bwfm_softc *sc) 1213 { 1214 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) { 1215 bwfm_chip_cr4_set_passive(sc); 1216 return; 1217 } 1218 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) { 1219 bwfm_chip_ca7_set_passive(sc); 1220 return; 1221 } 1222 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) { 1223 bwfm_chip_cm3_set_passive(sc); 1224 return; 1225 } 1226 } 1227 1228 int 1229 bwfm_chip_cr4_set_active(struct bwfm_softc *sc, uint32_t rstvec) 1230 { 1231 struct bwfm_core *core; 1232 1233 sc->sc_buscore_ops->bc_activate(sc, rstvec); 1234 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4); 1235 sc->sc_chip.ch_core_reset(sc, core, 1236 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0); 1237 1238 return 0; 1239 } 1240 1241 void 1242 bwfm_chip_cr4_set_passive(struct bwfm_softc *sc) 1243 { 1244 struct bwfm_core *core; 1245 uint32_t val; 1246 1247 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4); 1248 val = sc->sc_buscore_ops->bc_read(sc, 1249 core->co_wrapbase + BWFM_AGENT_IOCTL); 1250 sc->sc_chip.ch_core_reset(sc, core, 1251 val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 1252 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 1253 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT); 1254 1255 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); 1256 sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | 1257 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, 1258 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); 1259 } 1260 1261 int 1262 bwfm_chip_ca7_set_active(struct bwfm_softc *sc, uint32_t rstvec) 1263 { 1264 struct bwfm_core *core; 1265 1266 sc->sc_buscore_ops->bc_activate(sc, rstvec); 1267 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7); 1268 sc->sc_chip.ch_core_reset(sc, core, 1269 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0); 1270 1271 return 0; 1272 } 1273 1274 void 1275 bwfm_chip_ca7_set_passive(struct bwfm_softc *sc) 1276 { 1277 struct bwfm_core *core; 1278 uint32_t val; 1279 1280 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7); 1281 val = sc->sc_buscore_ops->bc_read(sc, 1282 core->co_wrapbase + BWFM_AGENT_IOCTL); 1283 sc->sc_chip.ch_core_reset(sc, core, 1284 val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 1285 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 1286 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT); 1287 1288 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); 1289 sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | 1290 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, 1291 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); 1292 } 1293 1294 int 1295 bwfm_chip_cm3_set_active(struct bwfm_softc *sc) 1296 { 1297 struct bwfm_core *core; 1298 1299 core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM); 1300 if (!sc->sc_chip.ch_core_isup(sc, core)) 1301 return 1; 1302 1303 sc->sc_buscore_ops->bc_activate(sc, 0); 1304 1305 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3); 1306 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); 1307 1308 return 0; 1309 } 1310 1311 void 1312 bwfm_chip_cm3_set_passive(struct bwfm_softc *sc) 1313 { 1314 struct bwfm_core *core; 1315 1316 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3); 1317 sc->sc_chip.ch_core_disable(sc, core, 0, 0); 1318 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); 1319 sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | 1320 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, 1321 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); 1322 core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM); 1323 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); 1324 1325 if (sc->sc_chip.ch_chip == BRCM_CC_43430_CHIP_ID) { 1326 sc->sc_buscore_ops->bc_write(sc, 1327 core->co_base + BWFM_SOCRAM_BANKIDX, 3); 1328 sc->sc_buscore_ops->bc_write(sc, 1329 core->co_base + BWFM_SOCRAM_BANKPDA, 0); 1330 } 1331 } 1332 1333 int 1334 bwfm_chip_sr_capable(struct bwfm_softc *sc) 1335 { 1336 struct bwfm_core *core; 1337 uint32_t reg; 1338 1339 if (sc->sc_chip.ch_pmurev < 17) 1340 return 0; 1341 1342 switch (sc->sc_chip.ch_chip) { 1343 case BRCM_CC_4345_CHIP_ID: 1344 case BRCM_CC_4354_CHIP_ID: 1345 case BRCM_CC_4356_CHIP_ID: 1346 core = bwfm_chip_get_pmu(sc); 1347 sc->sc_buscore_ops->bc_write(sc, core->co_base + 1348 BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3); 1349 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + 1350 BWFM_CHIP_REG_CHIPCONTROL_DATA); 1351 return (reg & (1 << 2)) != 0; 1352 case BRCM_CC_43241_CHIP_ID: 1353 case BRCM_CC_4335_CHIP_ID: 1354 case BRCM_CC_4339_CHIP_ID: 1355 core = bwfm_chip_get_pmu(sc); 1356 sc->sc_buscore_ops->bc_write(sc, core->co_base + 1357 BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3); 1358 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + 1359 BWFM_CHIP_REG_CHIPCONTROL_DATA); 1360 return reg != 0; 1361 case BRCM_CC_43430_CHIP_ID: 1362 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); 1363 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + 1364 BWFM_CHIP_REG_SR_CONTROL1); 1365 return reg != 0; 1366 case BRCM_CC_4378_CHIP_ID: 1367 return 0; 1368 default: 1369 core = bwfm_chip_get_pmu(sc); 1370 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + 1371 BWFM_CHIP_REG_PMUCAPABILITIES_EXT); 1372 if ((reg & BWFM_CHIP_REG_PMUCAPABILITIES_SR_SUPP) == 0) 1373 return 0; 1374 1375 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base + 1376 BWFM_CHIP_REG_RETENTION_CTL); 1377 return (reg & (BWFM_CHIP_REG_RETENTION_CTL_MACPHY_DIS | 1378 BWFM_CHIP_REG_RETENTION_CTL_LOGIC_DIS)) == 0; 1379 } 1380 } 1381 1382 /* RAM size helpers */ 1383 void 1384 bwfm_chip_socram_ramsize(struct bwfm_softc *sc, struct bwfm_core *core) 1385 { 1386 uint32_t coreinfo, nb, lss, banksize, bankinfo; 1387 uint32_t ramsize = 0, srsize = 0; 1388 int i; 1389 1390 if (!sc->sc_chip.ch_core_isup(sc, core)) 1391 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); 1392 1393 coreinfo = sc->sc_buscore_ops->bc_read(sc, 1394 core->co_base + BWFM_SOCRAM_COREINFO); 1395 nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK) 1396 >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT; 1397 1398 if (core->co_rev <= 7 || core->co_rev == 12) { 1399 banksize = coreinfo & BWFM_SOCRAM_COREINFO_SRBSZ_MASK; 1400 lss = (coreinfo & BWFM_SOCRAM_COREINFO_LSS_MASK) 1401 >> BWFM_SOCRAM_COREINFO_LSS_SHIFT; 1402 if (lss != 0) 1403 nb--; 1404 ramsize = nb * (1 << (banksize + BWFM_SOCRAM_COREINFO_SRBSZ_BASE)); 1405 if (lss != 0) 1406 ramsize += (1 << ((lss - 1) + BWFM_SOCRAM_COREINFO_SRBSZ_BASE)); 1407 } else { 1408 for (i = 0; i < nb; i++) { 1409 sc->sc_buscore_ops->bc_write(sc, 1410 core->co_base + BWFM_SOCRAM_BANKIDX, 1411 (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM << 1412 BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i); 1413 bankinfo = sc->sc_buscore_ops->bc_read(sc, 1414 core->co_base + BWFM_SOCRAM_BANKINFO); 1415 banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1) 1416 * BWFM_SOCRAM_BANKINFO_SZBASE; 1417 ramsize += banksize; 1418 if (bankinfo & BWFM_SOCRAM_BANKINFO_RETNTRAM_MASK) 1419 srsize += banksize; 1420 } 1421 } 1422 1423 switch (sc->sc_chip.ch_chip) { 1424 case BRCM_CC_4334_CHIP_ID: 1425 if (sc->sc_chip.ch_chiprev < 2) 1426 srsize = 32 * 1024; 1427 break; 1428 case BRCM_CC_43430_CHIP_ID: 1429 srsize = 64 * 1024; 1430 break; 1431 default: 1432 break; 1433 } 1434 1435 sc->sc_chip.ch_ramsize = ramsize; 1436 sc->sc_chip.ch_srsize = srsize; 1437 } 1438 1439 void 1440 bwfm_chip_sysmem_ramsize(struct bwfm_softc *sc, struct bwfm_core *core) 1441 { 1442 uint32_t coreinfo, nb, banksize, bankinfo; 1443 uint32_t ramsize = 0; 1444 int i; 1445 1446 if (!sc->sc_chip.ch_core_isup(sc, core)) 1447 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); 1448 1449 coreinfo = sc->sc_buscore_ops->bc_read(sc, 1450 core->co_base + BWFM_SOCRAM_COREINFO); 1451 nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK) 1452 >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT; 1453 1454 for (i = 0; i < nb; i++) { 1455 sc->sc_buscore_ops->bc_write(sc, 1456 core->co_base + BWFM_SOCRAM_BANKIDX, 1457 (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM << 1458 BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i); 1459 bankinfo = sc->sc_buscore_ops->bc_read(sc, 1460 core->co_base + BWFM_SOCRAM_BANKINFO); 1461 banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1) 1462 * BWFM_SOCRAM_BANKINFO_SZBASE; 1463 ramsize += banksize; 1464 } 1465 1466 sc->sc_chip.ch_ramsize = ramsize; 1467 } 1468 1469 void 1470 bwfm_chip_tcm_ramsize(struct bwfm_softc *sc, struct bwfm_core *core) 1471 { 1472 uint32_t cap, nab, nbb, totb, bxinfo, ramsize = 0; 1473 int i; 1474 1475 cap = sc->sc_buscore_ops->bc_read(sc, core->co_base + BWFM_ARMCR4_CAP); 1476 nab = (cap & BWFM_ARMCR4_CAP_TCBANB_MASK) >> BWFM_ARMCR4_CAP_TCBANB_SHIFT; 1477 nbb = (cap & BWFM_ARMCR4_CAP_TCBBNB_MASK) >> BWFM_ARMCR4_CAP_TCBBNB_SHIFT; 1478 totb = nab + nbb; 1479 1480 for (i = 0; i < totb; i++) { 1481 sc->sc_buscore_ops->bc_write(sc, 1482 core->co_base + BWFM_ARMCR4_BANKIDX, i); 1483 bxinfo = sc->sc_buscore_ops->bc_read(sc, 1484 core->co_base + BWFM_ARMCR4_BANKINFO); 1485 ramsize += ((bxinfo & BWFM_ARMCR4_BANKINFO_BSZ_MASK) + 1) * 1486 BWFM_ARMCR4_BANKINFO_BSZ_MULT; 1487 } 1488 1489 sc->sc_chip.ch_ramsize = ramsize; 1490 } 1491 1492 void 1493 bwfm_chip_tcm_rambase(struct bwfm_softc *sc) 1494 { 1495 switch (sc->sc_chip.ch_chip) { 1496 case BRCM_CC_4345_CHIP_ID: 1497 sc->sc_chip.ch_rambase = 0x198000; 1498 break; 1499 case BRCM_CC_4335_CHIP_ID: 1500 case BRCM_CC_4339_CHIP_ID: 1501 case BRCM_CC_4350_CHIP_ID: 1502 case BRCM_CC_4354_CHIP_ID: 1503 case BRCM_CC_4356_CHIP_ID: 1504 case BRCM_CC_43567_CHIP_ID: 1505 case BRCM_CC_43569_CHIP_ID: 1506 case BRCM_CC_43570_CHIP_ID: 1507 case BRCM_CC_4358_CHIP_ID: 1508 case BRCM_CC_43602_CHIP_ID: 1509 case BRCM_CC_4371_CHIP_ID: 1510 sc->sc_chip.ch_rambase = 0x180000; 1511 break; 1512 case BRCM_CC_4359_CHIP_ID: 1513 if (sc->sc_chip.ch_chiprev < 9) 1514 sc->sc_chip.ch_rambase = 0x180000; 1515 else 1516 sc->sc_chip.ch_rambase = 0x160000; 1517 break; 1518 case BRCM_CC_43465_CHIP_ID: 1519 case BRCM_CC_43525_CHIP_ID: 1520 case BRCM_CC_4365_CHIP_ID: 1521 case BRCM_CC_4366_CHIP_ID: 1522 sc->sc_chip.ch_rambase = 0x200000; 1523 break; 1524 case CY_CC_4373_CHIP_ID: 1525 sc->sc_chip.ch_rambase = 0x160000; 1526 break; 1527 case BRCM_CC_4378_CHIP_ID: 1528 sc->sc_chip.ch_rambase = 0x352000; 1529 break; 1530 default: 1531 printf("%s: unknown chip: %d\n", DEVNAME(sc), 1532 sc->sc_chip.ch_chip); 1533 break; 1534 } 1535 } 1536 1537 /* BCDC protocol implementation */ 1538 int 1539 bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *sc, int ifidx, 1540 int cmd, char *buf, size_t *len) 1541 { 1542 struct bwfm_proto_bcdc_dcmd *dcmd; 1543 size_t size = sizeof(dcmd->hdr) + *len; 1544 int ret = 1, reqid; 1545 1546 reqid = sc->sc_bcdc_reqid++; 1547 1548 if (*len > sizeof(dcmd->buf)) 1549 return ret; 1550 1551 dcmd = malloc(size, M_TEMP, M_WAITOK | M_ZERO); 1552 dcmd->hdr.cmd = htole32(cmd); 1553 dcmd->hdr.len = htole32(*len); 1554 dcmd->hdr.flags |= BWFM_BCDC_DCMD_GET; 1555 dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid); 1556 dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx); 1557 dcmd->hdr.flags = htole32(dcmd->hdr.flags); 1558 memcpy(&dcmd->buf, buf, *len); 1559 1560 if (bwfm_proto_bcdc_txctl(sc, reqid, (char *)dcmd, &size)) { 1561 DPRINTF(("%s: tx failed\n", DEVNAME(sc))); 1562 return ret; 1563 } 1564 1565 if (buf) { 1566 *len = min(*len, size); 1567 memcpy(buf, dcmd->buf, *len); 1568 } 1569 1570 if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR) 1571 ret = dcmd->hdr.status; 1572 else 1573 ret = 0; 1574 free(dcmd, M_TEMP, size); 1575 return ret; 1576 } 1577 1578 int 1579 bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *sc, int ifidx, 1580 int cmd, char *buf, size_t len) 1581 { 1582 struct bwfm_proto_bcdc_dcmd *dcmd; 1583 size_t size = sizeof(dcmd->hdr) + len; 1584 int ret = 1, reqid; 1585 1586 reqid = sc->sc_bcdc_reqid++; 1587 1588 if (len > sizeof(dcmd->buf)) 1589 return ret; 1590 1591 dcmd = malloc(size, M_TEMP, M_WAITOK | M_ZERO); 1592 dcmd->hdr.cmd = htole32(cmd); 1593 dcmd->hdr.len = htole32(len); 1594 dcmd->hdr.flags |= BWFM_BCDC_DCMD_SET; 1595 dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid); 1596 dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx); 1597 dcmd->hdr.flags = htole32(dcmd->hdr.flags); 1598 memcpy(&dcmd->buf, buf, len); 1599 1600 if (bwfm_proto_bcdc_txctl(sc, reqid, (char *)dcmd, &size)) { 1601 DPRINTF(("%s: txctl failed\n", DEVNAME(sc))); 1602 return ret; 1603 } 1604 1605 if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR) 1606 ret = dcmd->hdr.status; 1607 else 1608 ret = 0; 1609 free(dcmd, M_TEMP, size); 1610 return ret; 1611 } 1612 1613 int 1614 bwfm_proto_bcdc_txctl(struct bwfm_softc *sc, int reqid, char *buf, size_t *len) 1615 { 1616 struct bwfm_proto_bcdc_ctl *ctl, *tmp; 1617 int timeout = 0; 1618 1619 ctl = malloc(sizeof(*ctl), M_TEMP, M_WAITOK|M_ZERO); 1620 ctl->reqid = reqid; 1621 ctl->buf = buf; 1622 ctl->len = *len; 1623 1624 if (sc->sc_bus_ops->bs_txctl(sc, ctl)) { 1625 DPRINTF(("%s: tx failed\n", DEVNAME(sc))); 1626 return 1; 1627 } 1628 1629 if (tsleep_nsec(ctl, PWAIT, "bwfm", SEC_TO_NSEC(1))) 1630 timeout = 1; 1631 1632 TAILQ_FOREACH_SAFE(ctl, &sc->sc_bcdc_rxctlq, next, tmp) { 1633 if (ctl->reqid != reqid) 1634 continue; 1635 if (ctl->done) { 1636 TAILQ_REMOVE(&sc->sc_bcdc_rxctlq, ctl, next); 1637 *len = ctl->len; 1638 free(ctl, M_TEMP, sizeof(*ctl)); 1639 return 0; 1640 } 1641 if (timeout) { 1642 TAILQ_REMOVE(&sc->sc_bcdc_rxctlq, ctl, next); 1643 DPRINTF(("%s: timeout waiting for txctl response\n", 1644 DEVNAME(sc))); 1645 free(ctl->buf, M_TEMP, ctl->len); 1646 free(ctl, M_TEMP, sizeof(*ctl)); 1647 return 1; 1648 } 1649 break; 1650 } 1651 1652 DPRINTF(("%s: did%s find txctl metadata (timeout %d)\n", 1653 DEVNAME(sc), ctl == NULL ? " not": "", timeout)); 1654 return 1; 1655 } 1656 1657 void 1658 bwfm_proto_bcdc_rxctl(struct bwfm_softc *sc, char *buf, size_t len) 1659 { 1660 struct bwfm_proto_bcdc_dcmd *dcmd; 1661 struct bwfm_proto_bcdc_ctl *ctl, *tmp; 1662 1663 if (len < sizeof(dcmd->hdr)) 1664 return; 1665 1666 dcmd = (struct bwfm_proto_bcdc_dcmd *)buf; 1667 dcmd->hdr.cmd = letoh32(dcmd->hdr.cmd); 1668 dcmd->hdr.len = letoh32(dcmd->hdr.len); 1669 dcmd->hdr.flags = letoh32(dcmd->hdr.flags); 1670 dcmd->hdr.status = letoh32(dcmd->hdr.status); 1671 1672 TAILQ_FOREACH_SAFE(ctl, &sc->sc_bcdc_rxctlq, next, tmp) { 1673 if (ctl->reqid != BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags)) 1674 continue; 1675 if (ctl->len != len) { 1676 free(ctl->buf, M_TEMP, ctl->len); 1677 free(ctl, M_TEMP, sizeof(*ctl)); 1678 return; 1679 } 1680 memcpy(ctl->buf, buf, len); 1681 ctl->done = 1; 1682 wakeup(ctl); 1683 return; 1684 } 1685 } 1686 1687 void 1688 bwfm_proto_bcdc_rx(struct bwfm_softc *sc, struct mbuf *m, struct mbuf_list *ml) 1689 { 1690 struct bwfm_proto_bcdc_hdr *hdr; 1691 1692 hdr = mtod(m, struct bwfm_proto_bcdc_hdr *); 1693 if (m->m_len < sizeof(*hdr)) { 1694 m_freem(m); 1695 return; 1696 } 1697 if (m->m_len < sizeof(*hdr) + (hdr->data_offset << 2)) { 1698 m_freem(m); 1699 return; 1700 } 1701 m_adj(m, sizeof(*hdr) + (hdr->data_offset << 2)); 1702 1703 bwfm_rx(sc, m, ml); 1704 } 1705 1706 /* FW Variable code */ 1707 int 1708 bwfm_fwvar_cmd_get_data(struct bwfm_softc *sc, int cmd, void *data, size_t len) 1709 { 1710 return sc->sc_proto_ops->proto_query_dcmd(sc, 0, cmd, data, &len); 1711 } 1712 1713 int 1714 bwfm_fwvar_cmd_set_data(struct bwfm_softc *sc, int cmd, void *data, size_t len) 1715 { 1716 return sc->sc_proto_ops->proto_set_dcmd(sc, 0, cmd, data, len); 1717 } 1718 1719 int 1720 bwfm_fwvar_cmd_get_int(struct bwfm_softc *sc, int cmd, uint32_t *data) 1721 { 1722 int ret; 1723 ret = bwfm_fwvar_cmd_get_data(sc, cmd, data, sizeof(*data)); 1724 *data = letoh32(*data); 1725 return ret; 1726 } 1727 1728 int 1729 bwfm_fwvar_cmd_set_int(struct bwfm_softc *sc, int cmd, uint32_t data) 1730 { 1731 data = htole32(data); 1732 return bwfm_fwvar_cmd_set_data(sc, cmd, &data, sizeof(data)); 1733 } 1734 1735 int 1736 bwfm_fwvar_var_get_data(struct bwfm_softc *sc, char *name, void *data, size_t len) 1737 { 1738 char *buf; 1739 int ret; 1740 1741 buf = malloc(strlen(name) + 1 + len, M_TEMP, M_WAITOK); 1742 memcpy(buf, name, strlen(name) + 1); 1743 memcpy(buf + strlen(name) + 1, data, len); 1744 ret = bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_VAR, 1745 buf, strlen(name) + 1 + len); 1746 memcpy(data, buf, len); 1747 free(buf, M_TEMP, strlen(name) + 1 + len); 1748 return ret; 1749 } 1750 1751 int 1752 bwfm_fwvar_var_set_data(struct bwfm_softc *sc, char *name, void *data, size_t len) 1753 { 1754 char *buf; 1755 int ret; 1756 1757 buf = malloc(strlen(name) + 1 + len, M_TEMP, M_WAITOK); 1758 memcpy(buf, name, strlen(name) + 1); 1759 memcpy(buf + strlen(name) + 1, data, len); 1760 ret = bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_VAR, 1761 buf, strlen(name) + 1 + len); 1762 free(buf, M_TEMP, strlen(name) + 1 + len); 1763 return ret; 1764 } 1765 1766 int 1767 bwfm_fwvar_var_get_int(struct bwfm_softc *sc, char *name, uint32_t *data) 1768 { 1769 int ret; 1770 ret = bwfm_fwvar_var_get_data(sc, name, data, sizeof(*data)); 1771 *data = letoh32(*data); 1772 return ret; 1773 } 1774 1775 int 1776 bwfm_fwvar_var_set_int(struct bwfm_softc *sc, char *name, uint32_t data) 1777 { 1778 data = htole32(data); 1779 return bwfm_fwvar_var_set_data(sc, name, &data, sizeof(data)); 1780 } 1781 1782 /* Channel parameters */ 1783 uint32_t 1784 bwfm_chan2spec(struct bwfm_softc *sc, struct ieee80211_channel *c) 1785 { 1786 if (sc->sc_io_type == BWFM_IO_TYPE_D11N) 1787 return bwfm_chan2spec_d11n(sc, c); 1788 else 1789 return bwfm_chan2spec_d11ac(sc, c); 1790 } 1791 1792 uint32_t 1793 bwfm_chan2spec_d11n(struct bwfm_softc *sc, struct ieee80211_channel *c) 1794 { 1795 uint32_t chanspec; 1796 1797 chanspec = ieee80211_mhz2ieee(c->ic_freq, 0) & BWFM_CHANSPEC_CHAN_MASK; 1798 chanspec |= BWFM_CHANSPEC_D11N_SB_N; 1799 chanspec |= BWFM_CHANSPEC_D11N_BW_20; 1800 if (IEEE80211_IS_CHAN_2GHZ(c)) 1801 chanspec |= BWFM_CHANSPEC_D11N_BND_2G; 1802 if (IEEE80211_IS_CHAN_5GHZ(c)) 1803 chanspec |= BWFM_CHANSPEC_D11N_BND_5G; 1804 1805 return chanspec; 1806 } 1807 1808 uint32_t 1809 bwfm_chan2spec_d11ac(struct bwfm_softc *sc, struct ieee80211_channel *c) 1810 { 1811 uint32_t chanspec; 1812 1813 chanspec = ieee80211_mhz2ieee(c->ic_freq, 0) & BWFM_CHANSPEC_CHAN_MASK; 1814 chanspec |= BWFM_CHANSPEC_D11AC_SB_LLL; 1815 chanspec |= BWFM_CHANSPEC_D11AC_BW_20; 1816 if (IEEE80211_IS_CHAN_2GHZ(c)) 1817 chanspec |= BWFM_CHANSPEC_D11AC_BND_2G; 1818 if (IEEE80211_IS_CHAN_5GHZ(c)) 1819 chanspec |= BWFM_CHANSPEC_D11AC_BND_5G; 1820 1821 return chanspec; 1822 } 1823 1824 uint32_t 1825 bwfm_spec2chan(struct bwfm_softc *sc, uint32_t chanspec) 1826 { 1827 if (sc->sc_io_type == BWFM_IO_TYPE_D11N) 1828 return bwfm_spec2chan_d11n(sc, chanspec); 1829 else 1830 return bwfm_spec2chan_d11ac(sc, chanspec); 1831 } 1832 1833 uint32_t 1834 bwfm_spec2chan_d11n(struct bwfm_softc *sc, uint32_t chanspec) 1835 { 1836 uint32_t chanidx; 1837 1838 chanidx = chanspec & BWFM_CHANSPEC_CHAN_MASK; 1839 1840 switch (chanspec & BWFM_CHANSPEC_D11N_BW_MASK) { 1841 case BWFM_CHANSPEC_D11N_BW_40: 1842 switch (chanspec & BWFM_CHANSPEC_D11N_SB_MASK) { 1843 case BWFM_CHANSPEC_D11N_SB_L: 1844 chanidx -= 2; 1845 break; 1846 case BWFM_CHANSPEC_D11N_SB_U: 1847 chanidx += 2; 1848 break; 1849 default: 1850 break; 1851 } 1852 break; 1853 default: 1854 break; 1855 } 1856 1857 return chanidx; 1858 } 1859 1860 uint32_t 1861 bwfm_spec2chan_d11ac(struct bwfm_softc *sc, uint32_t chanspec) 1862 { 1863 uint32_t chanidx; 1864 1865 chanidx = chanspec & BWFM_CHANSPEC_CHAN_MASK; 1866 1867 switch (chanspec & BWFM_CHANSPEC_D11AC_BW_MASK) { 1868 case BWFM_CHANSPEC_D11AC_BW_40: 1869 switch (chanspec & BWFM_CHANSPEC_D11AC_SB_MASK) { 1870 case BWFM_CHANSPEC_D11AC_SB_LLL: 1871 chanidx -= 2; 1872 break; 1873 case BWFM_CHANSPEC_D11AC_SB_LLU: 1874 chanidx += 2; 1875 break; 1876 default: 1877 break; 1878 } 1879 break; 1880 case BWFM_CHANSPEC_D11AC_BW_80: 1881 switch (chanspec & BWFM_CHANSPEC_D11AC_SB_MASK) { 1882 case BWFM_CHANSPEC_D11AC_SB_LLL: 1883 chanidx -= 6; 1884 break; 1885 case BWFM_CHANSPEC_D11AC_SB_LLU: 1886 chanidx -= 2; 1887 break; 1888 case BWFM_CHANSPEC_D11AC_SB_LUL: 1889 chanidx += 2; 1890 break; 1891 case BWFM_CHANSPEC_D11AC_SB_LUU: 1892 chanidx += 6; 1893 break; 1894 default: 1895 break; 1896 } 1897 break; 1898 default: 1899 break; 1900 } 1901 1902 return chanidx; 1903 } 1904 1905 /* 802.11 code */ 1906 void 1907 bwfm_connect(struct bwfm_softc *sc) 1908 { 1909 struct ieee80211com *ic = &sc->sc_ic; 1910 struct bwfm_ext_join_params *params; 1911 uint8_t buf[64]; /* XXX max WPA/RSN/WMM IE length */ 1912 uint8_t *frm; 1913 1914 /* 1915 * OPEN: Open or WPA/WPA2 on newer Chips/Firmware. 1916 * SHARED KEY: WEP. 1917 * AUTO: Automatic, probably for older Chips/Firmware. 1918 */ 1919 if (ic->ic_flags & IEEE80211_F_RSNON) { 1920 uint32_t wsec = 0; 1921 uint32_t wpa = 0; 1922 1923 /* tell firmware to add WPA/RSN IE to (re)assoc request */ 1924 if (ic->ic_bss->ni_rsnprotos == IEEE80211_PROTO_RSN) 1925 frm = ieee80211_add_rsn(buf, ic, ic->ic_bss); 1926 else 1927 frm = ieee80211_add_wpa(buf, ic, ic->ic_bss); 1928 bwfm_fwvar_var_set_data(sc, "wpaie", buf, frm - buf); 1929 1930 if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA) { 1931 if (ic->ic_rsnakms & IEEE80211_AKM_PSK) 1932 wpa |= BWFM_WPA_AUTH_WPA_PSK; 1933 if (ic->ic_rsnakms & IEEE80211_AKM_8021X) 1934 wpa |= BWFM_WPA_AUTH_WPA_UNSPECIFIED; 1935 } 1936 if (ic->ic_rsnprotos & IEEE80211_PROTO_RSN) { 1937 if (ic->ic_rsnakms & IEEE80211_AKM_PSK) 1938 wpa |= BWFM_WPA_AUTH_WPA2_PSK; 1939 if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_PSK) 1940 wpa |= BWFM_WPA_AUTH_WPA2_PSK_SHA256; 1941 if (ic->ic_rsnakms & IEEE80211_AKM_8021X) 1942 wpa |= BWFM_WPA_AUTH_WPA2_UNSPECIFIED; 1943 if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_8021X) 1944 wpa |= BWFM_WPA_AUTH_WPA2_1X_SHA256; 1945 } 1946 if (ic->ic_rsnciphers & IEEE80211_WPA_CIPHER_TKIP || 1947 ic->ic_rsngroupcipher & IEEE80211_WPA_CIPHER_TKIP) 1948 wsec |= BWFM_WSEC_TKIP; 1949 if (ic->ic_rsnciphers & IEEE80211_WPA_CIPHER_CCMP || 1950 ic->ic_rsngroupcipher & IEEE80211_WPA_CIPHER_CCMP) 1951 wsec |= BWFM_WSEC_AES; 1952 1953 bwfm_fwvar_var_set_int(sc, "wpa_auth", wpa); 1954 bwfm_fwvar_var_set_int(sc, "wsec", wsec); 1955 } else { 1956 bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_DISABLED); 1957 bwfm_fwvar_var_set_int(sc, "wsec", BWFM_WSEC_NONE); 1958 } 1959 bwfm_fwvar_var_set_int(sc, "auth", BWFM_AUTH_OPEN); 1960 bwfm_fwvar_var_set_int(sc, "mfp", BWFM_MFP_NONE); 1961 1962 if (ic->ic_des_esslen && ic->ic_des_esslen < BWFM_MAX_SSID_LEN) { 1963 params = malloc(sizeof(*params), M_TEMP, M_WAITOK | M_ZERO); 1964 memcpy(params->ssid.ssid, ic->ic_des_essid, ic->ic_des_esslen); 1965 params->ssid.len = htole32(ic->ic_des_esslen); 1966 memcpy(params->assoc.bssid, ic->ic_bss->ni_bssid, 1967 sizeof(params->assoc.bssid)); 1968 params->scan.scan_type = -1; 1969 params->scan.nprobes = htole32(-1); 1970 params->scan.active_time = htole32(-1); 1971 params->scan.passive_time = htole32(-1); 1972 params->scan.home_time = htole32(-1); 1973 if (bwfm_fwvar_var_set_data(sc, "join", params, sizeof(*params))) { 1974 struct bwfm_join_params join; 1975 memset(&join, 0, sizeof(join)); 1976 memcpy(join.ssid.ssid, ic->ic_des_essid, 1977 ic->ic_des_esslen); 1978 join.ssid.len = htole32(ic->ic_des_esslen); 1979 memcpy(join.assoc.bssid, ic->ic_bss->ni_bssid, 1980 sizeof(join.assoc.bssid)); 1981 bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, 1982 sizeof(join)); 1983 } 1984 free(params, M_TEMP, sizeof(*params)); 1985 } 1986 } 1987 1988 #ifndef IEEE80211_STA_ONLY 1989 void 1990 bwfm_hostap(struct bwfm_softc *sc) 1991 { 1992 struct ieee80211com *ic = &sc->sc_ic; 1993 struct ieee80211_node *ni = ic->ic_bss; 1994 struct bwfm_join_params join; 1995 1996 /* 1997 * OPEN: Open or WPA/WPA2 on newer Chips/Firmware. 1998 * SHARED KEY: WEP. 1999 * AUTO: Automatic, probably for older Chips/Firmware. 2000 */ 2001 if (ic->ic_flags & IEEE80211_F_RSNON) { 2002 uint32_t wsec = 0; 2003 uint32_t wpa = 0; 2004 2005 /* TODO: Turn off if replay counter set */ 2006 if (ni->ni_rsnprotos & IEEE80211_PROTO_RSN) 2007 bwfm_fwvar_var_set_int(sc, "wme_bss_disable", 1); 2008 2009 if (ni->ni_rsnprotos & IEEE80211_PROTO_WPA) { 2010 if (ni->ni_rsnakms & IEEE80211_AKM_PSK) 2011 wpa |= BWFM_WPA_AUTH_WPA_PSK; 2012 if (ni->ni_rsnakms & IEEE80211_AKM_8021X) 2013 wpa |= BWFM_WPA_AUTH_WPA_UNSPECIFIED; 2014 } 2015 if (ni->ni_rsnprotos & IEEE80211_PROTO_RSN) { 2016 if (ni->ni_rsnakms & IEEE80211_AKM_PSK) 2017 wpa |= BWFM_WPA_AUTH_WPA2_PSK; 2018 if (ni->ni_rsnakms & IEEE80211_AKM_SHA256_PSK) 2019 wpa |= BWFM_WPA_AUTH_WPA2_PSK_SHA256; 2020 if (ni->ni_rsnakms & IEEE80211_AKM_8021X) 2021 wpa |= BWFM_WPA_AUTH_WPA2_UNSPECIFIED; 2022 if (ni->ni_rsnakms & IEEE80211_AKM_SHA256_8021X) 2023 wpa |= BWFM_WPA_AUTH_WPA2_1X_SHA256; 2024 } 2025 if (ni->ni_rsnciphers & IEEE80211_WPA_CIPHER_TKIP || 2026 ni->ni_rsngroupcipher & IEEE80211_WPA_CIPHER_TKIP) 2027 wsec |= BWFM_WSEC_TKIP; 2028 if (ni->ni_rsnciphers & IEEE80211_WPA_CIPHER_CCMP || 2029 ni->ni_rsngroupcipher & IEEE80211_WPA_CIPHER_CCMP) 2030 wsec |= BWFM_WSEC_AES; 2031 2032 bwfm_fwvar_var_set_int(sc, "wpa_auth", wpa); 2033 bwfm_fwvar_var_set_int(sc, "wsec", wsec); 2034 } else { 2035 bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_DISABLED); 2036 bwfm_fwvar_var_set_int(sc, "wsec", BWFM_WSEC_NONE); 2037 } 2038 bwfm_fwvar_var_set_int(sc, "auth", BWFM_AUTH_OPEN); 2039 bwfm_fwvar_var_set_int(sc, "mfp", BWFM_MFP_NONE); 2040 2041 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 1); 2042 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 1); 2043 bwfm_fwvar_var_set_int(sc, "chanspec", 2044 bwfm_chan2spec(sc, ic->ic_bss->ni_chan)); 2045 bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 1); 2046 2047 memset(&join, 0, sizeof(join)); 2048 memcpy(join.ssid.ssid, ic->ic_des_essid, ic->ic_des_esslen); 2049 join.ssid.len = htole32(ic->ic_des_esslen); 2050 memset(join.assoc.bssid, 0xff, sizeof(join.assoc.bssid)); 2051 bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, sizeof(join)); 2052 bwfm_fwvar_var_set_int(sc, "closednet", 2053 (ic->ic_userflags & IEEE80211_F_HIDENWID) != 0); 2054 } 2055 #endif 2056 2057 void 2058 bwfm_scan(struct bwfm_softc *sc) 2059 { 2060 struct ieee80211com *ic = &sc->sc_ic; 2061 struct bwfm_escan_params *params; 2062 uint32_t nssid = 0, nchan = 0; 2063 size_t params_size, chan_size, ssid_size; 2064 struct bwfm_ssid *ssid; 2065 2066 if (ic->ic_flags & IEEE80211_F_ASCAN && 2067 ic->ic_des_esslen && ic->ic_des_esslen < BWFM_MAX_SSID_LEN) 2068 nssid = 1; 2069 2070 chan_size = roundup(nchan * sizeof(uint16_t), sizeof(uint32_t)); 2071 ssid_size = sizeof(struct bwfm_ssid) * nssid; 2072 params_size = sizeof(*params) + chan_size + ssid_size; 2073 2074 params = malloc(params_size, M_TEMP, M_WAITOK | M_ZERO); 2075 ssid = (struct bwfm_ssid *) 2076 (((uint8_t *)params) + sizeof(*params) + chan_size); 2077 2078 memset(params->scan_params.bssid, 0xff, 2079 sizeof(params->scan_params.bssid)); 2080 params->scan_params.bss_type = 2; 2081 params->scan_params.scan_type = BWFM_SCANTYPE_PASSIVE; 2082 params->scan_params.nprobes = htole32(-1); 2083 params->scan_params.active_time = htole32(-1); 2084 params->scan_params.passive_time = htole32(-1); 2085 params->scan_params.home_time = htole32(-1); 2086 params->version = htole32(BWFM_ESCAN_REQ_VERSION); 2087 params->action = htole16(WL_ESCAN_ACTION_START); 2088 params->sync_id = htole16(0x1234); 2089 2090 if (ic->ic_flags & IEEE80211_F_ASCAN && 2091 ic->ic_des_esslen && ic->ic_des_esslen < BWFM_MAX_SSID_LEN) { 2092 params->scan_params.scan_type = BWFM_SCANTYPE_ACTIVE; 2093 ssid->len = htole32(ic->ic_des_esslen); 2094 memcpy(ssid->ssid, ic->ic_des_essid, ic->ic_des_esslen); 2095 } 2096 2097 params->scan_params.channel_num = htole32( 2098 nssid << BWFM_CHANNUM_NSSID_SHIFT | 2099 nchan << BWFM_CHANNUM_NCHAN_SHIFT); 2100 2101 #if 0 2102 /* Scan a specific channel */ 2103 params->scan_params.channel_list[0] = htole16( 2104 (1 & 0xff) << 0 | 2105 (3 & 0x3) << 8 | 2106 (2 & 0x3) << 10 | 2107 (2 & 0x3) << 12 2108 ); 2109 #endif 2110 2111 bwfm_fwvar_var_set_data(sc, "escan", params, params_size); 2112 free(params, M_TEMP, params_size); 2113 } 2114 2115 void 2116 bwfm_scan_abort(struct bwfm_softc *sc) 2117 { 2118 struct bwfm_escan_params *params; 2119 size_t params_size; 2120 2121 params_size = sizeof(*params) + sizeof(uint16_t); 2122 params = malloc(params_size, M_TEMP, M_WAITOK | M_ZERO); 2123 memset(params->scan_params.bssid, 0xff, 2124 sizeof(params->scan_params.bssid)); 2125 params->scan_params.bss_type = 2; 2126 params->scan_params.scan_type = BWFM_SCANTYPE_PASSIVE; 2127 params->scan_params.nprobes = htole32(-1); 2128 params->scan_params.active_time = htole32(-1); 2129 params->scan_params.passive_time = htole32(-1); 2130 params->scan_params.home_time = htole32(-1); 2131 params->version = htole32(BWFM_ESCAN_REQ_VERSION); 2132 params->action = htole16(WL_ESCAN_ACTION_START); 2133 params->sync_id = htole16(0x1234); 2134 params->scan_params.channel_num = htole32(1); 2135 params->scan_params.channel_list[0] = htole16(-1); 2136 bwfm_fwvar_var_set_data(sc, "escan", params, params_size); 2137 free(params, M_TEMP, params_size); 2138 } 2139 2140 struct mbuf * 2141 bwfm_newbuf(void) 2142 { 2143 struct mbuf *m; 2144 2145 MGETHDR(m, M_DONTWAIT, MT_DATA); 2146 if (m == NULL) 2147 return (NULL); 2148 2149 MCLGET(m, M_DONTWAIT); 2150 if (!(m->m_flags & M_EXT)) { 2151 m_freem(m); 2152 return (NULL); 2153 } 2154 2155 m->m_len = m->m_pkthdr.len = MCLBYTES; 2156 2157 return (m); 2158 } 2159 2160 void 2161 bwfm_rx(struct bwfm_softc *sc, struct mbuf *m, struct mbuf_list *ml) 2162 { 2163 struct ieee80211com *ic = &sc->sc_ic; 2164 struct ifnet *ifp = &ic->ic_if; 2165 struct ieee80211_node *ni; 2166 struct bwfm_event *e; 2167 2168 #ifdef __STRICT_ALIGNMENT 2169 /* Remaining data is an ethernet packet, so align. */ 2170 if ((mtod(m, paddr_t) & 0x3) != ETHER_ALIGN) { 2171 struct mbuf *m0; 2172 m0 = m_dup_pkt(m, ETHER_ALIGN, M_WAITOK); 2173 m_freem(m); 2174 if (m0 == NULL) { 2175 ifp->if_ierrors++; 2176 return; 2177 } 2178 m = m0; 2179 } 2180 #endif 2181 2182 e = mtod(m, struct bwfm_event *); 2183 if (m->m_len >= sizeof(e->ehdr) && 2184 ntohs(e->ehdr.ether_type) == BWFM_ETHERTYPE_LINK_CTL && 2185 memcmp(BWFM_BRCM_OUI, e->hdr.oui, sizeof(e->hdr.oui)) == 0 && 2186 ntohs(e->hdr.usr_subtype) == BWFM_BRCM_SUBTYPE_EVENT) { 2187 bwfm_rx_event(sc, m); 2188 return; 2189 } 2190 2191 /* Drop network packets if we are not in RUN state. */ 2192 if (ic->ic_state != IEEE80211_S_RUN) { 2193 m_freem(m); 2194 return; 2195 } 2196 2197 if ((ic->ic_flags & IEEE80211_F_RSNON) && 2198 m->m_len >= sizeof(e->ehdr) && 2199 ntohs(e->ehdr.ether_type) == ETHERTYPE_PAE) { 2200 ifp->if_ipackets++; 2201 #if NBPFILTER > 0 2202 if (ifp->if_bpf) 2203 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN); 2204 #endif 2205 #ifndef IEEE80211_STA_ONLY 2206 if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 2207 ni = ieee80211_find_node(ic, 2208 (void *)&e->ehdr.ether_shost); 2209 if (ni == NULL) { 2210 m_freem(m); 2211 return; 2212 } 2213 } else 2214 #endif 2215 ni = ic->ic_bss; 2216 ieee80211_eapol_key_input(ic, m, ni); 2217 } else 2218 ml_enqueue(ml, m); 2219 } 2220 2221 #ifndef IEEE80211_STA_ONLY 2222 void 2223 bwfm_rx_auth_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len) 2224 { 2225 struct ieee80211com *ic = &sc->sc_ic; 2226 struct ifnet *ifp = &ic->ic_if; 2227 struct ieee80211_rxinfo rxi; 2228 struct ieee80211_frame *wh; 2229 struct mbuf *m; 2230 uint32_t pktlen, ieslen; 2231 2232 /* Build a fake beacon frame to let net80211 do all the parsing. */ 2233 ieslen = betoh32(e->msg.datalen); 2234 pktlen = sizeof(*wh) + ieslen + 6; 2235 if (pktlen > MCLBYTES) 2236 return; 2237 m = bwfm_newbuf(); 2238 if (m == NULL) 2239 return; 2240 wh = mtod(m, struct ieee80211_frame *); 2241 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 2242 IEEE80211_FC0_SUBTYPE_AUTH; 2243 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2244 *(uint16_t *)wh->i_dur = 0; 2245 IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr); 2246 IEEE80211_ADDR_COPY(wh->i_addr2, &e->msg.addr); 2247 IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid); 2248 *(uint16_t *)wh->i_seq = 0; 2249 ((uint16_t *)(&wh[1]))[0] = IEEE80211_AUTH_ALG_OPEN; 2250 ((uint16_t *)(&wh[1]))[1] = IEEE80211_AUTH_OPEN_REQUEST; 2251 ((uint16_t *)(&wh[1]))[2] = 0; 2252 2253 /* Finalize mbuf. */ 2254 m->m_pkthdr.len = m->m_len = pktlen; 2255 rxi.rxi_flags = 0; 2256 rxi.rxi_rssi = 0; 2257 rxi.rxi_tstamp = 0; 2258 ieee80211_input(ifp, m, ic->ic_bss, &rxi); 2259 } 2260 2261 void 2262 bwfm_rx_assoc_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len, 2263 int reassoc) 2264 { 2265 struct ieee80211com *ic = &sc->sc_ic; 2266 struct ifnet *ifp = &ic->ic_if; 2267 struct ieee80211_rxinfo rxi; 2268 struct ieee80211_frame *wh; 2269 struct ieee80211_node *ni; 2270 struct mbuf *m; 2271 uint32_t pktlen, ieslen; 2272 2273 /* Build a fake beacon frame to let net80211 do all the parsing. */ 2274 ieslen = betoh32(e->msg.datalen); 2275 pktlen = sizeof(*wh) + ieslen + 4; 2276 if (reassoc) 2277 pktlen += IEEE80211_ADDR_LEN; 2278 if (pktlen > MCLBYTES) 2279 return; 2280 m = bwfm_newbuf(); 2281 if (m == NULL) 2282 return; 2283 wh = mtod(m, struct ieee80211_frame *); 2284 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT; 2285 if (reassoc) 2286 wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_REASSOC_REQ; 2287 else 2288 wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_ASSOC_REQ; 2289 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2290 *(uint16_t *)wh->i_dur = 0; 2291 IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr); 2292 IEEE80211_ADDR_COPY(wh->i_addr2, &e->msg.addr); 2293 IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid); 2294 *(uint16_t *)wh->i_seq = 0; 2295 ((uint16_t *)(&wh[1]))[0] = IEEE80211_CAPINFO_ESS; /* XXX */ 2296 ((uint16_t *)(&wh[1]))[1] = 100; /* XXX */ 2297 if (reassoc) { 2298 memset(((uint8_t *)&wh[1]) + 4, 0, IEEE80211_ADDR_LEN); 2299 memcpy(((uint8_t *)&wh[1]) + 4 + IEEE80211_ADDR_LEN, 2300 &e[1], ieslen); 2301 } else 2302 memcpy(((uint8_t *)&wh[1]) + 4, &e[1], ieslen); 2303 2304 /* Finalize mbuf. */ 2305 m->m_pkthdr.len = m->m_len = pktlen; 2306 ni = ieee80211_find_node(ic, wh->i_addr2); 2307 if (ni == NULL) { 2308 m_freem(m); 2309 return; 2310 } 2311 rxi.rxi_flags = 0; 2312 rxi.rxi_rssi = 0; 2313 rxi.rxi_tstamp = 0; 2314 ieee80211_input(ifp, m, ni, &rxi); 2315 } 2316 2317 void 2318 bwfm_rx_deauth_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len) 2319 { 2320 bwfm_rx_leave_ind(sc, e, len, IEEE80211_FC0_SUBTYPE_DEAUTH); 2321 } 2322 2323 void 2324 bwfm_rx_disassoc_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len) 2325 { 2326 bwfm_rx_leave_ind(sc, e, len, IEEE80211_FC0_SUBTYPE_DISASSOC); 2327 } 2328 2329 void 2330 bwfm_rx_leave_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len, 2331 int subtype) 2332 { 2333 struct ieee80211com *ic = &sc->sc_ic; 2334 struct ifnet *ifp = &ic->ic_if; 2335 struct ieee80211_rxinfo rxi; 2336 struct ieee80211_frame *wh; 2337 struct ieee80211_node *ni; 2338 struct mbuf *m; 2339 uint32_t pktlen; 2340 2341 /* Build a fake beacon frame to let net80211 do all the parsing. */ 2342 pktlen = sizeof(*wh) + 2; 2343 if (pktlen > MCLBYTES) 2344 return; 2345 m = bwfm_newbuf(); 2346 if (m == NULL) 2347 return; 2348 wh = mtod(m, struct ieee80211_frame *); 2349 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 2350 subtype; 2351 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2352 *(uint16_t *)wh->i_dur = 0; 2353 IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr); 2354 IEEE80211_ADDR_COPY(wh->i_addr2, &e->msg.addr); 2355 IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid); 2356 *(uint16_t *)wh->i_seq = 0; 2357 memset((uint8_t *)&wh[1], 0, 2); 2358 2359 /* Finalize mbuf. */ 2360 m->m_pkthdr.len = m->m_len = pktlen; 2361 ni = ieee80211_find_node(ic, wh->i_addr2); 2362 if (ni == NULL) { 2363 m_freem(m); 2364 return; 2365 } 2366 rxi.rxi_flags = 0; 2367 rxi.rxi_rssi = 0; 2368 rxi.rxi_tstamp = 0; 2369 ieee80211_input(ifp, m, ni, &rxi); 2370 } 2371 #endif 2372 2373 void 2374 bwfm_rx_event(struct bwfm_softc *sc, struct mbuf *m) 2375 { 2376 int s; 2377 2378 s = splnet(); 2379 ml_enqueue(&sc->sc_evml, m); 2380 splx(s); 2381 2382 task_add(sc->sc_taskq, &sc->sc_task); 2383 } 2384 2385 void 2386 bwfm_rx_event_cb(struct bwfm_softc *sc, struct mbuf *m) 2387 { 2388 struct ieee80211com *ic = &sc->sc_ic; 2389 struct ifnet *ifp = &ic->ic_if; 2390 struct bwfm_event *e = mtod(m, void *); 2391 size_t len = m->m_len; 2392 2393 if (ntohl(e->msg.event_type) >= BWFM_E_LAST) { 2394 m_freem(m); 2395 return; 2396 } 2397 2398 switch (ntohl(e->msg.event_type)) { 2399 case BWFM_E_ESCAN_RESULT: { 2400 struct bwfm_escan_results *res; 2401 struct bwfm_bss_info *bss; 2402 size_t reslen; 2403 int i; 2404 /* Abort event triggered by SCAN -> INIT */ 2405 if (ic->ic_state == IEEE80211_S_INIT && 2406 ntohl(e->msg.status) == BWFM_E_STATUS_ABORT) 2407 break; 2408 if (ic->ic_state != IEEE80211_S_SCAN) { 2409 DPRINTF(("%s: scan result (%u) while not in SCAN\n", 2410 DEVNAME(sc), ntohl(e->msg.status))); 2411 break; 2412 } 2413 if (ntohl(e->msg.status) != BWFM_E_STATUS_SUCCESS && 2414 ntohl(e->msg.status) != BWFM_E_STATUS_PARTIAL) { 2415 DPRINTF(("%s: unexpected scan result (%u)\n", 2416 DEVNAME(sc), ntohl(e->msg.status))); 2417 break; 2418 } 2419 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS) { 2420 ieee80211_end_scan(ifp); 2421 break; 2422 } 2423 len -= sizeof(*e); 2424 if (len < sizeof(*res)) { 2425 DPRINTF(("%s: results too small\n", DEVNAME(sc))); 2426 m_freem(m); 2427 return; 2428 } 2429 reslen = len; 2430 res = malloc(len, M_TEMP, M_WAITOK); 2431 memcpy(res, (void *)&e[1], len); 2432 if (len < letoh32(res->buflen)) { 2433 DPRINTF(("%s: results too small\n", DEVNAME(sc))); 2434 free(res, M_TEMP, reslen); 2435 m_freem(m); 2436 return; 2437 } 2438 len -= sizeof(*res); 2439 if (len < letoh16(res->bss_count) * sizeof(struct bwfm_bss_info)) { 2440 DPRINTF(("%s: results too small\n", DEVNAME(sc))); 2441 free(res, M_TEMP, reslen); 2442 m_freem(m); 2443 return; 2444 } 2445 bss = &res->bss_info[0]; 2446 for (i = 0; i < letoh16(res->bss_count); i++) { 2447 bwfm_scan_node(sc, &res->bss_info[i], len); 2448 len -= sizeof(*bss) + letoh32(bss->length); 2449 bss = (void *)((char *)bss) + letoh32(bss->length); 2450 if (len <= 0) 2451 break; 2452 } 2453 free(res, M_TEMP, reslen); 2454 break; 2455 } 2456 case BWFM_E_AUTH: 2457 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS && 2458 ic->ic_state == IEEE80211_S_AUTH) 2459 ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1); 2460 else 2461 ieee80211_begin_scan(ifp); 2462 break; 2463 case BWFM_E_ASSOC: 2464 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS && 2465 ic->ic_state == IEEE80211_S_ASSOC) 2466 ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 2467 else 2468 ieee80211_begin_scan(ifp); 2469 break; 2470 case BWFM_E_DEAUTH: 2471 case BWFM_E_DISASSOC: 2472 if (ic->ic_state != IEEE80211_S_INIT) 2473 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 2474 break; 2475 case BWFM_E_LINK: 2476 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS && 2477 ntohl(e->msg.reason) == 0) 2478 break; 2479 /* Link status has changed */ 2480 if (ic->ic_state != IEEE80211_S_INIT) 2481 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 2482 break; 2483 #ifndef IEEE80211_STA_ONLY 2484 case BWFM_E_AUTH_IND: 2485 bwfm_rx_auth_ind(sc, e, len); 2486 break; 2487 case BWFM_E_ASSOC_IND: 2488 bwfm_rx_assoc_ind(sc, e, len, 0); 2489 break; 2490 case BWFM_E_REASSOC_IND: 2491 bwfm_rx_assoc_ind(sc, e, len, 1); 2492 break; 2493 case BWFM_E_DEAUTH_IND: 2494 bwfm_rx_deauth_ind(sc, e, len); 2495 break; 2496 case BWFM_E_DISASSOC_IND: 2497 bwfm_rx_disassoc_ind(sc, e, len); 2498 break; 2499 #endif 2500 default: 2501 DPRINTF(("%s: len %lu datalen %u code %u status %u" 2502 " reason %u\n", __func__, len, ntohl(e->msg.datalen), 2503 ntohl(e->msg.event_type), ntohl(e->msg.status), 2504 ntohl(e->msg.reason))); 2505 break; 2506 } 2507 2508 m_freem(m); 2509 } 2510 2511 void 2512 bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_info *bss, size_t len) 2513 { 2514 struct ieee80211com *ic = &sc->sc_ic; 2515 struct ifnet *ifp = &ic->ic_if; 2516 struct ieee80211_frame *wh; 2517 struct ieee80211_node *ni; 2518 struct ieee80211_rxinfo rxi; 2519 struct ieee80211_channel *bss_chan; 2520 uint8_t saved_bssid[IEEE80211_ADDR_LEN] = { 0 }; 2521 struct mbuf *m; 2522 uint32_t pktlen, ieslen; 2523 uint16_t iesoff; 2524 int chanidx; 2525 2526 iesoff = letoh16(bss->ie_offset); 2527 ieslen = letoh32(bss->ie_length); 2528 if (ieslen > len - iesoff) 2529 return; 2530 2531 /* Build a fake beacon frame to let net80211 do all the parsing. */ 2532 pktlen = sizeof(*wh) + ieslen + 12; 2533 if (pktlen > MCLBYTES) 2534 return; 2535 m = bwfm_newbuf(); 2536 if (m == NULL) 2537 return; 2538 wh = mtod(m, struct ieee80211_frame *); 2539 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 2540 IEEE80211_FC0_SUBTYPE_BEACON; 2541 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2542 *(uint16_t *)wh->i_dur = 0; 2543 IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr); 2544 IEEE80211_ADDR_COPY(wh->i_addr2, bss->bssid); 2545 IEEE80211_ADDR_COPY(wh->i_addr3, bss->bssid); 2546 *(uint16_t *)wh->i_seq = 0; 2547 memset(&wh[1], 0, 12); 2548 ((uint16_t *)(&wh[1]))[4] = bss->beacon_period; 2549 ((uint16_t *)(&wh[1]))[5] = bss->capability; 2550 memcpy(((uint8_t *)&wh[1]) + 12, ((uint8_t *)bss) + iesoff, ieslen); 2551 2552 /* Finalize mbuf. */ 2553 m->m_pkthdr.len = m->m_len = pktlen; 2554 ni = ieee80211_find_rxnode(ic, wh); 2555 if (ni == ic->ic_bss) { 2556 /* 2557 * We may switch ic_bss's channel during scans. 2558 * Record the current channel so we can restore it later. 2559 */ 2560 bss_chan = ni->ni_chan; 2561 IEEE80211_ADDR_COPY(&saved_bssid, ni->ni_macaddr); 2562 } 2563 /* Channel mask equals IEEE80211_CHAN_MAX */ 2564 chanidx = bwfm_spec2chan(sc, letoh32(bss->chanspec)); 2565 ni->ni_chan = &ic->ic_channels[chanidx]; 2566 /* Supply RSSI */ 2567 rxi.rxi_flags = 0; 2568 rxi.rxi_rssi = (int16_t)letoh16(bss->rssi); 2569 rxi.rxi_tstamp = 0; 2570 ieee80211_input(ifp, m, ni, &rxi); 2571 /* 2572 * ieee80211_input() might have changed our BSS. 2573 * Restore ic_bss's channel if we are still in the same BSS. 2574 */ 2575 if (ni == ic->ic_bss && IEEE80211_ADDR_EQ(saved_bssid, ni->ni_macaddr)) 2576 ni->ni_chan = bss_chan; 2577 /* Node is no longer needed. */ 2578 ieee80211_release_node(ic, ni); 2579 } 2580 2581 void 2582 bwfm_task(void *arg) 2583 { 2584 struct bwfm_softc *sc = arg; 2585 struct bwfm_host_cmd_ring *ring = &sc->sc_cmdq; 2586 struct bwfm_host_cmd *cmd; 2587 struct mbuf *m; 2588 int s; 2589 2590 s = splnet(); 2591 while (ring->next != ring->cur) { 2592 cmd = &ring->cmd[ring->next]; 2593 splx(s); 2594 cmd->cb(sc, cmd->data); 2595 s = splnet(); 2596 ring->queued--; 2597 ring->next = (ring->next + 1) % BWFM_HOST_CMD_RING_COUNT; 2598 } 2599 splx(s); 2600 2601 s = splnet(); 2602 while ((m = ml_dequeue(&sc->sc_evml)) != NULL) { 2603 splx(s); 2604 bwfm_rx_event_cb(sc, m); 2605 s = splnet(); 2606 } 2607 splx(s); 2608 } 2609 2610 void 2611 bwfm_do_async(struct bwfm_softc *sc, 2612 void (*cb)(struct bwfm_softc *, void *), void *arg, int len) 2613 { 2614 struct bwfm_host_cmd_ring *ring = &sc->sc_cmdq; 2615 struct bwfm_host_cmd *cmd; 2616 int s; 2617 2618 s = splnet(); 2619 KASSERT(ring->queued < BWFM_HOST_CMD_RING_COUNT); 2620 if (ring->queued >= BWFM_HOST_CMD_RING_COUNT) { 2621 splx(s); 2622 return; 2623 } 2624 cmd = &ring->cmd[ring->cur]; 2625 cmd->cb = cb; 2626 KASSERT(len <= sizeof(cmd->data)); 2627 memcpy(cmd->data, arg, len); 2628 ring->cur = (ring->cur + 1) % BWFM_HOST_CMD_RING_COUNT; 2629 ring->queued++; 2630 task_add(sc->sc_taskq, &sc->sc_task); 2631 splx(s); 2632 } 2633 2634 int 2635 bwfm_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, 2636 int type, int arg1, int arg2) 2637 { 2638 #ifdef BWFM_DEBUG 2639 struct bwfm_softc *sc = ic->ic_softc; 2640 DPRINTF(("%s: %s\n", DEVNAME(sc), __func__)); 2641 #endif 2642 return 0; 2643 } 2644 2645 int 2646 bwfm_set_key(struct ieee80211com *ic, struct ieee80211_node *ni, 2647 struct ieee80211_key *k) 2648 { 2649 struct bwfm_softc *sc = ic->ic_softc; 2650 struct bwfm_cmd_key cmd; 2651 2652 cmd.ni = ni; 2653 cmd.k = k; 2654 bwfm_do_async(sc, bwfm_set_key_cb, &cmd, sizeof(cmd)); 2655 sc->sc_key_tasks++; 2656 return EBUSY; 2657 } 2658 2659 void 2660 bwfm_set_key_cb(struct bwfm_softc *sc, void *arg) 2661 { 2662 struct bwfm_cmd_key *cmd = arg; 2663 struct ieee80211_key *k = cmd->k; 2664 struct ieee80211_node *ni = cmd->ni; 2665 struct ieee80211com *ic = &sc->sc_ic; 2666 struct bwfm_wsec_key key; 2667 uint32_t wsec, wsec_enable; 2668 int ext_key = 0; 2669 2670 sc->sc_key_tasks--; 2671 2672 if ((k->k_flags & IEEE80211_KEY_GROUP) == 0 && 2673 k->k_cipher != IEEE80211_CIPHER_WEP40 && 2674 k->k_cipher != IEEE80211_CIPHER_WEP104) 2675 ext_key = 1; 2676 2677 memset(&key, 0, sizeof(key)); 2678 if (ext_key && !IEEE80211_IS_MULTICAST(ni->ni_macaddr)) 2679 memcpy(key.ea, ni->ni_macaddr, sizeof(key.ea)); 2680 key.index = htole32(k->k_id); 2681 key.len = htole32(k->k_len); 2682 memcpy(key.data, k->k_key, sizeof(key.data)); 2683 if (!ext_key) 2684 key.flags = htole32(BWFM_WSEC_PRIMARY_KEY); 2685 2686 switch (k->k_cipher) { 2687 case IEEE80211_CIPHER_WEP40: 2688 key.algo = htole32(BWFM_CRYPTO_ALGO_WEP1); 2689 wsec_enable = BWFM_WSEC_WEP; 2690 break; 2691 case IEEE80211_CIPHER_WEP104: 2692 key.algo = htole32(BWFM_CRYPTO_ALGO_WEP128); 2693 wsec_enable = BWFM_WSEC_WEP; 2694 break; 2695 case IEEE80211_CIPHER_TKIP: 2696 key.algo = htole32(BWFM_CRYPTO_ALGO_TKIP); 2697 wsec_enable = BWFM_WSEC_TKIP; 2698 break; 2699 case IEEE80211_CIPHER_CCMP: 2700 key.algo = htole32(BWFM_CRYPTO_ALGO_AES_CCM); 2701 wsec_enable = BWFM_WSEC_AES; 2702 break; 2703 default: 2704 printf("%s: cipher %x not supported\n", DEVNAME(sc), 2705 k->k_cipher); 2706 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 2707 return; 2708 } 2709 2710 delay(100); 2711 2712 bwfm_fwvar_var_set_data(sc, "wsec_key", &key, sizeof(key)); 2713 bwfm_fwvar_var_get_int(sc, "wsec", &wsec); 2714 wsec |= wsec_enable; 2715 bwfm_fwvar_var_set_int(sc, "wsec", wsec); 2716 2717 if (sc->sc_key_tasks == 0) { 2718 DPRINTF(("%s: marking port %s valid\n", DEVNAME(sc), 2719 ether_sprintf(cmd->ni->ni_macaddr))); 2720 cmd->ni->ni_port_valid = 1; 2721 ieee80211_set_link_state(ic, LINK_STATE_UP); 2722 } 2723 } 2724 2725 void 2726 bwfm_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni, 2727 struct ieee80211_key *k) 2728 { 2729 struct bwfm_softc *sc = ic->ic_softc; 2730 struct bwfm_cmd_key cmd; 2731 2732 cmd.ni = ni; 2733 cmd.k = k; 2734 bwfm_do_async(sc, bwfm_delete_key_cb, &cmd, sizeof(cmd)); 2735 } 2736 2737 void 2738 bwfm_delete_key_cb(struct bwfm_softc *sc, void *arg) 2739 { 2740 struct bwfm_cmd_key *cmd = arg; 2741 struct ieee80211_key *k = cmd->k; 2742 struct bwfm_wsec_key key; 2743 2744 memset(&key, 0, sizeof(key)); 2745 key.index = htole32(k->k_id); 2746 key.flags = htole32(BWFM_WSEC_PRIMARY_KEY); 2747 bwfm_fwvar_var_set_data(sc, "wsec_key", &key, sizeof(key)); 2748 } 2749 2750 int 2751 bwfm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 2752 { 2753 struct bwfm_softc *sc = ic->ic_softc; 2754 struct ifnet *ifp = &ic->ic_if; 2755 int s; 2756 2757 s = splnet(); 2758 2759 switch (nstate) { 2760 case IEEE80211_S_INIT: 2761 if (ic->ic_state == IEEE80211_S_SCAN) 2762 bwfm_scan_abort(sc); 2763 break; 2764 case IEEE80211_S_SCAN: 2765 #ifndef IEEE80211_STA_ONLY 2766 /* Don't start a scan if we already have a channel. */ 2767 if (ic->ic_state == IEEE80211_S_INIT && 2768 ic->ic_opmode == IEEE80211_M_HOSTAP && 2769 ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 2770 break; 2771 } 2772 #endif 2773 /* If we tried to connect, abort. */ 2774 if (ic->ic_state > IEEE80211_S_SCAN) 2775 bwfm_fwvar_cmd_set_data(sc, BWFM_C_DISASSOC, NULL, 0); 2776 /* Initiate scan. */ 2777 bwfm_scan(sc); 2778 if (ifp->if_flags & IFF_DEBUG) 2779 printf("%s: %s -> %s\n", DEVNAME(sc), 2780 ieee80211_state_name[ic->ic_state], 2781 ieee80211_state_name[nstate]); 2782 /* No need to do this again. */ 2783 if (ic->ic_state == IEEE80211_S_SCAN) { 2784 splx(s); 2785 return 0; 2786 } 2787 ieee80211_set_link_state(ic, LINK_STATE_DOWN); 2788 ieee80211_node_cleanup(ic, ic->ic_bss); 2789 ic->ic_state = nstate; 2790 splx(s); 2791 return 0; 2792 case IEEE80211_S_AUTH: 2793 ic->ic_bss->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE; 2794 bwfm_connect(sc); 2795 if (ifp->if_flags & IFF_DEBUG) 2796 printf("%s: %s -> %s\n", DEVNAME(sc), 2797 ieee80211_state_name[ic->ic_state], 2798 ieee80211_state_name[nstate]); 2799 ic->ic_state = nstate; 2800 if (ic->ic_flags & IEEE80211_F_RSNON) 2801 ic->ic_bss->ni_rsn_supp_state = RSNA_SUPP_PTKSTART; 2802 splx(s); 2803 return 0; 2804 #ifndef IEEE80211_STA_ONLY 2805 case IEEE80211_S_RUN: 2806 if (ic->ic_opmode == IEEE80211_M_HOSTAP) 2807 bwfm_hostap(sc); 2808 break; 2809 #endif 2810 default: 2811 break; 2812 } 2813 sc->sc_newstate(ic, nstate, arg); 2814 splx(s); 2815 return 0; 2816 } 2817 2818 int 2819 bwfm_nvram_convert(u_char *buf, size_t len, size_t *newlenp) 2820 { 2821 u_char *src, *dst, *end = buf + len; 2822 size_t count = 0, pad; 2823 uint32_t token; 2824 int skip = 0; 2825 2826 for (src = buf, dst = buf; src != end; ++src) { 2827 if (*src == '\n') { 2828 if (count > 0) 2829 *dst++ = '\0'; 2830 count = 0; 2831 skip = 0; 2832 continue; 2833 } 2834 if (skip) 2835 continue; 2836 if (*src == '#' && count == 0) { 2837 skip = 1; 2838 continue; 2839 } 2840 if (*src == '\r') 2841 continue; 2842 *dst++ = *src; 2843 ++count; 2844 } 2845 2846 count = dst - buf; 2847 pad = roundup(count + 1, 4) - count; 2848 2849 if (count + pad + sizeof(token) > len) 2850 return 1; 2851 2852 memset(dst, 0, pad); 2853 count += pad; 2854 dst += pad; 2855 2856 token = (count / 4) & 0xffff; 2857 token |= ~token << 16; 2858 token = htole32(token); 2859 2860 memcpy(dst, &token, sizeof(token)); 2861 count += sizeof(token); 2862 2863 *newlenp = count; 2864 return 0; 2865 } 2866 2867 void 2868 bwfm_process_clm_blob(struct bwfm_softc *sc) 2869 { 2870 struct bwfm_dload_data *data; 2871 size_t off, remain, len; 2872 2873 if (sc->sc_clm == NULL || sc->sc_clmsize == 0) 2874 return; 2875 2876 off = 0; 2877 remain = sc->sc_clmsize; 2878 data = malloc(sizeof(*data) + BWFM_DLOAD_MAX_LEN, M_TEMP, M_WAITOK); 2879 2880 while (remain) { 2881 len = min(remain, BWFM_DLOAD_MAX_LEN); 2882 2883 data->flag = htole16(BWFM_DLOAD_FLAG_HANDLER_VER_1); 2884 if (off == 0) 2885 data->flag |= htole16(BWFM_DLOAD_FLAG_BEGIN); 2886 if (remain < BWFM_DLOAD_MAX_LEN) 2887 data->flag |= htole16(BWFM_DLOAD_FLAG_END); 2888 data->type = htole16(BWFM_DLOAD_TYPE_CLM); 2889 data->len = htole32(len); 2890 data->crc = 0; 2891 memcpy(data->data, sc->sc_clm + off, len); 2892 2893 if (bwfm_fwvar_var_set_data(sc, "clmload", data, 2894 sizeof(*data) + len)) { 2895 printf("%s: could not load CLM blob\n", DEVNAME(sc)); 2896 goto out; 2897 } 2898 2899 off += len; 2900 remain -= len; 2901 } 2902 2903 out: 2904 free(data, M_TEMP, sizeof(*data) + BWFM_DLOAD_MAX_LEN); 2905 free(sc->sc_clm, M_DEVBUF, sc->sc_clmsize); 2906 sc->sc_clm = NULL; 2907 sc->sc_clmsize = 0; 2908 } 2909 2910 #if defined(__HAVE_FDT) 2911 const char * 2912 bwfm_sysname(void) 2913 { 2914 static char sysfw[128]; 2915 int len; 2916 char *p; 2917 2918 len = OF_getprop(OF_peer(0), "compatible", sysfw, sizeof(sysfw)); 2919 if (len > 0 && len < sizeof(sysfw)) { 2920 sysfw[len] = '\0'; 2921 if ((p = strchr(sysfw, '/')) != NULL) 2922 *p = '\0'; 2923 return sysfw; 2924 } 2925 return NULL; 2926 } 2927 #else 2928 const char * 2929 bwfm_sysname(void) 2930 { 2931 return NULL; 2932 } 2933 #endif 2934 2935 int 2936 bwfm_loadfirmware(struct bwfm_softc *sc, const char *chip, const char *bus, 2937 u_char **ucode, size_t *size, u_char **nvram, size_t *nvsize, size_t *nvlen) 2938 { 2939 const char *sysname = NULL; 2940 char name[128]; 2941 int r; 2942 2943 *ucode = *nvram = NULL; 2944 *size = *nvsize = *nvlen = 0; 2945 2946 sysname = bwfm_sysname(); 2947 2948 if (sysname != NULL) { 2949 r = snprintf(name, sizeof(name), "brcmfmac%s%s.%s.bin", chip, 2950 bus, sysname); 2951 if ((r > 0 && r < sizeof(name)) && 2952 loadfirmware(name, ucode, size) != 0) 2953 *size = 0; 2954 } 2955 if (*size == 0) { 2956 snprintf(name, sizeof(name), "brcmfmac%s%s.bin", chip, bus); 2957 if (loadfirmware(name, ucode, size) != 0) { 2958 snprintf(name, sizeof(name), "brcmfmac%s%s%s%s.bin", chip, bus, 2959 sysname ? "." : "", sysname ? sysname : ""); 2960 printf("%s: failed loadfirmware of file %s\n", 2961 DEVNAME(sc), name); 2962 return 1; 2963 } 2964 } 2965 2966 /* .txt needs to be processed first */ 2967 if (sysname != NULL) { 2968 r = snprintf(name, sizeof(name), "brcmfmac%s%s.%s.txt", chip, 2969 bus, sysname); 2970 if ((r > 0 && r < sizeof(name)) && 2971 loadfirmware(name, nvram, nvsize) == 0) { 2972 if (bwfm_nvram_convert(*nvram, *nvsize, nvlen) != 0) { 2973 printf("%s: failed to process file %s\n", 2974 DEVNAME(sc), name); 2975 free(*ucode, M_DEVBUF, *size); 2976 free(*nvram, M_DEVBUF, *nvsize); 2977 return 1; 2978 } 2979 } 2980 } 2981 2982 if (*nvlen == 0) { 2983 snprintf(name, sizeof(name), "brcmfmac%s%s.txt", chip, bus); 2984 if (loadfirmware(name, nvram, nvsize) == 0) { 2985 if (bwfm_nvram_convert(*nvram, *nvsize, nvlen) != 0) { 2986 printf("%s: failed to process file %s\n", 2987 DEVNAME(sc), name); 2988 free(*ucode, M_DEVBUF, *size); 2989 free(*nvram, M_DEVBUF, *nvsize); 2990 return 1; 2991 } 2992 } 2993 } 2994 2995 /* .nvram is the pre-processed version */ 2996 if (*nvlen == 0) { 2997 snprintf(name, sizeof(name), "brcmfmac%s%s.nvram", chip, bus); 2998 if (loadfirmware(name, nvram, nvsize) == 0) 2999 *nvlen = *nvsize; 3000 } 3001 3002 if (*nvlen == 0 && strcmp(bus, "-sdio") == 0) { 3003 snprintf(name, sizeof(name), "brcmfmac%s%s%s%s.txt", chip, bus, 3004 sysname ? "." : "", sysname ? sysname : ""); 3005 printf("%s: failed loadfirmware of file %s\n", 3006 DEVNAME(sc), name); 3007 free(*ucode, M_DEVBUF, *size); 3008 return 1; 3009 } 3010 3011 if (sysname != NULL) { 3012 r = snprintf(name, sizeof(name), "brcmfmac%s%s.%s.clm_blob", 3013 chip, bus, sysname); 3014 if (r > 0 && r < sizeof(name)) 3015 loadfirmware(name, &sc->sc_clm, &sc->sc_clmsize); 3016 } 3017 if (sc->sc_clmsize == 0) { 3018 snprintf(name, sizeof(name), "brcmfmac%s%s.clm_blob", chip, bus); 3019 loadfirmware(name, &sc->sc_clm, &sc->sc_clmsize); 3020 } 3021 3022 return 0; 3023 } 3024