Line data Source code
1 : /* $OpenBSD: bwfm.c,v 1.54 2018/07/25 20:37:11 patrick 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 NBPFILTER > 0
32 : #include <net/bpf.h>
33 : #endif
34 : #include <net/if.h>
35 : #include <net/if_dl.h>
36 : #include <net/if_media.h>
37 :
38 : #include <netinet/in.h>
39 : #include <netinet/if_ether.h>
40 :
41 : #include <net80211/ieee80211_var.h>
42 :
43 : #include <dev/ic/bwfmvar.h>
44 : #include <dev/ic/bwfmreg.h>
45 :
46 : /* #define BWFM_DEBUG */
47 : #ifdef BWFM_DEBUG
48 : #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0)
49 : #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0)
50 : static int bwfm_debug = 1;
51 : #else
52 : #define DPRINTF(x) do { ; } while (0)
53 : #define DPRINTFN(n, x) do { ; } while (0)
54 : #endif
55 :
56 : #define DEVNAME(sc) ((sc)->sc_dev.dv_xname)
57 :
58 : void bwfm_start(struct ifnet *);
59 : void bwfm_init(struct ifnet *);
60 : void bwfm_stop(struct ifnet *);
61 : void bwfm_watchdog(struct ifnet *);
62 : int bwfm_ioctl(struct ifnet *, u_long, caddr_t);
63 : int bwfm_media_change(struct ifnet *);
64 :
65 : int bwfm_chip_attach(struct bwfm_softc *);
66 : int bwfm_chip_detach(struct bwfm_softc *, int);
67 : struct bwfm_core *bwfm_chip_get_core(struct bwfm_softc *, int);
68 : struct bwfm_core *bwfm_chip_get_pmu(struct bwfm_softc *);
69 : int bwfm_chip_ai_isup(struct bwfm_softc *, struct bwfm_core *);
70 : void bwfm_chip_ai_disable(struct bwfm_softc *, struct bwfm_core *,
71 : uint32_t, uint32_t);
72 : void bwfm_chip_ai_reset(struct bwfm_softc *, struct bwfm_core *,
73 : uint32_t, uint32_t, uint32_t);
74 : void bwfm_chip_dmp_erom_scan(struct bwfm_softc *);
75 : int bwfm_chip_dmp_get_regaddr(struct bwfm_softc *, uint32_t *,
76 : uint32_t *, uint32_t *);
77 : int bwfm_chip_cr4_set_active(struct bwfm_softc *, uint32_t);
78 : void bwfm_chip_cr4_set_passive(struct bwfm_softc *);
79 : int bwfm_chip_ca7_set_active(struct bwfm_softc *, uint32_t);
80 : void bwfm_chip_ca7_set_passive(struct bwfm_softc *);
81 : int bwfm_chip_cm3_set_active(struct bwfm_softc *);
82 : void bwfm_chip_cm3_set_passive(struct bwfm_softc *);
83 : void bwfm_chip_socram_ramsize(struct bwfm_softc *, struct bwfm_core *);
84 : void bwfm_chip_sysmem_ramsize(struct bwfm_softc *, struct bwfm_core *);
85 : void bwfm_chip_tcm_ramsize(struct bwfm_softc *, struct bwfm_core *);
86 : void bwfm_chip_tcm_rambase(struct bwfm_softc *);
87 :
88 : int bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *, int,
89 : int, char *, size_t *);
90 : int bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *, int,
91 : int, char *, size_t);
92 : void bwfm_proto_bcdc_rx(struct bwfm_softc *, struct mbuf *);
93 : int bwfm_proto_bcdc_txctl(struct bwfm_softc *, int, char *, size_t *);
94 : void bwfm_proto_bcdc_rxctl(struct bwfm_softc *, char *, size_t);
95 :
96 : int bwfm_fwvar_cmd_get_data(struct bwfm_softc *, int, void *, size_t);
97 : int bwfm_fwvar_cmd_set_data(struct bwfm_softc *, int, void *, size_t);
98 : int bwfm_fwvar_cmd_get_int(struct bwfm_softc *, int, uint32_t *);
99 : int bwfm_fwvar_cmd_set_int(struct bwfm_softc *, int, uint32_t);
100 : int bwfm_fwvar_var_get_data(struct bwfm_softc *, char *, void *, size_t);
101 : int bwfm_fwvar_var_set_data(struct bwfm_softc *, char *, void *, size_t);
102 : int bwfm_fwvar_var_get_int(struct bwfm_softc *, char *, uint32_t *);
103 : int bwfm_fwvar_var_set_int(struct bwfm_softc *, char *, uint32_t);
104 :
105 : uint32_t bwfm_chan2spec(struct bwfm_softc *, struct ieee80211_channel *);
106 : uint32_t bwfm_chan2spec_d11n(struct bwfm_softc *, struct ieee80211_channel *);
107 : uint32_t bwfm_chan2spec_d11ac(struct bwfm_softc *, struct ieee80211_channel *);
108 : uint32_t bwfm_spec2chan(struct bwfm_softc *, uint32_t);
109 : uint32_t bwfm_spec2chan_d11n(struct bwfm_softc *, uint32_t);
110 : uint32_t bwfm_spec2chan_d11ac(struct bwfm_softc *, uint32_t);
111 :
112 : void bwfm_connect(struct bwfm_softc *);
113 : #ifndef IEEE80211_STA_ONLY
114 : void bwfm_hostap(struct bwfm_softc *);
115 : #endif
116 : void bwfm_scan(struct bwfm_softc *);
117 :
118 : void bwfm_task(void *);
119 : void bwfm_do_async(struct bwfm_softc *,
120 : void (*)(struct bwfm_softc *, void *), void *, int);
121 :
122 : int bwfm_set_key(struct ieee80211com *, struct ieee80211_node *,
123 : struct ieee80211_key *);
124 : void bwfm_delete_key(struct ieee80211com *, struct ieee80211_node *,
125 : struct ieee80211_key *);
126 : int bwfm_send_mgmt(struct ieee80211com *, struct ieee80211_node *,
127 : int, int, int);
128 : int bwfm_newstate(struct ieee80211com *, enum ieee80211_state, int);
129 :
130 : void bwfm_set_key_cb(struct bwfm_softc *, void *);
131 : void bwfm_delete_key_cb(struct bwfm_softc *, void *);
132 : void bwfm_rx_event_cb(struct bwfm_softc *, void *);
133 :
134 : struct mbuf *bwfm_newbuf(void);
135 : void bwfm_rx(struct bwfm_softc *, struct mbuf *);
136 : #ifndef IEEE80211_STA_ONLY
137 : void bwfm_rx_auth_ind(struct bwfm_softc *, struct bwfm_event *, size_t);
138 : void bwfm_rx_assoc_ind(struct bwfm_softc *, struct bwfm_event *, size_t, int);
139 : void bwfm_rx_deauth_ind(struct bwfm_softc *, struct bwfm_event *, size_t);
140 : void bwfm_rx_disassoc_ind(struct bwfm_softc *, struct bwfm_event *, size_t);
141 : void bwfm_rx_leave_ind(struct bwfm_softc *, struct bwfm_event *, size_t, int);
142 : #endif
143 : void bwfm_rx_event(struct bwfm_softc *, struct mbuf *);
144 : void bwfm_scan_node(struct bwfm_softc *, struct bwfm_bss_info *, size_t);
145 :
146 : extern void ieee80211_node2req(struct ieee80211com *,
147 : const struct ieee80211_node *, struct ieee80211_nodereq *);
148 : extern void ieee80211_req2node(struct ieee80211com *,
149 : const struct ieee80211_nodereq *, struct ieee80211_node *);
150 :
151 : uint8_t bwfm_2ghz_channels[] = {
152 : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
153 : };
154 : uint8_t bwfm_5ghz_channels[] = {
155 : 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, 100, 104, 108, 112,
156 : 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165,
157 : };
158 :
159 : struct bwfm_proto_ops bwfm_proto_bcdc_ops = {
160 : .proto_query_dcmd = bwfm_proto_bcdc_query_dcmd,
161 : .proto_set_dcmd = bwfm_proto_bcdc_set_dcmd,
162 : .proto_rx = bwfm_proto_bcdc_rx,
163 : .proto_rxctl = bwfm_proto_bcdc_rxctl,
164 : };
165 :
166 : struct cfdriver bwfm_cd = {
167 : NULL, "bwfm", DV_IFNET
168 : };
169 :
170 : void
171 0 : bwfm_attach(struct bwfm_softc *sc)
172 : {
173 0 : struct ieee80211com *ic = &sc->sc_ic;
174 0 : struct ifnet *ifp = &ic->ic_if;
175 :
176 0 : TAILQ_INIT(&sc->sc_bcdc_rxctlq);
177 :
178 : /* Init host async commands ring. */
179 0 : sc->sc_cmdq.cur = sc->sc_cmdq.next = sc->sc_cmdq.queued = 0;
180 0 : sc->sc_taskq = taskq_create(DEVNAME(sc), 1, IPL_SOFTNET, 0);
181 0 : task_set(&sc->sc_task, bwfm_task, sc);
182 :
183 0 : ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
184 0 : ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
185 0 : ic->ic_state = IEEE80211_S_INIT;
186 :
187 0 : ic->ic_caps =
188 : #ifndef IEEE80211_STA_ONLY
189 : IEEE80211_C_HOSTAP | /* Access Point */
190 : #endif
191 : IEEE80211_C_RSN | /* WPA/RSN */
192 : IEEE80211_C_SCANALL | /* device scans all channels at once */
193 : IEEE80211_C_SCANALLBAND; /* device scans all bands at once */
194 :
195 : /* IBSS channel undefined for now. */
196 0 : ic->ic_ibss_chan = &ic->ic_channels[0];
197 :
198 0 : ifp->if_softc = sc;
199 0 : ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
200 0 : ifp->if_ioctl = bwfm_ioctl;
201 0 : ifp->if_start = bwfm_start;
202 0 : ifp->if_watchdog = bwfm_watchdog;
203 0 : memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
204 :
205 0 : if_attach(ifp);
206 0 : ieee80211_ifattach(ifp);
207 :
208 0 : sc->sc_newstate = ic->ic_newstate;
209 0 : ic->ic_newstate = bwfm_newstate;
210 0 : ic->ic_send_mgmt = bwfm_send_mgmt;
211 0 : ic->ic_set_key = bwfm_set_key;
212 0 : ic->ic_delete_key = bwfm_delete_key;
213 :
214 0 : ieee80211_media_init(ifp, bwfm_media_change, ieee80211_media_status);
215 0 : }
216 :
217 : void
218 0 : bwfm_attachhook(struct device *self)
219 : {
220 0 : struct bwfm_softc *sc = (struct bwfm_softc *)self;
221 :
222 0 : if (sc->sc_bus_ops->bs_preinit != NULL &&
223 0 : sc->sc_bus_ops->bs_preinit(sc))
224 0 : return;
225 0 : if (bwfm_preinit(sc))
226 0 : return;
227 0 : sc->sc_initialized = 1;
228 0 : }
229 :
230 : int
231 0 : bwfm_preinit(struct bwfm_softc *sc)
232 : {
233 0 : struct ieee80211com *ic = &sc->sc_ic;
234 0 : struct ifnet *ifp = &ic->ic_if;
235 0 : int i, j, nbands, nmode, vhtmode;
236 0 : uint32_t bandlist[3], tmp;
237 :
238 0 : if (sc->sc_initialized)
239 0 : return 0;
240 :
241 0 : if (bwfm_fwvar_cmd_get_int(sc, BWFM_C_GET_VERSION, &tmp)) {
242 0 : printf("%s: could not read io type\n", DEVNAME(sc));
243 0 : return 1;
244 : } else
245 0 : sc->sc_io_type = tmp;
246 0 : if (bwfm_fwvar_var_get_data(sc, "cur_etheraddr", ic->ic_myaddr,
247 : sizeof(ic->ic_myaddr))) {
248 0 : printf("%s: could not read mac address\n", DEVNAME(sc));
249 0 : return 1;
250 : }
251 :
252 0 : if (bwfm_fwvar_var_get_int(sc, "nmode", &nmode))
253 0 : nmode = 0;
254 0 : if (bwfm_fwvar_var_get_int(sc, "vhtmode", &vhtmode))
255 0 : vhtmode = 0;
256 0 : if (bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_BANDLIST, bandlist,
257 : sizeof(bandlist))) {
258 0 : printf("%s: couldn't get supported band list\n", DEVNAME(sc));
259 0 : return 1;
260 : }
261 0 : nbands = letoh32(bandlist[0]);
262 0 : for (i = 1; i <= nbands && i < nitems(bandlist); i++) {
263 0 : switch (letoh32(bandlist[i])) {
264 : case BWFM_BAND_2G:
265 : DPRINTF(("%s: 2G HT %d VHT %d\n",
266 : DEVNAME(sc), nmode, vhtmode));
267 0 : ic->ic_sup_rates[IEEE80211_MODE_11B] =
268 0 : ieee80211_std_rateset_11b;
269 0 : ic->ic_sup_rates[IEEE80211_MODE_11G] =
270 0 : ieee80211_std_rateset_11g;
271 :
272 0 : for (j = 0; j < nitems(bwfm_2ghz_channels); j++) {
273 0 : uint8_t chan = bwfm_2ghz_channels[j];
274 0 : ic->ic_channels[chan].ic_freq =
275 0 : ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ);
276 0 : ic->ic_channels[chan].ic_flags =
277 : IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
278 : IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
279 0 : if (nmode)
280 0 : ic->ic_channels[chan].ic_flags |=
281 : IEEE80211_CHAN_HT;
282 : }
283 : break;
284 : case BWFM_BAND_5G:
285 : DPRINTF(("%s: 5G HT %d VHT %d\n",
286 : DEVNAME(sc), nmode, vhtmode));
287 0 : ic->ic_sup_rates[IEEE80211_MODE_11A] =
288 0 : ieee80211_std_rateset_11a;
289 :
290 0 : for (j = 0; j < nitems(bwfm_5ghz_channels); j++) {
291 0 : uint8_t chan = bwfm_5ghz_channels[j];
292 0 : ic->ic_channels[chan].ic_freq =
293 0 : ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ);
294 0 : ic->ic_channels[chan].ic_flags =
295 : IEEE80211_CHAN_A;
296 0 : if (nmode)
297 0 : ic->ic_channels[chan].ic_flags |=
298 : IEEE80211_CHAN_HT;
299 : }
300 : break;
301 : default:
302 0 : printf("%s: unsupported band 0x%x\n", DEVNAME(sc),
303 : letoh32(bandlist[i]));
304 0 : break;
305 : }
306 : }
307 :
308 : /* Configure channel information obtained from firmware. */
309 0 : ieee80211_channel_init(ifp);
310 :
311 : /* Configure MAC address. */
312 0 : if (if_setlladdr(ifp, ic->ic_myaddr))
313 0 : printf("%s: could not set MAC address\n", DEVNAME(sc));
314 :
315 0 : ieee80211_media_init(ifp, bwfm_media_change, ieee80211_media_status);
316 0 : return 0;
317 0 : }
318 :
319 : int
320 0 : bwfm_detach(struct bwfm_softc *sc, int flags)
321 : {
322 0 : struct ieee80211com *ic = &sc->sc_ic;
323 0 : struct ifnet *ifp = &ic->ic_if;
324 0 : task_del(sc->sc_taskq, &sc->sc_task);
325 0 : taskq_destroy(sc->sc_taskq);
326 0 : ieee80211_ifdetach(ifp);
327 0 : if_detach(ifp);
328 0 : return 0;
329 : }
330 :
331 : void
332 0 : bwfm_start(struct ifnet *ifp)
333 : {
334 0 : struct bwfm_softc *sc = ifp->if_softc;
335 : struct mbuf *m;
336 :
337 0 : if (!(ifp->if_flags & IFF_RUNNING))
338 0 : return;
339 0 : if (ifq_is_oactive(&ifp->if_snd))
340 0 : return;
341 0 : if (IFQ_IS_EMPTY(&ifp->if_snd))
342 0 : return;
343 :
344 : /* TODO: return if no link? */
345 :
346 0 : for (;;) {
347 0 : if (sc->sc_bus_ops->bs_txcheck(sc)) {
348 0 : ifq_set_oactive(&ifp->if_snd);
349 0 : break;
350 : }
351 :
352 0 : m = ifq_dequeue(&ifp->if_snd);
353 0 : if (m == NULL)
354 : break;
355 :
356 0 : if (sc->sc_bus_ops->bs_txdata(sc, m) != 0) {
357 0 : ifp->if_oerrors++;
358 0 : m_freem(m);
359 0 : continue;
360 : }
361 :
362 : #if NBPFILTER > 0
363 0 : if (ifp->if_bpf)
364 0 : bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
365 : #endif
366 : }
367 0 : }
368 :
369 : void
370 0 : bwfm_init(struct ifnet *ifp)
371 : {
372 0 : struct bwfm_softc *sc = ifp->if_softc;
373 0 : struct ieee80211com *ic = &sc->sc_ic;
374 0 : uint8_t evmask[BWFM_EVENT_MASK_LEN];
375 0 : struct bwfm_join_pref_params join_pref[2];
376 : int pm;
377 :
378 0 : if (!sc->sc_initialized) {
379 0 : if (sc->sc_bus_ops->bs_preinit != NULL &&
380 0 : sc->sc_bus_ops->bs_preinit(sc)) {
381 0 : printf("%s: could not init bus\n", DEVNAME(sc));
382 0 : return;
383 : }
384 0 : if (bwfm_preinit(sc)) {
385 0 : printf("%s: could not init\n", DEVNAME(sc));
386 0 : return;
387 : }
388 0 : sc->sc_initialized = 1;
389 0 : }
390 :
391 : /* Select default channel */
392 0 : ic->ic_bss->ni_chan = ic->ic_ibss_chan;
393 :
394 0 : if (bwfm_fwvar_var_set_int(sc, "mpc", 1)) {
395 0 : printf("%s: could not set mpc\n", DEVNAME(sc));
396 0 : return;
397 : }
398 :
399 : /* Select target by RSSI (boost on 5GHz) */
400 0 : join_pref[0].type = BWFM_JOIN_PREF_RSSI_DELTA;
401 0 : join_pref[0].len = 2;
402 0 : join_pref[0].rssi_gain = BWFM_JOIN_PREF_RSSI_BOOST;
403 0 : join_pref[0].band = BWFM_JOIN_PREF_BAND_5G;
404 0 : join_pref[1].type = BWFM_JOIN_PREF_RSSI;
405 0 : join_pref[1].len = 2;
406 0 : join_pref[1].rssi_gain = 0;
407 0 : join_pref[1].band = 0;
408 0 : if (bwfm_fwvar_var_set_data(sc, "join_pref", join_pref,
409 : sizeof(join_pref))) {
410 0 : printf("%s: could not set join pref\n", DEVNAME(sc));
411 0 : return;
412 : }
413 :
414 : #define BWFM_EVENT(event) evmask[(event) / 8] |= 1 << ((event) % 8)
415 0 : memset(evmask, 0, sizeof(evmask));
416 0 : switch (ic->ic_opmode) {
417 : case IEEE80211_M_STA:
418 0 : BWFM_EVENT(BWFM_E_IF);
419 0 : BWFM_EVENT(BWFM_E_LINK);
420 0 : BWFM_EVENT(BWFM_E_AUTH);
421 0 : BWFM_EVENT(BWFM_E_ASSOC);
422 0 : BWFM_EVENT(BWFM_E_DEAUTH);
423 0 : BWFM_EVENT(BWFM_E_DISASSOC);
424 0 : BWFM_EVENT(BWFM_E_SET_SSID);
425 0 : BWFM_EVENT(BWFM_E_ESCAN_RESULT);
426 0 : break;
427 : #ifndef IEEE80211_STA_ONLY
428 : case IEEE80211_M_HOSTAP:
429 0 : BWFM_EVENT(BWFM_E_AUTH_IND);
430 0 : BWFM_EVENT(BWFM_E_ASSOC_IND);
431 0 : BWFM_EVENT(BWFM_E_REASSOC_IND);
432 0 : BWFM_EVENT(BWFM_E_DEAUTH_IND);
433 0 : BWFM_EVENT(BWFM_E_DISASSOC_IND);
434 0 : BWFM_EVENT(BWFM_E_SET_SSID);
435 0 : BWFM_EVENT(BWFM_E_ESCAN_RESULT);
436 0 : break;
437 : #endif
438 : default:
439 : break;
440 : }
441 : #undef BWFM_EVENT
442 :
443 0 : if (bwfm_fwvar_var_set_data(sc, "event_msgs", evmask, sizeof(evmask))) {
444 0 : printf("%s: could not set event mask\n", DEVNAME(sc));
445 0 : return;
446 : }
447 :
448 0 : if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_CHANNEL_TIME,
449 : BWFM_DEFAULT_SCAN_CHANNEL_TIME)) {
450 0 : printf("%s: could not set scan channel time\n", DEVNAME(sc));
451 0 : return;
452 : }
453 0 : if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_UNASSOC_TIME,
454 : BWFM_DEFAULT_SCAN_UNASSOC_TIME)) {
455 0 : printf("%s: could not set scan unassoc time\n", DEVNAME(sc));
456 0 : return;
457 : }
458 0 : if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_PASSIVE_TIME,
459 : BWFM_DEFAULT_SCAN_PASSIVE_TIME)) {
460 0 : printf("%s: could not set scan passive time\n", DEVNAME(sc));
461 0 : return;
462 : }
463 :
464 : /*
465 : * Use CAM (constantly awake) when we are running as AP,
466 : * otherwise use fast power saving.
467 : */
468 : pm = BWFM_PM_FAST_PS;
469 : #ifndef IEEE80211_STA_ONLY
470 0 : if (ic->ic_opmode == IEEE80211_M_HOSTAP)
471 : pm = BWFM_PM_CAM;
472 : #endif
473 0 : if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, pm)) {
474 0 : printf("%s: could not set power\n", DEVNAME(sc));
475 0 : return;
476 : }
477 :
478 0 : bwfm_fwvar_var_set_int(sc, "txbf", 1);
479 0 : bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 0);
480 0 : bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 1);
481 0 : bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0);
482 :
483 : /* Disable all offloading (ARP, NDP, TCP/UDP cksum). */
484 0 : bwfm_fwvar_var_set_int(sc, "arp_ol", 0);
485 0 : bwfm_fwvar_var_set_int(sc, "arpoe", 0);
486 0 : bwfm_fwvar_var_set_int(sc, "ndoe", 0);
487 0 : bwfm_fwvar_var_set_int(sc, "toe", 0);
488 :
489 : /*
490 : * The firmware supplicant can handle the WPA handshake for
491 : * us, but we honestly want to do this ourselves, so disable
492 : * the firmware supplicant and let our stack handle it.
493 : */
494 0 : bwfm_fwvar_var_set_int(sc, "sup_wpa", 0);
495 :
496 : #if 0
497 : /* TODO: set these on proper ioctl */
498 : bwfm_fwvar_var_set_int(sc, "allmulti", 1);
499 : bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PROMISC, 1);
500 : #endif
501 :
502 0 : ifp->if_flags |= IFF_RUNNING;
503 0 : ifq_clr_oactive(&ifp->if_snd);
504 :
505 0 : ieee80211_begin_scan(ifp);
506 0 : }
507 :
508 : void
509 0 : bwfm_stop(struct ifnet *ifp)
510 : {
511 0 : struct bwfm_softc *sc = ifp->if_softc;
512 0 : struct ieee80211com *ic = &sc->sc_ic;
513 0 : struct bwfm_join_params join;
514 :
515 0 : sc->sc_tx_timer = 0;
516 0 : ifp->if_timer = 0;
517 0 : ifp->if_flags &= ~IFF_RUNNING;
518 0 : ifq_clr_oactive(&ifp->if_snd);
519 :
520 0 : ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
521 :
522 0 : memset(&join, 0, sizeof(join));
523 0 : bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, sizeof(join));
524 0 : bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1);
525 0 : bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0);
526 0 : bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 0);
527 0 : bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 1);
528 0 : bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, BWFM_PM_FAST_PS);
529 :
530 0 : if (sc->sc_bus_ops->bs_stop)
531 0 : sc->sc_bus_ops->bs_stop(sc);
532 0 : }
533 :
534 : void
535 0 : bwfm_watchdog(struct ifnet *ifp)
536 : {
537 0 : struct bwfm_softc *sc = ifp->if_softc;
538 :
539 0 : ifp->if_timer = 0;
540 :
541 0 : if (sc->sc_tx_timer > 0) {
542 0 : if (--sc->sc_tx_timer == 0) {
543 0 : printf("%s: device timeout\n", DEVNAME(sc));
544 0 : ifp->if_oerrors++;
545 0 : return;
546 : }
547 0 : ifp->if_timer = 1;
548 0 : }
549 0 : ieee80211_watchdog(ifp);
550 0 : }
551 :
552 : int
553 0 : bwfm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
554 : {
555 : int s, error = 0;
556 :
557 0 : s = splnet();
558 0 : switch (cmd) {
559 : case SIOCSIFADDR:
560 0 : ifp->if_flags |= IFF_UP;
561 : /* FALLTHROUGH */
562 : case SIOCSIFFLAGS:
563 0 : if (ifp->if_flags & IFF_UP) {
564 0 : if (!(ifp->if_flags & IFF_RUNNING))
565 0 : bwfm_init(ifp);
566 : } else {
567 0 : if (ifp->if_flags & IFF_RUNNING)
568 0 : bwfm_stop(ifp);
569 : }
570 : break;
571 : default:
572 0 : error = ieee80211_ioctl(ifp, cmd, data);
573 0 : }
574 0 : if (error == ENETRESET) {
575 0 : if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
576 : (IFF_UP | IFF_RUNNING)) {
577 0 : bwfm_stop(ifp);
578 0 : bwfm_init(ifp);
579 0 : }
580 : error = 0;
581 0 : }
582 0 : splx(s);
583 0 : return error;
584 : }
585 :
586 : int
587 0 : bwfm_media_change(struct ifnet *ifp)
588 : {
589 : int error;
590 :
591 0 : error = ieee80211_media_change(ifp);
592 0 : if (error != ENETRESET)
593 0 : return error;
594 :
595 0 : if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
596 : (IFF_UP | IFF_RUNNING)) {
597 0 : bwfm_stop(ifp);
598 0 : bwfm_init(ifp);
599 0 : }
600 0 : return 0;
601 0 : }
602 :
603 : /* Chip initialization (SDIO, PCIe) */
604 : int
605 0 : bwfm_chip_attach(struct bwfm_softc *sc)
606 : {
607 : struct bwfm_core *core;
608 : int need_socram = 0;
609 : int has_socram = 0;
610 : int cpu_found = 0;
611 : uint32_t val;
612 :
613 0 : LIST_INIT(&sc->sc_chip.ch_list);
614 :
615 0 : if (sc->sc_buscore_ops->bc_prepare(sc) != 0) {
616 0 : printf("%s: failed buscore prepare\n", DEVNAME(sc));
617 0 : return 1;
618 : }
619 :
620 0 : val = sc->sc_buscore_ops->bc_read(sc,
621 : BWFM_CHIP_BASE + BWFM_CHIP_REG_CHIPID);
622 0 : sc->sc_chip.ch_chip = BWFM_CHIP_CHIPID_ID(val);
623 0 : sc->sc_chip.ch_chiprev = BWFM_CHIP_CHIPID_REV(val);
624 :
625 0 : if ((sc->sc_chip.ch_chip > 0xa000) || (sc->sc_chip.ch_chip < 0x4000))
626 0 : snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name),
627 0 : "%d", sc->sc_chip.ch_chip);
628 : else
629 0 : snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name),
630 : "%x", sc->sc_chip.ch_chip);
631 :
632 0 : switch (BWFM_CHIP_CHIPID_TYPE(val))
633 : {
634 : case BWFM_CHIP_CHIPID_TYPE_SOCI_SB:
635 0 : printf("%s: SoC interconnect SB not implemented\n",
636 0 : DEVNAME(sc));
637 0 : return 1;
638 : case BWFM_CHIP_CHIPID_TYPE_SOCI_AI:
639 0 : sc->sc_chip.ch_core_isup = bwfm_chip_ai_isup;
640 0 : sc->sc_chip.ch_core_disable = bwfm_chip_ai_disable;
641 0 : sc->sc_chip.ch_core_reset = bwfm_chip_ai_reset;
642 0 : bwfm_chip_dmp_erom_scan(sc);
643 : break;
644 : default:
645 0 : printf("%s: SoC interconnect %d unknown\n",
646 0 : DEVNAME(sc), BWFM_CHIP_CHIPID_TYPE(val));
647 0 : return 1;
648 : }
649 :
650 0 : LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) {
651 : DPRINTF(("%s: 0x%x:%-2d base 0x%08x wrap 0x%08x\n",
652 : DEVNAME(sc), core->co_id, core->co_rev,
653 : core->co_base, core->co_wrapbase));
654 :
655 0 : switch (core->co_id) {
656 : case BWFM_AGENT_CORE_ARM_CM3:
657 0 : need_socram = 1;
658 : /* FALLTHROUGH */
659 : case BWFM_AGENT_CORE_ARM_CR4:
660 : case BWFM_AGENT_CORE_ARM_CA7:
661 : cpu_found = 1;
662 0 : break;
663 : case BWFM_AGENT_INTERNAL_MEM:
664 : has_socram = 1;
665 0 : break;
666 : default:
667 : break;
668 : }
669 : }
670 :
671 0 : if (!cpu_found) {
672 0 : printf("%s: CPU core not detected\n", DEVNAME(sc));
673 0 : return 1;
674 : }
675 0 : if (need_socram && !has_socram) {
676 0 : printf("%s: RAM core not provided\n", DEVNAME(sc));
677 0 : return 1;
678 : }
679 :
680 0 : bwfm_chip_set_passive(sc);
681 :
682 0 : if (sc->sc_buscore_ops->bc_reset) {
683 0 : sc->sc_buscore_ops->bc_reset(sc);
684 0 : bwfm_chip_set_passive(sc);
685 0 : }
686 :
687 0 : if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4)) != NULL) {
688 0 : bwfm_chip_tcm_ramsize(sc, core);
689 0 : bwfm_chip_tcm_rambase(sc);
690 0 : } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_SYS_MEM)) != NULL) {
691 0 : bwfm_chip_sysmem_ramsize(sc, core);
692 0 : bwfm_chip_tcm_rambase(sc);
693 0 : } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM)) != NULL) {
694 0 : bwfm_chip_socram_ramsize(sc, core);
695 0 : }
696 :
697 0 : core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
698 0 : sc->sc_chip.ch_cc_caps = sc->sc_buscore_ops->bc_read(sc,
699 0 : core->co_base + BWFM_CHIP_REG_CAPABILITIES);
700 0 : sc->sc_chip.ch_cc_caps_ext = sc->sc_buscore_ops->bc_read(sc,
701 0 : core->co_base + BWFM_CHIP_REG_CAPABILITIES_EXT);
702 :
703 0 : core = bwfm_chip_get_pmu(sc);
704 0 : if (sc->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU) {
705 0 : sc->sc_chip.ch_pmucaps = sc->sc_buscore_ops->bc_read(sc,
706 0 : core->co_base + BWFM_CHIP_REG_PMUCAPABILITIES);
707 0 : sc->sc_chip.ch_pmurev = sc->sc_chip.ch_pmucaps &
708 : BWFM_CHIP_REG_PMUCAPABILITIES_REV_MASK;
709 0 : }
710 :
711 0 : if (sc->sc_buscore_ops->bc_setup)
712 0 : sc->sc_buscore_ops->bc_setup(sc);
713 :
714 0 : return 0;
715 0 : }
716 :
717 : struct bwfm_core *
718 0 : bwfm_chip_get_core(struct bwfm_softc *sc, int id)
719 : {
720 : struct bwfm_core *core;
721 :
722 0 : LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) {
723 0 : if (core->co_id == id)
724 0 : return core;
725 : }
726 :
727 0 : return NULL;
728 0 : }
729 :
730 : struct bwfm_core *
731 0 : bwfm_chip_get_pmu(struct bwfm_softc *sc)
732 : {
733 : struct bwfm_core *cc, *pmu;
734 :
735 0 : cc = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
736 0 : if (cc->co_rev >= 35 && sc->sc_chip.ch_cc_caps_ext &
737 : BWFM_CHIP_REG_CAPABILITIES_EXT_AOB_PRESENT) {
738 0 : pmu = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_PMU);
739 0 : if (pmu)
740 0 : return pmu;
741 : }
742 :
743 0 : return cc;
744 0 : }
745 :
746 : /* Functions for the AI interconnect */
747 : int
748 0 : bwfm_chip_ai_isup(struct bwfm_softc *sc, struct bwfm_core *core)
749 : {
750 : uint32_t ioctl, reset;
751 :
752 0 : ioctl = sc->sc_buscore_ops->bc_read(sc,
753 0 : core->co_wrapbase + BWFM_AGENT_IOCTL);
754 0 : reset = sc->sc_buscore_ops->bc_read(sc,
755 0 : core->co_wrapbase + BWFM_AGENT_RESET_CTL);
756 :
757 0 : if (((ioctl & (BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK)) ==
758 0 : BWFM_AGENT_IOCTL_CLK) &&
759 0 : ((reset & BWFM_AGENT_RESET_CTL_RESET) == 0))
760 0 : return 1;
761 :
762 0 : return 0;
763 0 : }
764 :
765 : void
766 0 : bwfm_chip_ai_disable(struct bwfm_softc *sc, struct bwfm_core *core,
767 : uint32_t prereset, uint32_t reset)
768 : {
769 : uint32_t val;
770 : int i;
771 :
772 0 : val = sc->sc_buscore_ops->bc_read(sc,
773 0 : core->co_wrapbase + BWFM_AGENT_RESET_CTL);
774 0 : if ((val & BWFM_AGENT_RESET_CTL_RESET) == 0) {
775 :
776 0 : sc->sc_buscore_ops->bc_write(sc,
777 0 : core->co_wrapbase + BWFM_AGENT_IOCTL,
778 0 : prereset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK);
779 0 : sc->sc_buscore_ops->bc_read(sc,
780 0 : core->co_wrapbase + BWFM_AGENT_IOCTL);
781 :
782 0 : sc->sc_buscore_ops->bc_write(sc,
783 0 : core->co_wrapbase + BWFM_AGENT_RESET_CTL,
784 : BWFM_AGENT_RESET_CTL_RESET);
785 0 : delay(20);
786 :
787 0 : for (i = 300; i > 0; i--) {
788 0 : if (sc->sc_buscore_ops->bc_read(sc,
789 0 : core->co_wrapbase + BWFM_AGENT_RESET_CTL) ==
790 : BWFM_AGENT_RESET_CTL_RESET)
791 : break;
792 : }
793 0 : if (i == 0)
794 0 : printf("%s: timeout on core reset\n", DEVNAME(sc));
795 : }
796 :
797 0 : sc->sc_buscore_ops->bc_write(sc,
798 0 : core->co_wrapbase + BWFM_AGENT_IOCTL,
799 0 : reset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK);
800 0 : sc->sc_buscore_ops->bc_read(sc,
801 0 : core->co_wrapbase + BWFM_AGENT_IOCTL);
802 0 : }
803 :
804 : void
805 0 : bwfm_chip_ai_reset(struct bwfm_softc *sc, struct bwfm_core *core,
806 : uint32_t prereset, uint32_t reset, uint32_t postreset)
807 : {
808 : int i;
809 :
810 0 : bwfm_chip_ai_disable(sc, core, prereset, reset);
811 :
812 0 : for (i = 50; i > 0; i--) {
813 0 : if ((sc->sc_buscore_ops->bc_read(sc,
814 0 : core->co_wrapbase + BWFM_AGENT_RESET_CTL) &
815 0 : BWFM_AGENT_RESET_CTL_RESET) == 0)
816 : break;
817 0 : sc->sc_buscore_ops->bc_write(sc,
818 0 : core->co_wrapbase + BWFM_AGENT_RESET_CTL, 0);
819 0 : delay(60);
820 : }
821 0 : if (i == 0)
822 0 : printf("%s: timeout on core reset\n", DEVNAME(sc));
823 :
824 0 : sc->sc_buscore_ops->bc_write(sc,
825 0 : core->co_wrapbase + BWFM_AGENT_IOCTL,
826 0 : postreset | BWFM_AGENT_IOCTL_CLK);
827 0 : sc->sc_buscore_ops->bc_read(sc,
828 0 : core->co_wrapbase + BWFM_AGENT_IOCTL);
829 0 : }
830 :
831 : void
832 0 : bwfm_chip_dmp_erom_scan(struct bwfm_softc *sc)
833 : {
834 0 : uint32_t erom, val, base, wrap;
835 : uint8_t type = 0;
836 : uint16_t id;
837 : uint8_t nmw, nsw, rev;
838 : struct bwfm_core *core;
839 :
840 0 : erom = sc->sc_buscore_ops->bc_read(sc,
841 : BWFM_CHIP_BASE + BWFM_CHIP_REG_EROMPTR);
842 0 : while (type != BWFM_DMP_DESC_EOT) {
843 0 : val = sc->sc_buscore_ops->bc_read(sc, erom);
844 0 : type = val & BWFM_DMP_DESC_MASK;
845 0 : erom += 4;
846 :
847 0 : if (type != BWFM_DMP_DESC_COMPONENT)
848 0 : continue;
849 :
850 0 : id = (val & BWFM_DMP_COMP_PARTNUM)
851 0 : >> BWFM_DMP_COMP_PARTNUM_S;
852 :
853 0 : val = sc->sc_buscore_ops->bc_read(sc, erom);
854 0 : type = val & BWFM_DMP_DESC_MASK;
855 0 : erom += 4;
856 :
857 0 : if (type != BWFM_DMP_DESC_COMPONENT) {
858 0 : printf("%s: not component descriptor\n", DEVNAME(sc));
859 0 : return;
860 : }
861 :
862 0 : nmw = (val & BWFM_DMP_COMP_NUM_MWRAP)
863 0 : >> BWFM_DMP_COMP_NUM_MWRAP_S;
864 0 : nsw = (val & BWFM_DMP_COMP_NUM_SWRAP)
865 0 : >> BWFM_DMP_COMP_NUM_SWRAP_S;
866 0 : rev = (val & BWFM_DMP_COMP_REVISION)
867 0 : >> BWFM_DMP_COMP_REVISION_S;
868 :
869 0 : if (nmw + nsw == 0 && id != BWFM_AGENT_CORE_PMU)
870 0 : continue;
871 :
872 0 : if (bwfm_chip_dmp_get_regaddr(sc, &erom, &base, &wrap))
873 0 : continue;
874 :
875 0 : core = malloc(sizeof(*core), M_DEVBUF, M_WAITOK);
876 0 : core->co_id = id;
877 0 : core->co_base = base;
878 0 : core->co_wrapbase = wrap;
879 0 : core->co_rev = rev;
880 0 : LIST_INSERT_HEAD(&sc->sc_chip.ch_list, core, co_link);
881 : }
882 0 : }
883 :
884 : int
885 0 : bwfm_chip_dmp_get_regaddr(struct bwfm_softc *sc, uint32_t *erom,
886 : uint32_t *base, uint32_t *wrap)
887 : {
888 : uint8_t type = 0, mpnum = 0;
889 : uint8_t stype, sztype, wraptype;
890 : uint32_t val;
891 :
892 0 : *base = 0;
893 0 : *wrap = 0;
894 :
895 0 : val = sc->sc_buscore_ops->bc_read(sc, *erom);
896 0 : type = val & BWFM_DMP_DESC_MASK;
897 0 : if (type == BWFM_DMP_DESC_MASTER_PORT) {
898 0 : mpnum = (val & BWFM_DMP_MASTER_PORT_NUM)
899 0 : >> BWFM_DMP_MASTER_PORT_NUM_S;
900 : wraptype = BWFM_DMP_SLAVE_TYPE_MWRAP;
901 0 : *erom += 4;
902 0 : } else if ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) ==
903 : BWFM_DMP_DESC_ADDRESS)
904 : wraptype = BWFM_DMP_SLAVE_TYPE_SWRAP;
905 : else
906 0 : return 1;
907 :
908 0 : do {
909 0 : do {
910 0 : val = sc->sc_buscore_ops->bc_read(sc, *erom);
911 0 : type = val & BWFM_DMP_DESC_MASK;
912 0 : if (type == BWFM_DMP_DESC_COMPONENT)
913 0 : return 0;
914 0 : if (type == BWFM_DMP_DESC_EOT)
915 0 : return 1;
916 0 : *erom += 4;
917 0 : } while ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) !=
918 : BWFM_DMP_DESC_ADDRESS);
919 :
920 0 : if (type & BWFM_DMP_DESC_ADDRSIZE_GT32)
921 0 : *erom += 4;
922 :
923 0 : sztype = (val & BWFM_DMP_SLAVE_SIZE_TYPE)
924 0 : >> BWFM_DMP_SLAVE_SIZE_TYPE_S;
925 0 : if (sztype == BWFM_DMP_SLAVE_SIZE_DESC) {
926 0 : val = sc->sc_buscore_ops->bc_read(sc, *erom);
927 0 : type = val & BWFM_DMP_DESC_MASK;
928 0 : if (type & BWFM_DMP_DESC_ADDRSIZE_GT32)
929 0 : *erom += 8;
930 : else
931 0 : *erom += 4;
932 : }
933 0 : if (sztype != BWFM_DMP_SLAVE_SIZE_4K)
934 : continue;
935 :
936 0 : stype = (val & BWFM_DMP_SLAVE_TYPE) >> BWFM_DMP_SLAVE_TYPE_S;
937 0 : if (*base == 0 && stype == BWFM_DMP_SLAVE_TYPE_SLAVE)
938 0 : *base = val & BWFM_DMP_SLAVE_ADDR_BASE;
939 0 : if (*wrap == 0 && stype == wraptype)
940 0 : *wrap = val & BWFM_DMP_SLAVE_ADDR_BASE;
941 0 : } while (*base == 0 || *wrap == 0);
942 :
943 0 : return 0;
944 0 : }
945 :
946 : /* Core configuration */
947 : int
948 0 : bwfm_chip_set_active(struct bwfm_softc *sc, uint32_t rstvec)
949 : {
950 0 : if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL)
951 0 : return bwfm_chip_cr4_set_active(sc, rstvec);
952 0 : if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL)
953 0 : return bwfm_chip_ca7_set_active(sc, rstvec);
954 0 : if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL)
955 0 : return bwfm_chip_cm3_set_active(sc);
956 0 : return 1;
957 0 : }
958 :
959 : void
960 0 : bwfm_chip_set_passive(struct bwfm_softc *sc)
961 : {
962 0 : if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) {
963 0 : bwfm_chip_cr4_set_passive(sc);
964 0 : return;
965 : }
966 0 : if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) {
967 0 : bwfm_chip_ca7_set_passive(sc);
968 0 : return;
969 : }
970 0 : if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) {
971 0 : bwfm_chip_cm3_set_passive(sc);
972 0 : return;
973 : }
974 0 : }
975 :
976 : int
977 0 : bwfm_chip_cr4_set_active(struct bwfm_softc *sc, uint32_t rstvec)
978 : {
979 : struct bwfm_core *core;
980 :
981 0 : sc->sc_buscore_ops->bc_activate(sc, rstvec);
982 0 : core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4);
983 0 : sc->sc_chip.ch_core_reset(sc, core,
984 : BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0);
985 :
986 0 : return 0;
987 : }
988 :
989 : void
990 0 : bwfm_chip_cr4_set_passive(struct bwfm_softc *sc)
991 : {
992 : struct bwfm_core *core;
993 : uint32_t val;
994 :
995 0 : core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4);
996 0 : val = sc->sc_buscore_ops->bc_read(sc,
997 0 : core->co_wrapbase + BWFM_AGENT_IOCTL);
998 0 : sc->sc_chip.ch_core_reset(sc, core,
999 0 : val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1000 : BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1001 : BWFM_AGENT_IOCTL_ARMCR4_CPUHALT);
1002 :
1003 0 : core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211);
1004 0 : sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET |
1005 : BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN,
1006 : BWFM_AGENT_D11_IOCTL_PHYCLOCKEN);
1007 0 : }
1008 :
1009 : int
1010 0 : bwfm_chip_ca7_set_active(struct bwfm_softc *sc, uint32_t rstvec)
1011 : {
1012 : struct bwfm_core *core;
1013 :
1014 0 : sc->sc_buscore_ops->bc_activate(sc, rstvec);
1015 0 : core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7);
1016 0 : sc->sc_chip.ch_core_reset(sc, core,
1017 : BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0);
1018 :
1019 0 : return 0;
1020 : }
1021 :
1022 : void
1023 0 : bwfm_chip_ca7_set_passive(struct bwfm_softc *sc)
1024 : {
1025 : struct bwfm_core *core;
1026 : uint32_t val;
1027 :
1028 0 : core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7);
1029 0 : val = sc->sc_buscore_ops->bc_read(sc,
1030 0 : core->co_wrapbase + BWFM_AGENT_IOCTL);
1031 0 : sc->sc_chip.ch_core_reset(sc, core,
1032 0 : val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1033 : BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1034 : BWFM_AGENT_IOCTL_ARMCR4_CPUHALT);
1035 :
1036 0 : core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211);
1037 0 : sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET |
1038 : BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN,
1039 : BWFM_AGENT_D11_IOCTL_PHYCLOCKEN);
1040 0 : }
1041 :
1042 : int
1043 0 : bwfm_chip_cm3_set_active(struct bwfm_softc *sc)
1044 : {
1045 : struct bwfm_core *core;
1046 :
1047 0 : core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM);
1048 0 : if (!sc->sc_chip.ch_core_isup(sc, core))
1049 0 : return 1;
1050 :
1051 0 : sc->sc_buscore_ops->bc_activate(sc, 0);
1052 :
1053 0 : core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3);
1054 0 : sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1055 :
1056 0 : return 0;
1057 0 : }
1058 :
1059 : void
1060 0 : bwfm_chip_cm3_set_passive(struct bwfm_softc *sc)
1061 : {
1062 : struct bwfm_core *core;
1063 :
1064 0 : core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3);
1065 0 : sc->sc_chip.ch_core_disable(sc, core, 0, 0);
1066 0 : core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211);
1067 0 : sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET |
1068 : BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN,
1069 : BWFM_AGENT_D11_IOCTL_PHYCLOCKEN);
1070 0 : core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM);
1071 0 : sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1072 :
1073 0 : if (sc->sc_chip.ch_chip == BRCM_CC_43430_CHIP_ID) {
1074 0 : sc->sc_buscore_ops->bc_write(sc,
1075 0 : core->co_base + BWFM_SOCRAM_BANKIDX, 3);
1076 0 : sc->sc_buscore_ops->bc_write(sc,
1077 0 : core->co_base + BWFM_SOCRAM_BANKPDA, 0);
1078 0 : }
1079 0 : }
1080 :
1081 : int
1082 0 : bwfm_chip_sr_capable(struct bwfm_softc *sc)
1083 : {
1084 : struct bwfm_core *core;
1085 : uint32_t reg;
1086 :
1087 0 : if (sc->sc_chip.ch_pmurev < 17)
1088 0 : return 0;
1089 :
1090 0 : switch (sc->sc_chip.ch_chip) {
1091 : case BRCM_CC_4345_CHIP_ID:
1092 : case BRCM_CC_4354_CHIP_ID:
1093 : case BRCM_CC_4356_CHIP_ID:
1094 0 : core = bwfm_chip_get_pmu(sc);
1095 0 : sc->sc_buscore_ops->bc_write(sc, core->co_base +
1096 : BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3);
1097 0 : reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1098 : BWFM_CHIP_REG_CHIPCONTROL_DATA);
1099 0 : return (reg & (1 << 2)) != 0;
1100 : case BRCM_CC_43241_CHIP_ID:
1101 : case BRCM_CC_4335_CHIP_ID:
1102 : case BRCM_CC_4339_CHIP_ID:
1103 0 : core = bwfm_chip_get_pmu(sc);
1104 0 : sc->sc_buscore_ops->bc_write(sc, core->co_base +
1105 : BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3);
1106 0 : reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1107 : BWFM_CHIP_REG_CHIPCONTROL_DATA);
1108 0 : return reg != 0;
1109 : case BRCM_CC_43430_CHIP_ID:
1110 0 : core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1111 0 : reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1112 : BWFM_CHIP_REG_SR_CONTROL1);
1113 0 : return reg != 0;
1114 : default:
1115 0 : core = bwfm_chip_get_pmu(sc);
1116 0 : reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1117 : BWFM_CHIP_REG_PMUCAPABILITIES_EXT);
1118 0 : if ((reg & BWFM_CHIP_REG_PMUCAPABILITIES_SR_SUPP) == 0)
1119 0 : return 0;
1120 :
1121 0 : reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1122 : BWFM_CHIP_REG_RETENTION_CTL);
1123 0 : return (reg & (BWFM_CHIP_REG_RETENTION_CTL_MACPHY_DIS |
1124 0 : BWFM_CHIP_REG_RETENTION_CTL_LOGIC_DIS)) == 0;
1125 : }
1126 0 : }
1127 :
1128 : /* RAM size helpers */
1129 : void
1130 0 : bwfm_chip_socram_ramsize(struct bwfm_softc *sc, struct bwfm_core *core)
1131 : {
1132 : uint32_t coreinfo, nb, lss, banksize, bankinfo;
1133 : uint32_t ramsize = 0, srsize = 0;
1134 : int i;
1135 :
1136 0 : if (!sc->sc_chip.ch_core_isup(sc, core))
1137 0 : sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1138 :
1139 0 : coreinfo = sc->sc_buscore_ops->bc_read(sc,
1140 0 : core->co_base + BWFM_SOCRAM_COREINFO);
1141 0 : nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK)
1142 0 : >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT;
1143 :
1144 0 : if (core->co_rev <= 7 || core->co_rev == 12) {
1145 0 : banksize = coreinfo & BWFM_SOCRAM_COREINFO_SRBSZ_MASK;
1146 0 : lss = (coreinfo & BWFM_SOCRAM_COREINFO_LSS_MASK)
1147 0 : >> BWFM_SOCRAM_COREINFO_LSS_SHIFT;
1148 0 : if (lss != 0)
1149 0 : nb--;
1150 0 : ramsize = nb * (1 << (banksize + BWFM_SOCRAM_COREINFO_SRBSZ_BASE));
1151 0 : if (lss != 0)
1152 0 : ramsize += (1 << ((lss - 1) + BWFM_SOCRAM_COREINFO_SRBSZ_BASE));
1153 : } else {
1154 0 : for (i = 0; i < nb; i++) {
1155 0 : sc->sc_buscore_ops->bc_write(sc,
1156 0 : core->co_base + BWFM_SOCRAM_BANKIDX,
1157 : (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM <<
1158 : BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i);
1159 0 : bankinfo = sc->sc_buscore_ops->bc_read(sc,
1160 0 : core->co_base + BWFM_SOCRAM_BANKINFO);
1161 0 : banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1)
1162 0 : * BWFM_SOCRAM_BANKINFO_SZBASE;
1163 0 : ramsize += banksize;
1164 0 : if (bankinfo & BWFM_SOCRAM_BANKINFO_RETNTRAM_MASK)
1165 0 : srsize += banksize;
1166 : }
1167 : }
1168 :
1169 0 : switch (sc->sc_chip.ch_chip) {
1170 : case BRCM_CC_4334_CHIP_ID:
1171 0 : if (sc->sc_chip.ch_chiprev < 2)
1172 0 : srsize = 32 * 1024;
1173 : break;
1174 : case BRCM_CC_43430_CHIP_ID:
1175 : srsize = 64 * 1024;
1176 0 : break;
1177 : default:
1178 : break;
1179 : }
1180 :
1181 0 : sc->sc_chip.ch_ramsize = ramsize;
1182 0 : sc->sc_chip.ch_srsize = srsize;
1183 0 : }
1184 :
1185 : void
1186 0 : bwfm_chip_sysmem_ramsize(struct bwfm_softc *sc, struct bwfm_core *core)
1187 : {
1188 : uint32_t coreinfo, nb, banksize, bankinfo;
1189 : uint32_t ramsize = 0;
1190 : int i;
1191 :
1192 0 : if (!sc->sc_chip.ch_core_isup(sc, core))
1193 0 : sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1194 :
1195 0 : coreinfo = sc->sc_buscore_ops->bc_read(sc,
1196 0 : core->co_base + BWFM_SOCRAM_COREINFO);
1197 0 : nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK)
1198 0 : >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT;
1199 :
1200 0 : for (i = 0; i < nb; i++) {
1201 0 : sc->sc_buscore_ops->bc_write(sc,
1202 0 : core->co_base + BWFM_SOCRAM_BANKIDX,
1203 : (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM <<
1204 : BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i);
1205 0 : bankinfo = sc->sc_buscore_ops->bc_read(sc,
1206 0 : core->co_base + BWFM_SOCRAM_BANKINFO);
1207 0 : banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1)
1208 0 : * BWFM_SOCRAM_BANKINFO_SZBASE;
1209 0 : ramsize += banksize;
1210 : }
1211 :
1212 0 : sc->sc_chip.ch_ramsize = ramsize;
1213 0 : }
1214 :
1215 : void
1216 0 : bwfm_chip_tcm_ramsize(struct bwfm_softc *sc, struct bwfm_core *core)
1217 : {
1218 : uint32_t cap, nab, nbb, totb, bxinfo, ramsize = 0;
1219 : int i;
1220 :
1221 0 : cap = sc->sc_buscore_ops->bc_read(sc, core->co_base + BWFM_ARMCR4_CAP);
1222 0 : nab = (cap & BWFM_ARMCR4_CAP_TCBANB_MASK) >> BWFM_ARMCR4_CAP_TCBANB_SHIFT;
1223 0 : nbb = (cap & BWFM_ARMCR4_CAP_TCBBNB_MASK) >> BWFM_ARMCR4_CAP_TCBBNB_SHIFT;
1224 0 : totb = nab + nbb;
1225 :
1226 0 : for (i = 0; i < totb; i++) {
1227 0 : sc->sc_buscore_ops->bc_write(sc,
1228 0 : core->co_base + BWFM_ARMCR4_BANKIDX, i);
1229 0 : bxinfo = sc->sc_buscore_ops->bc_read(sc,
1230 0 : core->co_base + BWFM_ARMCR4_BANKINFO);
1231 0 : ramsize += ((bxinfo & BWFM_ARMCR4_BANKINFO_BSZ_MASK) + 1) *
1232 : BWFM_ARMCR4_BANKINFO_BSZ_MULT;
1233 : }
1234 :
1235 0 : sc->sc_chip.ch_ramsize = ramsize;
1236 0 : }
1237 :
1238 : void
1239 0 : bwfm_chip_tcm_rambase(struct bwfm_softc *sc)
1240 : {
1241 0 : switch (sc->sc_chip.ch_chip) {
1242 : case BRCM_CC_4345_CHIP_ID:
1243 0 : sc->sc_chip.ch_rambase = 0x198000;
1244 0 : break;
1245 : case BRCM_CC_4335_CHIP_ID:
1246 : case BRCM_CC_4339_CHIP_ID:
1247 : case BRCM_CC_4350_CHIP_ID:
1248 : case BRCM_CC_4354_CHIP_ID:
1249 : case BRCM_CC_4356_CHIP_ID:
1250 : case BRCM_CC_43567_CHIP_ID:
1251 : case BRCM_CC_43569_CHIP_ID:
1252 : case BRCM_CC_43570_CHIP_ID:
1253 : case BRCM_CC_4358_CHIP_ID:
1254 : case BRCM_CC_4359_CHIP_ID:
1255 : case BRCM_CC_43602_CHIP_ID:
1256 : case BRCM_CC_4371_CHIP_ID:
1257 0 : sc->sc_chip.ch_rambase = 0x180000;
1258 0 : break;
1259 : case BRCM_CC_43465_CHIP_ID:
1260 : case BRCM_CC_43525_CHIP_ID:
1261 : case BRCM_CC_4365_CHIP_ID:
1262 : case BRCM_CC_4366_CHIP_ID:
1263 0 : sc->sc_chip.ch_rambase = 0x200000;
1264 0 : break;
1265 : case CY_CC_4373_CHIP_ID:
1266 0 : sc->sc_chip.ch_rambase = 0x160000;
1267 0 : break;
1268 : default:
1269 0 : printf("%s: unknown chip: %d\n", DEVNAME(sc),
1270 : sc->sc_chip.ch_chip);
1271 0 : break;
1272 : }
1273 0 : }
1274 :
1275 : /* BCDC protocol implementation */
1276 : int
1277 0 : bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *sc, int ifidx,
1278 : int cmd, char *buf, size_t *len)
1279 : {
1280 : struct bwfm_proto_bcdc_dcmd *dcmd;
1281 0 : size_t size = sizeof(dcmd->hdr) + *len;
1282 : int ret = 1, reqid;
1283 :
1284 0 : reqid = sc->sc_bcdc_reqid++;
1285 :
1286 0 : if (*len > sizeof(dcmd->buf))
1287 0 : return ret;
1288 :
1289 0 : dcmd = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
1290 0 : dcmd->hdr.cmd = htole32(cmd);
1291 0 : dcmd->hdr.len = htole32(*len);
1292 0 : dcmd->hdr.flags |= BWFM_BCDC_DCMD_GET;
1293 0 : dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid);
1294 0 : dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx);
1295 0 : dcmd->hdr.flags = htole32(dcmd->hdr.flags);
1296 0 : memcpy(&dcmd->buf, buf, *len);
1297 :
1298 0 : if (bwfm_proto_bcdc_txctl(sc, reqid, (char *)dcmd, &size)) {
1299 : DPRINTF(("%s: tx failed\n", DEVNAME(sc)));
1300 0 : return ret;
1301 : }
1302 :
1303 0 : if (buf) {
1304 0 : *len = min(*len, size);
1305 0 : memcpy(buf, dcmd->buf, *len);
1306 0 : }
1307 :
1308 0 : if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR)
1309 0 : ret = dcmd->hdr.status;
1310 : else
1311 : ret = 0;
1312 0 : free(dcmd, M_TEMP, size);
1313 0 : return ret;
1314 0 : }
1315 :
1316 : int
1317 0 : bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *sc, int ifidx,
1318 : int cmd, char *buf, size_t len)
1319 : {
1320 : struct bwfm_proto_bcdc_dcmd *dcmd;
1321 0 : size_t size = sizeof(dcmd->hdr) + len;
1322 : int ret = 1, reqid;
1323 :
1324 0 : reqid = sc->sc_bcdc_reqid++;
1325 :
1326 0 : if (len > sizeof(dcmd->buf))
1327 0 : return ret;
1328 :
1329 0 : dcmd = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
1330 0 : dcmd->hdr.cmd = htole32(cmd);
1331 0 : dcmd->hdr.len = htole32(len);
1332 0 : dcmd->hdr.flags |= BWFM_BCDC_DCMD_SET;
1333 0 : dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid);
1334 0 : dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx);
1335 0 : dcmd->hdr.flags = htole32(dcmd->hdr.flags);
1336 0 : memcpy(&dcmd->buf, buf, len);
1337 :
1338 0 : if (bwfm_proto_bcdc_txctl(sc, reqid, (char *)dcmd, &size)) {
1339 : DPRINTF(("%s: txctl failed\n", DEVNAME(sc)));
1340 0 : return ret;
1341 : }
1342 :
1343 0 : if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR)
1344 0 : ret = dcmd->hdr.status;
1345 : else
1346 : ret = 0;
1347 0 : free(dcmd, M_TEMP, size);
1348 0 : return ret;
1349 0 : }
1350 :
1351 : int
1352 0 : bwfm_proto_bcdc_txctl(struct bwfm_softc *sc, int reqid, char *buf, size_t *len)
1353 : {
1354 : struct bwfm_proto_bcdc_ctl *ctl, *tmp;
1355 : int timeout = 0;
1356 :
1357 0 : ctl = malloc(sizeof(*ctl), M_TEMP, M_WAITOK|M_ZERO);
1358 0 : ctl->reqid = reqid;
1359 0 : ctl->buf = buf;
1360 0 : ctl->len = *len;
1361 :
1362 0 : if (sc->sc_bus_ops->bs_txctl(sc, ctl)) {
1363 : DPRINTF(("%s: tx failed\n", DEVNAME(sc)));
1364 0 : return 1;
1365 : }
1366 :
1367 0 : if (tsleep(ctl, PWAIT, "bwfm", hz))
1368 0 : timeout = 1;
1369 :
1370 0 : TAILQ_FOREACH_SAFE(ctl, &sc->sc_bcdc_rxctlq, next, tmp) {
1371 0 : if (ctl->reqid != reqid)
1372 : continue;
1373 0 : if (ctl->done) {
1374 0 : TAILQ_REMOVE(&sc->sc_bcdc_rxctlq, ctl, next);
1375 0 : *len = ctl->len;
1376 0 : free(ctl, M_TEMP, sizeof(*ctl));
1377 0 : return 0;
1378 : }
1379 0 : if (timeout) {
1380 0 : TAILQ_REMOVE(&sc->sc_bcdc_rxctlq, ctl, next);
1381 : DPRINTF(("%s: timeout waiting for txctl response\n",
1382 : DEVNAME(sc)));
1383 0 : free(ctl->buf, M_TEMP, ctl->len);
1384 0 : free(ctl, M_TEMP, sizeof(*ctl));
1385 0 : return 1;
1386 : }
1387 : break;
1388 : }
1389 :
1390 : DPRINTF(("%s: did%s find txctl metadata (timeout %d)\n",
1391 : DEVNAME(sc), ctl == NULL ? " not": "", timeout));
1392 0 : return 1;
1393 0 : }
1394 :
1395 : void
1396 0 : bwfm_proto_bcdc_rxctl(struct bwfm_softc *sc, char *buf, size_t len)
1397 : {
1398 : struct bwfm_proto_bcdc_dcmd *dcmd;
1399 : struct bwfm_proto_bcdc_ctl *ctl, *tmp;
1400 :
1401 0 : if (len < sizeof(dcmd->hdr))
1402 0 : return;
1403 :
1404 0 : dcmd = (struct bwfm_proto_bcdc_dcmd *)buf;
1405 0 : dcmd->hdr.cmd = letoh32(dcmd->hdr.cmd);
1406 0 : dcmd->hdr.len = letoh32(dcmd->hdr.len);
1407 0 : dcmd->hdr.flags = letoh32(dcmd->hdr.flags);
1408 0 : dcmd->hdr.status = letoh32(dcmd->hdr.status);
1409 :
1410 0 : TAILQ_FOREACH_SAFE(ctl, &sc->sc_bcdc_rxctlq, next, tmp) {
1411 0 : if (ctl->reqid != BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags))
1412 : continue;
1413 0 : if (ctl->len != len) {
1414 0 : free(ctl->buf, M_TEMP, ctl->len);
1415 0 : free(ctl, M_TEMP, sizeof(*ctl));
1416 0 : return;
1417 : }
1418 0 : memcpy(ctl->buf, buf, len);
1419 0 : ctl->done = 1;
1420 0 : wakeup(ctl);
1421 0 : return;
1422 : }
1423 0 : }
1424 :
1425 : void
1426 0 : bwfm_proto_bcdc_rx(struct bwfm_softc *sc, struct mbuf *m)
1427 : {
1428 : struct bwfm_proto_bcdc_hdr *hdr;
1429 :
1430 0 : hdr = mtod(m, struct bwfm_proto_bcdc_hdr *);
1431 0 : if (m->m_len < sizeof(*hdr)) {
1432 0 : m_freem(m);
1433 0 : return;
1434 : }
1435 0 : if (m->m_len < sizeof(*hdr) + (hdr->data_offset << 2)) {
1436 0 : m_freem(m);
1437 0 : return;
1438 : }
1439 0 : m_adj(m, sizeof(*hdr) + (hdr->data_offset << 2));
1440 :
1441 0 : bwfm_rx(sc, m);
1442 0 : }
1443 :
1444 : /* FW Variable code */
1445 : int
1446 0 : bwfm_fwvar_cmd_get_data(struct bwfm_softc *sc, int cmd, void *data, size_t len)
1447 : {
1448 0 : return sc->sc_proto_ops->proto_query_dcmd(sc, 0, cmd, data, &len);
1449 : }
1450 :
1451 : int
1452 0 : bwfm_fwvar_cmd_set_data(struct bwfm_softc *sc, int cmd, void *data, size_t len)
1453 : {
1454 0 : return sc->sc_proto_ops->proto_set_dcmd(sc, 0, cmd, data, len);
1455 : }
1456 :
1457 : int
1458 0 : bwfm_fwvar_cmd_get_int(struct bwfm_softc *sc, int cmd, uint32_t *data)
1459 : {
1460 : int ret;
1461 0 : ret = bwfm_fwvar_cmd_get_data(sc, cmd, data, sizeof(*data));
1462 0 : *data = letoh32(*data);
1463 0 : return ret;
1464 : }
1465 :
1466 : int
1467 0 : bwfm_fwvar_cmd_set_int(struct bwfm_softc *sc, int cmd, uint32_t data)
1468 : {
1469 0 : data = htole32(data);
1470 0 : return bwfm_fwvar_cmd_set_data(sc, cmd, &data, sizeof(data));
1471 : }
1472 :
1473 : int
1474 0 : bwfm_fwvar_var_get_data(struct bwfm_softc *sc, char *name, void *data, size_t len)
1475 : {
1476 : char *buf;
1477 : int ret;
1478 :
1479 0 : buf = malloc(strlen(name) + 1 + len, M_TEMP, M_WAITOK);
1480 0 : memcpy(buf, name, strlen(name) + 1);
1481 0 : memcpy(buf + strlen(name) + 1, data, len);
1482 0 : ret = bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_VAR,
1483 0 : buf, strlen(name) + 1 + len);
1484 0 : memcpy(data, buf, len);
1485 0 : free(buf, M_TEMP, strlen(name) + 1 + len);
1486 0 : return ret;
1487 : }
1488 :
1489 : int
1490 0 : bwfm_fwvar_var_set_data(struct bwfm_softc *sc, char *name, void *data, size_t len)
1491 : {
1492 : char *buf;
1493 : int ret;
1494 :
1495 0 : buf = malloc(strlen(name) + 1 + len, M_TEMP, M_WAITOK);
1496 0 : memcpy(buf, name, strlen(name) + 1);
1497 0 : memcpy(buf + strlen(name) + 1, data, len);
1498 0 : ret = bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_VAR,
1499 0 : buf, strlen(name) + 1 + len);
1500 0 : free(buf, M_TEMP, strlen(name) + 1 + len);
1501 0 : return ret;
1502 : }
1503 :
1504 : int
1505 0 : bwfm_fwvar_var_get_int(struct bwfm_softc *sc, char *name, uint32_t *data)
1506 : {
1507 : int ret;
1508 0 : ret = bwfm_fwvar_var_get_data(sc, name, data, sizeof(*data));
1509 0 : *data = letoh32(*data);
1510 0 : return ret;
1511 : }
1512 :
1513 : int
1514 0 : bwfm_fwvar_var_set_int(struct bwfm_softc *sc, char *name, uint32_t data)
1515 : {
1516 0 : data = htole32(data);
1517 0 : return bwfm_fwvar_var_set_data(sc, name, &data, sizeof(data));
1518 : }
1519 :
1520 : /* Channel parameters */
1521 : uint32_t
1522 0 : bwfm_chan2spec(struct bwfm_softc *sc, struct ieee80211_channel *c)
1523 : {
1524 0 : if (sc->sc_io_type == BWFM_IO_TYPE_D11N)
1525 0 : return bwfm_chan2spec_d11n(sc, c);
1526 : else
1527 0 : return bwfm_chan2spec_d11ac(sc, c);
1528 0 : }
1529 :
1530 : uint32_t
1531 0 : bwfm_chan2spec_d11n(struct bwfm_softc *sc, struct ieee80211_channel *c)
1532 : {
1533 : uint32_t chanspec;
1534 :
1535 0 : chanspec = ieee80211_mhz2ieee(c->ic_freq, 0) & BWFM_CHANSPEC_CHAN_MASK;
1536 0 : chanspec |= BWFM_CHANSPEC_D11N_SB_N;
1537 0 : chanspec |= BWFM_CHANSPEC_D11N_BW_20;
1538 0 : if (IEEE80211_IS_CHAN_2GHZ(c))
1539 0 : chanspec |= BWFM_CHANSPEC_D11N_BND_2G;
1540 0 : if (IEEE80211_IS_CHAN_5GHZ(c))
1541 0 : chanspec |= BWFM_CHANSPEC_D11N_BND_5G;
1542 :
1543 0 : return chanspec;
1544 : }
1545 :
1546 : uint32_t
1547 0 : bwfm_chan2spec_d11ac(struct bwfm_softc *sc, struct ieee80211_channel *c)
1548 : {
1549 : uint32_t chanspec;
1550 :
1551 0 : chanspec = ieee80211_mhz2ieee(c->ic_freq, 0) & BWFM_CHANSPEC_CHAN_MASK;
1552 : chanspec |= BWFM_CHANSPEC_D11AC_SB_LLL;
1553 0 : chanspec |= BWFM_CHANSPEC_D11AC_BW_20;
1554 0 : if (IEEE80211_IS_CHAN_2GHZ(c))
1555 0 : chanspec |= BWFM_CHANSPEC_D11AC_BND_2G;
1556 0 : if (IEEE80211_IS_CHAN_5GHZ(c))
1557 0 : chanspec |= BWFM_CHANSPEC_D11AC_BND_5G;
1558 :
1559 0 : return chanspec;
1560 : }
1561 :
1562 : uint32_t
1563 0 : bwfm_spec2chan(struct bwfm_softc *sc, uint32_t chanspec)
1564 : {
1565 0 : if (sc->sc_io_type == BWFM_IO_TYPE_D11N)
1566 0 : return bwfm_spec2chan_d11n(sc, chanspec);
1567 : else
1568 0 : return bwfm_spec2chan_d11ac(sc, chanspec);
1569 0 : }
1570 :
1571 : uint32_t
1572 0 : bwfm_spec2chan_d11n(struct bwfm_softc *sc, uint32_t chanspec)
1573 : {
1574 : uint32_t chanidx;
1575 :
1576 0 : chanidx = chanspec & BWFM_CHANSPEC_CHAN_MASK;
1577 :
1578 0 : switch (chanspec & BWFM_CHANSPEC_D11N_BW_MASK) {
1579 : case BWFM_CHANSPEC_D11N_BW_40:
1580 0 : switch (chanspec & BWFM_CHANSPEC_D11N_SB_MASK) {
1581 : case BWFM_CHANSPEC_D11N_SB_L:
1582 0 : chanidx -= 2;
1583 0 : break;
1584 : case BWFM_CHANSPEC_D11N_SB_U:
1585 0 : chanidx += 2;
1586 0 : break;
1587 : default:
1588 : break;
1589 : }
1590 : break;
1591 : default:
1592 : break;
1593 : }
1594 :
1595 0 : return chanidx;
1596 : }
1597 :
1598 : uint32_t
1599 0 : bwfm_spec2chan_d11ac(struct bwfm_softc *sc, uint32_t chanspec)
1600 : {
1601 : uint32_t chanidx;
1602 :
1603 0 : chanidx = chanspec & BWFM_CHANSPEC_CHAN_MASK;
1604 :
1605 0 : switch (chanspec & BWFM_CHANSPEC_D11AC_BW_MASK) {
1606 : case BWFM_CHANSPEC_D11AC_BW_40:
1607 0 : switch (chanspec & BWFM_CHANSPEC_D11AC_SB_MASK) {
1608 : case BWFM_CHANSPEC_D11AC_SB_LLL:
1609 0 : chanidx -= 2;
1610 0 : break;
1611 : case BWFM_CHANSPEC_D11AC_SB_LLU:
1612 0 : chanidx += 2;
1613 0 : break;
1614 : default:
1615 : break;
1616 : }
1617 : break;
1618 : case BWFM_CHANSPEC_D11AC_BW_80:
1619 0 : switch (chanspec & BWFM_CHANSPEC_D11AC_SB_MASK) {
1620 : case BWFM_CHANSPEC_D11AC_SB_LLL:
1621 0 : chanidx -= 6;
1622 0 : break;
1623 : case BWFM_CHANSPEC_D11AC_SB_LLU:
1624 0 : chanidx -= 2;
1625 0 : break;
1626 : case BWFM_CHANSPEC_D11AC_SB_LUL:
1627 0 : chanidx += 2;
1628 0 : break;
1629 : case BWFM_CHANSPEC_D11AC_SB_LUU:
1630 0 : chanidx += 6;
1631 0 : break;
1632 : default:
1633 : break;
1634 : }
1635 : break;
1636 : default:
1637 : break;
1638 : }
1639 :
1640 0 : return chanidx;
1641 : }
1642 :
1643 : /* 802.11 code */
1644 : void
1645 0 : bwfm_connect(struct bwfm_softc *sc)
1646 : {
1647 0 : struct ieee80211com *ic = &sc->sc_ic;
1648 : struct bwfm_ext_join_params *params;
1649 0 : uint8_t buf[64]; /* XXX max WPA/RSN/WMM IE length */
1650 : uint8_t *frm;
1651 :
1652 : /*
1653 : * OPEN: Open or WPA/WPA2 on newer Chips/Firmware.
1654 : * SHARED KEY: WEP.
1655 : * AUTO: Automatic, probably for older Chips/Firmware.
1656 : */
1657 0 : if (ic->ic_flags & IEEE80211_F_RSNON) {
1658 : uint32_t wsec = 0;
1659 : uint32_t wpa = 0;
1660 :
1661 : /* tell firmware to add WPA/RSN IE to (re)assoc request */
1662 0 : if (ic->ic_bss->ni_rsnprotos == IEEE80211_PROTO_RSN)
1663 0 : frm = ieee80211_add_rsn(buf, ic, ic->ic_bss);
1664 : else
1665 0 : frm = ieee80211_add_wpa(buf, ic, ic->ic_bss);
1666 0 : bwfm_fwvar_var_set_data(sc, "wpaie", buf, frm - buf);
1667 :
1668 0 : if (ic->ic_rsnprotos & IEEE80211_PROTO_WPA) {
1669 0 : if (ic->ic_rsnakms & IEEE80211_AKM_PSK)
1670 0 : wpa |= BWFM_WPA_AUTH_WPA_PSK;
1671 0 : if (ic->ic_rsnakms & IEEE80211_AKM_8021X)
1672 0 : wpa |= BWFM_WPA_AUTH_WPA_UNSPECIFIED;
1673 : }
1674 0 : if (ic->ic_rsnprotos & IEEE80211_PROTO_RSN) {
1675 0 : if (ic->ic_rsnakms & IEEE80211_AKM_PSK)
1676 0 : wpa |= BWFM_WPA_AUTH_WPA2_PSK;
1677 0 : if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_PSK)
1678 0 : wpa |= BWFM_WPA_AUTH_WPA2_PSK_SHA256;
1679 0 : if (ic->ic_rsnakms & IEEE80211_AKM_8021X)
1680 0 : wpa |= BWFM_WPA_AUTH_WPA2_UNSPECIFIED;
1681 0 : if (ic->ic_rsnakms & IEEE80211_AKM_SHA256_8021X)
1682 0 : wpa |= BWFM_WPA_AUTH_WPA2_1X_SHA256;
1683 : }
1684 0 : if (ic->ic_rsnciphers & IEEE80211_WPA_CIPHER_TKIP ||
1685 0 : ic->ic_rsngroupcipher & IEEE80211_WPA_CIPHER_TKIP)
1686 0 : wsec |= BWFM_WSEC_TKIP;
1687 0 : if (ic->ic_rsnciphers & IEEE80211_WPA_CIPHER_CCMP ||
1688 0 : ic->ic_rsngroupcipher & IEEE80211_WPA_CIPHER_CCMP)
1689 0 : wsec |= BWFM_WSEC_AES;
1690 :
1691 0 : bwfm_fwvar_var_set_int(sc, "wpa_auth", wpa);
1692 0 : bwfm_fwvar_var_set_int(sc, "wsec", wsec);
1693 0 : } else {
1694 0 : bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_DISABLED);
1695 0 : bwfm_fwvar_var_set_int(sc, "wsec", BWFM_WSEC_NONE);
1696 : }
1697 0 : bwfm_fwvar_var_set_int(sc, "auth", BWFM_AUTH_OPEN);
1698 0 : bwfm_fwvar_var_set_int(sc, "mfp", BWFM_MFP_NONE);
1699 :
1700 0 : if (ic->ic_des_esslen && ic->ic_des_esslen < BWFM_MAX_SSID_LEN) {
1701 0 : params = malloc(sizeof(*params), M_TEMP, M_WAITOK | M_ZERO);
1702 0 : memcpy(params->ssid.ssid, ic->ic_des_essid, ic->ic_des_esslen);
1703 0 : params->ssid.len = htole32(ic->ic_des_esslen);
1704 0 : memcpy(params->assoc.bssid, ic->ic_bss->ni_bssid,
1705 : sizeof(params->assoc.bssid));
1706 0 : params->scan.scan_type = -1;
1707 0 : params->scan.nprobes = htole32(-1);
1708 0 : params->scan.active_time = htole32(-1);
1709 0 : params->scan.passive_time = htole32(-1);
1710 0 : params->scan.home_time = htole32(-1);
1711 0 : if (bwfm_fwvar_var_set_data(sc, "join", params, sizeof(*params))) {
1712 0 : struct bwfm_join_params join;
1713 0 : memset(&join, 0, sizeof(join));
1714 0 : memcpy(join.ssid.ssid, ic->ic_des_essid,
1715 : ic->ic_des_esslen);
1716 0 : join.ssid.len = htole32(ic->ic_des_esslen);
1717 0 : memcpy(join.assoc.bssid, ic->ic_bss->ni_bssid,
1718 : sizeof(join.assoc.bssid));
1719 0 : bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join,
1720 : sizeof(join));
1721 0 : }
1722 0 : free(params, M_TEMP, sizeof(*params));
1723 0 : }
1724 0 : }
1725 :
1726 : #ifndef IEEE80211_STA_ONLY
1727 : void
1728 0 : bwfm_hostap(struct bwfm_softc *sc)
1729 : {
1730 0 : struct ieee80211com *ic = &sc->sc_ic;
1731 0 : struct ieee80211_node *ni = ic->ic_bss;
1732 0 : struct bwfm_join_params join;
1733 :
1734 : /*
1735 : * OPEN: Open or WPA/WPA2 on newer Chips/Firmware.
1736 : * SHARED KEY: WEP.
1737 : * AUTO: Automatic, probably for older Chips/Firmware.
1738 : */
1739 0 : if (ic->ic_flags & IEEE80211_F_RSNON) {
1740 : uint32_t wsec = 0;
1741 : uint32_t wpa = 0;
1742 :
1743 : /* TODO: Turn off if replay counter set */
1744 0 : if (ni->ni_rsnprotos & IEEE80211_PROTO_RSN)
1745 0 : bwfm_fwvar_var_set_int(sc, "wme_bss_disable", 1);
1746 :
1747 0 : if (ni->ni_rsnprotos & IEEE80211_PROTO_WPA) {
1748 0 : if (ni->ni_rsnakms & IEEE80211_AKM_PSK)
1749 0 : wpa |= BWFM_WPA_AUTH_WPA_PSK;
1750 0 : if (ni->ni_rsnakms & IEEE80211_AKM_8021X)
1751 0 : wpa |= BWFM_WPA_AUTH_WPA_UNSPECIFIED;
1752 : }
1753 0 : if (ni->ni_rsnprotos & IEEE80211_PROTO_RSN) {
1754 0 : if (ni->ni_rsnakms & IEEE80211_AKM_PSK)
1755 0 : wpa |= BWFM_WPA_AUTH_WPA2_PSK;
1756 0 : if (ni->ni_rsnakms & IEEE80211_AKM_SHA256_PSK)
1757 0 : wpa |= BWFM_WPA_AUTH_WPA2_PSK_SHA256;
1758 0 : if (ni->ni_rsnakms & IEEE80211_AKM_8021X)
1759 0 : wpa |= BWFM_WPA_AUTH_WPA2_UNSPECIFIED;
1760 0 : if (ni->ni_rsnakms & IEEE80211_AKM_SHA256_8021X)
1761 0 : wpa |= BWFM_WPA_AUTH_WPA2_1X_SHA256;
1762 : }
1763 0 : if (ni->ni_rsnciphers & IEEE80211_WPA_CIPHER_TKIP ||
1764 0 : ni->ni_rsngroupcipher & IEEE80211_WPA_CIPHER_TKIP)
1765 0 : wsec |= BWFM_WSEC_TKIP;
1766 0 : if (ni->ni_rsnciphers & IEEE80211_WPA_CIPHER_CCMP ||
1767 0 : ni->ni_rsngroupcipher & IEEE80211_WPA_CIPHER_CCMP)
1768 0 : wsec |= BWFM_WSEC_AES;
1769 :
1770 0 : bwfm_fwvar_var_set_int(sc, "wpa_auth", wpa);
1771 0 : bwfm_fwvar_var_set_int(sc, "wsec", wsec);
1772 0 : } else {
1773 0 : bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_DISABLED);
1774 0 : bwfm_fwvar_var_set_int(sc, "wsec", BWFM_WSEC_NONE);
1775 : }
1776 0 : bwfm_fwvar_var_set_int(sc, "auth", BWFM_AUTH_OPEN);
1777 0 : bwfm_fwvar_var_set_int(sc, "mfp", BWFM_MFP_NONE);
1778 :
1779 0 : bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 1);
1780 0 : bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 1);
1781 0 : bwfm_fwvar_var_set_int(sc, "chanspec",
1782 0 : bwfm_chan2spec(sc, ic->ic_bss->ni_chan));
1783 0 : bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 1);
1784 :
1785 0 : memset(&join, 0, sizeof(join));
1786 0 : memcpy(join.ssid.ssid, ic->ic_des_essid, ic->ic_des_esslen);
1787 0 : join.ssid.len = htole32(ic->ic_des_esslen);
1788 0 : memset(join.assoc.bssid, 0xff, sizeof(join.assoc.bssid));
1789 0 : bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, sizeof(join));
1790 0 : bwfm_fwvar_var_set_int(sc, "closednet",
1791 0 : (ic->ic_flags & IEEE80211_F_HIDENWID) != 0);
1792 0 : }
1793 : #endif
1794 :
1795 : void
1796 0 : bwfm_scan(struct bwfm_softc *sc)
1797 : {
1798 : struct bwfm_escan_params *params;
1799 : uint32_t nssid = 0, nchannel = 0;
1800 : size_t params_size;
1801 :
1802 : params_size = sizeof(*params);
1803 : params_size += sizeof(uint32_t) * ((nchannel + 1) / 2);
1804 : params_size += sizeof(struct bwfm_ssid) * nssid;
1805 :
1806 0 : params = malloc(params_size, M_TEMP, M_WAITOK | M_ZERO);
1807 0 : memset(params->scan_params.bssid, 0xff,
1808 : sizeof(params->scan_params.bssid));
1809 0 : params->scan_params.bss_type = 2;
1810 0 : params->scan_params.scan_type = BWFM_SCANTYPE_PASSIVE;
1811 0 : params->scan_params.nprobes = htole32(-1);
1812 0 : params->scan_params.active_time = htole32(-1);
1813 0 : params->scan_params.passive_time = htole32(-1);
1814 0 : params->scan_params.home_time = htole32(-1);
1815 0 : params->version = htole32(BWFM_ESCAN_REQ_VERSION);
1816 0 : params->action = htole16(WL_ESCAN_ACTION_START);
1817 0 : params->sync_id = htole16(0x1234);
1818 :
1819 : #if 0
1820 : /* Scan a specific channel */
1821 : params->scan_params.channel_list[0] = htole16(
1822 : (1 & 0xff) << 0 |
1823 : (3 & 0x3) << 8 |
1824 : (2 & 0x3) << 10 |
1825 : (2 & 0x3) << 12
1826 : );
1827 : params->scan_params.channel_num = htole32(
1828 : (1 & 0xffff) << 0
1829 : );
1830 : #endif
1831 :
1832 0 : bwfm_fwvar_var_set_data(sc, "escan", params, params_size);
1833 0 : free(params, M_TEMP, params_size);
1834 0 : }
1835 :
1836 : struct mbuf *
1837 0 : bwfm_newbuf(void)
1838 : {
1839 : struct mbuf *m;
1840 :
1841 0 : MGETHDR(m, M_DONTWAIT, MT_DATA);
1842 0 : if (m == NULL)
1843 0 : return (NULL);
1844 :
1845 0 : MCLGET(m, M_DONTWAIT);
1846 0 : if (!(m->m_flags & M_EXT)) {
1847 0 : m_freem(m);
1848 0 : return (NULL);
1849 : }
1850 :
1851 0 : m->m_len = m->m_pkthdr.len = MCLBYTES;
1852 :
1853 0 : return (m);
1854 0 : }
1855 :
1856 : void
1857 0 : bwfm_rx(struct bwfm_softc *sc, struct mbuf *m)
1858 : {
1859 0 : struct ieee80211com *ic = &sc->sc_ic;
1860 0 : struct ifnet *ifp = &ic->ic_if;
1861 0 : struct mbuf_list ml = MBUF_LIST_INITIALIZER();
1862 : struct ieee80211_node *ni;
1863 : struct bwfm_event *e;
1864 :
1865 : #ifdef __STRICT_ALIGNMENT
1866 : /* Remaining data is an ethernet packet, so align. */
1867 : if ((mtod(m, paddr_t) & 0x3) != ETHER_ALIGN) {
1868 : struct mbuf *m0;
1869 : m0 = m_dup_pkt(m, ETHER_ALIGN, M_WAITOK);
1870 : m_freem(m);
1871 : if (m0 == NULL) {
1872 : ifp->if_ierrors++;
1873 : return;
1874 : }
1875 : m = m0;
1876 : }
1877 : #endif
1878 :
1879 0 : e = mtod(m, struct bwfm_event *);
1880 0 : if (m->m_len >= sizeof(e->ehdr) &&
1881 0 : ntohs(e->ehdr.ether_type) == BWFM_ETHERTYPE_LINK_CTL &&
1882 0 : memcmp(BWFM_BRCM_OUI, e->hdr.oui, sizeof(e->hdr.oui)) == 0 &&
1883 0 : ntohs(e->hdr.usr_subtype) == BWFM_BRCM_SUBTYPE_EVENT) {
1884 0 : bwfm_rx_event(sc, m);
1885 0 : return;
1886 : }
1887 :
1888 : /* Drop network packets if we are not in RUN state. */
1889 0 : if (ic->ic_state != IEEE80211_S_RUN) {
1890 0 : m_freem(m);
1891 0 : return;
1892 : }
1893 :
1894 0 : if ((ic->ic_flags & IEEE80211_F_RSNON) &&
1895 0 : m->m_len >= sizeof(e->ehdr) &&
1896 0 : ntohs(e->ehdr.ether_type) == ETHERTYPE_PAE) {
1897 0 : ifp->if_ipackets++;
1898 : #if NBPFILTER > 0
1899 0 : if (ifp->if_bpf)
1900 0 : bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
1901 : #endif
1902 : #ifndef IEEE80211_STA_ONLY
1903 0 : if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
1904 0 : ni = ieee80211_find_node(ic,
1905 0 : (void *)&e->ehdr.ether_shost);
1906 0 : if (ni == NULL) {
1907 0 : m_free(m);
1908 0 : return;
1909 : }
1910 : } else
1911 : #endif
1912 0 : ni = ic->ic_bss;
1913 0 : ieee80211_eapol_key_input(ic, m, ni);
1914 0 : } else {
1915 0 : ml_enqueue(&ml, m);
1916 0 : if_input(ifp, &ml);
1917 : }
1918 0 : }
1919 :
1920 : #ifndef IEEE80211_STA_ONLY
1921 : void
1922 0 : bwfm_rx_auth_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len)
1923 : {
1924 0 : struct ieee80211com *ic = &sc->sc_ic;
1925 0 : struct ifnet *ifp = &ic->ic_if;
1926 0 : struct ieee80211_rxinfo rxi;
1927 : struct ieee80211_frame *wh;
1928 : struct mbuf *m;
1929 : uint32_t pktlen, ieslen;
1930 :
1931 : /* Build a fake beacon frame to let net80211 do all the parsing. */
1932 0 : ieslen = betoh32(e->msg.datalen);
1933 0 : pktlen = sizeof(*wh) + ieslen + 6;
1934 0 : if (pktlen > MCLBYTES)
1935 0 : return;
1936 0 : m = bwfm_newbuf();
1937 0 : if (m == NULL)
1938 0 : return;
1939 0 : wh = mtod(m, struct ieee80211_frame *);
1940 0 : wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
1941 : IEEE80211_FC0_SUBTYPE_AUTH;
1942 0 : wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
1943 0 : *(uint16_t *)wh->i_dur = 0;
1944 0 : IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
1945 0 : IEEE80211_ADDR_COPY(wh->i_addr2, &e->msg.addr);
1946 0 : IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid);
1947 0 : *(uint16_t *)wh->i_seq = 0;
1948 0 : ((uint16_t *)(&wh[1]))[0] = IEEE80211_AUTH_ALG_OPEN;
1949 0 : ((uint16_t *)(&wh[1]))[1] = IEEE80211_AUTH_OPEN_REQUEST;
1950 0 : ((uint16_t *)(&wh[1]))[2] = 0;
1951 :
1952 : /* Finalize mbuf. */
1953 0 : m->m_pkthdr.len = m->m_len = pktlen;
1954 0 : rxi.rxi_flags = 0;
1955 0 : rxi.rxi_rssi = 0;
1956 0 : rxi.rxi_tstamp = 0;
1957 0 : ieee80211_input(ifp, m, ic->ic_bss, &rxi);
1958 0 : }
1959 :
1960 : void
1961 0 : bwfm_rx_assoc_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len,
1962 : int reassoc)
1963 : {
1964 0 : struct ieee80211com *ic = &sc->sc_ic;
1965 0 : struct ifnet *ifp = &ic->ic_if;
1966 0 : struct ieee80211_rxinfo rxi;
1967 : struct ieee80211_frame *wh;
1968 : struct ieee80211_node *ni;
1969 : struct mbuf *m;
1970 : uint32_t pktlen, ieslen;
1971 :
1972 : /* Build a fake beacon frame to let net80211 do all the parsing. */
1973 0 : ieslen = betoh32(e->msg.datalen);
1974 0 : pktlen = sizeof(*wh) + ieslen + 4;
1975 0 : if (reassoc)
1976 0 : pktlen += IEEE80211_ADDR_LEN;
1977 0 : if (pktlen > MCLBYTES)
1978 0 : return;
1979 0 : m = bwfm_newbuf();
1980 0 : if (m == NULL)
1981 0 : return;
1982 0 : wh = mtod(m, struct ieee80211_frame *);
1983 0 : wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT;
1984 0 : if (reassoc)
1985 0 : wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_REASSOC_REQ;
1986 : else
1987 0 : wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_ASSOC_REQ;
1988 0 : wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
1989 0 : *(uint16_t *)wh->i_dur = 0;
1990 0 : IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
1991 0 : IEEE80211_ADDR_COPY(wh->i_addr2, &e->msg.addr);
1992 0 : IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid);
1993 0 : *(uint16_t *)wh->i_seq = 0;
1994 0 : ((uint16_t *)(&wh[1]))[0] = IEEE80211_CAPINFO_ESS; /* XXX */
1995 0 : ((uint16_t *)(&wh[1]))[1] = 100; /* XXX */
1996 0 : if (reassoc) {
1997 0 : memset(((uint8_t *)&wh[1]) + 4, 0, IEEE80211_ADDR_LEN);
1998 0 : memcpy(((uint8_t *)&wh[1]) + 4 + IEEE80211_ADDR_LEN,
1999 : &e[1], ieslen);
2000 0 : } else
2001 0 : memcpy(((uint8_t *)&wh[1]) + 4, &e[1], ieslen);
2002 :
2003 : /* Finalize mbuf. */
2004 0 : m->m_pkthdr.len = m->m_len = pktlen;
2005 0 : ni = ieee80211_find_node(ic, wh->i_addr2);
2006 0 : if (ni == NULL) {
2007 0 : m_free(m);
2008 0 : return;
2009 : }
2010 0 : rxi.rxi_flags = 0;
2011 0 : rxi.rxi_rssi = 0;
2012 0 : rxi.rxi_tstamp = 0;
2013 0 : ieee80211_input(ifp, m, ni, &rxi);
2014 0 : }
2015 :
2016 : void
2017 0 : bwfm_rx_deauth_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len)
2018 : {
2019 0 : bwfm_rx_leave_ind(sc, e, len, IEEE80211_FC0_SUBTYPE_DEAUTH);
2020 0 : }
2021 :
2022 : void
2023 0 : bwfm_rx_disassoc_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len)
2024 : {
2025 0 : bwfm_rx_leave_ind(sc, e, len, IEEE80211_FC0_SUBTYPE_DISASSOC);
2026 0 : }
2027 :
2028 : void
2029 0 : bwfm_rx_leave_ind(struct bwfm_softc *sc, struct bwfm_event *e, size_t len,
2030 : int subtype)
2031 : {
2032 0 : struct ieee80211com *ic = &sc->sc_ic;
2033 0 : struct ifnet *ifp = &ic->ic_if;
2034 0 : struct ieee80211_rxinfo rxi;
2035 : struct ieee80211_frame *wh;
2036 : struct ieee80211_node *ni;
2037 : struct mbuf *m;
2038 : uint32_t pktlen;
2039 :
2040 : /* Build a fake beacon frame to let net80211 do all the parsing. */
2041 : pktlen = sizeof(*wh) + 2;
2042 0 : if (pktlen > MCLBYTES)
2043 0 : return;
2044 0 : m = bwfm_newbuf();
2045 0 : if (m == NULL)
2046 0 : return;
2047 0 : wh = mtod(m, struct ieee80211_frame *);
2048 0 : wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
2049 : subtype;
2050 0 : wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
2051 0 : *(uint16_t *)wh->i_dur = 0;
2052 0 : IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
2053 0 : IEEE80211_ADDR_COPY(wh->i_addr2, &e->msg.addr);
2054 0 : IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid);
2055 0 : *(uint16_t *)wh->i_seq = 0;
2056 0 : memset((uint8_t *)&wh[1], 0, 2);
2057 :
2058 : /* Finalize mbuf. */
2059 0 : m->m_pkthdr.len = m->m_len = pktlen;
2060 0 : ni = ieee80211_find_node(ic, wh->i_addr2);
2061 0 : if (ni == NULL) {
2062 0 : m_free(m);
2063 0 : return;
2064 : }
2065 0 : rxi.rxi_flags = 0;
2066 0 : rxi.rxi_rssi = 0;
2067 0 : rxi.rxi_tstamp = 0;
2068 0 : ieee80211_input(ifp, m, ni, &rxi);
2069 0 : }
2070 : #endif
2071 :
2072 : void
2073 0 : bwfm_rx_event(struct bwfm_softc *sc, struct mbuf *m)
2074 : {
2075 0 : struct bwfm_cmd_mbuf cmd;
2076 :
2077 0 : cmd.m = m;
2078 0 : bwfm_do_async(sc, bwfm_rx_event_cb, &cmd, sizeof(cmd));
2079 0 : }
2080 :
2081 : void
2082 0 : bwfm_rx_event_cb(struct bwfm_softc *sc, void *arg)
2083 : {
2084 0 : struct ieee80211com *ic = &sc->sc_ic;
2085 0 : struct ifnet *ifp = &ic->ic_if;
2086 0 : struct bwfm_cmd_mbuf *cmd = arg;
2087 0 : struct mbuf *m = cmd->m;
2088 0 : struct bwfm_event *e = mtod(m, void *);
2089 0 : size_t len = m->m_len;
2090 :
2091 0 : if (ntohl(e->msg.event_type) >= BWFM_E_LAST) {
2092 0 : m_freem(m);
2093 0 : return;
2094 : }
2095 :
2096 0 : switch (ntohl(e->msg.event_type)) {
2097 : case BWFM_E_ESCAN_RESULT: {
2098 : struct bwfm_escan_results *res;
2099 : struct bwfm_bss_info *bss;
2100 : size_t reslen;
2101 : int i;
2102 0 : if (ntohl(e->msg.status) != BWFM_E_STATUS_PARTIAL &&
2103 0 : ic->ic_state == IEEE80211_S_SCAN) {
2104 0 : ieee80211_end_scan(ifp);
2105 0 : break;
2106 : }
2107 0 : len -= sizeof(*e);
2108 0 : if (len < sizeof(*res)) {
2109 : DPRINTF(("%s: results too small\n", DEVNAME(sc)));
2110 0 : m_freem(m);
2111 0 : return;
2112 : }
2113 : reslen = len;
2114 0 : res = malloc(len, M_TEMP, M_WAITOK);
2115 0 : memcpy(res, (void *)&e[1], len);
2116 0 : if (len < letoh32(res->buflen)) {
2117 : DPRINTF(("%s: results too small\n", DEVNAME(sc)));
2118 0 : free(res, M_TEMP, reslen);
2119 0 : m_freem(m);
2120 0 : return;
2121 : }
2122 0 : len -= sizeof(*res);
2123 0 : if (len < letoh16(res->bss_count) * sizeof(struct bwfm_bss_info)) {
2124 : DPRINTF(("%s: results too small\n", DEVNAME(sc)));
2125 0 : free(res, M_TEMP, reslen);
2126 0 : m_freem(m);
2127 0 : return;
2128 : }
2129 0 : bss = &res->bss_info[0];
2130 0 : for (i = 0; i < letoh16(res->bss_count); i++) {
2131 0 : bwfm_scan_node(sc, &res->bss_info[i], len);
2132 0 : len -= sizeof(*bss) + letoh32(bss->length);
2133 0 : bss = (void *)((char *)bss) + letoh32(bss->length);
2134 0 : if (len <= 0)
2135 : break;
2136 : }
2137 0 : free(res, M_TEMP, reslen);
2138 0 : break;
2139 : }
2140 : case BWFM_E_SET_SSID:
2141 0 : if (ntohl(e->msg.status) != BWFM_E_STATUS_SUCCESS)
2142 0 : ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2143 : break;
2144 : case BWFM_E_AUTH:
2145 0 : if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS &&
2146 0 : ic->ic_state == IEEE80211_S_AUTH)
2147 0 : ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1);
2148 : else
2149 0 : ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2150 : break;
2151 : case BWFM_E_ASSOC:
2152 0 : if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS &&
2153 0 : ic->ic_state == IEEE80211_S_ASSOC)
2154 0 : ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
2155 : else
2156 0 : ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2157 : break;
2158 : case BWFM_E_DEAUTH:
2159 : case BWFM_E_DISASSOC:
2160 0 : if (ic->ic_state != IEEE80211_S_INIT)
2161 0 : ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2162 : break;
2163 : case BWFM_E_LINK:
2164 0 : if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS &&
2165 0 : ntohl(e->msg.reason) == 0)
2166 : break;
2167 : /* Link status has changed */
2168 0 : if (ic->ic_state != IEEE80211_S_INIT)
2169 0 : ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2170 : break;
2171 : #ifndef IEEE80211_STA_ONLY
2172 : case BWFM_E_AUTH_IND:
2173 0 : bwfm_rx_auth_ind(sc, e, len);
2174 0 : break;
2175 : case BWFM_E_ASSOC_IND:
2176 0 : bwfm_rx_assoc_ind(sc, e, len, 0);
2177 0 : break;
2178 : case BWFM_E_REASSOC_IND:
2179 0 : bwfm_rx_assoc_ind(sc, e, len, 1);
2180 0 : break;
2181 : case BWFM_E_DEAUTH_IND:
2182 0 : bwfm_rx_deauth_ind(sc, e, len);
2183 0 : break;
2184 : case BWFM_E_DISASSOC_IND:
2185 0 : bwfm_rx_disassoc_ind(sc, e, len);
2186 0 : break;
2187 : #endif
2188 : default:
2189 : DPRINTF(("%s: len %lu datalen %u code %u status %u"
2190 : " reason %u\n", __func__, len, ntohl(e->msg.datalen),
2191 : ntohl(e->msg.event_type), ntohl(e->msg.status),
2192 : ntohl(e->msg.reason)));
2193 : break;
2194 : }
2195 :
2196 0 : m_freem(m);
2197 0 : }
2198 :
2199 : void
2200 0 : bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_info *bss, size_t len)
2201 : {
2202 0 : struct ieee80211com *ic = &sc->sc_ic;
2203 0 : struct ifnet *ifp = &ic->ic_if;
2204 : struct ieee80211_frame *wh;
2205 : struct ieee80211_node *ni;
2206 0 : struct ieee80211_rxinfo rxi;
2207 : struct ieee80211_channel *bss_chan;
2208 : struct mbuf *m;
2209 : uint32_t pktlen, ieslen;
2210 : uint16_t iesoff;
2211 : int chanidx;
2212 :
2213 0 : iesoff = letoh16(bss->ie_offset);
2214 0 : ieslen = letoh32(bss->ie_length);
2215 0 : if (ieslen > len - iesoff)
2216 0 : return;
2217 :
2218 : /* Build a fake beacon frame to let net80211 do all the parsing. */
2219 0 : pktlen = sizeof(*wh) + ieslen + 12;
2220 0 : if (pktlen > MCLBYTES)
2221 0 : return;
2222 0 : m = bwfm_newbuf();
2223 0 : if (m == NULL)
2224 0 : return;
2225 0 : wh = mtod(m, struct ieee80211_frame *);
2226 0 : wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
2227 : IEEE80211_FC0_SUBTYPE_BEACON;
2228 0 : wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
2229 0 : *(uint16_t *)wh->i_dur = 0;
2230 0 : IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
2231 0 : IEEE80211_ADDR_COPY(wh->i_addr2, bss->bssid);
2232 0 : IEEE80211_ADDR_COPY(wh->i_addr3, bss->bssid);
2233 0 : *(uint16_t *)wh->i_seq = 0;
2234 0 : memset(&wh[1], 0, 12);
2235 0 : ((uint16_t *)(&wh[1]))[4] = bss->beacon_period;
2236 0 : ((uint16_t *)(&wh[1]))[5] = bss->capability;
2237 0 : memcpy(((uint8_t *)&wh[1]) + 12, ((uint8_t *)bss) + iesoff, ieslen);
2238 :
2239 : /* Finalize mbuf. */
2240 0 : m->m_pkthdr.len = m->m_len = pktlen;
2241 0 : ni = ieee80211_find_rxnode(ic, wh);
2242 : /*
2243 : * We may switch ic_bss's channel during scans.
2244 : * Record the current channel so we can restore it later.
2245 : */
2246 : bss_chan = NULL;
2247 0 : if (ni == ic->ic_bss)
2248 0 : bss_chan = ni->ni_chan;
2249 : /* Channel mask equals IEEE80211_CHAN_MAX */
2250 0 : chanidx = bwfm_spec2chan(sc, letoh32(bss->chanspec));
2251 0 : ni->ni_chan = &ic->ic_channels[chanidx];
2252 : /* Supply RSSI */
2253 0 : rxi.rxi_flags = 0;
2254 0 : rxi.rxi_rssi = letoh32(bss->rssi);
2255 0 : rxi.rxi_tstamp = 0;
2256 0 : ieee80211_input(ifp, m, ni, &rxi);
2257 : /* Restore channel */
2258 0 : if (bss_chan)
2259 0 : ni->ni_chan = bss_chan;
2260 : /* Node is no longer needed. */
2261 0 : ieee80211_release_node(ic, ni);
2262 0 : }
2263 :
2264 : void
2265 0 : bwfm_task(void *arg)
2266 : {
2267 0 : struct bwfm_softc *sc = arg;
2268 0 : struct bwfm_host_cmd_ring *ring = &sc->sc_cmdq;
2269 : struct bwfm_host_cmd *cmd;
2270 : int s;
2271 :
2272 0 : s = splsoftnet();
2273 0 : while (ring->next != ring->cur) {
2274 0 : cmd = &ring->cmd[ring->next];
2275 0 : splx(s);
2276 0 : cmd->cb(sc, cmd->data);
2277 0 : s = splsoftnet();
2278 0 : ring->queued--;
2279 0 : ring->next = (ring->next + 1) % BWFM_HOST_CMD_RING_COUNT;
2280 : }
2281 0 : splx(s);
2282 0 : }
2283 :
2284 : void
2285 0 : bwfm_do_async(struct bwfm_softc *sc,
2286 : void (*cb)(struct bwfm_softc *, void *), void *arg, int len)
2287 : {
2288 0 : struct bwfm_host_cmd_ring *ring = &sc->sc_cmdq;
2289 : struct bwfm_host_cmd *cmd;
2290 : int s;
2291 :
2292 0 : s = splsoftnet();
2293 0 : if (ring->queued >= BWFM_HOST_CMD_RING_COUNT) {
2294 0 : splx(s);
2295 0 : return;
2296 : }
2297 0 : cmd = &ring->cmd[ring->cur];
2298 0 : cmd->cb = cb;
2299 0 : KASSERT(len <= sizeof(cmd->data));
2300 0 : memcpy(cmd->data, arg, len);
2301 0 : ring->cur = (ring->cur + 1) % BWFM_HOST_CMD_RING_COUNT;
2302 0 : ring->queued++;
2303 0 : task_add(sc->sc_taskq, &sc->sc_task);
2304 0 : splx(s);
2305 0 : }
2306 :
2307 : int
2308 0 : bwfm_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
2309 : int type, int arg1, int arg2)
2310 : {
2311 : #ifdef BWFM_DEBUG
2312 : struct bwfm_softc *sc = ic->ic_softc;
2313 : DPRINTF(("%s: %s\n", DEVNAME(sc), __func__));
2314 : #endif
2315 0 : return 0;
2316 : }
2317 :
2318 : int
2319 0 : bwfm_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
2320 : struct ieee80211_key *k)
2321 : {
2322 0 : struct bwfm_softc *sc = ic->ic_softc;
2323 0 : struct bwfm_cmd_key cmd;
2324 :
2325 0 : cmd.ni = ni;
2326 0 : cmd.k = k;
2327 0 : bwfm_do_async(sc, bwfm_set_key_cb, &cmd, sizeof(cmd));
2328 0 : return 0;
2329 0 : }
2330 :
2331 : void
2332 0 : bwfm_set_key_cb(struct bwfm_softc *sc, void *arg)
2333 : {
2334 0 : struct bwfm_cmd_key *cmd = arg;
2335 0 : struct ieee80211_key *k = cmd->k;
2336 0 : struct ieee80211_node *ni = cmd->ni;
2337 0 : struct bwfm_wsec_key key;
2338 0 : uint32_t wsec, wsec_enable;
2339 : int ext_key = 0;
2340 :
2341 0 : if ((k->k_flags & IEEE80211_KEY_GROUP) == 0 &&
2342 0 : k->k_cipher != IEEE80211_CIPHER_WEP40 &&
2343 0 : k->k_cipher != IEEE80211_CIPHER_WEP104)
2344 0 : ext_key = 1;
2345 :
2346 0 : memset(&key, 0, sizeof(key));
2347 0 : if (ext_key && !IEEE80211_IS_MULTICAST(ni->ni_macaddr))
2348 0 : memcpy(key.ea, ni->ni_macaddr, sizeof(key.ea));
2349 0 : key.index = htole32(k->k_id);
2350 0 : key.len = htole32(k->k_len);
2351 0 : memcpy(key.data, k->k_key, sizeof(key.data));
2352 0 : if (!ext_key)
2353 0 : key.flags = htole32(BWFM_WSEC_PRIMARY_KEY);
2354 :
2355 0 : switch (k->k_cipher) {
2356 : case IEEE80211_CIPHER_WEP40:
2357 0 : key.algo = htole32(BWFM_CRYPTO_ALGO_WEP1);
2358 : wsec_enable = BWFM_WSEC_WEP;
2359 0 : break;
2360 : case IEEE80211_CIPHER_WEP104:
2361 0 : key.algo = htole32(BWFM_CRYPTO_ALGO_WEP128);
2362 : wsec_enable = BWFM_WSEC_WEP;
2363 0 : break;
2364 : case IEEE80211_CIPHER_TKIP:
2365 0 : key.algo = htole32(BWFM_CRYPTO_ALGO_TKIP);
2366 : wsec_enable = BWFM_WSEC_TKIP;
2367 0 : break;
2368 : case IEEE80211_CIPHER_CCMP:
2369 0 : key.algo = htole32(BWFM_CRYPTO_ALGO_AES_CCM);
2370 : wsec_enable = BWFM_WSEC_AES;
2371 0 : break;
2372 : default:
2373 0 : printf("%s: cipher %x not supported\n", DEVNAME(sc),
2374 : k->k_cipher);
2375 0 : return;
2376 : }
2377 :
2378 0 : bwfm_fwvar_var_set_data(sc, "wsec_key", &key, sizeof(key));
2379 0 : bwfm_fwvar_var_get_int(sc, "wsec", &wsec);
2380 0 : wsec |= wsec_enable;
2381 0 : bwfm_fwvar_var_set_int(sc, "wsec", wsec);
2382 0 : }
2383 :
2384 : void
2385 0 : bwfm_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
2386 : struct ieee80211_key *k)
2387 : {
2388 0 : struct bwfm_softc *sc = ic->ic_softc;
2389 0 : struct bwfm_cmd_key cmd;
2390 :
2391 0 : cmd.ni = ni;
2392 0 : cmd.k = k;
2393 0 : bwfm_do_async(sc, bwfm_delete_key_cb, &cmd, sizeof(cmd));
2394 0 : }
2395 :
2396 : void
2397 0 : bwfm_delete_key_cb(struct bwfm_softc *sc, void *arg)
2398 : {
2399 0 : struct bwfm_cmd_key *cmd = arg;
2400 0 : struct ieee80211_key *k = cmd->k;
2401 0 : struct bwfm_wsec_key key;
2402 :
2403 0 : memset(&key, 0, sizeof(key));
2404 0 : key.index = htole32(k->k_id);
2405 0 : key.flags = htole32(BWFM_WSEC_PRIMARY_KEY);
2406 0 : bwfm_fwvar_var_set_data(sc, "wsec_key", &key, sizeof(key));
2407 0 : }
2408 :
2409 : int
2410 0 : bwfm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
2411 : {
2412 0 : struct bwfm_softc *sc = ic->ic_softc;
2413 : struct ifnet *ifp = &ic->ic_if;
2414 : int s;
2415 :
2416 0 : s = splnet();
2417 :
2418 0 : switch (nstate) {
2419 : case IEEE80211_S_SCAN:
2420 : #ifndef IEEE80211_STA_ONLY
2421 : /* Don't start a scan if we already have a channel. */
2422 0 : if (ic->ic_state == IEEE80211_S_INIT &&
2423 0 : ic->ic_opmode == IEEE80211_M_HOSTAP &&
2424 0 : ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
2425 : break;
2426 : }
2427 : #endif
2428 0 : bwfm_scan(sc);
2429 0 : if (ifp->if_flags & IFF_DEBUG)
2430 0 : printf("%s: %s -> %s\n", DEVNAME(sc),
2431 0 : ieee80211_state_name[ic->ic_state],
2432 0 : ieee80211_state_name[nstate]);
2433 0 : ieee80211_set_link_state(ic, LINK_STATE_DOWN);
2434 0 : ieee80211_free_allnodes(ic, 1);
2435 0 : ic->ic_state = nstate;
2436 0 : splx(s);
2437 0 : return 0;
2438 : case IEEE80211_S_AUTH:
2439 0 : ic->ic_bss->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE;
2440 0 : bwfm_connect(sc);
2441 0 : if (ifp->if_flags & IFF_DEBUG)
2442 0 : printf("%s: %s -> %s\n", DEVNAME(sc),
2443 0 : ieee80211_state_name[ic->ic_state],
2444 0 : ieee80211_state_name[nstate]);
2445 0 : ic->ic_state = nstate;
2446 0 : if (ic->ic_flags & IEEE80211_F_RSNON)
2447 0 : ic->ic_bss->ni_rsn_supp_state = RSNA_SUPP_PTKSTART;
2448 0 : splx(s);
2449 0 : return 0;
2450 : #ifndef IEEE80211_STA_ONLY
2451 : case IEEE80211_S_RUN:
2452 0 : if (ic->ic_opmode == IEEE80211_M_HOSTAP)
2453 0 : bwfm_hostap(sc);
2454 : break;
2455 : #endif
2456 : default:
2457 : break;
2458 : }
2459 0 : sc->sc_newstate(ic, nstate, arg);
2460 0 : splx(s);
2461 0 : return 0;
2462 0 : }
|