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