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