bwfm.c revision 1.1 1 1.1 jmcneill /* $NetBSD: bwfm.c,v 1.1 2017/10/19 23:58:41 jmcneill Exp $ */
2 1.1 jmcneill /* $OpenBSD: bwfm.c,v 1.5 2017/10/16 22:27:16 patrick Exp $ */
3 1.1 jmcneill /*
4 1.1 jmcneill * Copyright (c) 2010-2016 Broadcom Corporation
5 1.1 jmcneill * Copyright (c) 2016,2017 Patrick Wildt <patrick (at) blueri.se>
6 1.1 jmcneill *
7 1.1 jmcneill * Permission to use, copy, modify, and/or distribute this software for any
8 1.1 jmcneill * purpose with or without fee is hereby granted, provided that the above
9 1.1 jmcneill * copyright notice and this permission notice appear in all copies.
10 1.1 jmcneill *
11 1.1 jmcneill * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 1.1 jmcneill * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 1.1 jmcneill * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 1.1 jmcneill * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 1.1 jmcneill * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 1.1 jmcneill * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 1.1 jmcneill * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 1.1 jmcneill */
19 1.1 jmcneill
20 1.1 jmcneill #include <sys/param.h>
21 1.1 jmcneill #include <sys/systm.h>
22 1.1 jmcneill #include <sys/buf.h>
23 1.1 jmcneill #include <sys/kernel.h>
24 1.1 jmcneill #include <sys/malloc.h>
25 1.1 jmcneill #include <sys/device.h>
26 1.1 jmcneill #include <sys/queue.h>
27 1.1 jmcneill #include <sys/socket.h>
28 1.1 jmcneill #include <sys/kmem.h>
29 1.1 jmcneill #include <sys/workqueue.h>
30 1.1 jmcneill #include <sys/pcq.h>
31 1.1 jmcneill
32 1.1 jmcneill #include <net/bpf.h>
33 1.1 jmcneill #include <net/if.h>
34 1.1 jmcneill #include <net/if_dl.h>
35 1.1 jmcneill #include <net/if_media.h>
36 1.1 jmcneill #include <net/if_ether.h>
37 1.1 jmcneill
38 1.1 jmcneill #include <netinet/in.h>
39 1.1 jmcneill
40 1.1 jmcneill #include <net80211/ieee80211_var.h>
41 1.1 jmcneill
42 1.1 jmcneill #include <dev/ic/bwfmvar.h>
43 1.1 jmcneill #include <dev/ic/bwfmreg.h>
44 1.1 jmcneill
45 1.1 jmcneill /* #define BWFM_DEBUG */
46 1.1 jmcneill #ifdef BWFM_DEBUG
47 1.1 jmcneill #define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0)
48 1.1 jmcneill #define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0)
49 1.1 jmcneill static int bwfm_debug = 1;
50 1.1 jmcneill #else
51 1.1 jmcneill #define DPRINTF(x) do { ; } while (0)
52 1.1 jmcneill #define DPRINTFN(n, x) do { ; } while (0)
53 1.1 jmcneill #endif
54 1.1 jmcneill
55 1.1 jmcneill #define DEVNAME(sc) device_xname((sc)->sc_dev)
56 1.1 jmcneill
57 1.1 jmcneill void bwfm_start(struct ifnet *);
58 1.1 jmcneill int bwfm_init(struct ifnet *);
59 1.1 jmcneill void bwfm_stop(struct ifnet *, int);
60 1.1 jmcneill void bwfm_watchdog(struct ifnet *);
61 1.1 jmcneill int bwfm_ioctl(struct ifnet *, u_long, void *);
62 1.1 jmcneill int bwfm_media_change(struct ifnet *);
63 1.1 jmcneill void bwfm_media_status(struct ifnet *, struct ifmediareq *);
64 1.1 jmcneill
65 1.1 jmcneill int bwfm_send_mgmt(struct ieee80211com *, struct ieee80211_node *,
66 1.1 jmcneill int, int);
67 1.1 jmcneill void bwfm_recv_mgmt(struct ieee80211com *, struct mbuf *,
68 1.1 jmcneill struct ieee80211_node *, int, int, uint32_t);
69 1.1 jmcneill int bwfm_key_set(struct ieee80211com *, const struct ieee80211_key *,
70 1.1 jmcneill const uint8_t *);
71 1.1 jmcneill int bwfm_key_delete(struct ieee80211com *, const struct ieee80211_key *);
72 1.1 jmcneill int bwfm_newstate(struct ieee80211com *, enum ieee80211_state, int);
73 1.1 jmcneill void bwfm_newstate_cb(struct bwfm_softc *, struct bwfm_cmd_newstate *);
74 1.1 jmcneill void bwfm_task(struct work *, void *);
75 1.1 jmcneill
76 1.1 jmcneill int bwfm_chip_attach(struct bwfm_softc *);
77 1.1 jmcneill int bwfm_chip_detach(struct bwfm_softc *, int);
78 1.1 jmcneill struct bwfm_core *bwfm_chip_get_core(struct bwfm_softc *, int);
79 1.1 jmcneill struct bwfm_core *bwfm_chip_get_pmu(struct bwfm_softc *);
80 1.1 jmcneill int bwfm_chip_ai_isup(struct bwfm_softc *, struct bwfm_core *);
81 1.1 jmcneill void bwfm_chip_ai_disable(struct bwfm_softc *, struct bwfm_core *,
82 1.1 jmcneill uint32_t, uint32_t);
83 1.1 jmcneill void bwfm_chip_ai_reset(struct bwfm_softc *, struct bwfm_core *,
84 1.1 jmcneill uint32_t, uint32_t, uint32_t);
85 1.1 jmcneill void bwfm_chip_dmp_erom_scan(struct bwfm_softc *);
86 1.1 jmcneill int bwfm_chip_dmp_get_regaddr(struct bwfm_softc *, uint32_t *,
87 1.1 jmcneill uint32_t *, uint32_t *);
88 1.1 jmcneill void bwfm_chip_cr4_set_passive(struct bwfm_softc *);
89 1.1 jmcneill void bwfm_chip_ca7_set_passive(struct bwfm_softc *);
90 1.1 jmcneill void bwfm_chip_cm3_set_passive(struct bwfm_softc *);
91 1.1 jmcneill
92 1.1 jmcneill int bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *, int,
93 1.1 jmcneill int, char *, size_t *);
94 1.1 jmcneill int bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *, int,
95 1.1 jmcneill int, char *, size_t);
96 1.1 jmcneill
97 1.1 jmcneill int bwfm_fwvar_cmd_get_data(struct bwfm_softc *, int, void *, size_t);
98 1.1 jmcneill int bwfm_fwvar_cmd_set_data(struct bwfm_softc *, int, void *, size_t);
99 1.1 jmcneill int bwfm_fwvar_cmd_get_int(struct bwfm_softc *, int, uint32_t *);
100 1.1 jmcneill int bwfm_fwvar_cmd_set_int(struct bwfm_softc *, int, uint32_t);
101 1.1 jmcneill int bwfm_fwvar_var_get_data(struct bwfm_softc *, const char *, void *, size_t);
102 1.1 jmcneill int bwfm_fwvar_var_set_data(struct bwfm_softc *, const char *, void *, size_t);
103 1.1 jmcneill int bwfm_fwvar_var_get_int(struct bwfm_softc *, const char *, uint32_t *);
104 1.1 jmcneill int bwfm_fwvar_var_set_int(struct bwfm_softc *, const char *, uint32_t);
105 1.1 jmcneill
106 1.1 jmcneill struct ieee80211_channel *bwfm_bss2chan(struct bwfm_softc *, struct bwfm_bss_info *);
107 1.1 jmcneill void bwfm_scan(struct bwfm_softc *);
108 1.1 jmcneill void bwfm_connect(struct bwfm_softc *);
109 1.1 jmcneill
110 1.1 jmcneill void bwfm_rx(struct bwfm_softc *, char *, size_t);
111 1.1 jmcneill void bwfm_rx_event(struct bwfm_softc *, char *, size_t);
112 1.1 jmcneill void bwfm_scan_node(struct bwfm_softc *, struct bwfm_bss_info *, size_t);
113 1.1 jmcneill
114 1.1 jmcneill uint8_t bwfm_2ghz_channels[] = {
115 1.1 jmcneill 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
116 1.1 jmcneill };
117 1.1 jmcneill uint8_t bwfm_5ghz_channels[] = {
118 1.1 jmcneill 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, 100, 104, 108, 112,
119 1.1 jmcneill 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165,
120 1.1 jmcneill };
121 1.1 jmcneill
122 1.1 jmcneill struct bwfm_proto_ops bwfm_proto_bcdc_ops = {
123 1.1 jmcneill .proto_query_dcmd = bwfm_proto_bcdc_query_dcmd,
124 1.1 jmcneill .proto_set_dcmd = bwfm_proto_bcdc_set_dcmd,
125 1.1 jmcneill };
126 1.1 jmcneill
127 1.1 jmcneill void
128 1.1 jmcneill bwfm_attach(struct bwfm_softc *sc)
129 1.1 jmcneill {
130 1.1 jmcneill struct ieee80211com *ic = &sc->sc_ic;
131 1.1 jmcneill struct ifnet *ifp = &sc->sc_if;
132 1.1 jmcneill struct bwfm_task *t;
133 1.1 jmcneill char fw_version[BWFM_DCMD_SMLEN];
134 1.1 jmcneill uint32_t bandlist[3];
135 1.1 jmcneill uint32_t tmp;
136 1.1 jmcneill int i, error;
137 1.1 jmcneill
138 1.1 jmcneill error = workqueue_create(&sc->sc_taskq, DEVNAME(sc),
139 1.1 jmcneill bwfm_task, sc, PRI_NONE, IPL_NET, 0);
140 1.1 jmcneill if (error != 0) {
141 1.1 jmcneill printf("%s: could not create workqueue\n", DEVNAME(sc));
142 1.1 jmcneill return;
143 1.1 jmcneill }
144 1.1 jmcneill sc->sc_freetask = pcq_create(BWFM_TASK_COUNT, KM_SLEEP);
145 1.1 jmcneill for (i = 0; i < BWFM_TASK_COUNT; i++) {
146 1.1 jmcneill t = &sc->sc_task[i];
147 1.1 jmcneill t->t_sc = sc;
148 1.1 jmcneill pcq_put(sc->sc_freetask, t);
149 1.1 jmcneill }
150 1.1 jmcneill
151 1.1 jmcneill if (bwfm_fwvar_cmd_get_int(sc, BWFM_C_GET_VERSION, &tmp)) {
152 1.1 jmcneill printf("%s: could not read io type\n", DEVNAME(sc));
153 1.1 jmcneill return;
154 1.1 jmcneill } else
155 1.1 jmcneill sc->sc_io_type = tmp;
156 1.1 jmcneill if (bwfm_fwvar_var_get_data(sc, "cur_etheraddr", ic->ic_myaddr,
157 1.1 jmcneill sizeof(ic->ic_myaddr))) {
158 1.1 jmcneill printf("%s: could not read mac address\n", DEVNAME(sc));
159 1.1 jmcneill return;
160 1.1 jmcneill }
161 1.1 jmcneill
162 1.1 jmcneill memset(fw_version, 0, sizeof(fw_version));
163 1.1 jmcneill if (bwfm_fwvar_var_get_data(sc, "ver", fw_version, sizeof(fw_version)) == 0)
164 1.1 jmcneill printf("%s: %s", DEVNAME(sc), fw_version);
165 1.1 jmcneill printf("%s: address %s\n", DEVNAME(sc), ether_sprintf(ic->ic_myaddr));
166 1.1 jmcneill
167 1.1 jmcneill ic->ic_ifp = ifp;
168 1.1 jmcneill ic->ic_phytype = IEEE80211_T_OFDM;
169 1.1 jmcneill ic->ic_opmode = IEEE80211_M_STA;
170 1.1 jmcneill ic->ic_state = IEEE80211_S_INIT;
171 1.1 jmcneill
172 1.1 jmcneill ic->ic_caps =
173 1.1 jmcneill IEEE80211_C_WEP |
174 1.1 jmcneill IEEE80211_C_TKIP |
175 1.1 jmcneill IEEE80211_C_AES |
176 1.1 jmcneill IEEE80211_C_AES_CCM |
177 1.1 jmcneill #if notyet
178 1.1 jmcneill IEEE80211_C_MONITOR | /* monitor mode suported */
179 1.1 jmcneill IEEE80211_C_IBSS |
180 1.1 jmcneill IEEE80211_C_TXPMGT |
181 1.1 jmcneill IEEE80211_C_WME |
182 1.1 jmcneill #endif
183 1.1 jmcneill IEEE80211_C_SHSLOT | /* short slot time supported */
184 1.1 jmcneill IEEE80211_C_SHPREAMBLE | /* short preamble supported */
185 1.1 jmcneill IEEE80211_C_WPA | /* 802.11i */
186 1.1 jmcneill /* IEEE80211_C_WPA_4WAY */0; /* WPA 4-way handshake in hw */
187 1.1 jmcneill
188 1.1 jmcneill /* IBSS channel undefined for now. */
189 1.1 jmcneill ic->ic_ibss_chan = &ic->ic_channels[0];
190 1.1 jmcneill
191 1.1 jmcneill if (bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_BANDLIST, bandlist,
192 1.1 jmcneill sizeof(bandlist))) {
193 1.1 jmcneill printf("%s: couldn't get supported band list\n", DEVNAME(sc));
194 1.1 jmcneill return;
195 1.1 jmcneill }
196 1.1 jmcneill const u_int nbands = le32toh(bandlist[0]);
197 1.1 jmcneill for (i = 1; i <= MIN(nbands, __arraycount(bandlist) - 1); i++) {
198 1.1 jmcneill switch (le32toh(bandlist[i])) {
199 1.1 jmcneill case BWFM_BAND_2G:
200 1.1 jmcneill ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
201 1.1 jmcneill ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
202 1.1 jmcneill
203 1.1 jmcneill for (i = 0; i < __arraycount(bwfm_2ghz_channels); i++) {
204 1.1 jmcneill uint8_t chan = bwfm_2ghz_channels[i];
205 1.1 jmcneill ic->ic_channels[chan].ic_freq =
206 1.1 jmcneill ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ);
207 1.1 jmcneill ic->ic_channels[chan].ic_flags =
208 1.1 jmcneill IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
209 1.1 jmcneill IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
210 1.1 jmcneill }
211 1.1 jmcneill break;
212 1.1 jmcneill case BWFM_BAND_5G:
213 1.1 jmcneill ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a;
214 1.1 jmcneill
215 1.1 jmcneill for (i = 0; i < __arraycount(bwfm_5ghz_channels); i++) {
216 1.1 jmcneill uint8_t chan = bwfm_5ghz_channels[i];
217 1.1 jmcneill ic->ic_channels[chan].ic_freq =
218 1.1 jmcneill ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ);
219 1.1 jmcneill ic->ic_channels[chan].ic_flags =
220 1.1 jmcneill IEEE80211_CHAN_A;
221 1.1 jmcneill }
222 1.1 jmcneill break;
223 1.1 jmcneill }
224 1.1 jmcneill }
225 1.1 jmcneill
226 1.1 jmcneill ifp->if_softc = sc;
227 1.1 jmcneill ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
228 1.1 jmcneill ifp->if_init = bwfm_init;
229 1.1 jmcneill ifp->if_ioctl = bwfm_ioctl;
230 1.1 jmcneill ifp->if_start = bwfm_start;
231 1.1 jmcneill ifp->if_watchdog = bwfm_watchdog;
232 1.1 jmcneill IFQ_SET_READY(&ifp->if_snd);
233 1.1 jmcneill memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
234 1.1 jmcneill
235 1.1 jmcneill if_initialize(ifp);
236 1.1 jmcneill ieee80211_ifattach(ic);
237 1.1 jmcneill ifp->if_percpuq = if_percpuq_create(ifp);
238 1.1 jmcneill if_deferred_start_init(ifp, NULL);
239 1.1 jmcneill if_register(ifp);
240 1.1 jmcneill
241 1.1 jmcneill sc->sc_newstate = ic->ic_newstate;
242 1.1 jmcneill ic->ic_newstate = bwfm_newstate;
243 1.1 jmcneill ic->ic_send_mgmt = bwfm_send_mgmt;
244 1.1 jmcneill ic->ic_recv_mgmt = bwfm_recv_mgmt;
245 1.1 jmcneill ic->ic_crypto.cs_key_set = bwfm_key_set;
246 1.1 jmcneill ic->ic_crypto.cs_key_delete = bwfm_key_delete;
247 1.1 jmcneill ieee80211_media_init(ic, bwfm_media_change, bwfm_media_status);
248 1.1 jmcneill
249 1.1 jmcneill ieee80211_announce(ic);
250 1.1 jmcneill
251 1.1 jmcneill sc->sc_if_attached = true;
252 1.1 jmcneill }
253 1.1 jmcneill
254 1.1 jmcneill int
255 1.1 jmcneill bwfm_detach(struct bwfm_softc *sc, int flags)
256 1.1 jmcneill {
257 1.1 jmcneill struct ieee80211com *ic = &sc->sc_ic;
258 1.1 jmcneill struct ifnet *ifp = ic->ic_ifp;
259 1.1 jmcneill
260 1.1 jmcneill if (sc->sc_if_attached) {
261 1.1 jmcneill bpf_detach(ifp);
262 1.1 jmcneill ieee80211_ifdetach(ic);
263 1.1 jmcneill if_detach(ifp);
264 1.1 jmcneill }
265 1.1 jmcneill
266 1.1 jmcneill if (sc->sc_taskq)
267 1.1 jmcneill workqueue_destroy(sc->sc_taskq);
268 1.1 jmcneill if (sc->sc_freetask)
269 1.1 jmcneill pcq_destroy(sc->sc_freetask);
270 1.1 jmcneill
271 1.1 jmcneill return 0;
272 1.1 jmcneill }
273 1.1 jmcneill
274 1.1 jmcneill void
275 1.1 jmcneill bwfm_start(struct ifnet *ifp)
276 1.1 jmcneill {
277 1.1 jmcneill struct bwfm_softc *sc = ifp->if_softc;
278 1.1 jmcneill struct ieee80211com *ic = &sc->sc_ic;
279 1.1 jmcneill struct mbuf *m;
280 1.1 jmcneill int error;
281 1.1 jmcneill
282 1.1 jmcneill if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
283 1.1 jmcneill return;
284 1.1 jmcneill
285 1.1 jmcneill /* TODO: return if no link? */
286 1.1 jmcneill
287 1.1 jmcneill for (;;) {
288 1.1 jmcneill struct ieee80211_node *ni;
289 1.1 jmcneill struct ether_header *eh;
290 1.1 jmcneill
291 1.1 jmcneill /* Discard management packets (fw handles this for us) */
292 1.1 jmcneill IF_DEQUEUE(&ic->ic_mgtq, m);
293 1.1 jmcneill if (m != NULL) {
294 1.1 jmcneill m_freem(m);
295 1.1 jmcneill continue;
296 1.1 jmcneill }
297 1.1 jmcneill
298 1.1 jmcneill IFQ_DEQUEUE(&ifp->if_snd, m);
299 1.1 jmcneill if (m == NULL)
300 1.1 jmcneill break;
301 1.1 jmcneill
302 1.1 jmcneill eh = mtod(m, struct ether_header *);
303 1.1 jmcneill ni = ieee80211_find_txnode(ic, eh->ether_dhost);
304 1.1 jmcneill if (ni == NULL) {
305 1.1 jmcneill ifp->if_oerrors++;
306 1.1 jmcneill m_freem(m);
307 1.1 jmcneill continue;
308 1.1 jmcneill }
309 1.1 jmcneill
310 1.1 jmcneill if (ieee80211_classify(ic, m, ni) != 0) {
311 1.1 jmcneill ifp->if_oerrors++;
312 1.1 jmcneill m_freem(m);
313 1.1 jmcneill ieee80211_free_node(ni);
314 1.1 jmcneill continue;
315 1.1 jmcneill }
316 1.1 jmcneill
317 1.1 jmcneill error = sc->sc_bus_ops->bs_txdata(sc, m);
318 1.1 jmcneill if (error == ENOBUFS) {
319 1.1 jmcneill IF_PREPEND(&ifp->if_snd, m);
320 1.1 jmcneill ifp->if_flags |= IFF_OACTIVE;
321 1.1 jmcneill break;
322 1.1 jmcneill }
323 1.1 jmcneill
324 1.1 jmcneill if (error != 0) {
325 1.1 jmcneill ifp->if_oerrors++;
326 1.1 jmcneill m_freem(m);
327 1.1 jmcneill if (ni != NULL)
328 1.1 jmcneill ieee80211_free_node(ni);
329 1.1 jmcneill } else {
330 1.1 jmcneill bpf_mtap3(ic->ic_rawbpf, m);
331 1.1 jmcneill }
332 1.1 jmcneill }
333 1.1 jmcneill }
334 1.1 jmcneill
335 1.1 jmcneill int
336 1.1 jmcneill bwfm_init(struct ifnet *ifp)
337 1.1 jmcneill {
338 1.1 jmcneill struct bwfm_softc *sc = ifp->if_softc;
339 1.1 jmcneill struct ieee80211com *ic = &sc->sc_ic;
340 1.1 jmcneill uint8_t evmask[BWFM_EVENT_MASK_LEN];
341 1.1 jmcneill struct bwfm_join_pref_params join_pref[2];
342 1.1 jmcneill
343 1.1 jmcneill if (bwfm_fwvar_var_set_int(sc, "mpc", 1)) {
344 1.1 jmcneill printf("%s: could not set mpc\n", DEVNAME(sc));
345 1.1 jmcneill return EIO;
346 1.1 jmcneill }
347 1.1 jmcneill
348 1.1 jmcneill /* Select target by RSSI (boost on 5GHz) */
349 1.1 jmcneill join_pref[0].type = BWFM_JOIN_PREF_RSSI_DELTA;
350 1.1 jmcneill join_pref[0].len = 2;
351 1.1 jmcneill join_pref[0].rssi_gain = BWFM_JOIN_PREF_RSSI_BOOST;
352 1.1 jmcneill join_pref[0].band = BWFM_JOIN_PREF_BAND_5G;
353 1.1 jmcneill join_pref[1].type = BWFM_JOIN_PREF_RSSI;
354 1.1 jmcneill join_pref[1].len = 2;
355 1.1 jmcneill join_pref[1].rssi_gain = 0;
356 1.1 jmcneill join_pref[1].band = 0;
357 1.1 jmcneill if (bwfm_fwvar_var_set_data(sc, "join_pref", join_pref,
358 1.1 jmcneill sizeof(join_pref))) {
359 1.1 jmcneill printf("%s: could not set join pref\n", DEVNAME(sc));
360 1.1 jmcneill return EIO;
361 1.1 jmcneill }
362 1.1 jmcneill
363 1.1 jmcneill memset(evmask, 0, sizeof(evmask));
364 1.1 jmcneill
365 1.1 jmcneill #define ENABLE_EVENT(e) evmask[(e) / 8] |= 1 << ((e) % 8)
366 1.1 jmcneill /* Events used to drive the state machine */
367 1.1 jmcneill ENABLE_EVENT(BWFM_E_ASSOC);
368 1.1 jmcneill ENABLE_EVENT(BWFM_E_ESCAN_RESULT);
369 1.1 jmcneill ENABLE_EVENT(BWFM_E_SET_SSID);
370 1.1 jmcneill ENABLE_EVENT(BWFM_E_LINK);
371 1.1 jmcneill #undef ENABLE_EVENT
372 1.1 jmcneill
373 1.1 jmcneill #ifdef BWFM_DEBUG
374 1.1 jmcneill memset(evmask, 0xff, sizeof(evmask));
375 1.1 jmcneill #endif
376 1.1 jmcneill
377 1.1 jmcneill if (bwfm_fwvar_var_set_data(sc, "event_msgs", evmask, sizeof(evmask))) {
378 1.1 jmcneill printf("%s: could not set event mask\n", DEVNAME(sc));
379 1.1 jmcneill return EIO;
380 1.1 jmcneill }
381 1.1 jmcneill
382 1.1 jmcneill if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_CHANNEL_TIME,
383 1.1 jmcneill BWFM_DEFAULT_SCAN_CHANNEL_TIME)) {
384 1.1 jmcneill printf("%s: could not set scan channel time\n", DEVNAME(sc));
385 1.1 jmcneill return EIO;
386 1.1 jmcneill }
387 1.1 jmcneill if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_UNASSOC_TIME,
388 1.1 jmcneill BWFM_DEFAULT_SCAN_UNASSOC_TIME)) {
389 1.1 jmcneill printf("%s: could not set scan unassoc time\n", DEVNAME(sc));
390 1.1 jmcneill return EIO;
391 1.1 jmcneill }
392 1.1 jmcneill if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_SCAN_PASSIVE_TIME,
393 1.1 jmcneill BWFM_DEFAULT_SCAN_PASSIVE_TIME)) {
394 1.1 jmcneill printf("%s: could not set scan passive time\n", DEVNAME(sc));
395 1.1 jmcneill return EIO;
396 1.1 jmcneill }
397 1.1 jmcneill
398 1.1 jmcneill if (bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, 2)) {
399 1.1 jmcneill printf("%s: could not set power\n", DEVNAME(sc));
400 1.1 jmcneill return EIO;
401 1.1 jmcneill }
402 1.1 jmcneill
403 1.1 jmcneill bwfm_fwvar_var_set_int(sc, "txbf", 1);
404 1.1 jmcneill bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 0);
405 1.1 jmcneill bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 1);
406 1.1 jmcneill bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0);
407 1.1 jmcneill
408 1.1 jmcneill /* Disable all offloading (ARP, NDP, TCP/UDP cksum). */
409 1.1 jmcneill bwfm_fwvar_var_set_int(sc, "arp_ol", 0);
410 1.1 jmcneill bwfm_fwvar_var_set_int(sc, "arpoe", 0);
411 1.1 jmcneill bwfm_fwvar_var_set_int(sc, "ndoe", 0);
412 1.1 jmcneill bwfm_fwvar_var_set_int(sc, "toe", 0);
413 1.1 jmcneill
414 1.1 jmcneill /*
415 1.1 jmcneill * Tell the firmware supplicant that we are going to handle the
416 1.1 jmcneill * WPA handshake ourselves.
417 1.1 jmcneill */
418 1.1 jmcneill bwfm_fwvar_var_set_int(sc, "sup_wpa", 0);
419 1.1 jmcneill
420 1.1 jmcneill ifp->if_flags |= IFF_RUNNING;
421 1.1 jmcneill ifp->if_flags &= ~IFF_OACTIVE;
422 1.1 jmcneill
423 1.1 jmcneill if (ic->ic_opmode != IEEE80211_M_MONITOR) {
424 1.1 jmcneill if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
425 1.1 jmcneill ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
426 1.1 jmcneill } else {
427 1.1 jmcneill ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
428 1.1 jmcneill }
429 1.1 jmcneill
430 1.1 jmcneill return 0;
431 1.1 jmcneill }
432 1.1 jmcneill
433 1.1 jmcneill void
434 1.1 jmcneill bwfm_stop(struct ifnet *ifp, int disable)
435 1.1 jmcneill {
436 1.1 jmcneill struct bwfm_softc *sc = ifp->if_softc;
437 1.1 jmcneill struct ieee80211com *ic = &sc->sc_ic;
438 1.1 jmcneill
439 1.1 jmcneill sc->sc_tx_timer = 0;
440 1.1 jmcneill ifp->if_timer = 0;
441 1.1 jmcneill ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
442 1.1 jmcneill
443 1.1 jmcneill bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1);
444 1.1 jmcneill bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, 0);
445 1.1 jmcneill
446 1.1 jmcneill ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
447 1.1 jmcneill }
448 1.1 jmcneill
449 1.1 jmcneill void
450 1.1 jmcneill bwfm_watchdog(struct ifnet *ifp)
451 1.1 jmcneill {
452 1.1 jmcneill struct bwfm_softc *sc = ifp->if_softc;
453 1.1 jmcneill struct ieee80211com *ic = &sc->sc_ic;
454 1.1 jmcneill
455 1.1 jmcneill ifp->if_timer = 0;
456 1.1 jmcneill
457 1.1 jmcneill if (sc->sc_tx_timer > 0) {
458 1.1 jmcneill if (--sc->sc_tx_timer == 0) {
459 1.1 jmcneill printf("%s: device timeout\n", DEVNAME(sc));
460 1.1 jmcneill ifp->if_oerrors++;
461 1.1 jmcneill return;
462 1.1 jmcneill }
463 1.1 jmcneill ifp->if_timer = 1;
464 1.1 jmcneill }
465 1.1 jmcneill ieee80211_watchdog(ic);
466 1.1 jmcneill }
467 1.1 jmcneill
468 1.1 jmcneill int
469 1.1 jmcneill bwfm_ioctl(struct ifnet *ifp, u_long cmd, void *data)
470 1.1 jmcneill {
471 1.1 jmcneill struct bwfm_softc *sc = ifp->if_softc;
472 1.1 jmcneill struct ieee80211com *ic = &sc->sc_ic;
473 1.1 jmcneill int s, error = 0;
474 1.1 jmcneill
475 1.1 jmcneill s = splnet();
476 1.1 jmcneill
477 1.1 jmcneill switch (cmd) {
478 1.1 jmcneill case SIOCSIFFLAGS:
479 1.1 jmcneill if ((error = ifioctl_common(ifp, cmd, data)) != 0)
480 1.1 jmcneill break;
481 1.1 jmcneill switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
482 1.1 jmcneill case IFF_UP | IFF_RUNNING:
483 1.1 jmcneill break;
484 1.1 jmcneill case IFF_UP:
485 1.1 jmcneill bwfm_init(ifp);
486 1.1 jmcneill break;
487 1.1 jmcneill case IFF_RUNNING:
488 1.1 jmcneill bwfm_stop(ifp, 1);
489 1.1 jmcneill break;
490 1.1 jmcneill case 0:
491 1.1 jmcneill break;
492 1.1 jmcneill }
493 1.1 jmcneill break;
494 1.1 jmcneill
495 1.1 jmcneill case SIOCADDMULTI:
496 1.1 jmcneill case SIOCDELMULTI:
497 1.1 jmcneill if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
498 1.1 jmcneill /* setup multicast filter, etc */
499 1.1 jmcneill error = 0;
500 1.1 jmcneill }
501 1.1 jmcneill break;
502 1.1 jmcneill
503 1.1 jmcneill default:
504 1.1 jmcneill error = ieee80211_ioctl(ic, cmd, data);
505 1.1 jmcneill }
506 1.1 jmcneill
507 1.1 jmcneill if (error == ENETRESET) {
508 1.1 jmcneill if ((ifp->if_flags & IFF_UP) != 0 &&
509 1.1 jmcneill (ifp->if_flags & IFF_RUNNING) != 0 &&
510 1.1 jmcneill ic->ic_roaming != IEEE80211_ROAMING_MANUAL) {
511 1.1 jmcneill bwfm_init(ifp);
512 1.1 jmcneill }
513 1.1 jmcneill error = 0;
514 1.1 jmcneill }
515 1.1 jmcneill
516 1.1 jmcneill splx(s);
517 1.1 jmcneill
518 1.1 jmcneill return error;
519 1.1 jmcneill }
520 1.1 jmcneill
521 1.1 jmcneill int
522 1.1 jmcneill bwfm_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
523 1.1 jmcneill int type, int arg)
524 1.1 jmcneill {
525 1.1 jmcneill return 0;
526 1.1 jmcneill }
527 1.1 jmcneill
528 1.1 jmcneill void
529 1.1 jmcneill bwfm_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
530 1.1 jmcneill struct ieee80211_node *ni, int subtype, int rssi, uint32_t rstamp)
531 1.1 jmcneill {
532 1.1 jmcneill }
533 1.1 jmcneill
534 1.1 jmcneill int
535 1.1 jmcneill bwfm_key_set(struct ieee80211com *ic, const struct ieee80211_key *wk,
536 1.1 jmcneill const uint8_t mac[IEEE80211_ADDR_LEN])
537 1.1 jmcneill {
538 1.1 jmcneill struct bwfm_softc *sc = ic->ic_ifp->if_softc;
539 1.1 jmcneill struct bwfm_task *t;
540 1.1 jmcneill
541 1.1 jmcneill t = pcq_get(sc->sc_freetask);
542 1.1 jmcneill if (t == NULL) {
543 1.1 jmcneill printf("%s: no free tasks\n", DEVNAME(sc));
544 1.1 jmcneill return 0;
545 1.1 jmcneill }
546 1.1 jmcneill
547 1.1 jmcneill t->t_cmd = BWFM_TASK_KEY_SET;
548 1.1 jmcneill t->t_key.key = wk;
549 1.1 jmcneill memcpy(t->t_key.mac, mac, sizeof(t->t_key.mac));
550 1.1 jmcneill workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL);
551 1.1 jmcneill return 1;
552 1.1 jmcneill }
553 1.1 jmcneill
554 1.1 jmcneill static void
555 1.1 jmcneill bwfm_key_set_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck)
556 1.1 jmcneill {
557 1.1 jmcneill const struct ieee80211_key *wk = ck->key;
558 1.1 jmcneill const uint8_t *mac = ck->mac;
559 1.1 jmcneill struct bwfm_wsec_key wsec_key;
560 1.1 jmcneill uint32_t wsec_enable, wsec;
561 1.1 jmcneill bool ext_key;
562 1.1 jmcneill
563 1.1 jmcneill #ifdef BWFM_DEBUG
564 1.1 jmcneill printf("key_set: key cipher %s len %d: ", wk->wk_cipher->ic_name, wk->wk_keylen);
565 1.1 jmcneill for (int j = 0; j < sizeof(wk->wk_key); j++)
566 1.1 jmcneill printf("%02x", wk->wk_key[j]);
567 1.1 jmcneill #endif
568 1.1 jmcneill
569 1.1 jmcneill if ((wk->wk_flags & IEEE80211_KEY_GROUP) == 0 &&
570 1.1 jmcneill wk->wk_cipher->ic_cipher != IEEE80211_CIPHER_WEP) {
571 1.1 jmcneill ext_key = true;
572 1.1 jmcneill } else {
573 1.1 jmcneill ext_key = false;
574 1.1 jmcneill }
575 1.1 jmcneill
576 1.1 jmcneill #ifdef BWFM_DEBUG
577 1.1 jmcneill printf(", ext_key = %d", ext_key);
578 1.1 jmcneill printf(", mac = %02x:%02x:%02x:%02x:%02x:%02x",
579 1.1 jmcneill mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
580 1.1 jmcneill printf("\n");
581 1.1 jmcneill #endif
582 1.1 jmcneill
583 1.1 jmcneill memset(&wsec_key, 0, sizeof(wsec_key));
584 1.1 jmcneill if (ext_key && !IEEE80211_IS_MULTICAST(mac))
585 1.1 jmcneill memcpy(wsec_key.ea, mac, sizeof(wsec_key.ea));
586 1.1 jmcneill wsec_key.index = htole32(wk->wk_keyix);
587 1.1 jmcneill wsec_key.len = htole32(wk->wk_keylen);
588 1.1 jmcneill memcpy(wsec_key.data, wk->wk_key, sizeof(wsec_key.data));
589 1.1 jmcneill if (!ext_key)
590 1.1 jmcneill wsec_key.flags = htole32(BWFM_PRIMARY_KEY);
591 1.1 jmcneill
592 1.1 jmcneill switch (wk->wk_cipher->ic_cipher) {
593 1.1 jmcneill case IEEE80211_CIPHER_WEP:
594 1.1 jmcneill if (wk->wk_keylen == 5)
595 1.1 jmcneill wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP1);
596 1.1 jmcneill else if (wk->wk_keylen == 13)
597 1.1 jmcneill wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_WEP128);
598 1.1 jmcneill else
599 1.1 jmcneill return;
600 1.1 jmcneill wsec_enable = BWFM_WSEC_WEP;
601 1.1 jmcneill break;
602 1.1 jmcneill case IEEE80211_CIPHER_TKIP:
603 1.1 jmcneill wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_TKIP);
604 1.1 jmcneill wsec_enable = BWFM_WSEC_TKIP;
605 1.1 jmcneill break;
606 1.1 jmcneill case IEEE80211_CIPHER_AES_CCM:
607 1.1 jmcneill wsec_key.algo = htole32(BWFM_CRYPTO_ALGO_AES_CCM);
608 1.1 jmcneill wsec_enable = BWFM_WSEC_AES;
609 1.1 jmcneill break;
610 1.1 jmcneill default:
611 1.1 jmcneill printf("%s: %s: cipher %s not supported\n", DEVNAME(sc),
612 1.1 jmcneill __func__, wk->wk_cipher->ic_name);
613 1.1 jmcneill return;
614 1.1 jmcneill }
615 1.1 jmcneill
616 1.1 jmcneill if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key)))
617 1.1 jmcneill return;
618 1.1 jmcneill
619 1.1 jmcneill bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_WPA2_PSK);
620 1.1 jmcneill
621 1.1 jmcneill bwfm_fwvar_var_get_int(sc, "wsec", &wsec);
622 1.1 jmcneill wsec |= wsec_enable;
623 1.1 jmcneill bwfm_fwvar_var_set_int(sc, "wsec", wsec);
624 1.1 jmcneill }
625 1.1 jmcneill
626 1.1 jmcneill int
627 1.1 jmcneill bwfm_key_delete(struct ieee80211com *ic, const struct ieee80211_key *wk)
628 1.1 jmcneill {
629 1.1 jmcneill struct bwfm_softc *sc = ic->ic_ifp->if_softc;
630 1.1 jmcneill struct bwfm_task *t;
631 1.1 jmcneill
632 1.1 jmcneill t = pcq_get(sc->sc_freetask);
633 1.1 jmcneill if (t == NULL) {
634 1.1 jmcneill printf("%s: no free tasks\n", DEVNAME(sc));
635 1.1 jmcneill return 0;
636 1.1 jmcneill }
637 1.1 jmcneill
638 1.1 jmcneill t->t_cmd = BWFM_TASK_KEY_DELETE;
639 1.1 jmcneill t->t_key.key = wk;
640 1.1 jmcneill memset(t->t_key.mac, 0, sizeof(t->t_key.mac));
641 1.1 jmcneill workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL);
642 1.1 jmcneill
643 1.1 jmcneill return 1;
644 1.1 jmcneill }
645 1.1 jmcneill
646 1.1 jmcneill static void
647 1.1 jmcneill bwfm_key_delete_cb(struct bwfm_softc *sc, struct bwfm_cmd_key *ck)
648 1.1 jmcneill {
649 1.1 jmcneill const struct ieee80211_key *wk = ck->key;
650 1.1 jmcneill struct bwfm_wsec_key wsec_key;
651 1.1 jmcneill
652 1.1 jmcneill memset(&wsec_key, 0, sizeof(wsec_key));
653 1.1 jmcneill wsec_key.index = htole32(wk->wk_keyix);
654 1.1 jmcneill wsec_key.flags = htole32(BWFM_PRIMARY_KEY);
655 1.1 jmcneill
656 1.1 jmcneill if (bwfm_fwvar_var_set_data(sc, "wsec_key", &wsec_key, sizeof(wsec_key)))
657 1.1 jmcneill return;
658 1.1 jmcneill }
659 1.1 jmcneill
660 1.1 jmcneill int
661 1.1 jmcneill bwfm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
662 1.1 jmcneill {
663 1.1 jmcneill struct bwfm_softc *sc = ic->ic_ifp->if_softc;
664 1.1 jmcneill struct bwfm_task *t;
665 1.1 jmcneill
666 1.1 jmcneill t = pcq_get(sc->sc_freetask);
667 1.1 jmcneill if (t == NULL) {
668 1.1 jmcneill printf("%s: no free tasks\n", DEVNAME(sc));
669 1.1 jmcneill return EIO;
670 1.1 jmcneill }
671 1.1 jmcneill
672 1.1 jmcneill t->t_cmd = BWFM_TASK_NEWSTATE;
673 1.1 jmcneill t->t_newstate.state = nstate;
674 1.1 jmcneill t->t_newstate.arg = arg;
675 1.1 jmcneill workqueue_enqueue(sc->sc_taskq, (struct work *)t, NULL);
676 1.1 jmcneill
677 1.1 jmcneill return 0;
678 1.1 jmcneill }
679 1.1 jmcneill
680 1.1 jmcneill void
681 1.1 jmcneill bwfm_newstate_cb(struct bwfm_softc *sc, struct bwfm_cmd_newstate *cmd)
682 1.1 jmcneill {
683 1.1 jmcneill struct ieee80211com *ic = &sc->sc_ic;
684 1.1 jmcneill enum ieee80211_state ostate = ic->ic_state;
685 1.1 jmcneill enum ieee80211_state nstate = cmd->state;
686 1.1 jmcneill int s;
687 1.1 jmcneill
688 1.1 jmcneill DPRINTF(("%s: newstate %d -> %d\n", DEVNAME(sc), ostate, nstate));
689 1.1 jmcneill
690 1.1 jmcneill s = splnet();
691 1.1 jmcneill
692 1.1 jmcneill switch (nstate) {
693 1.1 jmcneill case IEEE80211_S_INIT:
694 1.1 jmcneill break;
695 1.1 jmcneill
696 1.1 jmcneill case IEEE80211_S_SCAN:
697 1.1 jmcneill if (ostate != IEEE80211_S_SCAN) {
698 1.1 jmcneill /* Start of scanning */
699 1.1 jmcneill bwfm_scan(sc);
700 1.1 jmcneill }
701 1.1 jmcneill break;
702 1.1 jmcneill
703 1.1 jmcneill case IEEE80211_S_AUTH:
704 1.1 jmcneill bwfm_connect(sc);
705 1.1 jmcneill break;
706 1.1 jmcneill
707 1.1 jmcneill case IEEE80211_S_ASSOC:
708 1.1 jmcneill break;
709 1.1 jmcneill
710 1.1 jmcneill case IEEE80211_S_RUN:
711 1.1 jmcneill break;
712 1.1 jmcneill }
713 1.1 jmcneill
714 1.1 jmcneill sc->sc_newstate(ic, nstate, cmd->arg);
715 1.1 jmcneill
716 1.1 jmcneill splx(s);
717 1.1 jmcneill }
718 1.1 jmcneill
719 1.1 jmcneill void
720 1.1 jmcneill bwfm_task(struct work *wk, void *arg)
721 1.1 jmcneill {
722 1.1 jmcneill struct bwfm_task *t = (struct bwfm_task *)wk;
723 1.1 jmcneill struct bwfm_softc *sc = t->t_sc;
724 1.1 jmcneill
725 1.1 jmcneill switch (t->t_cmd) {
726 1.1 jmcneill case BWFM_TASK_NEWSTATE:
727 1.1 jmcneill bwfm_newstate_cb(sc, &t->t_newstate);
728 1.1 jmcneill break;
729 1.1 jmcneill case BWFM_TASK_KEY_SET:
730 1.1 jmcneill bwfm_key_set_cb(sc, &t->t_key);
731 1.1 jmcneill break;
732 1.1 jmcneill case BWFM_TASK_KEY_DELETE:
733 1.1 jmcneill bwfm_key_delete_cb(sc, &t->t_key);
734 1.1 jmcneill break;
735 1.1 jmcneill default:
736 1.1 jmcneill panic("bwfm: unknown task command %d", t->t_cmd);
737 1.1 jmcneill }
738 1.1 jmcneill
739 1.1 jmcneill pcq_put(sc->sc_freetask, t);
740 1.1 jmcneill }
741 1.1 jmcneill
742 1.1 jmcneill int
743 1.1 jmcneill bwfm_media_change(struct ifnet *ifp)
744 1.1 jmcneill {
745 1.1 jmcneill return 0;
746 1.1 jmcneill }
747 1.1 jmcneill
748 1.1 jmcneill void
749 1.1 jmcneill bwfm_media_status(struct ifnet *ifp, struct ifmediareq *imr)
750 1.1 jmcneill {
751 1.1 jmcneill }
752 1.1 jmcneill
753 1.1 jmcneill /* Chip initialization (SDIO, PCIe) */
754 1.1 jmcneill int
755 1.1 jmcneill bwfm_chip_attach(struct bwfm_softc *sc)
756 1.1 jmcneill {
757 1.1 jmcneill struct bwfm_core *core;
758 1.1 jmcneill int need_socram = 0;
759 1.1 jmcneill int has_socram = 0;
760 1.1 jmcneill int cpu_found = 0;
761 1.1 jmcneill uint32_t val;
762 1.1 jmcneill
763 1.1 jmcneill LIST_INIT(&sc->sc_chip.ch_list);
764 1.1 jmcneill
765 1.1 jmcneill if (sc->sc_buscore_ops->bc_prepare(sc) != 0) {
766 1.1 jmcneill printf("%s: failed buscore prepare\n", DEVNAME(sc));
767 1.1 jmcneill return 1;
768 1.1 jmcneill }
769 1.1 jmcneill
770 1.1 jmcneill val = sc->sc_buscore_ops->bc_read(sc,
771 1.1 jmcneill BWFM_CHIP_BASE + BWFM_CHIP_REG_CHIPID);
772 1.1 jmcneill sc->sc_chip.ch_chip = BWFM_CHIP_CHIPID_ID(val);
773 1.1 jmcneill sc->sc_chip.ch_chiprev = BWFM_CHIP_CHIPID_REV(val);
774 1.1 jmcneill
775 1.1 jmcneill if ((sc->sc_chip.ch_chip > 0xa000) || (sc->sc_chip.ch_chip < 0x4000))
776 1.1 jmcneill snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name),
777 1.1 jmcneill "%d", sc->sc_chip.ch_chip);
778 1.1 jmcneill else
779 1.1 jmcneill snprintf(sc->sc_chip.ch_name, sizeof(sc->sc_chip.ch_name),
780 1.1 jmcneill "%x", sc->sc_chip.ch_chip);
781 1.1 jmcneill
782 1.1 jmcneill switch (BWFM_CHIP_CHIPID_TYPE(val))
783 1.1 jmcneill {
784 1.1 jmcneill case BWFM_CHIP_CHIPID_TYPE_SOCI_SB:
785 1.1 jmcneill printf("%s: SoC interconnect SB not implemented\n",
786 1.1 jmcneill DEVNAME(sc));
787 1.1 jmcneill return 1;
788 1.1 jmcneill case BWFM_CHIP_CHIPID_TYPE_SOCI_AI:
789 1.1 jmcneill sc->sc_chip.ch_core_isup = bwfm_chip_ai_isup;
790 1.1 jmcneill sc->sc_chip.ch_core_disable = bwfm_chip_ai_disable;
791 1.1 jmcneill sc->sc_chip.ch_core_reset = bwfm_chip_ai_reset;
792 1.1 jmcneill bwfm_chip_dmp_erom_scan(sc);
793 1.1 jmcneill break;
794 1.1 jmcneill default:
795 1.1 jmcneill printf("%s: SoC interconnect %d unknown\n",
796 1.1 jmcneill DEVNAME(sc), BWFM_CHIP_CHIPID_TYPE(val));
797 1.1 jmcneill return 1;
798 1.1 jmcneill }
799 1.1 jmcneill
800 1.1 jmcneill LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) {
801 1.1 jmcneill DPRINTF(("%s: 0x%x:%-2d base 0x%08x wrap 0x%08x\n",
802 1.1 jmcneill DEVNAME(sc), core->co_id, core->co_rev,
803 1.1 jmcneill core->co_base, core->co_wrapbase));
804 1.1 jmcneill
805 1.1 jmcneill switch (core->co_id) {
806 1.1 jmcneill case BWFM_AGENT_CORE_ARM_CM3:
807 1.1 jmcneill need_socram = true;
808 1.1 jmcneill /* FALLTHROUGH */
809 1.1 jmcneill case BWFM_AGENT_CORE_ARM_CR4:
810 1.1 jmcneill case BWFM_AGENT_CORE_ARM_CA7:
811 1.1 jmcneill cpu_found = true;
812 1.1 jmcneill break;
813 1.1 jmcneill case BWFM_AGENT_INTERNAL_MEM:
814 1.1 jmcneill has_socram = true;
815 1.1 jmcneill break;
816 1.1 jmcneill default:
817 1.1 jmcneill break;
818 1.1 jmcneill }
819 1.1 jmcneill }
820 1.1 jmcneill
821 1.1 jmcneill if (!cpu_found) {
822 1.1 jmcneill printf("%s: CPU core not detected\n", DEVNAME(sc));
823 1.1 jmcneill return 1;
824 1.1 jmcneill }
825 1.1 jmcneill if (need_socram && !has_socram) {
826 1.1 jmcneill printf("%s: RAM core not provided\n", DEVNAME(sc));
827 1.1 jmcneill return 1;
828 1.1 jmcneill }
829 1.1 jmcneill
830 1.1 jmcneill if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL)
831 1.1 jmcneill bwfm_chip_cr4_set_passive(sc);
832 1.1 jmcneill if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL)
833 1.1 jmcneill bwfm_chip_ca7_set_passive(sc);
834 1.1 jmcneill if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL)
835 1.1 jmcneill bwfm_chip_cm3_set_passive(sc);
836 1.1 jmcneill
837 1.1 jmcneill if (sc->sc_buscore_ops->bc_reset) {
838 1.1 jmcneill sc->sc_buscore_ops->bc_reset(sc);
839 1.1 jmcneill if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CR4) != NULL)
840 1.1 jmcneill bwfm_chip_cr4_set_passive(sc);
841 1.1 jmcneill if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CA7) != NULL)
842 1.1 jmcneill bwfm_chip_ca7_set_passive(sc);
843 1.1 jmcneill if (bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3) != NULL)
844 1.1 jmcneill bwfm_chip_cm3_set_passive(sc);
845 1.1 jmcneill }
846 1.1 jmcneill
847 1.1 jmcneill /* TODO: get raminfo */
848 1.1 jmcneill
849 1.1 jmcneill core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
850 1.1 jmcneill sc->sc_chip.ch_cc_caps = sc->sc_buscore_ops->bc_read(sc,
851 1.1 jmcneill core->co_base + BWFM_CHIP_REG_CAPABILITIES);
852 1.1 jmcneill sc->sc_chip.ch_cc_caps_ext = sc->sc_buscore_ops->bc_read(sc,
853 1.1 jmcneill core->co_base + BWFM_CHIP_REG_CAPABILITIES_EXT);
854 1.1 jmcneill
855 1.1 jmcneill core = bwfm_chip_get_pmu(sc);
856 1.1 jmcneill if (sc->sc_chip.ch_cc_caps & BWFM_CHIP_REG_CAPABILITIES_PMU) {
857 1.1 jmcneill sc->sc_chip.ch_pmucaps = sc->sc_buscore_ops->bc_read(sc,
858 1.1 jmcneill core->co_base + BWFM_CHIP_REG_PMUCAPABILITIES);
859 1.1 jmcneill sc->sc_chip.ch_pmurev = sc->sc_chip.ch_pmucaps &
860 1.1 jmcneill BWFM_CHIP_REG_PMUCAPABILITIES_REV_MASK;
861 1.1 jmcneill }
862 1.1 jmcneill
863 1.1 jmcneill if (sc->sc_buscore_ops->bc_setup)
864 1.1 jmcneill sc->sc_buscore_ops->bc_setup(sc);
865 1.1 jmcneill
866 1.1 jmcneill return 0;
867 1.1 jmcneill }
868 1.1 jmcneill
869 1.1 jmcneill struct bwfm_core *
870 1.1 jmcneill bwfm_chip_get_core(struct bwfm_softc *sc, int id)
871 1.1 jmcneill {
872 1.1 jmcneill struct bwfm_core *core;
873 1.1 jmcneill
874 1.1 jmcneill LIST_FOREACH(core, &sc->sc_chip.ch_list, co_link) {
875 1.1 jmcneill if (core->co_id == id)
876 1.1 jmcneill return core;
877 1.1 jmcneill }
878 1.1 jmcneill
879 1.1 jmcneill return NULL;
880 1.1 jmcneill }
881 1.1 jmcneill
882 1.1 jmcneill struct bwfm_core *
883 1.1 jmcneill bwfm_chip_get_pmu(struct bwfm_softc *sc)
884 1.1 jmcneill {
885 1.1 jmcneill struct bwfm_core *cc, *pmu;
886 1.1 jmcneill
887 1.1 jmcneill cc = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_CHIPCOMMON);
888 1.1 jmcneill if (cc->co_rev >= 35 && sc->sc_chip.ch_cc_caps_ext &
889 1.1 jmcneill BWFM_CHIP_REG_CAPABILITIES_EXT_AOB_PRESENT) {
890 1.1 jmcneill pmu = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_PMU);
891 1.1 jmcneill if (pmu)
892 1.1 jmcneill return pmu;
893 1.1 jmcneill }
894 1.1 jmcneill
895 1.1 jmcneill return cc;
896 1.1 jmcneill }
897 1.1 jmcneill
898 1.1 jmcneill /* Functions for the AI interconnect */
899 1.1 jmcneill int
900 1.1 jmcneill bwfm_chip_ai_isup(struct bwfm_softc *sc, struct bwfm_core *core)
901 1.1 jmcneill {
902 1.1 jmcneill uint32_t ioctl, reset;
903 1.1 jmcneill
904 1.1 jmcneill ioctl = sc->sc_buscore_ops->bc_read(sc,
905 1.1 jmcneill core->co_wrapbase + BWFM_AGENT_IOCTL);
906 1.1 jmcneill reset = sc->sc_buscore_ops->bc_read(sc,
907 1.1 jmcneill core->co_wrapbase + BWFM_AGENT_RESET_CTL);
908 1.1 jmcneill
909 1.1 jmcneill if (((ioctl & (BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK)) ==
910 1.1 jmcneill BWFM_AGENT_IOCTL_CLK) &&
911 1.1 jmcneill ((reset & BWFM_AGENT_RESET_CTL_RESET) == 0))
912 1.1 jmcneill return 1;
913 1.1 jmcneill
914 1.1 jmcneill return 0;
915 1.1 jmcneill }
916 1.1 jmcneill
917 1.1 jmcneill void
918 1.1 jmcneill bwfm_chip_ai_disable(struct bwfm_softc *sc, struct bwfm_core *core,
919 1.1 jmcneill uint32_t prereset, uint32_t reset)
920 1.1 jmcneill {
921 1.1 jmcneill uint32_t val;
922 1.1 jmcneill int i;
923 1.1 jmcneill
924 1.1 jmcneill val = sc->sc_buscore_ops->bc_read(sc,
925 1.1 jmcneill core->co_wrapbase + BWFM_AGENT_RESET_CTL);
926 1.1 jmcneill if ((val & BWFM_AGENT_RESET_CTL_RESET) == 0) {
927 1.1 jmcneill
928 1.1 jmcneill sc->sc_buscore_ops->bc_write(sc,
929 1.1 jmcneill core->co_wrapbase + BWFM_AGENT_IOCTL,
930 1.1 jmcneill prereset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK);
931 1.1 jmcneill sc->sc_buscore_ops->bc_read(sc,
932 1.1 jmcneill core->co_wrapbase + BWFM_AGENT_IOCTL);
933 1.1 jmcneill
934 1.1 jmcneill sc->sc_buscore_ops->bc_write(sc,
935 1.1 jmcneill core->co_wrapbase + BWFM_AGENT_RESET_CTL,
936 1.1 jmcneill BWFM_AGENT_RESET_CTL_RESET);
937 1.1 jmcneill delay(20);
938 1.1 jmcneill
939 1.1 jmcneill for (i = 300; i > 0; i--) {
940 1.1 jmcneill if (sc->sc_buscore_ops->bc_read(sc,
941 1.1 jmcneill core->co_wrapbase + BWFM_AGENT_RESET_CTL) ==
942 1.1 jmcneill BWFM_AGENT_RESET_CTL_RESET)
943 1.1 jmcneill break;
944 1.1 jmcneill }
945 1.1 jmcneill if (i == 0)
946 1.1 jmcneill printf("%s: timeout on core reset\n", DEVNAME(sc));
947 1.1 jmcneill }
948 1.1 jmcneill
949 1.1 jmcneill sc->sc_buscore_ops->bc_write(sc,
950 1.1 jmcneill core->co_wrapbase + BWFM_AGENT_IOCTL,
951 1.1 jmcneill reset | BWFM_AGENT_IOCTL_FGC | BWFM_AGENT_IOCTL_CLK);
952 1.1 jmcneill sc->sc_buscore_ops->bc_read(sc,
953 1.1 jmcneill core->co_wrapbase + BWFM_AGENT_IOCTL);
954 1.1 jmcneill }
955 1.1 jmcneill
956 1.1 jmcneill void
957 1.1 jmcneill bwfm_chip_ai_reset(struct bwfm_softc *sc, struct bwfm_core *core,
958 1.1 jmcneill uint32_t prereset, uint32_t reset, uint32_t postreset)
959 1.1 jmcneill {
960 1.1 jmcneill int i;
961 1.1 jmcneill
962 1.1 jmcneill bwfm_chip_ai_disable(sc, core, prereset, reset);
963 1.1 jmcneill
964 1.1 jmcneill for (i = 50; i > 0; i--) {
965 1.1 jmcneill if ((sc->sc_buscore_ops->bc_read(sc,
966 1.1 jmcneill core->co_wrapbase + BWFM_AGENT_RESET_CTL) &
967 1.1 jmcneill BWFM_AGENT_RESET_CTL_RESET) == 0)
968 1.1 jmcneill break;
969 1.1 jmcneill sc->sc_buscore_ops->bc_write(sc,
970 1.1 jmcneill core->co_wrapbase + BWFM_AGENT_RESET_CTL, 0);
971 1.1 jmcneill delay(60);
972 1.1 jmcneill }
973 1.1 jmcneill if (i == 0)
974 1.1 jmcneill printf("%s: timeout on core reset\n", DEVNAME(sc));
975 1.1 jmcneill
976 1.1 jmcneill sc->sc_buscore_ops->bc_write(sc,
977 1.1 jmcneill core->co_wrapbase + BWFM_AGENT_IOCTL,
978 1.1 jmcneill postreset | BWFM_AGENT_IOCTL_CLK);
979 1.1 jmcneill sc->sc_buscore_ops->bc_read(sc,
980 1.1 jmcneill core->co_wrapbase + BWFM_AGENT_IOCTL);
981 1.1 jmcneill }
982 1.1 jmcneill
983 1.1 jmcneill void
984 1.1 jmcneill bwfm_chip_dmp_erom_scan(struct bwfm_softc *sc)
985 1.1 jmcneill {
986 1.1 jmcneill uint32_t erom, val, base, wrap;
987 1.1 jmcneill uint8_t type = 0;
988 1.1 jmcneill uint16_t id;
989 1.1 jmcneill uint8_t nmw, nsw, rev;
990 1.1 jmcneill struct bwfm_core *core;
991 1.1 jmcneill
992 1.1 jmcneill erom = sc->sc_buscore_ops->bc_read(sc,
993 1.1 jmcneill BWFM_CHIP_BASE + BWFM_CHIP_REG_EROMPTR);
994 1.1 jmcneill while (type != BWFM_DMP_DESC_EOT) {
995 1.1 jmcneill val = sc->sc_buscore_ops->bc_read(sc, erom);
996 1.1 jmcneill type = val & BWFM_DMP_DESC_MASK;
997 1.1 jmcneill erom += 4;
998 1.1 jmcneill
999 1.1 jmcneill if (type != BWFM_DMP_DESC_COMPONENT)
1000 1.1 jmcneill continue;
1001 1.1 jmcneill
1002 1.1 jmcneill id = (val & BWFM_DMP_COMP_PARTNUM)
1003 1.1 jmcneill >> BWFM_DMP_COMP_PARTNUM_S;
1004 1.1 jmcneill
1005 1.1 jmcneill val = sc->sc_buscore_ops->bc_read(sc, erom);
1006 1.1 jmcneill type = val & BWFM_DMP_DESC_MASK;
1007 1.1 jmcneill erom += 4;
1008 1.1 jmcneill
1009 1.1 jmcneill if (type != BWFM_DMP_DESC_COMPONENT) {
1010 1.1 jmcneill printf("%s: not component descriptor\n", DEVNAME(sc));
1011 1.1 jmcneill return;
1012 1.1 jmcneill }
1013 1.1 jmcneill
1014 1.1 jmcneill nmw = (val & BWFM_DMP_COMP_NUM_MWRAP)
1015 1.1 jmcneill >> BWFM_DMP_COMP_NUM_MWRAP_S;
1016 1.1 jmcneill nsw = (val & BWFM_DMP_COMP_NUM_SWRAP)
1017 1.1 jmcneill >> BWFM_DMP_COMP_NUM_SWRAP_S;
1018 1.1 jmcneill rev = (val & BWFM_DMP_COMP_REVISION)
1019 1.1 jmcneill >> BWFM_DMP_COMP_REVISION_S;
1020 1.1 jmcneill
1021 1.1 jmcneill if (nmw + nsw == 0 && id != BWFM_AGENT_CORE_PMU)
1022 1.1 jmcneill continue;
1023 1.1 jmcneill
1024 1.1 jmcneill if (bwfm_chip_dmp_get_regaddr(sc, &erom, &base, &wrap))
1025 1.1 jmcneill continue;
1026 1.1 jmcneill
1027 1.1 jmcneill core = kmem_alloc(sizeof(*core), KM_SLEEP);
1028 1.1 jmcneill core->co_id = id;
1029 1.1 jmcneill core->co_base = base;
1030 1.1 jmcneill core->co_wrapbase = wrap;
1031 1.1 jmcneill core->co_rev = rev;
1032 1.1 jmcneill LIST_INSERT_HEAD(&sc->sc_chip.ch_list, core, co_link);
1033 1.1 jmcneill }
1034 1.1 jmcneill }
1035 1.1 jmcneill
1036 1.1 jmcneill int
1037 1.1 jmcneill bwfm_chip_dmp_get_regaddr(struct bwfm_softc *sc, uint32_t *erom,
1038 1.1 jmcneill uint32_t *base, uint32_t *wrap)
1039 1.1 jmcneill {
1040 1.1 jmcneill uint8_t type = 0, mpnum __unused = 0;
1041 1.1 jmcneill uint8_t stype, sztype, wraptype;
1042 1.1 jmcneill uint32_t val;
1043 1.1 jmcneill
1044 1.1 jmcneill *base = 0;
1045 1.1 jmcneill *wrap = 0;
1046 1.1 jmcneill
1047 1.1 jmcneill val = sc->sc_buscore_ops->bc_read(sc, *erom);
1048 1.1 jmcneill type = val & BWFM_DMP_DESC_MASK;
1049 1.1 jmcneill if (type == BWFM_DMP_DESC_MASTER_PORT) {
1050 1.1 jmcneill mpnum = (val & BWFM_DMP_MASTER_PORT_NUM)
1051 1.1 jmcneill >> BWFM_DMP_MASTER_PORT_NUM_S;
1052 1.1 jmcneill wraptype = BWFM_DMP_SLAVE_TYPE_MWRAP;
1053 1.1 jmcneill *erom += 4;
1054 1.1 jmcneill } else if ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) ==
1055 1.1 jmcneill BWFM_DMP_DESC_ADDRESS)
1056 1.1 jmcneill wraptype = BWFM_DMP_SLAVE_TYPE_SWRAP;
1057 1.1 jmcneill else
1058 1.1 jmcneill return 1;
1059 1.1 jmcneill
1060 1.1 jmcneill do {
1061 1.1 jmcneill do {
1062 1.1 jmcneill val = sc->sc_buscore_ops->bc_read(sc, *erom);
1063 1.1 jmcneill type = val & BWFM_DMP_DESC_MASK;
1064 1.1 jmcneill if (type == BWFM_DMP_DESC_COMPONENT)
1065 1.1 jmcneill return 0;
1066 1.1 jmcneill if (type == BWFM_DMP_DESC_EOT)
1067 1.1 jmcneill return 1;
1068 1.1 jmcneill *erom += 4;
1069 1.1 jmcneill } while ((type & ~BWFM_DMP_DESC_ADDRSIZE_GT32) !=
1070 1.1 jmcneill BWFM_DMP_DESC_ADDRESS);
1071 1.1 jmcneill
1072 1.1 jmcneill if (type & BWFM_DMP_DESC_ADDRSIZE_GT32)
1073 1.1 jmcneill *erom += 4;
1074 1.1 jmcneill
1075 1.1 jmcneill sztype = (val & BWFM_DMP_SLAVE_SIZE_TYPE)
1076 1.1 jmcneill >> BWFM_DMP_SLAVE_SIZE_TYPE_S;
1077 1.1 jmcneill if (sztype == BWFM_DMP_SLAVE_SIZE_DESC) {
1078 1.1 jmcneill val = sc->sc_buscore_ops->bc_read(sc, *erom);
1079 1.1 jmcneill type = val & BWFM_DMP_DESC_MASK;
1080 1.1 jmcneill if (type & BWFM_DMP_DESC_ADDRSIZE_GT32)
1081 1.1 jmcneill *erom += 8;
1082 1.1 jmcneill else
1083 1.1 jmcneill *erom += 4;
1084 1.1 jmcneill }
1085 1.1 jmcneill if (sztype != BWFM_DMP_SLAVE_SIZE_4K)
1086 1.1 jmcneill continue;
1087 1.1 jmcneill
1088 1.1 jmcneill stype = (val & BWFM_DMP_SLAVE_TYPE) >> BWFM_DMP_SLAVE_TYPE_S;
1089 1.1 jmcneill if (*base == 0 && stype == BWFM_DMP_SLAVE_TYPE_SLAVE)
1090 1.1 jmcneill *base = val & BWFM_DMP_SLAVE_ADDR_BASE;
1091 1.1 jmcneill if (*wrap == 0 && stype == wraptype)
1092 1.1 jmcneill *wrap = val & BWFM_DMP_SLAVE_ADDR_BASE;
1093 1.1 jmcneill } while (*base == 0 || *wrap == 0);
1094 1.1 jmcneill
1095 1.1 jmcneill return 0;
1096 1.1 jmcneill }
1097 1.1 jmcneill
1098 1.1 jmcneill /* Core configuration */
1099 1.1 jmcneill void
1100 1.1 jmcneill bwfm_chip_cr4_set_passive(struct bwfm_softc *sc)
1101 1.1 jmcneill {
1102 1.1 jmcneill panic("%s: CR4 not supported", DEVNAME(sc));
1103 1.1 jmcneill }
1104 1.1 jmcneill
1105 1.1 jmcneill void
1106 1.1 jmcneill bwfm_chip_ca7_set_passive(struct bwfm_softc *sc)
1107 1.1 jmcneill {
1108 1.1 jmcneill panic("%s: CA7 not supported", DEVNAME(sc));
1109 1.1 jmcneill }
1110 1.1 jmcneill
1111 1.1 jmcneill void
1112 1.1 jmcneill bwfm_chip_cm3_set_passive(struct bwfm_softc *sc)
1113 1.1 jmcneill {
1114 1.1 jmcneill struct bwfm_core *core;
1115 1.1 jmcneill
1116 1.1 jmcneill core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_ARM_CM3);
1117 1.1 jmcneill sc->sc_chip.ch_core_disable(sc, core, 0, 0);
1118 1.1 jmcneill core = bwfm_chip_get_core(sc, BWFM_AGENT_CORE_80211);
1119 1.1 jmcneill sc->sc_chip.ch_core_reset(sc, core, BWFM_AGENT_D11_IOCTL_PHYRESET |
1120 1.1 jmcneill BWFM_AGENT_D11_IOCTL_PHYCLOCKEN, BWFM_AGENT_D11_IOCTL_PHYCLOCKEN,
1121 1.1 jmcneill BWFM_AGENT_D11_IOCTL_PHYCLOCKEN);
1122 1.1 jmcneill core = bwfm_chip_get_core(sc, BWFM_AGENT_INTERNAL_MEM);
1123 1.1 jmcneill sc->sc_chip.ch_core_reset(sc, core, 0, 0, 0);
1124 1.1 jmcneill
1125 1.1 jmcneill if (sc->sc_chip.ch_chip == BRCM_CC_43430_CHIP_ID) {
1126 1.1 jmcneill sc->sc_buscore_ops->bc_write(sc,
1127 1.1 jmcneill core->co_base + BWFM_SOCRAM_BANKIDX, 3);
1128 1.1 jmcneill sc->sc_buscore_ops->bc_write(sc,
1129 1.1 jmcneill core->co_base + BWFM_SOCRAM_BANKPDA, 0);
1130 1.1 jmcneill }
1131 1.1 jmcneill }
1132 1.1 jmcneill
1133 1.1 jmcneill /* BCDC protocol implementation */
1134 1.1 jmcneill int
1135 1.1 jmcneill bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *sc, int ifidx,
1136 1.1 jmcneill int cmd, char *buf, size_t *len)
1137 1.1 jmcneill {
1138 1.1 jmcneill struct bwfm_proto_bcdc_dcmd *dcmd;
1139 1.1 jmcneill size_t size = sizeof(dcmd->hdr) + *len;
1140 1.1 jmcneill static int reqid = 0;
1141 1.1 jmcneill int ret = 1;
1142 1.1 jmcneill
1143 1.1 jmcneill reqid++;
1144 1.1 jmcneill
1145 1.1 jmcneill dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP);
1146 1.1 jmcneill if (*len > sizeof(dcmd->buf))
1147 1.1 jmcneill goto err;
1148 1.1 jmcneill
1149 1.1 jmcneill dcmd->hdr.cmd = htole32(cmd);
1150 1.1 jmcneill dcmd->hdr.len = htole32(*len);
1151 1.1 jmcneill dcmd->hdr.flags |= BWFM_BCDC_DCMD_GET;
1152 1.1 jmcneill dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid);
1153 1.1 jmcneill dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx);
1154 1.1 jmcneill dcmd->hdr.flags = htole32(dcmd->hdr.flags);
1155 1.1 jmcneill memcpy(&dcmd->buf, buf, *len);
1156 1.1 jmcneill
1157 1.1 jmcneill if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd,
1158 1.1 jmcneill sizeof(dcmd->hdr) + *len)) {
1159 1.1 jmcneill DPRINTF(("%s: tx failed\n", DEVNAME(sc)));
1160 1.1 jmcneill goto err;
1161 1.1 jmcneill }
1162 1.1 jmcneill
1163 1.1 jmcneill do {
1164 1.1 jmcneill if (sc->sc_bus_ops->bs_rxctl(sc, (void *)dcmd, &size)) {
1165 1.1 jmcneill DPRINTF(("%s: rx failed\n", DEVNAME(sc)));
1166 1.1 jmcneill goto err;
1167 1.1 jmcneill }
1168 1.1 jmcneill dcmd->hdr.cmd = le32toh(dcmd->hdr.cmd);
1169 1.1 jmcneill dcmd->hdr.len = le32toh(dcmd->hdr.len);
1170 1.1 jmcneill dcmd->hdr.flags = le32toh(dcmd->hdr.flags);
1171 1.1 jmcneill dcmd->hdr.status = le32toh(dcmd->hdr.status);
1172 1.1 jmcneill } while (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid);
1173 1.1 jmcneill
1174 1.1 jmcneill if (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid) {
1175 1.1 jmcneill printf("%s: unexpected request id\n", DEVNAME(sc));
1176 1.1 jmcneill goto err;
1177 1.1 jmcneill }
1178 1.1 jmcneill
1179 1.1 jmcneill if (buf) {
1180 1.1 jmcneill if (size > *len)
1181 1.1 jmcneill size = *len;
1182 1.1 jmcneill if (size < *len)
1183 1.1 jmcneill *len = size;
1184 1.1 jmcneill memcpy(buf, dcmd->buf, *len);
1185 1.1 jmcneill }
1186 1.1 jmcneill
1187 1.1 jmcneill if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR)
1188 1.1 jmcneill ret = dcmd->hdr.status;
1189 1.1 jmcneill else
1190 1.1 jmcneill ret = 0;
1191 1.1 jmcneill err:
1192 1.1 jmcneill kmem_free(dcmd, sizeof(*dcmd));
1193 1.1 jmcneill return ret;
1194 1.1 jmcneill }
1195 1.1 jmcneill
1196 1.1 jmcneill int
1197 1.1 jmcneill bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *sc, int ifidx,
1198 1.1 jmcneill int cmd, char *buf, size_t len)
1199 1.1 jmcneill {
1200 1.1 jmcneill struct bwfm_proto_bcdc_dcmd *dcmd;
1201 1.1 jmcneill size_t size = sizeof(dcmd->hdr) + len;
1202 1.1 jmcneill int reqid = 0;
1203 1.1 jmcneill int ret = 1;
1204 1.1 jmcneill
1205 1.1 jmcneill reqid++;
1206 1.1 jmcneill
1207 1.1 jmcneill dcmd = kmem_zalloc(sizeof(*dcmd), KM_SLEEP);
1208 1.1 jmcneill if (len > sizeof(dcmd->buf))
1209 1.1 jmcneill goto err;
1210 1.1 jmcneill
1211 1.1 jmcneill dcmd->hdr.cmd = htole32(cmd);
1212 1.1 jmcneill dcmd->hdr.len = htole32(len);
1213 1.1 jmcneill dcmd->hdr.flags |= BWFM_BCDC_DCMD_SET;
1214 1.1 jmcneill dcmd->hdr.flags |= BWFM_BCDC_DCMD_ID_SET(reqid);
1215 1.1 jmcneill dcmd->hdr.flags |= BWFM_BCDC_DCMD_IF_SET(ifidx);
1216 1.1 jmcneill dcmd->hdr.flags = htole32(dcmd->hdr.flags);
1217 1.1 jmcneill memcpy(&dcmd->buf, buf, len);
1218 1.1 jmcneill
1219 1.1 jmcneill if (sc->sc_bus_ops->bs_txctl(sc, (void *)dcmd, size)) {
1220 1.1 jmcneill DPRINTF(("%s: tx failed\n", DEVNAME(sc)));
1221 1.1 jmcneill goto err;
1222 1.1 jmcneill }
1223 1.1 jmcneill
1224 1.1 jmcneill do {
1225 1.1 jmcneill if (sc->sc_bus_ops->bs_rxctl(sc, (void *)dcmd, &size)) {
1226 1.1 jmcneill DPRINTF(("%s: rx failed\n", DEVNAME(sc)));
1227 1.1 jmcneill goto err;
1228 1.1 jmcneill }
1229 1.1 jmcneill dcmd->hdr.cmd = le32toh(dcmd->hdr.cmd);
1230 1.1 jmcneill dcmd->hdr.len = le32toh(dcmd->hdr.len);
1231 1.1 jmcneill dcmd->hdr.flags = le32toh(dcmd->hdr.flags);
1232 1.1 jmcneill dcmd->hdr.status = le32toh(dcmd->hdr.status);
1233 1.1 jmcneill } while (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid);
1234 1.1 jmcneill
1235 1.1 jmcneill if (BWFM_BCDC_DCMD_ID_GET(dcmd->hdr.flags) != reqid) {
1236 1.1 jmcneill printf("%s: unexpected request id\n", DEVNAME(sc));
1237 1.1 jmcneill goto err;
1238 1.1 jmcneill }
1239 1.1 jmcneill
1240 1.1 jmcneill if (dcmd->hdr.flags & BWFM_BCDC_DCMD_ERROR)
1241 1.1 jmcneill return dcmd->hdr.status;
1242 1.1 jmcneill
1243 1.1 jmcneill ret = 0;
1244 1.1 jmcneill err:
1245 1.1 jmcneill kmem_free(dcmd, sizeof(*dcmd));
1246 1.1 jmcneill return ret;
1247 1.1 jmcneill }
1248 1.1 jmcneill
1249 1.1 jmcneill /* FW Variable code */
1250 1.1 jmcneill int
1251 1.1 jmcneill bwfm_fwvar_cmd_get_data(struct bwfm_softc *sc, int cmd, void *data, size_t len)
1252 1.1 jmcneill {
1253 1.1 jmcneill return sc->sc_proto_ops->proto_query_dcmd(sc, 0, cmd, data, &len);
1254 1.1 jmcneill }
1255 1.1 jmcneill
1256 1.1 jmcneill int
1257 1.1 jmcneill bwfm_fwvar_cmd_set_data(struct bwfm_softc *sc, int cmd, void *data, size_t len)
1258 1.1 jmcneill {
1259 1.1 jmcneill return sc->sc_proto_ops->proto_set_dcmd(sc, 0, cmd, data, len);
1260 1.1 jmcneill }
1261 1.1 jmcneill
1262 1.1 jmcneill int
1263 1.1 jmcneill bwfm_fwvar_cmd_get_int(struct bwfm_softc *sc, int cmd, uint32_t *data)
1264 1.1 jmcneill {
1265 1.1 jmcneill int ret;
1266 1.1 jmcneill ret = bwfm_fwvar_cmd_get_data(sc, cmd, data, sizeof(*data));
1267 1.1 jmcneill *data = le32toh(*data);
1268 1.1 jmcneill return ret;
1269 1.1 jmcneill }
1270 1.1 jmcneill
1271 1.1 jmcneill int
1272 1.1 jmcneill bwfm_fwvar_cmd_set_int(struct bwfm_softc *sc, int cmd, uint32_t data)
1273 1.1 jmcneill {
1274 1.1 jmcneill data = htole32(data);
1275 1.1 jmcneill return bwfm_fwvar_cmd_set_data(sc, cmd, &data, sizeof(data));
1276 1.1 jmcneill }
1277 1.1 jmcneill
1278 1.1 jmcneill int
1279 1.1 jmcneill bwfm_fwvar_var_get_data(struct bwfm_softc *sc, const char *name, void *data, size_t len)
1280 1.1 jmcneill {
1281 1.1 jmcneill char *buf;
1282 1.1 jmcneill int ret;
1283 1.1 jmcneill
1284 1.1 jmcneill buf = kmem_alloc(strlen(name) + 1 + len, KM_SLEEP);
1285 1.1 jmcneill memcpy(buf, name, strlen(name) + 1);
1286 1.1 jmcneill memcpy(buf + strlen(name) + 1, data, len);
1287 1.1 jmcneill ret = bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_VAR,
1288 1.1 jmcneill buf, strlen(name) + 1 + len);
1289 1.1 jmcneill memcpy(data, buf, len);
1290 1.1 jmcneill kmem_free(buf, strlen(name) + 1 + len);
1291 1.1 jmcneill return ret;
1292 1.1 jmcneill }
1293 1.1 jmcneill
1294 1.1 jmcneill int
1295 1.1 jmcneill bwfm_fwvar_var_set_data(struct bwfm_softc *sc, const char *name, void *data, size_t len)
1296 1.1 jmcneill {
1297 1.1 jmcneill char *buf;
1298 1.1 jmcneill int ret;
1299 1.1 jmcneill
1300 1.1 jmcneill buf = kmem_alloc(strlen(name) + 1 + len, KM_SLEEP);
1301 1.1 jmcneill memcpy(buf, name, strlen(name) + 1);
1302 1.1 jmcneill memcpy(buf + strlen(name) + 1, data, len);
1303 1.1 jmcneill ret = bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_VAR,
1304 1.1 jmcneill buf, strlen(name) + 1 + len);
1305 1.1 jmcneill kmem_free(buf, strlen(name) + 1 + len);
1306 1.1 jmcneill return ret;
1307 1.1 jmcneill }
1308 1.1 jmcneill
1309 1.1 jmcneill int
1310 1.1 jmcneill bwfm_fwvar_var_get_int(struct bwfm_softc *sc, const char *name, uint32_t *data)
1311 1.1 jmcneill {
1312 1.1 jmcneill int ret;
1313 1.1 jmcneill ret = bwfm_fwvar_var_get_data(sc, name, data, sizeof(*data));
1314 1.1 jmcneill *data = le32toh(*data);
1315 1.1 jmcneill return ret;
1316 1.1 jmcneill }
1317 1.1 jmcneill
1318 1.1 jmcneill int
1319 1.1 jmcneill bwfm_fwvar_var_set_int(struct bwfm_softc *sc, const char *name, uint32_t data)
1320 1.1 jmcneill {
1321 1.1 jmcneill data = htole32(data);
1322 1.1 jmcneill return bwfm_fwvar_var_set_data(sc, name, &data, sizeof(data));
1323 1.1 jmcneill }
1324 1.1 jmcneill
1325 1.1 jmcneill /* 802.11 code */
1326 1.1 jmcneill void
1327 1.1 jmcneill bwfm_scan(struct bwfm_softc *sc)
1328 1.1 jmcneill {
1329 1.1 jmcneill struct bwfm_escan_params *params;
1330 1.1 jmcneill uint32_t nssid = 0, nchannel = 0;
1331 1.1 jmcneill size_t params_size;
1332 1.1 jmcneill
1333 1.1 jmcneill #if 0
1334 1.1 jmcneill /* Active scan is used for scanning for an SSID */
1335 1.1 jmcneill bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PASSIVE_SCAN, 0);
1336 1.1 jmcneill #endif
1337 1.1 jmcneill bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PASSIVE_SCAN, 1);
1338 1.1 jmcneill
1339 1.1 jmcneill params_size = sizeof(*params);
1340 1.1 jmcneill params_size += sizeof(uint32_t) * ((nchannel + 1) / 2);
1341 1.1 jmcneill params_size += sizeof(struct bwfm_ssid) * nssid;
1342 1.1 jmcneill
1343 1.1 jmcneill params = kmem_zalloc(params_size, KM_SLEEP);
1344 1.1 jmcneill memset(params->scan_params.bssid, 0xff,
1345 1.1 jmcneill sizeof(params->scan_params.bssid));
1346 1.1 jmcneill params->scan_params.bss_type = 2;
1347 1.1 jmcneill params->scan_params.nprobes = htole32(-1);
1348 1.1 jmcneill params->scan_params.active_time = htole32(-1);
1349 1.1 jmcneill params->scan_params.passive_time = htole32(-1);
1350 1.1 jmcneill params->scan_params.home_time = htole32(-1);
1351 1.1 jmcneill params->version = htole32(BWFM_ESCAN_REQ_VERSION);
1352 1.1 jmcneill params->action = htole16(WL_ESCAN_ACTION_START);
1353 1.1 jmcneill params->sync_id = htole16(0x1234);
1354 1.1 jmcneill
1355 1.1 jmcneill #if 0
1356 1.1 jmcneill /* Scan a specific channel */
1357 1.1 jmcneill params->scan_params.channel_list[0] = htole16(
1358 1.1 jmcneill (1 & 0xff) << 0 |
1359 1.1 jmcneill (3 & 0x3) << 8 |
1360 1.1 jmcneill (2 & 0x3) << 10 |
1361 1.1 jmcneill (2 & 0x3) << 12
1362 1.1 jmcneill );
1363 1.1 jmcneill params->scan_params.channel_num = htole32(
1364 1.1 jmcneill (1 & 0xffff) << 0
1365 1.1 jmcneill );
1366 1.1 jmcneill #endif
1367 1.1 jmcneill
1368 1.1 jmcneill bwfm_fwvar_var_set_data(sc, "escan", params, params_size);
1369 1.1 jmcneill kmem_free(params, params_size);
1370 1.1 jmcneill }
1371 1.1 jmcneill
1372 1.1 jmcneill static __inline int
1373 1.1 jmcneill bwfm_iswpaoui(const uint8_t *frm)
1374 1.1 jmcneill {
1375 1.1 jmcneill return frm[1] > 3 && le32dec(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
1376 1.1 jmcneill }
1377 1.1 jmcneill
1378 1.1 jmcneill /*
1379 1.1 jmcneill * Derive wireless security settings from WPA/RSN IE.
1380 1.1 jmcneill */
1381 1.1 jmcneill static uint32_t
1382 1.1 jmcneill bwfm_get_wsec(struct bwfm_softc *sc)
1383 1.1 jmcneill {
1384 1.1 jmcneill struct ieee80211com *ic = &sc->sc_ic;
1385 1.1 jmcneill uint8_t *wpa = ic->ic_opt_ie;
1386 1.1 jmcneill
1387 1.1 jmcneill KASSERT(ic->ic_opt_ie_len > 0);
1388 1.1 jmcneill
1389 1.1 jmcneill if (wpa[0] != IEEE80211_ELEMID_RSN) {
1390 1.1 jmcneill if (ic->ic_opt_ie_len < 12)
1391 1.1 jmcneill return BWFM_WSEC_NONE;
1392 1.1 jmcneill
1393 1.1 jmcneill /* non-RSN IE, expect that we are doing WPA1 */
1394 1.1 jmcneill if ((ic->ic_flags & IEEE80211_F_WPA1) == 0)
1395 1.1 jmcneill return BWFM_WSEC_NONE;
1396 1.1 jmcneill
1397 1.1 jmcneill /* Must contain WPA OUI */
1398 1.1 jmcneill if (!bwfm_iswpaoui(wpa))
1399 1.1 jmcneill return BWFM_WSEC_NONE;
1400 1.1 jmcneill
1401 1.1 jmcneill switch (le32dec(wpa + 8)) {
1402 1.1 jmcneill case ((WPA_CSE_TKIP<<24)|WPA_OUI):
1403 1.1 jmcneill return BWFM_WSEC_TKIP;
1404 1.1 jmcneill case ((WPA_CSE_CCMP<<24)|WPA_OUI):
1405 1.1 jmcneill return BWFM_WSEC_AES;
1406 1.1 jmcneill default:
1407 1.1 jmcneill return BWFM_WSEC_NONE;
1408 1.1 jmcneill }
1409 1.1 jmcneill } else {
1410 1.1 jmcneill if (ic->ic_opt_ie_len < 14)
1411 1.1 jmcneill return BWFM_WSEC_NONE;
1412 1.1 jmcneill
1413 1.1 jmcneill /* RSN IE, expect that we are doing WPA2 */
1414 1.1 jmcneill if ((ic->ic_flags & IEEE80211_F_WPA2) == 0)
1415 1.1 jmcneill return BWFM_WSEC_NONE;
1416 1.1 jmcneill
1417 1.1 jmcneill switch (le32dec(wpa + 10)) {
1418 1.1 jmcneill case ((RSN_CSE_TKIP<<24)|RSN_OUI):
1419 1.1 jmcneill return BWFM_WSEC_TKIP;
1420 1.1 jmcneill case ((RSN_CSE_CCMP<<24)|RSN_OUI):
1421 1.1 jmcneill return BWFM_WSEC_AES;
1422 1.1 jmcneill default:
1423 1.1 jmcneill return BWFM_WSEC_NONE;
1424 1.1 jmcneill }
1425 1.1 jmcneill }
1426 1.1 jmcneill }
1427 1.1 jmcneill
1428 1.1 jmcneill void
1429 1.1 jmcneill bwfm_connect(struct bwfm_softc *sc)
1430 1.1 jmcneill {
1431 1.1 jmcneill struct ieee80211com *ic = &sc->sc_ic;
1432 1.1 jmcneill struct ieee80211_node *ni = ic->ic_bss;
1433 1.1 jmcneill struct bwfm_ext_join_params *params;
1434 1.1 jmcneill
1435 1.1 jmcneill if (ic->ic_flags & IEEE80211_F_WPA) {
1436 1.1 jmcneill uint32_t wsec = 0;
1437 1.1 jmcneill uint32_t wpa = 0;
1438 1.1 jmcneill
1439 1.1 jmcneill if (ic->ic_opt_ie_len)
1440 1.1 jmcneill bwfm_fwvar_var_set_data(sc, "wpaie", ic->ic_opt_ie, ic->ic_opt_ie_len);
1441 1.1 jmcneill
1442 1.1 jmcneill if (ic->ic_flags & IEEE80211_F_WPA1)
1443 1.1 jmcneill wpa |= BWFM_WPA_AUTH_WPA_PSK;
1444 1.1 jmcneill if (ic->ic_flags & IEEE80211_F_WPA2)
1445 1.1 jmcneill wpa |= BWFM_WPA_AUTH_WPA2_PSK;
1446 1.1 jmcneill
1447 1.1 jmcneill wsec |= bwfm_get_wsec(sc);
1448 1.1 jmcneill
1449 1.1 jmcneill DPRINTF(("%s: WPA enabled, ic_flags = 0x%x, wpa 0x%x, wsec 0x%x\n",
1450 1.1 jmcneill DEVNAME(sc), ic->ic_flags, wpa, wsec));
1451 1.1 jmcneill
1452 1.1 jmcneill bwfm_fwvar_var_set_int(sc, "wpa_auth", wpa);
1453 1.1 jmcneill bwfm_fwvar_var_set_int(sc, "wsec", wsec);
1454 1.1 jmcneill } else {
1455 1.1 jmcneill bwfm_fwvar_var_set_int(sc, "wpa_auth", BWFM_WPA_AUTH_DISABLED);
1456 1.1 jmcneill bwfm_fwvar_var_set_int(sc, "wsec", BWFM_WSEC_NONE);
1457 1.1 jmcneill }
1458 1.1 jmcneill
1459 1.1 jmcneill bwfm_fwvar_var_set_int(sc, "auth", BWFM_AUTH_OPEN);
1460 1.1 jmcneill bwfm_fwvar_var_set_int(sc, "mfp", BWFM_MFP_NONE);
1461 1.1 jmcneill
1462 1.1 jmcneill if (ni->ni_esslen && ni->ni_esslen < BWFM_MAX_SSID_LEN) {
1463 1.1 jmcneill params = kmem_zalloc(sizeof(*params), KM_SLEEP);
1464 1.1 jmcneill memcpy(params->ssid.ssid, ni->ni_essid, ni->ni_esslen);
1465 1.1 jmcneill params->ssid.len = htole32(ni->ni_esslen);
1466 1.1 jmcneill memcpy(params->assoc.bssid, ni->ni_bssid, sizeof(params->assoc.bssid));
1467 1.1 jmcneill params->scan.scan_type = -1;
1468 1.1 jmcneill params->scan.nprobes = htole32(-1);
1469 1.1 jmcneill params->scan.active_time = htole32(-1);
1470 1.1 jmcneill params->scan.passive_time = htole32(-1);
1471 1.1 jmcneill params->scan.home_time = htole32(-1);
1472 1.1 jmcneill if (bwfm_fwvar_var_set_data(sc, "join", params, sizeof(*params))) {
1473 1.1 jmcneill struct bwfm_join_params join;
1474 1.1 jmcneill memset(&join, 0, sizeof(join));
1475 1.1 jmcneill memcpy(join.ssid.ssid, ni->ni_essid, ni->ni_esslen);
1476 1.1 jmcneill join.ssid.len = htole32(ni->ni_esslen);
1477 1.1 jmcneill memcpy(join.assoc.bssid, ni->ni_bssid, sizeof(join.assoc.bssid));
1478 1.1 jmcneill bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join,
1479 1.1 jmcneill sizeof(join));
1480 1.1 jmcneill }
1481 1.1 jmcneill kmem_free(params, sizeof(*params));
1482 1.1 jmcneill }
1483 1.1 jmcneill
1484 1.1 jmcneill /* XXX: added for testing only, remove */
1485 1.1 jmcneill bwfm_fwvar_var_set_int(sc, "allmulti", 1);
1486 1.1 jmcneill #if 0
1487 1.1 jmcneill bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PROMISC, 1);
1488 1.1 jmcneill #endif
1489 1.1 jmcneill }
1490 1.1 jmcneill
1491 1.1 jmcneill void
1492 1.1 jmcneill bwfm_rx(struct bwfm_softc *sc, char *buf, size_t len)
1493 1.1 jmcneill {
1494 1.1 jmcneill struct ieee80211com *ic = &sc->sc_ic;
1495 1.1 jmcneill struct ifnet *ifp = ic->ic_ifp;
1496 1.1 jmcneill struct bwfm_event *e = (void *)buf;
1497 1.1 jmcneill struct mbuf *m;
1498 1.1 jmcneill char *mb;
1499 1.1 jmcneill int s;
1500 1.1 jmcneill
1501 1.1 jmcneill DPRINTF(("%s: buf %p len %lu\n", __func__, buf, len));
1502 1.1 jmcneill
1503 1.1 jmcneill if (len >= sizeof(e->ehdr) &&
1504 1.1 jmcneill ntohs(e->ehdr.ether_type) == BWFM_ETHERTYPE_LINK_CTL &&
1505 1.1 jmcneill memcmp(BWFM_BRCM_OUI, e->hdr.oui, sizeof(e->hdr.oui)) == 0 &&
1506 1.1 jmcneill ntohs(e->hdr.usr_subtype) == BWFM_BRCM_SUBTYPE_EVENT)
1507 1.1 jmcneill bwfm_rx_event(sc, buf, len);
1508 1.1 jmcneill
1509 1.1 jmcneill if (__predict_false(len > MCLBYTES || len == 0))
1510 1.1 jmcneill return;
1511 1.1 jmcneill MGETHDR(m, M_DONTWAIT, MT_DATA);
1512 1.1 jmcneill if (__predict_false(m == NULL))
1513 1.1 jmcneill return;
1514 1.1 jmcneill if (len > MHLEN) {
1515 1.1 jmcneill MCLGET(m, M_DONTWAIT);
1516 1.1 jmcneill if (!(m->m_flags & M_EXT)) {
1517 1.1 jmcneill m_free(m);
1518 1.1 jmcneill return;
1519 1.1 jmcneill }
1520 1.1 jmcneill }
1521 1.1 jmcneill
1522 1.1 jmcneill s = splnet();
1523 1.1 jmcneill
1524 1.1 jmcneill if ((ifp->if_flags & IFF_RUNNING) != 0) {
1525 1.1 jmcneill mb = mtod(m, char *);
1526 1.1 jmcneill memcpy(mb, buf, len);
1527 1.1 jmcneill m->m_pkthdr.len = m->m_len = len;
1528 1.1 jmcneill m_set_rcvif(m, ifp);
1529 1.1 jmcneill
1530 1.1 jmcneill if_percpuq_enqueue(ifp->if_percpuq, m);
1531 1.1 jmcneill }
1532 1.1 jmcneill
1533 1.1 jmcneill splx(s);
1534 1.1 jmcneill }
1535 1.1 jmcneill
1536 1.1 jmcneill void
1537 1.1 jmcneill bwfm_rx_event(struct bwfm_softc *sc, char *buf, size_t len)
1538 1.1 jmcneill {
1539 1.1 jmcneill struct ieee80211com *ic = &sc->sc_ic;
1540 1.1 jmcneill struct bwfm_event *e = (void *)buf;
1541 1.1 jmcneill int s;
1542 1.1 jmcneill
1543 1.1 jmcneill DPRINTF(("%s: buf %p len %lu datalen %u code %u status %u"
1544 1.1 jmcneill " reason %u\n", __func__, buf, len, ntohl(e->msg.datalen),
1545 1.1 jmcneill ntohl(e->msg.event_type), ntohl(e->msg.status),
1546 1.1 jmcneill ntohl(e->msg.reason)));
1547 1.1 jmcneill
1548 1.1 jmcneill if (ntohl(e->msg.event_type) >= BWFM_E_LAST)
1549 1.1 jmcneill return;
1550 1.1 jmcneill
1551 1.1 jmcneill switch (ntohl(e->msg.event_type)) {
1552 1.1 jmcneill case BWFM_E_ESCAN_RESULT: {
1553 1.1 jmcneill struct bwfm_escan_results *res = (void *)(buf + sizeof(*e));
1554 1.1 jmcneill struct bwfm_bss_info *bss;
1555 1.1 jmcneill int i;
1556 1.1 jmcneill if (ntohl(e->msg.status) != BWFM_E_STATUS_PARTIAL) {
1557 1.1 jmcneill /* Scan complete */
1558 1.1 jmcneill s = splnet();
1559 1.1 jmcneill if (ic->ic_opmode != IEEE80211_M_MONITOR)
1560 1.1 jmcneill ieee80211_end_scan(ic);
1561 1.1 jmcneill splx(s);
1562 1.1 jmcneill break;
1563 1.1 jmcneill }
1564 1.1 jmcneill len -= sizeof(*e);
1565 1.1 jmcneill if (len < sizeof(*res) || len < le32toh(res->buflen)) {
1566 1.1 jmcneill printf("%s: results too small\n", DEVNAME(sc));
1567 1.1 jmcneill return;
1568 1.1 jmcneill }
1569 1.1 jmcneill len -= sizeof(*res);
1570 1.1 jmcneill if (len < le16toh(res->bss_count) * sizeof(struct bwfm_bss_info)) {
1571 1.1 jmcneill printf("%s: results too small\n", DEVNAME(sc));
1572 1.1 jmcneill return;
1573 1.1 jmcneill }
1574 1.1 jmcneill bss = &res->bss_info[0];
1575 1.1 jmcneill for (i = 0; i < le16toh(res->bss_count); i++) {
1576 1.1 jmcneill bwfm_scan_node(sc, &res->bss_info[i], len);
1577 1.1 jmcneill len -= sizeof(*bss) + le32toh(bss->length);
1578 1.1 jmcneill bss = (void *)(((uintptr_t)bss) + le32toh(bss->length));
1579 1.1 jmcneill if (len <= 0)
1580 1.1 jmcneill break;
1581 1.1 jmcneill }
1582 1.1 jmcneill break;
1583 1.1 jmcneill }
1584 1.1 jmcneill
1585 1.1 jmcneill case BWFM_E_SET_SSID:
1586 1.1 jmcneill if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS) {
1587 1.1 jmcneill ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
1588 1.1 jmcneill } else {
1589 1.1 jmcneill ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
1590 1.1 jmcneill }
1591 1.1 jmcneill break;
1592 1.1 jmcneill
1593 1.1 jmcneill case BWFM_E_ASSOC:
1594 1.1 jmcneill if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS) {
1595 1.1 jmcneill ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1);
1596 1.1 jmcneill } else {
1597 1.1 jmcneill ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
1598 1.1 jmcneill }
1599 1.1 jmcneill break;
1600 1.1 jmcneill
1601 1.1 jmcneill case BWFM_E_LINK:
1602 1.1 jmcneill if (ntohl(e->msg.status) == BWFM_E_STATUS_SUCCESS &&
1603 1.1 jmcneill ntohl(e->msg.reason) == 0)
1604 1.1 jmcneill break;
1605 1.1 jmcneill
1606 1.1 jmcneill /* Link status has changed */
1607 1.1 jmcneill ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
1608 1.1 jmcneill break;
1609 1.1 jmcneill
1610 1.1 jmcneill default:
1611 1.1 jmcneill break;
1612 1.1 jmcneill }
1613 1.1 jmcneill }
1614 1.1 jmcneill
1615 1.1 jmcneill void
1616 1.1 jmcneill bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_info *bss, size_t len)
1617 1.1 jmcneill {
1618 1.1 jmcneill struct ieee80211com *ic = &sc->sc_ic;
1619 1.1 jmcneill struct ieee80211_frame wh;
1620 1.1 jmcneill struct ieee80211_scanparams scan;
1621 1.1 jmcneill uint8_t rates[sizeof(bss->rates) + 2];
1622 1.1 jmcneill uint8_t ssid[sizeof(bss->ssid) + 2];
1623 1.1 jmcneill uint8_t *frm, *sfrm, *efrm;
1624 1.1 jmcneill uint64_t tsf;
1625 1.1 jmcneill
1626 1.1 jmcneill tsf = 0;
1627 1.1 jmcneill sfrm = ((uint8_t *)bss) + le16toh(bss->ie_offset);
1628 1.1 jmcneill efrm = sfrm + le32toh(bss->ie_length);
1629 1.1 jmcneill
1630 1.1 jmcneill /* Fake a wireless header with the scan result's BSSID */
1631 1.1 jmcneill memset(&wh, 0, sizeof(wh));
1632 1.1 jmcneill IEEE80211_ADDR_COPY(wh.i_addr2, bss->bssid);
1633 1.1 jmcneill IEEE80211_ADDR_COPY(wh.i_addr3, bss->bssid);
1634 1.1 jmcneill
1635 1.1 jmcneill if (efrm - sfrm < 12) {
1636 1.1 jmcneill ic->ic_stats.is_rx_elem_toosmall++;
1637 1.1 jmcneill return;
1638 1.1 jmcneill }
1639 1.1 jmcneill
1640 1.1 jmcneill rates[0] = 0;
1641 1.1 jmcneill rates[1] = le32toh(bss->nrates);
1642 1.1 jmcneill memcpy(&rates[2], bss->rates, sizeof(bss->rates));
1643 1.1 jmcneill
1644 1.1 jmcneill ssid[0] = 0;
1645 1.1 jmcneill ssid[1] = bss->ssid_len;
1646 1.1 jmcneill memcpy(&ssid[2], bss->ssid, sizeof(bss->ssid));
1647 1.1 jmcneill
1648 1.1 jmcneill /* Build scan result */
1649 1.1 jmcneill memset(&scan, 0, sizeof(scan));
1650 1.1 jmcneill scan.tstamp = (uint8_t *)&tsf;
1651 1.1 jmcneill scan.bintval = le16toh(bss->beacon_period);
1652 1.1 jmcneill scan.capinfo = le16toh(bss->capability);
1653 1.1 jmcneill scan.bchan = ieee80211_chan2ieee(ic, ic->ic_curchan);
1654 1.1 jmcneill scan.chan = scan.bchan;
1655 1.1 jmcneill scan.rates = rates;
1656 1.1 jmcneill scan.ssid = ssid;
1657 1.1 jmcneill
1658 1.1 jmcneill for (frm = sfrm; frm < efrm; frm += frm[1] + 2) {
1659 1.1 jmcneill switch (frm[0]) {
1660 1.1 jmcneill case IEEE80211_ELEMID_COUNTRY:
1661 1.1 jmcneill scan.country = frm;
1662 1.1 jmcneill break;
1663 1.1 jmcneill case IEEE80211_ELEMID_FHPARMS:
1664 1.1 jmcneill if (ic->ic_phytype == IEEE80211_T_FH) {
1665 1.1 jmcneill scan.fhdwell = le16dec(&frm[2]);
1666 1.1 jmcneill scan.chan = IEEE80211_FH_CHAN(frm[4], frm[5]);
1667 1.1 jmcneill scan.fhindex = frm[6];
1668 1.1 jmcneill }
1669 1.1 jmcneill break;
1670 1.1 jmcneill case IEEE80211_ELEMID_DSPARMS:
1671 1.1 jmcneill if (ic->ic_phytype != IEEE80211_T_FH)
1672 1.1 jmcneill scan.chan = frm[2];
1673 1.1 jmcneill break;
1674 1.1 jmcneill case IEEE80211_ELEMID_TIM:
1675 1.1 jmcneill scan.tim = frm;
1676 1.1 jmcneill scan.timoff = frm - sfrm;
1677 1.1 jmcneill break;
1678 1.1 jmcneill case IEEE80211_ELEMID_XRATES:
1679 1.1 jmcneill scan.xrates = frm;
1680 1.1 jmcneill break;
1681 1.1 jmcneill case IEEE80211_ELEMID_ERP:
1682 1.1 jmcneill if (frm[1] != 1) {
1683 1.1 jmcneill ic->ic_stats.is_rx_elem_toobig++;
1684 1.1 jmcneill break;
1685 1.1 jmcneill }
1686 1.1 jmcneill scan.erp = frm[2];
1687 1.1 jmcneill break;
1688 1.1 jmcneill case IEEE80211_ELEMID_RSN:
1689 1.1 jmcneill scan.wpa = frm;
1690 1.1 jmcneill break;
1691 1.1 jmcneill case IEEE80211_ELEMID_VENDOR:
1692 1.1 jmcneill if (bwfm_iswpaoui(frm))
1693 1.1 jmcneill scan.wpa = frm;
1694 1.1 jmcneill break;
1695 1.1 jmcneill }
1696 1.1 jmcneill }
1697 1.1 jmcneill
1698 1.1 jmcneill if (ic->ic_flags & IEEE80211_F_SCAN)
1699 1.1 jmcneill ieee80211_add_scan(ic, &scan, &wh, IEEE80211_FC0_SUBTYPE_BEACON,
1700 1.1 jmcneill le32toh(bss->rssi), 0);
1701 1.1 jmcneill }
1702