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