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