Line data Source code
1 : /* $OpenBSD: if_malo.c,v 1.93 2017/10/26 15:00:28 mpi Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org>
5 : *
6 : * Permission to use, copy, modify, and distribute this software for any
7 : * purpose with or without fee is hereby granted, provided that the above
8 : * copyright notice and this permission notice appear in all copies.
9 : *
10 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 : */
18 :
19 : #include "bpfilter.h"
20 :
21 : #include <sys/param.h>
22 : #include <sys/systm.h>
23 : #include <sys/kernel.h>
24 : #include <sys/device.h>
25 : #include <sys/timeout.h>
26 : #include <sys/socket.h>
27 : #include <sys/tree.h>
28 : #include <sys/malloc.h>
29 : #include <sys/sockio.h>
30 : #include <sys/mbuf.h>
31 :
32 : #if NBPFILTER > 0
33 : #include <net/bpf.h>
34 : #endif
35 :
36 : #include <net/if.h>
37 : #include <net/if_dl.h>
38 : #include <net/if_media.h>
39 : #include <net/if_llc.h>
40 :
41 : #include <netinet/in.h>
42 : #include <netinet/if_ether.h>
43 :
44 : #include <net80211/ieee80211_var.h>
45 : #include <net80211/ieee80211_radiotap.h>
46 :
47 : #include <machine/bus.h>
48 : #include <machine/intr.h>
49 :
50 : #include <dev/pcmcia/pcmciavar.h>
51 : #include <dev/pcmcia/pcmciadevs.h>
52 :
53 : #include <dev/pcmcia/if_malovar.h>
54 : #include <dev/pcmcia/if_maloreg.h>
55 :
56 : /*
57 : * Driver for the Marvell 88W8385 chip (Compact Flash).
58 : */
59 :
60 : #ifdef CMALO_DEBUG
61 : int cmalo_d = 1;
62 : #define DPRINTF(l, x...) do { if ((l) <= cmalo_d) printf(x); } while (0)
63 : #else
64 : #define DPRINTF(l, x...)
65 : #endif
66 :
67 : int malo_pcmcia_match(struct device *, void *, void *);
68 : void malo_pcmcia_attach(struct device *, struct device *, void *);
69 : int malo_pcmcia_detach(struct device *, int);
70 : int malo_pcmcia_activate(struct device *, int);
71 : void malo_pcmcia_wakeup(struct malo_softc *);
72 :
73 : void cmalo_attach(struct device *);
74 : int cmalo_ioctl(struct ifnet *, u_long, caddr_t);
75 : int cmalo_fw_alloc(struct malo_softc *);
76 : void cmalo_fw_free(struct malo_softc *);
77 : int cmalo_fw_load_helper(struct malo_softc *);
78 : int cmalo_fw_load_main(struct malo_softc *);
79 : int cmalo_init(struct ifnet *);
80 : void cmalo_stop(struct malo_softc *);
81 : int cmalo_media_change(struct ifnet *);
82 : int cmalo_newstate(struct ieee80211com *, enum ieee80211_state, int);
83 : void cmalo_detach(void *);
84 : int cmalo_intr(void *);
85 : void cmalo_intr_mask(struct malo_softc *, int);
86 : void cmalo_rx(struct malo_softc *);
87 : void cmalo_start(struct ifnet *);
88 : void cmalo_watchdog(struct ifnet *);
89 : int cmalo_tx(struct malo_softc *, struct mbuf *);
90 : void cmalo_tx_done(struct malo_softc *);
91 : void cmalo_event(struct malo_softc *);
92 : void cmalo_select_network(struct malo_softc *);
93 : void cmalo_reflect_network(struct malo_softc *);
94 : int cmalo_wep(struct malo_softc *);
95 : int cmalo_rate2bitmap(int);
96 :
97 : void cmalo_hexdump(void *, int);
98 : int cmalo_cmd_get_hwspec(struct malo_softc *);
99 : int cmalo_cmd_rsp_hwspec(struct malo_softc *);
100 : int cmalo_cmd_set_reset(struct malo_softc *);
101 : int cmalo_cmd_set_scan(struct malo_softc *);
102 : int cmalo_cmd_rsp_scan(struct malo_softc *);
103 : int cmalo_parse_elements(struct malo_softc *, void *, int, int);
104 : int cmalo_cmd_set_auth(struct malo_softc *);
105 : int cmalo_cmd_set_wep(struct malo_softc *, uint16_t,
106 : struct ieee80211_key *);
107 : int cmalo_cmd_set_snmp(struct malo_softc *, uint16_t);
108 : int cmalo_cmd_set_radio(struct malo_softc *, uint16_t);
109 : int cmalo_cmd_set_channel(struct malo_softc *, uint16_t);
110 : int cmalo_cmd_set_txpower(struct malo_softc *, int16_t);
111 : int cmalo_cmd_set_antenna(struct malo_softc *, uint16_t);
112 : int cmalo_cmd_set_macctrl(struct malo_softc *);
113 : int cmalo_cmd_set_macaddr(struct malo_softc *, uint8_t *);
114 : int cmalo_cmd_set_assoc(struct malo_softc *);
115 : int cmalo_cmd_rsp_assoc(struct malo_softc *);
116 : int cmalo_cmd_set_80211d(struct malo_softc *);
117 : int cmalo_cmd_set_bgscan_config(struct malo_softc *);
118 : int cmalo_cmd_set_bgscan_query(struct malo_softc *);
119 : int cmalo_cmd_set_rate(struct malo_softc *, int);
120 : int cmalo_cmd_request(struct malo_softc *, uint16_t, int);
121 : int cmalo_cmd_response(struct malo_softc *);
122 :
123 : /*
124 : * PCMCIA bus.
125 : */
126 : struct malo_pcmcia_softc {
127 : struct malo_softc sc_malo;
128 :
129 : struct pcmcia_function *sc_pf;
130 : struct pcmcia_io_handle sc_pcioh;
131 : int sc_io_window;
132 : void *sc_ih;
133 : };
134 :
135 : struct cfattach malo_pcmcia_ca = {
136 : sizeof(struct malo_pcmcia_softc),
137 : malo_pcmcia_match,
138 : malo_pcmcia_attach,
139 : malo_pcmcia_detach,
140 : malo_pcmcia_activate
141 : };
142 :
143 : int
144 0 : malo_pcmcia_match(struct device *parent, void *match, void *aux)
145 : {
146 0 : struct pcmcia_attach_args *pa = aux;
147 :
148 0 : if (pa->manufacturer == PCMCIA_VENDOR_AMBICOM &&
149 0 : pa->product == PCMCIA_PRODUCT_AMBICOM_WL54CF)
150 0 : return (1);
151 :
152 0 : return (0);
153 0 : }
154 :
155 : void
156 0 : malo_pcmcia_attach(struct device *parent, struct device *self, void *aux)
157 : {
158 0 : struct malo_pcmcia_softc *psc = (struct malo_pcmcia_softc *)self;
159 0 : struct malo_softc *sc = &psc->sc_malo;
160 0 : struct pcmcia_attach_args *pa = aux;
161 : struct pcmcia_config_entry *cfe;
162 : const char *intrstr = NULL;
163 :
164 0 : psc->sc_pf = pa->pf;
165 0 : cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head);
166 :
167 : /* enable card */
168 0 : pcmcia_function_init(psc->sc_pf, cfe);
169 0 : if (pcmcia_function_enable(psc->sc_pf)) {
170 0 : printf(": can't enable function\n");
171 0 : return;
172 : }
173 :
174 : /* allocate I/O space */
175 0 : if (pcmcia_io_alloc(psc->sc_pf, 0,
176 : cfe->iospace[0].length, cfe->iospace[0].length, &psc->sc_pcioh)) {
177 0 : printf(": can't allocate i/o space\n");
178 0 : pcmcia_function_disable(psc->sc_pf);
179 0 : return;
180 : }
181 :
182 : /* map I/O space */
183 0 : if (pcmcia_io_map(psc->sc_pf, PCMCIA_WIDTH_IO16, 0,
184 0 : cfe->iospace[0].length, &psc->sc_pcioh, &psc->sc_io_window)) {
185 0 : printf(": can't map i/o space\n");
186 0 : pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
187 0 : pcmcia_function_disable(psc->sc_pf);
188 0 : return;
189 : }
190 0 : sc->sc_iot = psc->sc_pcioh.iot;
191 0 : sc->sc_ioh = psc->sc_pcioh.ioh;
192 :
193 0 : printf(" port 0x%lx/%ld", psc->sc_pcioh.addr, psc->sc_pcioh.size);
194 :
195 : /* establish interrupt */
196 0 : psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, cmalo_intr, sc,
197 0 : sc->sc_dev.dv_xname);
198 0 : if (psc->sc_ih == NULL) {
199 0 : printf(": can't establish interrupt\n");
200 0 : return;
201 : }
202 0 : intrstr = pcmcia_intr_string(psc->sc_pf, psc->sc_ih);
203 0 : if (intrstr != NULL) {
204 0 : if (*intrstr != '\0')
205 0 : printf(", %s", intrstr);
206 : }
207 0 : printf("\n");
208 :
209 0 : config_mountroot(self, cmalo_attach);
210 0 : }
211 :
212 : int
213 0 : malo_pcmcia_detach(struct device *dev, int flags)
214 : {
215 0 : struct malo_pcmcia_softc *psc = (struct malo_pcmcia_softc *)dev;
216 0 : struct malo_softc *sc = &psc->sc_malo;
217 :
218 0 : cmalo_detach(sc);
219 :
220 0 : pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
221 0 : pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
222 :
223 0 : return (0);
224 : }
225 :
226 : int
227 0 : malo_pcmcia_activate(struct device *dev, int act)
228 : {
229 0 : struct malo_pcmcia_softc *psc = (struct malo_pcmcia_softc *)dev;
230 0 : struct malo_softc *sc = &psc->sc_malo;
231 0 : struct ieee80211com *ic = &sc->sc_ic;
232 0 : struct ifnet *ifp = &ic->ic_if;
233 :
234 0 : switch (act) {
235 : case DVACT_SUSPEND:
236 0 : if ((sc->sc_flags & MALO_DEVICE_ATTACHED) &&
237 0 : (ifp->if_flags & IFF_RUNNING))
238 0 : cmalo_stop(sc);
239 0 : if (psc->sc_ih)
240 0 : pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
241 0 : psc->sc_ih = NULL;
242 0 : pcmcia_function_disable(psc->sc_pf);
243 0 : break;
244 : case DVACT_RESUME:
245 0 : pcmcia_function_enable(psc->sc_pf);
246 0 : psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET,
247 0 : cmalo_intr, sc, sc->sc_dev.dv_xname);
248 0 : break;
249 : case DVACT_WAKEUP:
250 0 : malo_pcmcia_wakeup(sc);
251 0 : break;
252 : case DVACT_DEACTIVATE:
253 0 : if ((sc->sc_flags & MALO_DEVICE_ATTACHED) &&
254 0 : (ifp->if_flags & IFF_RUNNING))
255 0 : cmalo_stop(sc); /* XXX tries to touch regs */
256 0 : if (psc->sc_ih)
257 0 : pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
258 0 : psc->sc_ih = NULL;
259 0 : pcmcia_function_disable(psc->sc_pf);
260 0 : break;
261 : }
262 0 : return (0);
263 : }
264 :
265 : void
266 0 : malo_pcmcia_wakeup(struct malo_softc *sc)
267 : {
268 0 : struct ieee80211com *ic = &sc->sc_ic;
269 0 : struct ifnet *ifp = &ic->ic_if;
270 : int s;
271 :
272 0 : s = splnet();
273 0 : while (sc->sc_flags & MALO_BUSY)
274 0 : tsleep(&sc->sc_flags, 0, "malopwr", 0);
275 0 : sc->sc_flags |= MALO_BUSY;
276 :
277 0 : cmalo_init(ifp);
278 :
279 0 : sc->sc_flags &= ~MALO_BUSY;
280 0 : wakeup(&sc->sc_flags);
281 0 : splx(s);
282 0 : }
283 :
284 : /*
285 : * Driver.
286 : */
287 : void
288 0 : cmalo_attach(struct device *self)
289 : {
290 0 : struct malo_softc *sc = (struct malo_softc *)self;
291 0 : struct ieee80211com *ic = &sc->sc_ic;
292 0 : struct ifnet *ifp = &sc->sc_ic.ic_if;
293 : int i;
294 :
295 : /* disable interrupts */
296 0 : cmalo_intr_mask(sc, 0);
297 :
298 : /* load firmware */
299 0 : if (cmalo_fw_alloc(sc) != 0)
300 0 : return;
301 0 : if (cmalo_fw_load_helper(sc) != 0)
302 0 : return;
303 0 : if (cmalo_fw_load_main(sc) != 0)
304 0 : return;
305 0 : sc->sc_flags |= MALO_FW_LOADED;
306 :
307 : /* allocate command buffer */
308 0 : sc->sc_cmd = malloc(MALO_CMD_BUFFER_SIZE, M_DEVBUF, M_NOWAIT);
309 :
310 : /* allocate data buffer */
311 0 : sc->sc_data = malloc(MCLBYTES, M_DEVBUF, M_NOWAIT);
312 :
313 : /* enable interrupts */
314 0 : cmalo_intr_mask(sc, 1);
315 :
316 : /* we are context save here for FW commands */
317 0 : sc->sc_cmd_ctxsave = 1;
318 :
319 : /* get hardware specs */
320 0 : cmalo_cmd_get_hwspec(sc);
321 :
322 : /* setup interface */
323 0 : ifp->if_softc = sc;
324 0 : ifp->if_ioctl = cmalo_ioctl;
325 0 : ifp->if_start = cmalo_start;
326 0 : ifp->if_watchdog = cmalo_watchdog;
327 0 : ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
328 0 : strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
329 :
330 0 : ic->ic_opmode = IEEE80211_M_STA;
331 0 : ic->ic_state = IEEE80211_S_INIT;
332 0 : ic->ic_caps = IEEE80211_C_MONITOR | IEEE80211_C_WEP;
333 :
334 0 : ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
335 0 : ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
336 :
337 0 : for (i = 0; i <= 14; i++) {
338 0 : ic->ic_channels[i].ic_freq =
339 0 : ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
340 0 : ic->ic_channels[i].ic_flags =
341 : IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
342 : IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
343 : }
344 :
345 : /* attach interface */
346 0 : if_attach(ifp);
347 0 : ieee80211_ifattach(ifp);
348 :
349 0 : sc->sc_newstate = ic->ic_newstate;
350 0 : ic->ic_newstate = cmalo_newstate;
351 0 : ieee80211_media_init(ifp, cmalo_media_change, ieee80211_media_status);
352 :
353 : /* second attach line */
354 0 : printf("%s: address %s\n",
355 0 : sc->sc_dev.dv_xname, ether_sprintf(ic->ic_myaddr));
356 :
357 : /* device attached */
358 0 : sc->sc_flags |= MALO_DEVICE_ATTACHED;
359 0 : }
360 :
361 : int
362 0 : cmalo_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
363 : {
364 0 : struct malo_softc *sc = ifp->if_softc;
365 : struct ieee80211_nodereq_all *na;
366 : struct ieee80211_nodereq *nr;
367 : int i, j, s, error = 0;
368 :
369 0 : s = splnet();
370 : /*
371 : * Prevent processes from entering this function while another
372 : * process is tsleep'ing in it.
373 : */
374 0 : while ((sc->sc_flags & MALO_BUSY) && error == 0)
375 0 : error = tsleep(&sc->sc_flags, PCATCH, "maloioc", 0);
376 0 : if (error != 0) {
377 0 : splx(s);
378 0 : return error;
379 : }
380 0 : sc->sc_flags |= MALO_BUSY;
381 :
382 0 : switch (cmd) {
383 : case SIOCSIFADDR:
384 0 : ifp->if_flags |= IFF_UP;
385 : /* FALLTHROUGH */
386 : case SIOCSIFFLAGS:
387 0 : if (ifp->if_flags & IFF_UP) {
388 0 : if ((ifp->if_flags & IFF_RUNNING) == 0)
389 0 : cmalo_init(ifp);
390 : } else {
391 0 : if (ifp->if_flags & IFF_RUNNING)
392 0 : cmalo_stop(sc);
393 : }
394 : break;
395 : case SIOCS80211SCAN:
396 0 : cmalo_cmd_set_scan(sc);
397 0 : break;
398 : case SIOCG80211ALLNODES:
399 : nr = NULL;
400 0 : na = (struct ieee80211_nodereq_all *)data;
401 :
402 0 : if ((nr = malloc(sizeof(*nr), M_DEVBUF, M_WAITOK)) == NULL)
403 : break;
404 :
405 0 : for (na->na_nodes = i = j = 0; i < sc->sc_net_num &&
406 0 : (na->na_size >= j + sizeof(struct ieee80211_nodereq));
407 0 : i++) {
408 0 : bzero(nr, sizeof(*nr));
409 :
410 0 : IEEE80211_ADDR_COPY(nr->nr_macaddr,
411 : sc->sc_net[i].bssid);
412 0 : IEEE80211_ADDR_COPY(nr->nr_bssid,
413 : sc->sc_net[i].bssid);
414 0 : nr->nr_channel = sc->sc_net[i].channel;
415 0 : nr->nr_chan_flags = IEEE80211_CHAN_B; /* XXX */
416 0 : nr->nr_rssi = sc->sc_net[i].rssi;
417 0 : nr->nr_max_rssi = 0; /* XXX */
418 0 : nr->nr_nwid_len = strlen(sc->sc_net[i].ssid);
419 0 : bcopy(sc->sc_net[i].ssid, nr->nr_nwid,
420 0 : nr->nr_nwid_len);
421 0 : nr->nr_intval = sc->sc_net[i].beaconintvl;
422 0 : nr->nr_capinfo = sc->sc_net[i].capinfo;
423 0 : nr->nr_flags |= IEEE80211_NODEREQ_AP;
424 :
425 0 : if (copyout(nr, (caddr_t)na->na_node + j,
426 : sizeof(struct ieee80211_nodereq)))
427 : break;
428 :
429 0 : j += sizeof(struct ieee80211_nodereq);
430 0 : na->na_nodes++;
431 : }
432 :
433 0 : if (nr)
434 0 : free(nr, M_DEVBUF, 0);
435 : break;
436 : default:
437 0 : error = ieee80211_ioctl(ifp, cmd, data);
438 0 : break;
439 : }
440 :
441 0 : if (error == ENETRESET) {
442 0 : if (ifp->if_flags & (IFF_UP | IFF_RUNNING))
443 0 : cmalo_init(ifp);
444 : error = 0;
445 0 : }
446 :
447 0 : sc->sc_flags &= ~MALO_BUSY;
448 0 : wakeup(&sc->sc_flags);
449 0 : splx(s);
450 :
451 0 : return (error);
452 0 : }
453 :
454 : int
455 0 : cmalo_fw_alloc(struct malo_softc *sc)
456 : {
457 : const char *name_h = "malo8385-h";
458 : const char *name_m = "malo8385-m";
459 : int error;
460 :
461 0 : if (sc->sc_fw_h == NULL) {
462 : /* read helper firmware image */
463 0 : error = loadfirmware(name_h, &sc->sc_fw_h, &sc->sc_fw_h_size);
464 0 : if (error != 0) {
465 0 : printf("%s: error %d, could not read firmware %s\n",
466 0 : sc->sc_dev.dv_xname, error, name_h);
467 0 : return (EIO);
468 : }
469 : }
470 :
471 0 : if (sc->sc_fw_m == NULL) {
472 : /* read main firmware image */
473 0 : error = loadfirmware(name_m, &sc->sc_fw_m, &sc->sc_fw_m_size);
474 0 : if (error != 0) {
475 0 : printf("%s: error %d, could not read firmware %s\n",
476 0 : sc->sc_dev.dv_xname, error, name_m);
477 0 : return (EIO);
478 : }
479 : }
480 :
481 0 : return (0);
482 0 : }
483 :
484 : void
485 0 : cmalo_fw_free(struct malo_softc *sc)
486 : {
487 0 : if (sc->sc_fw_h != NULL) {
488 0 : free(sc->sc_fw_h, M_DEVBUF, 0);
489 0 : sc->sc_fw_h = NULL;
490 0 : }
491 :
492 0 : if (sc->sc_fw_m != NULL) {
493 0 : free(sc->sc_fw_m, M_DEVBUF, 0);
494 0 : sc->sc_fw_m = NULL;
495 0 : }
496 0 : }
497 :
498 : int
499 0 : cmalo_fw_load_helper(struct malo_softc *sc)
500 : {
501 : uint8_t val8;
502 : uint16_t bsize, *uc;
503 : int offset, i;
504 :
505 : /* verify if the card is ready for firmware download */
506 0 : val8 = MALO_READ_1(sc, MALO_REG_SCRATCH);
507 0 : if (val8 == MALO_VAL_SCRATCH_FW_LOADED)
508 : /* firmware already loaded */
509 0 : return (0);
510 0 : if (val8 != MALO_VAL_SCRATCH_READY) {
511 : /* bad register value */
512 0 : printf("%s: device not ready for FW download\n",
513 0 : sc->sc_dev.dv_xname);
514 0 : return (EIO);
515 : }
516 :
517 : /* download the helper firmware */
518 0 : for (offset = 0; offset < sc->sc_fw_h_size; offset += bsize) {
519 0 : if (sc->sc_fw_h_size - offset >= MALO_FW_HELPER_BSIZE)
520 0 : bsize = MALO_FW_HELPER_BSIZE;
521 : else
522 0 : bsize = sc->sc_fw_h_size - offset;
523 :
524 : /* send a block in words and confirm it */
525 : DPRINTF(3, "%s: download helper FW block (%d bytes, %d off)\n",
526 : sc->sc_dev.dv_xname, bsize, offset);
527 0 : MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, bsize);
528 0 : uc = (uint16_t *)(sc->sc_fw_h + offset);
529 0 : for (i = 0; i < bsize / 2; i++)
530 0 : MALO_WRITE_2(sc, MALO_REG_CMD_WRITE, htole16(uc[i]));
531 0 : MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER);
532 0 : MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE,
533 : MALO_VAL_CMD_DL_OVER);
534 :
535 : /* poll for an acknowledgement */
536 0 : for (i = 0; i < 50; i++) {
537 0 : if (MALO_READ_1(sc, MALO_REG_CARD_STATUS) ==
538 : MALO_VAL_CMD_DL_OVER)
539 : break;
540 0 : delay(1000);
541 : }
542 0 : if (i == 50) {
543 0 : printf("%s: timeout while helper FW block download\n",
544 0 : sc->sc_dev.dv_xname);
545 0 : return (EIO);
546 : }
547 : }
548 :
549 : /* helper firmware download done */
550 0 : MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, 0);
551 0 : MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER);
552 0 : MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_CMD_DL_OVER);
553 : DPRINTF(1, "%s: helper FW downloaded\n", sc->sc_dev.dv_xname);
554 :
555 0 : return (0);
556 0 : }
557 :
558 : int
559 0 : cmalo_fw_load_main(struct malo_softc *sc)
560 : {
561 : uint16_t val16, bsize, *uc;
562 : int offset, i, retry = 0;
563 :
564 : /* verify if the helper firmware has been loaded correctly */
565 0 : for (i = 0; i < 10; i++) {
566 0 : if (MALO_READ_1(sc, MALO_REG_RBAL) == MALO_FW_HELPER_LOADED)
567 : break;
568 0 : delay(1000);
569 : }
570 0 : if (i == 10) {
571 0 : printf("%s: helper FW not loaded\n", sc->sc_dev.dv_xname);
572 0 : return (EIO);
573 : }
574 : DPRINTF(1, "%s: helper FW loaded successfully\n", sc->sc_dev.dv_xname);
575 :
576 : /* download the main firmware */
577 : bsize = 0; /* XXX really??? */
578 0 : for (offset = 0; offset < sc->sc_fw_m_size; offset += bsize) {
579 0 : val16 = MALO_READ_2(sc, MALO_REG_RBAL);
580 : /*
581 : * If the helper firmware serves us an odd integer then
582 : * something went wrong and we retry to download the last
583 : * block until we receive a good integer again, or give up.
584 : */
585 0 : if (val16 & 0x0001) {
586 0 : if (retry > MALO_FW_MAIN_MAXRETRY) {
587 0 : printf("%s: main FW download failed\n",
588 0 : sc->sc_dev.dv_xname);
589 0 : return (EIO);
590 : }
591 0 : retry++;
592 0 : offset -= bsize;
593 0 : } else {
594 : retry = 0;
595 : bsize = val16;
596 : }
597 :
598 : /* send a block in words and confirm it */
599 : DPRINTF(3, "%s: download main FW block (%d bytes, %d off)\n",
600 : sc->sc_dev.dv_xname, bsize, offset);
601 0 : MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, bsize);
602 0 : uc = (uint16_t *)(sc->sc_fw_m + offset);
603 0 : for (i = 0; i < bsize / 2; i++)
604 0 : MALO_WRITE_2(sc, MALO_REG_CMD_WRITE, htole16(uc[i]));
605 0 : MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER);
606 0 : MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE,
607 : MALO_VAL_CMD_DL_OVER);
608 :
609 : /* poll for an acknowledgement */
610 0 : for (i = 0; i < 5000; i++) {
611 0 : if (MALO_READ_1(sc, MALO_REG_CARD_STATUS) ==
612 : MALO_VAL_CMD_DL_OVER)
613 : break;
614 : }
615 0 : if (i == 5000) {
616 0 : printf("%s: timeout while main FW block download\n",
617 0 : sc->sc_dev.dv_xname);
618 0 : return (EIO);
619 : }
620 : }
621 :
622 : DPRINTF(1, "%s: main FW downloaded\n", sc->sc_dev.dv_xname);
623 :
624 : /* verify if the main firmware has been loaded correctly */
625 0 : for (i = 0; i < 500; i++) {
626 0 : if (MALO_READ_1(sc, MALO_REG_SCRATCH) ==
627 : MALO_VAL_SCRATCH_FW_LOADED)
628 : break;
629 0 : delay(1000);
630 : }
631 0 : if (i == 500) {
632 0 : printf("%s: main FW not loaded\n", sc->sc_dev.dv_xname);
633 0 : return (EIO);
634 : }
635 :
636 : DPRINTF(1, "%s: main FW loaded successfully\n", sc->sc_dev.dv_xname);
637 :
638 0 : return (0);
639 0 : }
640 :
641 : int
642 0 : cmalo_init(struct ifnet *ifp)
643 : {
644 0 : struct malo_softc *sc = ifp->if_softc;
645 0 : struct ieee80211com *ic = &sc->sc_ic;
646 :
647 : /* reload the firmware if necessary */
648 0 : if (!(sc->sc_flags & MALO_FW_LOADED)) {
649 : /* disable interrupts */
650 0 : cmalo_intr_mask(sc, 0);
651 :
652 : /* load firmware */
653 0 : if (cmalo_fw_load_helper(sc) != 0)
654 0 : return (EIO);
655 0 : if (cmalo_fw_load_main(sc) != 0)
656 0 : return (EIO);
657 0 : sc->sc_flags |= MALO_FW_LOADED;
658 :
659 : /* enable interrupts */
660 0 : cmalo_intr_mask(sc, 1);
661 0 : }
662 :
663 : /* reset association state flag */
664 0 : sc->sc_flags &= ~MALO_ASSOC_FAILED;
665 :
666 : /* get current channel */
667 0 : ic->ic_bss->ni_chan = ic->ic_ibss_chan;
668 0 : sc->sc_curchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
669 : DPRINTF(1, "%s: current channel is %d\n",
670 : sc->sc_dev.dv_xname, sc->sc_curchan);
671 :
672 : /* setup device */
673 0 : if (cmalo_cmd_set_macctrl(sc) != 0)
674 0 : return (EIO);
675 0 : if (cmalo_cmd_set_txpower(sc, 15) != 0)
676 0 : return (EIO);
677 0 : if (cmalo_cmd_set_antenna(sc, 1) != 0)
678 0 : return (EIO);
679 0 : if (cmalo_cmd_set_antenna(sc, 2) != 0)
680 0 : return (EIO);
681 0 : if (cmalo_cmd_set_radio(sc, 1) != 0)
682 0 : return (EIO);
683 0 : if (cmalo_cmd_set_channel(sc, sc->sc_curchan) != 0)
684 0 : return (EIO);
685 0 : if (cmalo_cmd_set_rate(sc, ic->ic_fixed_rate) != 0)
686 0 : return (EIO);
687 0 : if (cmalo_cmd_set_snmp(sc, MALO_OID_RTSTRESH) != 0)
688 0 : return (EIO);
689 0 : if (cmalo_cmd_set_snmp(sc, MALO_OID_SHORTRETRY) != 0)
690 0 : return (EIO);
691 0 : if (cmalo_cmd_set_snmp(sc, MALO_OID_FRAGTRESH) != 0)
692 0 : return (EIO);
693 0 : IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
694 0 : if (cmalo_cmd_set_macaddr(sc, ic->ic_myaddr) != 0)
695 0 : return (EIO);
696 0 : if (sc->sc_ic.ic_flags & IEEE80211_F_WEPON) {
697 0 : if (cmalo_wep(sc) != 0)
698 0 : return (EIO);
699 : }
700 :
701 : /* device up */
702 0 : ifp->if_flags |= IFF_RUNNING;
703 0 : ifq_clr_oactive(&ifp->if_snd);
704 :
705 : /* start network */
706 0 : if (ic->ic_opmode != IEEE80211_M_MONITOR)
707 0 : ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
708 0 : if (sc->sc_flags & MALO_ASSOC_FAILED)
709 0 : ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
710 : else
711 0 : ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
712 :
713 : /* we are not context save anymore for FW commands */
714 0 : sc->sc_cmd_ctxsave = 0;
715 :
716 0 : return (0);
717 0 : }
718 :
719 : void
720 0 : cmalo_stop(struct malo_softc *sc)
721 : {
722 0 : struct ieee80211com *ic = &sc->sc_ic;
723 0 : struct ifnet *ifp = &ic->ic_if;
724 :
725 : /* device down */
726 0 : ifp->if_flags &= ~IFF_RUNNING;
727 0 : ifq_clr_oactive(&ifp->if_snd);
728 :
729 : /* change device back to initial state */
730 0 : ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
731 :
732 : /* reset device */
733 0 : cmalo_cmd_set_reset(sc);
734 0 : sc->sc_flags &= ~MALO_FW_LOADED;
735 0 : ifp->if_timer = 0;
736 :
737 : DPRINTF(1, "%s: device down\n", sc->sc_dev.dv_xname);
738 0 : }
739 :
740 : int
741 0 : cmalo_media_change(struct ifnet *ifp)
742 : {
743 : int error;
744 :
745 0 : if ((error = ieee80211_media_change(ifp) != ENETRESET))
746 0 : return (error);
747 :
748 0 : if (ifp->if_flags & (IFF_UP | IFF_RUNNING))
749 0 : cmalo_init(ifp);
750 :
751 0 : return (0);
752 0 : }
753 :
754 : int
755 0 : cmalo_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
756 : {
757 0 : struct malo_softc *sc = ic->ic_if.if_softc;
758 : enum ieee80211_state ostate;
759 :
760 0 : ostate = ic->ic_state;
761 :
762 0 : if (ostate == nstate)
763 : goto out;
764 :
765 0 : switch (nstate) {
766 : case IEEE80211_S_INIT:
767 : DPRINTF(1, "%s: newstate is IEEE80211_S_INIT\n",
768 : sc->sc_dev.dv_xname);
769 : break;
770 : case IEEE80211_S_SCAN:
771 : DPRINTF(1, "%s: newstate is IEEE80211_S_SCAN\n",
772 : sc->sc_dev.dv_xname);
773 0 : cmalo_cmd_set_scan(sc);
774 0 : if (!sc->sc_net_num) {
775 : /* no networks found */
776 : DPRINTF(1, "%s: no networks found\n",
777 : sc->sc_dev.dv_xname);
778 : break;
779 : }
780 0 : cmalo_select_network(sc);
781 0 : cmalo_cmd_set_auth(sc);
782 0 : cmalo_cmd_set_assoc(sc);
783 0 : break;
784 : case IEEE80211_S_AUTH:
785 : DPRINTF(1, "%s: newstate is IEEE80211_S_AUTH\n",
786 : sc->sc_dev.dv_xname);
787 : break;
788 : case IEEE80211_S_ASSOC:
789 : DPRINTF(1, "%s: newstate is IEEE80211_S_ASSOC\n",
790 : sc->sc_dev.dv_xname);
791 : break;
792 : case IEEE80211_S_RUN:
793 : DPRINTF(1, "%s: newstate is IEEE80211_S_RUN\n",
794 : sc->sc_dev.dv_xname);
795 0 : cmalo_reflect_network(sc);
796 0 : break;
797 : default:
798 : break;
799 : }
800 :
801 : out:
802 0 : return (sc->sc_newstate(ic, nstate, arg));
803 : }
804 :
805 : void
806 0 : cmalo_detach(void *arg)
807 : {
808 0 : struct malo_softc *sc = arg;
809 0 : struct ieee80211com *ic = &sc->sc_ic;
810 0 : struct ifnet *ifp = &ic->ic_if;
811 :
812 0 : if (!(sc->sc_flags & MALO_DEVICE_ATTACHED))
813 : /* device was not properly attached */
814 0 : return;
815 :
816 : /* free command buffer */
817 0 : if (sc->sc_cmd != NULL)
818 0 : free(sc->sc_cmd, M_DEVBUF, 0);
819 :
820 : /* free data buffer */
821 0 : if (sc->sc_data != NULL)
822 0 : free(sc->sc_data, M_DEVBUF, 0);
823 :
824 : /* free firmware */
825 0 : cmalo_fw_free(sc);
826 :
827 : /* detach inferface */
828 0 : ieee80211_ifdetach(ifp);
829 0 : if_detach(ifp);
830 0 : }
831 :
832 : int
833 0 : cmalo_intr(void *arg)
834 : {
835 0 : struct malo_softc *sc = arg;
836 : uint16_t intr = 0;
837 :
838 : /* read interrupt reason */
839 0 : intr = MALO_READ_2(sc, MALO_REG_HOST_INTR_CAUSE);
840 0 : if (intr == 0) {
841 : /* interrupt not for us */
842 0 : return (0);
843 : }
844 0 : if (intr == 0xffff) {
845 : /* card has been detached */
846 0 : return (0);
847 : }
848 :
849 : /* disable interrupts */
850 0 : cmalo_intr_mask(sc, 0);
851 :
852 : /* acknowledge interrupt */
853 0 : MALO_WRITE_2(sc, MALO_REG_HOST_INTR_CAUSE,
854 : intr & MALO_VAL_HOST_INTR_MASK_ON);
855 :
856 : /* enable interrupts */
857 0 : cmalo_intr_mask(sc, 1);
858 :
859 : DPRINTF(2, "%s: interrupt handler called (intr = 0x%04x)\n",
860 : sc->sc_dev.dv_xname, intr);
861 :
862 0 : if (intr & MALO_VAL_HOST_INTR_TX)
863 : /* TX frame sent */
864 0 : cmalo_tx_done(sc);
865 0 : if (intr & MALO_VAL_HOST_INTR_RX)
866 : /* RX frame received */
867 0 : cmalo_rx(sc);
868 0 : if (intr & MALO_VAL_HOST_INTR_CMD) {
869 : /* command response */
870 0 : wakeup(sc);
871 0 : if (!sc->sc_cmd_ctxsave)
872 0 : cmalo_cmd_response(sc);
873 : }
874 0 : if (intr & MALO_VAL_HOST_INTR_EVENT)
875 : /* event */
876 0 : cmalo_event(sc);
877 :
878 0 : return (1);
879 0 : }
880 :
881 : void
882 0 : cmalo_intr_mask(struct malo_softc *sc, int enable)
883 : {
884 : uint16_t val16;
885 :
886 0 : val16 = MALO_READ_2(sc, MALO_REG_HOST_INTR_MASK);
887 :
888 : DPRINTF(3, "%s: intr mask changed from 0x%04x ",
889 : sc->sc_dev.dv_xname, val16);
890 :
891 0 : if (enable)
892 0 : MALO_WRITE_2(sc, MALO_REG_HOST_INTR_MASK,
893 : val16 & ~MALO_VAL_HOST_INTR_MASK_ON);
894 : else
895 0 : MALO_WRITE_2(sc, MALO_REG_HOST_INTR_MASK,
896 : val16 | MALO_VAL_HOST_INTR_MASK_ON);
897 :
898 0 : val16 = MALO_READ_2(sc, MALO_REG_HOST_INTR_MASK);
899 :
900 : DPRINTF(3, "to 0x%04x\n", val16);
901 0 : }
902 :
903 : void
904 0 : cmalo_rx(struct malo_softc *sc)
905 : {
906 0 : struct ieee80211com *ic = &sc->sc_ic;
907 0 : struct ifnet *ifp = &ic->ic_if;
908 : struct malo_rx_desc *rxdesc;
909 0 : struct mbuf_list ml = MBUF_LIST_INITIALIZER();
910 : struct mbuf *m;
911 : uint8_t *data;
912 : uint16_t psize;
913 : int i;
914 :
915 0 : splassert(IPL_NET);
916 :
917 : /* read the whole RX packet which is always 802.3 */
918 0 : psize = MALO_READ_2(sc, MALO_REG_DATA_READ_LEN);
919 0 : if (psize & 0x0001) {
920 0 : MALO_READ_MULTI_2(sc, MALO_REG_DATA_READ, sc->sc_data,
921 : psize - 1);
922 0 : data = (uint8_t *)sc->sc_data;
923 0 : data[psize - 1] = MALO_READ_1(sc, MALO_REG_DATA_READ);
924 0 : } else
925 0 : MALO_READ_MULTI_2(sc, MALO_REG_DATA_READ, sc->sc_data, psize);
926 0 : MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_RX_DL_OVER);
927 0 : MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_RX_DL_OVER);
928 :
929 : /* access RX packet descriptor */
930 0 : rxdesc = (struct malo_rx_desc *)sc->sc_data;
931 0 : rxdesc->status = letoh16(rxdesc->status);
932 0 : rxdesc->pkglen = letoh16(rxdesc->pkglen);
933 0 : rxdesc->pkgoffset = letoh32(rxdesc->pkgoffset);
934 :
935 : DPRINTF(2, "RX status=%d, pkglen=%d, pkgoffset=%d\n",
936 : rxdesc->status, rxdesc->pkglen, rxdesc->pkgoffset);
937 :
938 0 : if (rxdesc->status != MALO_RX_STATUS_OK)
939 : /* RX packet is not OK */
940 0 : return;
941 :
942 : /* remove the LLC / SNAP header */
943 0 : data = sc->sc_data + rxdesc->pkgoffset;
944 : i = (ETHER_ADDR_LEN * 2) + sizeof(struct llc);
945 0 : bcopy(data + i, data + (ETHER_ADDR_LEN * 2), rxdesc->pkglen - i);
946 0 : rxdesc->pkglen -= sizeof(struct llc);
947 :
948 : /* prepare mbuf */
949 0 : m = m_devget(sc->sc_data + rxdesc->pkgoffset,
950 0 : rxdesc->pkglen, ETHER_ALIGN);
951 0 : if (m == NULL) {
952 : DPRINTF(1, "RX m_devget failed\n");
953 0 : ifp->if_ierrors++;
954 0 : return;
955 : }
956 :
957 : /* push the frame up to the network stack if not in monitor mode */
958 0 : if (ic->ic_opmode != IEEE80211_M_MONITOR) {
959 0 : ml_enqueue(&ml, m);
960 0 : if_input(ifp, &ml);
961 : #if NBPFILTER > 0
962 0 : } else {
963 0 : if (ifp->if_bpf)
964 0 : bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
965 : #endif
966 : }
967 :
968 0 : }
969 :
970 : void
971 0 : cmalo_start(struct ifnet *ifp)
972 : {
973 0 : struct malo_softc *sc = ifp->if_softc;
974 : struct mbuf *m;
975 :
976 : /* don't transmit packets if interface is busy or down */
977 0 : if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
978 0 : return;
979 :
980 0 : IFQ_DEQUEUE(&ifp->if_snd, m);
981 0 : if (m == NULL)
982 0 : return;
983 :
984 : #if NBPFILTER > 0
985 0 : if (ifp->if_bpf)
986 0 : bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
987 : #endif
988 :
989 0 : if (cmalo_tx(sc, m) != 0)
990 0 : ifp->if_oerrors++;
991 0 : }
992 :
993 : void
994 0 : cmalo_watchdog(struct ifnet *ifp)
995 : {
996 : DPRINTF(2, "watchdog timeout\n");
997 :
998 : /* accept TX packets again */
999 0 : ifq_clr_oactive(&ifp->if_snd);
1000 0 : }
1001 :
1002 : int
1003 0 : cmalo_tx(struct malo_softc *sc, struct mbuf *m)
1004 : {
1005 0 : struct ifnet *ifp = &sc->sc_ic.ic_if;
1006 0 : struct malo_tx_desc *txdesc = sc->sc_data;
1007 : uint8_t *data;
1008 : uint16_t psize;
1009 :
1010 0 : splassert(IPL_NET);
1011 :
1012 0 : bzero(sc->sc_data, sizeof(*txdesc));
1013 0 : psize = sizeof(*txdesc) + m->m_pkthdr.len;
1014 0 : data = mtod(m, uint8_t *);
1015 :
1016 : /* prepare TX descriptor */
1017 0 : txdesc->pkgoffset = htole32(sizeof(*txdesc));
1018 0 : txdesc->pkglen = htole16(m->m_pkthdr.len);
1019 0 : bcopy(data, txdesc->dstaddrhigh, sizeof(txdesc->dstaddrhigh));
1020 0 : bcopy(data + sizeof(txdesc->dstaddrhigh), txdesc->dstaddrlow,
1021 : sizeof(txdesc->dstaddrlow));
1022 :
1023 : /* copy mbuf data to the buffer */
1024 0 : m_copydata(m, 0, m->m_pkthdr.len, sc->sc_data + sizeof(*txdesc));
1025 0 : m_freem(m);
1026 :
1027 : /* send TX packet to the device */
1028 0 : MALO_WRITE_2(sc, MALO_REG_DATA_WRITE_LEN, psize);
1029 0 : if (psize & 0x0001) {
1030 0 : MALO_WRITE_MULTI_2(sc, MALO_REG_DATA_WRITE, sc->sc_data,
1031 : psize - 1);
1032 0 : data = (uint8_t *)sc->sc_data;
1033 0 : MALO_WRITE_1(sc, MALO_REG_DATA_WRITE, data[psize - 1]);
1034 0 : } else
1035 0 : MALO_WRITE_MULTI_2(sc, MALO_REG_DATA_WRITE, sc->sc_data, psize);
1036 0 : MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_TX_DL_OVER);
1037 0 : MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_TX_DL_OVER);
1038 :
1039 0 : ifq_set_oactive(&ifp->if_snd);
1040 0 : ifp->if_timer = 5;
1041 :
1042 : DPRINTF(2, "%s: TX status=%d, pkglen=%d, pkgoffset=%d\n",
1043 : sc->sc_dev.dv_xname, txdesc->status, letoh16(txdesc->pkglen),
1044 : sizeof(*txdesc));
1045 :
1046 0 : return (0);
1047 : }
1048 :
1049 : void
1050 0 : cmalo_tx_done(struct malo_softc *sc)
1051 : {
1052 0 : struct ifnet *ifp = &sc->sc_ic.ic_if;
1053 :
1054 0 : splassert(IPL_NET);
1055 :
1056 : DPRINTF(2, "%s: TX done\n", sc->sc_dev.dv_xname);
1057 :
1058 0 : ifq_clr_oactive(&ifp->if_snd);
1059 0 : ifp->if_timer = 0;
1060 0 : cmalo_start(ifp);
1061 0 : }
1062 :
1063 : void
1064 0 : cmalo_event(struct malo_softc *sc)
1065 : {
1066 : uint16_t event;
1067 :
1068 : /* read event reason */
1069 0 : event = MALO_READ_2(sc, MALO_REG_CARD_STATUS);
1070 0 : event &= MALO_VAL_CARD_STATUS_MASK;
1071 0 : event = event >> 8;
1072 :
1073 0 : switch (event) {
1074 : case MALO_EVENT_DEAUTH:
1075 : DPRINTF(1, "%s: got deauthentication event (0x%04x)\n",
1076 : sc->sc_dev.dv_xname, event);
1077 : /* try to associate again */
1078 0 : cmalo_cmd_set_assoc(sc);
1079 0 : break;
1080 : case MALO_EVENT_DISASSOC:
1081 : DPRINTF(1, "%s: got disassociation event (0x%04x)\n",
1082 : sc->sc_dev.dv_xname, event);
1083 : /* try to associate again */
1084 0 : cmalo_cmd_set_assoc(sc);
1085 0 : break;
1086 : default:
1087 : DPRINTF(1, "%s: got unknown event (0x%04x)\n",
1088 : sc->sc_dev.dv_xname, event);
1089 : break;
1090 : }
1091 :
1092 : /* acknowledge event */
1093 0 : MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_HOST_INTR_EVENT);
1094 0 : }
1095 :
1096 : void
1097 0 : cmalo_select_network(struct malo_softc *sc)
1098 : {
1099 0 : struct ieee80211com *ic = &sc->sc_ic;
1100 : int i, best_rssi;
1101 :
1102 : /* reset last selected network */
1103 0 : sc->sc_net_cur = 0;
1104 :
1105 : /* get desired network */
1106 0 : if (ic->ic_des_esslen) {
1107 0 : for (i = 0; i < sc->sc_net_num; i++) {
1108 0 : if (!strcmp(ic->ic_des_essid, sc->sc_net[i].ssid)) {
1109 0 : sc->sc_net_cur = i;
1110 : DPRINTF(1, "%s: desired network found (%s)\n",
1111 : sc->sc_dev.dv_xname, ic->ic_des_essid);
1112 0 : return;
1113 : }
1114 : }
1115 : DPRINTF(1, "%s: desired network not found in scan results "
1116 : "(%s)\n",
1117 : sc->sc_dev.dv_xname, ic->ic_des_essid);
1118 : }
1119 :
1120 : /* get network with best signal strength */
1121 0 : best_rssi = sc->sc_net[0].rssi;
1122 0 : for (i = 0; i < sc->sc_net_num; i++) {
1123 0 : if (best_rssi < sc->sc_net[i].rssi) {
1124 : best_rssi = sc->sc_net[i].rssi;
1125 0 : sc->sc_net_cur = i;
1126 0 : }
1127 : }
1128 : DPRINTF(1, "%s: best network found (%s)\n",
1129 : sc->sc_dev.dv_xname, sc->sc_net[sc->sc_net_cur].ssid);
1130 0 : }
1131 :
1132 : void
1133 0 : cmalo_reflect_network(struct malo_softc *sc)
1134 : {
1135 0 : struct ieee80211com *ic = &sc->sc_ic;
1136 : uint8_t chan;
1137 :
1138 : /* reflect active network to our 80211 stack */
1139 :
1140 : /* BSSID */
1141 0 : IEEE80211_ADDR_COPY(ic->ic_bss->ni_bssid,
1142 : sc->sc_net[sc->sc_net_cur].bssid);
1143 :
1144 : /* SSID */
1145 0 : ic->ic_bss->ni_esslen = strlen(sc->sc_net[sc->sc_net_cur].ssid);
1146 0 : bcopy(sc->sc_net[sc->sc_net_cur].ssid, ic->ic_bss->ni_essid,
1147 0 : ic->ic_bss->ni_esslen);
1148 :
1149 : /* channel */
1150 0 : chan = sc->sc_net[sc->sc_net_cur].channel;
1151 0 : ic->ic_bss->ni_chan = &ic->ic_channels[chan];
1152 0 : }
1153 :
1154 : int
1155 0 : cmalo_wep(struct malo_softc *sc)
1156 : {
1157 0 : struct ieee80211com *ic = &sc->sc_ic;
1158 : int i;
1159 :
1160 0 : for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1161 0 : struct ieee80211_key *key = &ic->ic_nw_keys[i];
1162 :
1163 0 : if (!key->k_len)
1164 0 : continue;
1165 :
1166 : DPRINTF(1, "%s: setting wep key for index %d\n",
1167 : sc->sc_dev.dv_xname, i);
1168 :
1169 0 : cmalo_cmd_set_wep(sc, i, key);
1170 0 : }
1171 :
1172 0 : return (0);
1173 : }
1174 :
1175 : int
1176 0 : cmalo_rate2bitmap(int rate)
1177 : {
1178 0 : switch (rate) {
1179 : /* CCK rates */
1180 0 : case 0: return (MALO_RATE_BITMAP_DS1);
1181 0 : case 1: return (MALO_RATE_BITMAP_DS2);
1182 0 : case 2: return (MALO_RATE_BITMAP_DS5);
1183 0 : case 3: return (MALO_RATE_BITMAP_DS11);
1184 :
1185 : /* OFDM rates */
1186 0 : case 4: return (MALO_RATE_BITMAP_OFDM6);
1187 0 : case 5: return (MALO_RATE_BITMAP_OFDM9);
1188 0 : case 6: return (MALO_RATE_BITMAP_OFDM12);
1189 0 : case 7: return (MALO_RATE_BITMAP_OFDM18);
1190 0 : case 8: return (MALO_RATE_BITMAP_OFDM24);
1191 0 : case 9: return (MALO_RATE_BITMAP_OFDM36);
1192 0 : case 10: return (MALO_RATE_BITMAP_OFDM48);
1193 0 : case 11: return (MALO_RATE_BITMAP_OFDM54);
1194 :
1195 : /* unknown rate: should not happen */
1196 0 : default: return (0);
1197 : }
1198 0 : }
1199 :
1200 : void
1201 0 : cmalo_hexdump(void *buf, int len)
1202 : {
1203 : #ifdef CMALO_DEBUG
1204 : int i;
1205 :
1206 : if (cmalo_d >= 2) {
1207 : for (i = 0; i < len; i++) {
1208 : if (i % 16 == 0)
1209 : printf("%s%5i:", i ? "\n" : "", i);
1210 : if (i % 4 == 0)
1211 : printf(" ");
1212 : printf("%02x", (int)*((u_char *)buf + i));
1213 : }
1214 : printf("\n");
1215 : }
1216 : #endif
1217 0 : }
1218 :
1219 : int
1220 0 : cmalo_cmd_get_hwspec(struct malo_softc *sc)
1221 : {
1222 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1223 : struct malo_cmd_body_spec *body;
1224 : uint16_t psize;
1225 :
1226 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1227 : psize = sizeof(*hdr) + sizeof(*body);
1228 :
1229 0 : hdr->cmd = htole16(MALO_CMD_HWSPEC);
1230 0 : hdr->size = htole16(sizeof(*body));
1231 0 : hdr->seqnum = htole16(1);
1232 0 : hdr->result = 0;
1233 0 : body = (struct malo_cmd_body_spec *)(hdr + 1);
1234 :
1235 : /* set all bits for MAC address, otherwise we won't get one back */
1236 0 : memset(body->macaddr, 0xff, ETHER_ADDR_LEN);
1237 :
1238 : /* process command request */
1239 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1240 0 : return (EIO);
1241 :
1242 : /* process command repsonse */
1243 0 : cmalo_cmd_response(sc);
1244 :
1245 0 : return (0);
1246 0 : }
1247 :
1248 : int
1249 0 : cmalo_cmd_rsp_hwspec(struct malo_softc *sc)
1250 : {
1251 0 : struct ieee80211com *ic = &sc->sc_ic;
1252 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1253 : struct malo_cmd_body_spec *body;
1254 : int i;
1255 :
1256 0 : body = (struct malo_cmd_body_spec *)(hdr + 1);
1257 :
1258 : /* get our MAC address */
1259 0 : for (i = 0; i < ETHER_ADDR_LEN; i++)
1260 0 : ic->ic_myaddr[i] = body->macaddr[i];
1261 :
1262 0 : return (0);
1263 : }
1264 :
1265 : int
1266 0 : cmalo_cmd_set_reset(struct malo_softc *sc)
1267 : {
1268 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1269 : uint16_t psize;
1270 :
1271 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1272 : psize = sizeof(*hdr);
1273 :
1274 0 : hdr->cmd = htole16(MALO_CMD_RESET);
1275 0 : hdr->size = 0;
1276 0 : hdr->seqnum = htole16(1);
1277 0 : hdr->result = 0;
1278 :
1279 : /* process command request */
1280 0 : if (cmalo_cmd_request(sc, psize, 1) != 0)
1281 0 : return (EIO);
1282 :
1283 : /* give the device some time to finish the reset */
1284 0 : delay(100);
1285 :
1286 0 : return (0);
1287 0 : }
1288 :
1289 : int
1290 0 : cmalo_cmd_set_scan(struct malo_softc *sc)
1291 : {
1292 0 : struct ieee80211com *ic = &sc->sc_ic;
1293 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1294 : struct malo_cmd_body_scan *body;
1295 : struct malo_cmd_tlv_ssid *body_ssid;
1296 : struct malo_cmd_tlv_chanlist *body_chanlist;
1297 : struct malo_cmd_tlv_rates *body_rates;
1298 : //struct malo_cmd_tlv_numprobes *body_numprobes;
1299 : uint16_t psize;
1300 : int i;
1301 :
1302 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1303 : psize = sizeof(*hdr) + sizeof(*body);
1304 :
1305 0 : hdr->cmd = htole16(MALO_CMD_SCAN);
1306 0 : hdr->seqnum = htole16(1);
1307 0 : hdr->result = 0;
1308 0 : body = (struct malo_cmd_body_scan *)(hdr + 1);
1309 :
1310 0 : body->bsstype = 0x03; /* any BSS */
1311 0 : memset(body->bssid, 0xff, ETHER_ADDR_LEN);
1312 :
1313 0 : body_ssid = sc->sc_cmd + psize;
1314 0 : body_ssid->type = htole16(MALO_TLV_TYPE_SSID);
1315 0 : body_ssid->size = htole16(0);
1316 : psize += (sizeof(*body_ssid) - 1);
1317 :
1318 0 : body_chanlist = sc->sc_cmd + psize;
1319 0 : body_chanlist->type = htole16(MALO_TLV_TYPE_CHANLIST);
1320 0 : body_chanlist->size = htole16(sizeof(body_chanlist->data));
1321 0 : for (i = 0; i < CHANNELS; i++) {
1322 0 : body_chanlist->data[i].radiotype = 0x00;
1323 0 : body_chanlist->data[i].channumber = (i + 1);
1324 0 : body_chanlist->data[i].scantype = 0x00; /* active */
1325 0 : body_chanlist->data[i].minscantime = htole16(0);
1326 0 : body_chanlist->data[i].maxscantime = htole16(100);
1327 : }
1328 : psize += sizeof(*body_chanlist);
1329 :
1330 0 : body_rates = sc->sc_cmd + psize;
1331 0 : body_rates->type = htole16(MALO_TLV_TYPE_RATES);
1332 0 : body_rates->size =
1333 0 : htole16(ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates);
1334 0 : bcopy(ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates, body_rates->data,
1335 0 : ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates);
1336 0 : psize += (sizeof(*body_rates) - 1) + letoh16(body_rates->size);
1337 : #if 0
1338 : body_numprobes = sc->sc_cmd + psize;
1339 : body_numprobes->type = htole16(MALO_TLV_TYPE_NUMPROBES);
1340 : body_numprobes->size = htole16(2);
1341 : body_numprobes->numprobes = htole16(1);
1342 : psize += sizeof(*body_numprobes);
1343 : #endif
1344 0 : hdr->size = htole16(psize - sizeof(*hdr));
1345 :
1346 : /* process command request */
1347 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1348 0 : return (EIO);
1349 :
1350 : /* process command repsonse */
1351 0 : cmalo_cmd_response(sc);
1352 :
1353 0 : return (0);
1354 0 : }
1355 :
1356 : int
1357 0 : cmalo_cmd_rsp_scan(struct malo_softc *sc)
1358 : {
1359 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1360 : struct malo_cmd_body_rsp_scan *body;
1361 : struct malo_cmd_body_rsp_scan_set *set;
1362 : uint16_t psize;
1363 : int i;
1364 :
1365 0 : bzero(sc->sc_net, sizeof(sc->sc_net));
1366 : psize = sizeof(*hdr) + sizeof(*body);
1367 :
1368 0 : body = (struct malo_cmd_body_rsp_scan *)(hdr + 1);
1369 :
1370 0 : body->bufsize = letoh16(body->bufsize);
1371 :
1372 : DPRINTF(1, "bufsize=%d, APs=%d\n", body->bufsize, body->numofset);
1373 0 : sc->sc_net_num = body->numofset;
1374 :
1375 : /* cycle through found networks */
1376 0 : for (i = 0; i < body->numofset; i++) {
1377 0 : set = (struct malo_cmd_body_rsp_scan_set *)(sc->sc_cmd + psize);
1378 :
1379 0 : set->size = letoh16(set->size);
1380 0 : set->beaconintvl = letoh16(set->beaconintvl);
1381 0 : set->capinfo = letoh16(set->capinfo);
1382 :
1383 : DPRINTF(1, "size=%d, bssid=%s, rssi=%d, beaconintvl=%d, "
1384 : "capinfo=0x%04x\n",
1385 : set->size, ether_sprintf(set->bssid), set->rssi,
1386 : set->beaconintvl, set->capinfo);
1387 :
1388 : /* save scan results */
1389 0 : bcopy(set->bssid, sc->sc_net[i].bssid, sizeof(set->bssid));
1390 0 : bcopy(set->timestamp, sc->sc_net[i].timestamp,
1391 : sizeof(set->timestamp));
1392 0 : sc->sc_net[i].rssi = set->rssi;
1393 0 : sc->sc_net[i].beaconintvl = set->beaconintvl;
1394 0 : sc->sc_net[i].capinfo = set->capinfo;
1395 0 : cmalo_parse_elements(sc, (set + 1),
1396 0 : set->size - (sizeof(*set) - sizeof(set->size)), i);
1397 :
1398 0 : psize += (set->size + sizeof(set->size));
1399 : }
1400 :
1401 0 : return (0);
1402 : }
1403 :
1404 : int
1405 0 : cmalo_parse_elements(struct malo_softc *sc, void *buf, int size, int pos)
1406 : {
1407 : uint8_t eid, len;
1408 : int i;
1409 :
1410 : DPRINTF(2, "element_size=%d, element_pos=%d\n", size, pos);
1411 :
1412 0 : for (i = 0; i < size; ) {
1413 0 : eid = *(uint8_t *)(buf + i);
1414 0 : i++;
1415 0 : len = *(uint8_t *)(buf + i);
1416 0 : i++;
1417 : DPRINTF(2, "eid=%d, len=%d, ", eid, len);
1418 :
1419 0 : switch (eid) {
1420 : case IEEE80211_ELEMID_SSID:
1421 0 : bcopy(buf + i, sc->sc_net[pos].ssid, len);
1422 : DPRINTF(2, "ssid=%s\n", sc->sc_net[pos].ssid);
1423 0 : break;
1424 : case IEEE80211_ELEMID_RATES:
1425 0 : bcopy(buf + i, sc->sc_net[pos].rates, len);
1426 : DPRINTF(2, "rates\n");
1427 0 : break;
1428 : case IEEE80211_ELEMID_DSPARMS:
1429 0 : sc->sc_net[pos].channel = *(uint8_t *)(buf + i);
1430 : DPRINTF(2, "chnl=%d\n", sc->sc_net[pos].channel);
1431 0 : break;
1432 : default:
1433 : DPRINTF(2, "unknown\n");
1434 : break;
1435 : }
1436 :
1437 0 : i += len;
1438 : }
1439 :
1440 0 : return (0);
1441 : }
1442 :
1443 : int
1444 0 : cmalo_cmd_set_auth(struct malo_softc *sc)
1445 : {
1446 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1447 : struct malo_cmd_body_auth *body;
1448 : uint16_t psize;
1449 :
1450 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1451 : psize = sizeof(*hdr) + sizeof(*body);
1452 :
1453 0 : hdr->cmd = htole16(MALO_CMD_AUTH);
1454 0 : hdr->size = htole16(sizeof(*body));
1455 0 : hdr->seqnum = htole16(1);
1456 0 : hdr->result = 0;
1457 0 : body = (struct malo_cmd_body_auth *)(hdr + 1);
1458 :
1459 0 : bcopy(sc->sc_net[sc->sc_net_cur].bssid, body->peermac, ETHER_ADDR_LEN);
1460 0 : body->authtype = 0;
1461 :
1462 : /* process command request */
1463 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1464 0 : return (EIO);
1465 :
1466 : /* process command repsonse */
1467 0 : cmalo_cmd_response(sc);
1468 :
1469 0 : return (0);
1470 0 : }
1471 :
1472 : int
1473 0 : cmalo_cmd_set_wep(struct malo_softc *sc, uint16_t index,
1474 : struct ieee80211_key *key)
1475 : {
1476 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1477 : struct malo_cmd_body_wep *body;
1478 : uint16_t psize;
1479 :
1480 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1481 : psize = sizeof(*hdr) + sizeof(*body);
1482 :
1483 0 : hdr->cmd = htole16(MALO_CMD_WEP);
1484 0 : hdr->size = htole16(sizeof(*body));
1485 0 : hdr->seqnum = htole16(1);
1486 0 : hdr->result = 0;
1487 0 : body = (struct malo_cmd_body_wep *)(hdr + 1);
1488 :
1489 0 : body->action = htole16(MALO_WEP_ACTION_TYPE_ADD);
1490 0 : body->key_index = htole16(index);
1491 :
1492 0 : if (body->key_index == 0) {
1493 0 : if (key->k_len > 5)
1494 0 : body->key_type_1 = MALO_WEP_KEY_TYPE_104BIT;
1495 : else
1496 0 : body->key_type_1 = MALO_WEP_KEY_TYPE_40BIT;
1497 0 : bcopy(key->k_key, body->key_value_1, key->k_len);
1498 0 : }
1499 0 : if (body->key_index == 1) {
1500 0 : if (key->k_len > 5)
1501 0 : body->key_type_2 = MALO_WEP_KEY_TYPE_104BIT;
1502 : else
1503 0 : body->key_type_2 = MALO_WEP_KEY_TYPE_40BIT;
1504 0 : bcopy(key->k_key, body->key_value_2, key->k_len);
1505 0 : }
1506 0 : if (body->key_index == 2) {
1507 0 : if (key->k_len > 5)
1508 0 : body->key_type_3 = MALO_WEP_KEY_TYPE_104BIT;
1509 : else
1510 0 : body->key_type_3 = MALO_WEP_KEY_TYPE_40BIT;
1511 0 : bcopy(key->k_key, body->key_value_3, key->k_len);
1512 0 : }
1513 0 : if (body->key_index == 3) {
1514 0 : if (key->k_len > 5)
1515 0 : body->key_type_4 = MALO_WEP_KEY_TYPE_104BIT;
1516 : else
1517 0 : body->key_type_4 = MALO_WEP_KEY_TYPE_40BIT;
1518 0 : bcopy(key->k_key, body->key_value_4, key->k_len);
1519 0 : }
1520 :
1521 : /* process command request */
1522 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1523 0 : return (EIO);
1524 :
1525 : /* process command repsonse */
1526 0 : cmalo_cmd_response(sc);
1527 :
1528 0 : return (0);
1529 0 : }
1530 :
1531 : int
1532 0 : cmalo_cmd_set_snmp(struct malo_softc *sc, uint16_t oid)
1533 : {
1534 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1535 : struct malo_cmd_body_snmp *body;
1536 : uint16_t psize;
1537 :
1538 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1539 : psize = sizeof(*hdr) + sizeof(*body);
1540 :
1541 0 : hdr->cmd = htole16(MALO_CMD_SNMP);
1542 0 : hdr->size = htole16(sizeof(*body));
1543 0 : hdr->seqnum = htole16(1);
1544 0 : hdr->result = 0;
1545 0 : body = (struct malo_cmd_body_snmp *)(hdr + 1);
1546 :
1547 0 : body->action = htole16(1);
1548 :
1549 0 : switch (oid) {
1550 : case MALO_OID_RTSTRESH:
1551 0 : body->oid = htole16(MALO_OID_RTSTRESH);
1552 0 : body->size = htole16(2);
1553 0 : *(uint16_t *)body->data = htole16(2347);
1554 0 : break;
1555 : case MALO_OID_SHORTRETRY:
1556 0 : body->oid = htole16(MALO_OID_SHORTRETRY);
1557 0 : body->size = htole16(2);
1558 0 : *(uint16_t *)body->data = htole16(4);
1559 0 : break;
1560 : case MALO_OID_FRAGTRESH:
1561 0 : body->oid = htole16(MALO_OID_FRAGTRESH);
1562 0 : body->size = htole16(2);
1563 0 : *(uint16_t *)body->data = htole16(2346);
1564 0 : break;
1565 : case MALO_OID_80211D:
1566 0 : body->oid = htole16(MALO_OID_80211D);
1567 0 : body->size = htole16(2);
1568 0 : *(uint16_t *)body->data = htole16(1);
1569 0 : break;
1570 : default:
1571 : break;
1572 : }
1573 :
1574 : /* process command request */
1575 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1576 0 : return (EIO);
1577 :
1578 : /* process command repsonse */
1579 0 : cmalo_cmd_response(sc);
1580 :
1581 0 : return (0);
1582 0 : }
1583 :
1584 : int
1585 0 : cmalo_cmd_set_radio(struct malo_softc *sc, uint16_t control)
1586 : {
1587 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1588 : struct malo_cmd_body_radio *body;
1589 : uint16_t psize;
1590 :
1591 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1592 : psize = sizeof(*hdr) + sizeof(*body);
1593 :
1594 0 : hdr->cmd = htole16(MALO_CMD_RADIO);
1595 0 : hdr->size = htole16(sizeof(*body));
1596 0 : hdr->seqnum = htole16(1);
1597 0 : hdr->result = 0;
1598 0 : body = (struct malo_cmd_body_radio *)(hdr + 1);
1599 :
1600 0 : body->action = htole16(1);
1601 :
1602 0 : if (control) {
1603 0 : body->control = htole16(MALO_CMD_RADIO_ON);
1604 0 : body->control |= htole16(MALO_CMD_RADIO_AUTO_P);
1605 0 : }
1606 :
1607 : /* process command request */
1608 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1609 0 : return (EIO);
1610 :
1611 : /* process command repsonse */
1612 0 : cmalo_cmd_response(sc);
1613 :
1614 0 : return (0);
1615 0 : }
1616 :
1617 : int
1618 0 : cmalo_cmd_set_channel(struct malo_softc *sc, uint16_t channel)
1619 : {
1620 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1621 : struct malo_cmd_body_channel *body;
1622 : uint16_t psize;
1623 :
1624 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1625 : psize = sizeof(*hdr) + sizeof(*body);
1626 :
1627 0 : hdr->cmd = htole16(MALO_CMD_CHANNEL);
1628 0 : hdr->size = htole16(sizeof(*body));
1629 0 : hdr->seqnum = htole16(1);
1630 0 : hdr->result = 0;
1631 0 : body = (struct malo_cmd_body_channel *)(hdr + 1);
1632 :
1633 0 : body->action = htole16(1);
1634 0 : body->channel = htole16(channel);
1635 :
1636 : /* process command request */
1637 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1638 0 : return (EIO);
1639 :
1640 : /* process command repsonse */
1641 0 : cmalo_cmd_response(sc);
1642 :
1643 0 : return (0);
1644 0 : }
1645 :
1646 :
1647 : int
1648 0 : cmalo_cmd_set_txpower(struct malo_softc *sc, int16_t txpower)
1649 : {
1650 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1651 : struct malo_cmd_body_txpower *body;
1652 : uint16_t psize;
1653 :
1654 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1655 : psize = sizeof(*hdr) + sizeof(*body);
1656 :
1657 0 : hdr->cmd = htole16(MALO_CMD_TXPOWER);
1658 0 : hdr->size = htole16(sizeof(*body));
1659 0 : hdr->seqnum = htole16(1);
1660 0 : hdr->result = 0;
1661 0 : body = (struct malo_cmd_body_txpower *)(hdr + 1);
1662 :
1663 0 : body->action = htole16(1);
1664 0 : body->txpower = htole16(txpower);
1665 :
1666 : /* process command request */
1667 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1668 0 : return (EIO);
1669 :
1670 : /* process command repsonse */
1671 0 : cmalo_cmd_response(sc);
1672 :
1673 0 : return (0);
1674 0 : }
1675 :
1676 : int
1677 0 : cmalo_cmd_set_antenna(struct malo_softc *sc, uint16_t action)
1678 : {
1679 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1680 : struct malo_cmd_body_antenna *body;
1681 : uint16_t psize;
1682 :
1683 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1684 : psize = sizeof(*hdr) + sizeof(*body);
1685 :
1686 0 : hdr->cmd = htole16(MALO_CMD_ANTENNA);
1687 0 : hdr->size = htole16(sizeof(*body));
1688 0 : hdr->seqnum = htole16(1);
1689 0 : hdr->result = 0;
1690 0 : body = (struct malo_cmd_body_antenna *)(hdr + 1);
1691 :
1692 : /* 1 = set RX, 2 = set TX */
1693 0 : body->action = htole16(action);
1694 :
1695 0 : if (action == 1)
1696 : /* set RX antenna */
1697 0 : body->antenna_mode = htole16(0xffff);
1698 0 : if (action == 2)
1699 : /* set TX antenna */
1700 0 : body->antenna_mode = htole16(2);
1701 :
1702 : /* process command request */
1703 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1704 0 : return (EIO);
1705 :
1706 : /* process command repsonse */
1707 0 : cmalo_cmd_response(sc);
1708 :
1709 0 : return (0);
1710 0 : }
1711 :
1712 : int
1713 0 : cmalo_cmd_set_macctrl(struct malo_softc *sc)
1714 : {
1715 0 : struct ieee80211com *ic = &sc->sc_ic;
1716 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1717 : struct malo_cmd_body_macctrl *body;
1718 : uint16_t psize;
1719 :
1720 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1721 : psize = sizeof(*hdr) + sizeof(*body);
1722 :
1723 0 : hdr->cmd = htole16(MALO_CMD_MACCTRL);
1724 0 : hdr->size = htole16(sizeof(*body));
1725 0 : hdr->seqnum = htole16(1);
1726 0 : hdr->result = 0;
1727 0 : body = (struct malo_cmd_body_macctrl *)(hdr + 1);
1728 :
1729 0 : body->action = htole16(MALO_CMD_MACCTRL_RX_ON);
1730 0 : body->action |= htole16(MALO_CMD_MACCTRL_TX_ON);
1731 0 : if (ic->ic_opmode == IEEE80211_M_MONITOR)
1732 0 : body->action |= htole16(MALO_CMD_MACCTRL_PROMISC_ON);
1733 :
1734 : /* process command request */
1735 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1736 0 : return (EIO);
1737 :
1738 : /* process command repsonse */
1739 0 : cmalo_cmd_response(sc);
1740 :
1741 0 : return (0);
1742 0 : }
1743 :
1744 : int
1745 0 : cmalo_cmd_set_macaddr(struct malo_softc *sc, uint8_t *macaddr)
1746 : {
1747 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1748 : struct malo_cmd_body_macaddr *body;
1749 : uint16_t psize;
1750 :
1751 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1752 : psize = sizeof(*hdr) + sizeof(*body);
1753 :
1754 0 : hdr->cmd = htole16(MALO_CMD_MACADDR);
1755 0 : hdr->size = htole16(sizeof(*body));
1756 0 : hdr->seqnum = htole16(1);
1757 0 : hdr->result = 0;
1758 0 : body = (struct malo_cmd_body_macaddr *)(hdr + 1);
1759 :
1760 0 : body->action = htole16(1);
1761 0 : bcopy(macaddr, body->macaddr, ETHER_ADDR_LEN);
1762 :
1763 : /* process command request */
1764 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1765 0 : return (EIO);
1766 :
1767 : /* process command repsonse */
1768 0 : cmalo_cmd_response(sc);
1769 :
1770 0 : return (0);
1771 0 : }
1772 :
1773 : int
1774 0 : cmalo_cmd_set_assoc(struct malo_softc *sc)
1775 : {
1776 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1777 : struct malo_cmd_body_assoc *body;
1778 : struct malo_cmd_tlv_ssid *body_ssid;
1779 : struct malo_cmd_tlv_phy *body_phy;
1780 : struct malo_cmd_tlv_cf *body_cf;
1781 : struct malo_cmd_tlv_rates *body_rates;
1782 : struct malo_cmd_tlv_passeid *body_passeid;
1783 : uint16_t psize;
1784 :
1785 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1786 : psize = sizeof(*hdr) + sizeof(*body);
1787 :
1788 0 : hdr->cmd = htole16(MALO_CMD_ASSOC);
1789 0 : hdr->seqnum = htole16(1);
1790 0 : hdr->result = 0;
1791 0 : body = (struct malo_cmd_body_assoc *)(hdr + 1);
1792 :
1793 0 : bcopy(sc->sc_net[sc->sc_net_cur].bssid, body->peermac, ETHER_ADDR_LEN);
1794 0 : body->capinfo = htole16(sc->sc_net[sc->sc_net_cur].capinfo);
1795 0 : body->listenintrv = htole16(10);
1796 :
1797 0 : body_ssid = sc->sc_cmd + psize;
1798 0 : body_ssid->type = htole16(MALO_TLV_TYPE_SSID);
1799 0 : body_ssid->size = htole16(strlen(sc->sc_net[sc->sc_net_cur].ssid));
1800 0 : bcopy(sc->sc_net[sc->sc_net_cur].ssid, body_ssid->data,
1801 0 : letoh16(body_ssid->size));
1802 0 : psize += (sizeof(*body_ssid) - 1) + letoh16(body_ssid->size);
1803 :
1804 0 : body_phy = sc->sc_cmd + psize;
1805 0 : body_phy->type = htole16(MALO_TLV_TYPE_PHY);
1806 0 : body_phy->size = htole16(1);
1807 0 : bcopy(&sc->sc_net[sc->sc_net_cur].channel, body_phy->data, 1);
1808 0 : psize += sizeof(*body_phy);
1809 :
1810 0 : body_cf = sc->sc_cmd + psize;
1811 0 : body_cf->type = htole16(MALO_TLV_TYPE_CF);
1812 0 : body_cf->size = htole16(0);
1813 0 : psize += (sizeof(*body_cf) - 1);
1814 :
1815 0 : body_rates = sc->sc_cmd + psize;
1816 0 : body_rates->type = htole16(MALO_TLV_TYPE_RATES);
1817 0 : body_rates->size = htole16(strlen(sc->sc_net[sc->sc_net_cur].rates));
1818 0 : bcopy(sc->sc_net[sc->sc_net_cur].rates, body_rates->data,
1819 0 : letoh16(body_rates->size));
1820 0 : psize += (sizeof(*body_rates) - 1) + letoh16(body_rates->size);
1821 :
1822 : /* hack to correct FW's wrong generated rates-element-id */
1823 0 : body_passeid = sc->sc_cmd + psize;
1824 0 : body_passeid->type = htole16(MALO_TLV_TYPE_PASSEID);
1825 0 : body_passeid->size = body_rates->size;
1826 0 : bcopy(body_rates->data, body_passeid->data, letoh16(body_rates->size));
1827 0 : psize += (sizeof(*body_passeid) - 1) + letoh16(body_passeid->size);
1828 :
1829 0 : hdr->size = htole16(psize - sizeof(*hdr));
1830 :
1831 : /* process command request */
1832 0 : if (!sc->sc_cmd_ctxsave) {
1833 0 : if (cmalo_cmd_request(sc, psize, 1) != 0)
1834 0 : return (EIO);
1835 0 : return (0);
1836 : }
1837 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1838 0 : return (EIO);
1839 :
1840 : /* process command repsonse */
1841 0 : cmalo_cmd_response(sc);
1842 :
1843 0 : return (0);
1844 0 : }
1845 :
1846 : int
1847 0 : cmalo_cmd_rsp_assoc(struct malo_softc *sc)
1848 : {
1849 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1850 : struct malo_cmd_body_rsp_assoc *body;
1851 :
1852 0 : body = (struct malo_cmd_body_rsp_assoc *)(hdr + 1);
1853 :
1854 0 : if (body->status) {
1855 : DPRINTF(1, "%s: association failed (status %d)\n",
1856 : sc->sc_dev.dv_xname, body->status);
1857 0 : sc->sc_flags |= MALO_ASSOC_FAILED;
1858 0 : } else
1859 : DPRINTF(1, "%s: association successful\n",
1860 : sc->sc_dev.dv_xname, body->status);
1861 :
1862 0 : return (0);
1863 : }
1864 :
1865 : int
1866 0 : cmalo_cmd_set_80211d(struct malo_softc *sc)
1867 : {
1868 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1869 : struct malo_cmd_body_80211d *body;
1870 : struct malo_cmd_tlv_80211d *body_80211d;
1871 : uint16_t psize;
1872 : int i;
1873 :
1874 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1875 : psize = sizeof(*hdr) + sizeof(*body);
1876 :
1877 0 : hdr->cmd = htole16(MALO_CMD_80211D);
1878 0 : hdr->seqnum = htole16(1);
1879 0 : hdr->result = 0;
1880 0 : body = (struct malo_cmd_body_80211d *)(hdr + 1);
1881 :
1882 0 : body->action = htole16(1);
1883 :
1884 0 : body_80211d = sc->sc_cmd + psize;
1885 0 : body_80211d->type = htole16(MALO_TLV_TYPE_80211D);
1886 0 : body_80211d->size = htole16(sizeof(body_80211d->data) +
1887 : sizeof(body_80211d->countrycode));
1888 0 : bcopy("EU ", body_80211d->countrycode,
1889 : sizeof(body_80211d->countrycode));
1890 0 : for (i = 0; i < CHANNELS; i++) {
1891 0 : body_80211d->data[i].firstchannel = 1;
1892 0 : body_80211d->data[i].numchannels = 12;
1893 0 : body_80211d->data[i].maxtxpower = 10;
1894 : }
1895 : psize += sizeof(*body_80211d);
1896 :
1897 0 : hdr->size = htole16(psize - sizeof(*hdr));
1898 :
1899 : /* process command request */
1900 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1901 0 : return (EIO);
1902 :
1903 : /* process command repsonse */
1904 0 : cmalo_cmd_response(sc);
1905 :
1906 0 : return (0);
1907 0 : }
1908 :
1909 : int
1910 0 : cmalo_cmd_set_bgscan_config(struct malo_softc *sc)
1911 : {
1912 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1913 : struct malo_cmd_body_bgscan_config *body;
1914 : uint16_t psize;
1915 :
1916 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1917 : psize = sizeof(*hdr) + sizeof(*body);
1918 :
1919 0 : hdr->cmd = htole16(MALO_CMD_BGSCAN_CONFIG);
1920 0 : hdr->size = htole16(sizeof(*body));
1921 0 : hdr->seqnum = htole16(1);
1922 0 : hdr->result = 0;
1923 0 : body = (struct malo_cmd_body_bgscan_config *)(hdr + 1);
1924 :
1925 0 : body->action = htole16(1);
1926 0 : body->enable = 1;
1927 0 : body->bsstype = 0x03;
1928 0 : body->chperscan = 12;
1929 0 : body->scanintvl = htole32(100);
1930 0 : body->maxscanres = htole16(12);
1931 :
1932 : /* process command request */
1933 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1934 0 : return (EIO);
1935 :
1936 : /* process command repsonse */
1937 0 : cmalo_cmd_response(sc);
1938 :
1939 0 : return (0);
1940 0 : }
1941 :
1942 : int
1943 0 : cmalo_cmd_set_bgscan_query(struct malo_softc *sc)
1944 : {
1945 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1946 : struct malo_cmd_body_bgscan_query *body;
1947 : uint16_t psize;
1948 :
1949 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1950 : psize = sizeof(*hdr) + sizeof(*body);
1951 :
1952 0 : hdr->cmd = htole16(MALO_CMD_BGSCAN_QUERY);
1953 0 : hdr->size = htole16(sizeof(*body));
1954 0 : hdr->seqnum = htole16(1);
1955 0 : hdr->result = 0;
1956 0 : body = (struct malo_cmd_body_bgscan_query *)(hdr + 1);
1957 :
1958 0 : body->flush = 0;
1959 :
1960 : /* process command request */
1961 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1962 0 : return (EIO);
1963 :
1964 : /* process command repsonse */
1965 0 : cmalo_cmd_response(sc);
1966 :
1967 0 : return (0);
1968 0 : }
1969 :
1970 : int
1971 0 : cmalo_cmd_set_rate(struct malo_softc *sc, int rate)
1972 : {
1973 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
1974 : struct malo_cmd_body_rate *body;
1975 : uint16_t psize;
1976 :
1977 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
1978 : psize = sizeof(*hdr) + sizeof(*body);
1979 :
1980 0 : hdr->cmd = htole16(MALO_CMD_RATE);
1981 0 : hdr->size = htole16(sizeof(*body));
1982 0 : hdr->seqnum = htole16(1);
1983 0 : hdr->result = 0;
1984 0 : body = (struct malo_cmd_body_rate *)(hdr + 1);
1985 :
1986 0 : body->action = htole16(1);
1987 0 : if (rate == -1) {
1988 0 : body->hwauto = htole16(1);
1989 0 : body->ratebitmap = htole16(MALO_RATE_BITMAP_AUTO);
1990 0 : } else {
1991 0 : body->hwauto = 0;
1992 0 : body->ratebitmap = htole16(cmalo_rate2bitmap(rate));
1993 : }
1994 :
1995 : /* process command request */
1996 0 : if (cmalo_cmd_request(sc, psize, 0) != 0)
1997 0 : return (EIO);
1998 :
1999 : /* process command repsonse */
2000 0 : cmalo_cmd_response(sc);
2001 :
2002 0 : return (0);
2003 0 : }
2004 :
2005 : int
2006 0 : cmalo_cmd_request(struct malo_softc *sc, uint16_t psize, int no_response)
2007 : {
2008 : uint8_t *cmd;
2009 :
2010 0 : cmalo_hexdump(sc->sc_cmd, psize);
2011 :
2012 : /* send command request */
2013 0 : MALO_WRITE_2(sc, MALO_REG_CMD_WRITE_LEN, psize);
2014 0 : if (psize & 0x0001) {
2015 0 : MALO_WRITE_MULTI_2(sc, MALO_REG_CMD_WRITE, sc->sc_cmd,
2016 : psize - 1);
2017 0 : cmd = (uint8_t *)sc->sc_cmd;
2018 0 : MALO_WRITE_1(sc, MALO_REG_CMD_WRITE, cmd[psize - 1]);
2019 0 : } else
2020 0 : MALO_WRITE_MULTI_2(sc, MALO_REG_CMD_WRITE, sc->sc_cmd, psize);
2021 0 : MALO_WRITE_1(sc, MALO_REG_HOST_STATUS, MALO_VAL_CMD_DL_OVER);
2022 0 : MALO_WRITE_2(sc, MALO_REG_CARD_INTR_CAUSE, MALO_VAL_CMD_DL_OVER);
2023 :
2024 0 : if (no_response)
2025 : /* we don't expect a response */
2026 0 : return (0);
2027 :
2028 : /* wait for the command response */
2029 0 : if (tsleep(sc, 0, "malocmd", 500)) {
2030 0 : printf("%s: timeout while waiting for cmd response\n",
2031 0 : sc->sc_dev.dv_xname);
2032 0 : return (EIO);
2033 : }
2034 :
2035 0 : return (0);
2036 0 : }
2037 :
2038 : int
2039 0 : cmalo_cmd_response(struct malo_softc *sc)
2040 : {
2041 0 : struct malo_cmd_header *hdr = sc->sc_cmd;
2042 : uint16_t psize;
2043 : uint8_t *cmd;
2044 : int s;
2045 :
2046 0 : s = splnet();
2047 :
2048 0 : bzero(sc->sc_cmd, MALO_CMD_BUFFER_SIZE);
2049 :
2050 : /* read the whole command response */
2051 0 : psize = MALO_READ_2(sc, MALO_REG_CMD_READ_LEN);
2052 0 : if (psize & 0x0001) {
2053 0 : MALO_READ_MULTI_2(sc, MALO_REG_CMD_READ, sc->sc_cmd,
2054 : psize - 1);
2055 0 : cmd = (uint8_t *)sc->sc_cmd;
2056 0 : cmd[psize - 1] = MALO_READ_1(sc, MALO_REG_CMD_READ);
2057 0 : } else
2058 0 : MALO_READ_MULTI_2(sc, MALO_REG_CMD_READ, sc->sc_cmd, psize);
2059 :
2060 0 : cmalo_hexdump(sc->sc_cmd, psize);
2061 :
2062 : /*
2063 : * We convert the header values into the machines correct endianess,
2064 : * so we don't have to letoh16() all over the code. The body is
2065 : * kept in the cards order, little endian. We need to take care
2066 : * about the body endianess in the corresponding response routines.
2067 : */
2068 0 : hdr->cmd = letoh16(hdr->cmd);
2069 0 : hdr->size = letoh16(hdr->size);
2070 0 : hdr->seqnum = letoh16(hdr->seqnum);
2071 0 : hdr->result = letoh16(hdr->result);
2072 :
2073 : /* check for a valid command response */
2074 0 : if (!(hdr->cmd & MALO_CMD_RESP)) {
2075 0 : printf("%s: got invalid command response (0x%04x)\n",
2076 0 : sc->sc_dev.dv_xname, hdr->cmd);
2077 0 : splx(s);
2078 0 : return (EIO);
2079 : }
2080 0 : hdr->cmd &= ~MALO_CMD_RESP;
2081 :
2082 : /* association cmd response is special */
2083 0 : if (hdr->cmd == 0x0012)
2084 0 : hdr->cmd = MALO_CMD_ASSOC;
2085 :
2086 : /* to which command does the response belong */
2087 0 : switch (hdr->cmd) {
2088 : case MALO_CMD_HWSPEC:
2089 : DPRINTF(1, "%s: got hwspec cmd response\n",
2090 : sc->sc_dev.dv_xname);
2091 0 : cmalo_cmd_rsp_hwspec(sc);
2092 0 : break;
2093 : case MALO_CMD_RESET:
2094 : /* reset will not send back a response */
2095 : break;
2096 : case MALO_CMD_SCAN:
2097 : DPRINTF(1, "%s: got scan cmd response\n",
2098 : sc->sc_dev.dv_xname);
2099 0 : cmalo_cmd_rsp_scan(sc);
2100 0 : break;
2101 : case MALO_CMD_AUTH:
2102 : /* do nothing */
2103 : DPRINTF(1, "%s: got auth cmd response\n",
2104 : sc->sc_dev.dv_xname);
2105 : break;
2106 : case MALO_CMD_WEP:
2107 : /* do nothing */
2108 : DPRINTF(1, "%s: got wep cmd response\n",
2109 : sc->sc_dev.dv_xname);
2110 : break;
2111 : case MALO_CMD_SNMP:
2112 : /* do nothing */
2113 : DPRINTF(1, "%s: got snmp cmd response\n",
2114 : sc->sc_dev.dv_xname);
2115 : break;
2116 : case MALO_CMD_RADIO:
2117 : /* do nothing */
2118 : DPRINTF(1, "%s: got radio cmd response\n",
2119 : sc->sc_dev.dv_xname);
2120 : break;
2121 : case MALO_CMD_CHANNEL:
2122 : /* do nothing */
2123 : DPRINTF(1, "%s: got channel cmd response\n",
2124 : sc->sc_dev.dv_xname);
2125 : break;
2126 : case MALO_CMD_TXPOWER:
2127 : /* do nothing */
2128 : DPRINTF(1, "%s: got txpower cmd response\n",
2129 : sc->sc_dev.dv_xname);
2130 : break;
2131 : case MALO_CMD_ANTENNA:
2132 : /* do nothing */
2133 : DPRINTF(1, "%s: got antenna cmd response\n",
2134 : sc->sc_dev.dv_xname);
2135 : break;
2136 : case MALO_CMD_MACCTRL:
2137 : /* do nothing */
2138 : DPRINTF(1, "%s: got macctrl cmd response\n",
2139 : sc->sc_dev.dv_xname);
2140 : break;
2141 : case MALO_CMD_MACADDR:
2142 : /* do nothing */
2143 : DPRINTF(1, "%s: got macaddr cmd response\n",
2144 : sc->sc_dev.dv_xname);
2145 : break;
2146 : case MALO_CMD_ASSOC:
2147 : /* do nothing */
2148 : DPRINTF(1, "%s: got assoc cmd response\n",
2149 : sc->sc_dev.dv_xname);
2150 0 : cmalo_cmd_rsp_assoc(sc);
2151 0 : break;
2152 : case MALO_CMD_80211D:
2153 : /* do nothing */
2154 : DPRINTF(1, "%s: got 80211d cmd response\n",
2155 : sc->sc_dev.dv_xname);
2156 : break;
2157 : case MALO_CMD_BGSCAN_CONFIG:
2158 : /* do nothing */
2159 : DPRINTF(1, "%s: got bgscan config cmd response\n",
2160 : sc->sc_dev.dv_xname);
2161 : break;
2162 : case MALO_CMD_BGSCAN_QUERY:
2163 : /* do nothing */
2164 : DPRINTF(1, "%s: got bgscan query cmd response\n",
2165 : sc->sc_dev.dv_xname);
2166 : break;
2167 : case MALO_CMD_RATE:
2168 : /* do nothing */
2169 : DPRINTF(1, "%s: got rate cmd response\n",
2170 : sc->sc_dev.dv_xname);
2171 : break;
2172 : default:
2173 0 : printf("%s: got unknown cmd response (0x%04x)\n",
2174 0 : sc->sc_dev.dv_xname, hdr->cmd);
2175 0 : break;
2176 : }
2177 :
2178 0 : splx(s);
2179 :
2180 0 : return (0);
2181 0 : }
|