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