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