Bug Summary

File:dev/ic/bwfm.c
Warning:line 2653, column 15
Assigned value is garbage or undefined

Annotated Source Code

Press '?' to see keyboard shortcuts

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