1*c9aa06c9Spatrick /* $OpenBSD: bwfm.c,v 1.36 2018/02/06 02:23:04 patrick Exp $ */ 232b2494eSpatrick /* 332b2494eSpatrick * Copyright (c) 2010-2016 Broadcom Corporation 432b2494eSpatrick * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se> 532b2494eSpatrick * 632b2494eSpatrick * Permission to use, copy, modify, and/or distribute this software for any 732b2494eSpatrick * purpose with or without fee is hereby granted, provided that the above 832b2494eSpatrick * copyright notice and this permission notice appear in all copies. 932b2494eSpatrick * 1032b2494eSpatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1132b2494eSpatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1232b2494eSpatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1332b2494eSpatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1432b2494eSpatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1532b2494eSpatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1632b2494eSpatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1732b2494eSpatrick */ 1832b2494eSpatrick 1932b2494eSpatrick #include "bpfilter.h" 2032b2494eSpatrick 2132b2494eSpatrick #include <sys/param.h> 2232b2494eSpatrick #include <sys/systm.h> 2332b2494eSpatrick #include <sys/buf.h> 2432b2494eSpatrick #include <sys/kernel.h> 2532b2494eSpatrick #include <sys/malloc.h> 2632b2494eSpatrick #include <sys/device.h> 2732b2494eSpatrick #include <sys/queue.h> 2832b2494eSpatrick #include <sys/socket.h> 2932b2494eSpatrick #include <sys/sockio.h> 3032b2494eSpatrick 3132b2494eSpatrick #if NBPFILTER > 0 3232b2494eSpatrick #include <net/bpf.h> 3332b2494eSpatrick #endif 3432b2494eSpatrick #include <net/if.h> 3532b2494eSpatrick #include <net/if_dl.h> 3632b2494eSpatrick #include <net/if_media.h> 3732b2494eSpatrick 3832b2494eSpatrick #include <netinet/in.h> 3932b2494eSpatrick #include <netinet/if_ether.h> 4032b2494eSpatrick 4132b2494eSpatrick #include <net80211/ieee80211_var.h> 4232b2494eSpatrick 4332b2494eSpatrick #include <dev/ic/bwfmvar.h> 4432b2494eSpatrick #include <dev/ic/bwfmreg.h> 4532b2494eSpatrick 4632b2494eSpatrick /* #define BWFM_DEBUG */ 4732b2494eSpatrick #ifdef BWFM_DEBUG 4832b2494eSpatrick #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0) 4932b2494eSpatrick #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0) 5032b2494eSpatrick static int bwfm_debug = 1; 5132b2494eSpatrick #else 5232b2494eSpatrick #define DPRINTF(x) do { ; } while (0) 5332b2494eSpatrick #define DPRINTFN(n, x) do { ; } while (0) 5432b2494eSpatrick #endif 5532b2494eSpatrick 5632b2494eSpatrick #define DEVNAME(sc) ((sc)->sc_dev.dv_xname) 5732b2494eSpatrick 5832b2494eSpatrick void bwfm_start(struct ifnet *); 5932b2494eSpatrick void bwfm_init(struct ifnet *); 6032b2494eSpatrick void bwfm_stop(struct ifnet *); 6132b2494eSpatrick void bwfm_watchdog(struct ifnet *); 6232b2494eSpatrick int bwfm_ioctl(struct ifnet *, u_long, caddr_t); 6332b2494eSpatrick int bwfm_media_change(struct ifnet *); 6432b2494eSpatrick 6532b2494eSpatrick int bwfm_chip_attach(struct bwfm_softc *); 6632b2494eSpatrick int bwfm_chip_detach(struct bwfm_softc *, int); 6732b2494eSpatrick struct bwfm_core *bwfm_chip_get_core(struct bwfm_softc *, int); 6832b2494eSpatrick struct bwfm_core *bwfm_chip_get_pmu(struct bwfm_softc *); 6932b2494eSpatrick int bwfm_chip_ai_isup(struct bwfm_softc *, struct bwfm_core *); 7032b2494eSpatrick void bwfm_chip_ai_disable(struct bwfm_softc *, struct bwfm_core *, 7132b2494eSpatrick uint32_t, uint32_t); 7232b2494eSpatrick void bwfm_chip_ai_reset(struct bwfm_softc *, struct bwfm_core *, 7332b2494eSpatrick uint32_t, uint32_t, uint32_t); 7432b2494eSpatrick void bwfm_chip_dmp_erom_scan(struct bwfm_softc *); 7532b2494eSpatrick int bwfm_chip_dmp_get_regaddr(struct bwfm_softc *, uint32_t *, 7632b2494eSpatrick uint32_t *, uint32_t *); 77e2612299Spatrick int bwfm_chip_cr4_set_active(struct bwfm_softc *, uint32_t); 7832b2494eSpatrick void bwfm_chip_cr4_set_passive(struct bwfm_softc *); 79e2612299Spatrick int bwfm_chip_ca7_set_active(struct bwfm_softc *, uint32_t); 8032b2494eSpatrick void bwfm_chip_ca7_set_passive(struct bwfm_softc *); 81e2612299Spatrick int bwfm_chip_cm3_set_active(struct bwfm_softc *); 8232b2494eSpatrick void bwfm_chip_cm3_set_passive(struct bwfm_softc *); 8385d32364Spatrick void bwfm_chip_socram_ramsize(struct bwfm_softc *, struct bwfm_core *); 8485d32364Spatrick void bwfm_chip_sysmem_ramsize(struct bwfm_softc *, struct bwfm_core *); 8585d32364Spatrick void bwfm_chip_tcm_ramsize(struct bwfm_softc *, struct bwfm_core *); 8685d32364Spatrick void bwfm_chip_tcm_rambase(struct bwfm_softc *); 8732b2494eSpatrick 8832b2494eSpatrick int bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *, int, 8932b2494eSpatrick int, char *, size_t *); 9032b2494eSpatrick int bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *, int, 9132b2494eSpatrick int, char *, size_t); 9232b2494eSpatrick 9332b2494eSpatrick int bwfm_fwvar_cmd_get_data(struct bwfm_softc *, int, void *, size_t); 9432b2494eSpatrick int bwfm_fwvar_cmd_set_data(struct bwfm_softc *, int, void *, size_t); 9532b2494eSpatrick int bwfm_fwvar_cmd_get_int(struct bwfm_softc *, int, uint32_t *); 9632b2494eSpatrick int bwfm_fwvar_cmd_set_int(struct bwfm_softc *, int, uint32_t); 9732b2494eSpatrick int bwfm_fwvar_var_get_data(struct bwfm_softc *, char *, void *, size_t); 9832b2494eSpatrick int bwfm_fwvar_var_set_data(struct bwfm_softc *, char *, void *, size_t); 9932b2494eSpatrick int bwfm_fwvar_var_get_int(struct bwfm_softc *, char *, uint32_t *); 10032b2494eSpatrick int bwfm_fwvar_var_set_int(struct bwfm_softc *, char *, uint32_t); 10132b2494eSpatrick 1028b2458cfSpatrick uint32_t bwfm_spec2chan(struct bwfm_softc *, uint32_t); 1038b2458cfSpatrick uint32_t bwfm_spec2chan_d11n(struct bwfm_softc *, uint32_t); 1048b2458cfSpatrick uint32_t bwfm_spec2chan_d11ac(struct bwfm_softc *, uint32_t); 1058b2458cfSpatrick 10663498aa8Spatrick void bwfm_connect(struct bwfm_softc *); 107c11618f6Spatrick #ifndef IEEE80211_STA_ONLY 108c11618f6Spatrick void bwfm_hostap(struct bwfm_softc *); 109c11618f6Spatrick #endif 11032b2494eSpatrick void bwfm_scan(struct bwfm_softc *); 11163498aa8Spatrick 11263498aa8Spatrick void bwfm_task(void *); 11363498aa8Spatrick void bwfm_do_async(struct bwfm_softc *, 11463498aa8Spatrick void (*)(struct bwfm_softc *, void *), void *, int); 11563498aa8Spatrick 11663498aa8Spatrick int bwfm_set_key(struct ieee80211com *, struct ieee80211_node *, 11763498aa8Spatrick struct ieee80211_key *); 11863498aa8Spatrick void bwfm_delete_key(struct ieee80211com *, struct ieee80211_node *, 11963498aa8Spatrick struct ieee80211_key *); 12063498aa8Spatrick int bwfm_send_mgmt(struct ieee80211com *, struct ieee80211_node *, 12163498aa8Spatrick int, int, int); 12263498aa8Spatrick int bwfm_newstate(struct ieee80211com *, enum ieee80211_state, int); 12363498aa8Spatrick 12463498aa8Spatrick void bwfm_set_key_cb(struct bwfm_softc *, void *); 12563498aa8Spatrick void bwfm_delete_key_cb(struct bwfm_softc *, void *); 126f4e8af02Spatrick void bwfm_rx_event_cb(struct bwfm_softc *, void *); 12732b2494eSpatrick 128c11618f6Spatrick struct mbuf *bwfm_newbuf(void); 129f37fc236Spatrick void bwfm_rx(struct bwfm_softc *, struct mbuf *); 130c11618f6Spatrick #ifndef IEEE80211_STA_ONLY 131c11618f6Spatrick void bwfm_rx_auth_ind(struct bwfm_softc *, struct bwfm_event *, size_t); 132c11618f6Spatrick void bwfm_rx_assoc_ind(struct bwfm_softc *, struct bwfm_event *, size_t, int); 133c11618f6Spatrick void bwfm_rx_deauth_ind(struct bwfm_softc *, struct bwfm_event *, size_t); 134c11618f6Spatrick void bwfm_rx_disassoc_ind(struct bwfm_softc *, struct bwfm_event *, size_t); 135c11618f6Spatrick void bwfm_rx_leave_ind(struct bwfm_softc *, struct bwfm_event *, size_t, int); 136c11618f6Spatrick #endif 137f4e8af02Spatrick void bwfm_rx_event(struct bwfm_softc *, struct mbuf *); 13832b2494eSpatrick void bwfm_scan_node(struct bwfm_softc *, struct bwfm_bss_info *, size_t); 13932b2494eSpatrick 14032b2494eSpatrick extern void ieee80211_node2req(struct ieee80211com *, 14132b2494eSpatrick const struct ieee80211_node *, struct ieee80211_nodereq *); 14232b2494eSpatrick extern void ieee80211_req2node(struct ieee80211com *, 14332b2494eSpatrick const struct ieee80211_nodereq *, struct ieee80211_node *); 14432b2494eSpatrick 14532b2494eSpatrick uint8_t bwfm_2ghz_channels[] = { 14632b2494eSpatrick 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14732b2494eSpatrick }; 14832b2494eSpatrick uint8_t bwfm_5ghz_channels[] = { 14932b2494eSpatrick 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, 100, 104, 108, 112, 15032b2494eSpatrick 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, 15132b2494eSpatrick }; 15232b2494eSpatrick 15332b2494eSpatrick struct bwfm_proto_ops bwfm_proto_bcdc_ops = { 15432b2494eSpatrick .proto_query_dcmd = bwfm_proto_bcdc_query_dcmd, 15532b2494eSpatrick .proto_set_dcmd = bwfm_proto_bcdc_set_dcmd, 15632b2494eSpatrick }; 15732b2494eSpatrick 15832b2494eSpatrick struct cfdriver bwfm_cd = { 15932b2494eSpatrick NULL, "bwfm", DV_IFNET 16032b2494eSpatrick }; 16132b2494eSpatrick 16232b2494eSpatrick void 16332b2494eSpatrick bwfm_attach(struct bwfm_softc *sc) 16432b2494eSpatrick { 16532b2494eSpatrick struct ieee80211com *ic = &sc->sc_ic; 16632b2494eSpatrick struct ifnet *ifp = &ic->ic_if; 1679c7e455cSpatrick uint32_t bandlist[3], tmp; 16833e6a401Spatrick int i, j, nbands, nmode, vhtmode; 16932b2494eSpatrick 17032b2494eSpatrick if (bwfm_fwvar_cmd_get_int(sc, BWFM_C_GET_VERSION, &tmp)) { 17132b2494eSpatrick printf("%s: could not read io type\n", DEVNAME(sc)); 17232b2494eSpatrick return; 17332b2494eSpatrick } else 17432b2494eSpatrick sc->sc_io_type = tmp; 17532b2494eSpatrick if (bwfm_fwvar_var_get_data(sc, "cur_etheraddr", ic->ic_myaddr, 17632b2494eSpatrick sizeof(ic->ic_myaddr))) { 17732b2494eSpatrick printf("%s: could not read mac address\n", DEVNAME(sc)); 17832b2494eSpatrick return; 17932b2494eSpatrick } 18032b2494eSpatrick printf("%s: address %s\n", DEVNAME(sc), ether_sprintf(ic->ic_myaddr)); 18132b2494eSpatrick 18263498aa8Spatrick /* Init host async commands ring. */ 18363498aa8Spatrick sc->sc_cmdq.cur = sc->sc_cmdq.next = sc->sc_cmdq.queued = 0; 18463498aa8Spatrick sc->sc_taskq = taskq_create(DEVNAME(sc), 1, IPL_SOFTNET, 0); 18563498aa8Spatrick task_set(&sc->sc_task, bwfm_task, sc); 18632b2494eSpatrick 18763498aa8Spatrick ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 18863498aa8Spatrick ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 18963498aa8Spatrick ic->ic_state = IEEE80211_S_INIT; 19063498aa8Spatrick 19163498aa8Spatrick ic->ic_caps = 192c11618f6Spatrick #ifndef IEEE80211_STA_ONLY 193c11618f6Spatrick IEEE80211_C_HOSTAP | /* Access Point */ 194c11618f6Spatrick #endif 19563498aa8Spatrick IEEE80211_C_RSN | /* WPA/RSN */ 19663498aa8Spatrick IEEE80211_C_SCANALL | /* device scans all channels at once */ 19763498aa8Spatrick IEEE80211_C_SCANALLBAND; /* device scans all bands at once */ 19827fa8129Spatrick 1999c7e455cSpatrick if (bwfm_fwvar_var_get_int(sc, "nmode", &nmode)) 2009c7e455cSpatrick nmode = 0; 2019c7e455cSpatrick if (bwfm_fwvar_var_get_int(sc, "vhtmode", &vhtmode)) 2029c7e455cSpatrick vhtmode = 0; 2039c7e455cSpatrick if (bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_BANDLIST, bandlist, 2049c7e455cSpatrick sizeof(bandlist))) { 2059c7e455cSpatrick printf("%s: couldn't get supported band list\n", DEVNAME(sc)); 2069c7e455cSpatrick return; 2079c7e455cSpatrick } 2089c7e455cSpatrick nbands = letoh32(bandlist[0]); 2099c7e455cSpatrick for (i = 1; i <= nbands && i < nitems(bandlist); i++) { 2109c7e455cSpatrick switch (letoh32(bandlist[i])) { 2119c7e455cSpatrick case BWFM_BAND_2G: 2129c7e455cSpatrick DPRINTF(("%s: 2G HT %d VHT %d\n", 2139c7e455cSpatrick DEVNAME(sc), nmode, vhtmode)); 2149c7e455cSpatrick ic->ic_sup_rates[IEEE80211_MODE_11B] = 2159c7e455cSpatrick ieee80211_std_rateset_11b; 2169c7e455cSpatrick ic->ic_sup_rates[IEEE80211_MODE_11G] = 2179c7e455cSpatrick ieee80211_std_rateset_11g; 21832b2494eSpatrick 21933e6a401Spatrick for (j = 0; j < nitems(bwfm_2ghz_channels); j++) { 22033e6a401Spatrick uint8_t chan = bwfm_2ghz_channels[j]; 22132b2494eSpatrick ic->ic_channels[chan].ic_freq = 22232b2494eSpatrick ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ); 22332b2494eSpatrick ic->ic_channels[chan].ic_flags = 22432b2494eSpatrick IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | 22532b2494eSpatrick IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; 2269c7e455cSpatrick if (nmode) 2279c7e455cSpatrick ic->ic_channels[chan].ic_flags |= 2289c7e455cSpatrick IEEE80211_CHAN_HT; 22932b2494eSpatrick } 2309c7e455cSpatrick break; 2319c7e455cSpatrick case BWFM_BAND_5G: 2329c7e455cSpatrick DPRINTF(("%s: 5G HT %d VHT %d\n", 2339c7e455cSpatrick DEVNAME(sc), nmode, vhtmode)); 2349c7e455cSpatrick ic->ic_sup_rates[IEEE80211_MODE_11A] = 2359c7e455cSpatrick ieee80211_std_rateset_11a; 2369c7e455cSpatrick 23733e6a401Spatrick for (j = 0; j < nitems(bwfm_5ghz_channels); j++) { 23833e6a401Spatrick uint8_t chan = bwfm_5ghz_channels[j]; 23932b2494eSpatrick ic->ic_channels[chan].ic_freq = 24032b2494eSpatrick ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ); 24132b2494eSpatrick ic->ic_channels[chan].ic_flags = 24232b2494eSpatrick IEEE80211_CHAN_A; 2439c7e455cSpatrick if (nmode) 2449c7e455cSpatrick ic->ic_channels[chan].ic_flags |= 2459c7e455cSpatrick IEEE80211_CHAN_HT; 24632b2494eSpatrick } 2479c7e455cSpatrick break; 2489c7e455cSpatrick default: 2499c7e455cSpatrick printf("%s: unsupported band 0x%x\n", DEVNAME(sc), 2509c7e455cSpatrick letoh32(bandlist[i])); 2519c7e455cSpatrick break; 2529c7e455cSpatrick } 2539c7e455cSpatrick } 2549c7e455cSpatrick 2559c7e455cSpatrick /* IBSS channel undefined for now. */ 2569c7e455cSpatrick ic->ic_ibss_chan = &ic->ic_channels[0]; 25732b2494eSpatrick 25832b2494eSpatrick ifp->if_softc = sc; 25932b2494eSpatrick ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 26032b2494eSpatrick ifp->if_ioctl = bwfm_ioctl; 26132b2494eSpatrick ifp->if_start = bwfm_start; 26232b2494eSpatrick ifp->if_watchdog = bwfm_watchdog; 26332b2494eSpatrick memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); 26432b2494eSpatrick 26532b2494eSpatrick if_attach(ifp); 26663498aa8Spatrick ieee80211_ifattach(ifp); 26763498aa8Spatrick 26863498aa8Spatrick sc->sc_newstate = ic->ic_newstate; 26963498aa8Spatrick ic->ic_newstate = bwfm_newstate; 27063498aa8Spatrick ic->ic_send_mgmt = bwfm_send_mgmt; 27163498aa8Spatrick ic->ic_set_key = bwfm_set_key; 27263498aa8Spatrick ic->ic_delete_key = bwfm_delete_key; 27363498aa8Spatrick 27463498aa8Spatrick ieee80211_media_init(ifp, bwfm_media_change, ieee80211_media_status); 27532b2494eSpatrick } 27632b2494eSpatrick 27732b2494eSpatrick int 27832b2494eSpatrick bwfm_detach(struct bwfm_softc *sc, int flags) 27932b2494eSpatrick { 28032b2494eSpatrick struct ieee80211com *ic = &sc->sc_ic; 28132b2494eSpatrick struct ifnet *ifp = &ic->ic_if; 28263498aa8Spatrick task_del(sc->sc_taskq, &sc->sc_task); 28363498aa8Spatrick taskq_destroy(sc->sc_taskq); 28463498aa8Spatrick ieee80211_ifdetach(ifp); 28532b2494eSpatrick if_detach(ifp); 28632b2494eSpatrick return 0; 28732b2494eSpatrick } 28832b2494eSpatrick 28932b2494eSpatrick void 29032b2494eSpatrick bwfm_start(struct ifnet *ifp) 29132b2494eSpatrick { 29232b2494eSpatrick struct bwfm_softc *sc = ifp->if_softc; 29332b2494eSpatrick struct mbuf *m; 29432b2494eSpatrick int error; 29532b2494eSpatrick 29632b2494eSpatrick if (!(ifp->if_flags & IFF_RUNNING)) 29732b2494eSpatrick return; 29832b2494eSpatrick if (ifq_is_oactive(&ifp->if_snd)) 29932b2494eSpatrick return; 30032b2494eSpatrick if (IFQ_IS_EMPTY(&ifp->if_snd)) 30132b2494eSpatrick return; 30232b2494eSpatrick 30332b2494eSpatrick /* TODO: return if no link? */ 30432b2494eSpatrick 30532b2494eSpatrick m = ifq_deq_begin(&ifp->if_snd); 30632b2494eSpatrick while (m != NULL) { 30732b2494eSpatrick error = sc->sc_bus_ops->bs_txdata(sc, m); 30832b2494eSpatrick if (error == ENOBUFS) { 30932b2494eSpatrick ifq_deq_rollback(&ifp->if_snd, m); 31032b2494eSpatrick ifq_set_oactive(&ifp->if_snd); 31132b2494eSpatrick break; 31232b2494eSpatrick } 31332b2494eSpatrick if (error == EFBIG) { 31432b2494eSpatrick ifq_deq_commit(&ifp->if_snd, m); 31532b2494eSpatrick m_freem(m); /* give up: drop it */ 31632b2494eSpatrick ifp->if_oerrors++; 31732b2494eSpatrick continue; 31832b2494eSpatrick } 31932b2494eSpatrick 32032b2494eSpatrick /* Now we are committed to transmit the packet. */ 32132b2494eSpatrick ifq_deq_commit(&ifp->if_snd, m); 32232b2494eSpatrick 32332b2494eSpatrick #if NBPFILTER > 0 32432b2494eSpatrick if (ifp->if_bpf) 32532b2494eSpatrick bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 32632b2494eSpatrick #endif 32732b2494eSpatrick 32832b2494eSpatrick m = ifq_deq_begin(&ifp->if_snd); 32932b2494eSpatrick } 33032b2494eSpatrick } 33132b2494eSpatrick 33232b2494eSpatrick void 33332b2494eSpatrick bwfm_init(struct ifnet *ifp) 33432b2494eSpatrick { 33532b2494eSpatrick struct bwfm_softc *sc = ifp->if_softc; 336c11618f6Spatrick struct ieee80211com *ic = &sc->sc_ic; 33732b2494eSpatrick uint8_t evmask[BWFM_EVENT_MASK_LEN]; 3381179aa9cSpatrick struct bwfm_join_pref_params join_pref[2]; 339c11618f6Spatrick int pm; 34032b2494eSpatrick 341a2c6ff8bSpatrick if (sc->sc_bus_ops->bs_init) 342a2c6ff8bSpatrick sc->sc_bus_ops->bs_init(sc); 343a2c6ff8bSpatrick 34432b2494eSpatrick if (bwfm_fwvar_var_set_int(sc, "mpc", 1)) { 34532b2494eSpatrick printf("%s: could not set mpc\n", DEVNAME(sc)); 34632b2494eSpatrick return; 34732b2494eSpatrick } 34832b2494eSpatrick 3491179aa9cSpatrick /* Select target by RSSI (boost on 5GHz) */ 3501179aa9cSpatrick join_pref[0].type = BWFM_JOIN_PREF_RSSI_DELTA; 3511179aa9cSpatrick join_pref[0].len = 2; 3521179aa9cSpatrick join_pref[0].rssi_gain = BWFM_JOIN_PREF_RSSI_BOOST; 3531179aa9cSpatrick join_pref[0].band = BWFM_JOIN_PREF_BAND_5G; 3541179aa9cSpatrick join_pref[1].type = BWFM_JOIN_PREF_RSSI; 3551179aa9cSpatrick join_pref[1].len = 2; 3561179aa9cSpatrick join_pref[1].rssi_gain = 0; 3571179aa9cSpatrick join_pref[1].band = 0; 3581179aa9cSpatrick if (bwfm_fwvar_var_set_data(sc, "join_pref", join_pref, 3591179aa9cSpatrick sizeof(join_pref))) { 3601179aa9cSpatrick printf("%s: could not set join pref\n", DEVNAME(sc)); 3611179aa9cSpatrick return; 3621179aa9cSpatrick } 36332b2494eSpatrick 364c11618f6Spatrick #define BWFM_EVENT(event) evmask[(event) / 8] |= 1 << ((event) % 8) 365c11618f6Spatrick memset(evmask, 0, sizeof(evmask)); 366c11618f6Spatrick switch (ic->ic_opmode) { 367c11618f6Spatrick case IEEE80211_M_STA: 368c11618f6Spatrick BWFM_EVENT(BWFM_E_IF); 369c11618f6Spatrick BWFM_EVENT(BWFM_E_LINK); 370c11618f6Spatrick BWFM_EVENT(BWFM_E_AUTH); 371c11618f6Spatrick BWFM_EVENT(BWFM_E_ASSOC); 372c11618f6Spatrick BWFM_EVENT(BWFM_E_DEAUTH); 373c11618f6Spatrick BWFM_EVENT(BWFM_E_DISASSOC); 374c11618f6Spatrick BWFM_EVENT(BWFM_E_SET_SSID); 375c11618f6Spatrick BWFM_EVENT(BWFM_E_ESCAN_RESULT); 376c11618f6Spatrick break; 377c11618f6Spatrick #ifndef IEEE80211_STA_ONLY 378c11618f6Spatrick case IEEE80211_M_HOSTAP: 379c11618f6Spatrick BWFM_EVENT(BWFM_E_AUTH_IND); 380c11618f6Spatrick BWFM_EVENT(BWFM_E_ASSOC_IND); 381c11618f6Spatrick BWFM_EVENT(BWFM_E_REASSOC_IND); 382c11618f6Spatrick BWFM_EVENT(BWFM_E_DEAUTH_IND); 383c11618f6Spatrick BWFM_EVENT(BWFM_E_DISASSOC_IND); 384c11618f6Spatrick BWFM_EVENT(BWFM_E_SET_SSID); 385c11618f6Spatrick BWFM_EVENT(BWFM_E_ESCAN_RESULT); 386c11618f6Spatrick break; 387c11618f6Spatrick #endif 388c11618f6Spatrick default: 389c11618f6Spatrick break; 39032b2494eSpatrick } 391c11618f6Spatrick #undef BWFM_EVENT 392c11618f6Spatrick 39332b2494eSpatrick if (bwfm_fwvar_var_set_data(sc, "event_msgs", evmask, sizeof(evmask))) { 39432b2494eSpatrick printf("%s: could not set event mask\n", DEVNAME(sc)); 39532b2494eSpatrick return; 39632b2494eSpatrick } 39732b2494eSpatrick 39832b2494eSpatrick if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_CHANNEL_TIME, 39932b2494eSpatrick BWFM_DEFAULT_SCAN_CHANNEL_TIME)) { 40032b2494eSpatrick printf("%s: could not set scan channel time\n", DEVNAME(sc)); 40132b2494eSpatrick return; 40232b2494eSpatrick } 40332b2494eSpatrick if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_UNASSOC_TIME, 40432b2494eSpatrick BWFM_DEFAULT_SCAN_UNASSOC_TIME)) { 40532b2494eSpatrick printf("%s: could not set scan unassoc time\n", DEVNAME(sc)); 40632b2494eSpatrick return; 40732b2494eSpatrick } 40832b2494eSpatrick if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_PASSIVE_TIME, 40932b2494eSpatrick BWFM_DEFAULT_SCAN_PASSIVE_TIME)) { 41032b2494eSpatrick printf("%s: could not set scan passive time\n", DEVNAME(sc)); 41132b2494eSpatrick return; 41232b2494eSpatrick } 41332b2494eSpatrick 414c11618f6Spatrick /* 415c11618f6Spatrick * Use CAM (constantly awake) when we are running as AP, 416c11618f6Spatrick * otherwise use fast power saving. 417c11618f6Spatrick */ 418c11618f6Spatrick pm = BWFM_PM_FAST_PS; 419c11618f6Spatrick #ifndef IEEE80211_STA_ONLY 420c11618f6Spatrick if (ic->ic_opmode == IEEE80211_M_HOSTAP) 421c11618f6Spatrick pm = BWFM_PM_CAM; 422c11618f6Spatrick #endif 423c11618f6Spatrick if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, pm)) { 42432b2494eSpatrick printf("%s: could not set power\n", DEVNAME(sc)); 42532b2494eSpatrick return; 42632b2494eSpatrick } 42732b2494eSpatrick 42832b2494eSpatrick bwfm_fwvar_var_set_int(sc, "txbf", 1); 42932b2494eSpatrick bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 0); 43032b2494eSpatrick bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 1); 43132b2494eSpatrick bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0); 43232b2494eSpatrick 43332b2494eSpatrick /* Disable all offloading (ARP, NDP, TCP/UDP cksum). */ 43432b2494eSpatrick bwfm_fwvar_var_set_int(sc, "arp_ol", 0); 43532b2494eSpatrick bwfm_fwvar_var_set_int(sc, "arpoe", 0); 43632b2494eSpatrick bwfm_fwvar_var_set_int(sc, "ndoe", 0); 43732b2494eSpatrick bwfm_fwvar_var_set_int(sc, "toe", 0); 43832b2494eSpatrick 439d346a16fSpatrick /* 44063498aa8Spatrick * The firmware supplicant can handle the WPA handshake for 44163498aa8Spatrick * us, but we honestly want to do this ourselves, so disable 44263498aa8Spatrick * the firmware supplicant and let our stack handle it. 443d346a16fSpatrick */ 44463498aa8Spatrick bwfm_fwvar_var_set_int(sc, "sup_wpa", 0); 44532b2494eSpatrick 4469f68d685Spatrick #if 0 4479f68d685Spatrick /* TODO: set these on proper ioctl */ 44832b2494eSpatrick bwfm_fwvar_var_set_int(sc, "allmulti", 1); 44932b2494eSpatrick bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PROMISC, 1); 4509f68d685Spatrick #endif 45132b2494eSpatrick 45232b2494eSpatrick ifp->if_flags |= IFF_RUNNING; 45332b2494eSpatrick ifq_clr_oactive(&ifp->if_snd); 45463498aa8Spatrick 45563498aa8Spatrick ieee80211_begin_scan(ifp); 45632b2494eSpatrick } 45732b2494eSpatrick 45832b2494eSpatrick void 45932b2494eSpatrick bwfm_stop(struct ifnet *ifp) 46032b2494eSpatrick { 46132b2494eSpatrick struct bwfm_softc *sc = ifp->if_softc; 46232b2494eSpatrick struct ieee80211com *ic = &sc->sc_ic; 46332b2494eSpatrick 46432b2494eSpatrick sc->sc_tx_timer = 0; 46532b2494eSpatrick ifp->if_timer = 0; 46632b2494eSpatrick ifp->if_flags &= ~IFF_RUNNING; 46732b2494eSpatrick ifq_clr_oactive(&ifp->if_snd); 46832b2494eSpatrick 46932b2494eSpatrick /* In case we were scanning, release the scan "lock". */ 47032b2494eSpatrick ic->ic_scan_lock = IEEE80211_SCAN_UNLOCKED; 47132b2494eSpatrick 47263498aa8Spatrick ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 47363498aa8Spatrick 47432b2494eSpatrick bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1); 475c11618f6Spatrick bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, BWFM_PM_CAM); 476a2c6ff8bSpatrick 477a2c6ff8bSpatrick if (sc->sc_bus_ops->bs_stop) 478a2c6ff8bSpatrick sc->sc_bus_ops->bs_stop(sc); 47932b2494eSpatrick } 48032b2494eSpatrick 48132b2494eSpatrick void 48232b2494eSpatrick bwfm_watchdog(struct ifnet *ifp) 48332b2494eSpatrick { 48432b2494eSpatrick struct bwfm_softc *sc = ifp->if_softc; 48532b2494eSpatrick 48632b2494eSpatrick ifp->if_timer = 0; 48732b2494eSpatrick 48832b2494eSpatrick if (sc->sc_tx_timer > 0) { 48932b2494eSpatrick if (--sc->sc_tx_timer == 0) { 49032b2494eSpatrick printf("%s: device timeout\n", DEVNAME(sc)); 49132b2494eSpatrick ifp->if_oerrors++; 49232b2494eSpatrick return; 49332b2494eSpatrick } 49432b2494eSpatrick ifp->if_timer = 1; 49532b2494eSpatrick } 49632b2494eSpatrick ieee80211_watchdog(ifp); 49732b2494eSpatrick } 49832b2494eSpatrick 49932b2494eSpatrick int 50032b2494eSpatrick bwfm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 50132b2494eSpatrick { 50263498aa8Spatrick int s, error = 0; 50332b2494eSpatrick 50432b2494eSpatrick s = splnet(); 50532b2494eSpatrick switch (cmd) { 50632b2494eSpatrick case SIOCSIFADDR: 50732b2494eSpatrick ifp->if_flags |= IFF_UP; 50863498aa8Spatrick /* FALLTHROUGH */ 50932b2494eSpatrick case SIOCSIFFLAGS: 51032b2494eSpatrick if (ifp->if_flags & IFF_UP) { 51132b2494eSpatrick if (!(ifp->if_flags & IFF_RUNNING)) 51232b2494eSpatrick bwfm_init(ifp); 51332b2494eSpatrick } else { 51432b2494eSpatrick if (ifp->if_flags & IFF_RUNNING) 51532b2494eSpatrick bwfm_stop(ifp); 51632b2494eSpatrick } 51732b2494eSpatrick break; 51832b2494eSpatrick default: 51963498aa8Spatrick error = ieee80211_ioctl(ifp, cmd, data); 52032b2494eSpatrick } 52132b2494eSpatrick if (error == ENETRESET) { 52232b2494eSpatrick if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == 52332b2494eSpatrick (IFF_UP | IFF_RUNNING)) { 52432b2494eSpatrick bwfm_stop(ifp); 52532b2494eSpatrick bwfm_init(ifp); 52632b2494eSpatrick } 52732b2494eSpatrick error = 0; 52832b2494eSpatrick } 52932b2494eSpatrick splx(s); 53032b2494eSpatrick return error; 53132b2494eSpatrick } 53232b2494eSpatrick 53332b2494eSpatrick int 53432b2494eSpatrick bwfm_media_change(struct ifnet *ifp) 53532b2494eSpatrick { 53663498aa8Spatrick int error; 53732b2494eSpatrick 53863498aa8Spatrick error = ieee80211_media_change(ifp); 53963498aa8Spatrick if (error != ENETRESET) 54063498aa8Spatrick return error; 54163498aa8Spatrick 54263498aa8Spatrick if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == 54363498aa8Spatrick (IFF_UP | IFF_RUNNING)) { 54463498aa8Spatrick bwfm_stop(ifp); 54563498aa8Spatrick bwfm_init(ifp); 54663498aa8Spatrick } 54763498aa8Spatrick return 0; 54832b2494eSpatrick } 54932b2494eSpatrick 55032b2494eSpatrick /* Chip initialization (SDIO, PCIe) */ 55132b2494eSpatrick int 55232b2494eSpatrick bwfm_chip_attach(struct bwfm_softc *sc) 55332b2494eSpatrick { 55432b2494eSpatrick struct bwfm_core *core; 55532b2494eSpatrick int need_socram = 0; 55632b2494eSpatrick int has_socram = 0; 55732b2494eSpatrick int cpu_found = 0; 55832b2494eSpatrick uint32_t val; 55932b2494eSpatrick 56032b2494eSpatrick LIST_INIT(&sc->sc_chip.ch_list); 56132b2494eSpatrick 56232b2494eSpatrick if (sc->sc_buscore_ops->bc_prepare(sc) != 0) { 56332b2494eSpatrick printf("%s: failed buscore prepare\n", DEVNAME(sc)); 56432b2494eSpatrick return 1; 56532b2494eSpatrick } 56632b2494eSpatrick 56732b2494eSpatrick val = sc->sc_buscore_ops->bc_read(sc, 56832b2494eSpatrick BWFM_CHIP_BASE + BWFM_CHIP_REG_CHIPID); 56932b2494eSpatrick sc->sc_chip.ch_chip = BWFM_CHIP_CHIPID_ID(val); 57032b2494eSpatrick sc->sc_chip.ch_chiprev = BWFM_CHIP_CHIPID_REV(val); 57132b2494eSpatrick 57232b2494eSpatrick if ((sc->sc_chip.ch_chip > 0xa000) || (sc->sc_chip.ch_chip < 0x4000)) 57332b2494eSpatrick snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name), 57432b2494eSpatrick "%d", sc->sc_chip.ch_chip); 57532b2494eSpatrick else 57632b2494eSpatrick snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name), 57732b2494eSpatrick "%x", sc->sc_chip.ch_chip); 57832b2494eSpatrick 57932b2494eSpatrick switch (BWFM_CHIP_CHIPID_TYPE(val)) 58032b2494eSpatrick { 58132b2494eSpatrick case BWFM_CHIP_CHIPID_TYPE_SOCI_SB: 58232b2494eSpatrick printf("%s: SoC interconnect SB not implemented\n", 58332b2494eSpatrick DEVNAME(sc)); 58432b2494eSpatrick return 1; 58532b2494eSpatrick case BWFM_CHIP_CHIPID_TYPE_SOCI_AI: 58632b2494eSpatrick sc->sc_chip.ch_core_isup = bwfm_chip_ai_isup; 58732b2494eSpatrick sc->sc_chip.ch_core_disable = bwfm_chip_ai_disable; 58832b2494eSpatrick sc->sc_chip.ch_core_reset = bwfm_chip_ai_reset; 58932b2494eSpatrick bwfm_chip_dmp_erom_scan(sc); 59032b2494eSpatrick break; 59132b2494eSpatrick default: 59232b2494eSpatrick printf("%s: SoC interconnect %d unknown\n", 59332b2494eSpatrick DEVNAME(sc), BWFM_CHIP_CHIPID_TYPE(val)); 59432b2494eSpatrick return 1; 59532b2494eSpatrick } 59632b2494eSpatrick 59732b2494eSpatrick LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) { 59832b2494eSpatrick DPRINTF(("%s: 0x%x:%-2d base 0x%08x wrap 0x%08x\n", 59932b2494eSpatrick DEVNAME(sc), core->co_id, core->co_rev, 60032b2494eSpatrick core->co_base, core->co_wrapbase)); 60132b2494eSpatrick 60232b2494eSpatrick switch (core->co_id) { 60332b2494eSpatrick case BWFM_AGENT_CORE_ARM_CM3: 604de919281Spatrick need_socram = 1; 60532b2494eSpatrick /* FALLTHROUGH */ 60632b2494eSpatrick case BWFM_AGENT_CORE_ARM_CR4: 60732b2494eSpatrick case BWFM_AGENT_CORE_ARM_CA7: 608de919281Spatrick cpu_found = 1; 60932b2494eSpatrick break; 61032b2494eSpatrick case BWFM_AGENT_INTERNAL_MEM: 611de919281Spatrick has_socram = 1; 61232b2494eSpatrick break; 61332b2494eSpatrick default: 61432b2494eSpatrick break; 61532b2494eSpatrick } 61632b2494eSpatrick } 61732b2494eSpatrick 61832b2494eSpatrick if (!cpu_found) { 61932b2494eSpatrick printf("%s: CPU core not detected\n", DEVNAME(sc)); 62032b2494eSpatrick return 1; 62132b2494eSpatrick } 62232b2494eSpatrick if (need_socram && !has_socram) { 62332b2494eSpatrick printf("%s: RAM core not provided\n", DEVNAME(sc)); 62432b2494eSpatrick return 1; 62532b2494eSpatrick } 62632b2494eSpatrick 627e2612299Spatrick bwfm_chip_set_passive(sc); 62832b2494eSpatrick 62932b2494eSpatrick if (sc->sc_buscore_ops->bc_reset) { 63032b2494eSpatrick sc->sc_buscore_ops->bc_reset(sc); 631e2612299Spatrick bwfm_chip_set_passive(sc); 63232b2494eSpatrick } 63332b2494eSpatrick 63485d32364Spatrick if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4)) != NULL) { 63585d32364Spatrick bwfm_chip_tcm_ramsize(sc, core); 63685d32364Spatrick bwfm_chip_tcm_rambase(sc); 63785d32364Spatrick } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_SYS_MEM)) != NULL) { 63885d32364Spatrick bwfm_chip_sysmem_ramsize(sc, core); 63985d32364Spatrick bwfm_chip_tcm_rambase(sc); 64085d32364Spatrick } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM)) != NULL) { 64185d32364Spatrick bwfm_chip_socram_ramsize(sc, core); 64285d32364Spatrick } 64332b2494eSpatrick 64432b2494eSpatrick core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); 64532b2494eSpatrick sc->sc_chip.ch_cc_caps = sc->sc_buscore_ops->bc_read(sc, 64632b2494eSpatrick core->co_base + BWFM_CHIP_REG_CAPABILITIES); 64732b2494eSpatrick sc->sc_chip.ch_cc_caps_ext = sc->sc_buscore_ops->bc_read(sc, 64832b2494eSpatrick core->co_base + BWFM_CHIP_REG_CAPABILITIES_EXT); 64932b2494eSpatrick 65032b2494eSpatrick core = bwfm_chip_get_pmu(sc); 65132b2494eSpatrick if (sc->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU) { 65232b2494eSpatrick sc->sc_chip.ch_pmucaps = sc->sc_buscore_ops->bc_read(sc, 65332b2494eSpatrick core->co_base + BWFM_CHIP_REG_PMUCAPABILITIES); 65432b2494eSpatrick sc->sc_chip.ch_pmurev = sc->sc_chip.ch_pmucaps & 65532b2494eSpatrick BWFM_CHIP_REG_PMUCAPABILITIES_REV_MASK; 65632b2494eSpatrick } 65732b2494eSpatrick 65832b2494eSpatrick if (sc->sc_buscore_ops->bc_setup) 65932b2494eSpatrick sc->sc_buscore_ops->bc_setup(sc); 66032b2494eSpatrick 66132b2494eSpatrick return 0; 66232b2494eSpatrick } 66332b2494eSpatrick 66432b2494eSpatrick struct bwfm_core * 66532b2494eSpatrick bwfm_chip_get_core(struct bwfm_softc *sc, int id) 66632b2494eSpatrick { 66732b2494eSpatrick struct bwfm_core *core; 66832b2494eSpatrick 66932b2494eSpatrick LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) { 67032b2494eSpatrick if (core->co_id == id) 67132b2494eSpatrick return core; 67232b2494eSpatrick } 67332b2494eSpatrick 67432b2494eSpatrick return NULL; 67532b2494eSpatrick } 67632b2494eSpatrick 67732b2494eSpatrick struct bwfm_core * 67832b2494eSpatrick bwfm_chip_get_pmu(struct bwfm_softc *sc) 67932b2494eSpatrick { 68032b2494eSpatrick struct bwfm_core *cc, *pmu; 68132b2494eSpatrick 68232b2494eSpatrick cc = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON); 68332b2494eSpatrick if (cc->co_rev >= 35 && sc->sc_chip.ch_cc_caps_ext & 68432b2494eSpatrick BWFM_CHIP_REG_CAPABILITIES_EXT_AOB_PRESENT) { 68532b2494eSpatrick pmu = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_PMU); 68632b2494eSpatrick if (pmu) 68732b2494eSpatrick return pmu; 68832b2494eSpatrick } 68932b2494eSpatrick 69032b2494eSpatrick return cc; 69132b2494eSpatrick } 69232b2494eSpatrick 69332b2494eSpatrick /* Functions for the AI interconnect */ 69432b2494eSpatrick int 69532b2494eSpatrick bwfm_chip_ai_isup(struct bwfm_softc *sc, struct bwfm_core *core) 69632b2494eSpatrick { 69732b2494eSpatrick uint32_t ioctl, reset; 69832b2494eSpatrick 69932b2494eSpatrick ioctl = sc->sc_buscore_ops->bc_read(sc, 70032b2494eSpatrick core->co_wrapbase + BWFM_AGENT_IOCTL); 70132b2494eSpatrick reset = sc->sc_buscore_ops->bc_read(sc, 70232b2494eSpatrick core->co_wrapbase + BWFM_AGENT_RESET_CTL); 70332b2494eSpatrick 70432b2494eSpatrick if (((ioctl & (BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK)) == 70532b2494eSpatrick BWFM_AGENT_IOCTL_CLK) && 70632b2494eSpatrick ((reset & BWFM_AGENT_RESET_CTL_RESET) == 0)) 70732b2494eSpatrick return 1; 70832b2494eSpatrick 70932b2494eSpatrick return 0; 71032b2494eSpatrick } 71132b2494eSpatrick 71232b2494eSpatrick void 71332b2494eSpatrick bwfm_chip_ai_disable(struct bwfm_softc *sc, struct bwfm_core *core, 71432b2494eSpatrick uint32_t prereset, uint32_t reset) 71532b2494eSpatrick { 71632b2494eSpatrick uint32_t val; 71732b2494eSpatrick int i; 71832b2494eSpatrick 71932b2494eSpatrick val = sc->sc_buscore_ops->bc_read(sc, 72032b2494eSpatrick core->co_wrapbase + BWFM_AGENT_RESET_CTL); 72132b2494eSpatrick if ((val & BWFM_AGENT_RESET_CTL_RESET) == 0) { 72232b2494eSpatrick 72332b2494eSpatrick sc->sc_buscore_ops->bc_write(sc, 72432b2494eSpatrick core->co_wrapbase + BWFM_AGENT_IOCTL, 72532b2494eSpatrick prereset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK); 72632b2494eSpatrick sc->sc_buscore_ops->bc_read(sc, 72732b2494eSpatrick core->co_wrapbase + BWFM_AGENT_IOCTL); 72832b2494eSpatrick 72932b2494eSpatrick sc->sc_buscore_ops->bc_write(sc, 73032b2494eSpatrick core->co_wrapbase + BWFM_AGENT_RESET_CTL, 73132b2494eSpatrick BWFM_AGENT_RESET_CTL_RESET); 73232b2494eSpatrick delay(20); 73332b2494eSpatrick 73432b2494eSpatrick for (i = 300; i > 0; i--) { 73532b2494eSpatrick if (sc->sc_buscore_ops->bc_read(sc, 73632b2494eSpatrick core->co_wrapbase + BWFM_AGENT_RESET_CTL) == 73732b2494eSpatrick BWFM_AGENT_RESET_CTL_RESET) 73832b2494eSpatrick break; 73932b2494eSpatrick } 74032b2494eSpatrick if (i == 0) 74132b2494eSpatrick printf("%s: timeout on core reset\n", DEVNAME(sc)); 74232b2494eSpatrick } 74332b2494eSpatrick 74432b2494eSpatrick sc->sc_buscore_ops->bc_write(sc, 74532b2494eSpatrick core->co_wrapbase + BWFM_AGENT_IOCTL, 74632b2494eSpatrick reset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK); 74732b2494eSpatrick sc->sc_buscore_ops->bc_read(sc, 74832b2494eSpatrick core->co_wrapbase + BWFM_AGENT_IOCTL); 74932b2494eSpatrick } 75032b2494eSpatrick 75132b2494eSpatrick void 75232b2494eSpatrick bwfm_chip_ai_reset(struct bwfm_softc *sc, struct bwfm_core *core, 75332b2494eSpatrick uint32_t prereset, uint32_t reset, uint32_t postreset) 75432b2494eSpatrick { 75532b2494eSpatrick int i; 75632b2494eSpatrick 75732b2494eSpatrick bwfm_chip_ai_disable(sc, core, prereset, reset); 75832b2494eSpatrick 75932b2494eSpatrick for (i = 50; i > 0; i--) { 76032b2494eSpatrick if ((sc->sc_buscore_ops->bc_read(sc, 76132b2494eSpatrick core->co_wrapbase + BWFM_AGENT_RESET_CTL) & 76232b2494eSpatrick BWFM_AGENT_RESET_CTL_RESET) == 0) 76332b2494eSpatrick break; 76432b2494eSpatrick sc->sc_buscore_ops->bc_write(sc, 76532b2494eSpatrick core->co_wrapbase + BWFM_AGENT_RESET_CTL, 0); 76632b2494eSpatrick delay(60); 76732b2494eSpatrick } 76832b2494eSpatrick if (i == 0) 76932b2494eSpatrick printf("%s: timeout on core reset\n", DEVNAME(sc)); 77032b2494eSpatrick 77132b2494eSpatrick sc->sc_buscore_ops->bc_write(sc, 77232b2494eSpatrick core->co_wrapbase + BWFM_AGENT_IOCTL, 77332b2494eSpatrick postreset | BWFM_AGENT_IOCTL_CLK); 77432b2494eSpatrick sc->sc_buscore_ops->bc_read(sc, 77532b2494eSpatrick core->co_wrapbase + BWFM_AGENT_IOCTL); 77632b2494eSpatrick } 77732b2494eSpatrick 77832b2494eSpatrick void 77932b2494eSpatrick bwfm_chip_dmp_erom_scan(struct bwfm_softc *sc) 78032b2494eSpatrick { 78132b2494eSpatrick uint32_t erom, val, base, wrap; 78232b2494eSpatrick uint8_t type = 0; 78332b2494eSpatrick uint16_t id; 78432b2494eSpatrick uint8_t nmw, nsw, rev; 78532b2494eSpatrick struct bwfm_core *core; 78632b2494eSpatrick 78732b2494eSpatrick erom = sc->sc_buscore_ops->bc_read(sc, 78832b2494eSpatrick BWFM_CHIP_BASE + BWFM_CHIP_REG_EROMPTR); 78932b2494eSpatrick while (type != BWFM_DMP_DESC_EOT) { 79032b2494eSpatrick val = sc->sc_buscore_ops->bc_read(sc, erom); 79132b2494eSpatrick type = val & BWFM_DMP_DESC_MASK; 79232b2494eSpatrick erom += 4; 79332b2494eSpatrick 79432b2494eSpatrick if (type != BWFM_DMP_DESC_COMPONENT) 79532b2494eSpatrick continue; 79632b2494eSpatrick 79732b2494eSpatrick id = (val & BWFM_DMP_COMP_PARTNUM) 79832b2494eSpatrick >> BWFM_DMP_COMP_PARTNUM_S; 79932b2494eSpatrick 80032b2494eSpatrick val = sc->sc_buscore_ops->bc_read(sc, erom); 80132b2494eSpatrick type = val & BWFM_DMP_DESC_MASK; 80232b2494eSpatrick erom += 4; 80332b2494eSpatrick 80432b2494eSpatrick if (type != BWFM_DMP_DESC_COMPONENT) { 80532b2494eSpatrick printf("%s: not component descriptor\n", DEVNAME(sc)); 80632b2494eSpatrick return; 80732b2494eSpatrick } 80832b2494eSpatrick 80932b2494eSpatrick nmw = (val & BWFM_DMP_COMP_NUM_MWRAP) 81032b2494eSpatrick >> BWFM_DMP_COMP_NUM_MWRAP_S; 81132b2494eSpatrick nsw = (val & BWFM_DMP_COMP_NUM_SWRAP) 81232b2494eSpatrick >> BWFM_DMP_COMP_NUM_SWRAP_S; 81332b2494eSpatrick rev = (val & BWFM_DMP_COMP_REVISION) 81432b2494eSpatrick >> BWFM_DMP_COMP_REVISION_S; 81532b2494eSpatrick 81632b2494eSpatrick if (nmw + nsw == 0 && id != BWFM_AGENT_CORE_PMU) 81732b2494eSpatrick continue; 81832b2494eSpatrick 81932b2494eSpatrick if (bwfm_chip_dmp_get_regaddr(sc, &erom, &base, &wrap)) 82032b2494eSpatrick continue; 82132b2494eSpatrick 82232b2494eSpatrick core = malloc(sizeof(*core), M_DEVBUF, M_WAITOK); 82332b2494eSpatrick core->co_id = id; 82432b2494eSpatrick core->co_base = base; 82532b2494eSpatrick core->co_wrapbase = wrap; 82632b2494eSpatrick core->co_rev = rev; 82732b2494eSpatrick LIST_INSERT_HEAD(&sc->sc_chip.ch_list, core, co_link); 82832b2494eSpatrick } 82932b2494eSpatrick } 83032b2494eSpatrick 83132b2494eSpatrick int 83232b2494eSpatrick bwfm_chip_dmp_get_regaddr(struct bwfm_softc *sc, uint32_t *erom, 83332b2494eSpatrick uint32_t *base, uint32_t *wrap) 83432b2494eSpatrick { 83532b2494eSpatrick uint8_t type = 0, mpnum = 0; 83632b2494eSpatrick uint8_t stype, sztype, wraptype; 83732b2494eSpatrick uint32_t val; 83832b2494eSpatrick 83932b2494eSpatrick *base = 0; 84032b2494eSpatrick *wrap = 0; 84132b2494eSpatrick 84232b2494eSpatrick val = sc->sc_buscore_ops->bc_read(sc, *erom); 84332b2494eSpatrick type = val & BWFM_DMP_DESC_MASK; 84432b2494eSpatrick if (type == BWFM_DMP_DESC_MASTER_PORT) { 84532b2494eSpatrick mpnum = (val & BWFM_DMP_MASTER_PORT_NUM) 84632b2494eSpatrick >> BWFM_DMP_MASTER_PORT_NUM_S; 84732b2494eSpatrick wraptype = BWFM_DMP_SLAVE_TYPE_MWRAP; 84832b2494eSpatrick *erom += 4; 84932b2494eSpatrick } else if ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) == 85032b2494eSpatrick BWFM_DMP_DESC_ADDRESS) 85132b2494eSpatrick wraptype = BWFM_DMP_SLAVE_TYPE_SWRAP; 85232b2494eSpatrick else 85332b2494eSpatrick return 1; 85432b2494eSpatrick 85532b2494eSpatrick do { 85632b2494eSpatrick do { 85732b2494eSpatrick val = sc->sc_buscore_ops->bc_read(sc, *erom); 85832b2494eSpatrick type = val & BWFM_DMP_DESC_MASK; 85932b2494eSpatrick if (type == BWFM_DMP_DESC_COMPONENT) 86032b2494eSpatrick return 0; 86132b2494eSpatrick if (type == BWFM_DMP_DESC_EOT) 86232b2494eSpatrick return 1; 86332b2494eSpatrick *erom += 4; 86432b2494eSpatrick } while ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) != 86532b2494eSpatrick BWFM_DMP_DESC_ADDRESS); 86632b2494eSpatrick 86732b2494eSpatrick if (type & BWFM_DMP_DESC_ADDRSIZE_GT32) 86832b2494eSpatrick *erom += 4; 86932b2494eSpatrick 87032b2494eSpatrick sztype = (val & BWFM_DMP_SLAVE_SIZE_TYPE) 87132b2494eSpatrick >> BWFM_DMP_SLAVE_SIZE_TYPE_S; 87232b2494eSpatrick if (sztype == BWFM_DMP_SLAVE_SIZE_DESC) { 87332b2494eSpatrick val = sc->sc_buscore_ops->bc_read(sc, *erom); 87432b2494eSpatrick type = val & BWFM_DMP_DESC_MASK; 87532b2494eSpatrick if (type & BWFM_DMP_DESC_ADDRSIZE_GT32) 87632b2494eSpatrick *erom += 8; 87732b2494eSpatrick else 87832b2494eSpatrick *erom += 4; 87932b2494eSpatrick } 88032b2494eSpatrick if (sztype != BWFM_DMP_SLAVE_SIZE_4K) 88132b2494eSpatrick continue; 88232b2494eSpatrick 88332b2494eSpatrick stype = (val & BWFM_DMP_SLAVE_TYPE) >> BWFM_DMP_SLAVE_TYPE_S; 88432b2494eSpatrick if (*base == 0 && stype == BWFM_DMP_SLAVE_TYPE_SLAVE) 88532b2494eSpatrick *base = val & BWFM_DMP_SLAVE_ADDR_BASE; 88632b2494eSpatrick if (*wrap == 0 && stype == wraptype) 88732b2494eSpatrick *wrap = val & BWFM_DMP_SLAVE_ADDR_BASE; 88832b2494eSpatrick } while (*base == 0 || *wrap == 0); 88932b2494eSpatrick 89032b2494eSpatrick return 0; 89132b2494eSpatrick } 89232b2494eSpatrick 89332b2494eSpatrick /* Core configuration */ 894e2612299Spatrick int 895e2612299Spatrick bwfm_chip_set_active(struct bwfm_softc *sc, uint32_t rstvec) 896e2612299Spatrick { 897e2612299Spatrick if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) 898e2612299Spatrick return bwfm_chip_cr4_set_active(sc, rstvec); 899e2612299Spatrick if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) 900e2612299Spatrick return bwfm_chip_ca7_set_active(sc, rstvec); 901e2612299Spatrick if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) 902e2612299Spatrick return bwfm_chip_cm3_set_active(sc); 903e2612299Spatrick return 1; 904e2612299Spatrick } 905e2612299Spatrick 906e2612299Spatrick void 907e2612299Spatrick bwfm_chip_set_passive(struct bwfm_softc *sc) 908e2612299Spatrick { 909e2612299Spatrick if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) { 910e2612299Spatrick bwfm_chip_cr4_set_passive(sc); 911e2612299Spatrick return; 912e2612299Spatrick } 913e2612299Spatrick if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) { 914e2612299Spatrick bwfm_chip_ca7_set_passive(sc); 915e2612299Spatrick return; 916e2612299Spatrick } 917e2612299Spatrick if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) { 918e2612299Spatrick bwfm_chip_cm3_set_passive(sc); 919e2612299Spatrick return; 920e2612299Spatrick } 921e2612299Spatrick } 922e2612299Spatrick 923e2612299Spatrick int 924e2612299Spatrick bwfm_chip_cr4_set_active(struct bwfm_softc *sc, uint32_t rstvec) 925e2612299Spatrick { 926e2612299Spatrick struct bwfm_core *core; 927e2612299Spatrick 928608f8b14Spatrick sc->sc_buscore_ops->bc_activate(sc, rstvec); 929e2612299Spatrick core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4); 930e2612299Spatrick sc->sc_chip.ch_core_reset(sc, core, 931e2612299Spatrick BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0); 932e2612299Spatrick 933e2612299Spatrick return 0; 934e2612299Spatrick } 935e2612299Spatrick 93632b2494eSpatrick void 93732b2494eSpatrick bwfm_chip_cr4_set_passive(struct bwfm_softc *sc) 93832b2494eSpatrick { 939c6962397Spatrick struct bwfm_core *core; 9403e129b89Spatrick uint32_t val; 941c6962397Spatrick 942c6962397Spatrick core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4); 9433e129b89Spatrick val = sc->sc_buscore_ops->bc_read(sc, 9443e129b89Spatrick core->co_wrapbase + BWFM_AGENT_IOCTL); 9453e129b89Spatrick sc->sc_chip.ch_core_reset(sc, core, 9463e129b89Spatrick val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 9473e129b89Spatrick BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 9483e129b89Spatrick BWFM_AGENT_IOCTL_ARMCR4_CPUHALT); 9493e129b89Spatrick 950c6962397Spatrick core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); 951c6962397Spatrick sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | 952c6962397Spatrick BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, 953c6962397Spatrick BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); 95432b2494eSpatrick } 95532b2494eSpatrick 956e2612299Spatrick int 957e2612299Spatrick bwfm_chip_ca7_set_active(struct bwfm_softc *sc, uint32_t rstvec) 958e2612299Spatrick { 9593e129b89Spatrick struct bwfm_core *core; 9603e129b89Spatrick 9613e129b89Spatrick sc->sc_buscore_ops->bc_activate(sc, rstvec); 9623e129b89Spatrick core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7); 9633e129b89Spatrick sc->sc_chip.ch_core_reset(sc, core, 9643e129b89Spatrick BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0); 9653e129b89Spatrick 9663e129b89Spatrick return 0; 967e2612299Spatrick } 968e2612299Spatrick 96932b2494eSpatrick void 97032b2494eSpatrick bwfm_chip_ca7_set_passive(struct bwfm_softc *sc) 97132b2494eSpatrick { 9723e129b89Spatrick struct bwfm_core *core; 9733e129b89Spatrick uint32_t val; 9743e129b89Spatrick 9753e129b89Spatrick core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7); 9763e129b89Spatrick val = sc->sc_buscore_ops->bc_read(sc, 9773e129b89Spatrick core->co_wrapbase + BWFM_AGENT_IOCTL); 9783e129b89Spatrick sc->sc_chip.ch_core_reset(sc, core, 9793e129b89Spatrick val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 9803e129b89Spatrick BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 9813e129b89Spatrick BWFM_AGENT_IOCTL_ARMCR4_CPUHALT); 9823e129b89Spatrick 9833e129b89Spatrick core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); 9843e129b89Spatrick sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | 9853e129b89Spatrick BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, 9863e129b89Spatrick BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); 98732b2494eSpatrick } 98832b2494eSpatrick 989e2612299Spatrick int 990e2612299Spatrick bwfm_chip_cm3_set_active(struct bwfm_softc *sc) 991e2612299Spatrick { 992b5537148Spatrick struct bwfm_core *core; 993b5537148Spatrick 994b5537148Spatrick core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM); 995b5537148Spatrick if (!sc->sc_chip.ch_core_isup(sc, core)) 996b5537148Spatrick return 1; 997b5537148Spatrick 998b5537148Spatrick sc->sc_buscore_ops->bc_activate(sc, 0); 999b5537148Spatrick 1000b5537148Spatrick core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3); 1001b5537148Spatrick sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); 1002b5537148Spatrick 1003b5537148Spatrick return 0; 1004e2612299Spatrick } 1005e2612299Spatrick 100632b2494eSpatrick void 100732b2494eSpatrick bwfm_chip_cm3_set_passive(struct bwfm_softc *sc) 100832b2494eSpatrick { 100932b2494eSpatrick struct bwfm_core *core; 101032b2494eSpatrick 101132b2494eSpatrick core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3); 101232b2494eSpatrick sc->sc_chip.ch_core_disable(sc, core, 0, 0); 101332b2494eSpatrick core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211); 101432b2494eSpatrick sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET | 101532b2494eSpatrick BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, 101632b2494eSpatrick BWFM_AGENT_D11_IOCTL_PHYCLOCKEN); 101732b2494eSpatrick core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM); 101832b2494eSpatrick sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); 101932b2494eSpatrick 102032b2494eSpatrick if (sc->sc_chip.ch_chip == BRCM_CC_43430_CHIP_ID) { 102132b2494eSpatrick sc->sc_buscore_ops->bc_write(sc, 102232b2494eSpatrick core->co_base + BWFM_SOCRAM_BANKIDX, 3); 102332b2494eSpatrick sc->sc_buscore_ops->bc_write(sc, 102432b2494eSpatrick core->co_base + BWFM_SOCRAM_BANKPDA, 0); 102532b2494eSpatrick } 102632b2494eSpatrick } 102732b2494eSpatrick 102885d32364Spatrick /* RAM size helpers */ 102985d32364Spatrick void 103085d32364Spatrick bwfm_chip_socram_ramsize(struct bwfm_softc *sc, struct bwfm_core *core) 103185d32364Spatrick { 10325212e703Spatrick uint32_t coreinfo, nb, lss, banksize, bankinfo; 10335212e703Spatrick uint32_t ramsize = 0, srsize = 0; 10345212e703Spatrick int i; 10355212e703Spatrick 10365212e703Spatrick if (!sc->sc_chip.ch_core_isup(sc, core)) 10375212e703Spatrick sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); 10385212e703Spatrick 10395212e703Spatrick coreinfo = sc->sc_buscore_ops->bc_read(sc, 10405212e703Spatrick core->co_base + BWFM_SOCRAM_COREINFO); 10415212e703Spatrick nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK) 10425212e703Spatrick >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT; 10435212e703Spatrick 10445212e703Spatrick if (core->co_rev <= 7 || core->co_rev == 12) { 10455212e703Spatrick banksize = coreinfo & BWFM_SOCRAM_COREINFO_SRBSZ_MASK; 10465212e703Spatrick lss = (coreinfo & BWFM_SOCRAM_COREINFO_LSS_MASK) 10475212e703Spatrick >> BWFM_SOCRAM_COREINFO_LSS_SHIFT; 10485212e703Spatrick if (lss != 0) 10495212e703Spatrick nb--; 10505212e703Spatrick ramsize = nb * (1 << (banksize + BWFM_SOCRAM_COREINFO_SRBSZ_BASE)); 10515212e703Spatrick if (lss != 0) 10525212e703Spatrick ramsize += (1 << ((lss - 1) + BWFM_SOCRAM_COREINFO_SRBSZ_BASE)); 10535212e703Spatrick } else { 10545212e703Spatrick for (i = 0; i < nb; i++) { 10555212e703Spatrick sc->sc_buscore_ops->bc_write(sc, 10565212e703Spatrick core->co_base + BWFM_SOCRAM_BANKIDX, 10575212e703Spatrick (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM << 10585212e703Spatrick BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i); 10595212e703Spatrick bankinfo = sc->sc_buscore_ops->bc_read(sc, 10605212e703Spatrick core->co_base + BWFM_SOCRAM_BANKINFO); 10615212e703Spatrick banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1) 10625212e703Spatrick * BWFM_SOCRAM_BANKINFO_SZBASE; 10635212e703Spatrick ramsize += banksize; 10645212e703Spatrick if (bankinfo & BWFM_SOCRAM_BANKINFO_RETNTRAM_MASK) 10655212e703Spatrick srsize += banksize; 10665212e703Spatrick } 10675212e703Spatrick } 10685212e703Spatrick 10695212e703Spatrick switch (sc->sc_chip.ch_chip) { 10705212e703Spatrick case BRCM_CC_4334_CHIP_ID: 10715212e703Spatrick if (sc->sc_chip.ch_chiprev < 2) 10725212e703Spatrick srsize = 32 * 1024; 10735212e703Spatrick break; 10745212e703Spatrick case BRCM_CC_43430_CHIP_ID: 10755212e703Spatrick srsize = 64 * 1024; 10765212e703Spatrick break; 10775212e703Spatrick default: 10785212e703Spatrick break; 10795212e703Spatrick } 10805212e703Spatrick 10815212e703Spatrick sc->sc_chip.ch_ramsize = ramsize; 10825212e703Spatrick sc->sc_chip.ch_srsize = srsize; 108385d32364Spatrick } 108485d32364Spatrick 108585d32364Spatrick void 108685d32364Spatrick bwfm_chip_sysmem_ramsize(struct bwfm_softc *sc, struct bwfm_core *core) 108785d32364Spatrick { 1088*c9aa06c9Spatrick uint32_t coreinfo, nb, banksize, bankinfo; 1089*c9aa06c9Spatrick uint32_t ramsize = 0; 1090*c9aa06c9Spatrick int i; 1091*c9aa06c9Spatrick 1092*c9aa06c9Spatrick if (!sc->sc_chip.ch_core_isup(sc, core)) 1093*c9aa06c9Spatrick sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0); 1094*c9aa06c9Spatrick 1095*c9aa06c9Spatrick coreinfo = sc->sc_buscore_ops->bc_read(sc, 1096*c9aa06c9Spatrick core->co_base + BWFM_SOCRAM_COREINFO); 1097*c9aa06c9Spatrick nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK) 1098*c9aa06c9Spatrick >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT; 1099*c9aa06c9Spatrick 1100*c9aa06c9Spatrick for (i = 0; i < nb; i++) { 1101*c9aa06c9Spatrick sc->sc_buscore_ops->bc_write(sc, 1102*c9aa06c9Spatrick core->co_base + BWFM_SOCRAM_BANKIDX, 1103*c9aa06c9Spatrick (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM << 1104*c9aa06c9Spatrick BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i); 1105*c9aa06c9Spatrick bankinfo = sc->sc_buscore_ops->bc_read(sc, 1106*c9aa06c9Spatrick core->co_base + BWFM_SOCRAM_BANKINFO); 1107*c9aa06c9Spatrick banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1) 1108*c9aa06c9Spatrick * BWFM_SOCRAM_BANKINFO_SZBASE; 1109*c9aa06c9Spatrick ramsize += banksize; 1110*c9aa06c9Spatrick } 1111*c9aa06c9Spatrick 1112*c9aa06c9Spatrick sc->sc_chip.ch_ramsize = ramsize; 111385d32364Spatrick } 111485d32364Spatrick 111585d32364Spatrick void 111685d32364Spatrick bwfm_chip_tcm_ramsize(struct bwfm_softc *sc, struct bwfm_core *core) 111785d32364Spatrick { 11185212e703Spatrick uint32_t cap, nab, nbb, totb, bxinfo, ramsize = 0; 111985d32364Spatrick int i; 112085d32364Spatrick 112185d32364Spatrick cap = sc->sc_buscore_ops->bc_read(sc, core->co_base + BWFM_ARMCR4_CAP); 112285d32364Spatrick nab = (cap & BWFM_ARMCR4_CAP_TCBANB_MASK) >> BWFM_ARMCR4_CAP_TCBANB_SHIFT; 112385d32364Spatrick nbb = (cap & BWFM_ARMCR4_CAP_TCBBNB_MASK) >> BWFM_ARMCR4_CAP_TCBBNB_SHIFT; 112485d32364Spatrick totb = nab + nbb; 112585d32364Spatrick 112685d32364Spatrick for (i = 0; i < totb; i++) { 112785d32364Spatrick sc->sc_buscore_ops->bc_write(sc, 112885d32364Spatrick core->co_base + BWFM_ARMCR4_BANKIDX, i); 112985d32364Spatrick bxinfo = sc->sc_buscore_ops->bc_read(sc, 113085d32364Spatrick core->co_base + BWFM_ARMCR4_BANKINFO); 11315212e703Spatrick ramsize += ((bxinfo & BWFM_ARMCR4_BANKINFO_BSZ_MASK) + 1) * 113285d32364Spatrick BWFM_ARMCR4_BANKINFO_BSZ_MULT; 113385d32364Spatrick } 113485d32364Spatrick 11355212e703Spatrick sc->sc_chip.ch_ramsize = ramsize; 113685d32364Spatrick } 113785d32364Spatrick 113885d32364Spatrick void 113985d32364Spatrick bwfm_chip_tcm_rambase(struct bwfm_softc *sc) 114085d32364Spatrick { 114185d32364Spatrick switch (sc->sc_chip.ch_chip) { 114285d32364Spatrick case BRCM_CC_4345_CHIP_ID: 114385d32364Spatrick sc->sc_chip.ch_rambase = 0x198000; 114485d32364Spatrick break; 114585d32364Spatrick case BRCM_CC_4335_CHIP_ID: 114685d32364Spatrick case BRCM_CC_4339_CHIP_ID: 114785d32364Spatrick case BRCM_CC_4350_CHIP_ID: 114885d32364Spatrick case BRCM_CC_4354_CHIP_ID: 114985d32364Spatrick case BRCM_CC_4356_CHIP_ID: 115085d32364Spatrick case BRCM_CC_43567_CHIP_ID: 115185d32364Spatrick case BRCM_CC_43569_CHIP_ID: 115285d32364Spatrick case BRCM_CC_43570_CHIP_ID: 115385d32364Spatrick case BRCM_CC_4358_CHIP_ID: 115485d32364Spatrick case BRCM_CC_4359_CHIP_ID: 115585d32364Spatrick case BRCM_CC_43602_CHIP_ID: 115685d32364Spatrick case BRCM_CC_4371_CHIP_ID: 115785d32364Spatrick sc->sc_chip.ch_rambase = 0x180000; 115885d32364Spatrick break; 115985d32364Spatrick case BRCM_CC_43465_CHIP_ID: 116085d32364Spatrick case BRCM_CC_43525_CHIP_ID: 116185d32364Spatrick case BRCM_CC_4365_CHIP_ID: 116285d32364Spatrick case BRCM_CC_4366_CHIP_ID: 116385d32364Spatrick sc->sc_chip.ch_rambase = 0x200000; 116485d32364Spatrick break; 116585d32364Spatrick case CY_CC_4373_CHIP_ID: 116685d32364Spatrick sc->sc_chip.ch_rambase = 0x160000; 116785d32364Spatrick break; 116885d32364Spatrick default: 116985d32364Spatrick printf("%s: unknown chip: %d\n", DEVNAME(sc), 117085d32364Spatrick sc->sc_chip.ch_chip); 117185d32364Spatrick break; 117285d32364Spatrick } 117385d32364Spatrick } 117485d32364Spatrick 117532b2494eSpatrick /* BCDC protocol implementation */ 117632b2494eSpatrick int 117732b2494eSpatrick bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *sc, int ifidx, 117832b2494eSpatrick int cmd, char *buf, size_t *len) 117932b2494eSpatrick { 118032b2494eSpatrick struct bwfm_proto_bcdc_dcmd *dcmd; 118132b2494eSpatrick size_t size = sizeof(dcmd->hdr) + *len; 118232b2494eSpatrick static int reqid = 0; 118332b2494eSpatrick int ret = 1; 118432b2494eSpatrick 118532b2494eSpatrick reqid++; 118632b2494eSpatrick 118732b2494eSpatrick dcmd = malloc(sizeof(*dcmd), M_TEMP, M_WAITOK | M_ZERO); 118832b2494eSpatrick if (*len > sizeof(dcmd->buf)) 118932b2494eSpatrick goto err; 119032b2494eSpatrick 119132b2494eSpatrick dcmd->hdr.cmd = htole32(cmd); 119232b2494eSpatrick dcmd->hdr.len = htole32(*len); 119332b2494eSpatrick dcmd->hdr.flags |= BWFM_BCDC_DCMD_GET; 119432b2494eSpatrick dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid); 119532b2494eSpatrick dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx); 119632b2494eSpatrick dcmd->hdr.flags = htole32(dcmd->hdr.flags); 119732b2494eSpatrick memcpy(&dcmd->buf, buf, *len); 119832b2494eSpatrick 119932b2494eSpatrick if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd, 120032b2494eSpatrick sizeof(dcmd->hdr) + *len)) { 120132b2494eSpatrick DPRINTF(("%s: tx failed\n", DEVNAME(sc))); 120232b2494eSpatrick goto err; 120332b2494eSpatrick } 120432b2494eSpatrick 120532b2494eSpatrick do { 120632b2494eSpatrick if (sc->sc_bus_ops->bs_rxctl(sc, (void *)dcmd, &size)) { 120732b2494eSpatrick DPRINTF(("%s: rx failed\n", DEVNAME(sc))); 120832b2494eSpatrick goto err; 120932b2494eSpatrick } 121032b2494eSpatrick dcmd->hdr.cmd = letoh32(dcmd->hdr.cmd); 121132b2494eSpatrick dcmd->hdr.len = letoh32(dcmd->hdr.len); 121232b2494eSpatrick dcmd->hdr.flags = letoh32(dcmd->hdr.flags); 121332b2494eSpatrick dcmd->hdr.status = letoh32(dcmd->hdr.status); 121432b2494eSpatrick } while (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid); 121532b2494eSpatrick 121632b2494eSpatrick if (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid) { 121732b2494eSpatrick printf("%s: unexpected request id\n", DEVNAME(sc)); 121832b2494eSpatrick goto err; 121932b2494eSpatrick } 122032b2494eSpatrick 122132b2494eSpatrick if (buf) { 122232b2494eSpatrick if (size > *len) 122332b2494eSpatrick size = *len; 122432b2494eSpatrick if (size < *len) 122532b2494eSpatrick *len = size; 122632b2494eSpatrick memcpy(buf, dcmd->buf, *len); 122732b2494eSpatrick } 122832b2494eSpatrick 122932b2494eSpatrick if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR) 123032b2494eSpatrick ret = dcmd->hdr.status; 123132b2494eSpatrick else 123232b2494eSpatrick ret = 0; 123332b2494eSpatrick err: 123432b2494eSpatrick free(dcmd, M_TEMP, sizeof(*dcmd)); 123532b2494eSpatrick return ret; 123632b2494eSpatrick } 123732b2494eSpatrick 123832b2494eSpatrick int 123932b2494eSpatrick bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *sc, int ifidx, 124032b2494eSpatrick int cmd, char *buf, size_t len) 124132b2494eSpatrick { 124232b2494eSpatrick struct bwfm_proto_bcdc_dcmd *dcmd; 124332b2494eSpatrick size_t size = sizeof(dcmd->hdr) + len; 124432b2494eSpatrick int reqid = 0; 124532b2494eSpatrick int ret = 1; 124632b2494eSpatrick 124732b2494eSpatrick reqid++; 124832b2494eSpatrick 124932b2494eSpatrick dcmd = malloc(sizeof(*dcmd), M_TEMP, M_WAITOK | M_ZERO); 125032b2494eSpatrick if (len > sizeof(dcmd->buf)) 125132b2494eSpatrick goto err; 125232b2494eSpatrick 125332b2494eSpatrick dcmd->hdr.cmd = htole32(cmd); 125432b2494eSpatrick dcmd->hdr.len = htole32(len); 125532b2494eSpatrick dcmd->hdr.flags |= BWFM_BCDC_DCMD_SET; 125632b2494eSpatrick dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid); 125732b2494eSpatrick dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx); 125832b2494eSpatrick dcmd->hdr.flags = htole32(dcmd->hdr.flags); 125932b2494eSpatrick memcpy(&dcmd->buf, buf, len); 126032b2494eSpatrick 126132b2494eSpatrick if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd, size)) { 126232b2494eSpatrick DPRINTF(("%s: tx failed\n", DEVNAME(sc))); 126332b2494eSpatrick goto err; 126432b2494eSpatrick } 126532b2494eSpatrick 126632b2494eSpatrick do { 126732b2494eSpatrick if (sc->sc_bus_ops->bs_rxctl(sc, (void *)dcmd, &size)) { 126832b2494eSpatrick DPRINTF(("%s: rx failed\n", DEVNAME(sc))); 126932b2494eSpatrick goto err; 127032b2494eSpatrick } 127132b2494eSpatrick dcmd->hdr.cmd = letoh32(dcmd->hdr.cmd); 127232b2494eSpatrick dcmd->hdr.len = letoh32(dcmd->hdr.len); 127332b2494eSpatrick dcmd->hdr.flags = letoh32(dcmd->hdr.flags); 127432b2494eSpatrick dcmd->hdr.status = letoh32(dcmd->hdr.status); 127532b2494eSpatrick } while (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid); 127632b2494eSpatrick 127732b2494eSpatrick if (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid) { 127832b2494eSpatrick printf("%s: unexpected request id\n", DEVNAME(sc)); 127932b2494eSpatrick goto err; 128032b2494eSpatrick } 128132b2494eSpatrick 128232b2494eSpatrick if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR) 128332b2494eSpatrick return dcmd->hdr.status; 128432b2494eSpatrick 128532b2494eSpatrick ret = 0; 128632b2494eSpatrick err: 128732b2494eSpatrick free(dcmd, M_TEMP, sizeof(*dcmd)); 128832b2494eSpatrick return ret; 128932b2494eSpatrick } 129032b2494eSpatrick 129132b2494eSpatrick /* FW Variable code */ 129232b2494eSpatrick int 129332b2494eSpatrick bwfm_fwvar_cmd_get_data(struct bwfm_softc *sc, int cmd, void *data, size_t len) 129432b2494eSpatrick { 129532b2494eSpatrick return sc->sc_proto_ops->proto_query_dcmd(sc, 0, cmd, data, &len); 129632b2494eSpatrick } 129732b2494eSpatrick 129832b2494eSpatrick int 129932b2494eSpatrick bwfm_fwvar_cmd_set_data(struct bwfm_softc *sc, int cmd, void *data, size_t len) 130032b2494eSpatrick { 130132b2494eSpatrick return sc->sc_proto_ops->proto_set_dcmd(sc, 0, cmd, data, len); 130232b2494eSpatrick } 130332b2494eSpatrick 130432b2494eSpatrick int 130532b2494eSpatrick bwfm_fwvar_cmd_get_int(struct bwfm_softc *sc, int cmd, uint32_t *data) 130632b2494eSpatrick { 130732b2494eSpatrick int ret; 130832b2494eSpatrick ret = bwfm_fwvar_cmd_get_data(sc, cmd, data, sizeof(*data)); 130932b2494eSpatrick *data = letoh32(*data); 131032b2494eSpatrick return ret; 131132b2494eSpatrick } 131232b2494eSpatrick 131332b2494eSpatrick int 131432b2494eSpatrick bwfm_fwvar_cmd_set_int(struct bwfm_softc *sc, int cmd, uint32_t data) 131532b2494eSpatrick { 131632b2494eSpatrick data = htole32(data); 131732b2494eSpatrick return bwfm_fwvar_cmd_set_data(sc, cmd, &data, sizeof(data)); 131832b2494eSpatrick } 131932b2494eSpatrick 132032b2494eSpatrick int 132132b2494eSpatrick bwfm_fwvar_var_get_data(struct bwfm_softc *sc, char *name, void *data, size_t len) 132232b2494eSpatrick { 132332b2494eSpatrick char *buf; 132432b2494eSpatrick int ret; 132532b2494eSpatrick 132632b2494eSpatrick buf = malloc(strlen(name) + 1 + len, M_TEMP, M_WAITOK); 132732b2494eSpatrick memcpy(buf, name, strlen(name) + 1); 132832b2494eSpatrick memcpy(buf + strlen(name) + 1, data, len); 132932b2494eSpatrick ret = bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_VAR, 133032b2494eSpatrick buf, strlen(name) + 1 + len); 133132b2494eSpatrick memcpy(data, buf, len); 133232b2494eSpatrick free(buf, M_TEMP, strlen(name) + 1 + len); 133332b2494eSpatrick return ret; 133432b2494eSpatrick } 133532b2494eSpatrick 133632b2494eSpatrick int 133732b2494eSpatrick bwfm_fwvar_var_set_data(struct bwfm_softc *sc, char *name, void *data, size_t len) 133832b2494eSpatrick { 133932b2494eSpatrick char *buf; 134032b2494eSpatrick int ret; 134132b2494eSpatrick 134232b2494eSpatrick buf = malloc(strlen(name) + 1 + len, M_TEMP, M_WAITOK); 134332b2494eSpatrick memcpy(buf, name, strlen(name) + 1); 134432b2494eSpatrick memcpy(buf + strlen(name) + 1, data, len); 134532b2494eSpatrick ret = bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_VAR, 134632b2494eSpatrick buf, strlen(name) + 1 + len); 134732b2494eSpatrick free(buf, M_TEMP, strlen(name) + 1 + len); 134832b2494eSpatrick return ret; 134932b2494eSpatrick } 135032b2494eSpatrick 135132b2494eSpatrick int 135232b2494eSpatrick bwfm_fwvar_var_get_int(struct bwfm_softc *sc, char *name, uint32_t *data) 135332b2494eSpatrick { 135432b2494eSpatrick int ret; 135532b2494eSpatrick ret = bwfm_fwvar_var_get_data(sc, name, data, sizeof(*data)); 135632b2494eSpatrick *data = letoh32(*data); 135732b2494eSpatrick return ret; 135832b2494eSpatrick } 135932b2494eSpatrick 136032b2494eSpatrick int 136132b2494eSpatrick bwfm_fwvar_var_set_int(struct bwfm_softc *sc, char *name, uint32_t data) 136232b2494eSpatrick { 136332b2494eSpatrick data = htole32(data); 136432b2494eSpatrick return bwfm_fwvar_var_set_data(sc, name, &data, sizeof(data)); 136532b2494eSpatrick } 136632b2494eSpatrick 13678b2458cfSpatrick /* Channel parameters */ 13688b2458cfSpatrick uint32_t 13698b2458cfSpatrick bwfm_spec2chan(struct bwfm_softc *sc, uint32_t chanspec) 13708b2458cfSpatrick { 13718b2458cfSpatrick if (sc->sc_io_type == BWFM_IO_TYPE_D11N) 13728b2458cfSpatrick return bwfm_spec2chan_d11n(sc, chanspec); 13738b2458cfSpatrick else 13748b2458cfSpatrick return bwfm_spec2chan_d11ac(sc, chanspec); 13758b2458cfSpatrick } 13768b2458cfSpatrick 13778b2458cfSpatrick uint32_t 13788b2458cfSpatrick bwfm_spec2chan_d11n(struct bwfm_softc *sc, uint32_t chanspec) 13798b2458cfSpatrick { 13808b2458cfSpatrick uint32_t chanidx; 13818b2458cfSpatrick 13828b2458cfSpatrick chanidx = chanspec & BWFM_CHANSPEC_CHAN_MASK; 13838b2458cfSpatrick 13848b2458cfSpatrick switch (chanspec & BWFM_CHANSPEC_D11N_BW_MASK) { 13858b2458cfSpatrick case BWFM_CHANSPEC_D11N_BW_40: 13868b2458cfSpatrick switch (chanspec & BWFM_CHANSPEC_D11N_SB_MASK) { 13878b2458cfSpatrick case BWFM_CHANSPEC_D11N_SB_L: 13888b2458cfSpatrick chanidx -= 2; 13898b2458cfSpatrick break; 13908b2458cfSpatrick case BWFM_CHANSPEC_D11N_SB_U: 13918b2458cfSpatrick chanidx += 2; 13928b2458cfSpatrick break; 13938b2458cfSpatrick default: 13948b2458cfSpatrick break; 13958b2458cfSpatrick } 13968b2458cfSpatrick break; 13978b2458cfSpatrick default: 13988b2458cfSpatrick break; 13998b2458cfSpatrick } 14008b2458cfSpatrick 14018b2458cfSpatrick return chanidx; 14028b2458cfSpatrick } 14038b2458cfSpatrick 14048b2458cfSpatrick uint32_t 14058b2458cfSpatrick bwfm_spec2chan_d11ac(struct bwfm_softc *sc, uint32_t chanspec) 14068b2458cfSpatrick { 14078b2458cfSpatrick uint32_t chanidx; 14088b2458cfSpatrick 14098b2458cfSpatrick chanidx = chanspec & BWFM_CHANSPEC_CHAN_MASK; 14108b2458cfSpatrick 14118b2458cfSpatrick switch (chanspec & BWFM_CHANSPEC_D11AC_BW_MASK) { 14128b2458cfSpatrick case BWFM_CHANSPEC_D11AC_BW_40: 14138b2458cfSpatrick switch (chanspec & BWFM_CHANSPEC_D11AC_SB_MASK) { 14148b2458cfSpatrick case BWFM_CHANSPEC_D11AC_SB_LLL: 14158b2458cfSpatrick chanidx -= 2; 14168b2458cfSpatrick break; 14178b2458cfSpatrick case BWFM_CHANSPEC_D11AC_SB_LLU: 14188b2458cfSpatrick chanidx += 2; 14198b2458cfSpatrick break; 14208b2458cfSpatrick default: 14218b2458cfSpatrick break; 14228b2458cfSpatrick } 14238b2458cfSpatrick break; 14248b2458cfSpatrick case BWFM_CHANSPEC_D11AC_BW_80: 14258b2458cfSpatrick switch (chanspec & BWFM_CHANSPEC_D11AC_SB_MASK) { 14268b2458cfSpatrick case BWFM_CHANSPEC_D11AC_SB_LLL: 14278b2458cfSpatrick chanidx -= 6; 14288b2458cfSpatrick break; 14298b2458cfSpatrick case BWFM_CHANSPEC_D11AC_SB_LLU: 14308b2458cfSpatrick chanidx -= 2; 14318b2458cfSpatrick break; 14328b2458cfSpatrick case BWFM_CHANSPEC_D11AC_SB_LUL: 14338b2458cfSpatrick chanidx += 2; 14348b2458cfSpatrick break; 14358b2458cfSpatrick case BWFM_CHANSPEC_D11AC_SB_LUU: 14368b2458cfSpatrick chanidx += 6; 14378b2458cfSpatrick break; 14388b2458cfSpatrick default: 14398b2458cfSpatrick break; 14408b2458cfSpatrick } 14418b2458cfSpatrick break; 14428b2458cfSpatrick default: 14438b2458cfSpatrick break; 14448b2458cfSpatrick } 14458b2458cfSpatrick 14468b2458cfSpatrick return chanidx; 14478b2458cfSpatrick } 14488b2458cfSpatrick 144932b2494eSpatrick /* 802.11 code */ 145032b2494eSpatrick void 145163498aa8Spatrick bwfm_connect(struct bwfm_softc *sc) 145232b2494eSpatrick { 145332b2494eSpatrick struct ieee80211com *ic = &sc->sc_ic; 145463498aa8Spatrick struct bwfm_ext_join_params *params; 145563498aa8Spatrick uint8_t buf[64]; /* XXX max WPA/RSN/WMM IE length */ 145663498aa8Spatrick uint8_t *frm; 145763498aa8Spatrick 145863498aa8Spatrick /* 145963498aa8Spatrick * OPEN: Open or WPA/WPA2 on newer Chips/Firmware. 146063498aa8Spatrick * SHARED KEY: WEP. 146163498aa8Spatrick * AUTO: Automatic, probably for older Chips/Firmware. 146263498aa8Spatrick */ 146363498aa8Spatrick if (ic->ic_flags & IEEE80211_F_RSNON) { 146463498aa8Spatrick uint32_t wsec = 0; 146563498aa8Spatrick uint32_t wpa = 0; 146663498aa8Spatrick 146763498aa8Spatrick /* tell firmware to add WPA/RSN IE to (re)assoc request */ 146863498aa8Spatrick if (ic->ic_bss->ni_rsnprotos == IEEE80211_PROTO_RSN) 146963498aa8Spatrick frm = ieee80211_add_rsn(buf, ic, ic->ic_bss); 147063498aa8Spatrick else 147163498aa8Spatrick frm = ieee80211_add_wpa(buf, ic, ic->ic_bss); 147263498aa8Spatrick bwfm_fwvar_var_set_data(sc, "wpaie", buf, frm - buf); 147363498aa8Spatrick 147463498aa8Spatrick if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA) { 147563498aa8Spatrick if (ic->ic_rsnakms & IEEE80211_AKM_PSK) 147663498aa8Spatrick wpa |= BWFM_WPA_AUTH_WPA_PSK; 147763498aa8Spatrick if (ic->ic_rsnakms & IEEE80211_AKM_8021X) 147863498aa8Spatrick wpa |= BWFM_WPA_AUTH_WPA_UNSPECIFIED; 147963498aa8Spatrick } 148063498aa8Spatrick if (ic->ic_rsnprotos & IEEE80211_PROTO_RSN) { 148163498aa8Spatrick if (ic->ic_rsnakms & IEEE80211_AKM_PSK) 148263498aa8Spatrick wpa |= BWFM_WPA_AUTH_WPA2_PSK; 148363498aa8Spatrick if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_PSK) 148463498aa8Spatrick wpa |= BWFM_WPA_AUTH_WPA2_PSK_SHA256; 148563498aa8Spatrick if (ic->ic_rsnakms & IEEE80211_AKM_8021X) 148663498aa8Spatrick wpa |= BWFM_WPA_AUTH_WPA2_UNSPECIFIED; 148763498aa8Spatrick if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_8021X) 148863498aa8Spatrick wpa |= BWFM_WPA_AUTH_WPA2_1X_SHA256; 148963498aa8Spatrick } 149063498aa8Spatrick if (ic->ic_rsnciphers & IEEE80211_WPA_CIPHER_TKIP || 149163498aa8Spatrick ic->ic_rsngroupcipher & IEEE80211_WPA_CIPHER_TKIP) 149263498aa8Spatrick wsec |= BWFM_WSEC_TKIP; 149363498aa8Spatrick if (ic->ic_rsnciphers & IEEE80211_WPA_CIPHER_CCMP || 149463498aa8Spatrick ic->ic_rsngroupcipher & IEEE80211_WPA_CIPHER_CCMP) 149563498aa8Spatrick wsec |= BWFM_WSEC_AES; 149663498aa8Spatrick 149763498aa8Spatrick bwfm_fwvar_var_set_int(sc, "wpa_auth", wpa); 149863498aa8Spatrick bwfm_fwvar_var_set_int(sc, "wsec", wsec); 149963498aa8Spatrick } else { 150063498aa8Spatrick bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_DISABLED); 150163498aa8Spatrick bwfm_fwvar_var_set_int(sc, "wsec", BWFM_WSEC_NONE); 150263498aa8Spatrick } 150363498aa8Spatrick bwfm_fwvar_var_set_int(sc, "auth", BWFM_AUTH_OPEN); 150463498aa8Spatrick bwfm_fwvar_var_set_int(sc, "mfp", BWFM_MFP_NONE); 150563498aa8Spatrick 150663498aa8Spatrick if (ic->ic_des_esslen && ic->ic_des_esslen < BWFM_MAX_SSID_LEN) { 150763498aa8Spatrick params = malloc(sizeof(*params), M_TEMP, M_WAITOK | M_ZERO); 150863498aa8Spatrick memcpy(params->ssid.ssid, ic->ic_des_essid, ic->ic_des_esslen); 150963498aa8Spatrick params->ssid.len = htole32(ic->ic_des_esslen); 151002662318Spatrick memcpy(params->assoc.bssid, ic->ic_bss->ni_bssid, 151102662318Spatrick sizeof(params->assoc.bssid)); 151263498aa8Spatrick params->scan.scan_type = -1; 151363498aa8Spatrick params->scan.nprobes = htole32(-1); 151463498aa8Spatrick params->scan.active_time = htole32(-1); 151563498aa8Spatrick params->scan.passive_time = htole32(-1); 151663498aa8Spatrick params->scan.home_time = htole32(-1); 151763498aa8Spatrick if (bwfm_fwvar_var_set_data(sc, "join", params, sizeof(*params))) { 151863498aa8Spatrick struct bwfm_join_params join; 151963498aa8Spatrick memset(&join, 0, sizeof(join)); 152002662318Spatrick memcpy(join.ssid.ssid, ic->ic_des_essid, 152102662318Spatrick ic->ic_des_esslen); 152263498aa8Spatrick join.ssid.len = htole32(ic->ic_des_esslen); 152302662318Spatrick memcpy(join.assoc.bssid, ic->ic_bss->ni_bssid, 152402662318Spatrick sizeof(join.assoc.bssid)); 152563498aa8Spatrick bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, 152663498aa8Spatrick sizeof(join)); 152763498aa8Spatrick } 152863498aa8Spatrick free(params, M_TEMP, sizeof(*params)); 152963498aa8Spatrick } 153063498aa8Spatrick } 153163498aa8Spatrick 1532c11618f6Spatrick #ifndef IEEE80211_STA_ONLY 1533c11618f6Spatrick void 1534c11618f6Spatrick bwfm_hostap(struct bwfm_softc *sc) 1535c11618f6Spatrick { 1536c11618f6Spatrick struct ieee80211com *ic = &sc->sc_ic; 1537c11618f6Spatrick struct ieee80211_node *ni = ic->ic_bss; 1538c11618f6Spatrick struct bwfm_join_params join; 1539c11618f6Spatrick 1540c11618f6Spatrick /* 1541c11618f6Spatrick * OPEN: Open or WPA/WPA2 on newer Chips/Firmware. 1542c11618f6Spatrick * SHARED KEY: WEP. 1543c11618f6Spatrick * AUTO: Automatic, probably for older Chips/Firmware. 1544c11618f6Spatrick */ 1545c11618f6Spatrick if (ic->ic_flags & IEEE80211_F_RSNON) { 1546c11618f6Spatrick uint32_t wsec = 0; 1547c11618f6Spatrick uint32_t wpa = 0; 1548c11618f6Spatrick 1549c11618f6Spatrick /* TODO: Turn off if replay counter set */ 1550c11618f6Spatrick if (ni->ni_rsnprotos & IEEE80211_PROTO_RSN) 1551c11618f6Spatrick bwfm_fwvar_var_set_int(sc, "wme_bss_disable", 1); 1552c11618f6Spatrick 1553c11618f6Spatrick if (ni->ni_rsnprotos & IEEE80211_PROTO_WPA) { 1554c11618f6Spatrick if (ni->ni_rsnakms & IEEE80211_AKM_PSK) 1555c11618f6Spatrick wpa |= BWFM_WPA_AUTH_WPA_PSK; 1556c11618f6Spatrick if (ni->ni_rsnakms & IEEE80211_AKM_8021X) 1557c11618f6Spatrick wpa |= BWFM_WPA_AUTH_WPA_UNSPECIFIED; 1558c11618f6Spatrick } 1559c11618f6Spatrick if (ni->ni_rsnprotos & IEEE80211_PROTO_RSN) { 1560c11618f6Spatrick if (ni->ni_rsnakms & IEEE80211_AKM_PSK) 1561c11618f6Spatrick wpa |= BWFM_WPA_AUTH_WPA2_PSK; 1562c11618f6Spatrick if (ni->ni_rsnakms & IEEE80211_AKM_SHA256_PSK) 1563c11618f6Spatrick wpa |= BWFM_WPA_AUTH_WPA2_PSK_SHA256; 1564c11618f6Spatrick if (ni->ni_rsnakms & IEEE80211_AKM_8021X) 1565c11618f6Spatrick wpa |= BWFM_WPA_AUTH_WPA2_UNSPECIFIED; 1566c11618f6Spatrick if (ni->ni_rsnakms & IEEE80211_AKM_SHA256_8021X) 1567c11618f6Spatrick wpa |= BWFM_WPA_AUTH_WPA2_1X_SHA256; 1568c11618f6Spatrick } 1569c11618f6Spatrick if (ni->ni_rsnciphers & IEEE80211_WPA_CIPHER_TKIP || 1570c11618f6Spatrick ni->ni_rsngroupcipher & IEEE80211_WPA_CIPHER_TKIP) 1571c11618f6Spatrick wsec |= BWFM_WSEC_TKIP; 1572c11618f6Spatrick if (ni->ni_rsnciphers & IEEE80211_WPA_CIPHER_CCMP || 1573c11618f6Spatrick ni->ni_rsngroupcipher & IEEE80211_WPA_CIPHER_CCMP) 1574c11618f6Spatrick wsec |= BWFM_WSEC_AES; 1575c11618f6Spatrick 1576c11618f6Spatrick bwfm_fwvar_var_set_int(sc, "wpa_auth", wpa); 1577c11618f6Spatrick bwfm_fwvar_var_set_int(sc, "wsec", wsec); 1578c11618f6Spatrick } else { 1579c11618f6Spatrick bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_DISABLED); 1580c11618f6Spatrick bwfm_fwvar_var_set_int(sc, "wsec", BWFM_WSEC_NONE); 1581c11618f6Spatrick } 1582c11618f6Spatrick bwfm_fwvar_var_set_int(sc, "auth", BWFM_AUTH_OPEN); 1583c11618f6Spatrick bwfm_fwvar_var_set_int(sc, "mfp", BWFM_MFP_NONE); 1584c11618f6Spatrick 1585c11618f6Spatrick bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 1); 1586c11618f6Spatrick bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 1); 1587c11618f6Spatrick bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 1); 1588c11618f6Spatrick 1589c11618f6Spatrick memset(&join, 0, sizeof(join)); 1590c11618f6Spatrick memcpy(join.ssid.ssid, ic->ic_des_essid, ic->ic_des_esslen); 1591c11618f6Spatrick join.ssid.len = htole32(ic->ic_des_esslen); 1592c11618f6Spatrick memset(join.assoc.bssid, 0xff, sizeof(join.assoc.bssid)); 1593c11618f6Spatrick bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, sizeof(join)); 1594c11618f6Spatrick bwfm_fwvar_var_set_int(sc, "closednet", 1595c11618f6Spatrick (ic->ic_flags & IEEE80211_F_HIDENWID) != 0); 1596c11618f6Spatrick } 1597c11618f6Spatrick #endif 1598c11618f6Spatrick 159963498aa8Spatrick void 160063498aa8Spatrick bwfm_scan(struct bwfm_softc *sc) 160163498aa8Spatrick { 160232b2494eSpatrick struct bwfm_escan_params *params; 160332b2494eSpatrick uint32_t nssid = 0, nchannel = 0; 160432b2494eSpatrick size_t params_size; 160532b2494eSpatrick 160632b2494eSpatrick params_size = sizeof(*params); 160732b2494eSpatrick params_size += sizeof(uint32_t) * ((nchannel + 1) / 2); 160832b2494eSpatrick params_size += sizeof(struct bwfm_ssid) * nssid; 160932b2494eSpatrick 161032b2494eSpatrick params = malloc(params_size, M_TEMP, M_WAITOK | M_ZERO); 161132b2494eSpatrick memset(params->scan_params.bssid, 0xff, 161232b2494eSpatrick sizeof(params->scan_params.bssid)); 161332b2494eSpatrick params->scan_params.bss_type = 2; 16141d29b516Spatrick params->scan_params.scan_type = BWFM_SCANTYPE_PASSIVE; 161532b2494eSpatrick params->scan_params.nprobes = htole32(-1); 161632b2494eSpatrick params->scan_params.active_time = htole32(-1); 161732b2494eSpatrick params->scan_params.passive_time = htole32(-1); 161832b2494eSpatrick params->scan_params.home_time = htole32(-1); 161932b2494eSpatrick params->version = htole32(BWFM_ESCAN_REQ_VERSION); 162032b2494eSpatrick params->action = htole16(WL_ESCAN_ACTION_START); 162132b2494eSpatrick params->sync_id = htole16(0x1234); 162232b2494eSpatrick 162332b2494eSpatrick #if 0 162432b2494eSpatrick /* Scan a specific channel */ 162532b2494eSpatrick params->scan_params.channel_list[0] = htole16( 162632b2494eSpatrick (1 & 0xff) << 0 | 162732b2494eSpatrick (3 & 0x3) << 8 | 162832b2494eSpatrick (2 & 0x3) << 10 | 162932b2494eSpatrick (2 & 0x3) << 12 163032b2494eSpatrick ); 163132b2494eSpatrick params->scan_params.channel_num = htole32( 163232b2494eSpatrick (1 & 0xffff) << 0 163332b2494eSpatrick ); 163432b2494eSpatrick #endif 163532b2494eSpatrick 163632b2494eSpatrick bwfm_fwvar_var_set_data(sc, "escan", params, params_size); 163732b2494eSpatrick free(params, M_TEMP, params_size); 163832b2494eSpatrick } 163932b2494eSpatrick 1640c11618f6Spatrick struct mbuf * 1641c11618f6Spatrick bwfm_newbuf(void) 1642c11618f6Spatrick { 1643c11618f6Spatrick struct mbuf *m; 1644c11618f6Spatrick 1645c11618f6Spatrick MGETHDR(m, M_DONTWAIT, MT_DATA); 1646c11618f6Spatrick if (m == NULL) 1647c11618f6Spatrick return (NULL); 1648c11618f6Spatrick 1649c11618f6Spatrick MCLGET(m, M_DONTWAIT); 1650c11618f6Spatrick if (!(m->m_flags & M_EXT)) { 1651c11618f6Spatrick m_freem(m); 1652c11618f6Spatrick return (NULL); 1653c11618f6Spatrick } 1654c11618f6Spatrick 1655c11618f6Spatrick m->m_len = m->m_pkthdr.len = MCLBYTES; 1656c11618f6Spatrick 1657c11618f6Spatrick return (m); 1658c11618f6Spatrick } 1659c11618f6Spatrick 166032b2494eSpatrick void 1661f37fc236Spatrick bwfm_rx(struct bwfm_softc *sc, struct mbuf *m) 166232b2494eSpatrick { 166332b2494eSpatrick struct ieee80211com *ic = &sc->sc_ic; 166432b2494eSpatrick struct ifnet *ifp = &ic->ic_if; 1665f37fc236Spatrick struct bwfm_event *e = mtod(m, struct bwfm_event *); 166632b2494eSpatrick struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 1667c11618f6Spatrick struct ieee80211_node *ni; 166832b2494eSpatrick 1669f37fc236Spatrick if (m->m_len >= sizeof(e->ehdr) && 167032b2494eSpatrick ntohs(e->ehdr.ether_type) == BWFM_ETHERTYPE_LINK_CTL && 167132b2494eSpatrick memcmp(BWFM_BRCM_OUI, e->hdr.oui, sizeof(e->hdr.oui)) == 0 && 1672010fb2f1Spatrick ntohs(e->hdr.usr_subtype) == BWFM_BRCM_SUBTYPE_EVENT) { 1673f4e8af02Spatrick bwfm_rx_event(sc, m); 1674010fb2f1Spatrick return; 1675010fb2f1Spatrick } 1676010fb2f1Spatrick 1677010fb2f1Spatrick /* Drop network packets if we are not in RUN state. */ 1678010fb2f1Spatrick if (ic->ic_state != IEEE80211_S_RUN) { 1679010fb2f1Spatrick m_freem(m); 1680010fb2f1Spatrick return; 1681010fb2f1Spatrick } 168232b2494eSpatrick 168363498aa8Spatrick if ((ic->ic_flags & IEEE80211_F_RSNON) && 1684f37fc236Spatrick m->m_len >= sizeof(e->ehdr) && 168563498aa8Spatrick ntohs(e->ehdr.ether_type) == ETHERTYPE_PAE) { 168663498aa8Spatrick ifp->if_ipackets++; 168763498aa8Spatrick #if NBPFILTER > 0 168863498aa8Spatrick if (ifp->if_bpf) 168963498aa8Spatrick bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN); 169063498aa8Spatrick #endif 1691c11618f6Spatrick #ifndef IEEE80211_STA_ONLY 1692c11618f6Spatrick if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 1693c11618f6Spatrick ni = ieee80211_find_node(ic, 1694c11618f6Spatrick (void *)&e->ehdr.ether_shost); 1695c11618f6Spatrick if (ni == NULL) { 1696c11618f6Spatrick m_free(m); 1697c11618f6Spatrick return; 1698c11618f6Spatrick } 1699c11618f6Spatrick } else 1700c11618f6Spatrick #endif 1701c11618f6Spatrick ni = ic->ic_bss; 1702c11618f6Spatrick ieee80211_eapol_key_input(ic, m, ni); 170363498aa8Spatrick } else { 170432b2494eSpatrick ml_enqueue(&ml, m); 170532b2494eSpatrick if_input(ifp, &ml); 170632b2494eSpatrick } 170763498aa8Spatrick } 170832b2494eSpatrick 1709c11618f6Spatrick #ifndef IEEE80211_STA_ONLY 1710c11618f6Spatrick void 1711c11618f6Spatrick bwfm_rx_auth_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len) 1712c11618f6Spatrick { 1713c11618f6Spatrick struct ieee80211com *ic = &sc->sc_ic; 1714c11618f6Spatrick struct ifnet *ifp = &ic->ic_if; 1715c11618f6Spatrick struct ieee80211_rxinfo rxi; 1716c11618f6Spatrick struct ieee80211_frame *wh; 1717c11618f6Spatrick struct ieee80211_node *ni; 1718c11618f6Spatrick struct mbuf *m; 1719c11618f6Spatrick uint32_t pktlen, ieslen; 1720c11618f6Spatrick 1721c11618f6Spatrick /* Build a fake beacon frame to let net80211 do all the parsing. */ 1722c11618f6Spatrick ieslen = betoh32(e->msg.datalen); 1723c11618f6Spatrick pktlen = sizeof(*wh) + ieslen + 6; 1724c11618f6Spatrick if (pktlen > MCLBYTES) 1725c11618f6Spatrick return; 1726c11618f6Spatrick m = bwfm_newbuf(); 1727c11618f6Spatrick if (m == NULL) 1728c11618f6Spatrick return; 1729c11618f6Spatrick wh = mtod(m, struct ieee80211_frame *); 1730c11618f6Spatrick wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 1731c11618f6Spatrick IEEE80211_FC0_SUBTYPE_AUTH; 1732c11618f6Spatrick wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 1733c11618f6Spatrick *(uint16_t *)wh->i_dur = 0; 1734c11618f6Spatrick IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr); 1735c11618f6Spatrick IEEE80211_ADDR_COPY(wh->i_addr2, &e->msg.addr); 1736c11618f6Spatrick IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid); 1737c11618f6Spatrick *(uint16_t *)wh->i_seq = 0; 1738c11618f6Spatrick ((uint16_t *)(&wh[1]))[0] = IEEE80211_AUTH_ALG_OPEN; 1739c11618f6Spatrick ((uint16_t *)(&wh[1]))[1] = IEEE80211_AUTH_OPEN_REQUEST; 1740c11618f6Spatrick ((uint16_t *)(&wh[1]))[2] = 0; 1741c11618f6Spatrick 1742c11618f6Spatrick /* Finalize mbuf. */ 1743c11618f6Spatrick m->m_pkthdr.len = m->m_len = pktlen; 1744c11618f6Spatrick ni = ieee80211_find_node(ic, wh->i_addr2); 1745c11618f6Spatrick if (ni == NULL) 1746c11618f6Spatrick ni = ieee80211_alloc_node(ic, wh->i_addr2); 1747c11618f6Spatrick if (ni == NULL) { 1748c11618f6Spatrick m_free(m); 1749c11618f6Spatrick return; 1750c11618f6Spatrick } 1751c11618f6Spatrick ni->ni_chan = &ic->ic_channels[0]; 1752c11618f6Spatrick rxi.rxi_flags = 0; 1753c11618f6Spatrick rxi.rxi_rssi = 0; 1754c11618f6Spatrick rxi.rxi_tstamp = 0; 1755c11618f6Spatrick ieee80211_input(ifp, m, ni, &rxi); 1756c11618f6Spatrick } 1757c11618f6Spatrick 1758c11618f6Spatrick void 1759c11618f6Spatrick bwfm_rx_assoc_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len, 1760c11618f6Spatrick int reassoc) 1761c11618f6Spatrick { 1762c11618f6Spatrick struct ieee80211com *ic = &sc->sc_ic; 1763c11618f6Spatrick struct ifnet *ifp = &ic->ic_if; 1764c11618f6Spatrick struct ieee80211_rxinfo rxi; 1765c11618f6Spatrick struct ieee80211_frame *wh; 1766c11618f6Spatrick struct ieee80211_node *ni; 1767c11618f6Spatrick struct mbuf *m; 1768c11618f6Spatrick uint32_t pktlen, ieslen; 1769c11618f6Spatrick 1770c11618f6Spatrick /* Build a fake beacon frame to let net80211 do all the parsing. */ 1771c11618f6Spatrick ieslen = betoh32(e->msg.datalen); 1772c11618f6Spatrick pktlen = sizeof(*wh) + ieslen + 4; 1773c11618f6Spatrick if (reassoc) 1774c11618f6Spatrick pktlen += IEEE80211_ADDR_LEN; 1775c11618f6Spatrick if (pktlen > MCLBYTES) 1776c11618f6Spatrick return; 1777c11618f6Spatrick m = bwfm_newbuf(); 1778c11618f6Spatrick if (m == NULL) 1779c11618f6Spatrick return; 1780c11618f6Spatrick wh = mtod(m, struct ieee80211_frame *); 1781c11618f6Spatrick wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT; 1782c11618f6Spatrick if (reassoc) 1783c11618f6Spatrick wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_REASSOC_REQ; 1784c11618f6Spatrick else 1785c11618f6Spatrick wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_ASSOC_REQ; 1786c11618f6Spatrick wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 1787c11618f6Spatrick *(uint16_t *)wh->i_dur = 0; 1788c11618f6Spatrick IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr); 1789c11618f6Spatrick IEEE80211_ADDR_COPY(wh->i_addr2, &e->msg.addr); 1790c11618f6Spatrick IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid); 1791c11618f6Spatrick *(uint16_t *)wh->i_seq = 0; 1792c11618f6Spatrick ((uint16_t *)(&wh[1]))[0] = IEEE80211_CAPINFO_ESS; /* XXX */ 1793c11618f6Spatrick ((uint16_t *)(&wh[1]))[1] = 100; /* XXX */ 1794c11618f6Spatrick if (reassoc) { 1795c11618f6Spatrick memset(&wh[1] + 4, 0, IEEE80211_ADDR_LEN); 1796c11618f6Spatrick memcpy(((uint8_t *)&wh[1]) + 4 + IEEE80211_ADDR_LEN, 1797c11618f6Spatrick &e[1], ieslen); 1798c11618f6Spatrick } else 1799c11618f6Spatrick memcpy(((uint8_t *)&wh[1]) + 4, &e[1], ieslen); 1800c11618f6Spatrick 1801c11618f6Spatrick /* Finalize mbuf. */ 1802c11618f6Spatrick m->m_pkthdr.len = m->m_len = pktlen; 1803c11618f6Spatrick ni = ieee80211_find_node(ic, wh->i_addr2); 1804c11618f6Spatrick if (ni == NULL) 1805c11618f6Spatrick ni = ieee80211_alloc_node(ic, wh->i_addr2); 1806c11618f6Spatrick if (ni == NULL) { 1807c11618f6Spatrick m_free(m); 1808c11618f6Spatrick return; 1809c11618f6Spatrick } 1810c11618f6Spatrick ni->ni_chan = &ic->ic_channels[0]; 1811c11618f6Spatrick rxi.rxi_flags = 0; 1812c11618f6Spatrick rxi.rxi_rssi = 0; 1813c11618f6Spatrick rxi.rxi_tstamp = 0; 1814c11618f6Spatrick ieee80211_input(ifp, m, ni, &rxi); 1815c11618f6Spatrick } 1816c11618f6Spatrick 1817c11618f6Spatrick void 1818c11618f6Spatrick bwfm_rx_deauth_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len) 1819c11618f6Spatrick { 1820c11618f6Spatrick bwfm_rx_leave_ind(sc, e, len, IEEE80211_FC0_SUBTYPE_DEAUTH); 1821c11618f6Spatrick } 1822c11618f6Spatrick 1823c11618f6Spatrick void 1824c11618f6Spatrick bwfm_rx_disassoc_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len) 1825c11618f6Spatrick { 1826c11618f6Spatrick bwfm_rx_leave_ind(sc, e, len, IEEE80211_FC0_SUBTYPE_DISASSOC); 1827c11618f6Spatrick } 1828c11618f6Spatrick 1829c11618f6Spatrick void 1830c11618f6Spatrick bwfm_rx_leave_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len, 1831c11618f6Spatrick int subtype) 1832c11618f6Spatrick { 1833c11618f6Spatrick struct ieee80211com *ic = &sc->sc_ic; 1834c11618f6Spatrick struct ifnet *ifp = &ic->ic_if; 1835c11618f6Spatrick struct ieee80211_rxinfo rxi; 1836c11618f6Spatrick struct ieee80211_frame *wh; 1837c11618f6Spatrick struct ieee80211_node *ni; 1838c11618f6Spatrick struct mbuf *m; 1839c11618f6Spatrick uint32_t pktlen; 1840c11618f6Spatrick 1841c11618f6Spatrick /* Build a fake beacon frame to let net80211 do all the parsing. */ 1842c11618f6Spatrick pktlen = sizeof(*wh) + 2; 1843c11618f6Spatrick if (pktlen > MCLBYTES) 1844c11618f6Spatrick return; 1845c11618f6Spatrick m = bwfm_newbuf(); 1846c11618f6Spatrick if (m == NULL) 1847c11618f6Spatrick return; 1848c11618f6Spatrick wh = mtod(m, struct ieee80211_frame *); 1849c11618f6Spatrick wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 1850c11618f6Spatrick subtype; 1851c11618f6Spatrick wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 1852c11618f6Spatrick *(uint16_t *)wh->i_dur = 0; 1853c11618f6Spatrick IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr); 1854c11618f6Spatrick IEEE80211_ADDR_COPY(wh->i_addr2, &e->msg.addr); 1855c11618f6Spatrick IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid); 1856c11618f6Spatrick *(uint16_t *)wh->i_seq = 0; 1857c11618f6Spatrick memset(&wh[1], 0, 2); 1858c11618f6Spatrick 1859c11618f6Spatrick /* Finalize mbuf. */ 1860c11618f6Spatrick m->m_pkthdr.len = m->m_len = pktlen; 1861c11618f6Spatrick ni = ieee80211_find_node(ic, wh->i_addr2); 1862c11618f6Spatrick if (ni == NULL) { 1863c11618f6Spatrick m_free(m); 1864c11618f6Spatrick return; 1865c11618f6Spatrick } 1866c11618f6Spatrick rxi.rxi_flags = 0; 1867c11618f6Spatrick rxi.rxi_rssi = 0; 1868c11618f6Spatrick rxi.rxi_tstamp = 0; 1869c11618f6Spatrick ieee80211_input(ifp, m, ni, &rxi); 1870c11618f6Spatrick } 1871c11618f6Spatrick #endif 1872c11618f6Spatrick 187332b2494eSpatrick void 1874f4e8af02Spatrick bwfm_rx_event(struct bwfm_softc *sc, struct mbuf *m) 1875f4e8af02Spatrick { 1876f4e8af02Spatrick struct bwfm_cmd_mbuf cmd; 1877f4e8af02Spatrick 1878f4e8af02Spatrick cmd.m = m; 1879f4e8af02Spatrick bwfm_do_async(sc, bwfm_rx_event_cb, &cmd, sizeof(cmd)); 1880f4e8af02Spatrick } 1881f4e8af02Spatrick 1882f4e8af02Spatrick void 1883f4e8af02Spatrick bwfm_rx_event_cb(struct bwfm_softc *sc, void *arg) 188432b2494eSpatrick { 188532b2494eSpatrick struct ieee80211com *ic = &sc->sc_ic; 188663498aa8Spatrick struct ifnet *ifp = &ic->ic_if; 1887f4e8af02Spatrick struct bwfm_cmd_mbuf *cmd = arg; 1888f4e8af02Spatrick struct mbuf *m = cmd->m; 1889f4e8af02Spatrick struct bwfm_event *e = mtod(m, void *); 1890f4e8af02Spatrick size_t len = m->m_len; 189132b2494eSpatrick 1892f4e8af02Spatrick if (ntohl(e->msg.event_type) >= BWFM_E_LAST) { 1893f4e8af02Spatrick m_freem(m); 189432b2494eSpatrick return; 1895f4e8af02Spatrick } 189632b2494eSpatrick 189732b2494eSpatrick switch (ntohl(e->msg.event_type)) { 189832b2494eSpatrick case BWFM_E_ESCAN_RESULT: { 1899f4e8af02Spatrick struct bwfm_escan_results *res = (void *)&e[1]; 190032b2494eSpatrick struct bwfm_bss_info *bss; 190132b2494eSpatrick int i; 190232b2494eSpatrick if (ntohl(e->msg.status) != BWFM_E_STATUS_PARTIAL) { 190363498aa8Spatrick ieee80211_end_scan(ifp); 190432b2494eSpatrick break; 190532b2494eSpatrick } 190632b2494eSpatrick len -= sizeof(*e); 190732b2494eSpatrick if (len < sizeof(*res) || len < letoh32(res->buflen)) { 190832b2494eSpatrick printf("%s: results too small\n", DEVNAME(sc)); 1909f4e8af02Spatrick m_freem(m); 191032b2494eSpatrick return; 191132b2494eSpatrick } 191232b2494eSpatrick len -= sizeof(*res); 191332b2494eSpatrick if (len < letoh16(res->bss_count) * sizeof(struct bwfm_bss_info)) { 191432b2494eSpatrick printf("%s: results too small\n", DEVNAME(sc)); 1915f4e8af02Spatrick m_freem(m); 191632b2494eSpatrick return; 191732b2494eSpatrick } 191832b2494eSpatrick bss = &res->bss_info[0]; 191932b2494eSpatrick for (i = 0; i < letoh16(res->bss_count); i++) { 192032b2494eSpatrick bwfm_scan_node(sc, &res->bss_info[i], len); 192132b2494eSpatrick len -= sizeof(*bss) + letoh32(bss->length); 192232b2494eSpatrick bss = (void *)((char *)bss) + letoh32(bss->length); 192332b2494eSpatrick if (len <= 0) 192432b2494eSpatrick break; 192532b2494eSpatrick } 192632b2494eSpatrick break; 192732b2494eSpatrick } 192863498aa8Spatrick case BWFM_E_SET_SSID: 19297a818b26Spatrick if (ntohl(e->msg.status) != BWFM_E_STATUS_SUCCESS) 19307a818b26Spatrick ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 19317a818b26Spatrick break; 19327a818b26Spatrick case BWFM_E_AUTH: 1933750cbd98Spatrick if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS && 1934750cbd98Spatrick ic->ic_state == IEEE80211_S_AUTH) 19357a818b26Spatrick ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1); 193663498aa8Spatrick else 193763498aa8Spatrick ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 193863498aa8Spatrick break; 193963498aa8Spatrick case BWFM_E_ASSOC: 1940750cbd98Spatrick if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS && 1941750cbd98Spatrick ic->ic_state == IEEE80211_S_ASSOC) 19427a818b26Spatrick ieee80211_new_state(ic, IEEE80211_S_RUN, -1); 194363498aa8Spatrick else 194463498aa8Spatrick ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 194563498aa8Spatrick break; 1946750cbd98Spatrick case BWFM_E_DEAUTH: 1947750cbd98Spatrick case BWFM_E_DISASSOC: 1948750cbd98Spatrick ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 1949750cbd98Spatrick break; 195063498aa8Spatrick case BWFM_E_LINK: 195163498aa8Spatrick if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS && 195263498aa8Spatrick ntohl(e->msg.reason) == 0) 195363498aa8Spatrick break; 195463498aa8Spatrick /* Link status has changed */ 195563498aa8Spatrick ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 195663498aa8Spatrick break; 1957c11618f6Spatrick #ifndef IEEE80211_STA_ONLY 1958c11618f6Spatrick case BWFM_E_AUTH_IND: 1959c11618f6Spatrick bwfm_rx_auth_ind(sc, e, len); 1960c11618f6Spatrick break; 1961c11618f6Spatrick case BWFM_E_ASSOC_IND: 1962c11618f6Spatrick bwfm_rx_assoc_ind(sc, e, len, 0); 1963c11618f6Spatrick break; 1964c11618f6Spatrick case BWFM_E_REASSOC_IND: 1965c11618f6Spatrick bwfm_rx_assoc_ind(sc, e, len, 1); 1966c11618f6Spatrick break; 1967c11618f6Spatrick case BWFM_E_DEAUTH_IND: 1968c11618f6Spatrick bwfm_rx_deauth_ind(sc, e, len); 1969c11618f6Spatrick break; 1970c11618f6Spatrick case BWFM_E_DISASSOC_IND: 1971c11618f6Spatrick bwfm_rx_disassoc_ind(sc, e, len); 1972c11618f6Spatrick break; 1973c11618f6Spatrick #endif 197432b2494eSpatrick default: 1975cd99bb20Spatrick DPRINTF(("%s: len %lu datalen %u code %u status %u" 1976cd99bb20Spatrick " reason %u\n", __func__, len, ntohl(e->msg.datalen), 197732b2494eSpatrick ntohl(e->msg.event_type), ntohl(e->msg.status), 1978cd99bb20Spatrick ntohl(e->msg.reason))); 197932b2494eSpatrick break; 198032b2494eSpatrick } 1981f4e8af02Spatrick 1982f4e8af02Spatrick m_freem(m); 198332b2494eSpatrick } 198432b2494eSpatrick 198532b2494eSpatrick void 198632b2494eSpatrick bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_info *bss, size_t len) 198732b2494eSpatrick { 198832b2494eSpatrick struct ieee80211com *ic = &sc->sc_ic; 198963498aa8Spatrick struct ifnet *ifp = &ic->ic_if; 199063498aa8Spatrick struct ieee80211_frame *wh; 199132b2494eSpatrick struct ieee80211_node *ni; 19928b2458cfSpatrick struct ieee80211_rxinfo rxi; 19938b2458cfSpatrick struct ieee80211_channel *bss_chan; 199463498aa8Spatrick struct mbuf *m; 199563498aa8Spatrick uint32_t pktlen, ieslen; 199663498aa8Spatrick uint16_t iesoff; 19978b2458cfSpatrick int chanidx; 199832b2494eSpatrick 199963498aa8Spatrick iesoff = letoh16(bss->ie_offset); 200063498aa8Spatrick ieslen = letoh32(bss->ie_length); 200163498aa8Spatrick if (ieslen > len - iesoff) 200263498aa8Spatrick return; 200363498aa8Spatrick 200463498aa8Spatrick /* Build a fake beacon frame to let net80211 do all the parsing. */ 200563498aa8Spatrick pktlen = sizeof(*wh) + ieslen + 12; 2006c11618f6Spatrick if (pktlen > MCLBYTES) 200763498aa8Spatrick return; 2008c11618f6Spatrick m = bwfm_newbuf(); 2009c11618f6Spatrick if (m == NULL) 201063498aa8Spatrick return; 201163498aa8Spatrick wh = mtod(m, struct ieee80211_frame *); 201263498aa8Spatrick wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 201363498aa8Spatrick IEEE80211_FC0_SUBTYPE_BEACON; 201463498aa8Spatrick wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 201563498aa8Spatrick *(uint16_t *)wh->i_dur = 0; 201663498aa8Spatrick IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr); 201763498aa8Spatrick IEEE80211_ADDR_COPY(wh->i_addr2, bss->bssid); 201863498aa8Spatrick IEEE80211_ADDR_COPY(wh->i_addr3, bss->bssid); 201963498aa8Spatrick *(uint16_t *)wh->i_seq = 0; 202063498aa8Spatrick memset(&wh[1], 0, 12); 202163498aa8Spatrick ((uint16_t *)(&wh[1]))[4] = bss->beacon_period; 202263498aa8Spatrick ((uint16_t *)(&wh[1]))[5] = bss->capability; 202363498aa8Spatrick memcpy(((uint8_t *)&wh[1]) + 12, ((uint8_t *)bss) + iesoff, ieslen); 202463498aa8Spatrick 202563498aa8Spatrick /* Finalize mbuf. */ 202663498aa8Spatrick m->m_pkthdr.len = m->m_len = pktlen; 202763498aa8Spatrick ni = ieee80211_find_rxnode(ic, wh); 20288b2458cfSpatrick /* 20298b2458cfSpatrick * We may switch ic_bss's channel during scans. 20308b2458cfSpatrick * Record the current channel so we can restore it later. 20318b2458cfSpatrick */ 20328b2458cfSpatrick bss_chan = NULL; 20338b2458cfSpatrick if (ni == ic->ic_bss) 20348b2458cfSpatrick bss_chan = ni->ni_chan; 20358b2458cfSpatrick /* Channel mask equals IEEE80211_CHAN_MAX */ 20368b2458cfSpatrick chanidx = bwfm_spec2chan(sc, letoh32(bss->chanspec)); 20378b2458cfSpatrick ni->ni_chan = &ic->ic_channels[chanidx]; 20388b2458cfSpatrick /* Supply RSSI */ 203963498aa8Spatrick rxi.rxi_flags = 0; 204063498aa8Spatrick rxi.rxi_rssi = letoh32(bss->rssi); 204163498aa8Spatrick rxi.rxi_tstamp = 0; 204263498aa8Spatrick ieee80211_input(ifp, m, ni, &rxi); 20438b2458cfSpatrick /* Restore channel */ 20448b2458cfSpatrick if (bss_chan) 20458b2458cfSpatrick ni->ni_chan = bss_chan; 204663498aa8Spatrick /* Node is no longer needed. */ 204763498aa8Spatrick ieee80211_release_node(ic, ni); 204863498aa8Spatrick } 204963498aa8Spatrick 205063498aa8Spatrick void 205163498aa8Spatrick bwfm_task(void *arg) 205263498aa8Spatrick { 205363498aa8Spatrick struct bwfm_softc *sc = arg; 205463498aa8Spatrick struct bwfm_host_cmd_ring *ring = &sc->sc_cmdq; 205563498aa8Spatrick struct bwfm_host_cmd *cmd; 205663498aa8Spatrick int s; 205763498aa8Spatrick 205863498aa8Spatrick s = splsoftnet(); 205963498aa8Spatrick while (ring->next != ring->cur) { 206063498aa8Spatrick cmd = &ring->cmd[ring->next]; 206163498aa8Spatrick splx(s); 206263498aa8Spatrick cmd->cb(sc, cmd->data); 206363498aa8Spatrick s = splsoftnet(); 206463498aa8Spatrick ring->queued--; 206563498aa8Spatrick ring->next = (ring->next + 1) % BWFM_HOST_CMD_RING_COUNT; 206663498aa8Spatrick } 206763498aa8Spatrick splx(s); 206863498aa8Spatrick } 206963498aa8Spatrick 207063498aa8Spatrick void 207163498aa8Spatrick bwfm_do_async(struct bwfm_softc *sc, 207263498aa8Spatrick void (*cb)(struct bwfm_softc *, void *), void *arg, int len) 207363498aa8Spatrick { 207463498aa8Spatrick struct bwfm_host_cmd_ring *ring = &sc->sc_cmdq; 207563498aa8Spatrick struct bwfm_host_cmd *cmd; 207663498aa8Spatrick int s; 207763498aa8Spatrick 207863498aa8Spatrick s = splsoftnet(); 2079f4e8af02Spatrick if (ring->queued >= BWFM_HOST_CMD_RING_COUNT) { 2080f4e8af02Spatrick splx(s); 2081f4e8af02Spatrick return; 2082f4e8af02Spatrick } 208363498aa8Spatrick cmd = &ring->cmd[ring->cur]; 208463498aa8Spatrick cmd->cb = cb; 208563498aa8Spatrick KASSERT(len <= sizeof(cmd->data)); 208663498aa8Spatrick memcpy(cmd->data, arg, len); 208763498aa8Spatrick ring->cur = (ring->cur + 1) % BWFM_HOST_CMD_RING_COUNT; 2088f4e8af02Spatrick ring->queued++; 208963498aa8Spatrick task_add(sc->sc_taskq, &sc->sc_task); 209063498aa8Spatrick splx(s); 209163498aa8Spatrick } 209263498aa8Spatrick 209363498aa8Spatrick int 209463498aa8Spatrick bwfm_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, 209563498aa8Spatrick int type, int arg1, int arg2) 209663498aa8Spatrick { 209763498aa8Spatrick #ifdef BWFM_DEBUG 209863498aa8Spatrick struct bwfm_softc *sc = ic->ic_softc; 209963498aa8Spatrick DPRINTF(("%s: %s\n", DEVNAME(sc), __func__)); 210063498aa8Spatrick #endif 210163498aa8Spatrick return 0; 210263498aa8Spatrick } 210363498aa8Spatrick 210463498aa8Spatrick int 210563498aa8Spatrick bwfm_set_key(struct ieee80211com *ic, struct ieee80211_node *ni, 210663498aa8Spatrick struct ieee80211_key *k) 210763498aa8Spatrick { 210863498aa8Spatrick struct bwfm_softc *sc = ic->ic_softc; 210963498aa8Spatrick struct bwfm_cmd_key cmd; 211063498aa8Spatrick 211163498aa8Spatrick cmd.ni = ni; 211263498aa8Spatrick cmd.k = k; 211363498aa8Spatrick bwfm_do_async(sc, bwfm_set_key_cb, &cmd, sizeof(cmd)); 211463498aa8Spatrick return 0; 211563498aa8Spatrick } 211663498aa8Spatrick 211763498aa8Spatrick void 211863498aa8Spatrick bwfm_set_key_cb(struct bwfm_softc *sc, void *arg) 211963498aa8Spatrick { 212063498aa8Spatrick struct bwfm_cmd_key *cmd = arg; 212163498aa8Spatrick struct ieee80211_key *k = cmd->k; 212263498aa8Spatrick struct ieee80211_node *ni = cmd->ni; 212363498aa8Spatrick struct bwfm_wsec_key key; 212463498aa8Spatrick uint32_t wsec, wsec_enable; 212563498aa8Spatrick int ext_key = 0; 212663498aa8Spatrick 212763498aa8Spatrick if ((k->k_flags & IEEE80211_KEY_GROUP) == 0 && 212863498aa8Spatrick k->k_cipher != IEEE80211_CIPHER_WEP40 && 212963498aa8Spatrick k->k_cipher != IEEE80211_CIPHER_WEP104) 213063498aa8Spatrick ext_key = 1; 213163498aa8Spatrick 213263498aa8Spatrick memset(&key, 0, sizeof(key)); 2133c11618f6Spatrick if (ext_key && !IEEE80211_IS_MULTICAST(ni->ni_macaddr)) 2134c11618f6Spatrick memcpy(key.ea, ni->ni_macaddr, sizeof(key.ea)); 213563498aa8Spatrick key.index = htole32(k->k_id); 213663498aa8Spatrick key.len = htole32(k->k_len); 213763498aa8Spatrick memcpy(key.data, k->k_key, sizeof(key.data)); 213863498aa8Spatrick if (!ext_key) 213963498aa8Spatrick key.flags = htole32(BWFM_WSEC_PRIMARY_KEY); 214063498aa8Spatrick 214163498aa8Spatrick switch (k->k_cipher) { 214263498aa8Spatrick case IEEE80211_CIPHER_WEP40: 214363498aa8Spatrick key.algo = htole32(BWFM_CRYPTO_ALGO_WEP1); 214463498aa8Spatrick wsec_enable = BWFM_WSEC_WEP; 214563498aa8Spatrick break; 214663498aa8Spatrick case IEEE80211_CIPHER_WEP104: 214763498aa8Spatrick key.algo = htole32(BWFM_CRYPTO_ALGO_WEP128); 214863498aa8Spatrick wsec_enable = BWFM_WSEC_WEP; 214963498aa8Spatrick break; 215063498aa8Spatrick case IEEE80211_CIPHER_TKIP: 215163498aa8Spatrick key.algo = htole32(BWFM_CRYPTO_ALGO_TKIP); 215263498aa8Spatrick wsec_enable = BWFM_WSEC_TKIP; 215363498aa8Spatrick break; 215463498aa8Spatrick case IEEE80211_CIPHER_CCMP: 215563498aa8Spatrick key.algo = htole32(BWFM_CRYPTO_ALGO_AES_CCM); 215663498aa8Spatrick wsec_enable = BWFM_WSEC_AES; 215763498aa8Spatrick break; 215863498aa8Spatrick default: 215963498aa8Spatrick printf("%s: cipher %x not supported\n", DEVNAME(sc), 216063498aa8Spatrick k->k_cipher); 216163498aa8Spatrick return; 216263498aa8Spatrick } 216363498aa8Spatrick 216463498aa8Spatrick bwfm_fwvar_var_set_data(sc, "wsec_key", &key, sizeof(key)); 216563498aa8Spatrick bwfm_fwvar_var_get_int(sc, "wsec", &wsec); 216663498aa8Spatrick wsec |= wsec_enable; 216763498aa8Spatrick bwfm_fwvar_var_set_int(sc, "wsec", wsec); 216863498aa8Spatrick } 216963498aa8Spatrick 217063498aa8Spatrick void 217163498aa8Spatrick bwfm_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni, 217263498aa8Spatrick struct ieee80211_key *k) 217363498aa8Spatrick { 217463498aa8Spatrick struct bwfm_softc *sc = ic->ic_softc; 217563498aa8Spatrick struct bwfm_cmd_key cmd; 217663498aa8Spatrick 217763498aa8Spatrick cmd.ni = ni; 217863498aa8Spatrick cmd.k = k; 217963498aa8Spatrick bwfm_do_async(sc, bwfm_delete_key_cb, &cmd, sizeof(cmd)); 218063498aa8Spatrick } 218163498aa8Spatrick 218263498aa8Spatrick void 218363498aa8Spatrick bwfm_delete_key_cb(struct bwfm_softc *sc, void *arg) 218463498aa8Spatrick { 218563498aa8Spatrick struct bwfm_cmd_key *cmd = arg; 218663498aa8Spatrick struct ieee80211_key *k = cmd->k; 218763498aa8Spatrick struct bwfm_wsec_key key; 218863498aa8Spatrick 218963498aa8Spatrick memset(&key, 0, sizeof(key)); 219063498aa8Spatrick key.index = htole32(k->k_id); 219163498aa8Spatrick key.flags = htole32(BWFM_WSEC_PRIMARY_KEY); 219263498aa8Spatrick bwfm_fwvar_var_set_data(sc, "wsec_key", &key, sizeof(key)); 219363498aa8Spatrick } 219463498aa8Spatrick 219563498aa8Spatrick int 219663498aa8Spatrick bwfm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 219763498aa8Spatrick { 219863498aa8Spatrick struct bwfm_softc *sc = ic->ic_softc; 21995d1a01feSstsp struct ifnet *ifp = &ic->ic_if; 220063498aa8Spatrick int s; 220163498aa8Spatrick 220263498aa8Spatrick s = splnet(); 220363498aa8Spatrick 220463498aa8Spatrick switch (nstate) { 220563498aa8Spatrick case IEEE80211_S_SCAN: 220663498aa8Spatrick bwfm_scan(sc); 22075d1a01feSstsp if (ifp->if_flags & IFF_DEBUG) 22085d1a01feSstsp printf("%s: %s -> %s\n", DEVNAME(sc), 22095d1a01feSstsp ieee80211_state_name[ic->ic_state], 22105d1a01feSstsp ieee80211_state_name[nstate]); 221163498aa8Spatrick ic->ic_state = nstate; 221263498aa8Spatrick splx(s); 2213f4e8af02Spatrick return 0; 221463498aa8Spatrick case IEEE80211_S_AUTH: 221563498aa8Spatrick ic->ic_bss->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE; 221663498aa8Spatrick bwfm_connect(sc); 22175d1a01feSstsp if (ifp->if_flags & IFF_DEBUG) 22185d1a01feSstsp printf("%s: %s -> %s\n", DEVNAME(sc), 22195d1a01feSstsp ieee80211_state_name[ic->ic_state], 22205d1a01feSstsp ieee80211_state_name[nstate]); 22215d1a01feSstsp ic->ic_state = nstate; 222263498aa8Spatrick if (ic->ic_flags & IEEE80211_F_RSNON) 222363498aa8Spatrick ic->ic_bss->ni_rsn_supp_state = RSNA_SUPP_PTKSTART; 222463498aa8Spatrick splx(s); 2225f4e8af02Spatrick return 0; 2226c11618f6Spatrick #ifndef IEEE80211_STA_ONLY 2227c11618f6Spatrick case IEEE80211_S_RUN: 2228c11618f6Spatrick if (ic->ic_opmode == IEEE80211_M_HOSTAP) 2229c11618f6Spatrick bwfm_hostap(sc); 2230c11618f6Spatrick break; 2231c11618f6Spatrick #endif 223263498aa8Spatrick default: 223363498aa8Spatrick break; 223463498aa8Spatrick } 2235f4e8af02Spatrick sc->sc_newstate(ic, nstate, arg); 223663498aa8Spatrick splx(s); 2237f4e8af02Spatrick return 0; 223832b2494eSpatrick } 2239