LCOV - code coverage report
Current view: top level - dev/ic - bwfm.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1310 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 71 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13