bwfm.c revision 1.31 1 /* $NetBSD: bwfm.c,v 1.31 2021/06/16 00:21:18 riastradh Exp $ */
2 /* $OpenBSD: bwfm.c,v 1.5 2017/10/16 22:27:16 patrick Exp $ */
3 /*
4 * Copyright (c) 2010-2016 Broadcom Corporation
5 * Copyright (c) 2016,2017 Patrick Wildt <patrick (at) blueri.se>
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <sys/param.h>
21 #include <sys/types.h>
22
23 #include <sys/buf.h>
24 #include <sys/device.h>
25 #include <sys/kernel.h>
26 #include <sys/kmem.h>
27 #include <sys/pool.h>
28 #include <sys/queue.h>
29 #include <sys/socket.h>
30 #include <sys/systm.h>
31 #include <sys/workqueue.h>
32
33 #include <net/bpf.h>
34 #include <net/if.h>
35 #include <net/if_dl.h>
36 #include <net/if_ether.h>
37 #include <net/if_media.h>
38
39 #include <netinet/in.h>
40
41 #include <net80211/ieee80211_var.h>
42
43 #include <dev/firmload.h>
44
45 #include <dev/ic/bwfmreg.h>
46 #include <dev/ic/bwfmvar.h>
47
48 /* #define BWFM_DEBUG */
49 #ifdef BWFM_DEBUG
50 #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0)
51 #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0)
52 static int bwfm_debug = 1;
53 #else
54 #define DPRINTF(x) do { ; } while (0)
55 #define DPRINTFN(n, x) do { ; } while (0)
56 #endif
57
58 #define DEVNAME(sc) device_xname((sc)->sc_dev)
59
60 void bwfm_start(struct ifnet *);
61 int bwfm_init(struct ifnet *);
62 void bwfm_stop(struct ifnet *, int);
63 void bwfm_watchdog(struct ifnet *);
64 int bwfm_ioctl(struct ifnet *, u_long, void *);
65 int bwfm_media_change(struct ifnet *);
66
67 int bwfm_send_mgmt(struct ieee80211com *, struct ieee80211_node *,
68 int, int);
69 void bwfm_recv_mgmt(struct ieee80211com *, struct mbuf *,
70 struct ieee80211_node *, int, int, uint32_t);
71 int bwfm_key_set(struct ieee80211com *, const struct ieee80211_key *,
72 const uint8_t *);
73 int bwfm_key_delete(struct ieee80211com *, const struct ieee80211_key *);
74 int bwfm_newstate(struct ieee80211com *, enum ieee80211_state, int);
75 void bwfm_newstate_cb(struct bwfm_softc *, struct bwfm_cmd_newstate *);
76 void bwfm_newassoc(struct ieee80211_node *, int);
77 void bwfm_task(struct work *, void *);
78
79 int bwfm_chip_attach(struct bwfm_softc *);
80 int bwfm_chip_detach(struct bwfm_softc *, int);
81 struct bwfm_core *bwfm_chip_get_core(struct bwfm_softc *, int);
82 struct bwfm_core *bwfm_chip_get_pmu(struct bwfm_softc *);
83 int bwfm_chip_ai_isup(struct bwfm_softc *, struct bwfm_core *);
84 void bwfm_chip_ai_disable(struct bwfm_softc *, struct bwfm_core *,
85 uint32_t, uint32_t);
86 void bwfm_chip_ai_reset(struct bwfm_softc *, struct bwfm_core *,
87 uint32_t, uint32_t, uint32_t);
88 void bwfm_chip_dmp_erom_scan(struct bwfm_softc *);
89 int bwfm_chip_dmp_get_regaddr(struct bwfm_softc *, uint32_t *,
90 uint32_t *, uint32_t *);
91 int bwfm_chip_cr4_set_active(struct bwfm_softc *, const uint32_t);
92 void bwfm_chip_cr4_set_passive(struct bwfm_softc *);
93 int bwfm_chip_ca7_set_active(struct bwfm_softc *, const uint32_t);
94 void bwfm_chip_ca7_set_passive(struct bwfm_softc *);
95 int bwfm_chip_cm3_set_active(struct bwfm_softc *);
96 void bwfm_chip_cm3_set_passive(struct bwfm_softc *);
97 void bwfm_chip_socram_ramsize(struct bwfm_softc *, struct bwfm_core *);
98 void bwfm_chip_sysmem_ramsize(struct bwfm_softc *, struct bwfm_core *);
99 void bwfm_chip_tcm_ramsize(struct bwfm_softc *, struct bwfm_core *);
100 void bwfm_chip_tcm_rambase(struct bwfm_softc *);
101
102 int bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *, int,
103 int, char *, size_t *);
104 int bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *, int,
105 int, char *, size_t);
106
107 int bwfm_fwvar_cmd_get_data(struct bwfm_softc *, int, void *, size_t);
108 int bwfm_fwvar_cmd_set_data(struct bwfm_softc *, int, void *, size_t);
109 int bwfm_fwvar_cmd_get_int(struct bwfm_softc *, int, uint32_t *);
110 int bwfm_fwvar_cmd_set_int(struct bwfm_softc *, int, uint32_t);
111 int bwfm_fwvar_var_get_data(struct bwfm_softc *, const char *, void *, size_t);
112 int bwfm_fwvar_var_set_data(struct bwfm_softc *, const char *, void *, size_t);
113 int bwfm_fwvar_var_get_int(struct bwfm_softc *, const char *, uint32_t *);
114 int bwfm_fwvar_var_set_int(struct bwfm_softc *, const char *, uint32_t);
115
116 struct ieee80211_channel *bwfm_bss2chan(struct bwfm_softc *, struct bwfm_bss_info *);
117 void bwfm_scan(struct bwfm_softc *);
118 void bwfm_connect(struct bwfm_softc *);
119 void bwfm_get_sta_info(struct bwfm_softc *, struct ifmediareq *);
120
121 void bwfm_rx(struct bwfm_softc *, struct mbuf *);
122 void bwfm_rx_event(struct bwfm_softc *, struct mbuf *);
123 void bwfm_rx_event_cb(struct bwfm_softc *, struct mbuf *);
124 void bwfm_scan_node(struct bwfm_softc *, struct bwfm_bss_info *, size_t);
125
126 static const uint8_t bwfm_2ghz_channels[] = {
127 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
128 };
129 static const uint8_t bwfm_5ghz_channels[] = {
130 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, 100, 104, 108, 112,
131 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165,
132 };
133
134 const struct bwfm_proto_ops bwfm_proto_bcdc_ops = {
135 .proto_query_dcmd = bwfm_proto_bcdc_query_dcmd,
136 .proto_set_dcmd = bwfm_proto_bcdc_set_dcmd,
137 };
138
139 static const struct {
140 const char *suffix;
141 const char *description;
142 } bwfm_firmware_filetypes[] = {
143 [BWFM_FILETYPE_UCODE] = {
144 .suffix = "bin",
145 .description = "Firmware",
146 },
147 [BWFM_FILETYPE_NVRAM] = {
148 .suffix = "txt",
149 .description = "NVRAM",
150 },
151 [BWFM_FILETYPE_CLM] = {
152 .suffix = "clm_blob",
153 .description = "CLM",
154 },
155 };
156
157 static void
158 bwfm_firmware_read_file(struct bwfm_softc * const sc,
159 const struct bwfm_firmware_selector * const fwp,
160 struct bwfm_firmware_context * const ctx,
161 unsigned int const which)
162 {
163 firmware_handle_t fwh;
164 char *names[2];
165 int i, error;
166
167 names[1] = kmem_asprintf("%s.%s", fwp->fwsel_basename,
168 bwfm_firmware_filetypes[which].suffix);
169 names[0] = ctx->ctx_model ? kmem_asprintf("%s.%s.%s",
170 fwp->fwsel_basename, ctx->ctx_model,
171 bwfm_firmware_filetypes[which].suffix) : NULL;
172
173 aprint_verbose_dev(sc->sc_dev, "%s file default: %s\n",
174 bwfm_firmware_filetypes[which].description, names[1]);
175 if (names[0]) {
176 aprint_verbose_dev(sc->sc_dev, "%s file model-spec: %s\n",
177 bwfm_firmware_filetypes[which].description, names[0]);
178 }
179
180 for (i = 0; i < 2; i++) {
181 if (names[i] == NULL)
182 continue;
183 error = firmware_open("if_bwfm", names[i], &fwh);
184 if (error == 0)
185 break;
186 }
187 if (i == 2)
188 goto out;
189
190 aprint_verbose_dev(sc->sc_dev, "Found %s file: %s\n",
191 bwfm_firmware_filetypes[which].description, names[i]);
192
193 size_t size = firmware_get_size(fwh);
194 void *data = firmware_malloc(size);
195 if (data == NULL) {
196 aprint_error_dev(sc->sc_dev,
197 "unable to allocate %zu bytes for %s image\n", size,
198 bwfm_firmware_filetypes[which].description);
199 firmware_close(fwh);
200 goto out;
201 }
202 error = firmware_read(fwh, 0, data, size);
203 firmware_close(fwh);
204 if (error) {
205 aprint_error_dev(sc->sc_dev,
206 "failed to read %s file, error %d\n",
207 bwfm_firmware_filetypes[which].description,
208 error);
209 firmware_free(data, size);
210 goto out;
211 }
212
213 ctx->ctx_file[which].ctx_f_data = data;
214 ctx->ctx_file[which].ctx_f_size = size;
215 out:
216 for (i = 0; i < 2; i++) {
217 if (names[i])
218 kmem_free(names[i], strlen(names[i])+1);
219 }
220 }
221
222 void
223 bwfm_firmware_context_init(struct bwfm_firmware_context * const ctx,
224 uint32_t const chip, uint32_t const chiprev, const char * const model,
225 uint32_t req)
226 {
227 memset(ctx, 0, sizeof(*ctx));
228 ctx->ctx_chip = chip;
229 ctx->ctx_chiprev = chiprev;
230 ctx->ctx_model = model;
231
232 /* all devices require ucode */
233 ctx->ctx_req = req | BWFM_FWREQ(BWFM_FILETYPE_UCODE);
234 }
235
236 bool
237 bwfm_firmware_open(struct bwfm_softc * const sc,
238 const struct bwfm_firmware_selector * const fwtab,
239 struct bwfm_firmware_context * const ctx)
240 {
241 const struct bwfm_firmware_selector *fwp;
242 unsigned int i;
243
244 KASSERT(fwtab != NULL);
245 KASSERT(ctx != NULL);
246
247 /* First locate the appropriate entry for this chip / rev. */
248 for (fwp = fwtab; fwp->fwsel_basename != NULL; fwp++) {
249 if (fwp->fwsel_chip == ctx->ctx_chip &&
250 fwp->fwsel_revmask & __BIT(ctx->ctx_chiprev))
251 break;
252 }
253 if (fwp->fwsel_basename == NULL) {
254 aprint_error_dev(sc->sc_dev,
255 "No firmware entry for chip 0x%x/%u rev %u model %s\n",
256 ctx->ctx_chip, ctx->ctx_chip, ctx->ctx_chiprev,
257 ctx->ctx_model);
258 return false;
259 }
260
261 bool rv = true;
262
263 /*
264 * Read in each file that the front-end has requested as
265 * either required or optional.
266 */
267 for (i = 0; i < BWFM_NFILETYPES; i++) {
268 if (ctx->ctx_req & (BWFM_FWREQ(i) | BWFM_FWOPT(i)))
269 bwfm_firmware_read_file(sc, fwp, ctx, i);
270 if ((ctx->ctx_req & BWFM_FWREQ(i)) &&
271 ctx->ctx_file[i].ctx_f_data == NULL) {
272 aprint_error_dev(sc->sc_dev,
273 "%s file not available\n",
274 bwfm_firmware_filetypes[i].description);
275 rv = false;
276 }
277 }
278
279 if (rv == false)
280 bwfm_firmware_close(ctx);
281
282 return rv;
283 }
284
285 void
286 bwfm_firmware_close(struct bwfm_firmware_context * const ctx)
287 {
288 for (int i = 0; i < BWFM_NFILETYPES; i++) {
289 if (ctx->ctx_file[i].ctx_f_data == NULL)
290 continue;
291 firmware_free(ctx->ctx_file[i].ctx_f_data,
292 ctx->ctx_file[i].ctx_f_size);
293 ctx->ctx_file[i].ctx_f_data = NULL;
294 }
295 }
296
297 void *
298 bwfm_firmware_data(struct bwfm_firmware_context * const ctx,
299 unsigned int const which, size_t *sizep)
300 {
301 KASSERT(which < BWFM_NFILETYPES);
302 KASSERT(sizep != NULL);
303
304 *sizep = ctx->ctx_file[which].ctx_f_size;
305 return ctx->ctx_file[which].ctx_f_data;
306 }
307
308 const char *
309 bwfm_firmware_description(unsigned int const which)
310 {
311 KASSERT(which < BWFM_NFILETYPES);
312
313 return bwfm_firmware_filetypes[which].description;
314 }
315
316 void
317 bwfm_attach(struct bwfm_softc *sc)
318 {
319 struct ieee80211com *ic = &sc->sc_ic;
320 struct ifnet *ifp = &sc->sc_if;
321 char fw_version[BWFM_DCMD_SMLEN];
322 uint32_t bandlist[3];
323 uint32_t tmp;
324 int i, j, error;
325
326 error = workqueue_create(&sc->sc_taskq, DEVNAME(sc),
327 bwfm_task, sc, PRI_NONE, IPL_NET, 0);
328 if (error != 0) {
329 printf("%s: could not create workqueue\n", DEVNAME(sc));
330 return;
331 }
332 sc->sc_freetask = pool_cache_init(sizeof(struct bwfm_task), 0, 0, 0,
333 "bwfmtask", NULL, IPL_NET /* XXX IPL_SOFTNET? */,
334 NULL, NULL, NULL);
335 pool_cache_prime(sc->sc_freetask, BWFM_TASK_COUNT);
336
337 /* Stop the device in case it was previously initialized */
338 bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1);
339
340 if (bwfm_fwvar_cmd_get_int(sc, BWFM_C_GET_VERSION, &tmp)) {
341 printf("%s: could not read io type\n", DEVNAME(sc));
342 return;
343 } else
344 sc->sc_io_type = tmp;
345 if (bwfm_fwvar_var_get_data(sc, "cur_etheraddr", ic->ic_myaddr,
346 sizeof(ic->ic_myaddr))) {
347 printf("%s: could not read mac address\n", DEVNAME(sc));
348 return;
349 }
350
351 memset(fw_version, 0, sizeof(fw_version));
352 if (bwfm_fwvar_var_get_data(sc, "ver", fw_version, sizeof(fw_version)) == 0)
353 printf("%s: %s", DEVNAME(sc), fw_version);
354 printf("%s: address %s\n", DEVNAME(sc), ether_sprintf(ic->ic_myaddr));
355
356 ic->ic_ifp = ifp;
357 ic->ic_phytype = IEEE80211_T_OFDM;
358 ic->ic_opmode = IEEE80211_M_STA;
359 ic->ic_state = IEEE80211_S_INIT;
360
361 ic->ic_caps =
362 IEEE80211_C_WEP |
363 IEEE80211_C_TKIP |
364 IEEE80211_C_AES |
365 IEEE80211_C_AES_CCM |
366 #if notyet
367 IEEE80211_C_MONITOR | /* monitor mode supported */
368 IEEE80211_C_IBSS |
369 IEEE80211_C_TXPMGT |
370 IEEE80211_C_WME |
371 #endif
372 IEEE80211_C_SHSLOT | /* short slot time supported */
373 IEEE80211_C_SHPREAMBLE | /* short preamble supported */
374 IEEE80211_C_WPA | /* 802.11i */
375 /* IEEE80211_C_WPA_4WAY */0; /* WPA 4-way handshake in hw */
376
377 /* IBSS channel undefined for now. */
378 ic->ic_ibss_chan = &ic->ic_channels[0];
379
380 if (bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_BANDLIST, bandlist,
381 sizeof(bandlist))) {
382 printf("%s: couldn't get supported band list\n", DEVNAME(sc));
383 return;
384 }
385 const u_int nbands = le32toh(bandlist[0]);
386 for (i = 1; i <= MIN(nbands, __arraycount(bandlist) - 1); i++) {
387 switch (le32toh(bandlist[i])) {
388 case BWFM_BAND_2G:
389 ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
390 ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
391
392 for (j = 0; j < __arraycount(bwfm_2ghz_channels); j++) {
393 uint8_t chan = bwfm_2ghz_channels[j];
394 ic->ic_channels[chan].ic_freq =
395 ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ);
396 ic->ic_channels[chan].ic_flags =
397 IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
398 IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
399 }
400 break;
401 case BWFM_BAND_5G:
402 ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a;
403
404 for (j = 0; j < __arraycount(bwfm_5ghz_channels); j++) {
405 uint8_t chan = bwfm_5ghz_channels[j];
406 ic->ic_channels[chan].ic_freq =
407 ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ);
408 ic->ic_channels[chan].ic_flags =
409 IEEE80211_CHAN_A;
410 }
411 break;
412 }
413 }
414
415 ifp->if_softc = sc;
416 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
417 ifp->if_init = bwfm_init;
418 ifp->if_ioctl = bwfm_ioctl;
419 ifp->if_start = bwfm_start;
420 ifp->if_stop = bwfm_stop;
421 ifp->if_watchdog = bwfm_watchdog;
422 IFQ_SET_READY(&ifp->if_snd);
423 memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
424
425 if_initialize(ifp);
426 ieee80211_ifattach(ic);
427 sc->sc_newstate = ic->ic_newstate;
428 ic->ic_newstate = bwfm_newstate;
429 ic->ic_newassoc = bwfm_newassoc;
430 ic->ic_send_mgmt = bwfm_send_mgmt;
431 ic->ic_recv_mgmt = bwfm_recv_mgmt;
432 ic->ic_crypto.cs_key_set = bwfm_key_set;
433 ic->ic_crypto.cs_key_delete = bwfm_key_delete;
434
435 ifp->if_percpuq = if_percpuq_create(ifp);
436 if_deferred_start_init(ifp, NULL);
437 if_register(ifp);
438 ieee80211_media_init(ic, bwfm_media_change, ieee80211_media_status);
439
440 ieee80211_announce(ic);
441
442 sc->sc_if_attached = true;
443 }
444
445 int
446 bwfm_detach(struct bwfm_softc *sc, int flags)
447 {
448 struct ieee80211com *ic = &sc->sc_ic;
449 struct ifnet *ifp = ic->ic_ifp;
450
451 if (sc->sc_if_attached) {
452 bpf_detach(ifp);
453 ieee80211_ifdetach(ic);
454 if_detach(ifp);
455 }
456
457 if (sc->sc_taskq)
458 workqueue_destroy(sc->sc_taskq);
459 if (sc->sc_freetask)
460 pool_cache_destroy(sc->sc_freetask);
461
462 return 0;
463 }
464
465 void
466 bwfm_start(struct ifnet *ifp)
467 {
468 struct bwfm_softc *sc = ifp->if_softc;
469 struct ieee80211com *ic = &sc->sc_ic;
470 struct mbuf *m;
471 int error;
472
473 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
474 return;
475
476 /* TODO: return if no link? */
477
478 for (;;) {
479 /* Discard management packets (fw handles this for us) */
480 IF_DEQUEUE(&ic->ic_mgtq, m);
481 if (m != NULL) {
482 m_freem(m);
483 continue;
484 }
485
486 if (sc->sc_bus_ops->bs_txcheck(sc)) {
487 ifp->if_flags |= IFF_OACTIVE;
488 break;
489 }
490
491 IFQ_DEQUEUE(&ifp->if_snd, m);
492 if (m == NULL)
493 break;
494
495 error = sc->sc_bus_ops->bs_txdata(sc, &m);
496 if (error == ENOBUFS) {
497 IF_PREPEND(&ifp->if_snd, m);
498 ifp->if_flags |= IFF_OACTIVE;
499 break;
500 }
501 if (error != 0) {
502 if_statinc(ifp, if_oerrors);
503 m_freem(m);
504 continue;
505 }
506
507 bpf_mtap(ifp, m, BPF_D_OUT);
508 }
509 }
510
511 int
512 bwfm_init(struct ifnet *ifp)
513 {
514 struct bwfm_softc *sc = ifp->if_softc;
515 struct ieee80211com *ic = &sc->sc_ic;
516 uint8_t evmask[BWFM_EVENT_MASK_LEN];
517 struct bwfm_join_pref_params join_pref[2];
518 int pm;
519
520 if (bwfm_fwvar_var_set_int(sc, "mpc", 1)) {
521 printf("%s: could not set mpc\n", DEVNAME(sc));
522 return EIO;
523 }
524
525 /* Select target by RSSI (boost on 5GHz) */
526 join_pref[0].type = BWFM_JOIN_PREF_RSSI_DELTA;
527 join_pref[0].len = 2;
528 join_pref[0].rssi_gain = BWFM_JOIN_PREF_RSSI_BOOST;
529 join_pref[0].band = BWFM_JOIN_PREF_BAND_5G;
530 join_pref[1].type = BWFM_JOIN_PREF_RSSI;
531 join_pref[1].len = 2;
532 join_pref[1].rssi_gain = 0;
533 join_pref[1].band = 0;
534 if (bwfm_fwvar_var_set_data(sc, "join_pref", join_pref,
535 sizeof(join_pref))) {
536 printf("%s: could not set join pref\n", DEVNAME(sc));
537 return EIO;
538 }
539
540 memset(evmask, 0, sizeof(evmask));
541
542 #define ENABLE_EVENT(e) evmask[(e) / 8] |= 1 << ((e) % 8)
543 /* Events used to drive the state machine */
544 switch (ic->ic_opmode) {
545 case IEEE80211_M_STA:
546 ENABLE_EVENT(BWFM_E_IF);
547 ENABLE_EVENT(BWFM_E_LINK);
548 ENABLE_EVENT(BWFM_E_AUTH);
549 ENABLE_EVENT(BWFM_E_ASSOC);
550 ENABLE_EVENT(BWFM_E_DEAUTH);
551 ENABLE_EVENT(BWFM_E_DISASSOC);
552 ENABLE_EVENT(BWFM_E_SET_SSID);
553 ENABLE_EVENT(BWFM_E_ESCAN_RESULT);
554 break;
555 #ifndef IEEE80211_STA_ONLY
556 case IEEE80211_M_HOSTAP:
557 ENABLE_EVENT(BWFM_E_AUTH_IND);
558 ENABLE_EVENT(BWFM_E_ASSOC_IND);
559 ENABLE_EVENT(BWFM_E_REASSOC_IND);
560 ENABLE_EVENT(BWFM_E_DEAUTH_IND);
561 ENABLE_EVENT(BWFM_E_DISASSOC_IND);
562 ENABLE_EVENT(BWFM_E_ESCAN_RESULT);
563 ENABLE_EVENT(BWFM_E_ESCAN_RESULT);
564 break;
565 #endif
566 default:
567 break;
568 }
569 #undef ENABLE_EVENT
570
571 #ifdef BWFM_DEBUG
572 memset(evmask, 0xff, sizeof(evmask));
573 #endif
574
575 if (bwfm_fwvar_var_set_data(sc, "event_msgs", evmask, sizeof(evmask))) {
576 printf("%s: could not set event mask\n", DEVNAME(sc));
577 return EIO;
578 }
579
580 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_CHANNEL_TIME,
581 BWFM_DEFAULT_SCAN_CHANNEL_TIME)) {
582 printf("%s: could not set scan channel time\n", DEVNAME(sc));
583 return EIO;
584 }
585 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_UNASSOC_TIME,
586 BWFM_DEFAULT_SCAN_UNASSOC_TIME)) {
587 printf("%s: could not set scan unassoc time\n", DEVNAME(sc));
588 return EIO;
589 }
590 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_PASSIVE_TIME,
591 BWFM_DEFAULT_SCAN_PASSIVE_TIME)) {
592 printf("%s: could not set scan passive time\n", DEVNAME(sc));
593 return EIO;
594 }
595
596 /*
597 * Use CAM (constantly awake) when we are running as AP
598 * otherwise use fast power saving.
599 */
600 pm = BWFM_PM_FAST_PS;
601 #ifndef IEEE80211_STA_ONLY
602 if (ic->ic_opmode == IEEE80211_M_HOSTAP)
603 pm = BWFM_PM_CAM;
604 #endif
605 if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, pm)) {
606 printf("%s: could not set power\n", DEVNAME(sc));
607 return EIO;
608 }
609
610 bwfm_fwvar_var_set_int(sc, "txbf", 1);
611 bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 0);
612 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 1);
613 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0);
614
615 /* Disable all offloading (ARP, NDP, TCP/UDP cksum). */
616 bwfm_fwvar_var_set_int(sc, "arp_ol", 0);
617 bwfm_fwvar_var_set_int(sc, "arpoe", 0);
618 bwfm_fwvar_var_set_int(sc, "ndoe", 0);
619 bwfm_fwvar_var_set_int(sc, "toe", 0);
620
621 /* Accept all multicast frames. */
622 bwfm_fwvar_var_set_int(sc, "allmulti", 1);
623
624 /* Setup promiscuous mode */
625 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PROMISC,
626 (ifp->if_flags & IFF_PROMISC) ? 1 : 0);
627
628 /*
629 * Tell the firmware supplicant that we are going to handle the
630 * WPA handshake ourselves.
631 */
632 bwfm_fwvar_var_set_int(sc, "sup_wpa", 0);
633
634 ifp->if_flags |= IFF_RUNNING;
635 ifp->if_flags &= ~IFF_OACTIVE;
636
637 if (ic->ic_opmode != IEEE80211_M_MONITOR) {
638 if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
639 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
640 } else {
641 ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
642 }
643
644 return 0;
645 }
646
647 void
648 bwfm_stop(struct ifnet *ifp, int disable)
649 {
650 struct bwfm_softc *sc = ifp->if_softc;
651 struct ieee80211com *ic = &sc->sc_ic;
652 struct bwfm_join_params join;
653
654 sc->sc_tx_timer = 0;
655 ifp->if_timer = 0;
656 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
657
658 memset(&join, 0, sizeof(join));
659 bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, sizeof(join));
660 bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1);
661 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, 0);
662 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0);
663 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 0);
664 bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 1);
665 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, BWFM_PM_FAST_PS);
666
667 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
668
669 if (sc->sc_bus_ops->bs_stop)
670 sc->sc_bus_ops->bs_stop(sc);
671 }
672
673 void
674 bwfm_watchdog(struct ifnet *ifp)
675 {
676 struct bwfm_softc *sc = ifp->if_softc;
677 struct ieee80211com *ic = &sc->sc_ic;
678
679 ifp->if_timer = 0;
680
681 if (sc->sc_tx_timer > 0) {
682 if (--sc->sc_tx_timer == 0) {
683 printf("%s: device timeout\n", DEVNAME(sc));
684 if_statinc(ifp, if_oerrors);
685 return;
686 }
687 ifp->if_timer = 1;
688 }
689 ieee80211_watchdog(ic);
690 }
691
692 int
693 bwfm_ioctl(struct ifnet *ifp, u_long cmd, void *data)
694 {
695 struct bwfm_softc *sc = ifp->if_softc;
696 struct ieee80211com *ic = &sc->sc_ic;
697 int s, error = 0;
698
699 s = splnet();
700
701 switch (cmd) {
702 case SIOCSIFFLAGS:
703 if ((error = ifioctl_common(ifp, cmd, data)) != 0)
704 break;
705 switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
706 case IFF_UP | IFF_RUNNING:
707 break;
708 case IFF_UP:
709 bwfm_init(ifp);
710 break;
711 case IFF_RUNNING:
712 bwfm_stop(ifp, 1);
713 break;
714 case 0:
715 break;
716 }
717 break;
718
719 case SIOCADDMULTI:
720 case SIOCDELMULTI:
721 if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
722 /* setup multicast filter, etc */
723 error = 0;
724 }
725 break;
726
727 case SIOCGIFMEDIA:
728 error = ieee80211_ioctl(ic, cmd, data);
729 if (error == 0 && ic->ic_state == IEEE80211_S_RUN)
730 bwfm_get_sta_info(sc, (struct ifmediareq *)data);
731 break;
732
733 default:
734 error = ieee80211_ioctl(ic, cmd, data);
735 }
736
737 if (error == ENETRESET) {
738 if ((ifp->if_flags & IFF_UP) != 0 &&
739 (ifp->if_flags & IFF_RUNNING) != 0 &&
740 ic->ic_roaming != IEEE80211_ROAMING_MANUAL) {
741 bwfm_init(ifp);
742 }
743 error = 0;
744 }
745
746 splx(s);
747
748 return error;
749 }
750
751 int
752 bwfm_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
753 int type, int arg)
754 {
755 return 0;
756 }
757
758 void
759 bwfm_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
760 struct ieee80211_node *ni, int subtype, int rssi, uint32_t rstamp)
761 {
762 }
763
764 int
765 bwfm_key_set(struct ieee80211com *ic, const struct ieee80211_key *wk,
766 const uint8_t mac[IEEE80211_ADDR_LEN])
767 {
768 struct bwfm_softc *sc = ic->ic_ifp->if_softc;
769 struct bwfm_task *t;
770
771 t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
772 if (t == NULL) {
773 printf("%s: no free tasks\n", DEVNAME(sc));
774 return 0;
775 }
776
777 t->t_sc = sc;
778 t->t_cmd = BWFM_TASK_KEY_SET;
779 t->t_key.key = wk;
780 memcpy(t->t_key.mac, mac, sizeof(t->t_key.mac));
781 workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL);
782 return 1;
783 }
784
785 static void
786 bwfm_key_set_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck)
787 {
788 const struct ieee80211_key *wk = ck->key;
789 const uint8_t *mac = ck->mac;
790 struct bwfm_wsec_key wsec_key;
791 uint32_t wsec_enable, wsec;
792 bool ext_key;
793
794 #ifdef BWFM_DEBUG
795 printf("key_set: key cipher %s len %d: ", wk->wk_cipher->ic_name, wk->wk_keylen);
796 for (int j = 0; j < sizeof(wk->wk_key); j++)
797 printf("%02x", wk->wk_key[j]);
798 #endif
799
800 if ((wk->wk_flags & IEEE80211_KEY_GROUP) == 0 &&
801 wk->wk_cipher->ic_cipher != IEEE80211_CIPHER_WEP) {
802 ext_key = true;
803 } else {
804 ext_key = false;
805 }
806
807 #ifdef BWFM_DEBUG
808 printf(", ext_key = %d", ext_key);
809 printf(", mac = %02x:%02x:%02x:%02x:%02x:%02x",
810 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
811 printf("\n");
812 #endif
813
814 memset(&wsec_key, 0, sizeof(wsec_key));
815 if (ext_key && !IEEE80211_IS_MULTICAST(mac))
816 memcpy(wsec_key.ea, mac, sizeof(wsec_key.ea));
817 wsec_key.index = htole32(wk->wk_keyix);
818 wsec_key.len = htole32(wk->wk_keylen);
819 memcpy(wsec_key.data, wk->wk_key, sizeof(wsec_key.data));
820 if (!ext_key)
821 wsec_key.flags = htole32(BWFM_WSEC_PRIMARY_KEY);
822
823 switch (wk->wk_cipher->ic_cipher) {
824 case IEEE80211_CIPHER_WEP:
825 if (wk->wk_keylen == 5)
826 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP1);
827 else if (wk->wk_keylen == 13)
828 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP128);
829 else
830 return;
831 wsec_enable = BWFM_WSEC_WEP;
832 break;
833 case IEEE80211_CIPHER_TKIP:
834 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_TKIP);
835 wsec_enable = BWFM_WSEC_TKIP;
836 break;
837 case IEEE80211_CIPHER_AES_CCM:
838 wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_AES_CCM);
839 wsec_enable = BWFM_WSEC_AES;
840 break;
841 default:
842 printf("%s: %s: cipher %s not supported\n", DEVNAME(sc),
843 __func__, wk->wk_cipher->ic_name);
844 return;
845 }
846
847 if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key)))
848 return;
849
850 bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_WPA2_PSK);
851
852 bwfm_fwvar_var_get_int(sc, "wsec", &wsec);
853 wsec |= wsec_enable;
854 bwfm_fwvar_var_set_int(sc, "wsec", wsec);
855 }
856
857 int
858 bwfm_key_delete(struct ieee80211com *ic, const struct ieee80211_key *wk)
859 {
860 struct bwfm_softc *sc = ic->ic_ifp->if_softc;
861 struct bwfm_task *t;
862
863 t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
864 if (t == NULL) {
865 printf("%s: no free tasks\n", DEVNAME(sc));
866 return 0;
867 }
868
869 t->t_sc = sc;
870 t->t_cmd = BWFM_TASK_KEY_DELETE;
871 t->t_key.key = wk;
872 memset(t->t_key.mac, 0, sizeof(t->t_key.mac));
873 workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL);
874
875 return 1;
876 }
877
878 static void
879 bwfm_key_delete_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck)
880 {
881 const struct ieee80211_key *wk = ck->key;
882 struct bwfm_wsec_key wsec_key;
883
884 memset(&wsec_key, 0, sizeof(wsec_key));
885 wsec_key.index = htole32(wk->wk_keyix);
886 wsec_key.flags = htole32(BWFM_WSEC_PRIMARY_KEY);
887
888 if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key)))
889 return;
890 }
891
892 int
893 bwfm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
894 {
895 struct bwfm_softc *sc = ic->ic_ifp->if_softc;
896 struct bwfm_task *t;
897
898 t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
899 if (t == NULL) {
900 printf("%s: no free tasks\n", DEVNAME(sc));
901 return EIO;
902 }
903
904 t->t_sc = sc;
905 t->t_cmd = BWFM_TASK_NEWSTATE;
906 t->t_newstate.state = nstate;
907 t->t_newstate.arg = arg;
908 workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL);
909
910 return 0;
911 }
912
913 void
914 bwfm_newstate_cb(struct bwfm_softc *sc, struct bwfm_cmd_newstate *cmd)
915 {
916 struct ieee80211com *ic = &sc->sc_ic;
917 enum ieee80211_state ostate = ic->ic_state;
918 enum ieee80211_state nstate = cmd->state;
919 int s;
920
921 DPRINTF(("%s: newstate %d -> %d\n", DEVNAME(sc), ostate, nstate));
922
923 s = splnet();
924
925 switch (nstate) {
926 case IEEE80211_S_INIT:
927 break;
928
929 case IEEE80211_S_SCAN:
930 if (ostate != IEEE80211_S_SCAN) {
931 /* Start of scanning */
932 bwfm_scan(sc);
933 }
934 break;
935
936 case IEEE80211_S_AUTH:
937 bwfm_connect(sc);
938 break;
939
940 case IEEE80211_S_ASSOC:
941 break;
942
943 case IEEE80211_S_RUN:
944 break;
945 }
946
947 sc->sc_newstate(ic, nstate, cmd->arg);
948
949 splx(s);
950 }
951
952 void
953 bwfm_newassoc(struct ieee80211_node *ni, int isnew)
954 {
955 /* Firmware handles rate adaptation for us */
956 ni->ni_txrate = 0;
957 }
958
959 void
960 bwfm_task(struct work *wk, void *arg)
961 {
962 struct bwfm_task *t = (struct bwfm_task *)wk;
963 struct bwfm_softc *sc = t->t_sc;
964
965 switch (t->t_cmd) {
966 case BWFM_TASK_NEWSTATE:
967 bwfm_newstate_cb(sc, &t->t_newstate);
968 break;
969 case BWFM_TASK_KEY_SET:
970 bwfm_key_set_cb(sc, &t->t_key);
971 break;
972 case BWFM_TASK_KEY_DELETE:
973 bwfm_key_delete_cb(sc, &t->t_key);
974 break;
975 case BWFM_TASK_RX_EVENT:
976 bwfm_rx_event_cb(sc, t->t_mbuf);
977 break;
978 default:
979 panic("bwfm: unknown task command %d", t->t_cmd);
980 }
981
982 pool_cache_put(sc->sc_freetask, t);
983 }
984
985 int
986 bwfm_media_change(struct ifnet *ifp)
987 {
988 return 0;
989 }
990
991 /* Chip initialization (SDIO, PCIe) */
992 int
993 bwfm_chip_attach(struct bwfm_softc *sc)
994 {
995 struct bwfm_core *core;
996 int need_socram = 0;
997 int has_socram = 0;
998 int cpu_found = 0;
999 uint32_t val;
1000
1001 LIST_INIT(&sc->sc_chip.ch_list);
1002
1003 if (sc->sc_buscore_ops->bc_prepare(sc) != 0) {
1004 printf("%s: failed buscore prepare\n", DEVNAME(sc));
1005 return 1;
1006 }
1007
1008 val = sc->sc_buscore_ops->bc_read(sc,
1009 BWFM_CHIP_BASE + BWFM_CHIP_REG_CHIPID);
1010 sc->sc_chip.ch_chip = BWFM_CHIP_CHIPID_ID(val);
1011 sc->sc_chip.ch_chiprev = BWFM_CHIP_CHIPID_REV(val);
1012
1013 if ((sc->sc_chip.ch_chip > 0xa000) || (sc->sc_chip.ch_chip < 0x4000))
1014 snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name),
1015 "%d", sc->sc_chip.ch_chip);
1016 else
1017 snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name),
1018 "%x", sc->sc_chip.ch_chip);
1019
1020 switch (BWFM_CHIP_CHIPID_TYPE(val))
1021 {
1022 case BWFM_CHIP_CHIPID_TYPE_SOCI_SB:
1023 printf("%s: SoC interconnect SB not implemented\n",
1024 DEVNAME(sc));
1025 return 1;
1026 case BWFM_CHIP_CHIPID_TYPE_SOCI_AI:
1027 sc->sc_chip.ch_core_isup = bwfm_chip_ai_isup;
1028 sc->sc_chip.ch_core_disable = bwfm_chip_ai_disable;
1029 sc->sc_chip.ch_core_reset = bwfm_chip_ai_reset;
1030 bwfm_chip_dmp_erom_scan(sc);
1031 break;
1032 default:
1033 printf("%s: SoC interconnect %d unknown\n",
1034 DEVNAME(sc), BWFM_CHIP_CHIPID_TYPE(val));
1035 return 1;
1036 }
1037
1038 LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) {
1039 DPRINTF(("%s: 0x%x:%-2d base 0x%08x wrap 0x%08x\n",
1040 DEVNAME(sc), core->co_id, core->co_rev,
1041 core->co_base, core->co_wrapbase));
1042
1043 switch (core->co_id) {
1044 case BWFM_AGENT_CORE_ARM_CM3:
1045 need_socram = true;
1046 /* FALLTHROUGH */
1047 case BWFM_AGENT_CORE_ARM_CR4:
1048 case BWFM_AGENT_CORE_ARM_CA7:
1049 cpu_found = true;
1050 break;
1051 case BWFM_AGENT_INTERNAL_MEM:
1052 has_socram = true;
1053 break;
1054 default:
1055 break;
1056 }
1057 }
1058
1059 if (!cpu_found) {
1060 printf("%s: CPU core not detected\n", DEVNAME(sc));
1061 return 1;
1062 }
1063 if (need_socram && !has_socram) {
1064 printf("%s: RAM core not provided\n", DEVNAME(sc));
1065 return 1;
1066 }
1067
1068 bwfm_chip_set_passive(sc);
1069
1070 if (sc->sc_buscore_ops->bc_reset) {
1071 sc->sc_buscore_ops->bc_reset(sc);
1072 bwfm_chip_set_passive(sc);
1073 }
1074
1075 if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4)) != NULL) {
1076 bwfm_chip_tcm_ramsize(sc, core);
1077 bwfm_chip_tcm_rambase(sc);
1078 } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_SYS_MEM)) != NULL) {
1079 bwfm_chip_sysmem_ramsize(sc, core);
1080 bwfm_chip_tcm_rambase(sc);
1081 } else if ((core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM)) != NULL) {
1082 bwfm_chip_socram_ramsize(sc, core);
1083 }
1084
1085 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1086 sc->sc_chip.ch_cc_caps = sc->sc_buscore_ops->bc_read(sc,
1087 core->co_base + BWFM_CHIP_REG_CAPABILITIES);
1088 sc->sc_chip.ch_cc_caps_ext = sc->sc_buscore_ops->bc_read(sc,
1089 core->co_base + BWFM_CHIP_REG_CAPABILITIES_EXT);
1090
1091 core = bwfm_chip_get_pmu(sc);
1092 if (sc->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU) {
1093 sc->sc_chip.ch_pmucaps = sc->sc_buscore_ops->bc_read(sc,
1094 core->co_base + BWFM_CHIP_REG_PMUCAPABILITIES);
1095 sc->sc_chip.ch_pmurev = sc->sc_chip.ch_pmucaps &
1096 BWFM_CHIP_REG_PMUCAPABILITIES_REV_MASK;
1097 }
1098
1099 if (sc->sc_buscore_ops->bc_setup)
1100 sc->sc_buscore_ops->bc_setup(sc);
1101
1102 return 0;
1103 }
1104
1105 struct bwfm_core *
1106 bwfm_chip_get_core(struct bwfm_softc *sc, int id)
1107 {
1108 struct bwfm_core *core;
1109
1110 LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) {
1111 if (core->co_id == id)
1112 return core;
1113 }
1114
1115 return NULL;
1116 }
1117
1118 struct bwfm_core *
1119 bwfm_chip_get_pmu(struct bwfm_softc *sc)
1120 {
1121 struct bwfm_core *cc, *pmu;
1122
1123 cc = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1124 if (cc->co_rev >= 35 && sc->sc_chip.ch_cc_caps_ext &
1125 BWFM_CHIP_REG_CAPABILITIES_EXT_AOB_PRESENT) {
1126 pmu = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_PMU);
1127 if (pmu)
1128 return pmu;
1129 }
1130
1131 return cc;
1132 }
1133
1134 /* Functions for the AI interconnect */
1135 int
1136 bwfm_chip_ai_isup(struct bwfm_softc *sc, struct bwfm_core *core)
1137 {
1138 uint32_t ioctl, reset;
1139
1140 ioctl = sc->sc_buscore_ops->bc_read(sc,
1141 core->co_wrapbase + BWFM_AGENT_IOCTL);
1142 reset = sc->sc_buscore_ops->bc_read(sc,
1143 core->co_wrapbase + BWFM_AGENT_RESET_CTL);
1144
1145 if (((ioctl & (BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK)) ==
1146 BWFM_AGENT_IOCTL_CLK) &&
1147 ((reset & BWFM_AGENT_RESET_CTL_RESET) == 0))
1148 return 1;
1149
1150 return 0;
1151 }
1152
1153 void
1154 bwfm_chip_ai_disable(struct bwfm_softc *sc, struct bwfm_core *core,
1155 uint32_t prereset, uint32_t reset)
1156 {
1157 uint32_t val;
1158 int i;
1159
1160 val = sc->sc_buscore_ops->bc_read(sc,
1161 core->co_wrapbase + BWFM_AGENT_RESET_CTL);
1162 if ((val & BWFM_AGENT_RESET_CTL_RESET) == 0) {
1163
1164 sc->sc_buscore_ops->bc_write(sc,
1165 core->co_wrapbase + BWFM_AGENT_IOCTL,
1166 prereset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK);
1167 sc->sc_buscore_ops->bc_read(sc,
1168 core->co_wrapbase + BWFM_AGENT_IOCTL);
1169
1170 sc->sc_buscore_ops->bc_write(sc,
1171 core->co_wrapbase + BWFM_AGENT_RESET_CTL,
1172 BWFM_AGENT_RESET_CTL_RESET);
1173 delay(20);
1174
1175 for (i = 300; i > 0; i--) {
1176 if (sc->sc_buscore_ops->bc_read(sc,
1177 core->co_wrapbase + BWFM_AGENT_RESET_CTL) ==
1178 BWFM_AGENT_RESET_CTL_RESET)
1179 break;
1180 }
1181 if (i == 0)
1182 printf("%s: timeout on core reset\n", DEVNAME(sc));
1183 }
1184
1185 sc->sc_buscore_ops->bc_write(sc,
1186 core->co_wrapbase + BWFM_AGENT_IOCTL,
1187 reset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK);
1188 sc->sc_buscore_ops->bc_read(sc,
1189 core->co_wrapbase + BWFM_AGENT_IOCTL);
1190 }
1191
1192 void
1193 bwfm_chip_ai_reset(struct bwfm_softc *sc, struct bwfm_core *core,
1194 uint32_t prereset, uint32_t reset, uint32_t postreset)
1195 {
1196 int i;
1197
1198 bwfm_chip_ai_disable(sc, core, prereset, reset);
1199
1200 for (i = 50; i > 0; i--) {
1201 if ((sc->sc_buscore_ops->bc_read(sc,
1202 core->co_wrapbase + BWFM_AGENT_RESET_CTL) &
1203 BWFM_AGENT_RESET_CTL_RESET) == 0)
1204 break;
1205 sc->sc_buscore_ops->bc_write(sc,
1206 core->co_wrapbase + BWFM_AGENT_RESET_CTL, 0);
1207 delay(60);
1208 }
1209 if (i == 0)
1210 printf("%s: timeout on core reset\n", DEVNAME(sc));
1211
1212 sc->sc_buscore_ops->bc_write(sc,
1213 core->co_wrapbase + BWFM_AGENT_IOCTL,
1214 postreset | BWFM_AGENT_IOCTL_CLK);
1215 sc->sc_buscore_ops->bc_read(sc,
1216 core->co_wrapbase + BWFM_AGENT_IOCTL);
1217 }
1218
1219 void
1220 bwfm_chip_dmp_erom_scan(struct bwfm_softc *sc)
1221 {
1222 uint32_t erom, val, base, wrap;
1223 uint8_t type = 0;
1224 uint16_t id;
1225 uint8_t nmw, nsw, rev;
1226 struct bwfm_core *core;
1227
1228 erom = sc->sc_buscore_ops->bc_read(sc,
1229 BWFM_CHIP_BASE + BWFM_CHIP_REG_EROMPTR);
1230 while (type != BWFM_DMP_DESC_EOT) {
1231 val = sc->sc_buscore_ops->bc_read(sc, erom);
1232 type = val & BWFM_DMP_DESC_MASK;
1233 erom += 4;
1234
1235 if (type != BWFM_DMP_DESC_COMPONENT)
1236 continue;
1237
1238 id = (val & BWFM_DMP_COMP_PARTNUM)
1239 >> BWFM_DMP_COMP_PARTNUM_S;
1240
1241 val = sc->sc_buscore_ops->bc_read(sc, erom);
1242 type = val & BWFM_DMP_DESC_MASK;
1243 erom += 4;
1244
1245 if (type != BWFM_DMP_DESC_COMPONENT) {
1246 printf("%s: not component descriptor\n", DEVNAME(sc));
1247 return;
1248 }
1249
1250 nmw = (val & BWFM_DMP_COMP_NUM_MWRAP)
1251 >> BWFM_DMP_COMP_NUM_MWRAP_S;
1252 nsw = (val & BWFM_DMP_COMP_NUM_SWRAP)
1253 >> BWFM_DMP_COMP_NUM_SWRAP_S;
1254 rev = (val & BWFM_DMP_COMP_REVISION)
1255 >> BWFM_DMP_COMP_REVISION_S;
1256
1257 if (nmw + nsw == 0 && id != BWFM_AGENT_CORE_PMU)
1258 continue;
1259
1260 if (bwfm_chip_dmp_get_regaddr(sc, &erom, &base, &wrap))
1261 continue;
1262
1263 core = kmem_alloc(sizeof(*core), KM_SLEEP);
1264 core->co_id = id;
1265 core->co_base = base;
1266 core->co_wrapbase = wrap;
1267 core->co_rev = rev;
1268 LIST_INSERT_HEAD(&sc->sc_chip.ch_list, core, co_link);
1269 }
1270 }
1271
1272 int
1273 bwfm_chip_dmp_get_regaddr(struct bwfm_softc *sc, uint32_t *erom,
1274 uint32_t *base, uint32_t *wrap)
1275 {
1276 uint8_t type = 0, mpnum __unused = 0;
1277 uint8_t stype, sztype, wraptype;
1278 uint32_t val;
1279
1280 *base = 0;
1281 *wrap = 0;
1282
1283 val = sc->sc_buscore_ops->bc_read(sc, *erom);
1284 type = val & BWFM_DMP_DESC_MASK;
1285 if (type == BWFM_DMP_DESC_MASTER_PORT) {
1286 mpnum = (val & BWFM_DMP_MASTER_PORT_NUM)
1287 >> BWFM_DMP_MASTER_PORT_NUM_S;
1288 wraptype = BWFM_DMP_SLAVE_TYPE_MWRAP;
1289 *erom += 4;
1290 } else if ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) ==
1291 BWFM_DMP_DESC_ADDRESS)
1292 wraptype = BWFM_DMP_SLAVE_TYPE_SWRAP;
1293 else
1294 return 1;
1295
1296 do {
1297 do {
1298 val = sc->sc_buscore_ops->bc_read(sc, *erom);
1299 type = val & BWFM_DMP_DESC_MASK;
1300 if (type == BWFM_DMP_DESC_COMPONENT)
1301 return 0;
1302 if (type == BWFM_DMP_DESC_EOT)
1303 return 1;
1304 *erom += 4;
1305 } while ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) !=
1306 BWFM_DMP_DESC_ADDRESS);
1307
1308 if (type & BWFM_DMP_DESC_ADDRSIZE_GT32)
1309 *erom += 4;
1310
1311 sztype = (val & BWFM_DMP_SLAVE_SIZE_TYPE)
1312 >> BWFM_DMP_SLAVE_SIZE_TYPE_S;
1313 if (sztype == BWFM_DMP_SLAVE_SIZE_DESC) {
1314 val = sc->sc_buscore_ops->bc_read(sc, *erom);
1315 type = val & BWFM_DMP_DESC_MASK;
1316 if (type & BWFM_DMP_DESC_ADDRSIZE_GT32)
1317 *erom += 8;
1318 else
1319 *erom += 4;
1320 }
1321 if (sztype != BWFM_DMP_SLAVE_SIZE_4K)
1322 continue;
1323
1324 stype = (val & BWFM_DMP_SLAVE_TYPE) >> BWFM_DMP_SLAVE_TYPE_S;
1325 if (*base == 0 && stype == BWFM_DMP_SLAVE_TYPE_SLAVE)
1326 *base = val & BWFM_DMP_SLAVE_ADDR_BASE;
1327 if (*wrap == 0 && stype == wraptype)
1328 *wrap = val & BWFM_DMP_SLAVE_ADDR_BASE;
1329 } while (*base == 0 || *wrap == 0);
1330
1331 return 0;
1332 }
1333
1334 /* Core configuration */
1335 int
1336 bwfm_chip_set_active(struct bwfm_softc *sc, const uint32_t rstvec)
1337 {
1338 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL)
1339 return bwfm_chip_cr4_set_active(sc, rstvec);
1340 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL)
1341 return bwfm_chip_ca7_set_active(sc, rstvec);
1342 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL)
1343 return bwfm_chip_cm3_set_active(sc);
1344 return 1;
1345 }
1346
1347 void
1348 bwfm_chip_set_passive(struct bwfm_softc *sc)
1349 {
1350 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL) {
1351 bwfm_chip_cr4_set_passive(sc);
1352 return;
1353 }
1354 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL) {
1355 bwfm_chip_ca7_set_passive(sc);
1356 return;
1357 }
1358 if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL) {
1359 bwfm_chip_cm3_set_passive(sc);
1360 return;
1361 }
1362 }
1363
1364 int
1365 bwfm_chip_cr4_set_active(struct bwfm_softc *sc, const uint32_t rstvec)
1366 {
1367 struct bwfm_core *core;
1368
1369 sc->sc_buscore_ops->bc_activate(sc, rstvec);
1370 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4);
1371 sc->sc_chip.ch_core_reset(sc, core,
1372 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0);
1373
1374 return 0;
1375 }
1376
1377 void
1378 bwfm_chip_cr4_set_passive(struct bwfm_softc *sc)
1379 {
1380 struct bwfm_core *core;
1381 uint32_t val;
1382
1383 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4);
1384 val = sc->sc_buscore_ops->bc_read(sc,
1385 core->co_wrapbase + BWFM_AGENT_IOCTL);
1386 sc->sc_chip.ch_core_reset(sc, core,
1387 val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1388 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1389 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT);
1390
1391 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211);
1392 sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET |
1393 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN,
1394 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN);
1395 }
1396
1397 int
1398 bwfm_chip_ca7_set_active(struct bwfm_softc *sc, const uint32_t rstvec)
1399 {
1400 struct bwfm_core *core;
1401
1402 sc->sc_buscore_ops->bc_activate(sc, rstvec);
1403 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7);
1404 sc->sc_chip.ch_core_reset(sc, core,
1405 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT, 0, 0);
1406
1407 return 0;
1408 }
1409
1410 void
1411 bwfm_chip_ca7_set_passive(struct bwfm_softc *sc)
1412 {
1413 struct bwfm_core *core;
1414 uint32_t val;
1415
1416 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7);
1417 val = sc->sc_buscore_ops->bc_read(sc,
1418 core->co_wrapbase + BWFM_AGENT_IOCTL);
1419 sc->sc_chip.ch_core_reset(sc, core,
1420 val & BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1421 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT,
1422 BWFM_AGENT_IOCTL_ARMCR4_CPUHALT);
1423
1424 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211);
1425 sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET |
1426 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN,
1427 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN);
1428 }
1429
1430 int
1431 bwfm_chip_cm3_set_active(struct bwfm_softc *sc)
1432 {
1433 struct bwfm_core *core;
1434
1435 core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM);
1436 if (!sc->sc_chip.ch_core_isup(sc, core))
1437 return 1;
1438
1439 sc->sc_buscore_ops->bc_activate(sc, 0);
1440
1441 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3);
1442 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1443
1444 return 0;
1445 }
1446
1447 void
1448 bwfm_chip_cm3_set_passive(struct bwfm_softc *sc)
1449 {
1450 struct bwfm_core *core;
1451
1452 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3);
1453 sc->sc_chip.ch_core_disable(sc, core, 0, 0);
1454 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211);
1455 sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET |
1456 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN,
1457 BWFM_AGENT_D11_IOCTL_PHYCLOCKEN);
1458 core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM);
1459 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1460
1461 if (sc->sc_chip.ch_chip == BRCM_CC_43430_CHIP_ID) {
1462 sc->sc_buscore_ops->bc_write(sc,
1463 core->co_base + BWFM_SOCRAM_BANKIDX, 3);
1464 sc->sc_buscore_ops->bc_write(sc,
1465 core->co_base + BWFM_SOCRAM_BANKPDA, 0);
1466 }
1467 }
1468
1469 int
1470 bwfm_chip_sr_capable(struct bwfm_softc *sc)
1471 {
1472 struct bwfm_core *core;
1473 uint32_t reg;
1474
1475 if (sc->sc_chip.ch_pmurev < 17)
1476 return 0;
1477
1478 switch (sc->sc_chip.ch_chip) {
1479 case BRCM_CC_4345_CHIP_ID:
1480 case BRCM_CC_4354_CHIP_ID:
1481 case BRCM_CC_4356_CHIP_ID:
1482 core = bwfm_chip_get_pmu(sc);
1483 sc->sc_buscore_ops->bc_write(sc, core->co_base +
1484 BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3);
1485 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1486 BWFM_CHIP_REG_CHIPCONTROL_DATA);
1487 return (reg & (1 << 2)) != 0;
1488 case BRCM_CC_43241_CHIP_ID:
1489 case BRCM_CC_4335_CHIP_ID:
1490 case BRCM_CC_4339_CHIP_ID:
1491 core = bwfm_chip_get_pmu(sc);
1492 sc->sc_buscore_ops->bc_write(sc, core->co_base +
1493 BWFM_CHIP_REG_CHIPCONTROL_ADDR, 3);
1494 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1495 BWFM_CHIP_REG_CHIPCONTROL_DATA);
1496 return reg != 0;
1497 case BRCM_CC_43430_CHIP_ID:
1498 core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
1499 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1500 BWFM_CHIP_REG_SR_CONTROL1);
1501 return reg != 0;
1502 default:
1503 core = bwfm_chip_get_pmu(sc);
1504 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1505 BWFM_CHIP_REG_PMUCAPABILITIES_EXT);
1506 if ((reg & BWFM_CHIP_REG_PMUCAPABILITIES_SR_SUPP) == 0)
1507 return 0;
1508 reg = sc->sc_buscore_ops->bc_read(sc, core->co_base +
1509 BWFM_CHIP_REG_RETENTION_CTL);
1510 return (reg & (BWFM_CHIP_REG_RETENTION_CTL_MACPHY_DIS |
1511 BWFM_CHIP_REG_RETENTION_CTL_LOGIC_DIS)) == 0;
1512 }
1513 }
1514
1515 /* RAM size helpers */
1516 void
1517 bwfm_chip_socram_ramsize(struct bwfm_softc *sc, struct bwfm_core *core)
1518 {
1519 uint32_t coreinfo, nb, lss, banksize, bankinfo;
1520 uint32_t ramsize = 0, srsize = 0;
1521 int i;
1522
1523 if (!sc->sc_chip.ch_core_isup(sc, core))
1524 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1525
1526 coreinfo = sc->sc_buscore_ops->bc_read(sc,
1527 core->co_base + BWFM_SOCRAM_COREINFO);
1528 nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK)
1529 >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT;
1530
1531 if (core->co_rev <= 7 || core->co_rev == 12) {
1532 banksize = coreinfo & BWFM_SOCRAM_COREINFO_SRBSZ_MASK;
1533 lss = (coreinfo & BWFM_SOCRAM_COREINFO_LSS_MASK)
1534 >> BWFM_SOCRAM_COREINFO_LSS_SHIFT;
1535 if (lss != 0)
1536 nb--;
1537 ramsize = nb * (1 << (banksize + BWFM_SOCRAM_COREINFO_SRBSZ_BASE));
1538 if (lss != 0)
1539 ramsize += (1 << ((lss - 1) + BWFM_SOCRAM_COREINFO_SRBSZ_BASE));
1540 } else {
1541 for (i = 0; i < nb; i++) {
1542 sc->sc_buscore_ops->bc_write(sc,
1543 core->co_base + BWFM_SOCRAM_BANKIDX,
1544 (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM <<
1545 BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i);
1546 bankinfo = sc->sc_buscore_ops->bc_read(sc,
1547 core->co_base + BWFM_SOCRAM_BANKINFO);
1548 banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1)
1549 * BWFM_SOCRAM_BANKINFO_SZBASE;
1550 ramsize += banksize;
1551 if (bankinfo & BWFM_SOCRAM_BANKINFO_RETNTRAM_MASK)
1552 srsize += banksize;
1553 }
1554 }
1555
1556 switch (sc->sc_chip.ch_chip) {
1557 case BRCM_CC_4334_CHIP_ID:
1558 if (sc->sc_chip.ch_chiprev < 2)
1559 srsize = 32 * 1024;
1560 break;
1561 case BRCM_CC_43430_CHIP_ID:
1562 srsize = 64 * 1024;
1563 break;
1564 default:
1565 break;
1566 }
1567
1568 sc->sc_chip.ch_ramsize = ramsize;
1569 sc->sc_chip.ch_srsize = srsize;
1570 }
1571
1572 void
1573 bwfm_chip_sysmem_ramsize(struct bwfm_softc *sc, struct bwfm_core *core)
1574 {
1575 uint32_t coreinfo, nb, banksize, bankinfo;
1576 uint32_t ramsize = 0;
1577 int i;
1578
1579 if (!sc->sc_chip.ch_core_isup(sc, core))
1580 sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1581
1582 coreinfo = sc->sc_buscore_ops->bc_read(sc,
1583 core->co_base + BWFM_SOCRAM_COREINFO);
1584 nb = (coreinfo & BWFM_SOCRAM_COREINFO_SRNB_MASK)
1585 >> BWFM_SOCRAM_COREINFO_SRNB_SHIFT;
1586
1587 for (i = 0; i < nb; i++) {
1588 sc->sc_buscore_ops->bc_write(sc,
1589 core->co_base + BWFM_SOCRAM_BANKIDX,
1590 (BWFM_SOCRAM_BANKIDX_MEMTYPE_RAM <<
1591 BWFM_SOCRAM_BANKIDX_MEMTYPE_SHIFT) | i);
1592 bankinfo = sc->sc_buscore_ops->bc_read(sc,
1593 core->co_base + BWFM_SOCRAM_BANKINFO);
1594 banksize = ((bankinfo & BWFM_SOCRAM_BANKINFO_SZMASK) + 1)
1595 * BWFM_SOCRAM_BANKINFO_SZBASE;
1596 ramsize += banksize;
1597 }
1598
1599 sc->sc_chip.ch_ramsize = ramsize;
1600 }
1601
1602 void
1603 bwfm_chip_tcm_ramsize(struct bwfm_softc *sc, struct bwfm_core *core)
1604 {
1605 uint32_t cap, nab, nbb, totb, bxinfo, ramsize = 0;
1606 int i;
1607
1608 cap = sc->sc_buscore_ops->bc_read(sc, core->co_base + BWFM_ARMCR4_CAP);
1609 nab = (cap & BWFM_ARMCR4_CAP_TCBANB_MASK) >> BWFM_ARMCR4_CAP_TCBANB_SHIFT;
1610 nbb = (cap & BWFM_ARMCR4_CAP_TCBBNB_MASK) >> BWFM_ARMCR4_CAP_TCBBNB_SHIFT;
1611 totb = nab + nbb;
1612
1613 for (i = 0; i < totb; i++) {
1614 sc->sc_buscore_ops->bc_write(sc,
1615 core->co_base + BWFM_ARMCR4_BANKIDX, i);
1616 bxinfo = sc->sc_buscore_ops->bc_read(sc,
1617 core->co_base + BWFM_ARMCR4_BANKINFO);
1618 ramsize += ((bxinfo & BWFM_ARMCR4_BANKINFO_BSZ_MASK) + 1) *
1619 BWFM_ARMCR4_BANKINFO_BSZ_MULT;
1620 }
1621
1622 sc->sc_chip.ch_ramsize = ramsize;
1623 }
1624
1625 void
1626 bwfm_chip_tcm_rambase(struct bwfm_softc *sc)
1627 {
1628 switch (sc->sc_chip.ch_chip) {
1629 case BRCM_CC_4345_CHIP_ID:
1630 sc->sc_chip.ch_rambase = 0x198000;
1631 break;
1632 case BRCM_CC_4335_CHIP_ID:
1633 case BRCM_CC_4339_CHIP_ID:
1634 case BRCM_CC_4350_CHIP_ID:
1635 case BRCM_CC_4354_CHIP_ID:
1636 case BRCM_CC_4356_CHIP_ID:
1637 case BRCM_CC_43567_CHIP_ID:
1638 case BRCM_CC_43569_CHIP_ID:
1639 case BRCM_CC_43570_CHIP_ID:
1640 case BRCM_CC_4358_CHIP_ID:
1641 case BRCM_CC_4359_CHIP_ID:
1642 case BRCM_CC_43602_CHIP_ID:
1643 case BRCM_CC_4371_CHIP_ID:
1644 sc->sc_chip.ch_rambase = 0x180000;
1645 break;
1646 case BRCM_CC_43465_CHIP_ID:
1647 case BRCM_CC_43525_CHIP_ID:
1648 case BRCM_CC_4365_CHIP_ID:
1649 case BRCM_CC_4366_CHIP_ID:
1650 sc->sc_chip.ch_rambase = 0x200000;
1651 break;
1652 case CY_CC_4373_CHIP_ID:
1653 sc->sc_chip.ch_rambase = 0x160000;
1654 break;
1655 default:
1656 printf("%s: unknown chip: %d\n", DEVNAME(sc),
1657 sc->sc_chip.ch_chip);
1658 break;
1659 }
1660 }
1661
1662 /* BCDC protocol implementation */
1663 int
1664 bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *sc, int ifidx,
1665 int cmd, char *buf, size_t *len)
1666 {
1667 struct bwfm_proto_bcdc_dcmd *dcmd;
1668 size_t size = sizeof(dcmd->hdr) + *len;
1669 int reqid;
1670 int ret = 1;
1671
1672 reqid = sc->sc_bcdc_reqid++;
1673
1674 dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP);
1675 if (*len > sizeof(dcmd->buf))
1676 goto err;
1677
1678 dcmd->hdr.cmd = htole32(cmd);
1679 dcmd->hdr.len = htole32(*len);
1680 dcmd->hdr.flags |= BWFM_BCDC_DCMD_GET;
1681 dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid);
1682 dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx);
1683 dcmd->hdr.flags = htole32(dcmd->hdr.flags);
1684 memcpy(&dcmd->buf, buf, *len);
1685
1686 if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd,
1687 sizeof(dcmd->hdr) + *len)) {
1688 DPRINTF(("%s: tx failed\n", DEVNAME(sc)));
1689 goto err;
1690 }
1691
1692 do {
1693 if (sc->sc_bus_ops->bs_rxctl(sc, (void *)dcmd, &size)) {
1694 DPRINTF(("%s: rx failed\n", DEVNAME(sc)));
1695 goto err;
1696 }
1697 dcmd->hdr.cmd = le32toh(dcmd->hdr.cmd);
1698 dcmd->hdr.len = le32toh(dcmd->hdr.len);
1699 dcmd->hdr.flags = le32toh(dcmd->hdr.flags);
1700 dcmd->hdr.status = le32toh(dcmd->hdr.status);
1701 } while (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid);
1702
1703 if (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid) {
1704 printf("%s: unexpected request id\n", DEVNAME(sc));
1705 goto err;
1706 }
1707
1708 if (buf) {
1709 if (size < *len)
1710 *len = size;
1711 memcpy(buf, dcmd->buf, *len);
1712 }
1713
1714 if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR)
1715 ret = dcmd->hdr.status;
1716 else
1717 ret = 0;
1718 err:
1719 kmem_free(dcmd, sizeof(*dcmd));
1720 return ret;
1721 }
1722
1723 int
1724 bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *sc, int ifidx,
1725 int cmd, char *buf, size_t len)
1726 {
1727 struct bwfm_proto_bcdc_dcmd *dcmd;
1728 size_t size = sizeof(dcmd->hdr) + len;
1729 int ret = 1, reqid;
1730
1731 reqid = sc->sc_bcdc_reqid++;
1732
1733 dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP);
1734 if (len > sizeof(dcmd->buf))
1735 goto err;
1736
1737 dcmd->hdr.cmd = htole32(cmd);
1738 dcmd->hdr.len = htole32(len);
1739 dcmd->hdr.flags |= BWFM_BCDC_DCMD_SET;
1740 dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid);
1741 dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx);
1742 dcmd->hdr.flags = htole32(dcmd->hdr.flags);
1743 memcpy(&dcmd->buf, buf, len);
1744
1745 if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd, size)) {
1746 DPRINTF(("%s: tx failed\n", DEVNAME(sc)));
1747 goto err;
1748 }
1749
1750 do {
1751 if (sc->sc_bus_ops->bs_rxctl(sc, (void *)dcmd, &size)) {
1752 DPRINTF(("%s: rx failed\n", DEVNAME(sc)));
1753 goto err;
1754 }
1755 dcmd->hdr.cmd = le32toh(dcmd->hdr.cmd);
1756 dcmd->hdr.len = le32toh(dcmd->hdr.len);
1757 dcmd->hdr.flags = le32toh(dcmd->hdr.flags);
1758 dcmd->hdr.status = le32toh(dcmd->hdr.status);
1759 } while (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid);
1760
1761 if (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid) {
1762 printf("%s: unexpected request id\n", DEVNAME(sc));
1763 goto err;
1764 }
1765
1766 if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR)
1767 return dcmd->hdr.status;
1768
1769 ret = 0;
1770 err:
1771 kmem_free(dcmd, sizeof(*dcmd));
1772 return ret;
1773 }
1774
1775 /* FW Variable code */
1776 int
1777 bwfm_fwvar_cmd_get_data(struct bwfm_softc *sc, int cmd, void *data, size_t len)
1778 {
1779 return sc->sc_proto_ops->proto_query_dcmd(sc, 0, cmd, data, &len);
1780 }
1781
1782 int
1783 bwfm_fwvar_cmd_set_data(struct bwfm_softc *sc, int cmd, void *data, size_t len)
1784 {
1785 return sc->sc_proto_ops->proto_set_dcmd(sc, 0, cmd, data, len);
1786 }
1787
1788 int
1789 bwfm_fwvar_cmd_get_int(struct bwfm_softc *sc, int cmd, uint32_t *data)
1790 {
1791 int ret;
1792 ret = bwfm_fwvar_cmd_get_data(sc, cmd, data, sizeof(*data));
1793 *data = le32toh(*data);
1794 return ret;
1795 }
1796
1797 int
1798 bwfm_fwvar_cmd_set_int(struct bwfm_softc *sc, int cmd, uint32_t data)
1799 {
1800 data = htole32(data);
1801 return bwfm_fwvar_cmd_set_data(sc, cmd, &data, sizeof(data));
1802 }
1803
1804 int
1805 bwfm_fwvar_var_get_data(struct bwfm_softc *sc, const char *name, void *data, size_t len)
1806 {
1807 char *buf;
1808 int ret;
1809
1810 buf = kmem_alloc(strlen(name) + 1 + len, KM_SLEEP);
1811 memcpy(buf, name, strlen(name) + 1);
1812 memcpy(buf + strlen(name) + 1, data, len);
1813 ret = bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_VAR,
1814 buf, strlen(name) + 1 + len);
1815 memcpy(data, buf, len);
1816 kmem_free(buf, strlen(name) + 1 + len);
1817 return ret;
1818 }
1819
1820 int
1821 bwfm_fwvar_var_set_data(struct bwfm_softc *sc, const char *name, void *data, size_t len)
1822 {
1823 char *buf;
1824 int ret;
1825
1826 buf = kmem_alloc(strlen(name) + 1 + len, KM_SLEEP);
1827 memcpy(buf, name, strlen(name) + 1);
1828 memcpy(buf + strlen(name) + 1, data, len);
1829 ret = bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_VAR,
1830 buf, strlen(name) + 1 + len);
1831 kmem_free(buf, strlen(name) + 1 + len);
1832 return ret;
1833 }
1834
1835 int
1836 bwfm_fwvar_var_get_int(struct bwfm_softc *sc, const char *name, uint32_t *data)
1837 {
1838 int ret;
1839 ret = bwfm_fwvar_var_get_data(sc, name, data, sizeof(*data));
1840 *data = le32toh(*data);
1841 return ret;
1842 }
1843
1844 int
1845 bwfm_fwvar_var_set_int(struct bwfm_softc *sc, const char *name, uint32_t data)
1846 {
1847 data = htole32(data);
1848 return bwfm_fwvar_var_set_data(sc, name, &data, sizeof(data));
1849 }
1850
1851 /* 802.11 code */
1852 void
1853 bwfm_scan(struct bwfm_softc *sc)
1854 {
1855 struct bwfm_escan_params *params;
1856 uint32_t nssid = 0, nchannel = 0;
1857 size_t params_size;
1858
1859 #if 0
1860 /* Active scan is used for scanning for an SSID */
1861 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PASSIVE_SCAN, 0);
1862 #endif
1863 bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PASSIVE_SCAN, 1);
1864
1865 params_size = sizeof(*params);
1866 params_size += sizeof(uint32_t) * ((nchannel + 1) / 2);
1867 params_size += sizeof(struct bwfm_ssid) * nssid;
1868
1869 params = kmem_zalloc(params_size, KM_SLEEP);
1870 memset(params->scan_params.bssid, 0xff,
1871 sizeof(params->scan_params.bssid));
1872 params->scan_params.bss_type = 2;
1873 params->scan_params.nprobes = htole32(-1);
1874 params->scan_params.active_time = htole32(-1);
1875 params->scan_params.passive_time = htole32(-1);
1876 params->scan_params.home_time = htole32(-1);
1877 params->version = htole32(BWFM_ESCAN_REQ_VERSION);
1878 params->action = htole16(WL_ESCAN_ACTION_START);
1879 params->sync_id = htole16(0x1234);
1880
1881 #if 0
1882 /* Scan a specific channel */
1883 params->scan_params.channel_list[0] = htole16(
1884 (1 & 0xff) << 0 |
1885 (3 & 0x3) << 8 |
1886 (2 & 0x3) << 10 |
1887 (2 & 0x3) << 12
1888 );
1889 params->scan_params.channel_num = htole32(
1890 (1 & 0xffff) << 0
1891 );
1892 #endif
1893
1894 bwfm_fwvar_var_set_data(sc, "escan", params, params_size);
1895 kmem_free(params, params_size);
1896 }
1897
1898 static __inline int
1899 bwfm_iswpaoui(const uint8_t *frm)
1900 {
1901 return frm[1] > 3 && le32dec(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
1902 }
1903
1904 /*
1905 * Derive wireless security settings from WPA/RSN IE.
1906 */
1907 static uint32_t
1908 bwfm_get_wsec(struct bwfm_softc *sc)
1909 {
1910 struct ieee80211com *ic = &sc->sc_ic;
1911 uint8_t *wpa = ic->ic_opt_ie;
1912
1913 KASSERT(ic->ic_opt_ie_len > 0);
1914
1915 if (wpa[0] != IEEE80211_ELEMID_RSN) {
1916 if (ic->ic_opt_ie_len < 12)
1917 return BWFM_WSEC_NONE;
1918
1919 /* non-RSN IE, expect that we are doing WPA1 */
1920 if ((ic->ic_flags & IEEE80211_F_WPA1) == 0)
1921 return BWFM_WSEC_NONE;
1922
1923 /* Must contain WPA OUI */
1924 if (!bwfm_iswpaoui(wpa))
1925 return BWFM_WSEC_NONE;
1926
1927 switch (le32dec(wpa + 8)) {
1928 case ((WPA_CSE_TKIP<<24)|WPA_OUI):
1929 return BWFM_WSEC_TKIP;
1930 case ((WPA_CSE_CCMP<<24)|WPA_OUI):
1931 return BWFM_WSEC_AES;
1932 default:
1933 return BWFM_WSEC_NONE;
1934 }
1935 } else {
1936 if (ic->ic_opt_ie_len < 14)
1937 return BWFM_WSEC_NONE;
1938
1939 /* RSN IE, expect that we are doing WPA2 */
1940 if ((ic->ic_flags & IEEE80211_F_WPA2) == 0)
1941 return BWFM_WSEC_NONE;
1942
1943 switch (le32dec(wpa + 10)) {
1944 case ((RSN_CSE_TKIP<<24)|RSN_OUI):
1945 return BWFM_WSEC_TKIP;
1946 case ((RSN_CSE_CCMP<<24)|RSN_OUI):
1947 return BWFM_WSEC_AES;
1948 default:
1949 return BWFM_WSEC_NONE;
1950 }
1951 }
1952 }
1953
1954 void
1955 bwfm_connect(struct bwfm_softc *sc)
1956 {
1957 struct ieee80211com *ic = &sc->sc_ic;
1958 struct ieee80211_node *ni = ic->ic_bss;
1959 struct bwfm_ext_join_params *params;
1960
1961 if (ic->ic_flags & IEEE80211_F_WPA) {
1962 uint32_t wsec = 0;
1963 uint32_t wpa = 0;
1964
1965 if (ic->ic_opt_ie_len)
1966 bwfm_fwvar_var_set_data(sc, "wpaie", ic->ic_opt_ie, ic->ic_opt_ie_len);
1967
1968 if (ic->ic_flags & IEEE80211_F_WPA1)
1969 wpa |= BWFM_WPA_AUTH_WPA_PSK;
1970 if (ic->ic_flags & IEEE80211_F_WPA2)
1971 wpa |= BWFM_WPA_AUTH_WPA2_PSK;
1972
1973 wsec |= bwfm_get_wsec(sc);
1974
1975 DPRINTF(("%s: WPA enabled, ic_flags = 0x%x, wpa 0x%x, wsec 0x%x\n",
1976 DEVNAME(sc), ic->ic_flags, wpa, wsec));
1977
1978 bwfm_fwvar_var_set_int(sc, "wpa_auth", wpa);
1979 bwfm_fwvar_var_set_int(sc, "wsec", wsec);
1980 } else {
1981 bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_DISABLED);
1982 bwfm_fwvar_var_set_int(sc, "wsec", BWFM_WSEC_NONE);
1983 }
1984
1985 bwfm_fwvar_var_set_int(sc, "auth", BWFM_AUTH_OPEN);
1986 bwfm_fwvar_var_set_int(sc, "mfp", BWFM_MFP_NONE);
1987
1988 if (ni->ni_esslen && ni->ni_esslen < BWFM_MAX_SSID_LEN) {
1989 params = kmem_zalloc(sizeof(*params), KM_SLEEP);
1990 memcpy(params->ssid.ssid, ni->ni_essid, ni->ni_esslen);
1991 params->ssid.len = htole32(ni->ni_esslen);
1992 memcpy(params->assoc.bssid, ni->ni_bssid, sizeof(params->assoc.bssid));
1993 params->scan.scan_type = -1;
1994 params->scan.nprobes = htole32(-1);
1995 params->scan.active_time = htole32(-1);
1996 params->scan.passive_time = htole32(-1);
1997 params->scan.home_time = htole32(-1);
1998 if (bwfm_fwvar_var_set_data(sc, "join", params, sizeof(*params))) {
1999 struct bwfm_join_params join;
2000 memset(&join, 0, sizeof(join));
2001 memcpy(join.ssid.ssid, ni->ni_essid, ni->ni_esslen);
2002 join.ssid.len = htole32(ni->ni_esslen);
2003 memcpy(join.assoc.bssid, ni->ni_bssid, sizeof(join.assoc.bssid));
2004 bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join,
2005 sizeof(join));
2006 }
2007 kmem_free(params, sizeof(*params));
2008 }
2009 }
2010
2011 void
2012 bwfm_get_sta_info(struct bwfm_softc *sc, struct ifmediareq *ifmr)
2013 {
2014 struct ieee80211com *ic = &sc->sc_ic;
2015 struct ieee80211_node *ni = ic->ic_bss;
2016 struct bwfm_sta_info sta;
2017 uint32_t flags, txrate;
2018
2019 memset(&sta, 0, sizeof(sta));
2020 memcpy(&sta, ni->ni_macaddr, sizeof(ni->ni_macaddr));
2021
2022 if (bwfm_fwvar_var_get_data(sc, "sta_info", &sta, sizeof(sta)))
2023 return;
2024
2025 if (!IEEE80211_ADDR_EQ(ni->ni_macaddr, sta.ea))
2026 return;
2027
2028 if (le16toh(sta.ver) < 4)
2029 return;
2030
2031 flags = le32toh(sta.flags);
2032 if ((flags & BWFM_STA_SCBSTATS) == 0)
2033 return;
2034
2035 txrate = le32toh(sta.tx_rate);
2036 if (txrate == 0xffffffff)
2037 return;
2038
2039 if ((flags & BWFM_STA_VHT_CAP) != 0) {
2040 ifmr->ifm_active &= ~IFM_TMASK;
2041 ifmr->ifm_active |= IFM_IEEE80211_VHT;
2042 ifmr->ifm_active &= ~IFM_MMASK;
2043 ifmr->ifm_active |= IFM_IEEE80211_11AC;
2044 } else if ((flags & BWFM_STA_N_CAP) != 0) {
2045 ifmr->ifm_active &= ~IFM_TMASK;
2046 ifmr->ifm_active |= IFM_IEEE80211_MCS;
2047 ifmr->ifm_active &= ~IFM_MMASK;
2048 if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
2049 ifmr->ifm_active |= IFM_IEEE80211_11NG;
2050 else
2051 ifmr->ifm_active |= IFM_IEEE80211_11NA;
2052 }
2053 }
2054
2055 void
2056 bwfm_rx(struct bwfm_softc *sc, struct mbuf *m)
2057 {
2058 struct ieee80211com *ic = &sc->sc_ic;
2059 struct ifnet *ifp = ic->ic_ifp;
2060 struct bwfm_event *e = mtod(m, struct bwfm_event *);
2061
2062 if (m->m_len >= sizeof(e->ehdr) &&
2063 ntohs(e->ehdr.ether_type) == BWFM_ETHERTYPE_LINK_CTL &&
2064 memcmp(BWFM_BRCM_OUI, e->hdr.oui, sizeof(e->hdr.oui)) == 0 &&
2065 ntohs(e->hdr.usr_subtype) == BWFM_BRCM_SUBTYPE_EVENT) {
2066 bwfm_rx_event(sc, m);
2067 // m_freem(m);
2068 return;
2069 }
2070
2071 m_set_rcvif(m, ifp);
2072 if_percpuq_enqueue(ifp->if_percpuq, m);
2073 }
2074
2075 void
2076 bwfm_rx_event(struct bwfm_softc *sc, struct mbuf *m)
2077 {
2078 struct bwfm_task *t;
2079
2080 t = pool_cache_get(sc->sc_freetask, PR_NOWAIT);
2081 if (t == NULL) {
2082 m_freem(m);
2083 printf("%s: no free tasks\n", DEVNAME(sc));
2084 return;
2085 }
2086
2087 t->t_sc = sc;
2088 t->t_cmd = BWFM_TASK_RX_EVENT;
2089 t->t_mbuf = m;
2090 workqueue_enqueue(sc->sc_taskq, (struct work*)t, NULL);
2091 }
2092
2093 void
2094 bwfm_rx_event_cb(struct bwfm_softc *sc, struct mbuf *m)
2095 {
2096 struct ieee80211com *ic = &sc->sc_ic;
2097 struct bwfm_event *e = mtod(m, void *);
2098 size_t len = m->m_len;
2099 int s;
2100
2101 DPRINTF(("%s: event %p len %lu datalen %u code %u status %u"
2102 " reason %u\n", __func__, e, len, ntohl(e->msg.datalen),
2103 ntohl(e->msg.event_type), ntohl(e->msg.status),
2104 ntohl(e->msg.reason)));
2105
2106 if (ntohl(e->msg.event_type) >= BWFM_E_LAST) {
2107 m_freem(m);
2108 return;
2109 }
2110
2111 switch (ntohl(e->msg.event_type)) {
2112 case BWFM_E_ESCAN_RESULT: {
2113 struct bwfm_escan_results *res = (void *)&e[1];
2114 struct bwfm_bss_info *bss;
2115 int i;
2116 if (ntohl(e->msg.status) != BWFM_E_STATUS_PARTIAL) {
2117 /* Scan complete */
2118 s = splnet();
2119 if (ic->ic_opmode != IEEE80211_M_MONITOR)
2120 ieee80211_end_scan(ic);
2121 splx(s);
2122 break;
2123 }
2124 len -= sizeof(*e);
2125 if (len < sizeof(*res) || len < le32toh(res->buflen)) {
2126 m_freem(m);
2127 printf("%s: results too small\n", DEVNAME(sc));
2128 return;
2129 }
2130 len -= sizeof(*res);
2131 if (len < le16toh(res->bss_count) * sizeof(struct bwfm_bss_info)) {
2132 m_freem(m);
2133 printf("%s: results too small\n", DEVNAME(sc));
2134 return;
2135 }
2136 bss = &res->bss_info[0];
2137 for (i = 0; i < le16toh(res->bss_count); i++) {
2138 /* Fix alignment of bss_info */
2139 if (len > sizeof(sc->sc_bss_buf)) {
2140 printf("%s: bss_info buffer too big\n", DEVNAME(sc));
2141 } else {
2142 memcpy(&sc->sc_bss_buf, &res->bss_info[i], len);
2143 bwfm_scan_node(sc, &sc->sc_bss_buf.bss_info,
2144 len);
2145 }
2146 len -= sizeof(*bss) + le32toh(bss->length);
2147 bss = (void *)(((uintptr_t)bss) + le32toh(bss->length));
2148 if (len <= 0)
2149 break;
2150 }
2151 break;
2152 }
2153
2154 case BWFM_E_SET_SSID:
2155 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS) {
2156 ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
2157 } else {
2158 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2159 }
2160 break;
2161
2162 case BWFM_E_ASSOC:
2163 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS) {
2164 ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1);
2165 } else {
2166 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2167 }
2168 break;
2169
2170 case BWFM_E_LINK:
2171 if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS &&
2172 ntohl(e->msg.reason) == 0)
2173 break;
2174
2175 /* Link status has changed */
2176 ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2177 break;
2178
2179 default:
2180 break;
2181 }
2182
2183 m_freem(m);
2184 }
2185
2186 void
2187 bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_info *bss, size_t len)
2188 {
2189 struct ieee80211com *ic = &sc->sc_ic;
2190 struct ieee80211_frame wh;
2191 struct ieee80211_scanparams scan;
2192 uint8_t rates[sizeof(bss->rates) + 2];
2193 uint8_t ssid[sizeof(bss->ssid) + 2];
2194 uint8_t *frm, *sfrm, *efrm;
2195 uint64_t tsf;
2196
2197 tsf = 0;
2198 sfrm = ((uint8_t *)bss) + le16toh(bss->ie_offset);
2199 efrm = sfrm + le32toh(bss->ie_length);
2200
2201 /* Fake a wireless header with the scan result's BSSID */
2202 memset(&wh, 0, sizeof(wh));
2203 IEEE80211_ADDR_COPY(wh.i_addr2, bss->bssid);
2204 IEEE80211_ADDR_COPY(wh.i_addr3, bss->bssid);
2205
2206 if (efrm - sfrm < 12) {
2207 ic->ic_stats.is_rx_elem_toosmall++;
2208 return;
2209 }
2210
2211 rates[0] = 0;
2212 rates[1] = le32toh(bss->nrates);
2213 memcpy(&rates[2], bss->rates, sizeof(bss->rates));
2214
2215 ssid[0] = 0;
2216 ssid[1] = bss->ssid_len;
2217 memcpy(&ssid[2], bss->ssid, sizeof(bss->ssid));
2218
2219 /* Build scan result */
2220 memset(&scan, 0, sizeof(scan));
2221 scan.sp_tstamp = (uint8_t *)&tsf;
2222 scan.sp_bintval = le16toh(bss->beacon_period);
2223 scan.sp_capinfo = le16toh(bss->capability);
2224 scan.sp_bchan = ieee80211_chan2ieee(ic, ic->ic_curchan);
2225 scan.sp_chan = scan.sp_bchan;
2226 scan.sp_rates = rates;
2227 scan.sp_ssid = ssid;
2228
2229 for (frm = sfrm; frm < efrm; frm += frm[1] + 2) {
2230 switch (frm[0]) {
2231 case IEEE80211_ELEMID_COUNTRY:
2232 scan.sp_country = frm;
2233 break;
2234 case IEEE80211_ELEMID_FHPARMS:
2235 if (ic->ic_phytype == IEEE80211_T_FH) {
2236 if (frm + 6 >= efrm)
2237 break;
2238 scan.sp_fhdwell = le16dec(&frm[2]);
2239 scan.sp_chan = IEEE80211_FH_CHAN(frm[4], frm[5]);
2240 scan.sp_fhindex = frm[6];
2241 }
2242 break;
2243 case IEEE80211_ELEMID_DSPARMS:
2244 if (ic->ic_phytype != IEEE80211_T_FH) {
2245 if (frm + 2 >= efrm)
2246 break;
2247 scan.sp_chan = frm[2];
2248 }
2249 break;
2250 case IEEE80211_ELEMID_TIM:
2251 scan.sp_tim = frm;
2252 scan.sp_timoff = frm - sfrm;
2253 break;
2254 case IEEE80211_ELEMID_XRATES:
2255 scan.sp_xrates = frm;
2256 break;
2257 case IEEE80211_ELEMID_ERP:
2258 if (frm + 1 >= efrm)
2259 break;
2260 if (frm[1] != 1) {
2261 ic->ic_stats.is_rx_elem_toobig++;
2262 break;
2263 }
2264 scan.sp_erp = frm[2];
2265 break;
2266 case IEEE80211_ELEMID_RSN:
2267 scan.sp_wpa = frm;
2268 break;
2269 case IEEE80211_ELEMID_VENDOR:
2270 if (frm + 1 >= efrm)
2271 break;
2272 if (frm + frm[1] + 2 >= efrm)
2273 break;
2274 if (bwfm_iswpaoui(frm))
2275 scan.sp_wpa = frm;
2276 break;
2277 }
2278 if (frm + 1 >= efrm)
2279 break;
2280 }
2281
2282 if (ic->ic_flags & IEEE80211_F_SCAN)
2283 ieee80211_add_scan(ic, &scan, &wh, IEEE80211_FC0_SUBTYPE_BEACON,
2284 le32toh(bss->rssi), 0);
2285 }
2286