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