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