Bug Summary

File:dev/ic/bwfm.c
Warning:line 1183, column 3
Value stored to 'mpnum' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name bwfm.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -target-feature +retpoline-external-thunk -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/legacy-dpm -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu13 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/inc -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc/pmfw_if -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D SUSPEND -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/scan/2024-01-11-110808-61670-1 -x c /usr/src/sys/dev/ic/bwfm.c
1/* $OpenBSD: bwfm.c,v 1.110 2023/10/09 21:49:34 kettenis Exp $ */
2/*
3 * Copyright (c) 2010-2016 Broadcom Corporation
4 * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include "bpfilter.h"
20
21#include <sys/param.h>
22#include <sys/systm.h>
23#include <sys/buf.h>
24#include <sys/kernel.h>
25#include <sys/malloc.h>
26#include <sys/device.h>
27#include <sys/queue.h>
28#include <sys/socket.h>
29#include <sys/sockio.h>
30
31#if defined(__HAVE_FDT)
32#include <machine/fdt.h>
33#include <dev/ofw/openfirm.h>
34#endif
35
36#if NBPFILTER1 > 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 { ; } while (0) do { if (bwfm_debug > 0) printf x; } while (0)
54#define DPRINTFN(n, x)do { ; } while (0) do { if (bwfm_debug >= (n)) printf x; } while (0)
55static int bwfm_debug = 1;
56#else
57#define DPRINTF(x)do { ; } while (0) do { ; } while (0)
58#define DPRINTFN(n, x)do { ; } while (0) do { ; } while (0)
59#endif
60
61#define DEVNAME(sc)((sc)->sc_dev.dv_xname) ((sc)->sc_dev.dv_xname)
62
63void bwfm_start(struct ifnet *);
64void bwfm_init(struct ifnet *);
65void bwfm_stop(struct ifnet *);
66void bwfm_iff(struct bwfm_softc *);
67void bwfm_watchdog(struct ifnet *);
68void bwfm_update_node(void *, struct ieee80211_node *);
69void bwfm_update_nodes(struct bwfm_softc *);
70int bwfm_ioctl(struct ifnet *, u_long, caddr_t);
71int bwfm_media_change(struct ifnet *);
72
73void bwfm_init_board_type(struct bwfm_softc *);
74void bwfm_process_blob(struct bwfm_softc *, char *, u_char **, size_t *);
75
76int bwfm_chip_attach(struct bwfm_softc *);
77void bwfm_chip_detach(struct bwfm_softc *);
78struct bwfm_core *bwfm_chip_get_core_idx(struct bwfm_softc *, int, int);
79struct bwfm_core *bwfm_chip_get_core(struct bwfm_softc *, int);
80struct bwfm_core *bwfm_chip_get_pmu(struct bwfm_softc *);
81int bwfm_chip_ai_isup(struct bwfm_softc *, struct bwfm_core *);
82void bwfm_chip_ai_disable(struct bwfm_softc *, struct bwfm_core *,
83 uint32_t, uint32_t);
84void bwfm_chip_ai_reset(struct bwfm_softc *, struct bwfm_core *,
85 uint32_t, uint32_t, uint32_t);
86void bwfm_chip_dmp_erom_scan(struct bwfm_softc *);
87int bwfm_chip_dmp_get_regaddr(struct bwfm_softc *, uint32_t *,
88 uint32_t *, uint32_t *);
89int bwfm_chip_cr4_set_active(struct bwfm_softc *, uint32_t);
90void bwfm_chip_cr4_set_passive(struct bwfm_softc *);
91int bwfm_chip_ca7_set_active(struct bwfm_softc *, uint32_t);
92void bwfm_chip_ca7_set_passive(struct bwfm_softc *);
93int bwfm_chip_cm3_set_active(struct bwfm_softc *);
94void bwfm_chip_cm3_set_passive(struct bwfm_softc *);
95void bwfm_chip_socram_ramsize(struct bwfm_softc *, struct bwfm_core *);
96void bwfm_chip_sysmem_ramsize(struct bwfm_softc *, struct bwfm_core *);
97void bwfm_chip_tcm_ramsize(struct bwfm_softc *, struct bwfm_core *);
98void bwfm_chip_tcm_rambase(struct bwfm_softc *);
99
100int bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *, int,
101 int, char *, size_t *);
102int bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *, int,
103 int, char *, size_t);
104void bwfm_proto_bcdc_rx(struct bwfm_softc *, struct mbuf *,
105 struct mbuf_list *);
106int bwfm_proto_bcdc_txctl(struct bwfm_softc *, int, char *, size_t *);
107void bwfm_proto_bcdc_rxctl(struct bwfm_softc *, char *, size_t);
108
109int bwfm_fwvar_cmd_get_data(struct bwfm_softc *, int, void *, size_t);
110int bwfm_fwvar_cmd_set_data(struct bwfm_softc *, int, void *, size_t);
111int bwfm_fwvar_cmd_get_int(struct bwfm_softc *, int, uint32_t *);
112int bwfm_fwvar_cmd_set_int(struct bwfm_softc *, int, uint32_t);
113int bwfm_fwvar_var_get_data(struct bwfm_softc *, char *, void *, size_t);
114int bwfm_fwvar_var_set_data(struct bwfm_softc *, char *, void *, size_t);
115int bwfm_fwvar_var_get_int(struct bwfm_softc *, char *, uint32_t *);
116int bwfm_fwvar_var_set_int(struct bwfm_softc *, char *, uint32_t);
117
118uint32_t bwfm_chan2spec(struct bwfm_softc *, struct ieee80211_channel *);
119uint32_t bwfm_chan2spec_d11n(struct bwfm_softc *, struct ieee80211_channel *);
120uint32_t bwfm_chan2spec_d11ac(struct bwfm_softc *, struct ieee80211_channel *);
121uint32_t bwfm_spec2chan(struct bwfm_softc *, uint32_t);
122uint32_t bwfm_spec2chan_d11n(struct bwfm_softc *, uint32_t);
123uint32_t bwfm_spec2chan_d11ac(struct bwfm_softc *, uint32_t);
124
125void bwfm_connect(struct bwfm_softc *);
126#ifndef IEEE80211_STA_ONLY
127void bwfm_hostap(struct bwfm_softc *);
128#endif
129void bwfm_scan(struct bwfm_softc *);
130void bwfm_scan_abort(struct bwfm_softc *);
131
132void bwfm_task(void *);
133void bwfm_do_async(struct bwfm_softc *,
134 void (*)(struct bwfm_softc *, void *), void *, int);
135
136int bwfm_set_key(struct ieee80211com *, struct ieee80211_node *,
137 struct ieee80211_key *);
138void bwfm_delete_key(struct ieee80211com *, struct ieee80211_node *,
139 struct ieee80211_key *);
140int bwfm_send_mgmt(struct ieee80211com *, struct ieee80211_node *,
141 int, int, int);
142int bwfm_newstate(struct ieee80211com *, enum ieee80211_state, int);
143
144void bwfm_set_key_cb(struct bwfm_softc *, void *);
145void bwfm_delete_key_cb(struct bwfm_softc *, void *);
146void bwfm_rx_event_cb(struct bwfm_softc *, struct mbuf *);
147
148struct mbuf *bwfm_newbuf(void);
149#ifndef IEEE80211_STA_ONLY
150void bwfm_rx_auth_ind(struct bwfm_softc *, struct bwfm_event *, size_t);
151void bwfm_rx_assoc_ind(struct bwfm_softc *, struct bwfm_event *, size_t, int);
152void bwfm_rx_deauth_ind(struct bwfm_softc *, struct bwfm_event *, size_t);
153void bwfm_rx_disassoc_ind(struct bwfm_softc *, struct bwfm_event *, size_t);
154void bwfm_rx_leave_ind(struct bwfm_softc *, struct bwfm_event *, size_t, int);
155#endif
156void bwfm_rx_event(struct bwfm_softc *, struct mbuf *);
157void bwfm_scan_node(struct bwfm_softc *, struct bwfm_bss_info *, size_t);
158
159extern void ieee80211_node2req(struct ieee80211com *,
160 const struct ieee80211_node *, struct ieee80211_nodereq *);
161extern void ieee80211_req2node(struct ieee80211com *,
162 const struct ieee80211_nodereq *, struct ieee80211_node *);
163
164uint8_t bwfm_2ghz_channels[] = {
165 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
166};
167uint8_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
172struct 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
179struct cfdriver bwfm_cd = {
180 NULL((void *)0), "bwfm", DV_IFNET
181};
182
183void
184bwfm_attach(struct bwfm_softc *sc)
185{
186 struct ieee80211com *ic = &sc->sc_ic;
187 struct ifnet *ifp = &ic->ic_ific_ac.ac_if;
188
189 TAILQ_INIT(&sc->sc_bcdc_rxctlq)do { (&sc->sc_bcdc_rxctlq)->tqh_first = ((void *)0)
; (&sc->sc_bcdc_rxctlq)->tqh_last = &(&sc->
sc_bcdc_rxctlq)->tqh_first; } while (0)
;
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)((sc)->sc_dev.dv_xname), 1, IPL_SOFTNET0x2, 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_WEP0x00000001 |
203#ifndef IEEE80211_STA_ONLY
204 IEEE80211_C_HOSTAP0x00000008 | /* Access Point */
205#endif
206 IEEE80211_C_RSN0x00001000 | /* WPA/RSN */
207 IEEE80211_C_SCANALL0x00000400 | /* device scans all channels at once */
208 IEEE80211_C_SCANALLBAND0x00008000; /* 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_BROADCAST0x2 | IFF_SIMPLEX0x800 | IFF_MULTICAST0x8000;
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)__builtin_memcpy((ifp->if_xname), (((sc)->sc_dev.dv_xname
)), (16))
;
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
232void
233bwfm_attachhook(struct device *self)
234{
235 struct bwfm_softc *sc = (struct bwfm_softc *)self;
236
237 if (sc->sc_bus_ops->bs_preinit != NULL((void *)0) &&
238 sc->sc_bus_ops->bs_preinit(sc))
239 return;
240 if (bwfm_preinit(sc))
241 return;
242 sc->sc_initialized = 1;
243}
244
245int
246bwfm_preinit(struct bwfm_softc *sc)
247{
248 struct ieee80211com *ic = &sc->sc_ic;
249 struct ifnet *ifp = &ic->ic_ific_ac.ac_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_VERSION1, &tmp)) {
257 printf("%s: could not read io type\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
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)((sc)->sc_dev.dv_xname));
264 return 1;
265 }
266
267 printf("%s: address %s\n", DEVNAME(sc)((sc)->sc_dev.dv_xname), 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_BANDLIST140, bandlist,
280 sizeof(bandlist))) {
281 printf("%s: couldn't get supported band list\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
282 return 1;
283 }
284 nbands = letoh32(bandlist[0])((__uint32_t)(bandlist[0]));
285 for (i = 1; i <= nbands && i < nitems(bandlist)(sizeof((bandlist)) / sizeof((bandlist)[0])); i++) {
286 switch (letoh32(bandlist[i])((__uint32_t)(bandlist[i]))) {
287 case BWFM_BAND_2G2:
288 DPRINTF(("%s: 2G HT %d VHT %d\n",do { ; } while (0)
289 DEVNAME(sc), nmode, vhtmode))do { ; } while (0);
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)(sizeof((bwfm_2ghz_channels)) / sizeof((bwfm_2ghz_channels)[0
]))
; j++) {
296 uint8_t chan = bwfm_2ghz_channels[j];
297 ic->ic_channels[chan].ic_freq =
298 ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ0x0080);
299 ic->ic_channels[chan].ic_flags =
300 IEEE80211_CHAN_CCK0x0020 | IEEE80211_CHAN_OFDM0x0040 |
301 IEEE80211_CHAN_DYN0x0400 | IEEE80211_CHAN_2GHZ0x0080;
302 if (nmode)
303 ic->ic_channels[chan].ic_flags |=
304 IEEE80211_CHAN_HT0x2000;
305 /* VHT is 5GHz only */
306 }
307 break;
308 case BWFM_BAND_5G1:
309 DPRINTF(("%s: 5G HT %d VHT %d\n",do { ; } while (0)
310 DEVNAME(sc), nmode, vhtmode))do { ; } while (0);
311 ic->ic_sup_rates[IEEE80211_MODE_11A] =
312 ieee80211_std_rateset_11a;
313
314 for (j = 0; j < nitems(bwfm_5ghz_channels)(sizeof((bwfm_5ghz_channels)) / sizeof((bwfm_5ghz_channels)[0
]))
; j++) {
315 uint8_t chan = bwfm_5ghz_channels[j];
316 ic->ic_channels[chan].ic_freq =
317 ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ0x0100);
318 ic->ic_channels[chan].ic_flags =
319 IEEE80211_CHAN_A(0x0100 | 0x0040);
320 if (nmode)
321 ic->ic_channels[chan].ic_flags |=
322 IEEE80211_CHAN_HT0x2000;
323 if (vhtmode)
324 ic->ic_channels[chan].ic_flags |=
325 IEEE80211_CHAN_VHT0x4000;
326 }
327 break;
328 default:
329 printf("%s: unsupported band 0x%x\n", DEVNAME(sc)((sc)->sc_dev.dv_xname),
330 letoh32(bandlist[i])((__uint32_t)(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)((sc)->sc_dev.dv_xname));
341
342 ieee80211_media_init(ifp, bwfm_media_change, ieee80211_media_status);
343 return 0;
344}
345
346void
347bwfm_cleanup(struct bwfm_softc *sc)
348{
349 bwfm_chip_detach(sc);
350 sc->sc_initialized = 0;
351}
352
353int
354bwfm_detach(struct bwfm_softc *sc, int flags)
355{
356 struct ieee80211com *ic = &sc->sc_ic;
357 struct ifnet *ifp = &ic->ic_ific_ac.ac_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
369int
370bwfm_activate(struct bwfm_softc *sc, int act)
371{
372 struct ieee80211com *ic = &sc->sc_ic;
373 struct ifnet *ifp = &ic->ic_ific_ac.ac_if;
374
375 switch (act) {
376 case DVACT_QUIESCE2:
377 if (ifp->if_flags & IFF_UP0x1)
378 bwfm_stop(ifp);
379 break;
380 case DVACT_WAKEUP5:
381 if (ifp->if_flags & IFF_UP0x1)
382 bwfm_init(ifp);
383 break;
384 default:
385 break;
386 }
387
388 return 0;
389}
390
391void
392bwfm_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_RUNNING0x40))
399 return;
400 if (ifq_is_oactive(&ifp->if_snd))
401 return;
402 if (ifq_empty(&ifp->if_snd)(({ typeof((&ifp->if_snd)->ifq_len) __tmp = *(volatile
typeof((&ifp->if_snd)->ifq_len) *)&((&ifp->
if_snd)->ifq_len); membar_datadep_consumer(); __tmp; }) ==
0)
)
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_ONLY0x00000001))
415 break;
416
417 m = ifq_dequeue(&ifp->if_snd);
418 if (m == NULL((void *)0))
419 break;
420
421 if (sc->sc_bus_ops->bs_txdata(sc, m) != 0) {
422 ifp->if_oerrorsif_data.ifi_oerrors++;
423 m_freem(m);
424 continue;
425 }
426
427#if NBPFILTER1 > 0
428 if (ifp->if_bpf)
429 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT(1 << 1));
430#endif
431 }
432}
433
434void
435bwfm_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(((((BWFM_E_LAST)+((8)-1))/(8))*(8)) / 8)];
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((void *)0) &&
445 sc->sc_bus_ops->bs_preinit(sc)) {
446 printf("%s: could not init bus\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
447 return;
448 }
449 if (bwfm_preinit(sc)) {
450 printf("%s: could not init\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
451 return;
452 }
453 sc->sc_initialized = 1;
454 }
455
456 /* Select default channel */
457 ic->ic_bss->ni_chan = ic->ic_ibss_chan;
458
459 if (bwfm_fwvar_var_set_int(sc, "mpc", 1)) {
460 printf("%s: could not set mpc\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
461 return;
462 }
463
464 /* Select target by RSSI (boost on 5GHz) */
465 join_pref[0].type = BWFM_JOIN_PREF_RSSI_DELTA4;
466 join_pref[0].len = 2;
467 join_pref[0].rssi_gain = BWFM_JOIN_PREF_RSSI_BOOST8;
468 join_pref[0].band = BWFM_JOIN_PREF_BAND_5G1;
469 join_pref[1].type = BWFM_JOIN_PREF_RSSI1;
470 join_pref[1].len = 2;
471 join_pref[1].rssi_gain = 0;
472 join_pref[1].band = 0;
473 if (bwfm_fwvar_var_set_data(sc, "join_pref", join_pref,
474 sizeof(join_pref))) {
475 printf("%s: could not set join pref\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
476 return;
477 }
478
479#define BWFM_EVENT(event) evmask[(event) / 8] |= 1 << ((event) % 8)
480 memset(evmask, 0, sizeof(evmask))__builtin_memset((evmask), (0), (sizeof(evmask)));
481 switch (ic->ic_opmode) {
482 case IEEE80211_M_STA:
483 BWFM_EVENT(BWFM_E_IF);
484 BWFM_EVENT(BWFM_E_LINK);
485 BWFM_EVENT(BWFM_E_AUTH);
486 BWFM_EVENT(BWFM_E_ASSOC);
487 BWFM_EVENT(BWFM_E_DEAUTH);
488 BWFM_EVENT(BWFM_E_DISASSOC);
489 BWFM_EVENT(BWFM_E_ESCAN_RESULT);
490 break;
491#ifndef IEEE80211_STA_ONLY
492 case IEEE80211_M_HOSTAP:
493 BWFM_EVENT(BWFM_E_AUTH_IND);
494 BWFM_EVENT(BWFM_E_ASSOC_IND);
495 BWFM_EVENT(BWFM_E_REASSOC_IND);
496 BWFM_EVENT(BWFM_E_DEAUTH_IND);
497 BWFM_EVENT(BWFM_E_DISASSOC_IND);
498 BWFM_EVENT(BWFM_E_ESCAN_RESULT);
499 break;
500#endif
501 default:
502 break;
503 }
504#undef BWFM_EVENT
505
506 if (bwfm_fwvar_var_set_data(sc, "event_msgs", evmask, sizeof(evmask))) {
507 printf("%s: could not set event mask\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
508 return;
509 }
510
511 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_CHANNEL_TIME185,
512 BWFM_DEFAULT_SCAN_CHANNEL_TIME40)) {
513 printf("%s: could not set scan channel time\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
514 return;
515 }
516 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_UNASSOC_TIME187,
517 BWFM_DEFAULT_SCAN_UNASSOC_TIME40)) {
518 printf("%s: could not set scan unassoc time\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
519 return;
520 }
521 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_PASSIVE_TIME258,
522 BWFM_DEFAULT_SCAN_PASSIVE_TIME120)) {
523 printf("%s: could not set scan passive time\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
524 return;
525 }
526
527 /*
528 * Use CAM (constantly awake) when we are running as AP,
529 * otherwise use fast power saving.
530 */
531 pm = BWFM_PM_FAST_PS2;
532#ifndef IEEE80211_STA_ONLY
533 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
534 pm = BWFM_PM_CAM0;
535#endif
536 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM86, pm)) {
537 printf("%s: could not set power\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
538 return;
539 }
540
541 bwfm_fwvar_var_set_int(sc, "txbf", 1);
542 bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP2, 0);
543 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA20, 1);
544 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP118, 0);
545
546 /* Disable all offloading (ARP, NDP, TCP/UDP cksum). */
547 bwfm_fwvar_var_set_int(sc, "arp_ol", 0);
548 bwfm_fwvar_var_set_int(sc, "arpoe", 0);
549 bwfm_fwvar_var_set_int(sc, "ndoe", 0);
550 bwfm_fwvar_var_set_int(sc, "toe", 0);
551
552 /*
553 * The firmware supplicant can handle the WPA handshake for
554 * us, but we honestly want to do this ourselves, so disable
555 * the firmware supplicant and let our stack handle it.
556 */
557 bwfm_fwvar_var_set_int(sc, "sup_wpa", 0);
558
559 bwfm_iff(sc);
560
561 ifp->if_flags |= IFF_RUNNING0x40;
562 ifq_clr_oactive(&ifp->if_snd);
563
564 ieee80211_begin_scan(ifp);
565}
566
567void
568bwfm_stop(struct ifnet *ifp)
569{
570 struct bwfm_softc *sc = ifp->if_softc;
571 struct ieee80211com *ic = &sc->sc_ic;
572 struct bwfm_join_params join;
573
574 sc->sc_tx_timer = 0;
575 ifp->if_timer = 0;
576 ifp->if_flags &= ~IFF_RUNNING0x40;
577 ifq_clr_oactive(&ifp->if_snd);
578
579 ieee80211_new_state(ic, IEEE80211_S_INIT, -1)(((ic)->ic_newstate)((ic), (IEEE80211_S_INIT), (-1)));
580
581 memset(&join, 0, sizeof(join))__builtin_memset((&join), (0), (sizeof(join)));
582 bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID26, &join, sizeof(join));
583 bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN3, 1);
584 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP118, 0);
585 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA20, 0);
586 bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP2, 1);
587 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM86, BWFM_PM_FAST_PS2);
588 bwfm_fwvar_var_set_int(sc, "mpc", 1);
589
590 if (sc->sc_bus_ops->bs_stop)
591 sc->sc_bus_ops->bs_stop(sc);
592}
593
594void
595bwfm_iff(struct bwfm_softc *sc)
596{
597 struct arpcom *ac = &sc->sc_ic.ic_ac;
598 struct ifnet *ifp = &ac->ac_if;
599 struct ether_multi *enm;
600 struct ether_multistep step;
601 size_t mcastlen;
602 char *mcast;
603 int i = 0;
604
605 mcastlen = sizeof(uint32_t) + ac->ac_multicnt * ETHER_ADDR_LEN6;
606 mcast = malloc(mcastlen, M_TEMP127, M_WAITOK0x0001);
607 htolem32((uint32_t *)mcast, ac->ac_multicnt)(*(__uint32_t *)((uint32_t *)mcast) = ((__uint32_t)(ac->ac_multicnt
)))
;
608
609 ifp->if_flags &= ~IFF_ALLMULTI0x200;
610 if (ifp->if_flags & IFF_PROMISC0x100 || ac->ac_multirangecnt > 0) {
611 ifp->if_flags |= IFF_ALLMULTI0x200;
612 } else {
613 ETHER_FIRST_MULTI(step, ac, enm)do { (step).e_enm = ((&(ac)->ac_multiaddrs)->lh_first
); do { if ((((enm)) = ((step)).e_enm) != ((void *)0)) ((step
)).e_enm = ((((enm)))->enm_list.le_next); } while ( 0); } while
( 0)
;
614 while (enm != NULL((void *)0)) {
615 memcpy(mcast + sizeof(uint32_t) + i * ETHER_ADDR_LEN,__builtin_memcpy((mcast + sizeof(uint32_t) + i * 6), (enm->
enm_addrlo), (6))
616 enm->enm_addrlo, ETHER_ADDR_LEN)__builtin_memcpy((mcast + sizeof(uint32_t) + i * 6), (enm->
enm_addrlo), (6))
;
617 ETHER_NEXT_MULTI(step, enm)do { if (((enm) = (step).e_enm) != ((void *)0)) (step).e_enm =
(((enm))->enm_list.le_next); } while ( 0)
;
618 i++;
619 }
620 }
621
622 bwfm_fwvar_var_set_data(sc, "mcast_list", mcast, mcastlen);
623 bwfm_fwvar_var_set_int(sc, "allmulti",
624 !!(ifp->if_flags & IFF_ALLMULTI0x200));
625 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PROMISC10,
626 !!(ifp->if_flags & IFF_PROMISC0x100));
627
628 free(mcast, M_TEMP127, mcastlen);
629}
630
631void
632bwfm_watchdog(struct ifnet *ifp)
633{
634 struct bwfm_softc *sc = ifp->if_softc;
635
636 ifp->if_timer = 0;
637
638 if (sc->sc_tx_timer > 0) {
639 if (--sc->sc_tx_timer == 0) {
640 printf("%s: device timeout\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
641 ifp->if_oerrorsif_data.ifi_oerrors++;
642 return;
643 }
644 ifp->if_timer = 1;
645 }
646 ieee80211_watchdog(ifp);
647}
648
649/*
650 * Tx-rate to MCS conversion might lie since some rates map to multiple MCS.
651 * But this is the best we can do given that firmware only reports kbit/s.
652 */
653
654void
655bwfm_rate2vhtmcs(int *mcs, int *ss, uint32_t txrate)
656{
657 const struct ieee80211_vht_rateset *rs;
658 int i, j;
659
660 *mcs = -1;
661 *ss = -1;
662 /* TODO: Select specific ratesets based on BSS channel width. */
663 for (i = 0; i < IEEE80211_VHT_NUM_RATESETS12; i++) {
664 rs = &ieee80211_std_ratesets_11ac[i];
665 for (j = 0; j < rs->nrates; j++) {
666 if (rs->rates[j] == txrate / 500) {
667 *mcs = j;
668 *ss = rs->num_ss;
669 return;
670 }
671 }
672 }
673}
674
675int
676bwfm_rate2htmcs(uint32_t txrate)
677{
678 const struct ieee80211_ht_rateset *rs;
679 int i, j;
680
681 /* TODO: Select specific ratesets based on BSS channel width. */
682 for (i = 0; i < IEEE80211_HT_NUM_RATESETS16; i++) {
683 rs = &ieee80211_std_ratesets_11n[i];
684 for (j = 0; j < rs->nrates; j++) {
685 if (rs->rates[j] == txrate / 500)
686 return rs->min_mcs + j;
687 }
688 }
689
690 return -1;
691}
692
693void
694bwfm_update_node(void *arg, struct ieee80211_node *ni)
695{
696 struct bwfm_softc *sc = arg;
697 struct ieee80211com *ic = &sc->sc_ic;
698 struct bwfm_sta_info sta;
699 uint32_t flags;
700 int8_t rssi;
701 uint32_t txrate;
702 int i;
703
704 memset(&sta, 0, sizeof(sta))__builtin_memset((&sta), (0), (sizeof(sta)));
705 memcpy((uint8_t *)&sta, ni->ni_macaddr, sizeof(ni->ni_macaddr))__builtin_memcpy(((uint8_t *)&sta), (ni->ni_macaddr), (
sizeof(ni->ni_macaddr)))
;
706
707 if (bwfm_fwvar_var_get_data(sc, "sta_info", &sta, sizeof(sta)))
708 return;
709
710 if (!IEEE80211_ADDR_EQ(ni->ni_macaddr, sta.ea)(__builtin_memcmp((ni->ni_macaddr), (sta.ea), (6)) == 0))
711 return;
712
713 if (le16toh(sta.ver)((__uint16_t)(sta.ver)) < 3)
714 return;
715
716 flags = le32toh(sta.flags)((__uint32_t)(sta.flags));
717 if ((flags & BWFM_STA_SCBSTATS0x00004000) == 0)
718 return;
719
720 if (le16toh(sta.ver)((__uint16_t)(sta.ver)) >= 4) {
721 rssi = 0;
722 for (i = 0; i < BWFM_ANT_MAX4; i++) {
723 if (sta.rssi[i] >= 0)
724 continue;
725 if (rssi == 0 || sta.rssi[i] > rssi)
726 rssi = sta.rssi[i];
727 }
728 if (rssi)
729 ni->ni_rssi = rssi;
730 }
731
732 txrate = le32toh(sta.tx_rate)((__uint32_t)(sta.tx_rate)); /* in kbit/s */
733 if (txrate == 0xffffffff) /* Seen this happening during association. */
734 return;
735
736 if ((le32toh(sta.flags)((__uint32_t)(sta.flags)) & BWFM_STA_VHT_CAP0x00100000)) {
737 int mcs, ss;
738 /* Tell net80211 that firmware has negotiated 11ac. */
739 ni->ni_flags |= IEEE80211_NODE_VHT0x10000;
740 ni->ni_flags |= IEEE80211_NODE_HT0x0400; /* VHT implies HT support */
741 if (ic->ic_curmode < IEEE80211_MODE_11AC)
742 ieee80211_setmode(ic, IEEE80211_MODE_11AC);
743 bwfm_rate2vhtmcs(&mcs, &ss, txrate);
744 if (mcs >= 0) {
745 ni->ni_txmcs = mcs;
746 ni->ni_vht_ss = ss;
747 } else {
748 ni->ni_txmcs = 0;
749 ni->ni_vht_ss = 1;
750 }
751 } else if ((le32toh(sta.flags)((__uint32_t)(sta.flags)) & BWFM_STA_N_CAP0x00002000)) {
752 int mcs;
753 /* Tell net80211 that firmware has negotiated 11n. */
754 ni->ni_flags |= IEEE80211_NODE_HT0x0400;
755 if (ic->ic_curmode < IEEE80211_MODE_11N)
756 ieee80211_setmode(ic, IEEE80211_MODE_11N);
757 mcs = bwfm_rate2htmcs(txrate);
758 ni->ni_txmcs = (mcs >= 0 ? mcs : 0);
759 } else {
760 /* We're in 11a/g mode. Map to a legacy rate. */
761 for (i = 0; i < ni->ni_rates.rs_nrates; i++) {
762 uint8_t rate = ni->ni_rates.rs_rates[i];
763 rate &= IEEE80211_RATE_VAL0x7f;
764 if (rate == txrate / 500) {
765 ni->ni_txrate = i;
766 break;
767 }
768 }
769 }
770}
771
772void
773bwfm_update_nodes(struct bwfm_softc *sc)
774{
775 struct ieee80211com *ic = &sc->sc_ic;
776 struct ieee80211_node *ni;
777
778 switch (ic->ic_opmode) {
779 case IEEE80211_M_STA:
780 bwfm_update_node(sc, ic->ic_bss);
781 /* Update cached copy in the nodes tree as well. */
782 ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr);
783 if (ni) {
784 ni->ni_rssi = ic->ic_bss->ni_rssi;
785 }
786 break;
787#ifndef IEEE80211_STA_ONLY
788 case IEEE80211_M_HOSTAP:
789 ieee80211_iterate_nodes(ic, bwfm_update_node, sc);
790 break;
791#endif
792 default:
793 break;
794 }
795}
796
797int
798bwfm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
799{
800 struct bwfm_softc *sc = ifp->if_softc;
801 struct ieee80211com *ic = &sc->sc_ic;
802 struct ifreq *ifr;
803 int s, error = 0;
804
805 s = splnet()splraise(0x4);
806 switch (cmd) {
807 case SIOCSIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((12)))
:
808 ifp->if_flags |= IFF_UP0x1;
809 /* FALLTHROUGH */
810 case SIOCSIFFLAGS((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((16)))
:
811 if (ifp->if_flags & IFF_UP0x1) {
812 if (!(ifp->if_flags & IFF_RUNNING0x40))
813 bwfm_init(ifp);
814 } else {
815 if (ifp->if_flags & IFF_RUNNING0x40)
816 bwfm_stop(ifp);
817 }
818 break;
819 case SIOCADDMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((49)))
:
820 case SIOCDELMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((50)))
:
821 ifr = (struct ifreq *)data;
822 error = (cmd == SIOCADDMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((49)))
) ?
823 ether_addmulti(ifr, &ic->ic_ac) :
824 ether_delmulti(ifr, &ic->ic_ac);
825 if (error == ENETRESET52) {
826 bwfm_iff(sc);
827 error = 0;
828 }
829 break;
830 case SIOCGIFMEDIA(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifmediareq) & 0x1fff) << 16) | ((('i')) <<
8) | ((56)))
:
831 case SIOCG80211NODE(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ieee80211_nodereq) & 0x1fff) << 16) | ((('i'
)) << 8) | ((211)))
:
832 case SIOCG80211ALLNODES(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ieee80211_nodereq_all) & 0x1fff) << 16) | (
(('i')) << 8) | ((214)))
:
833 if (ic->ic_state == IEEE80211_S_RUN)
834 bwfm_update_nodes(sc);
835 /* fall through */
836 default:
837 error = ieee80211_ioctl(ifp, cmd, data);
838 }
839 if (error == ENETRESET52) {
840 if ((ifp->if_flags & (IFF_UP0x1 | IFF_RUNNING0x40)) ==
841 (IFF_UP0x1 | IFF_RUNNING0x40)) {
842 bwfm_stop(ifp);
843 bwfm_init(ifp);
844 }
845 error = 0;
846 }
847 splx(s)spllower(s);
848 return error;
849}
850
851int
852bwfm_media_change(struct ifnet *ifp)
853{
854 int error;
855
856 error = ieee80211_media_change(ifp);
857 if (error != ENETRESET52)
858 return error;
859
860 if ((ifp->if_flags & (IFF_UP0x1 | IFF_RUNNING0x40)) ==
861 (IFF_UP0x1 | IFF_RUNNING0x40)) {
862 bwfm_stop(ifp);
863 bwfm_init(ifp);
864 }
865 return error;
866}
867
868/* Chip initialization (SDIO, PCIe) */
869int
870bwfm_chip_attach(struct bwfm_softc *sc)
871{
872 struct bwfm_core *core;
873 int need_socram = 0;
874 int has_socram = 0;
875 int cpu_found = 0;
876 uint32_t val;
877
878 LIST_INIT(&sc->sc_chip.ch_list)do { ((&sc->sc_chip.ch_list)->lh_first) = ((void *)
0); } while (0)
;
879
880 if (sc->sc_buscore_ops->bc_prepare(sc) != 0) {
881 printf("%s: failed buscore prepare\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
882 return 1;
883 }
884
885 val = sc->sc_buscore_ops->bc_read(sc,
886 BWFM_CHIP_BASE0x18000000 + BWFM_CHIP_REG_CHIPID0x00000000);
887 sc->sc_chip.ch_chip = BWFM_CHIP_CHIPID_ID(val)(((val) >> 0) & 0xffff);
888 sc->sc_chip.ch_chiprev = BWFM_CHIP_CHIPID_REV(val)(((val) >> 16) & 0xf);
889
890 if ((sc->sc_chip.ch_chip > 0xa000) || (sc->sc_chip.ch_chip < 0x4000))
891 snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name),
892 "%d", sc->sc_chip.ch_chip);
893 else
894 snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name),
895 "%x", sc->sc_chip.ch_chip);
896
897 switch (BWFM_CHIP_CHIPID_TYPE(val)(((val) >> 28) & 0xf))
898 {
899 case BWFM_CHIP_CHIPID_TYPE_SOCI_SB0:
900 printf("%s: SoC interconnect SB not implemented\n",
901 DEVNAME(sc)((sc)->sc_dev.dv_xname));
902 return 1;
903 case BWFM_CHIP_CHIPID_TYPE_SOCI_AI1:
904 sc->sc_chip.ch_core_isup = bwfm_chip_ai_isup;
905 sc->sc_chip.ch_core_disable = bwfm_chip_ai_disable;
906 sc->sc_chip.ch_core_reset = bwfm_chip_ai_reset;
907 bwfm_chip_dmp_erom_scan(sc);
908 break;
909 default:
910 printf("%s: SoC interconnect %d unknown\n",
911 DEVNAME(sc)((sc)->sc_dev.dv_xname), BWFM_CHIP_CHIPID_TYPE(val)(((val) >> 28) & 0xf));
912 return 1;
913 }
914
915 LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link)for((core) = ((&sc->sc_chip.ch_list)->lh_first); (core
)!= ((void *)0); (core) = ((core)->co_link.le_next))
{
916 DPRINTF(("%s: 0x%x:%-2d base 0x%08x wrap 0x%08x\n",do { ; } while (0)
917 DEVNAME(sc), core->co_id, core->co_rev,do { ; } while (0)
918 core->co_base, core->co_wrapbase))do { ; } while (0);
919
920 switch (core->co_id) {
921 case BWFM_AGENT_CORE_ARM_CM30x82A:
922 need_socram = 1;
923 /* FALLTHROUGH */
924 case BWFM_AGENT_CORE_ARM_CR40x83E:
925 case BWFM_AGENT_CORE_ARM_CA70x847:
926 cpu_found = 1;
927 break;
928 case BWFM_AGENT_INTERNAL_MEM0x80E:
929 has_socram = 1;
930 break;
931 default:
932 break;
933 }
934 }
935
936 if (!cpu_found) {
937 printf("%s: CPU core not detected\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
938 return 1;
939 }
940 if (need_socram && !has_socram) {
941 printf("%s: RAM core not provided\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
942 return 1;
943 }
944
945 bwfm_chip_set_passive(sc);
946
947 if (sc->sc_buscore_ops->bc_reset) {
948 sc->sc_buscore_ops->bc_reset(sc);
949 bwfm_chip_set_passive(sc);
950 }
951
952 if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR40x83E)) != NULL((void *)0)) {
953 bwfm_chip_tcm_ramsize(sc, core);
954 bwfm_chip_tcm_rambase(sc);
955 } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_SYS_MEM0x849)) != NULL((void *)0)) {
956 bwfm_chip_sysmem_ramsize(sc, core);
957 bwfm_chip_tcm_rambase(sc);
958 } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM0x80E)) != NULL((void *)0)) {
959 bwfm_chip_socram_ramsize(sc, core);
960 }
961
962 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON0x800);
963 sc->sc_chip.ch_cc_caps = sc->sc_buscore_ops->bc_read(sc,
964 core->co_base + BWFM_CHIP_REG_CAPABILITIES0x00000004);
965 sc->sc_chip.ch_cc_caps_ext = sc->sc_buscore_ops->bc_read(sc,
966 core->co_base + BWFM_CHIP_REG_CAPABILITIES_EXT0x000000AC);
967
968 core = bwfm_chip_get_pmu(sc);
969 if (sc->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU0x10000000) {
970 sc->sc_chip.ch_pmucaps = sc->sc_buscore_ops->bc_read(sc,
971 core->co_base + BWFM_CHIP_REG_PMUCAPABILITIES0x00000604);
972 sc->sc_chip.ch_pmurev = sc->sc_chip.ch_pmucaps &
973 BWFM_CHIP_REG_PMUCAPABILITIES_REV_MASK0x000000ff;
974 }
975
976 if (sc->sc_buscore_ops->bc_setup)
977 sc->sc_buscore_ops->bc_setup(sc);
978
979 bwfm_init_board_type(sc);
980
981 return 0;
982}
983
984void
985bwfm_chip_detach(struct bwfm_softc *sc)
986{
987 struct bwfm_core *core, *tmp;
988
989 LIST_FOREACH_SAFE(core, &sc->sc_chip.ch_list, co_link, tmp)for ((core) = ((&sc->sc_chip.ch_list)->lh_first); (
core) && ((tmp) = ((core)->co_link.le_next), 1); (
core) = (tmp))
{
990 LIST_REMOVE(core, co_link)do { if ((core)->co_link.le_next != ((void *)0)) (core)->
co_link.le_next->co_link.le_prev = (core)->co_link.le_prev
; *(core)->co_link.le_prev = (core)->co_link.le_next; (
(core)->co_link.le_prev) = ((void *)-1); ((core)->co_link
.le_next) = ((void *)-1); } while (0)
;
991 free(core, M_DEVBUF2, sizeof(*core));
992 }
993}
994
995struct bwfm_core *
996bwfm_chip_get_core_idx(struct bwfm_softc *sc, int id, int idx)
997{
998 struct bwfm_core *core;
999
1000 LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link)for((core) = ((&sc->sc_chip.ch_list)->lh_first); (core
)!= ((void *)0); (core) = ((core)->co_link.le_next))
{
1001 if (core->co_id == id && idx-- == 0)
1002 return core;
1003 }
1004
1005 return NULL((void *)0);
1006}
1007
1008struct bwfm_core *
1009bwfm_chip_get_core(struct bwfm_softc *sc, int id)
1010{
1011 return bwfm_chip_get_core_idx(sc, id, 0);
1012}
1013
1014struct bwfm_core *
1015bwfm_chip_get_pmu(struct bwfm_softc *sc)
1016{
1017 struct bwfm_core *cc, *pmu;
1018
1019 cc = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON0x800);
1020 if (cc->co_rev >= 35 && sc->sc_chip.ch_cc_caps_ext &
1021 BWFM_CHIP_REG_CAPABILITIES_EXT_AOB_PRESENT0x00000040) {
1022 pmu = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_PMU0x827);
1023 if (pmu)
1024 return pmu;
1025 }
1026
1027 return cc;
1028}
1029
1030/* Functions for the AI interconnect */
1031int
1032bwfm_chip_ai_isup(struct bwfm_softc *sc, struct bwfm_core *core)
1033{
1034 uint32_t ioctl, reset;
1035
1036 ioctl = sc->sc_buscore_ops->bc_read(sc,
1037 core->co_wrapbase + BWFM_AGENT_IOCTL0x0408);
1038 reset = sc->sc_buscore_ops->bc_read(sc,
1039 core->co_wrapbase + BWFM_AGENT_RESET_CTL0x0800);
1040
1041 if (((ioctl & (BWFM_AGENT_IOCTL_FGC0x0002 | BWFM_AGENT_IOCTL_CLK0x0001)) ==
1042 BWFM_AGENT_IOCTL_CLK0x0001) &&
1043 ((reset & BWFM_AGENT_RESET_CTL_RESET0x0001) == 0))
1044 return 1;
1045
1046 return 0;
1047}
1048
1049void
1050bwfm_chip_ai_disable(struct bwfm_softc *sc, struct bwfm_core *core,
1051 uint32_t prereset, uint32_t reset)
1052{
1053 uint32_t val;
1054 int i;
1055
1056 val = sc->sc_buscore_ops->bc_read(sc,
1057 core->co_wrapbase + BWFM_AGENT_RESET_CTL0x0800);
1058 if ((val & BWFM_AGENT_RESET_CTL_RESET0x0001) == 0) {
1059
1060 sc->sc_buscore_ops->bc_write(sc,
1061 core->co_wrapbase + BWFM_AGENT_IOCTL0x0408,
1062 prereset | BWFM_AGENT_IOCTL_FGC0x0002 | BWFM_AGENT_IOCTL_CLK0x0001);
1063 sc->sc_buscore_ops->bc_read(sc,
1064 core->co_wrapbase + BWFM_AGENT_IOCTL0x0408);
1065
1066 sc->sc_buscore_ops->bc_write(sc,
1067 core->co_wrapbase + BWFM_AGENT_RESET_CTL0x0800,
1068 BWFM_AGENT_RESET_CTL_RESET0x0001);
1069 delay(20)(*delay_func)(20);
1070
1071 for (i = 300; i > 0; i--) {
1072 if (sc->sc_buscore_ops->bc_read(sc,
1073 core->co_wrapbase + BWFM_AGENT_RESET_CTL0x0800) ==
1074 BWFM_AGENT_RESET_CTL_RESET0x0001)
1075 break;
1076 }
1077 if (i == 0)
1078 printf("%s: timeout on core reset\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
1079 }
1080
1081 sc->sc_buscore_ops->bc_write(sc,
1082 core->co_wrapbase + BWFM_AGENT_IOCTL0x0408,
1083 reset | BWFM_AGENT_IOCTL_FGC0x0002 | BWFM_AGENT_IOCTL_CLK0x0001);
1084 sc->sc_buscore_ops->bc_read(sc,
1085 core->co_wrapbase + BWFM_AGENT_IOCTL0x0408);
1086}
1087
1088void
1089bwfm_chip_ai_reset(struct bwfm_softc *sc, struct bwfm_core *core,
1090 uint32_t prereset, uint32_t reset, uint32_t postreset)
1091{
1092 int i;
1093
1094 bwfm_chip_ai_disable(sc, core, prereset, reset);
1095
1096 for (i = 50; i > 0; i--) {
1097 if ((sc->sc_buscore_ops->bc_read(sc,
1098 core->co_wrapbase + BWFM_AGENT_RESET_CTL0x0800) &
1099 BWFM_AGENT_RESET_CTL_RESET0x0001) == 0)
1100 break;
1101 sc->sc_buscore_ops->bc_write(sc,
1102 core->co_wrapbase + BWFM_AGENT_RESET_CTL0x0800, 0);
1103 delay(60)(*delay_func)(60);
1104 }
1105 if (i == 0)
1106 printf("%s: timeout on core reset\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
1107
1108 sc->sc_buscore_ops->bc_write(sc,
1109 core->co_wrapbase + BWFM_AGENT_IOCTL0x0408,
1110 postreset | BWFM_AGENT_IOCTL_CLK0x0001);
1111 sc->sc_buscore_ops->bc_read(sc,
1112 core->co_wrapbase + BWFM_AGENT_IOCTL0x0408);
1113}
1114
1115void
1116bwfm_chip_dmp_erom_scan(struct bwfm_softc *sc)
1117{
1118 uint32_t erom, val, base, wrap;
1119 uint8_t type = 0;
1120 uint16_t id;
1121 uint8_t nmw, nsw, rev;
1122 struct bwfm_core *core;
1123
1124 erom = sc->sc_buscore_ops->bc_read(sc,
1125 BWFM_CHIP_BASE0x18000000 + BWFM_CHIP_REG_EROMPTR0x000000FC);
1126 while (type != BWFM_DMP_DESC_EOT0x0000000F) {
1127 val = sc->sc_buscore_ops->bc_read(sc, erom);
1128 type = val & BWFM_DMP_DESC_MASK0x0000000F;
1129 erom += 4;
1130
1131 if (type != BWFM_DMP_DESC_COMPONENT0x00000001)
1132 continue;
1133
1134 id = (val & BWFM_DMP_COMP_PARTNUM0x000FFF00)
1135 >> BWFM_DMP_COMP_PARTNUM_S8;
1136
1137 val = sc->sc_buscore_ops->bc_read(sc, erom);
1138 type = val & BWFM_DMP_DESC_MASK0x0000000F;
1139 erom += 4;
1140
1141 if (type != BWFM_DMP_DESC_COMPONENT0x00000001) {
1142 printf("%s: not component descriptor\n", DEVNAME(sc)((sc)->sc_dev.dv_xname));
1143 return;
1144 }
1145
1146 nmw = (val & BWFM_DMP_COMP_NUM_MWRAP0x0007C000)
1147 >> BWFM_DMP_COMP_NUM_MWRAP_S14;
1148 nsw = (val & BWFM_DMP_COMP_NUM_SWRAP0x00F80000)
1149 >> BWFM_DMP_COMP_NUM_SWRAP_S19;
1150 rev = (val & BWFM_DMP_COMP_REVISION0xFF000000)
1151 >> BWFM_DMP_COMP_REVISION_S24;
1152
1153 if (nmw + nsw == 0 && id != BWFM_AGENT_CORE_PMU0x827 &&
1154 id != BWFM_AGENT_CORE_GCI0x840)
1155 continue;
1156
1157 if (bwfm_chip_dmp_get_regaddr(sc, &erom, &base, &wrap))
1158 continue;
1159
1160 core = malloc(sizeof(*core), M_DEVBUF2, M_WAITOK0x0001);
1161 core->co_id = id;
1162 core->co_base = base;
1163 core->co_wrapbase = wrap;
1164 core->co_rev = rev;
1165 LIST_INSERT_HEAD(&sc->sc_chip.ch_list, core, co_link)do { if (((core)->co_link.le_next = (&sc->sc_chip.ch_list
)->lh_first) != ((void *)0)) (&sc->sc_chip.ch_list)
->lh_first->co_link.le_prev = &(core)->co_link.le_next
; (&sc->sc_chip.ch_list)->lh_first = (core); (core)
->co_link.le_prev = &(&sc->sc_chip.ch_list)->
lh_first; } while (0)
;
1166 }
1167}
1168
1169int
1170bwfm_chip_dmp_get_regaddr(struct bwfm_softc *sc, uint32_t *erom,
1171 uint32_t *base, uint32_t *wrap)
1172{
1173 uint8_t type = 0, mpnum = 0;
1174 uint8_t stype, sztype, wraptype;
1175 uint32_t val;
1176
1177 *base = 0;
1178 *wrap = 0;
1179
1180 val = sc->sc_buscore_ops->bc_read(sc, *erom);
1181 type = val & BWFM_DMP_DESC_MASK0x0000000F;
1182 if (type == BWFM_DMP_DESC_MASTER_PORT0x00000003) {
1183 mpnum = (val & BWFM_DMP_MASTER_PORT_NUM0x000000F0)
Value stored to 'mpnum' is never read
1184 >> BWFM_DMP_MASTER_PORT_NUM_S4;
1185 wraptype = BWFM_DMP_SLAVE_TYPE_MWRAP3;
1186 *erom += 4;
1187 } else if ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT320x00000008) ==
1188 BWFM_DMP_DESC_ADDRESS0x00000005)
1189 wraptype = BWFM_DMP_SLAVE_TYPE_SWRAP2;
1190 else
1191 return 1;
1192
1193 do {
1194 do {
1195 val = sc->sc_buscore_ops->bc_read(sc, *erom);
1196 type = val & BWFM_DMP_DESC_MASK0x0000000F;
1197 if (type == BWFM_DMP_DESC_COMPONENT0x00000001)
1198 return 0;
1199 if (type == BWFM_DMP_DESC_EOT0x0000000F)
1200 return 1;
1201 *erom += 4;
1202 } while ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT320x00000008) !=
1203 BWFM_DMP_DESC_ADDRESS0x00000005);
1204
1205 if (type & BWFM_DMP_DESC_ADDRSIZE_GT320x00000008)
1206 *erom += 4;
1207
1208 sztype = (val & BWFM_DMP_SLAVE_SIZE_TYPE0x00000030)
1209 >> BWFM_DMP_SLAVE_SIZE_TYPE_S4;
1210 if (sztype == BWFM_DMP_SLAVE_SIZE_DESC3) {
1211 val = sc->sc_buscore_ops->bc_read(sc, *erom);
1212 type = val & BWFM_DMP_DESC_MASK0x0000000F;
1213 if (type & BWFM_DMP_DESC_ADDRSIZE_GT320x00000008)
1214 *erom += 8;
1215 else
1216 *erom += 4;
1217 }
1218 if (sztype != BWFM_DMP_SLAVE_SIZE_4K0 &&
1219 sztype != BWFM_DMP_SLAVE_SIZE_8K1)
1220 continue;
1221
1222 stype = (val & BWFM_DMP_SLAVE_TYPE0x000000C0) >> BWFM_DMP_SLAVE_TYPE_S6;
1223 if (*base == 0 && stype == BWFM_DMP_SLAVE_TYPE_SLAVE0)
1224 *base = val & BWFM_DMP_SLAVE_ADDR_BASE0xFFFFF000;
1225 if (*wrap == 0 && stype == wraptype)
1226 *wrap = val & BWFM_DMP_SLAVE_ADDR_BASE0xFFFFF000;
1227 } while (*base == 0 || *wrap == 0);
1228
1229 return 0;
1230}
1231
1232/* Core configuration */
1233int
1234bwfm_chip_set_active(struct bwfm_softc *sc, uint32_t rstvec)
1235{
1236 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR40x83E) != NULL((void *)0))
1237 return bwfm_chip_cr4_set_active(sc, rstvec);
1238 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA70x847) != NULL((void *)0))
1239 return bwfm_chip_ca7_set_active(sc, rstvec);
1240 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM30x82A) != NULL((void *)0))
1241 return bwfm_chip_cm3_set_active(sc);
1242 return 1;
1243}
1244
1245void
1246bwfm_chip_set_passive(struct bwfm_softc *sc)
1247{
1248 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR40x83E) != NULL((void *)0)) {
1249 bwfm_chip_cr4_set_passive(sc);
1250 return;
1251 }
1252 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA70x847) != NULL((void *)0)) {
1253 bwfm_chip_ca7_set_passive(sc);
1254 return;
1255 }
1256 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM30x82A) != NULL((void *)0)) {
1257 bwfm_chip_cm3_set_passive(sc);
1258 return;
1259 }
1260}
1261
1262int
1263bwfm_chip_cr4_set_active(struct bwfm_softc *sc, uint32_t rstvec)
1264{
1265 struct bwfm_core *core;
1266
1267 sc->sc_buscore_ops->bc_activate(sc, rstvec);
1268 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR40x83E);
1269 sc->sc_chip.ch_core_reset(sc, core,
1270 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT0x0020, 0, 0);
1271
1272 return 0;
1273}
1274
1275void
1276bwfm_chip_cr4_set_passive(struct bwfm_softc *sc)
1277{
1278 struct bwfm_core *core;
1279 uint32_t val;
1280 int i = 0;
1281
1282 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR40x83E);
1283 val = sc->sc_buscore_ops->bc_read(sc,
1284 core->co_wrapbase + BWFM_AGENT_IOCTL0x0408);
1285 sc->sc_chip.ch_core_reset(sc, core,
1286 val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT0x0020,
1287 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT0x0020,
1288 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT0x0020);
1289
1290 while ((core = bwfm_chip_get_core_idx(sc, BWFM_AGENT_CORE_802110x812, i++)))
1291 sc->sc_chip.ch_core_disable(sc, core,
1292 BWFM_AGENT_D11_IOCTL_PHYRESET0x0008 |
1293 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN0x0004,
1294 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN0x0004);
1295}
1296
1297int
1298bwfm_chip_ca7_set_active(struct bwfm_softc *sc, uint32_t rstvec)
1299{
1300 struct bwfm_core *core;
1301
1302 sc->sc_buscore_ops->bc_activate(sc, rstvec);
1303 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA70x847);
1304 sc->sc_chip.ch_core_reset(sc, core,
1305 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT0x0020, 0, 0);
1306
1307 return 0;
1308}
1309
1310void
1311bwfm_chip_ca7_set_passive(struct bwfm_softc *sc)
1312{
1313 struct bwfm_core *core;
1314 uint32_t val;
1315 int i = 0;
1316
1317 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA70x847);
1318 val = sc->sc_buscore_ops->bc_read(sc,
1319 core->co_wrapbase + BWFM_AGENT_IOCTL0x0408);
1320 sc->sc_chip.ch_core_reset(sc, core,
1321 val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT0x0020,
1322 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT0x0020,
1323 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT0x0020);
1324
1325 while ((core = bwfm_chip_get_core_idx(sc, BWFM_AGENT_CORE_802110x812, i++)))
1326 sc->sc_chip.ch_core_disable(sc, core,
1327 BWFM_AGENT_D11_IOCTL_PHYRESET0x0008 |
1328 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN0x0004,
1329 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN0x0004);
1330}
1331
1332int
1333bwfm_chip_cm3_set_active(struct bwfm_softc *sc)
1334{
1335 struct bwfm_core *core;
1336
1337 core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM0x80E);
1338 if (!sc->sc_chip.ch_core_isup(sc, core))
1339 return 1;
1340
1341 sc->sc_buscore_ops->bc_activate(sc, 0);
1342
1343 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM30x82A);
1344 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1345
1346 return 0;
1347}
1348
1349void
1350bwfm_chip_cm3_set_passive(struct bwfm_softc *sc)
1351{
1352 struct bwfm_core *core;
1353
1354 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM30x82A);
1355 sc->sc_chip.ch_core_disable(sc, core, 0, 0);
1356 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_802110x812);
1357 sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET0x0008 |
1358 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN0x0004, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN0x0004,
1359 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN0x0004);
1360 core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM0x80E);
1361 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1362
1363 if (sc->sc_chip.ch_chip == BRCM_CC_43430_CHIP_ID43430) {
1364 sc->sc_buscore_ops->bc_write(sc,
1365 core->co_base + BWFM_SOCRAM_BANKIDX0x0010, 3);
1366 sc->sc_buscore_ops->bc_write(sc,
1367 core->co_base + BWFM_SOCRAM_BANKPDA0x0044, 0);
1368 }
1369}
1370
1371int
1372bwfm_chip_sr_capable(struct bwfm_softc *sc)
1373{
1374 struct bwfm_core *core;
1375 uint32_t reg;
1376
1377 if (sc->sc_chip.ch_pmurev < 17)
1378 return 0;
1379
1380 switch (sc->sc_chip.ch_chip) {
1381 case BRCM_CC_4345_CHIP_ID0x4345:
1382 case BRCM_CC_4354_CHIP_ID0x4354:
1383 case BRCM_CC_4356_CHIP_ID0x4356:
1384 core = bwfm_chip_get_pmu(sc);
1385 sc->sc_buscore_ops->bc_write(sc, core->co_base +
1386 BWFM_CHIP_REG_CHIPCONTROL_ADDR0x00000650, 3);
1387 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1388 BWFM_CHIP_REG_CHIPCONTROL_DATA0x00000654);
1389 return (reg & (1 << 2)) != 0;
1390 case BRCM_CC_43241_CHIP_ID0x4324:
1391 case BRCM_CC_4335_CHIP_ID0x4335:
1392 case BRCM_CC_4339_CHIP_ID0x4339:
1393 core = bwfm_chip_get_pmu(sc);
1394 sc->sc_buscore_ops->bc_write(sc, core->co_base +
1395 BWFM_CHIP_REG_CHIPCONTROL_ADDR0x00000650, 3);
1396 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1397 BWFM_CHIP_REG_CHIPCONTROL_DATA0x00000654);
1398 return reg != 0;
1399 case BRCM_CC_43430_CHIP_ID43430:
1400 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON0x800);
1401 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1402 BWFM_CHIP_REG_SR_CONTROL10x00000508);
1403 return reg != 0;
1404 case CY_CC_4373_CHIP_ID0x4373:
1405 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON0x800);
1406 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1407 BWFM_CHIP_REG_SR_CONTROL00x00000504);
1408 return (reg & BWFM_CHIP_REG_SR_CONTROL0_ENABLE(1 << 0)) != 0;
1409 case BRCM_CC_4359_CHIP_ID0x4359:
1410 case CY_CC_43752_CHIP_ID43752:
1411 case CY_CC_43012_CHIP_ID43012:
1412 core = bwfm_chip_get_pmu(sc);
1413 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1414 BWFM_CHIP_REG_RETENTION_CTL0x00000670);
1415 return (reg & (BWFM_CHIP_REG_RETENTION_CTL_MACPHY_DIS(1 << 26) |
1416 BWFM_CHIP_REG_RETENTION_CTL_LOGIC_DIS(1 << 27))) == 0;
1417 case BRCM_CC_4378_CHIP_ID0x4378:
1418 return 0;
1419 default:
1420 core = bwfm_chip_get_pmu(sc);
1421 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1422 BWFM_CHIP_REG_PMUCAPABILITIES_EXT0x0000064C);
1423 if ((reg & BWFM_CHIP_REG_PMUCAPABILITIES_SR_SUPP(1 << 1)) == 0)
1424 return 0;
1425
1426 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1427 BWFM_CHIP_REG_RETENTION_CTL0x00000670);
1428 return (reg & (BWFM_CHIP_REG_RETENTION_CTL_MACPHY_DIS(1 << 26) |
1429 BWFM_CHIP_REG_RETENTION_CTL_LOGIC_DIS(1 << 27))) == 0;
1430 }
1431}
1432
1433/* RAM size helpers */
1434void
1435bwfm_chip_socram_ramsize(struct bwfm_softc *sc, struct bwfm_core *core)
1436{
1437 uint32_t coreinfo, nb, lss, banksize, bankinfo;
1438 uint32_t ramsize = 0, srsize = 0;
1439 int i;
1440
1441 if (!sc->sc_chip.ch_core_isup(sc, core))
1442 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1443
1444 coreinfo = sc->sc_buscore_ops->bc_read(sc,
1445 core->co_base + BWFM_SOCRAM_COREINFO0x0000);
1446 nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK0xf0)
1447 >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT4;
1448
1449 if (core->co_rev <= 7 || core->co_rev == 12) {
1450 banksize = coreinfo & BWFM_SOCRAM_COREINFO_SRBSZ_MASK0xf;
1451 lss = (coreinfo & BWFM_SOCRAM_COREINFO_LSS_MASK0xf00000)
1452 >> BWFM_SOCRAM_COREINFO_LSS_SHIFT20;
1453 if (lss != 0)
1454 nb--;
1455 ramsize = nb * (1 << (banksize + BWFM_SOCRAM_COREINFO_SRBSZ_BASE14));
1456 if (lss != 0)
1457 ramsize += (1 << ((lss - 1) + BWFM_SOCRAM_COREINFO_SRBSZ_BASE14));
1458 } else {
1459 for (i = 0; i < nb; i++) {
1460 sc->sc_buscore_ops->bc_write(sc,
1461 core->co_base + BWFM_SOCRAM_BANKIDX0x0010,
1462 (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM0 <<
1463 BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT8) | i);
1464 bankinfo = sc->sc_buscore_ops->bc_read(sc,
1465 core->co_base + BWFM_SOCRAM_BANKINFO0x0040);
1466 banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK0x7f) + 1)
1467 * BWFM_SOCRAM_BANKINFO_SZBASE8192;
1468 ramsize += banksize;
1469 if (bankinfo & BWFM_SOCRAM_BANKINFO_RETNTRAM_MASK0x10000)
1470 srsize += banksize;
1471 }
1472 }
1473
1474 switch (sc->sc_chip.ch_chip) {
1475 case BRCM_CC_4334_CHIP_ID0x4334:
1476 if (sc->sc_chip.ch_chiprev < 2)
1477 srsize = 32 * 1024;
1478 break;
1479 case BRCM_CC_43430_CHIP_ID43430:
1480 srsize = 64 * 1024;
1481 break;
1482 default:
1483 break;
1484 }
1485
1486 sc->sc_chip.ch_ramsize = ramsize;
1487 sc->sc_chip.ch_srsize = srsize;
1488}
1489
1490void
1491bwfm_chip_sysmem_ramsize(struct bwfm_softc *sc, struct bwfm_core *core)
1492{
1493 uint32_t coreinfo, nb, banksize, bankinfo;
1494 uint32_t ramsize = 0;
1495 int i;
1496
1497 if (!sc->sc_chip.ch_core_isup(sc, core))
1498 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1499
1500 coreinfo = sc->sc_buscore_ops->bc_read(sc,
1501 core->co_base + BWFM_SOCRAM_COREINFO0x0000);
1502 nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK0xf0)
1503 >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT4;
1504
1505 for (i = 0; i < nb; i++) {
1506 sc->sc_buscore_ops->bc_write(sc,
1507 core->co_base + BWFM_SOCRAM_BANKIDX0x0010,
1508 (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM0 <<
1509 BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT8) | i);
1510 bankinfo = sc->sc_buscore_ops->bc_read(sc,
1511 core->co_base + BWFM_SOCRAM_BANKINFO0x0040);
1512 banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK0x7f) + 1)
1513 * BWFM_SOCRAM_BANKINFO_SZBASE8192;
1514 ramsize += banksize;
1515 }
1516
1517 sc->sc_chip.ch_ramsize = ramsize;
1518}
1519
1520void
1521bwfm_chip_tcm_ramsize(struct bwfm_softc *sc, struct bwfm_core *core)
1522{
1523 uint32_t cap, nab, nbb, totb, bxinfo, blksize, ramsize = 0;
1524 int i;
1525
1526 cap = sc->sc_buscore_ops->bc_read(sc, core->co_base + BWFM_ARMCR4_CAP0x0004);
1527 nab = (cap & BWFM_ARMCR4_CAP_TCBANB_MASK0xf) >> BWFM_ARMCR4_CAP_TCBANB_SHIFT0;
1528 nbb = (cap & BWFM_ARMCR4_CAP_TCBBNB_MASK0xf0) >> BWFM_ARMCR4_CAP_TCBBNB_SHIFT4;
1529 totb = nab + nbb;
1530
1531 for (i = 0; i < totb; i++) {
1532 sc->sc_buscore_ops->bc_write(sc,
1533 core->co_base + BWFM_ARMCR4_BANKIDX0x0040, i);
1534 bxinfo = sc->sc_buscore_ops->bc_read(sc,
1535 core->co_base + BWFM_ARMCR4_BANKINFO0x0044);
1536 if (bxinfo & BWFM_ARMCR4_BANKINFO_BLK_1K_MASK0x200)
1537 blksize = 1024;
1538 else
1539 blksize = 8192;
1540 ramsize += ((bxinfo & BWFM_ARMCR4_BANKINFO_BSZ_MASK0x7f) + 1) *
1541 blksize;
1542 }
1543
1544 sc->sc_chip.ch_ramsize = ramsize;
1545}
1546
1547void
1548bwfm_chip_tcm_rambase(struct bwfm_softc *sc)
1549{
1550 switch (sc->sc_chip.ch_chip) {
1551 case BRCM_CC_4345_CHIP_ID0x4345:
1552 sc->sc_chip.ch_rambase = 0x198000;
1553 break;
1554 case BRCM_CC_4335_CHIP_ID0x4335:
1555 case BRCM_CC_4339_CHIP_ID0x4339:
1556 case BRCM_CC_4350_CHIP_ID0x4350:
1557 case BRCM_CC_4354_CHIP_ID0x4354:
1558 case BRCM_CC_4356_CHIP_ID0x4356:
1559 case BRCM_CC_43567_CHIP_ID43567:
1560 case BRCM_CC_43569_CHIP_ID43569:
1561 case BRCM_CC_43570_CHIP_ID43570:
1562 case BRCM_CC_4358_CHIP_ID0x4358:
1563 case BRCM_CC_43602_CHIP_ID43602:
1564 case BRCM_CC_4371_CHIP_ID0x4371:
1565 sc->sc_chip.ch_rambase = 0x180000;
1566 break;
1567 case BRCM_CC_43465_CHIP_ID43465:
1568 case BRCM_CC_43525_CHIP_ID43525:
1569 case BRCM_CC_4365_CHIP_ID0x4365:
1570 case BRCM_CC_4366_CHIP_ID0x4366:
1571 case BRCM_CC_43664_CHIP_ID43664:
1572 case BRCM_CC_43666_CHIP_ID43666:
1573 sc->sc_chip.ch_rambase = 0x200000;
1574 break;
1575 case BRCM_CC_4359_CHIP_ID0x4359:
1576 if (sc->sc_chip.ch_chiprev < 9)
1577 sc->sc_chip.ch_rambase = 0x180000;
1578 else
1579 sc->sc_chip.ch_rambase = 0x160000;
1580 break;
1581 case BRCM_CC_4355_CHIP_ID0x4355:
1582 case BRCM_CC_4364_CHIP_ID0x4364:
1583 case CY_CC_4373_CHIP_ID0x4373:
1584 sc->sc_chip.ch_rambase = 0x160000;
1585 break;
1586 case BRCM_CC_4377_CHIP_ID0x4377:
1587 case CY_CC_43752_CHIP_ID43752:
1588 sc->sc_chip.ch_rambase = 0x170000;
1589 break;
1590 case BRCM_CC_4378_CHIP_ID0x4378:
1591 sc->sc_chip.ch_rambase = 0x352000;
1592 break;
1593 case BRCM_CC_4387_CHIP_ID0x4387:
1594 sc->sc_chip.ch_rambase = 0x740000;
1595 break;
1596 default:
1597 printf("%s: unknown chip: %d\n", DEVNAME(sc)((sc)->sc_dev.dv_xname),
1598 sc->sc_chip.ch_chip);
1599 break;
1600 }
1601}
1602
1603/* BCDC protocol implementation */
1604int
1605bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *sc, int ifidx,
1606 int cmd, char *buf, size_t *len)
1607{
1608 struct bwfm_proto_bcdc_dcmd *dcmd;
1609 size_t size = sizeof(dcmd->hdr) + *len;
1610 int ret = 1, reqid;
1611
1612 reqid = sc->sc_bcdc_reqid++;
1613
1614 if (*len > sizeof(dcmd->buf))
1615 return ret;
1616
1617 dcmd = malloc(size, M_TEMP127, M_WAITOK0x0001 | M_ZERO0x0008);
1618 dcmd->hdr.cmd = htole32(cmd)((__uint32_t)(cmd));
1619 dcmd->hdr.len = htole32(*len)((__uint32_t)(*len));
1620 dcmd->hdr.flags |= BWFM_BCDC_DCMD_GET(0 << 1);
1621 dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid)(((reqid) & 0xffff) << 16);
1622 dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx)(((ifidx) & 0xf) << 12);
1623 dcmd->hdr.flags = htole32(dcmd->hdr.flags)((__uint32_t)(dcmd->hdr.flags));
1624 memcpy(&dcmd->buf, buf, *len)__builtin_memcpy((&dcmd->buf), (buf), (*len));
1625
1626 if (bwfm_proto_bcdc_txctl(sc, reqid, (char *)dcmd, &size)) {
1627 DPRINTF(("%s: tx failed\n", DEVNAME(sc)))do { ; } while (0);
1628 return ret;
1629 }
1630
1631 if (buf) {
1632 *len = min(*len, size);
1633 memcpy(buf, dcmd->buf, *len)__builtin_memcpy((buf), (dcmd->buf), (*len));
1634 }
1635
1636 if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR(1 << 0))
1637 ret = dcmd->hdr.status;
1638 else
1639 ret = 0;
1640 free(dcmd, M_TEMP127, size);
1641 return ret;
1642}
1643
1644int
1645bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *sc, int ifidx,
1646 int cmd, char *buf, size_t len)
1647{
1648 struct bwfm_proto_bcdc_dcmd *dcmd;
1649 size_t size = sizeof(dcmd->hdr) + len;
1650 int ret = 1, reqid;
1651
1652 reqid = sc->sc_bcdc_reqid++;
1653
1654 if (len > sizeof(dcmd->buf))
1655 return ret;
1656
1657 dcmd = malloc(size, M_TEMP127, M_WAITOK0x0001 | M_ZERO0x0008);
1658 dcmd->hdr.cmd = htole32(cmd)((__uint32_t)(cmd));
1659 dcmd->hdr.len = htole32(len)((__uint32_t)(len));
1660 dcmd->hdr.flags |= BWFM_BCDC_DCMD_SET(1 << 1);
1661 dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid)(((reqid) & 0xffff) << 16);
1662 dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx)(((ifidx) & 0xf) << 12);
1663 dcmd->hdr.flags = htole32(dcmd->hdr.flags)((__uint32_t)(dcmd->hdr.flags));
1664 memcpy(&dcmd->buf, buf, len)__builtin_memcpy((&dcmd->buf), (buf), (len));
1665
1666 if (bwfm_proto_bcdc_txctl(sc, reqid, (char *)dcmd, &size)) {
1667 DPRINTF(("%s: txctl failed\n", DEVNAME(sc)))do { ; } while (0);
1668 return ret;
1669 }
1670
1671 if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR(1 << 0))
1672 ret = dcmd->hdr.status;
1673 else
1674 ret = 0;
1675 free(dcmd, M_TEMP127, size);
1676 return ret;
1677}
1678
1679int
1680bwfm_proto_bcdc_txctl(struct bwfm_softc *sc, int reqid, char *buf, size_t *len)
1681{
1682 struct bwfm_proto_bcdc_ctl *ctl, *tmp;
1683 int timeout = 0;
1684
1685 ctl = malloc(sizeof(*ctl), M_TEMP127, M_WAITOK0x0001|M_ZERO0x0008);
1686 ctl->reqid = reqid;
1687 ctl->buf = buf;
1688 ctl->len = *len;
1689
1690 if (sc->sc_bus_ops->bs_txctl(sc, ctl)) {
1691 DPRINTF(("%s: tx failed\n", DEVNAME(sc)))do { ; } while (0);
1692 return 1;
1693 }
1694
1695 if (tsleep_nsec(ctl, PWAIT32, "bwfm", SEC_TO_NSEC(1)))
1696 timeout = 1;
1697
1698 TAILQ_FOREACH_SAFE(ctl, &sc->sc_bcdc_rxctlq, next, tmp)for ((ctl) = ((&sc->sc_bcdc_rxctlq)->tqh_first); (ctl
) != ((void *)0) && ((tmp) = ((ctl)->next.tqe_next
), 1); (ctl) = (tmp))
{
1699 if (ctl->reqid != reqid)
1700 continue;
1701 if (ctl->done) {
1702 TAILQ_REMOVE(&sc->sc_bcdc_rxctlq, ctl, next)do { if (((ctl)->next.tqe_next) != ((void *)0)) (ctl)->
next.tqe_next->next.tqe_prev = (ctl)->next.tqe_prev; else
(&sc->sc_bcdc_rxctlq)->tqh_last = (ctl)->next.tqe_prev
; *(ctl)->next.tqe_prev = (ctl)->next.tqe_next; ((ctl)->
next.tqe_prev) = ((void *)-1); ((ctl)->next.tqe_next) = ((
void *)-1); } while (0)
;
1703 *len = ctl->len;
1704 free(ctl, M_TEMP127, sizeof(*ctl));
1705 return 0;
1706 }
1707 if (timeout) {
1708 TAILQ_REMOVE(&sc->sc_bcdc_rxctlq, ctl, next)do { if (((ctl)->next.tqe_next) != ((void *)0)) (ctl)->
next.tqe_next->next.tqe_prev = (ctl)->next.tqe_prev; else
(&sc->sc_bcdc_rxctlq)->tqh_last = (ctl)->next.tqe_prev
; *(ctl)->next.tqe_prev = (ctl)->next.tqe_next; ((ctl)->
next.tqe_prev) = ((void *)-1); ((ctl)->next.tqe_next) = ((
void *)-1); } while (0)
;
1709 DPRINTF(("%s: timeout waiting for txctl response\n",do { ; } while (0)
1710 DEVNAME(sc)))do { ; } while (0);
1711 free(ctl->buf, M_TEMP127, ctl->len);
1712 free(ctl, M_TEMP127, sizeof(*ctl));
1713 return 1;
1714 }
1715 break;
1716 }
1717
1718 DPRINTF(("%s: did%s find txctl metadata (timeout %d)\n",do { ; } while (0)
1719 DEVNAME(sc), ctl == NULL ? " not": "", timeout))do { ; } while (0);
1720 return 1;
1721}
1722
1723void
1724bwfm_proto_bcdc_rxctl(struct bwfm_softc *sc, char *buf, size_t len)
1725{
1726 struct bwfm_proto_bcdc_dcmd *dcmd;
1727 struct bwfm_proto_bcdc_ctl *ctl, *tmp;
1728
1729 if (len < sizeof(dcmd->hdr))
1730 return;
1731
1732 dcmd = (struct bwfm_proto_bcdc_dcmd *)buf;
1733 dcmd->hdr.cmd = letoh32(dcmd->hdr.cmd)((__uint32_t)(dcmd->hdr.cmd));
1734 dcmd->hdr.len = letoh32(dcmd->hdr.len)((__uint32_t)(dcmd->hdr.len));
1735 dcmd->hdr.flags = letoh32(dcmd->hdr.flags)((__uint32_t)(dcmd->hdr.flags));
1736 dcmd->hdr.status = letoh32(dcmd->hdr.status)((__uint32_t)(dcmd->hdr.status));
1737
1738 TAILQ_FOREACH_SAFE(ctl, &sc->sc_bcdc_rxctlq, next, tmp)for ((ctl) = ((&sc->sc_bcdc_rxctlq)->tqh_first); (ctl
) != ((void *)0) && ((tmp) = ((ctl)->next.tqe_next
), 1); (ctl) = (tmp))
{
1739 if (ctl->reqid != BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags)(((dcmd->hdr.flags) >> 16) & 0xffff))
1740 continue;
1741 if (ctl->len != len) {
1742 free(ctl->buf, M_TEMP127, ctl->len);
1743 free(ctl, M_TEMP127, sizeof(*ctl));
1744 return;
1745 }
1746 memcpy(ctl->buf, buf, len)__builtin_memcpy((ctl->buf), (buf), (len));
1747 ctl->done = 1;
1748 wakeup(ctl);
1749 return;
1750 }
1751}
1752
1753void
1754bwfm_proto_bcdc_rx(struct bwfm_softc *sc, struct mbuf *m, struct mbuf_list *ml)
1755{
1756 struct bwfm_proto_bcdc_hdr *hdr;
1757
1758 hdr = mtod(m, struct bwfm_proto_bcdc_hdr *)((struct bwfm_proto_bcdc_hdr *)((m)->m_hdr.mh_data));
1759 if (m->m_lenm_hdr.mh_len < sizeof(*hdr)) {
1760 m_freem(m);
1761 return;
1762 }
1763 if (m->m_lenm_hdr.mh_len < sizeof(*hdr) + (hdr->data_offset << 2)) {
1764 m_freem(m);
1765 return;
1766 }
1767 m_adj(m, sizeof(*hdr) + (hdr->data_offset << 2));
1768
1769 bwfm_rx(sc, m, ml);
1770}
1771
1772/* FW Variable code */
1773int
1774bwfm_fwvar_cmd_get_data(struct bwfm_softc *sc, int cmd, void *data, size_t len)
1775{
1776 return sc->sc_proto_ops->proto_query_dcmd(sc, 0, cmd, data, &len);
1777}
1778
1779int
1780bwfm_fwvar_cmd_set_data(struct bwfm_softc *sc, int cmd, void *data, size_t len)
1781{
1782 return sc->sc_proto_ops->proto_set_dcmd(sc, 0, cmd, data, len);
1783}
1784
1785int
1786bwfm_fwvar_cmd_get_int(struct bwfm_softc *sc, int cmd, uint32_t *data)
1787{
1788 int ret;
1789 ret = bwfm_fwvar_cmd_get_data(sc, cmd, data, sizeof(*data));
1790 *data = letoh32(*data)((__uint32_t)(*data));
1791 return ret;
1792}
1793
1794int
1795bwfm_fwvar_cmd_set_int(struct bwfm_softc *sc, int cmd, uint32_t data)
1796{
1797 data = htole32(data)((__uint32_t)(data));
1798 return bwfm_fwvar_cmd_set_data(sc, cmd, &data, sizeof(data));
1799}
1800
1801int
1802bwfm_fwvar_var_get_data(struct bwfm_softc *sc, char *name, void *data, size_t len)
1803{
1804 char *buf;
1805 int ret;
1806
1807 buf = malloc(strlen(name) + 1 + len, M_TEMP127, M_WAITOK0x0001);
1808 memcpy(buf, name, strlen(name) + 1)__builtin_memcpy((buf), (name), (strlen(name) + 1));
1809 memcpy(buf + strlen(name) + 1, data, len)__builtin_memcpy((buf + strlen(name) + 1), (data), (len));
1810 ret = bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_VAR262,
1811 buf, strlen(name) + 1 + len);
1812 memcpy(data, buf, len)__builtin_memcpy((data), (buf), (len));
1813 free(buf, M_TEMP127, strlen(name) + 1 + len);
1814 return ret;
1815}
1816
1817int
1818bwfm_fwvar_var_set_data(struct bwfm_softc *sc, char *name, void *data, size_t len)
1819{
1820 char *buf;
1821 int ret;
1822
1823 buf = malloc(strlen(name) + 1 + len, M_TEMP127, M_WAITOK0x0001);
1824 memcpy(buf, name, strlen(name) + 1)__builtin_memcpy((buf), (name), (strlen(name) + 1));
1825 memcpy(buf + strlen(name) + 1, data, len)__builtin_memcpy((buf + strlen(name) + 1), (data), (len));
1826 ret = bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_VAR263,
1827 buf, strlen(name) + 1 + len);
1828 free(buf, M_TEMP127, strlen(name) + 1 + len);
1829 return ret;
1830}
1831
1832int
1833bwfm_fwvar_var_get_int(struct bwfm_softc *sc, char *name, uint32_t *data)
1834{
1835 int ret;
1836 ret = bwfm_fwvar_var_get_data(sc, name, data, sizeof(*data));
1837 *data = letoh32(*data)((__uint32_t)(*data));
1838 return ret;
1839}
1840
1841int
1842bwfm_fwvar_var_set_int(struct bwfm_softc *sc, char *name, uint32_t data)
1843{
1844 data = htole32(data)((__uint32_t)(data));
1845 return bwfm_fwvar_var_set_data(sc, name, &data, sizeof(data));
1846}
1847
1848/* Channel parameters */
1849uint32_t
1850bwfm_chan2spec(struct bwfm_softc *sc, struct ieee80211_channel *c)
1851{
1852 if (sc->sc_io_type == BWFM_IO_TYPE_D11N1)
1853 return bwfm_chan2spec_d11n(sc, c);
1854 else
1855 return bwfm_chan2spec_d11ac(sc, c);
1856}
1857
1858uint32_t
1859bwfm_chan2spec_d11n(struct bwfm_softc *sc, struct ieee80211_channel *c)
1860{
1861 uint32_t chanspec;
1862
1863 chanspec = ieee80211_mhz2ieee(c->ic_freq, 0) & BWFM_CHANSPEC_CHAN_MASK0xff;
1864 chanspec |= BWFM_CHANSPEC_D11N_SB_N(0x3 << 8);
1865 chanspec |= BWFM_CHANSPEC_D11N_BW_20(0x2 << 10);
1866 if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0))
1867 chanspec |= BWFM_CHANSPEC_D11N_BND_2G(0x2 << 12);
1868 if (IEEE80211_IS_CHAN_5GHZ(c)(((c)->ic_flags & 0x0100) != 0))
1869 chanspec |= BWFM_CHANSPEC_D11N_BND_5G(0x1 << 12);
1870
1871 return chanspec;
1872}
1873
1874uint32_t
1875bwfm_chan2spec_d11ac(struct bwfm_softc *sc, struct ieee80211_channel *c)
1876{
1877 uint32_t chanspec;
1878
1879 chanspec = ieee80211_mhz2ieee(c->ic_freq, 0) & BWFM_CHANSPEC_CHAN_MASK0xff;
1880 chanspec |= BWFM_CHANSPEC_D11AC_SB_LLL(0x0 << 8);
1881 chanspec |= BWFM_CHANSPEC_D11AC_BW_20(0x2 << 11);
1882 if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0))
1883 chanspec |= BWFM_CHANSPEC_D11AC_BND_2G(0x0 << 14);
1884 if (IEEE80211_IS_CHAN_5GHZ(c)(((c)->ic_flags & 0x0100) != 0))
1885 chanspec |= BWFM_CHANSPEC_D11AC_BND_5G(0x3 << 14);
1886
1887 return chanspec;
1888}
1889
1890uint32_t
1891bwfm_spec2chan(struct bwfm_softc *sc, uint32_t chanspec)
1892{
1893 if (sc->sc_io_type == BWFM_IO_TYPE_D11N1)
1894 return bwfm_spec2chan_d11n(sc, chanspec);
1895 else
1896 return bwfm_spec2chan_d11ac(sc, chanspec);
1897}
1898
1899uint32_t
1900bwfm_spec2chan_d11n(struct bwfm_softc *sc, uint32_t chanspec)
1901{
1902 uint32_t chanidx;
1903
1904 chanidx = chanspec & BWFM_CHANSPEC_CHAN_MASK0xff;
1905
1906 switch (chanspec & BWFM_CHANSPEC_D11N_BW_MASK(0x3 << 10)) {
1907 case BWFM_CHANSPEC_D11N_BW_40(0x3 << 10):
1908 switch (chanspec & BWFM_CHANSPEC_D11N_SB_MASK(0x3 << 8)) {
1909 case BWFM_CHANSPEC_D11N_SB_L(0x1 << 8):
1910 chanidx -= 2;
1911 break;
1912 case BWFM_CHANSPEC_D11N_SB_U(0x2 << 8):
1913 chanidx += 2;
1914 break;
1915 default:
1916 break;
1917 }
1918 break;
1919 default:
1920 break;
1921 }
1922
1923 return chanidx;
1924}
1925
1926uint32_t
1927bwfm_spec2chan_d11ac(struct bwfm_softc *sc, uint32_t chanspec)
1928{
1929 uint32_t chanidx;
1930
1931 chanidx = chanspec & BWFM_CHANSPEC_CHAN_MASK0xff;
1932
1933 switch (chanspec & BWFM_CHANSPEC_D11AC_BW_MASK(0x7 << 11)) {
1934 case BWFM_CHANSPEC_D11AC_BW_40(0x3 << 11):
1935 switch (chanspec & BWFM_CHANSPEC_D11AC_SB_MASK(0x7 << 8)) {
1936 case BWFM_CHANSPEC_D11AC_SB_LLL(0x0 << 8):
1937 chanidx -= 2;
1938 break;
1939 case BWFM_CHANSPEC_D11AC_SB_LLU(0x1 << 8):
1940 chanidx += 2;
1941 break;
1942 default:
1943 break;
1944 }
1945 break;
1946 case BWFM_CHANSPEC_D11AC_BW_80(0x4 << 11):
1947 switch (chanspec & BWFM_CHANSPEC_D11AC_SB_MASK(0x7 << 8)) {
1948 case BWFM_CHANSPEC_D11AC_SB_LLL(0x0 << 8):
1949 chanidx -= 6;
1950 break;
1951 case BWFM_CHANSPEC_D11AC_SB_LLU(0x1 << 8):
1952 chanidx -= 2;
1953 break;
1954 case BWFM_CHANSPEC_D11AC_SB_LUL(0x2 << 8):
1955 chanidx += 2;
1956 break;
1957 case BWFM_CHANSPEC_D11AC_SB_LUU(0x3 << 8):
1958 chanidx += 6;
1959 break;
1960 default:
1961 break;
1962 }
1963 break;
1964 default:
1965 break;
1966 }
1967
1968 return chanidx;
1969}
1970
1971/* 802.11 code */
1972void
1973bwfm_connect(struct bwfm_softc *sc)
1974{
1975 struct ieee80211com *ic = &sc->sc_ic;
1976 struct bwfm_ext_join_params *params;
1977 uint8_t buf[64]; /* XXX max WPA/RSN/WMM IE length */
1978 uint8_t *frm;
1979
1980 /*
1981 * OPEN: Open or WEP or WPA/WPA2 on newer Chips/Firmware.
1982 * AUTO: Automatic, probably for older Chips/Firmware.
1983 */
1984 if (ic->ic_flags & IEEE80211_F_RSNON0x00200000) {
1985 uint32_t wsec = 0;
1986 uint32_t wpa = 0;
1987
1988 /* tell firmware to add WPA/RSN IE to (re)assoc request */
1989 if (ic->ic_bss->ni_rsnprotos == IEEE80211_PROTO_RSN(1 << 0))
1990 frm = ieee80211_add_rsn(buf, ic, ic->ic_bss);
1991 else
1992 frm = ieee80211_add_wpa(buf, ic, ic->ic_bss);
1993 bwfm_fwvar_var_set_data(sc, "wpaie", buf, frm - buf);
1994
1995 if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA(1 << 1)) {
1996 if (ic->ic_rsnakms & IEEE80211_AKM_PSK)
1997 wpa |= BWFM_WPA_AUTH_WPA_PSK(1 << 2);
1998 if (ic->ic_rsnakms & IEEE80211_AKM_8021X)
1999 wpa |= BWFM_WPA_AUTH_WPA_UNSPECIFIED(1 << 1);
2000 }
2001 if (ic->ic_rsnprotos & IEEE80211_PROTO_RSN(1 << 0)) {
2002 if (ic->ic_rsnakms & IEEE80211_AKM_PSK)
2003 wpa |= BWFM_WPA_AUTH_WPA2_PSK(1 << 7);
2004 if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_PSK)
2005 wpa |= BWFM_WPA_AUTH_WPA2_PSK_SHA256(1 << 15);
2006 if (ic->ic_rsnakms & IEEE80211_AKM_8021X)
2007 wpa |= BWFM_WPA_AUTH_WPA2_UNSPECIFIED(1 << 6);
2008 if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_8021X)
2009 wpa |= BWFM_WPA_AUTH_WPA2_1X_SHA256(1 << 12);
2010 }
2011 if (ic->ic_rsnciphers & IEEE80211_WPA_CIPHER_TKIP0x04 ||
2012 ic->ic_rsngroupcipher & IEEE80211_WPA_CIPHER_TKIP0x04)
2013 wsec |= BWFM_WSEC_TKIP(1 << 1);
2014 if (ic->ic_rsnciphers & IEEE80211_WPA_CIPHER_CCMP0x08 ||
2015 ic->ic_rsngroupcipher & IEEE80211_WPA_CIPHER_CCMP0x08)
2016 wsec |= BWFM_WSEC_AES(1 << 2);
2017
2018 bwfm_fwvar_var_set_int(sc, "wpa_auth", wpa);
2019 bwfm_fwvar_var_set_int(sc, "wsec", wsec);
2020 } else if (ic->ic_flags & IEEE80211_F_WEPON0x00000100) {
2021 bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_DISABLED(0 << 0));
2022 bwfm_fwvar_var_set_int(sc, "wsec", BWFM_WSEC_WEP(1 << 0));
2023 } else {
2024 bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_DISABLED(0 << 0));
2025 bwfm_fwvar_var_set_int(sc, "wsec", BWFM_WSEC_NONE(0 << 0));
2026 }
2027 bwfm_fwvar_var_set_int(sc, "auth", BWFM_AUTH_OPEN0);
2028 bwfm_fwvar_var_set_int(sc, "mfp", BWFM_MFP_NONE0);
2029
2030 if (ic->ic_des_esslen && ic->ic_des_esslen <= BWFM_MAX_SSID_LEN32) {
2031 params = malloc(sizeof(*params), M_TEMP127, M_WAITOK0x0001 | M_ZERO0x0008);
2032 memcpy(params->ssid.ssid, ic->ic_des_essid, ic->ic_des_esslen)__builtin_memcpy((params->ssid.ssid), (ic->ic_des_essid
), (ic->ic_des_esslen))
;
2033 params->ssid.len = htole32(ic->ic_des_esslen)((__uint32_t)(ic->ic_des_esslen));
2034 memcpy(params->assoc.bssid, ic->ic_bss->ni_bssid,__builtin_memcpy((params->assoc.bssid), (ic->ic_bss->
ni_bssid), (sizeof(params->assoc.bssid)))
2035 sizeof(params->assoc.bssid))__builtin_memcpy((params->assoc.bssid), (ic->ic_bss->
ni_bssid), (sizeof(params->assoc.bssid)))
;
2036 params->scan.scan_type = -1;
2037 params->scan.nprobes = htole32(-1)((__uint32_t)(-1));
2038 params->scan.active_time = htole32(-1)((__uint32_t)(-1));
2039 params->scan.passive_time = htole32(-1)((__uint32_t)(-1));
2040 params->scan.home_time = htole32(-1)((__uint32_t)(-1));
2041 if (bwfm_fwvar_var_set_data(sc, "join", params, sizeof(*params))) {
2042 struct bwfm_join_params join;
2043 memset(&join, 0, sizeof(join))__builtin_memset((&join), (0), (sizeof(join)));
2044 memcpy(join.ssid.ssid, ic->ic_des_essid,__builtin_memcpy((join.ssid.ssid), (ic->ic_des_essid), (ic
->ic_des_esslen))
2045 ic->ic_des_esslen)__builtin_memcpy((join.ssid.ssid), (ic->ic_des_essid), (ic
->ic_des_esslen))
;
2046 join.ssid.len = htole32(ic->ic_des_esslen)((__uint32_t)(ic->ic_des_esslen));
2047 memcpy(join.assoc.bssid, ic->ic_bss->ni_bssid,__builtin_memcpy((join.assoc.bssid), (ic->ic_bss->ni_bssid
), (sizeof(join.assoc.bssid)))
2048 sizeof(join.assoc.bssid))__builtin_memcpy((join.assoc.bssid), (ic->ic_bss->ni_bssid
), (sizeof(join.assoc.bssid)))
;
2049 bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID26, &join,
2050 sizeof(join));
2051 }
2052 free(params, M_TEMP127, sizeof(*params));
2053 }
2054}
2055
2056#ifndef IEEE80211_STA_ONLY
2057void
2058bwfm_hostap(struct bwfm_softc *sc)
2059{
2060 struct ieee80211com *ic = &sc->sc_ic;
2061 struct ieee80211_node *ni = ic->ic_bss;
2062 struct bwfm_join_params join;
2063
2064 /*
2065 * OPEN: Open or WEP or WPA/WPA2 on newer Chips/Firmware.
2066 * AUTO: Automatic, probably for older Chips/Firmware.
2067 */
2068 if (ic->ic_flags & IEEE80211_F_RSNON0x00200000) {
2069 uint32_t wsec = 0;
2070 uint32_t wpa = 0;
2071
2072 /* TODO: Turn off if replay counter set */
2073 if (ni->ni_rsnprotos & IEEE80211_PROTO_RSN(1 << 0))
2074 bwfm_fwvar_var_set_int(sc, "wme_bss_disable", 1);
2075
2076 if (ni->ni_rsnprotos & IEEE80211_PROTO_WPA(1 << 1)) {
2077 if (ni->ni_rsnakms & IEEE80211_AKM_PSK)
2078 wpa |= BWFM_WPA_AUTH_WPA_PSK(1 << 2);
2079 if (ni->ni_rsnakms & IEEE80211_AKM_8021X)
2080 wpa |= BWFM_WPA_AUTH_WPA_UNSPECIFIED(1 << 1);
2081 }
2082 if (ni->ni_rsnprotos & IEEE80211_PROTO_RSN(1 << 0)) {
2083 if (ni->ni_rsnakms & IEEE80211_AKM_PSK)
2084 wpa |= BWFM_WPA_AUTH_WPA2_PSK(1 << 7);
2085 if (ni->ni_rsnakms & IEEE80211_AKM_SHA256_PSK)
2086 wpa |= BWFM_WPA_AUTH_WPA2_PSK_SHA256(1 << 15);
2087 if (ni->ni_rsnakms & IEEE80211_AKM_8021X)
2088 wpa |= BWFM_WPA_AUTH_WPA2_UNSPECIFIED(1 << 6);
2089 if (ni->ni_rsnakms & IEEE80211_AKM_SHA256_8021X)
2090 wpa |= BWFM_WPA_AUTH_WPA2_1X_SHA256(1 << 12);
2091 }
2092 if (ni->ni_rsnciphers & IEEE80211_WPA_CIPHER_TKIP0x04 ||
2093 ni->ni_rsngroupcipher & IEEE80211_WPA_CIPHER_TKIP0x04)
2094 wsec |= BWFM_WSEC_TKIP(1 << 1);
2095 if (ni->ni_rsnciphers & IEEE80211_WPA_CIPHER_CCMP0x08 ||
2096 ni->ni_rsngroupcipher & IEEE80211_WPA_CIPHER_CCMP0x08)
2097 wsec |= BWFM_WSEC_AES(1 << 2);
2098
2099 bwfm_fwvar_var_set_int(sc, "wpa_auth", wpa);
2100 bwfm_fwvar_var_set_int(sc, "wsec", wsec);
2101 } else {
2102 bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_DISABLED(0 << 0));
2103 bwfm_fwvar_var_set_int(sc, "wsec", BWFM_WSEC_NONE(0 << 0));
2104 }
2105 bwfm_fwvar_var_set_int(sc, "auth", BWFM_AUTH_OPEN0);
2106 bwfm_fwvar_var_set_int(sc, "mfp", BWFM_MFP_NONE0);
2107
2108 bwfm_fwvar_var_set_int(sc, "mpc", 0);
2109 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA20, 1);
2110 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP118, 1);
2111 bwfm_fwvar_var_set_int(sc, "chanspec",
2112 bwfm_chan2spec(sc, ic->ic_bss->ni_chan));
2113 bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP2, 1);
2114
2115 memset(&join, 0, sizeof(join))__builtin_memset((&join), (0), (sizeof(join)));
2116 memcpy(join.ssid.ssid, ic->ic_des_essid, ic->ic_des_esslen)__builtin_memcpy((join.ssid.ssid), (ic->ic_des_essid), (ic
->ic_des_esslen))
;
2117 join.ssid.len = htole32(ic->ic_des_esslen)((__uint32_t)(ic->ic_des_esslen));
2118 memset(join.assoc.bssid, 0xff, sizeof(join.assoc.bssid))__builtin_memset((join.assoc.bssid), (0xff), (sizeof(join.assoc
.bssid)))
;
2119 bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID26, &join, sizeof(join));
2120 bwfm_fwvar_var_set_int(sc, "closednet",
2121 (ic->ic_userflags & IEEE80211_F_HIDENWID0x00000001) != 0);
2122}
2123#endif
2124
2125void
2126bwfm_scan_v0(struct bwfm_softc *sc)
2127{
2128 struct ieee80211com *ic = &sc->sc_ic;
2129 struct bwfm_escan_params_v0 *params;
2130 uint32_t nssid = 0, nchan = 0;
2131 size_t params_size, chan_size, ssid_size;
2132 struct bwfm_ssid *ssid;
2133
2134 if (ic->ic_flags & IEEE80211_F_ASCAN0x00000001 &&
2135 ic->ic_des_esslen && ic->ic_des_esslen <= BWFM_MAX_SSID_LEN32)
2136 nssid = 1;
2137
2138 chan_size = roundup(nchan * sizeof(uint16_t), sizeof(uint32_t))((((nchan * sizeof(uint16_t))+((sizeof(uint32_t))-1))/(sizeof
(uint32_t)))*(sizeof(uint32_t)))
;
2139 ssid_size = sizeof(struct bwfm_ssid) * nssid;
2140 params_size = sizeof(*params) + chan_size + ssid_size;
2141
2142 params = malloc(params_size, M_TEMP127, M_WAITOK0x0001 | M_ZERO0x0008);
2143 ssid = (struct bwfm_ssid *)
2144 (((uint8_t *)params) + sizeof(*params) + chan_size);
2145
2146 memset(params->scan_params.bssid, 0xff,__builtin_memset((params->scan_params.bssid), (0xff), (sizeof
(params->scan_params.bssid)))
2147 sizeof(params->scan_params.bssid))__builtin_memset((params->scan_params.bssid), (0xff), (sizeof
(params->scan_params.bssid)))
;
2148 params->scan_params.bss_type = 2;
2149 params->scan_params.scan_type = BWFM_SCANTYPE_PASSIVE1;
2150 params->scan_params.nprobes = htole32(-1)((__uint32_t)(-1));
2151 params->scan_params.active_time = htole32(-1)((__uint32_t)(-1));
2152 params->scan_params.passive_time = htole32(-1)((__uint32_t)(-1));
2153 params->scan_params.home_time = htole32(-1)((__uint32_t)(-1));
2154 params->version = htole32(BWFM_ESCAN_REQ_VERSION)((__uint32_t)(1));
2155 params->action = htole16(WL_ESCAN_ACTION_START)((__uint16_t)(1));
2156 params->sync_id = htole16(0x1234)((__uint16_t)(0x1234));
2157
2158 if (ic->ic_flags & IEEE80211_F_ASCAN0x00000001 &&
2159 ic->ic_des_esslen && ic->ic_des_esslen <= BWFM_MAX_SSID_LEN32) {
2160 params->scan_params.scan_type = BWFM_SCANTYPE_ACTIVE0;
2161 ssid->len = htole32(ic->ic_des_esslen)((__uint32_t)(ic->ic_des_esslen));
2162 memcpy(ssid->ssid, ic->ic_des_essid, ic->ic_des_esslen)__builtin_memcpy((ssid->ssid), (ic->ic_des_essid), (ic->
ic_des_esslen))
;
2163 }
2164
2165 params->scan_params.channel_num = htole32(((__uint32_t)(nssid << 16 | nchan << 0))
2166 nssid << BWFM_CHANNUM_NSSID_SHIFT |((__uint32_t)(nssid << 16 | nchan << 0))
2167 nchan << BWFM_CHANNUM_NCHAN_SHIFT)((__uint32_t)(nssid << 16 | nchan << 0));
2168
2169#if 0
2170 /* Scan a specific channel */
2171 params->scan_params.channel_list[0] = htole16(((__uint16_t)((1 & 0xff) << 0 | (3 & 0x3) <<
8 | (2 & 0x3) << 10 | (2 & 0x3) << 12))
2172 (1 & 0xff) << 0 |((__uint16_t)((1 & 0xff) << 0 | (3 & 0x3) <<
8 | (2 & 0x3) << 10 | (2 & 0x3) << 12))
2173 (3 & 0x3) << 8 |((__uint16_t)((1 & 0xff) << 0 | (3 & 0x3) <<
8 | (2 & 0x3) << 10 | (2 & 0x3) << 12))
2174 (2 & 0x3) << 10 |((__uint16_t)((1 & 0xff) << 0 | (3 & 0x3) <<
8 | (2 & 0x3) << 10 | (2 & 0x3) << 12))
2175 (2 & 0x3) << 12((__uint16_t)((1 & 0xff) << 0 | (3 & 0x3) <<
8 | (2 & 0x3) << 10 | (2 & 0x3) << 12))
2176 )((__uint16_t)((1 & 0xff) << 0 | (3 & 0x3) <<
8 | (2 & 0x3) << 10 | (2 & 0x3) << 12))
;
2177#endif
2178
2179 bwfm_fwvar_var_set_data(sc, "escan", params, params_size);
2180 free(params, M_TEMP127, params_size);
2181}
2182
2183void
2184bwfm_scan_v2(struct bwfm_softc *sc)
2185{
2186 struct ieee80211com *ic = &sc->sc_ic;
2187 struct bwfm_escan_params_v2 *params;
2188 uint32_t nssid = 0, nchan = 0;
2189 size_t params_size, chan_size, ssid_size;
2190 struct bwfm_ssid *ssid;
2191
2192 if (ic->ic_flags & IEEE80211_F_ASCAN0x00000001 &&
2193 ic->ic_des_esslen && ic->ic_des_esslen <= BWFM_MAX_SSID_LEN32)
2194 nssid = 1;
2195
2196 chan_size = roundup(nchan * sizeof(uint16_t), sizeof(uint32_t))((((nchan * sizeof(uint16_t))+((sizeof(uint32_t))-1))/(sizeof
(uint32_t)))*(sizeof(uint32_t)))
;
2197 ssid_size = sizeof(struct bwfm_ssid) * nssid;
2198 params_size = sizeof(*params) + chan_size + ssid_size;
2199
2200 params = malloc(params_size, M_TEMP127, M_WAITOK0x0001 | M_ZERO0x0008);
2201 ssid = (struct bwfm_ssid *)
2202 (((uint8_t *)params) + sizeof(*params) + chan_size);
2203
2204 params->scan_params.version = 2;
2205 params->scan_params.length = params_size;
2206 memset(params->scan_params.bssid, 0xff,__builtin_memset((params->scan_params.bssid), (0xff), (sizeof
(params->scan_params.bssid)))
2207 sizeof(params->scan_params.bssid))__builtin_memset((params->scan_params.bssid), (0xff), (sizeof
(params->scan_params.bssid)))
;
2208 params->scan_params.bss_type = 2;
2209 params->scan_params.scan_type = BWFM_SCANTYPE_PASSIVE1;
2210 params->scan_params.nprobes = htole32(-1)((__uint32_t)(-1));
2211 params->scan_params.active_time = htole32(-1)((__uint32_t)(-1));
2212 params->scan_params.passive_time = htole32(-1)((__uint32_t)(-1));
2213 params->scan_params.home_time = htole32(-1)((__uint32_t)(-1));
2214 params->version = htole32(BWFM_ESCAN_REQ_VERSION_V2)((__uint32_t)(2));
2215 params->action = htole16(WL_ESCAN_ACTION_START)((__uint16_t)(1));
2216 params->sync_id = htole16(0x1234)((__uint16_t)(0x1234));
2217
2218 if (ic->ic_flags & IEEE80211_F_ASCAN0x00000001 &&
2219 ic->ic_des_esslen && ic->ic_des_esslen <= BWFM_MAX_SSID_LEN32) {
2220 params->scan_params.scan_type = BWFM_SCANTYPE_ACTIVE0;
2221 ssid->len = htole32(ic->ic_des_esslen)((__uint32_t)(ic->ic_des_esslen));
2222 memcpy(ssid->ssid, ic->ic_des_essid, ic->ic_des_esslen)__builtin_memcpy((ssid->ssid), (ic->ic_des_essid), (ic->
ic_des_esslen))
;
2223 }
2224
2225 params->scan_params.channel_num = htole32(((__uint32_t)(nssid << 16 | nchan << 0))
2226 nssid << BWFM_CHANNUM_NSSID_SHIFT |((__uint32_t)(nssid << 16 | nchan << 0))
2227 nchan << BWFM_CHANNUM_NCHAN_SHIFT)((__uint32_t)(nssid << 16 | nchan << 0));
2228
2229#if 0
2230 /* Scan a specific channel */
2231 params->scan_params.channel_list[0] = htole16(((__uint16_t)((1 & 0xff) << 0 | (3 & 0x3) <<
8 | (2 & 0x3) << 10 | (2 & 0x3) << 12))
2232 (1 & 0xff) << 0 |((__uint16_t)((1 & 0xff) << 0 | (3 & 0x3) <<
8 | (2 & 0x3) << 10 | (2 & 0x3) << 12))
2233 (3 & 0x3) << 8 |((__uint16_t)((1 & 0xff) << 0 | (3 & 0x3) <<
8 | (2 & 0x3) << 10 | (2 & 0x3) << 12))
2234 (2 & 0x3) << 10 |((__uint16_t)((1 & 0xff) << 0 | (3 & 0x3) <<
8 | (2 & 0x3) << 10 | (2 & 0x3) << 12))
2235 (2 & 0x3) << 12((__uint16_t)((1 & 0xff) << 0 | (3 & 0x3) <<
8 | (2 & 0x3) << 10 | (2 & 0x3) << 12))
2236 )((__uint16_t)((1 & 0xff) << 0 | (3 & 0x3) <<
8 | (2 & 0x3) << 10 | (2 & 0x3) << 12))
;
2237#endif
2238
2239 bwfm_fwvar_var_set_data(sc, "escan", params, params_size);
2240 free(params, M_TEMP127, params_size);
2241}
2242
2243void
2244bwfm_scan(struct bwfm_softc *sc)
2245{
2246 if (sc->sc_scan_ver == 0)
2247 bwfm_scan_v0(sc);
2248 else
2249 bwfm_scan_v2(sc);
2250}
2251
2252void
2253bwfm_scan_abort_v0(struct bwfm_softc *sc)
2254{
2255 struct bwfm_escan_params_v0 *params;
2256 size_t params_size;
2257
2258 params_size = sizeof(*params) + sizeof(uint16_t);
2259 params = malloc(params_size, M_TEMP127, M_WAITOK0x0001 | M_ZERO0x0008);
2260 memset(params->scan_params.bssid, 0xff,__builtin_memset((params->scan_params.bssid), (0xff), (sizeof
(params->scan_params.bssid)))
2261 sizeof(params->scan_params.bssid))__builtin_memset((params->scan_params.bssid), (0xff), (sizeof
(params->scan_params.bssid)))
;
2262 params->scan_params.bss_type = 2;
2263 params->scan_params.scan_type = BWFM_SCANTYPE_PASSIVE1;
2264 params->scan_params.nprobes = htole32(-1)((__uint32_t)(-1));
2265 params->scan_params.active_time = htole32(-1)((__uint32_t)(-1));
2266 params->scan_params.passive_time = htole32(-1)((__uint32_t)(-1));
2267 params->scan_params.home_time = htole32(-1)((__uint32_t)(-1));
2268 params->version = htole32(BWFM_ESCAN_REQ_VERSION)((__uint32_t)(1));
2269 params->action = htole16(WL_ESCAN_ACTION_START)((__uint16_t)(1));
2270 params->sync_id = htole16(0x1234)((__uint16_t)(0x1234));
2271 params->scan_params.channel_num = htole32(1)((__uint32_t)(1));
2272 params->scan_params.channel_list[0] = htole16(-1)((__uint16_t)(-1));
2273 bwfm_fwvar_var_set_data(sc, "escan", params, params_size);
2274 free(params, M_TEMP127, params_size);
2275}
2276
2277void
2278bwfm_scan_abort_v2(struct bwfm_softc *sc)
2279{
2280 struct bwfm_escan_params_v2 *params;
2281 size_t params_size;
2282
2283 params_size = sizeof(*params) + sizeof(uint16_t);
2284 params = malloc(params_size, M_TEMP127, M_WAITOK0x0001 | M_ZERO0x0008);
2285 params->scan_params.version = 2;
2286 params->scan_params.length = params_size;
2287 memset(params->scan_params.bssid, 0xff,__builtin_memset((params->scan_params.bssid), (0xff), (sizeof
(params->scan_params.bssid)))
2288 sizeof(params->scan_params.bssid))__builtin_memset((params->scan_params.bssid), (0xff), (sizeof
(params->scan_params.bssid)))
;
2289 params->scan_params.bss_type = 2;
2290 params->scan_params.scan_type = BWFM_SCANTYPE_PASSIVE1;
2291 params->scan_params.nprobes = htole32(-1)((__uint32_t)(-1));
2292 params->scan_params.active_time = htole32(-1)((__uint32_t)(-1));
2293 params->scan_params.passive_time = htole32(-1)((__uint32_t)(-1));
2294 params->scan_params.home_time = htole32(-1)((__uint32_t)(-1));
2295 params->version = htole32(BWFM_ESCAN_REQ_VERSION_V2)((__uint32_t)(2));
2296 params->action = htole16(WL_ESCAN_ACTION_START)((__uint16_t)(1));
2297 params->sync_id = htole16(0x1234)((__uint16_t)(0x1234));
2298 params->scan_params.channel_num = htole32(1)((__uint32_t)(1));
2299 params->scan_params.channel_list[0] = htole16(-1)((__uint16_t)(-1));
2300 bwfm_fwvar_var_set_data(sc, "escan", params, params_size);
2301 free(params, M_TEMP127, params_size);
2302}
2303
2304void
2305bwfm_scan_abort(struct bwfm_softc *sc)
2306{
2307 if (sc->sc_scan_ver == 0)
2308 bwfm_scan_abort_v0(sc);
2309 else
2310 bwfm_scan_abort_v2(sc);
2311}
2312
2313struct mbuf *
2314bwfm_newbuf(void)
2315{
2316 struct mbuf *m;
2317
2318 MGETHDR(m, M_DONTWAIT, MT_DATA)m = m_gethdr((0x0002), (1));
2319 if (m == NULL((void *)0))
2320 return (NULL((void *)0));
2321
2322 MCLGET(m, M_DONTWAIT)(void) m_clget((m), (0x0002), (1 << 11));
2323 if (!(m->m_flagsm_hdr.mh_flags & M_EXT0x0001)) {
2324 m_freem(m);
2325 return (NULL((void *)0));
2326 }
2327
2328 m->m_lenm_hdr.mh_len = m->m_pkthdrM_dat.MH.MH_pkthdr.len = MCLBYTES(1 << 11);
2329
2330 return (m);
2331}
2332
2333void
2334bwfm_rx(struct bwfm_softc *sc, struct mbuf *m, struct mbuf_list *ml)
2335{
2336 struct ieee80211com *ic = &sc->sc_ic;
2337 struct ifnet *ifp = &ic->ic_ific_ac.ac_if;
2338 struct ieee80211_node *ni;
2339 struct bwfm_event *e;
2340
2341#ifdef __STRICT_ALIGNMENT
2342 /* Remaining data is an ethernet packet, so align. */
2343 if ((mtod(m, paddr_t)((paddr_t)((m)->m_hdr.mh_data)) & 0x3) != ETHER_ALIGN2) {
2344 struct mbuf *m0;
2345 m0 = m_dup_pkt(m, ETHER_ALIGN2, M_WAITOK0x0001);
2346 m_freem(m);
2347 if (m0 == NULL((void *)0)) {
2348 ifp->if_ierrorsif_data.ifi_ierrors++;
2349 return;
2350 }
2351 m = m0;
2352 }
2353#endif
2354
2355 e = mtod(m, struct bwfm_event *)((struct bwfm_event *)((m)->m_hdr.mh_data));
2356 if (m->m_lenm_hdr.mh_len >= sizeof(e->ehdr) &&
2357 ntohs(e->ehdr.ether_type)(__uint16_t)(__builtin_constant_p(e->ehdr.ether_type) ? (__uint16_t
)(((__uint16_t)(e->ehdr.ether_type) & 0xffU) << 8
| ((__uint16_t)(e->ehdr.ether_type) & 0xff00U) >>
8) : __swap16md(e->ehdr.ether_type))
== BWFM_ETHERTYPE_LINK_CTL0x886c &&
2358 memcmp(BWFM_BRCM_OUI, e->hdr.oui, sizeof(e->hdr.oui))__builtin_memcmp(("\x00\x10\x18"), (e->hdr.oui), (sizeof(e
->hdr.oui)))
== 0 &&
2359 ntohs(e->hdr.usr_subtype)(__uint16_t)(__builtin_constant_p(e->hdr.usr_subtype) ? (__uint16_t
)(((__uint16_t)(e->hdr.usr_subtype) & 0xffU) << 8
| ((__uint16_t)(e->hdr.usr_subtype) & 0xff00U) >>
8) : __swap16md(e->hdr.usr_subtype))
== BWFM_BRCM_SUBTYPE_EVENT1) {
2360 bwfm_rx_event(sc, m);
2361 return;
2362 }
2363
2364 /* Drop network packets if we are not in RUN state. */
2365 if (ic->ic_state != IEEE80211_S_RUN) {
2366 m_freem(m);
2367 return;
2368 }
2369
2370 if ((ic->ic_flags & IEEE80211_F_RSNON0x00200000) &&
2371 m->m_lenm_hdr.mh_len >= sizeof(e->ehdr) &&
2372 ntohs(e->ehdr.ether_type)(__uint16_t)(__builtin_constant_p(e->ehdr.ether_type) ? (__uint16_t
)(((__uint16_t)(e->ehdr.ether_type) & 0xffU) << 8
| ((__uint16_t)(e->ehdr.ether_type) & 0xff00U) >>
8) : __swap16md(e->ehdr.ether_type))
== ETHERTYPE_EAPOL0x888E) {
2373 ifp->if_ipacketsif_data.ifi_ipackets++;
2374#if NBPFILTER1 > 0
2375 if (ifp->if_bpf)
2376 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN(1 << 0));
2377#endif
2378#ifndef IEEE80211_STA_ONLY
2379 if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
2380 ni = ieee80211_find_node(ic,
2381 (void *)&e->ehdr.ether_shost);
2382 if (ni == NULL((void *)0)) {
2383 m_freem(m);
2384 return;
2385 }
2386 } else
2387#endif
2388 ni = ic->ic_bss;
2389 ieee80211_eapol_key_input(ic, m, ni);
2390 } else
2391 ml_enqueue(ml, m);
2392}
2393
2394#ifndef IEEE80211_STA_ONLY
2395void
2396bwfm_rx_auth_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len)
2397{
2398 struct ieee80211com *ic = &sc->sc_ic;
2399 struct ifnet *ifp = &ic->ic_ific_ac.ac_if;
2400 struct ieee80211_rxinfo rxi;
2401 struct ieee80211_frame *wh;
2402 struct mbuf *m;
2403 uint32_t pktlen, ieslen;
2404
2405 /* Build a fake beacon frame to let net80211 do all the parsing. */
2406 ieslen = betoh32(e->msg.datalen)(__uint32_t)(__builtin_constant_p(e->msg.datalen) ? (__uint32_t
)(((__uint32_t)(e->msg.datalen) & 0xff) << 24 | (
(__uint32_t)(e->msg.datalen) & 0xff00) << 8 | ((
__uint32_t)(e->msg.datalen) & 0xff0000) >> 8 | (
(__uint32_t)(e->msg.datalen) & 0xff000000) >> 24
) : __swap32md(e->msg.datalen))
;
2407 pktlen = sizeof(*wh) + ieslen + 6;
2408 if (pktlen > MCLBYTES(1 << 11))
2409 return;
2410 m = bwfm_newbuf();
2411 if (m == NULL((void *)0))
2412 return;
2413 wh = mtod(m, struct ieee80211_frame *)((struct ieee80211_frame *)((m)->m_hdr.mh_data));
2414 wh->i_fc[0] = IEEE80211_FC0_VERSION_00x00 | IEEE80211_FC0_TYPE_MGT0x00 |
2415 IEEE80211_FC0_SUBTYPE_AUTH0xb0;
2416 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS0x00;
2417 *(uint16_t *)wh->i_dur = 0;
2418 IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr)__builtin_memcpy((wh->i_addr1), (etherbroadcastaddr), (6));
2419 IEEE80211_ADDR_COPY(wh->i_addr2, &e->msg.addr)__builtin_memcpy((wh->i_addr2), (&e->msg.addr), (6)
)
;
2420 IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid)__builtin_memcpy((wh->i_addr3), (ic->ic_bss->ni_bssid
), (6))
;
2421 *(uint16_t *)wh->i_seq = 0;
2422 ((uint16_t *)(&wh[1]))[0] = IEEE80211_AUTH_ALG_OPEN0x0000;
2423 ((uint16_t *)(&wh[1]))[1] = IEEE80211_AUTH_OPEN_REQUEST;
2424 ((uint16_t *)(&wh[1]))[2] = 0;
2425
2426 /* Finalize mbuf. */
2427 m->m_pkthdrM_dat.MH.MH_pkthdr.len = m->m_lenm_hdr.mh_len = pktlen;
2428 memset(&rxi, 0, sizeof(rxi))__builtin_memset((&rxi), (0), (sizeof(rxi)));
2429 ieee80211_input(ifp, m, ic->ic_bss, &rxi);
2430}
2431
2432void
2433bwfm_rx_assoc_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len,
2434 int reassoc)
2435{
2436 struct ieee80211com *ic = &sc->sc_ic;
2437 struct ifnet *ifp = &ic->ic_ific_ac.ac_if;
2438 struct ieee80211_rxinfo rxi;
2439 struct ieee80211_frame *wh;
2440 struct ieee80211_node *ni;
2441 struct mbuf *m;
2442 uint32_t pktlen, ieslen;
2443
2444 /* Build a fake beacon frame to let net80211 do all the parsing. */
2445 ieslen = betoh32(e->msg.datalen)(__uint32_t)(__builtin_constant_p(e->msg.datalen) ? (__uint32_t
)(((__uint32_t)(e->msg.datalen) & 0xff) << 24 | (
(__uint32_t)(e->msg.datalen) & 0xff00) << 8 | ((
__uint32_t)(e->msg.datalen) & 0xff0000) >> 8 | (
(__uint32_t)(e->msg.datalen) & 0xff000000) >> 24
) : __swap32md(e->msg.datalen))
;
2446 pktlen = sizeof(*wh) + ieslen + 4;
2447 if (reassoc)
2448 pktlen += IEEE80211_ADDR_LEN6;
2449 if (pktlen > MCLBYTES(1 << 11))
2450 return;
2451 m = bwfm_newbuf();
2452 if (m == NULL((void *)0))
2453 return;
2454 wh = mtod(m, struct ieee80211_frame *)((struct ieee80211_frame *)((m)->m_hdr.mh_data));
2455 wh->i_fc[0] = IEEE80211_FC0_VERSION_00x00 | IEEE80211_FC0_TYPE_MGT0x00;
2456 if (reassoc)
2457 wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_REASSOC_REQ0x20;
2458 else
2459 wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_ASSOC_REQ0x00;
2460 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS0x00;
2461 *(uint16_t *)wh->i_dur = 0;
2462 IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr)__builtin_memcpy((wh->i_addr1), (etherbroadcastaddr), (6));
2463 IEEE80211_ADDR_COPY(wh->i_addr2, &e->msg.addr)__builtin_memcpy((wh->i_addr2), (&e->msg.addr), (6)
)
;
2464 IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid)__builtin_memcpy((wh->i_addr3), (ic->ic_bss->ni_bssid
), (6))
;
2465 *(uint16_t *)wh->i_seq = 0;
2466 ((uint16_t *)(&wh[1]))[0] = IEEE80211_CAPINFO_ESS0x0001; /* XXX */
2467 ((uint16_t *)(&wh[1]))[1] = 100; /* XXX */
2468 if (reassoc) {
2469 memset(((uint8_t *)&wh[1]) + 4, 0, IEEE80211_ADDR_LEN)__builtin_memset((((uint8_t *)&wh[1]) + 4), (0), (6));
2470 memcpy(((uint8_t *)&wh[1]) + 4 + IEEE80211_ADDR_LEN,__builtin_memcpy((((uint8_t *)&wh[1]) + 4 + 6), (&e[1
]), (ieslen))
2471 &e[1], ieslen)__builtin_memcpy((((uint8_t *)&wh[1]) + 4 + 6), (&e[1
]), (ieslen))
;
2472 } else
2473 memcpy(((uint8_t *)&wh[1]) + 4, &e[1], ieslen)__builtin_memcpy((((uint8_t *)&wh[1]) + 4), (&e[1]), (
ieslen))
;
2474
2475 /* Finalize mbuf. */
2476 m->m_pkthdrM_dat.MH.MH_pkthdr.len = m->m_lenm_hdr.mh_len = pktlen;
2477 ni = ieee80211_find_node(ic, wh->i_addr2);
2478 if (ni == NULL((void *)0)) {
2479 m_freem(m);
2480 return;
2481 }
2482 memset(&rxi, 0, sizeof(rxi))__builtin_memset((&rxi), (0), (sizeof(rxi)));
2483 ieee80211_input(ifp, m, ni, &rxi);
2484}
2485
2486void
2487bwfm_rx_deauth_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len)
2488{
2489 bwfm_rx_leave_ind(sc, e, len, IEEE80211_FC0_SUBTYPE_DEAUTH0xc0);
2490}
2491
2492void
2493bwfm_rx_disassoc_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len)
2494{
2495 bwfm_rx_leave_ind(sc, e, len, IEEE80211_FC0_SUBTYPE_DISASSOC0xa0);
2496}
2497
2498void
2499bwfm_rx_leave_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len,
2500 int subtype)
2501{
2502 struct ieee80211com *ic = &sc->sc_ic;
2503 struct ifnet *ifp = &ic->ic_ific_ac.ac_if;
2504 struct ieee80211_rxinfo rxi;
2505 struct ieee80211_frame *wh;
2506 struct ieee80211_node *ni;
2507 struct mbuf *m;
2508 uint32_t pktlen;
2509
2510 /* Build a fake beacon frame to let net80211 do all the parsing. */
2511 pktlen = sizeof(*wh) + 2;
2512 if (pktlen > MCLBYTES(1 << 11))
2513 return;
2514 m = bwfm_newbuf();
2515 if (m == NULL((void *)0))
2516 return;
2517 wh = mtod(m, struct ieee80211_frame *)((struct ieee80211_frame *)((m)->m_hdr.mh_data));
2518 wh->i_fc[0] = IEEE80211_FC0_VERSION_00x00 | IEEE80211_FC0_TYPE_MGT0x00 |
2519 subtype;
2520 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS0x00;
2521 *(uint16_t *)wh->i_dur = 0;
2522 IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr)__builtin_memcpy((wh->i_addr1), (etherbroadcastaddr), (6));
2523 IEEE80211_ADDR_COPY(wh->i_addr2, &e->msg.addr)__builtin_memcpy((wh->i_addr2), (&e->msg.addr), (6)
)
;
2524 IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid)__builtin_memcpy((wh->i_addr3), (ic->ic_bss->ni_bssid
), (6))
;
2525 *(uint16_t *)wh->i_seq = 0;
2526 memset((uint8_t *)&wh[1], 0, 2)__builtin_memset(((uint8_t *)&wh[1]), (0), (2));
2527
2528 /* Finalize mbuf. */
2529 m->m_pkthdrM_dat.MH.MH_pkthdr.len = m->m_lenm_hdr.mh_len = pktlen;
2530 ni = ieee80211_find_node(ic, wh->i_addr2);
2531 if (ni == NULL((void *)0)) {
2532 m_freem(m);
2533 return;
2534 }
2535 memset(&rxi, 0, sizeof(rxi))__builtin_memset((&rxi), (0), (sizeof(rxi)));
2536 ieee80211_input(ifp, m, ni, &rxi);
2537}
2538#endif
2539
2540void
2541bwfm_rx_event(struct bwfm_softc *sc, struct mbuf *m)
2542{
2543 int s;
2544
2545 s = splnet()splraise(0x4);
2546 ml_enqueue(&sc->sc_evml, m);
2547 splx(s)spllower(s);
2548
2549 task_add(sc->sc_taskq, &sc->sc_task);
2550}
2551
2552void
2553bwfm_rx_event_cb(struct bwfm_softc *sc, struct mbuf *m)
2554{
2555 struct ieee80211com *ic = &sc->sc_ic;
2556 struct ifnet *ifp = &ic->ic_ific_ac.ac_if;
2557 struct bwfm_event *e = mtod(m, void *)((void *)((m)->m_hdr.mh_data));
2558 size_t len = m->m_lenm_hdr.mh_len;
2559
2560 if (ntohl(e->msg.event_type)(__uint32_t)(__builtin_constant_p(e->msg.event_type) ? (__uint32_t
)(((__uint32_t)(e->msg.event_type) & 0xff) << 24
| ((__uint32_t)(e->msg.event_type) & 0xff00) <<
8 | ((__uint32_t)(e->msg.event_type) & 0xff0000) >>
8 | ((__uint32_t)(e->msg.event_type) & 0xff000000) >>
24) : __swap32md(e->msg.event_type))
>= BWFM_E_LAST) {
2561 m_freem(m);
2562 return;
2563 }
2564
2565 switch (ntohl(e->msg.event_type)(__uint32_t)(__builtin_constant_p(e->msg.event_type) ? (__uint32_t
)(((__uint32_t)(e->msg.event_type) & 0xff) << 24
| ((__uint32_t)(e->msg.event_type) & 0xff00) <<
8 | ((__uint32_t)(e->msg.event_type) & 0xff0000) >>
8 | ((__uint32_t)(e->msg.event_type) & 0xff000000) >>
24) : __swap32md(e->msg.event_type))
) {
2566 case BWFM_E_ESCAN_RESULT: {
2567 struct bwfm_escan_results *res;
2568 struct bwfm_bss_info *bss;
2569 size_t reslen;
2570 int i;
2571 /* Abort event triggered by SCAN -> INIT */
2572 if (ic->ic_state == IEEE80211_S_INIT &&
2573 ntohl(e->msg.status)(__uint32_t)(__builtin_constant_p(e->msg.status) ? (__uint32_t
)(((__uint32_t)(e->msg.status) & 0xff) << 24 | (
(__uint32_t)(e->msg.status) & 0xff00) << 8 | ((__uint32_t
)(e->msg.status) & 0xff0000) >> 8 | ((__uint32_t
)(e->msg.status) & 0xff000000) >> 24) : __swap32md
(e->msg.status))
== BWFM_E_STATUS_ABORT)
2574 break;
2575 if (ic->ic_state != IEEE80211_S_SCAN) {
2576 DPRINTF(("%s: scan result (%u) while not in SCAN\n",do { ; } while (0)
2577 DEVNAME(sc), ntohl(e->msg.status)))do { ; } while (0);
2578 break;
2579 }
2580 if (ntohl(e->msg.status)(__uint32_t)(__builtin_constant_p(e->msg.status) ? (__uint32_t
)(((__uint32_t)(e->msg.status) & 0xff) << 24 | (
(__uint32_t)(e->msg.status) & 0xff00) << 8 | ((__uint32_t
)(e->msg.status) & 0xff0000) >> 8 | ((__uint32_t
)(e->msg.status) & 0xff000000) >> 24) : __swap32md
(e->msg.status))
!= BWFM_E_STATUS_SUCCESS &&
2581 ntohl(e->msg.status)(__uint32_t)(__builtin_constant_p(e->msg.status) ? (__uint32_t
)(((__uint32_t)(e->msg.status) & 0xff) << 24 | (
(__uint32_t)(e->msg.status) & 0xff00) << 8 | ((__uint32_t
)(e->msg.status) & 0xff0000) >> 8 | ((__uint32_t
)(e->msg.status) & 0xff000000) >> 24) : __swap32md
(e->msg.status))
!= BWFM_E_STATUS_PARTIAL) {
2582 DPRINTF(("%s: unexpected scan result (%u)\n",do { ; } while (0)
2583 DEVNAME(sc), ntohl(e->msg.status)))do { ; } while (0);
2584 break;
2585 }
2586 if (ntohl(e->msg.status)(__uint32_t)(__builtin_constant_p(e->msg.status) ? (__uint32_t
)(((__uint32_t)(e->msg.status) & 0xff) << 24 | (
(__uint32_t)(e->msg.status) & 0xff00) << 8 | ((__uint32_t
)(e->msg.status) & 0xff0000) >> 8 | ((__uint32_t
)(e->msg.status) & 0xff000000) >> 24) : __swap32md
(e->msg.status))
== BWFM_E_STATUS_SUCCESS) {
2587 ieee80211_end_scan(ifp);
2588 break;
2589 }
2590 len -= sizeof(*e);
2591 if (len < sizeof(*res)) {
2592 DPRINTF(("%s: results too small\n", DEVNAME(sc)))do { ; } while (0);
2593 m_freem(m);
2594 return;
2595 }
2596 reslen = len;
2597 res = malloc(len, M_TEMP127, M_WAITOK0x0001);
2598 memcpy(res, (void *)&e[1], len)__builtin_memcpy((res), ((void *)&e[1]), (len));
2599 if (len < letoh32(res->buflen)((__uint32_t)(res->buflen))) {
2600 DPRINTF(("%s: results too small\n", DEVNAME(sc)))do { ; } while (0);
2601 free(res, M_TEMP127, reslen);
2602 m_freem(m);
2603 return;
2604 }
2605 len -= sizeof(*res);
2606 if (len < letoh16(res->bss_count)((__uint16_t)(res->bss_count)) * sizeof(struct bwfm_bss_info)) {
2607 DPRINTF(("%s: results too small\n", DEVNAME(sc)))do { ; } while (0);
2608 free(res, M_TEMP127, reslen);
2609 m_freem(m);
2610 return;
2611 }
2612 bss = &res->bss_info[0];
2613 for (i = 0; i < letoh16(res->bss_count)((__uint16_t)(res->bss_count)); i++) {
2614 bwfm_scan_node(sc, &res->bss_info[i], len);
2615 len -= sizeof(*bss) + letoh32(bss->length)((__uint32_t)(bss->length));
2616 bss = (void *)((char *)bss) + letoh32(bss->length)((__uint32_t)(bss->length));
2617 if (len <= 0)
2618 break;
2619 }
2620 free(res, M_TEMP127, reslen);
2621 break;
2622 }
2623 case BWFM_E_AUTH:
2624 if (ntohl(e->msg.status)(__uint32_t)(__builtin_constant_p(e->msg.status) ? (__uint32_t
)(((__uint32_t)(e->msg.status) & 0xff) << 24 | (
(__uint32_t)(e->msg.status) & 0xff00) << 8 | ((__uint32_t
)(e->msg.status) & 0xff0000) >> 8 | ((__uint32_t
)(e->msg.status) & 0xff000000) >> 24) : __swap32md
(e->msg.status))
== BWFM_E_STATUS_SUCCESS &&
2625 ic->ic_state == IEEE80211_S_AUTH)
2626 ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1)(((ic)->ic_newstate)((ic), (IEEE80211_S_ASSOC), (-1)));
2627 else
2628 ieee80211_begin_scan(ifp);
2629 break;
2630 case BWFM_E_ASSOC:
2631 if (ntohl(e->msg.status)(__uint32_t)(__builtin_constant_p(e->msg.status) ? (__uint32_t
)(((__uint32_t)(e->msg.status) & 0xff) << 24 | (
(__uint32_t)(e->msg.status) & 0xff00) << 8 | ((__uint32_t
)(e->msg.status) & 0xff0000) >> 8 | ((__uint32_t
)(e->msg.status) & 0xff000000) >> 24) : __swap32md
(e->msg.status))
== BWFM_E_STATUS_SUCCESS &&
2632 ic->ic_state == IEEE80211_S_ASSOC)
2633 ieee80211_new_state(ic, IEEE80211_S_RUN, -1)(((ic)->ic_newstate)((ic), (IEEE80211_S_RUN), (-1)));
2634 else if (ntohl(e->msg.status)(__uint32_t)(__builtin_constant_p(e->msg.status) ? (__uint32_t
)(((__uint32_t)(e->msg.status) & 0xff) << 24 | (
(__uint32_t)(e->msg.status) & 0xff00) << 8 | ((__uint32_t
)(e->msg.status) & 0xff0000) >> 8 | ((__uint32_t
)(e->msg.status) & 0xff000000) >> 24) : __swap32md
(e->msg.status))
!= BWFM_E_STATUS_UNSOLICITED)
2635 ieee80211_begin_scan(ifp);
2636 break;
2637 case BWFM_E_DEAUTH:
2638 case BWFM_E_DISASSOC:
2639 if (ic->ic_state > IEEE80211_S_SCAN)
2640 ieee80211_begin_scan(ifp);
2641 break;
2642 case BWFM_E_LINK:
2643 if (ntohl(e->msg.status)(__uint32_t)(__builtin_constant_p(e->msg.status) ? (__uint32_t
)(((__uint32_t)(e->msg.status) & 0xff) << 24 | (
(__uint32_t)(e->msg.status) & 0xff00) << 8 | ((__uint32_t
)(e->msg.status) & 0xff0000) >> 8 | ((__uint32_t
)(e->msg.status) & 0xff000000) >> 24) : __swap32md
(e->msg.status))
== BWFM_E_STATUS_SUCCESS &&
2644 ntohl(e->msg.reason)(__uint32_t)(__builtin_constant_p(e->msg.reason) ? (__uint32_t
)(((__uint32_t)(e->msg.reason) & 0xff) << 24 | (
(__uint32_t)(e->msg.reason) & 0xff00) << 8 | ((__uint32_t
)(e->msg.reason) & 0xff0000) >> 8 | ((__uint32_t
)(e->msg.reason) & 0xff000000) >> 24) : __swap32md
(e->msg.reason))
== 0)
2645 break;
2646 /* Link status has changed */
2647 if (ic->ic_state > IEEE80211_S_SCAN)
2648 ieee80211_begin_scan(ifp);
2649 break;
2650#ifndef IEEE80211_STA_ONLY
2651 case BWFM_E_AUTH_IND:
2652 bwfm_rx_auth_ind(sc, e, len);
2653 break;
2654 case BWFM_E_ASSOC_IND:
2655 bwfm_rx_assoc_ind(sc, e, len, 0);
2656 break;
2657 case BWFM_E_REASSOC_IND:
2658 bwfm_rx_assoc_ind(sc, e, len, 1);
2659 break;
2660 case BWFM_E_DEAUTH_IND:
2661 bwfm_rx_deauth_ind(sc, e, len);
2662 break;
2663 case BWFM_E_DISASSOC_IND:
2664 bwfm_rx_disassoc_ind(sc, e, len);
2665 break;
2666#endif
2667 default:
2668 DPRINTF(("%s: len %lu datalen %u code %u status %u"do { ; } while (0)
2669 " reason %u\n", __func__, len, ntohl(e->msg.datalen),do { ; } while (0)
2670 ntohl(e->msg.event_type), ntohl(e->msg.status),do { ; } while (0)
2671 ntohl(e->msg.reason)))do { ; } while (0);
2672 break;
2673 }
2674
2675 m_freem(m);
2676}
2677
2678void
2679bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_info *bss, size_t len)
2680{
2681 struct ieee80211com *ic = &sc->sc_ic;
2682 struct ifnet *ifp = &ic->ic_ific_ac.ac_if;
2683 struct ieee80211_frame *wh;
2684 struct ieee80211_node *ni;
2685 struct ieee80211_rxinfo rxi;
2686 struct mbuf *m;
2687 uint32_t pktlen, ieslen;
2688 uint16_t iesoff;
2689 int chanidx;
2690
2691 iesoff = letoh16(bss->ie_offset)((__uint16_t)(bss->ie_offset));
2692 ieslen = letoh32(bss->ie_length)((__uint32_t)(bss->ie_length));
2693 if (ieslen > len - iesoff)
2694 return;
2695
2696 /* Build a fake beacon frame to let net80211 do all the parsing. */
2697 pktlen = sizeof(*wh) + ieslen + 12;
2698 if (pktlen > MCLBYTES(1 << 11))
2699 return;
2700 m = bwfm_newbuf();
2701 if (m == NULL((void *)0))
2702 return;
2703 wh = mtod(m, struct ieee80211_frame *)((struct ieee80211_frame *)((m)->m_hdr.mh_data));
2704 wh->i_fc[0] = IEEE80211_FC0_VERSION_00x00 | IEEE80211_FC0_TYPE_MGT0x00 |
2705 IEEE80211_FC0_SUBTYPE_BEACON0x80;
2706 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS0x00;
2707 *(uint16_t *)wh->i_dur = 0;
2708 IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr)__builtin_memcpy((wh->i_addr1), (etherbroadcastaddr), (6));
2709 IEEE80211_ADDR_COPY(wh->i_addr2, bss->bssid)__builtin_memcpy((wh->i_addr2), (bss->bssid), (6));
2710 IEEE80211_ADDR_COPY(wh->i_addr3, bss->bssid)__builtin_memcpy((wh->i_addr3), (bss->bssid), (6));
2711 *(uint16_t *)wh->i_seq = 0;
2712 memset(&wh[1], 0, 12)__builtin_memset((&wh[1]), (0), (12));
2713 ((uint16_t *)(&wh[1]))[4] = bss->beacon_period;
2714 ((uint16_t *)(&wh[1]))[5] = bss->capability;
2715 memcpy(((uint8_t *)&wh[1]) + 12, ((uint8_t *)bss) + iesoff, ieslen)__builtin_memcpy((((uint8_t *)&wh[1]) + 12), (((uint8_t *
)bss) + iesoff), (ieslen))
;
2716
2717 /* Finalize mbuf. */
2718 m->m_pkthdrM_dat.MH.MH_pkthdr.len = m->m_lenm_hdr.mh_len = pktlen;
2719 ni = ieee80211_find_rxnode(ic, wh);
2720 /* Channel mask equals IEEE80211_CHAN_MAX */
2721 chanidx = bwfm_spec2chan(sc, letoh32(bss->chanspec)((__uint32_t)(bss->chanspec)));
2722 /* Supply RSSI */
2723 memset(&rxi, 0, sizeof(rxi))__builtin_memset((&rxi), (0), (sizeof(rxi)));
2724 rxi.rxi_rssi = (int16_t)letoh16(bss->rssi)((__uint16_t)(bss->rssi));
2725 rxi.rxi_chan = chanidx;
2726 ieee80211_input(ifp, m, ni, &rxi);
2727 /* Node is no longer needed. */
2728 ieee80211_release_node(ic, ni);
2729}
2730
2731void
2732bwfm_task(void *arg)
2733{
2734 struct bwfm_softc *sc = arg;
2735 struct bwfm_host_cmd_ring *ring = &sc->sc_cmdq;
2736 struct bwfm_host_cmd *cmd;
2737 struct mbuf *m;
2738 int s;
2739
2740 s = splnet()splraise(0x4);
2741 while (ring->next != ring->cur) {
2742 cmd = &ring->cmd[ring->next];
2743 splx(s)spllower(s);
2744 cmd->cb(sc, cmd->data);
2745 s = splnet()splraise(0x4);
2746 ring->queued--;
2747 ring->next = (ring->next + 1) % BWFM_HOST_CMD_RING_COUNT32;
2748 }
2749 splx(s)spllower(s);
2750
2751 s = splnet()splraise(0x4);
2752 while ((m = ml_dequeue(&sc->sc_evml)) != NULL((void *)0)) {
2753 splx(s)spllower(s);
2754 bwfm_rx_event_cb(sc, m);
2755 s = splnet()splraise(0x4);
2756 }
2757 splx(s)spllower(s);
2758}
2759
2760void
2761bwfm_do_async(struct bwfm_softc *sc,
2762 void (*cb)(struct bwfm_softc *, void *), void *arg, int len)
2763{
2764 struct bwfm_host_cmd_ring *ring = &sc->sc_cmdq;
2765 struct bwfm_host_cmd *cmd;
2766 int s;
2767
2768 s = splnet()splraise(0x4);
2769 KASSERT(ring->queued < BWFM_HOST_CMD_RING_COUNT)((ring->queued < 32) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/dev/ic/bwfm.c", 2769, "ring->queued < BWFM_HOST_CMD_RING_COUNT"
))
;
2770 if (ring->queued >= BWFM_HOST_CMD_RING_COUNT32) {
2771 splx(s)spllower(s);
2772 return;
2773 }
2774 cmd = &ring->cmd[ring->cur];
2775 cmd->cb = cb;
2776 KASSERT(len <= sizeof(cmd->data))((len <= sizeof(cmd->data)) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/dev/ic/bwfm.c", 2776, "len <= sizeof(cmd->data)"
))
;
2777 memcpy(cmd->data, arg, len)__builtin_memcpy((cmd->data), (arg), (len));
2778 ring->cur = (ring->cur + 1) % BWFM_HOST_CMD_RING_COUNT32;
2779 ring->queued++;
2780 task_add(sc->sc_taskq, &sc->sc_task);
2781 splx(s)spllower(s);
2782}
2783
2784int
2785bwfm_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
2786 int type, int arg1, int arg2)
2787{
2788#ifdef BWFM_DEBUG
2789 struct bwfm_softc *sc = ic->ic_softcic_ac.ac_if.if_softc;
2790 DPRINTF(("%s: %s\n", DEVNAME(sc), __func__))do { ; } while (0);
2791#endif
2792 return 0;
2793}
2794
2795int
2796bwfm_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
2797 struct ieee80211_key *k)
2798{
2799 struct bwfm_softc *sc = ic->ic_softcic_ac.ac_if.if_softc;
2800 struct bwfm_cmd_key cmd;
2801
2802 cmd.ni = ni;
2803 cmd.k = k;
2804 bwfm_do_async(sc, bwfm_set_key_cb, &cmd, sizeof(cmd));
2805 sc->sc_key_tasks++;
2806 return EBUSY16;
2807}
2808
2809void
2810bwfm_set_key_cb(struct bwfm_softc *sc, void *arg)
2811{
2812 struct bwfm_cmd_key *cmd = arg;
2813 struct ieee80211_key *k = cmd->k;
2814 struct ieee80211_node *ni = cmd->ni;
2815 struct ieee80211com *ic = &sc->sc_ic;
2816 struct bwfm_wsec_key key;
2817 uint32_t wsec, wsec_enable;
2818 int ext_key = 0;
2819
2820 sc->sc_key_tasks--;
2821
2822 if ((k->k_flags & IEEE80211_KEY_GROUP0x00000001) == 0 &&
2823 k->k_cipher != IEEE80211_CIPHER_WEP40 &&
2824 k->k_cipher != IEEE80211_CIPHER_WEP104)
2825 ext_key = 1;
2826
2827 memset(&key, 0, sizeof(key))__builtin_memset((&key), (0), (sizeof(key)));
2828 if (ext_key && !IEEE80211_IS_MULTICAST(ni->ni_macaddr)(*(ni->ni_macaddr) & 0x01))
2829 memcpy(key.ea, ni->ni_macaddr, sizeof(key.ea))__builtin_memcpy((key.ea), (ni->ni_macaddr), (sizeof(key.ea
)))
;
2830 key.index = htole32(k->k_id)((__uint32_t)(k->k_id));
2831 key.len = htole32(k->k_len)((__uint32_t)(k->k_len));
2832 memcpy(key.data, k->k_key, sizeof(key.data))__builtin_memcpy((key.data), (k->k_key), (sizeof(key.data)
))
;
2833 if (!ext_key)
2834 key.flags = htole32(BWFM_WSEC_PRIMARY_KEY)((__uint32_t)((1 << 1)));
2835
2836 switch (k->k_cipher) {
2837 case IEEE80211_CIPHER_WEP40:
2838 key.algo = htole32(BWFM_CRYPTO_ALGO_WEP1)((__uint32_t)(1));
2839 wsec_enable = BWFM_WSEC_WEP(1 << 0);
2840 break;
2841 case IEEE80211_CIPHER_WEP104:
2842 key.algo = htole32(BWFM_CRYPTO_ALGO_WEP128)((__uint32_t)(3));
2843 wsec_enable = BWFM_WSEC_WEP(1 << 0);
2844 break;
2845 case IEEE80211_CIPHER_TKIP:
2846 key.algo = htole32(BWFM_CRYPTO_ALGO_TKIP)((__uint32_t)(2));
2847 wsec_enable = BWFM_WSEC_TKIP(1 << 1);
2848 break;
2849 case IEEE80211_CIPHER_CCMP:
2850 key.algo = htole32(BWFM_CRYPTO_ALGO_AES_CCM)((__uint32_t)(4));
2851 wsec_enable = BWFM_WSEC_AES(1 << 2);
2852 break;
2853 default:
2854 printf("%s: cipher %x not supported\n", DEVNAME(sc)((sc)->sc_dev.dv_xname),
2855 k->k_cipher);
2856 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1)(((ic)->ic_newstate)((ic), (IEEE80211_S_SCAN), (-1)));
2857 return;
2858 }
2859
2860 delay(100)(*delay_func)(100);
2861
2862 bwfm_fwvar_var_set_data(sc, "wsec_key", &key, sizeof(key));
2863 bwfm_fwvar_var_get_int(sc, "wsec", &wsec);
2864 wsec &= ~(BWFM_WSEC_WEP(1 << 0) | BWFM_WSEC_TKIP(1 << 1) | BWFM_WSEC_AES(1 << 2));
2865 wsec |= wsec_enable;
2866 bwfm_fwvar_var_set_int(sc, "wsec", wsec);
2867
2868 if (wsec_enable != BWFM_WSEC_WEP(1 << 0) && cmd->ni != NULL((void *)0) &&
2869 sc->sc_key_tasks == 0) {
2870 DPRINTF(("%s: marking port %s valid\n", DEVNAME(sc),do { ; } while (0)
2871 ether_sprintf(cmd->ni->ni_macaddr)))do { ; } while (0);
2872 cmd->ni->ni_port_valid = 1;
2873 ieee80211_set_link_state(ic, LINK_STATE_UP4);
2874 }
2875}
2876
2877void
2878bwfm_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
2879 struct ieee80211_key *k)
2880{
2881 struct bwfm_softc *sc = ic->ic_softcic_ac.ac_if.if_softc;
2882 struct bwfm_cmd_key cmd;
2883
2884 cmd.ni = ni;
2885 cmd.k = k;
2886 bwfm_do_async(sc, bwfm_delete_key_cb, &cmd, sizeof(cmd));
2887}
2888
2889void
2890bwfm_delete_key_cb(struct bwfm_softc *sc, void *arg)
2891{
2892 struct bwfm_cmd_key *cmd = arg;
2893 struct ieee80211_key *k = cmd->k;
2894 struct bwfm_wsec_key key;
2895
2896 memset(&key, 0, sizeof(key))__builtin_memset((&key), (0), (sizeof(key)));
2897 key.index = htole32(k->k_id)((__uint32_t)(k->k_id));
2898 key.flags = htole32(BWFM_WSEC_PRIMARY_KEY)((__uint32_t)((1 << 1)));
2899 bwfm_fwvar_var_set_data(sc, "wsec_key", &key, sizeof(key));
2900}
2901
2902int
2903bwfm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
2904{
2905 struct bwfm_softc *sc = ic->ic_softcic_ac.ac_if.if_softc;
2906 struct ifnet *ifp = &ic->ic_ific_ac.ac_if;
2907 int s;
2908
2909 s = splnet()splraise(0x4);
2910
2911 switch (nstate) {
2912 case IEEE80211_S_INIT:
2913 if (ic->ic_state == IEEE80211_S_SCAN)
2914 bwfm_scan_abort(sc);
2915 break;
2916 case IEEE80211_S_SCAN:
2917#ifndef IEEE80211_STA_ONLY
2918 /* Don't start a scan if we already have a channel. */
2919 if (ic->ic_state == IEEE80211_S_INIT &&
2920 ic->ic_opmode == IEEE80211_M_HOSTAP &&
2921 ic->ic_des_chan != IEEE80211_CHAN_ANYC((struct ieee80211_channel *) ((void *)0))) {
2922 break;
2923 }
2924#endif
2925 /* If we tried to connect, abort. */
2926 if (ic->ic_state > IEEE80211_S_SCAN)
2927 bwfm_fwvar_cmd_set_data(sc, BWFM_C_DISASSOC52, NULL((void *)0), 0);
2928 /* Initiate scan. */
2929 bwfm_scan(sc);
2930 if (ifp->if_flags & IFF_DEBUG0x4)
2931 printf("%s: %s -> %s\n", DEVNAME(sc)((sc)->sc_dev.dv_xname),
2932 ieee80211_state_name[ic->ic_state],
2933 ieee80211_state_name[nstate]);
2934 /* No need to do this again. */
2935 if (ic->ic_state == IEEE80211_S_SCAN) {
2936 splx(s)spllower(s);
2937 return 0;
2938 }
2939 ieee80211_set_link_state(ic, LINK_STATE_DOWN2);
2940 ieee80211_free_allnodes(ic, 1);
2941 ic->ic_state = nstate;
2942 splx(s)spllower(s);
2943 return 0;
2944 case IEEE80211_S_AUTH:
2945 ic->ic_bss->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE;
2946 bwfm_connect(sc);
2947 if (ifp->if_flags & IFF_DEBUG0x4)
2948 printf("%s: %s -> %s\n", DEVNAME(sc)((sc)->sc_dev.dv_xname),
2949 ieee80211_state_name[ic->ic_state],
2950 ieee80211_state_name[nstate]);
2951 ic->ic_state = nstate;
2952 if (ic->ic_flags & IEEE80211_F_RSNON0x00200000)
2953 ic->ic_bss->ni_rsn_supp_state = RSNA_SUPP_PTKSTART;
2954 splx(s)spllower(s);
2955 return 0;
2956#ifndef IEEE80211_STA_ONLY
2957 case IEEE80211_S_RUN:
2958 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
2959 bwfm_hostap(sc);
2960 break;
2961#endif
2962 default:
2963 break;
2964 }
2965 sc->sc_newstate(ic, nstate, arg);
2966 splx(s)spllower(s);
2967 return 0;
2968}
2969
2970int
2971bwfm_nvram_convert(int node, u_char **bufp, size_t *sizep, size_t *newlenp)
2972{
2973 u_char *src, *dst, *end = *bufp + *sizep, *newbuf;
2974 size_t count = 0, newsize, pad;
2975 uint32_t token;
2976 int skip = 0;
2977
2978 /*
2979 * Allocate a new buffer with enough space for the MAC
2980 * address, padding and final token.
2981 */
2982 newsize = *sizep + 64;
2983 newbuf = malloc(newsize, M_DEVBUF2, M_NOWAIT0x0002);
2984 if (newbuf == NULL((void *)0))
2985 return 1;
2986
2987 for (src = *bufp, dst = newbuf; src != end; ++src) {
2988 if (*src == '\n') {
2989 if (count > 0)
2990 *dst++ = '\0';
2991 count = 0;
2992 skip = 0;
2993 continue;
2994 }
2995 if (skip)
2996 continue;
2997 if (*src == '#' && count == 0) {
2998 skip = 1;
2999 continue;
3000 }
3001 if (*src == '\r')
3002 continue;
3003 *dst++ = *src;
3004 ++count;
3005 }
3006
3007#if defined(__HAVE_FDT)
3008 /*
3009 * Append MAC address if one is provided in the device tree.
3010 * This is needed on Apple Silicon Macs.
3011 */
3012 if (node) {
3013 u_char enaddr[ETHER_ADDR_LEN6];
3014 char macaddr[32];
3015
3016 if (OF_getprop(node, "local-mac-address",
3017 enaddr, sizeof(enaddr))) {
3018 snprintf(macaddr, sizeof(macaddr),
3019 "macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
3020 enaddr[0], enaddr[1], enaddr[2], enaddr[3],
3021 enaddr[4], enaddr[5]);
3022 if (*dst)
3023 *dst++ = '\0';
3024 memcpy(dst, macaddr, strlen(macaddr))__builtin_memcpy((dst), (macaddr), (strlen(macaddr)));
3025 dst += strlen(macaddr);
3026 }
3027 }
3028#endif
3029
3030 count = dst - newbuf;
3031 pad = roundup(count + 1, 4)((((count + 1)+((4)-1))/(4))*(4)) - count;
3032
3033 memset(dst, 0, pad)__builtin_memset((dst), (0), (pad));
3034 count += pad;
3035 dst += pad;
3036
3037 token = (count / 4) & 0xffff;
3038 token |= ~token << 16;
3039 token = htole32(token)((__uint32_t)(token));
3040
3041 memcpy(dst, &token, sizeof(token))__builtin_memcpy((dst), (&token), (sizeof(token)));
3042 count += sizeof(token);
3043
3044 free(*bufp, M_DEVBUF2, *sizep);
3045 *bufp = newbuf;
3046 *sizep = newsize;
3047 *newlenp = count;
3048 return 0;
3049}
3050
3051void
3052bwfm_process_blob(struct bwfm_softc *sc, char *var, u_char **blob,
3053 size_t *blobsize)
3054{
3055 struct bwfm_dload_data *data;
3056 size_t off, remain, len;
3057
3058 if (*blob == NULL((void *)0) || *blobsize == 0)
3059 return;
3060
3061 off = 0;
3062 remain = *blobsize;
3063 data = malloc(sizeof(*data) + BWFM_DLOAD_MAX_LEN1400, M_TEMP127, M_WAITOK0x0001);
3064
3065 while (remain) {
3066 len = min(remain, BWFM_DLOAD_MAX_LEN1400);
3067
3068 data->flag = htole16(BWFM_DLOAD_FLAG_HANDLER_VER_1)((__uint16_t)((1 << 12)));
3069 if (off == 0)
3070 data->flag |= htole16(BWFM_DLOAD_FLAG_BEGIN)((__uint16_t)((1 << 1)));
3071 if (remain <= BWFM_DLOAD_MAX_LEN1400)
3072 data->flag |= htole16(BWFM_DLOAD_FLAG_END)((__uint16_t)((1 << 2)));
3073 data->type = htole16(BWFM_DLOAD_TYPE_CLM)((__uint16_t)(2));
3074 data->len = htole32(len)((__uint32_t)(len));
3075 data->crc = 0;
3076 memcpy(data->data, *blob + off, len)__builtin_memcpy((data->data), (*blob + off), (len));
3077
3078 if (bwfm_fwvar_var_set_data(sc, var, data,
3079 sizeof(*data) + len)) {
3080 printf("%s: could not load blob (%s)\n", DEVNAME(sc)((sc)->sc_dev.dv_xname),
3081 var);
3082 goto out;
3083 }
3084
3085 off += len;
3086 remain -= len;
3087 }
3088
3089out:
3090 free(data, M_TEMP127, sizeof(*data) + BWFM_DLOAD_MAX_LEN1400);
3091 free(*blob, M_DEVBUF2, *blobsize);
3092 *blob = NULL((void *)0);
3093 *blobsize = 0;
3094}
3095
3096void
3097bwfm_init_board_type(struct bwfm_softc *sc)
3098{
3099#if defined(__HAVE_FDT)
3100 char compat[128];
3101 int len;
3102 char *p;
3103
3104 len = OF_getprop(OF_peer(0), "compatible", compat, sizeof(compat));
3105 if (len > 0 && len < sizeof(compat)) {
3106 compat[len] = '\0';
3107 if ((p = strchr(compat, '/')) != NULL((void *)0))
3108 *p = '\0';
3109 strlcpy(sc->sc_board_type, compat, sizeof(sc->sc_board_type));
3110 }
3111#endif
3112}
3113
3114int
3115bwfm_loadfirmware(struct bwfm_softc *sc, const char *chip, const char *bus,
3116 u_char **ucode, size_t *size, u_char **nvram, size_t *nvsize, size_t *nvlen)
3117{
3118 const char *board_type = NULL((void *)0);
3119 char name[128];
3120 int r;
3121
3122 *ucode = *nvram = NULL((void *)0);
3123 *size = *nvsize = *nvlen = 0;
3124
3125 if (strlen(sc->sc_board_type) > 0)
3126 board_type = sc->sc_board_type;
3127
3128 if (board_type != NULL((void *)0)) {
3129 r = snprintf(name, sizeof(name), "%sbrcmfmac%s%s.%s.bin",
3130 sc->sc_fwdir, chip, bus, board_type);
3131 if ((r > 0 && r < sizeof(name)) &&
3132 loadfirmware(name, ucode, size) != 0)
3133 *size = 0;
3134 }
3135 if (*size == 0) {
3136 snprintf(name, sizeof(name), "%sbrcmfmac%s%s.bin",
3137 sc->sc_fwdir, chip, bus);
3138 if (loadfirmware(name, ucode, size) != 0) {
3139 snprintf(name, sizeof(name), "%sbrcmfmac%s%s%s%s.bin",
3140 sc->sc_fwdir, chip, bus, board_type ? "." : "",
3141 board_type ? board_type : "");
3142 printf("%s: failed loadfirmware of file %s\n",
3143 DEVNAME(sc)((sc)->sc_dev.dv_xname), name);
3144 return 1;
3145 }
3146 }
3147
3148 /* .txt needs to be processed first */
3149 if (strlen(sc->sc_modrev) > 0) {
3150 r = snprintf(name, sizeof(name),
3151 "%sbrcmfmac%s%s.%s-%s-%s-%s.txt", sc->sc_fwdir, chip, bus,
3152 board_type, sc->sc_module, sc->sc_vendor, sc->sc_modrev);
3153 if (r > 0 && r < sizeof(name))
3154 loadfirmware(name, nvram, nvsize);
3155 }
3156 if (*nvsize == 0 && strlen(sc->sc_vendor) > 0) {
3157 r = snprintf(name, sizeof(name),
3158 "%sbrcmfmac%s%s.%s-%s-%s.txt", sc->sc_fwdir, chip, bus,
3159 board_type, sc->sc_module, sc->sc_vendor);
3160 if (r > 0 && r < sizeof(name))
3161 loadfirmware(name, nvram, nvsize);
3162 }
3163
3164 if (*nvsize == 0 && board_type != NULL((void *)0)) {
3165 r = snprintf(name, sizeof(name), "%sbrcmfmac%s%s.%s.txt",
3166 sc->sc_fwdir, chip, bus, board_type);
3167 if (r > 0 && r < sizeof(name))
3168 loadfirmware(name, nvram, nvsize);
3169 }
3170
3171 if (*nvsize == 0) {
3172 snprintf(name, sizeof(name), "%sbrcmfmac%s%s.txt",
3173 sc->sc_fwdir, chip, bus);
3174 loadfirmware(name, nvram, nvsize);
3175 }
3176
3177 if (*nvsize != 0) {
3178 if (bwfm_nvram_convert(sc->sc_node, nvram, nvsize, nvlen)) {
3179 printf("%s: failed to process file %s\n",
3180 DEVNAME(sc)((sc)->sc_dev.dv_xname), name);
3181 free(*ucode, M_DEVBUF2, *size);
3182 free(*nvram, M_DEVBUF2, *nvsize);
3183 return 1;
3184 }
3185 }
3186
3187 /* .nvram is the pre-processed version */
3188 if (*nvlen == 0) {
3189 snprintf(name, sizeof(name), "%sbrcmfmac%s%s.nvram",
3190 sc->sc_fwdir, chip, bus);
3191 if (loadfirmware(name, nvram, nvsize) == 0)
3192 *nvlen = *nvsize;
3193 }
3194
3195 if (*nvlen == 0 && strcmp(bus, "-sdio") == 0) {
3196 snprintf(name, sizeof(name), "%sbrcmfmac%s%s%s%s.txt",
3197 sc->sc_fwdir, chip, bus, board_type ? "." : "",
3198 board_type ? board_type : "");
3199 printf("%s: failed loadfirmware of file %s\n",
3200 DEVNAME(sc)((sc)->sc_dev.dv_xname), name);
3201 free(*ucode, M_DEVBUF2, *size);
3202 return 1;
3203 }
3204
3205 if (board_type != NULL((void *)0)) {
3206 r = snprintf(name, sizeof(name), "%sbrcmfmac%s%s.%s.clm_blob",
3207 sc->sc_fwdir, chip, bus, board_type);
3208 if (r > 0 && r < sizeof(name))
3209 loadfirmware(name, &sc->sc_clm, &sc->sc_clmsize);
3210 }
3211 if (sc->sc_clmsize == 0) {
3212 snprintf(name, sizeof(name), "%sbrcmfmac%s%s.clm_blob",
3213 sc->sc_fwdir, chip, bus);
3214 loadfirmware(name, &sc->sc_clm, &sc->sc_clmsize);
3215 }
3216
3217 if (board_type != NULL((void *)0)) {
3218 r = snprintf(name, sizeof(name),
3219 "%sbrcmfmac%s%s.%s.txcap_blob", sc->sc_fwdir,
3220 chip, bus, board_type);
3221 if (r > 0 && r < sizeof(name))
3222 loadfirmware(name, &sc->sc_txcap, &sc->sc_txcapsize);
3223 }
3224 if (sc->sc_txcapsize == 0) {
3225 snprintf(name, sizeof(name), "%sbrcmfmac%s%s.txcap_blob",
3226 sc->sc_fwdir, chip, bus);
3227 loadfirmware(name, &sc->sc_txcap, &sc->sc_txcapsize);
3228 }
3229
3230 return 0;
3231}