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