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