Annotation of sys/dev/ic/awi.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: awi.c,v 1.23 2007/02/11 20:29:22 miod Exp $ */
! 2: /* $NetBSD: awi.c,v 1.26 2000/07/21 04:48:55 onoe Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1999 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Bill Sommerfeld
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39: /*
! 40: * Driver for AMD 802.11 firmware.
! 41: * Uses am79c930 chip driver to talk to firmware running on the am79c930.
! 42: *
! 43: * More-or-less a generic ethernet-like if driver, with 802.11 gorp added.
! 44: */
! 45:
! 46: /*
! 47: * todo:
! 48: * - flush tx queue on resynch.
! 49: * - clear oactive on "down".
! 50: * - rewrite copy-into-mbuf code
! 51: * - mgmt state machine gets stuck retransmitting assoc requests.
! 52: * - multicast filter.
! 53: * - fix device reset so it's more likely to work
! 54: * - show status goo through ifmedia.
! 55: *
! 56: * more todo:
! 57: * - deal with more 802.11 frames.
! 58: * - send reassoc request
! 59: * - deal with reassoc response
! 60: * - send/deal with disassociation
! 61: * - deal with "full" access points (no room for me).
! 62: * - power save mode
! 63: *
! 64: * later:
! 65: * - SSID preferences
! 66: * - need ioctls for poking at the MIBs
! 67: * - implement ad-hoc mode (including bss creation).
! 68: * - decide when to do "ad hoc" vs. infrastructure mode (IFF_LINK flags?)
! 69: * (focus on inf. mode since that will be needed for ietf)
! 70: * - deal with DH vs. FH versions of the card
! 71: * - deal with faster cards (2mb/s)
! 72: * - ?WEP goo (mmm, rc4) (it looks not particularly useful).
! 73: * - ifmedia revision.
! 74: * - common 802.11 mibish things.
! 75: * - common 802.11 media layer.
! 76: */
! 77:
! 78: /*
! 79: * Driver for AMD 802.11 PCnetMobile firmware.
! 80: * Uses am79c930 chip driver to talk to firmware running on the am79c930.
! 81: *
! 82: * The initial version of the driver was written by
! 83: * Bill Sommerfeld <sommerfeld@netbsd.org>.
! 84: * Then the driver module completely rewritten to support cards with DS phy
! 85: * and to support adhoc mode by Atsushi Onoe <onoe@netbsd.org>
! 86: */
! 87:
! 88: #if defined(__FreeBSD__) && __FreeBSD__ >= 4
! 89: #define NBPFILTER 1
! 90: #elif defined(__FreeBSD__) && __FreeBSD__ >= 3
! 91: #include "bpf.h"
! 92: #define NBPFILTER NBPF
! 93: #else
! 94: #include "bpfilter.h"
! 95: #endif
! 96:
! 97: #include <sys/param.h>
! 98: #include <sys/systm.h>
! 99: #include <sys/kernel.h>
! 100: #include <sys/mbuf.h>
! 101: #include <sys/malloc.h>
! 102: #include <sys/proc.h>
! 103: #include <sys/socket.h>
! 104: #include <sys/sockio.h>
! 105: #include <sys/errno.h>
! 106: #include <sys/syslog.h>
! 107: #if defined(__FreeBSD__) && __FreeBSD__ >= 4
! 108: #include <sys/bus.h>
! 109: #else
! 110: #include <sys/device.h>
! 111: #endif
! 112:
! 113: #include <net/if.h>
! 114: #include <net/if_dl.h>
! 115: #ifndef __OpenBSD__
! 116: #ifdef __FreeBSD__
! 117: #include <net/ethernet.h>
! 118: #else
! 119: #include <net/if_ether.h>
! 120: #endif
! 121: #endif
! 122: #include <net/if_media.h>
! 123: #include <net/if_llc.h>
! 124:
! 125: #ifdef INET
! 126: #include <netinet/in.h>
! 127: #include <netinet/in_systm.h>
! 128: #include <netinet/in_var.h>
! 129: #include <netinet/ip.h>
! 130: #ifdef __NetBSD__
! 131: #include <netinet/if_inarp.h>
! 132: #else
! 133: #include <netinet/if_ether.h>
! 134: #endif
! 135: #endif
! 136:
! 137: #include <net80211/ieee80211.h>
! 138: #include <net80211/ieee80211_ioctl.h>
! 139:
! 140: #if NBPFILTER > 0
! 141: #include <net/bpf.h>
! 142: #endif
! 143:
! 144: #include <machine/cpu.h>
! 145: #include <machine/bus.h>
! 146: #ifdef __NetBSD__
! 147: #include <machine/intr.h>
! 148: #endif
! 149: #ifdef __FreeBSD__
! 150: #include <machine/clock.h>
! 151: #endif
! 152:
! 153: #if defined(__NetBSD__) || defined(__OpenBSD__)
! 154: #include <dev/ic/am79c930reg.h>
! 155: #include <dev/ic/am79c930var.h>
! 156: #include <dev/ic/awireg.h>
! 157: #include <dev/ic/awivar.h>
! 158: #endif
! 159: #ifdef __FreeBSD__
! 160: #include <dev/awi/am79c930reg.h>
! 161: #include <dev/awi/am79c930var.h>
! 162: #include <dev/awi/awireg.h>
! 163: #include <dev/awi/awivar.h>
! 164: #endif
! 165:
! 166: static int awi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
! 167: #ifdef IFM_IEEE80211
! 168: static int awi_media_rate2opt(struct awi_softc *sc, int rate);
! 169: static int awi_media_opt2rate(struct awi_softc *sc, int opt);
! 170: static int awi_media_change(struct ifnet *ifp);
! 171: static void awi_media_status(struct ifnet *ifp, struct ifmediareq *imr);
! 172: #endif
! 173: static void awi_watchdog(struct ifnet *ifp);
! 174: static void awi_start(struct ifnet *ifp);
! 175: static void awi_txint(struct awi_softc *sc);
! 176: static struct mbuf * awi_fix_txhdr(struct awi_softc *sc, struct mbuf *m0);
! 177: static struct mbuf * awi_fix_rxhdr(struct awi_softc *sc, struct mbuf *m0);
! 178: static void awi_input(struct awi_softc *sc, struct mbuf *m, u_int32_t rxts, u_int8_t rssi);
! 179: static void awi_rxint(struct awi_softc *sc);
! 180: static struct mbuf * awi_devget(struct awi_softc *sc, u_int32_t off, u_int16_t len);
! 181: static int awi_init_hw(struct awi_softc *sc);
! 182: static int awi_init_mibs(struct awi_softc *sc);
! 183: static int awi_init_txrx(struct awi_softc *sc);
! 184: static void awi_stop_txrx(struct awi_softc *sc);
! 185: static int awi_start_scan(struct awi_softc *sc);
! 186: static int awi_next_scan(struct awi_softc *sc);
! 187: static void awi_stop_scan(struct awi_softc *sc);
! 188: static void awi_recv_beacon(struct awi_softc *sc, struct mbuf *m0, u_int32_t rxts, u_int8_t rssi);
! 189: static int awi_set_ss(struct awi_softc *sc);
! 190: static void awi_try_sync(struct awi_softc *sc);
! 191: static void awi_sync_done(struct awi_softc *sc);
! 192: static void awi_send_deauth(struct awi_softc *sc);
! 193: static void awi_send_auth(struct awi_softc *sc, int seq);
! 194: static void awi_recv_auth(struct awi_softc *sc, struct mbuf *m0);
! 195: static void awi_send_asreq(struct awi_softc *sc, int reassoc);
! 196: static void awi_recv_asresp(struct awi_softc *sc, struct mbuf *m0);
! 197: static int awi_mib(struct awi_softc *sc, u_int8_t cmd, u_int8_t mib);
! 198: static int awi_cmd_scan(struct awi_softc *sc);
! 199: static int awi_cmd(struct awi_softc *sc, u_int8_t cmd);
! 200: static void awi_cmd_done(struct awi_softc *sc);
! 201: static int awi_next_txd(struct awi_softc *sc, int len, u_int32_t *framep, u_int32_t*ntxdp);
! 202: static int awi_lock(struct awi_softc *sc);
! 203: static void awi_unlock(struct awi_softc *sc);
! 204: static int awi_intr_lock(struct awi_softc *sc);
! 205: static void awi_intr_unlock(struct awi_softc *sc);
! 206: static int awi_cmd_wait(struct awi_softc *sc);
! 207: static void awi_print_essid(u_int8_t *essid);
! 208:
! 209: #ifdef AWI_DEBUG
! 210: static void awi_dump_pkt(struct awi_softc *sc, struct mbuf *m, int rssi);
! 211: int awi_verbose = 0;
! 212: int awi_dump = 0;
! 213: #define AWI_DUMP_MASK(fc0) (1 << (((fc0) & IEEE80211_FC0_SUBTYPE_MASK) >> 4))
! 214: int awi_dump_mask = AWI_DUMP_MASK(IEEE80211_FC0_SUBTYPE_BEACON);
! 215: int awi_dump_hdr = 0;
! 216: int awi_dump_len = 28;
! 217: #endif
! 218:
! 219: #if NBPFILTER > 0
! 220: #define AWI_BPF_NORM 0
! 221: #define AWI_BPF_RAW 1
! 222: #ifdef __FreeBSD__
! 223: #define AWI_BPF_MTAP(sc, m, raw, dir) do { \
! 224: if ((sc)->sc_ifp->if_bpf && (sc)->sc_rawbpf == (raw)) \
! 225: bpf_mtap((sc)->sc_ifp, (m)); \
! 226: } while (0);
! 227: #else
! 228: #define AWI_BPF_MTAP(sc, m, raw, dir) do { \
! 229: if ((sc)->sc_ifp->if_bpf && (sc)->sc_rawbpf == (raw)) \
! 230: bpf_mtap((sc)->sc_ifp->if_bpf, (m), dir); \
! 231: } while (0);
! 232: #endif
! 233: #else
! 234: #define AWI_BPF_MTAP(sc, m, raw, dir)
! 235: #endif
! 236:
! 237: #ifndef llc_snap
! 238: #define llc_snap llc_un.type_snap
! 239: #endif
! 240:
! 241: #ifdef __OpenBSD__
! 242: struct cfdriver awi_cd = {
! 243: NULL, "awi", DV_IFNET
! 244: };
! 245: #endif
! 246:
! 247: #ifdef __FreeBSD__
! 248: #if __FreeBSD__ >= 4
! 249: devclass_t awi_devclass;
! 250: #endif
! 251:
! 252: /* NetBSD compatible functions */
! 253: static char * ether_sprintf(u_int8_t *);
! 254:
! 255: static char *
! 256: ether_sprintf(enaddr)
! 257: u_int8_t *enaddr;
! 258: {
! 259: static char strbuf[18];
! 260:
! 261: snprintf(strbuf, sizeof strbuf, "%6D", enaddr, ":");
! 262: return strbuf;
! 263: }
! 264: #endif
! 265:
! 266: int
! 267: awi_attach(sc)
! 268: struct awi_softc *sc;
! 269: {
! 270: struct ifnet *ifp = sc->sc_ifp;
! 271: int s;
! 272: int error;
! 273: #ifdef IFM_IEEE80211
! 274: int i;
! 275: u_int8_t *phy_rates;
! 276: int mword;
! 277: struct ifmediareq imr;
! 278: #endif
! 279:
! 280: s = splnet();
! 281: /*
! 282: * Even if we can sleep in initialization state,
! 283: * all other processes (e.g. ifconfig) have to wait for
! 284: * completion of attaching interface.
! 285: */
! 286: sc->sc_busy = 1;
! 287: sc->sc_status = AWI_ST_INIT;
! 288: TAILQ_INIT(&sc->sc_scan);
! 289: error = awi_init_hw(sc);
! 290: if (error) {
! 291: sc->sc_invalid = 1;
! 292: splx(s);
! 293: return error;
! 294: }
! 295: error = awi_init_mibs(sc);
! 296: splx(s);
! 297: if (error) {
! 298: sc->sc_invalid = 1;
! 299: return error;
! 300: }
! 301:
! 302: ifp->if_softc = sc;
! 303: ifp->if_start = awi_start;
! 304: ifp->if_ioctl = awi_ioctl;
! 305: ifp->if_watchdog = awi_watchdog;
! 306: ifp->if_hdrlen = sizeof(struct ieee80211_frame) +
! 307: sizeof(struct ether_header);
! 308: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 309: #ifdef IFF_NOTRAILERS
! 310: ifp->if_flags |= IFF_NOTRAILERS;
! 311: #endif
! 312: #if defined(__NetBSD__) || defined(__OpenBSD__)
! 313: memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
! 314: #endif
! 315: #ifdef __FreeBSD__
! 316: ifp->if_output = ether_output;
! 317: IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
! 318: memcpy(sc->sc_ec.ac_enaddr, sc->sc_mib_addr.aMAC_Address,
! 319: ETHER_ADDR_LEN);
! 320: #endif
! 321: IFQ_SET_READY(&ifp->if_snd);
! 322:
! 323: printf("%s: IEEE802.11 %s %dMbps (firmware %s)\n",
! 324: sc->sc_dev.dv_xname,
! 325: sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH ? "FH" : "DS",
! 326: sc->sc_tx_rate / 10, sc->sc_banner);
! 327: printf("%s: address %s\n",
! 328: sc->sc_dev.dv_xname, ether_sprintf(sc->sc_mib_addr.aMAC_Address));
! 329: if_attach(ifp);
! 330: #ifdef __OpenBSD__
! 331: ether_ifattach(ifp);
! 332: #elif defined(__FreeBSD__)
! 333: ether_ifattach(ifp);
! 334: #if NBPFILTER > 0
! 335: bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
! 336: #endif
! 337: #elif defined(__NetBSD__)
! 338: ether_ifattach(ifp, sc->sc_mib_addr.aMAC_Address);
! 339: #endif
! 340:
! 341: #ifdef IFM_IEEE80211
! 342: ifmedia_init(&sc->sc_media, 0, awi_media_change, awi_media_status);
! 343: phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
! 344: for (i = 0; i < phy_rates[1]; i++) {
! 345: mword = awi_media_rate2opt(sc, AWI_80211_RATE(phy_rates[2 + i]));
! 346: if (mword == 0)
! 347: continue;
! 348: mword |= IFM_IEEE80211;
! 349: ifmedia_add(&sc->sc_media, mword, 0, NULL);
! 350: ifmedia_add(&sc->sc_media,
! 351: mword | IFM_IEEE80211_ADHOC, 0, NULL);
! 352: if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_FH)
! 353: ifmedia_add(&sc->sc_media,
! 354: mword | IFM_IEEE80211_ADHOC | IFM_FLAG0, 0, NULL);
! 355: }
! 356: awi_media_status(ifp, &imr);
! 357: ifmedia_set(&sc->sc_media, imr.ifm_active);
! 358: #endif
! 359:
! 360: /* ready to accept ioctl */
! 361: awi_unlock(sc);
! 362:
! 363: /* Attach is successful. */
! 364: sc->sc_attached = 1;
! 365: return 0;
! 366: }
! 367:
! 368: #ifndef __FreeBSD__
! 369: int
! 370: awi_detach(sc)
! 371: struct awi_softc *sc;
! 372: {
! 373: struct ifnet *ifp = sc->sc_ifp;
! 374: int s;
! 375:
! 376: /* Succeed if there is no work to do. */
! 377: if (!sc->sc_attached)
! 378: return (0);
! 379:
! 380: s = splnet();
! 381: sc->sc_invalid = 1;
! 382: awi_stop(sc);
! 383: while (sc->sc_sleep_cnt > 0) {
! 384: wakeup(sc);
! 385: (void)tsleep(sc, PWAIT, "awidet", 1);
! 386: }
! 387: if (sc->sc_wep_ctx != NULL)
! 388: free(sc->sc_wep_ctx, M_DEVBUF);
! 389: #ifdef IFM_IEEE80211
! 390: ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
! 391: #endif
! 392: ether_ifdetach(ifp);
! 393: if_detach(ifp);
! 394: if (sc->sc_enabled) {
! 395: if (sc->sc_disable)
! 396: (*sc->sc_disable)(sc);
! 397: sc->sc_enabled = 0;
! 398: }
! 399: splx(s);
! 400: return 0;
! 401: }
! 402:
! 403: int
! 404: awi_activate(self, act)
! 405: struct device *self;
! 406: enum devact act;
! 407: {
! 408: struct awi_softc *sc = (struct awi_softc *)self;
! 409: int s, error = 0;
! 410:
! 411: s = splnet();
! 412: switch (act) {
! 413: case DVACT_ACTIVATE:
! 414: break;
! 415:
! 416: case DVACT_DEACTIVATE:
! 417: sc->sc_invalid = 1;
! 418: #ifdef __NetBSD__
! 419: if (sc->sc_ifp)
! 420: if_deactivate(sc->sc_ifp);
! 421: #endif
! 422: break;
! 423: }
! 424: splx(s);
! 425:
! 426: return error;
! 427: }
! 428:
! 429: void
! 430: awi_power(sc, why)
! 431: struct awi_softc *sc;
! 432: int why;
! 433: {
! 434: int s;
! 435: int ocansleep;
! 436:
! 437: if (!sc->sc_enabled)
! 438: return;
! 439:
! 440: s = splnet();
! 441: ocansleep = sc->sc_cansleep;
! 442: sc->sc_cansleep = 0;
! 443: #ifdef needtobefixed /*ONOE*/
! 444: if (why == PWR_RESUME) {
! 445: sc->sc_enabled = 0;
! 446: awi_init(sc);
! 447: (void)awi_intr(sc);
! 448: } else {
! 449: awi_stop(sc);
! 450: if (sc->sc_disable)
! 451: (*sc->sc_disable)(sc);
! 452: }
! 453: #endif
! 454: sc->sc_cansleep = ocansleep;
! 455: splx(s);
! 456: }
! 457: #endif /* __NetBSD__ */
! 458:
! 459: static int
! 460: awi_ioctl(ifp, cmd, data)
! 461: struct ifnet *ifp;
! 462: u_long cmd;
! 463: caddr_t data;
! 464: {
! 465: struct awi_softc *sc = ifp->if_softc;
! 466: struct ifreq *ifr = (struct ifreq *)data;
! 467: struct ifaddr *ifa = (struct ifaddr *)data;
! 468: int s, error;
! 469: struct ieee80211_nwid nwid;
! 470: u_int8_t *p;
! 471:
! 472: s = splnet();
! 473:
! 474: #ifdef __OpenBSD__
! 475: if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
! 476: splx(s);
! 477: return (error);
! 478: }
! 479: #endif
! 480:
! 481: /* serialize ioctl */
! 482: error = awi_lock(sc);
! 483: if (error)
! 484: goto cantlock;
! 485: switch (cmd) {
! 486: case SIOCSIFADDR:
! 487: ifp->if_flags |= IFF_UP;
! 488: switch (ifa->ifa_addr->sa_family) {
! 489: #ifdef INET
! 490: case AF_INET:
! 491: arp_ifinit((void *)ifp, ifa);
! 492: break;
! 493: #endif
! 494: }
! 495: /* FALLTHROUGH */
! 496: case SIOCSIFFLAGS:
! 497: sc->sc_format_llc = !(ifp->if_flags & IFF_LINK0);
! 498: if (!(ifp->if_flags & IFF_UP)) {
! 499: if (sc->sc_enabled) {
! 500: awi_stop(sc);
! 501: if (sc->sc_disable)
! 502: (*sc->sc_disable)(sc);
! 503: sc->sc_enabled = 0;
! 504: }
! 505: break;
! 506: }
! 507: error = awi_init(sc);
! 508: break;
! 509:
! 510: case SIOCADDMULTI:
! 511: case SIOCDELMULTI:
! 512: #ifdef __FreeBSD__
! 513: error = ENETRESET; /*XXX*/
! 514: #else
! 515: error = (cmd == SIOCADDMULTI) ?
! 516: ether_addmulti(ifr, &sc->sc_arpcom) :
! 517: ether_delmulti(ifr, &sc->sc_arpcom);
! 518: #endif
! 519: /*
! 520: * Do not rescan BSS. Rather, just reset multicast filter.
! 521: */
! 522: if (error == ENETRESET) {
! 523: if (ifp->if_flags & IFF_RUNNING)
! 524: error = awi_init(sc);
! 525: else
! 526: error = 0;
! 527: }
! 528: break;
! 529: case SIOCSIFMTU:
! 530: if (ifr->ifr_mtu > ETHERMTU)
! 531: error = EINVAL;
! 532: else
! 533: ifp->if_mtu = ifr->ifr_mtu;
! 534: break;
! 535: case SIOCS80211NWID:
! 536: if ((error = suser(curproc, 0)) != 0)
! 537: break;
! 538: error = copyin(ifr->ifr_data, &nwid, sizeof(nwid));
! 539: if (error)
! 540: break;
! 541: if (nwid.i_len > IEEE80211_NWID_LEN) {
! 542: error = EINVAL;
! 543: break;
! 544: }
! 545: if (sc->sc_mib_mac.aDesired_ESS_ID[1] == nwid.i_len &&
! 546: memcmp(&sc->sc_mib_mac.aDesired_ESS_ID[2], nwid.i_nwid,
! 547: nwid.i_len) == 0)
! 548: break;
! 549: memset(sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
! 550: sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
! 551: sc->sc_mib_mac.aDesired_ESS_ID[1] = nwid.i_len;
! 552: memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], nwid.i_nwid,
! 553: nwid.i_len);
! 554: if (sc->sc_enabled) {
! 555: awi_stop(sc);
! 556: error = awi_init(sc);
! 557: }
! 558: break;
! 559: case SIOCG80211NWID:
! 560: if (ifp->if_flags & IFF_RUNNING)
! 561: p = sc->sc_bss.essid;
! 562: else
! 563: p = sc->sc_mib_mac.aDesired_ESS_ID;
! 564: error = copyout(p + 1, ifr->ifr_data, 1 + IEEE80211_NWID_LEN);
! 565: break;
! 566: case SIOCS80211NWKEY:
! 567: if ((error = suser(curproc, 0)) != 0)
! 568: break;
! 569: error = awi_wep_setnwkey(sc, (struct ieee80211_nwkey *)data);
! 570: break;
! 571: case SIOCG80211NWKEY:
! 572: error = awi_wep_getnwkey(sc, (struct ieee80211_nwkey *)data);
! 573: break;
! 574: #ifdef IFM_IEEE80211
! 575: case SIOCSIFMEDIA:
! 576: case SIOCGIFMEDIA:
! 577: error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
! 578: break;
! 579: #endif
! 580: default:
! 581: #ifdef notyet
! 582: error = awi_wicfg(ifp, cmd, data);
! 583: #else
! 584: error = EINVAL;
! 585: #endif
! 586: break;
! 587: }
! 588: awi_unlock(sc);
! 589: cantlock:
! 590: splx(s);
! 591: return error;
! 592: }
! 593:
! 594: #ifdef IFM_IEEE80211
! 595: static int
! 596: awi_media_rate2opt(sc, rate)
! 597: struct awi_softc *sc;
! 598: int rate;
! 599: {
! 600: int mword;
! 601:
! 602: mword = 0;
! 603: switch (rate) {
! 604: case 10:
! 605: if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
! 606: mword = IFM_IEEE80211_FH1;
! 607: else
! 608: mword = IFM_IEEE80211_DS1;
! 609: break;
! 610: case 20:
! 611: if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
! 612: mword = IFM_IEEE80211_FH2;
! 613: else
! 614: mword = IFM_IEEE80211_DS2;
! 615: break;
! 616: case 55:
! 617: if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_DS)
! 618: mword = IFM_IEEE80211_DS5;
! 619: break;
! 620: case 110:
! 621: if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_DS)
! 622: mword = IFM_IEEE80211_DS11;
! 623: break;
! 624: }
! 625: return mword;
! 626: }
! 627:
! 628: static int
! 629: awi_media_opt2rate(sc, opt)
! 630: struct awi_softc *sc;
! 631: int opt;
! 632: {
! 633: int rate;
! 634:
! 635: rate = 0;
! 636: switch (IFM_SUBTYPE(opt)) {
! 637: case IFM_IEEE80211_FH1:
! 638: case IFM_IEEE80211_FH2:
! 639: if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_FH)
! 640: return 0;
! 641: break;
! 642: case IFM_IEEE80211_DS1:
! 643: case IFM_IEEE80211_DS2:
! 644: case IFM_IEEE80211_DS5:
! 645: case IFM_IEEE80211_DS11:
! 646: if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_DS)
! 647: return 0;
! 648: break;
! 649: }
! 650:
! 651: switch (IFM_SUBTYPE(opt)) {
! 652: case IFM_IEEE80211_FH1:
! 653: case IFM_IEEE80211_DS1:
! 654: rate = 10;
! 655: break;
! 656: case IFM_IEEE80211_FH2:
! 657: case IFM_IEEE80211_DS2:
! 658: rate = 20;
! 659: break;
! 660: case IFM_IEEE80211_DS5:
! 661: rate = 55;
! 662: break;
! 663: case IFM_IEEE80211_DS11:
! 664: rate = 110;
! 665: break;
! 666: }
! 667: return rate;
! 668: }
! 669:
! 670: /*
! 671: * Called from ifmedia_ioctl via awi_ioctl with lock obtained.
! 672: */
! 673: static int
! 674: awi_media_change(ifp)
! 675: struct ifnet *ifp;
! 676: {
! 677: struct awi_softc *sc = ifp->if_softc;
! 678: struct ifmedia_entry *ime;
! 679: u_int8_t *phy_rates;
! 680: int i, rate, error;
! 681:
! 682: error = 0;
! 683: ime = sc->sc_media.ifm_cur;
! 684: rate = awi_media_opt2rate(sc, ime->ifm_media);
! 685: if (rate == 0)
! 686: return EINVAL;
! 687: if (rate != sc->sc_tx_rate) {
! 688: phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
! 689: for (i = 0; i < phy_rates[1]; i++) {
! 690: if (rate == AWI_80211_RATE(phy_rates[2 + i]))
! 691: break;
! 692: }
! 693: if (i == phy_rates[1])
! 694: return EINVAL;
! 695: }
! 696: if (ime->ifm_media & IFM_IEEE80211_ADHOC) {
! 697: sc->sc_mib_local.Network_Mode = 0;
! 698: if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
! 699: sc->sc_no_bssid = 0;
! 700: else
! 701: sc->sc_no_bssid = (ime->ifm_media & IFM_FLAG0) ? 1 : 0;
! 702: } else {
! 703: sc->sc_mib_local.Network_Mode = 1;
! 704: }
! 705: if (sc->sc_enabled) {
! 706: awi_stop(sc);
! 707: error = awi_init(sc);
! 708: }
! 709: return error;
! 710: }
! 711:
! 712: static void
! 713: awi_media_status(ifp, imr)
! 714: struct ifnet *ifp;
! 715: struct ifmediareq *imr;
! 716: {
! 717: struct awi_softc *sc = ifp->if_softc;
! 718:
! 719: imr->ifm_status = IFM_AVALID;
! 720: if (ifp->if_flags & IFF_RUNNING)
! 721: imr->ifm_status |= IFM_ACTIVE;
! 722: imr->ifm_active = IFM_IEEE80211;
! 723: imr->ifm_active |= awi_media_rate2opt(sc, sc->sc_tx_rate);
! 724: if (sc->sc_mib_local.Network_Mode == 0) {
! 725: imr->ifm_active |= IFM_IEEE80211_ADHOC;
! 726: if (sc->sc_no_bssid)
! 727: imr->ifm_active |= IFM_FLAG0;
! 728: }
! 729: }
! 730: #endif /* IFM_IEEE80211 */
! 731:
! 732: int
! 733: awi_intr(arg)
! 734: void *arg;
! 735: {
! 736: struct awi_softc *sc = arg;
! 737: u_int16_t status;
! 738: int error, handled = 0, ocansleep;
! 739:
! 740: if (!sc->sc_enabled || !sc->sc_enab_intr || sc->sc_invalid)
! 741: return 0;
! 742:
! 743: am79c930_gcr_setbits(&sc->sc_chip,
! 744: AM79C930_GCR_DISPWDN | AM79C930_GCR_ECINT);
! 745: awi_write_1(sc, AWI_DIS_PWRDN, 1);
! 746: ocansleep = sc->sc_cansleep;
! 747: sc->sc_cansleep = 0;
! 748:
! 749: for (;;) {
! 750: error = awi_intr_lock(sc);
! 751: if (error)
! 752: break;
! 753: status = awi_read_1(sc, AWI_INTSTAT);
! 754: awi_write_1(sc, AWI_INTSTAT, 0);
! 755: awi_write_1(sc, AWI_INTSTAT, 0);
! 756: status |= awi_read_1(sc, AWI_INTSTAT2) << 8;
! 757: awi_write_1(sc, AWI_INTSTAT2, 0);
! 758: DELAY(10);
! 759: awi_intr_unlock(sc);
! 760: if (!sc->sc_cmd_inprog)
! 761: status &= ~AWI_INT_CMD; /* make sure */
! 762: if (status == 0)
! 763: break;
! 764: handled = 1;
! 765: if (status & AWI_INT_RX)
! 766: awi_rxint(sc);
! 767: if (status & AWI_INT_TX)
! 768: awi_txint(sc);
! 769: if (status & AWI_INT_CMD)
! 770: awi_cmd_done(sc);
! 771: if (status & AWI_INT_SCAN_CMPLT) {
! 772: if (sc->sc_status == AWI_ST_SCAN &&
! 773: sc->sc_mgt_timer > 0)
! 774: (void)awi_next_scan(sc);
! 775: }
! 776: }
! 777: sc->sc_cansleep = ocansleep;
! 778: am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_DISPWDN);
! 779: awi_write_1(sc, AWI_DIS_PWRDN, 0);
! 780: return handled;
! 781: }
! 782:
! 783: int
! 784: awi_init(sc)
! 785: struct awi_softc *sc;
! 786: {
! 787: int error, ostatus;
! 788: int n;
! 789: struct ifnet *ifp = sc->sc_ifp;
! 790: #ifdef __FreeBSD__
! 791: struct ifmultiaddr *ifma;
! 792: #else
! 793: struct ether_multi *enm;
! 794: struct ether_multistep step;
! 795: #endif
! 796:
! 797: /* reinitialize muticast filter */
! 798: n = 0;
! 799: ifp->if_flags |= IFF_ALLMULTI;
! 800: sc->sc_mib_local.Accept_All_Multicast_Dis = 0;
! 801: if (ifp->if_flags & IFF_PROMISC) {
! 802: sc->sc_mib_mac.aPromiscuous_Enable = 1;
! 803: goto set_mib;
! 804: }
! 805: sc->sc_mib_mac.aPromiscuous_Enable = 0;
! 806: #ifdef __FreeBSD__
! 807: if (ifp->if_amcount != 0)
! 808: goto set_mib;
! 809: for (ifma = LIST_FIRST(&ifp->if_multiaddrs); ifma != NULL;
! 810: ifma = LIST_NEXT(ifma, ifma_link)) {
! 811: if (ifma->ifma_addr->sa_family != AF_LINK)
! 812: continue;
! 813: if (n == AWI_GROUP_ADDR_SIZE)
! 814: goto set_mib;
! 815: memcpy(sc->sc_mib_addr.aGroup_Addresses[n],
! 816: LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
! 817: ETHER_ADDR_LEN);
! 818: n++;
! 819: }
! 820: #else
! 821: ETHER_FIRST_MULTI(step, &sc->sc_arpcom, enm);
! 822: while (enm != NULL) {
! 823: if (n == AWI_GROUP_ADDR_SIZE ||
! 824: memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)
! 825: != 0)
! 826: goto set_mib;
! 827: memcpy(sc->sc_mib_addr.aGroup_Addresses[n], enm->enm_addrlo,
! 828: ETHER_ADDR_LEN);
! 829: n++;
! 830: ETHER_NEXT_MULTI(step, enm);
! 831: }
! 832: #endif
! 833: for (; n < AWI_GROUP_ADDR_SIZE; n++)
! 834: memset(sc->sc_mib_addr.aGroup_Addresses[n], 0, ETHER_ADDR_LEN);
! 835: ifp->if_flags &= ~IFF_ALLMULTI;
! 836: sc->sc_mib_local.Accept_All_Multicast_Dis = 1;
! 837:
! 838: set_mib:
! 839: #ifdef notdef /* allow non-encrypted frame for receiving. */
! 840: sc->sc_mib_mgt.Wep_Required = sc->sc_wep_algo != NULL ? 1 : 0;
! 841: #endif
! 842: if (!sc->sc_enabled) {
! 843: sc->sc_enabled = 1;
! 844: if (sc->sc_enable)
! 845: (*sc->sc_enable)(sc);
! 846: sc->sc_status = AWI_ST_INIT;
! 847: error = awi_init_hw(sc);
! 848: if (error)
! 849: return error;
! 850: }
! 851: ostatus = sc->sc_status;
! 852: sc->sc_status = AWI_ST_INIT;
! 853: if ((error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_LOCAL)) != 0 ||
! 854: (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_ADDR)) != 0 ||
! 855: (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MAC)) != 0 ||
! 856: (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT)) != 0 ||
! 857: (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_PHY)) != 0) {
! 858: awi_stop(sc);
! 859: return error;
! 860: }
! 861: if (ifp->if_flags & IFF_RUNNING)
! 862: sc->sc_status = AWI_ST_RUNNING;
! 863: else {
! 864: if (ostatus == AWI_ST_INIT) {
! 865: error = awi_init_txrx(sc);
! 866: if (error)
! 867: return error;
! 868: }
! 869: error = awi_start_scan(sc);
! 870: }
! 871: return error;
! 872: }
! 873:
! 874: void
! 875: awi_stop(sc)
! 876: struct awi_softc *sc;
! 877: {
! 878: struct ifnet *ifp = sc->sc_ifp;
! 879: struct awi_bss *bp;
! 880: struct mbuf *m;
! 881:
! 882: sc->sc_status = AWI_ST_INIT;
! 883: if (!sc->sc_invalid) {
! 884: (void)awi_cmd_wait(sc);
! 885: if (sc->sc_mib_local.Network_Mode &&
! 886: sc->sc_status > AWI_ST_AUTH)
! 887: awi_send_deauth(sc);
! 888: awi_stop_txrx(sc);
! 889: }
! 890: ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
! 891: ifp->if_timer = 0;
! 892: sc->sc_tx_timer = sc->sc_rx_timer = sc->sc_mgt_timer = 0;
! 893: for (;;) {
! 894: IF_DEQUEUE(&sc->sc_mgtq, m);
! 895: if (m == NULL)
! 896: break;
! 897: m_freem(m);
! 898: }
! 899: IFQ_PURGE(&ifp->if_snd);
! 900: while ((bp = TAILQ_FIRST(&sc->sc_scan)) != NULL) {
! 901: TAILQ_REMOVE(&sc->sc_scan, bp, list);
! 902: free(bp, M_DEVBUF);
! 903: }
! 904: }
! 905:
! 906: static void
! 907: awi_watchdog(ifp)
! 908: struct ifnet *ifp;
! 909: {
! 910: struct awi_softc *sc = ifp->if_softc;
! 911: int ocansleep;
! 912:
! 913: if (sc->sc_invalid) {
! 914: ifp->if_timer = 0;
! 915: return;
! 916: }
! 917:
! 918: ocansleep = sc->sc_cansleep;
! 919: sc->sc_cansleep = 0;
! 920: if (sc->sc_tx_timer && --sc->sc_tx_timer == 0) {
! 921: printf("%s: transmit timeout\n", sc->sc_dev.dv_xname);
! 922: awi_txint(sc);
! 923: }
! 924: if (sc->sc_rx_timer && --sc->sc_rx_timer == 0) {
! 925: if (ifp->if_flags & IFF_DEBUG) {
! 926: printf("%s: no recent beacons from %s; rescanning\n",
! 927: sc->sc_dev.dv_xname,
! 928: ether_sprintf(sc->sc_bss.bssid));
! 929: }
! 930: ifp->if_flags &= ~IFF_RUNNING;
! 931: awi_start_scan(sc);
! 932: }
! 933: if (sc->sc_mgt_timer && --sc->sc_mgt_timer == 0) {
! 934: switch (sc->sc_status) {
! 935: case AWI_ST_SCAN:
! 936: awi_stop_scan(sc);
! 937: break;
! 938: case AWI_ST_AUTH:
! 939: case AWI_ST_ASSOC:
! 940: /* restart scan */
! 941: awi_start_scan(sc);
! 942: break;
! 943: default:
! 944: break;
! 945: }
! 946: }
! 947:
! 948: if (sc->sc_tx_timer == 0 && sc->sc_rx_timer == 0 &&
! 949: sc->sc_mgt_timer == 0)
! 950: ifp->if_timer = 0;
! 951: else
! 952: ifp->if_timer = 1;
! 953: sc->sc_cansleep = ocansleep;
! 954: }
! 955:
! 956: static void
! 957: awi_start(ifp)
! 958: struct ifnet *ifp;
! 959: {
! 960: struct awi_softc *sc = ifp->if_softc;
! 961: struct mbuf *m0, *m;
! 962: u_int32_t txd, frame, ntxd;
! 963: u_int8_t rate;
! 964: int len, sent = 0;
! 965:
! 966: for (;;) {
! 967: txd = sc->sc_txnext;
! 968: IF_DEQUEUE(&sc->sc_mgtq, m0);
! 969: if (m0 != NULL) {
! 970: if (awi_next_txd(sc, m0->m_pkthdr.len, &frame, &ntxd)) {
! 971: IF_PREPEND(&sc->sc_mgtq, m0);
! 972: ifp->if_flags |= IFF_OACTIVE;
! 973: break;
! 974: }
! 975: } else {
! 976: if (!(ifp->if_flags & IFF_RUNNING))
! 977: break;
! 978: IFQ_POLL(&ifp->if_snd, m0);
! 979: if (m0 == NULL)
! 980: break;
! 981: len = m0->m_pkthdr.len + sizeof(struct ieee80211_frame);
! 982: if (sc->sc_format_llc)
! 983: len += sizeof(struct llc) -
! 984: sizeof(struct ether_header);
! 985: if (sc->sc_wep_algo != NULL)
! 986: len += IEEE80211_WEP_IVLEN +
! 987: IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
! 988: if (awi_next_txd(sc, len, &frame, &ntxd)) {
! 989: ifp->if_flags |= IFF_OACTIVE;
! 990: break;
! 991: }
! 992: IFQ_DEQUEUE(&ifp->if_snd, m0);
! 993: AWI_BPF_MTAP(sc, m0, AWI_BPF_NORM, BPF_DIRECTION_OUT);
! 994: m0 = awi_fix_txhdr(sc, m0);
! 995: if (sc->sc_wep_algo != NULL && m0 != NULL)
! 996: m0 = awi_wep_encrypt(sc, m0, 1);
! 997: if (m0 == NULL) {
! 998: ifp->if_oerrors++;
! 999: continue;
! 1000: }
! 1001: ifp->if_opackets++;
! 1002: }
! 1003: #ifdef AWI_DEBUG
! 1004: if (awi_dump)
! 1005: awi_dump_pkt(sc, m0, -1);
! 1006: #endif
! 1007: AWI_BPF_MTAP(sc, m0, AWI_BPF_RAW, BPF_DIRECTION_OUT);
! 1008: len = 0;
! 1009: for (m = m0; m != NULL; m = m->m_next) {
! 1010: awi_write_bytes(sc, frame + len, mtod(m, u_int8_t *),
! 1011: m->m_len);
! 1012: len += m->m_len;
! 1013: }
! 1014: m_freem(m0);
! 1015: rate = sc->sc_tx_rate; /*XXX*/
! 1016: awi_write_1(sc, ntxd + AWI_TXD_STATE, 0);
! 1017: awi_write_4(sc, txd + AWI_TXD_START, frame);
! 1018: awi_write_4(sc, txd + AWI_TXD_NEXT, ntxd);
! 1019: awi_write_4(sc, txd + AWI_TXD_LENGTH, len);
! 1020: awi_write_1(sc, txd + AWI_TXD_RATE, rate);
! 1021: awi_write_4(sc, txd + AWI_TXD_NDA, 0);
! 1022: awi_write_4(sc, txd + AWI_TXD_NRA, 0);
! 1023: awi_write_1(sc, txd + AWI_TXD_STATE, AWI_TXD_ST_OWN);
! 1024: sc->sc_txnext = ntxd;
! 1025: sent++;
! 1026: }
! 1027: if (sent) {
! 1028: if (sc->sc_tx_timer == 0)
! 1029: sc->sc_tx_timer = 5;
! 1030: ifp->if_timer = 1;
! 1031: #ifdef AWI_DEBUG
! 1032: if (awi_verbose)
! 1033: printf("awi_start: sent %d txdone %d txnext %d txbase %d txend %d\n", sent, sc->sc_txdone, sc->sc_txnext, sc->sc_txbase, sc->sc_txend);
! 1034: #endif
! 1035: }
! 1036: }
! 1037:
! 1038: static void
! 1039: awi_txint(sc)
! 1040: struct awi_softc *sc;
! 1041: {
! 1042: struct ifnet *ifp = sc->sc_ifp;
! 1043: u_int8_t flags;
! 1044:
! 1045: while (sc->sc_txdone != sc->sc_txnext) {
! 1046: flags = awi_read_1(sc, sc->sc_txdone + AWI_TXD_STATE);
! 1047: if ((flags & AWI_TXD_ST_OWN) || !(flags & AWI_TXD_ST_DONE))
! 1048: break;
! 1049: if (flags & AWI_TXD_ST_ERROR)
! 1050: ifp->if_oerrors++;
! 1051: sc->sc_txdone = awi_read_4(sc, sc->sc_txdone + AWI_TXD_NEXT) &
! 1052: 0x7fff;
! 1053: }
! 1054: sc->sc_tx_timer = 0;
! 1055: ifp->if_flags &= ~IFF_OACTIVE;
! 1056: #ifdef AWI_DEBUG
! 1057: if (awi_verbose)
! 1058: printf("awi_txint: txdone %d txnext %d txbase %d txend %d\n",
! 1059: sc->sc_txdone, sc->sc_txnext, sc->sc_txbase, sc->sc_txend);
! 1060: #endif
! 1061: awi_start(ifp);
! 1062: }
! 1063:
! 1064: static struct mbuf *
! 1065: awi_fix_txhdr(sc, m0)
! 1066: struct awi_softc *sc;
! 1067: struct mbuf *m0;
! 1068: {
! 1069: struct ether_header eh;
! 1070: struct ieee80211_frame *wh;
! 1071: struct llc *llc;
! 1072:
! 1073: if (m0->m_len < sizeof(eh)) {
! 1074: m0 = m_pullup(m0, sizeof(eh));
! 1075: if (m0 == NULL)
! 1076: return NULL;
! 1077: }
! 1078: memcpy(&eh, mtod(m0, caddr_t), sizeof(eh));
! 1079: if (sc->sc_format_llc) {
! 1080: m_adj(m0, sizeof(struct ether_header) - sizeof(struct llc));
! 1081: llc = mtod(m0, struct llc *);
! 1082: llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
! 1083: llc->llc_control = LLC_UI;
! 1084: llc->llc_snap.org_code[0] = llc->llc_snap.org_code[1] =
! 1085: llc->llc_snap.org_code[2] = 0;
! 1086: llc->llc_snap.ether_type = eh.ether_type;
! 1087: }
! 1088: M_PREPEND(m0, sizeof(struct ieee80211_frame), M_DONTWAIT);
! 1089: if (m0 == NULL)
! 1090: return NULL;
! 1091: wh = mtod(m0, struct ieee80211_frame *);
! 1092:
! 1093: wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
! 1094: LE_WRITE_2(wh->i_dur, 0);
! 1095: LE_WRITE_2(wh->i_seq, 0);
! 1096: if (sc->sc_mib_local.Network_Mode) {
! 1097: wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
! 1098: memcpy(wh->i_addr1, sc->sc_bss.bssid, ETHER_ADDR_LEN);
! 1099: memcpy(wh->i_addr2, eh.ether_shost, ETHER_ADDR_LEN);
! 1100: memcpy(wh->i_addr3, eh.ether_dhost, ETHER_ADDR_LEN);
! 1101: } else {
! 1102: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
! 1103: memcpy(wh->i_addr1, eh.ether_dhost, ETHER_ADDR_LEN);
! 1104: memcpy(wh->i_addr2, eh.ether_shost, ETHER_ADDR_LEN);
! 1105: memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN);
! 1106: }
! 1107: return m0;
! 1108: }
! 1109:
! 1110: static struct mbuf *
! 1111: awi_fix_rxhdr(sc, m0)
! 1112: struct awi_softc *sc;
! 1113: struct mbuf *m0;
! 1114: {
! 1115: struct ieee80211_frame wh;
! 1116: struct ether_header *eh;
! 1117: struct llc *llc;
! 1118:
! 1119: if (m0->m_len < sizeof(wh)) {
! 1120: m_freem(m0);
! 1121: return NULL;
! 1122: }
! 1123: llc = (struct llc *)(mtod(m0, caddr_t) + sizeof(wh));
! 1124: if (llc->llc_dsap == LLC_SNAP_LSAP &&
! 1125: llc->llc_ssap == LLC_SNAP_LSAP &&
! 1126: llc->llc_control == LLC_UI &&
! 1127: llc->llc_snap.org_code[0] == 0 &&
! 1128: llc->llc_snap.org_code[1] == 0 &&
! 1129: llc->llc_snap.org_code[2] == 0) {
! 1130: memcpy(&wh, mtod(m0, caddr_t), sizeof(wh));
! 1131: m_adj(m0, sizeof(wh) + sizeof(*llc) - sizeof(*eh));
! 1132: eh = mtod(m0, struct ether_header *);
! 1133: switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) {
! 1134: case IEEE80211_FC1_DIR_NODS:
! 1135: memcpy(eh->ether_dhost, wh.i_addr1, ETHER_ADDR_LEN);
! 1136: memcpy(eh->ether_shost, wh.i_addr2, ETHER_ADDR_LEN);
! 1137: break;
! 1138: case IEEE80211_FC1_DIR_TODS:
! 1139: memcpy(eh->ether_dhost, wh.i_addr3, ETHER_ADDR_LEN);
! 1140: memcpy(eh->ether_shost, wh.i_addr2, ETHER_ADDR_LEN);
! 1141: break;
! 1142: case IEEE80211_FC1_DIR_FROMDS:
! 1143: memcpy(eh->ether_dhost, wh.i_addr1, ETHER_ADDR_LEN);
! 1144: memcpy(eh->ether_shost, wh.i_addr3, ETHER_ADDR_LEN);
! 1145: break;
! 1146: case IEEE80211_FC1_DIR_DSTODS:
! 1147: m_freem(m0);
! 1148: return NULL;
! 1149: }
! 1150: } else {
! 1151: /* assuming ethernet encapsulation, just strip 802.11 header */
! 1152: m_adj(m0, sizeof(wh));
! 1153: }
! 1154: if (ALIGN(mtod(m0, caddr_t) + sizeof(struct ether_header)) !=
! 1155: (u_int)(mtod(m0, caddr_t) + sizeof(struct ether_header))) {
! 1156: /* XXX: we lose to estimate the type of encapsulation */
! 1157: struct mbuf *n, *n0, **np;
! 1158: caddr_t newdata;
! 1159: int off, oldmlen;
! 1160:
! 1161: n0 = NULL;
! 1162: np = &n0;
! 1163: off = 0;
! 1164: oldmlen = m0->m_pkthdr.len;
! 1165: while (oldmlen > off) {
! 1166: if (n0 == NULL) {
! 1167: MGETHDR(n, M_DONTWAIT, MT_DATA);
! 1168: if (n == NULL) {
! 1169: m_freem(m0);
! 1170: return NULL;
! 1171: }
! 1172: M_MOVE_PKTHDR(n, m0);
! 1173: n->m_len = MHLEN;
! 1174: } else {
! 1175: MGET(n, M_DONTWAIT, MT_DATA);
! 1176: if (n == NULL) {
! 1177: m_freem(m0);
! 1178: m_freem(n0);
! 1179: return NULL;
! 1180: }
! 1181: n->m_len = MLEN;
! 1182: }
! 1183: if (oldmlen - off >= MINCLSIZE) {
! 1184: MCLGET(n, M_DONTWAIT);
! 1185: if (n->m_flags & M_EXT)
! 1186: n->m_len = n->m_ext.ext_size;
! 1187: }
! 1188: if (n0 == NULL) {
! 1189: newdata = (caddr_t)
! 1190: ALIGN(n->m_data
! 1191: + sizeof(struct ether_header))
! 1192: - sizeof(struct ether_header);
! 1193: n->m_len -= newdata - n->m_data;
! 1194: n->m_data = newdata;
! 1195: }
! 1196: if (n->m_len > oldmlen - off)
! 1197: n->m_len = oldmlen - off;
! 1198: m_copydata(m0, off, n->m_len, mtod(n, caddr_t));
! 1199: off += n->m_len;
! 1200: *np = n;
! 1201: np = &n->m_next;
! 1202: }
! 1203: m_freem(m0);
! 1204: m0 = n0;
! 1205: }
! 1206: return m0;
! 1207: }
! 1208:
! 1209: static void
! 1210: awi_input(sc, m, rxts, rssi)
! 1211: struct awi_softc *sc;
! 1212: struct mbuf *m;
! 1213: u_int32_t rxts;
! 1214: u_int8_t rssi;
! 1215: {
! 1216: struct ifnet *ifp = sc->sc_ifp;
! 1217: struct ieee80211_frame *wh;
! 1218:
! 1219: /* trim CRC here for WEP can find its own CRC at the end of packet. */
! 1220: m_adj(m, -ETHER_CRC_LEN);
! 1221: AWI_BPF_MTAP(sc, m, AWI_BPF_RAW, BPF_DIRECTION_IN);
! 1222: wh = mtod(m, struct ieee80211_frame *);
! 1223: if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
! 1224: IEEE80211_FC0_VERSION_0) {
! 1225: printf("%s; receive packet with wrong version: %x\n",
! 1226: sc->sc_dev.dv_xname, wh->i_fc[0]);
! 1227: m_freem(m);
! 1228: ifp->if_ierrors++;
! 1229: return;
! 1230: }
! 1231: if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
! 1232: m = awi_wep_encrypt(sc, m, 0);
! 1233: if (m == NULL) {
! 1234: ifp->if_ierrors++;
! 1235: return;
! 1236: }
! 1237: wh = mtod(m, struct ieee80211_frame *);
! 1238: }
! 1239: #ifdef AWI_DEBUG
! 1240: if (awi_dump)
! 1241: awi_dump_pkt(sc, m, rssi);
! 1242: #endif
! 1243:
! 1244: if ((sc->sc_mib_local.Network_Mode || !sc->sc_no_bssid) &&
! 1245: sc->sc_status == AWI_ST_RUNNING) {
! 1246: if (memcmp(wh->i_addr2, sc->sc_bss.bssid, ETHER_ADDR_LEN) == 0) {
! 1247: sc->sc_rx_timer = 10;
! 1248: sc->sc_bss.rssi = rssi;
! 1249: }
! 1250: }
! 1251: switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
! 1252: case IEEE80211_FC0_TYPE_DATA:
! 1253: if (sc->sc_mib_local.Network_Mode) {
! 1254: if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
! 1255: IEEE80211_FC1_DIR_FROMDS) {
! 1256: m_freem(m);
! 1257: return;
! 1258: }
! 1259: } else {
! 1260: if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
! 1261: IEEE80211_FC1_DIR_NODS) {
! 1262: m_freem(m);
! 1263: return;
! 1264: }
! 1265: }
! 1266: m = awi_fix_rxhdr(sc, m);
! 1267: if (m == NULL) {
! 1268: ifp->if_ierrors++;
! 1269: break;
! 1270: }
! 1271: ifp->if_ipackets++;
! 1272: #if !(defined(__FreeBSD__) && __FreeBSD__ >= 4)
! 1273: AWI_BPF_MTAP(sc, m, AWI_BPF_NORM, BPF_DIRECTION_IN);
! 1274: #endif
! 1275: #ifdef __NetBSD__
! 1276: (*ifp->if_input)(ifp, m);
! 1277: #else
! 1278: ether_input_mbuf(ifp, m);
! 1279: #endif
! 1280: break;
! 1281: case IEEE80211_FC0_TYPE_MGT:
! 1282: if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
! 1283: IEEE80211_FC1_DIR_NODS) {
! 1284: m_freem(m);
! 1285: return;
! 1286: }
! 1287: switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
! 1288: case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
! 1289: case IEEE80211_FC0_SUBTYPE_BEACON:
! 1290: awi_recv_beacon(sc, m, rxts, rssi);
! 1291: break;
! 1292: case IEEE80211_FC0_SUBTYPE_AUTH:
! 1293: awi_recv_auth(sc, m);
! 1294: break;
! 1295: case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
! 1296: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
! 1297: awi_recv_asresp(sc, m);
! 1298: break;
! 1299: case IEEE80211_FC0_SUBTYPE_DEAUTH:
! 1300: if (sc->sc_mib_local.Network_Mode)
! 1301: awi_send_auth(sc, 1);
! 1302: break;
! 1303: case IEEE80211_FC0_SUBTYPE_DISASSOC:
! 1304: if (sc->sc_mib_local.Network_Mode)
! 1305: awi_send_asreq(sc, 1);
! 1306: break;
! 1307: }
! 1308: m_freem(m);
! 1309: break;
! 1310: case IEEE80211_FC0_TYPE_CTL:
! 1311: default:
! 1312: /* should not come here */
! 1313: m_freem(m);
! 1314: break;
! 1315: }
! 1316: }
! 1317:
! 1318: static void
! 1319: awi_rxint(sc)
! 1320: struct awi_softc *sc;
! 1321: {
! 1322: u_int8_t state, rate, rssi;
! 1323: u_int16_t len;
! 1324: u_int32_t frame, next, rxts, rxoff;
! 1325: struct mbuf *m;
! 1326:
! 1327: rxoff = sc->sc_rxdoff;
! 1328: for (;;) {
! 1329: state = awi_read_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE);
! 1330: if (state & AWI_RXD_ST_OWN)
! 1331: break;
! 1332: if (!(state & AWI_RXD_ST_CONSUMED)) {
! 1333: if (state & AWI_RXD_ST_RXERROR)
! 1334: sc->sc_ifp->if_ierrors++;
! 1335: else {
! 1336: len = awi_read_2(sc, rxoff + AWI_RXD_LEN);
! 1337: rate = awi_read_1(sc, rxoff + AWI_RXD_RATE);
! 1338: rssi = awi_read_1(sc, rxoff + AWI_RXD_RSSI);
! 1339: frame = awi_read_4(sc, rxoff + AWI_RXD_START_FRAME) & 0x7fff;
! 1340: rxts = awi_read_4(sc, rxoff + AWI_RXD_LOCALTIME);
! 1341: m = awi_devget(sc, frame, len);
! 1342: if (state & AWI_RXD_ST_LF)
! 1343: awi_input(sc, m, rxts, rssi);
! 1344: else
! 1345: sc->sc_rxpend = m;
! 1346: }
! 1347: state |= AWI_RXD_ST_CONSUMED;
! 1348: awi_write_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE, state);
! 1349: }
! 1350: next = awi_read_4(sc, rxoff + AWI_RXD_NEXT);
! 1351: if (next & AWI_RXD_NEXT_LAST)
! 1352: break;
! 1353: /* make sure the next pointer is correct */
! 1354: if (next != awi_read_4(sc, rxoff + AWI_RXD_NEXT))
! 1355: break;
! 1356: state |= AWI_RXD_ST_OWN;
! 1357: awi_write_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE, state);
! 1358: rxoff = next & 0x7fff;
! 1359: }
! 1360: sc->sc_rxdoff = rxoff;
! 1361: }
! 1362:
! 1363: static struct mbuf *
! 1364: awi_devget(sc, off, len)
! 1365: struct awi_softc *sc;
! 1366: u_int32_t off;
! 1367: u_int16_t len;
! 1368: {
! 1369: struct mbuf *m;
! 1370: struct mbuf *top, **mp;
! 1371: u_int tlen;
! 1372:
! 1373: top = sc->sc_rxpend;
! 1374: mp = ⊤
! 1375: if (top != NULL) {
! 1376: sc->sc_rxpend = NULL;
! 1377: top->m_pkthdr.len += len;
! 1378: m = top;
! 1379: while (*mp != NULL) {
! 1380: m = *mp;
! 1381: mp = &m->m_next;
! 1382: }
! 1383: if (m->m_flags & M_EXT)
! 1384: tlen = m->m_ext.ext_size;
! 1385: else if (m->m_flags & M_PKTHDR)
! 1386: tlen = MHLEN;
! 1387: else
! 1388: tlen = MLEN;
! 1389: tlen -= m->m_len;
! 1390: if (tlen > len)
! 1391: tlen = len;
! 1392: awi_read_bytes(sc, off, mtod(m, u_int8_t *) + m->m_len, tlen);
! 1393: off += tlen;
! 1394: len -= tlen;
! 1395: }
! 1396:
! 1397: while (len > 0) {
! 1398: if (top == NULL) {
! 1399: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 1400: if (m == NULL)
! 1401: return NULL;
! 1402: m->m_pkthdr.rcvif = sc->sc_ifp;
! 1403: m->m_pkthdr.len = len;
! 1404: m->m_len = MHLEN;
! 1405: } else {
! 1406: MGET(m, M_DONTWAIT, MT_DATA);
! 1407: if (m == NULL) {
! 1408: m_freem(top);
! 1409: return NULL;
! 1410: }
! 1411: m->m_len = MLEN;
! 1412: }
! 1413: if (len >= MINCLSIZE) {
! 1414: MCLGET(m, M_DONTWAIT);
! 1415: if (m->m_flags & M_EXT)
! 1416: m->m_len = m->m_ext.ext_size;
! 1417: }
! 1418: if (top == NULL) {
! 1419: int hdrlen = sizeof(struct ieee80211_frame) +
! 1420: (sc->sc_format_llc ? sizeof(struct llc) :
! 1421: sizeof(struct ether_header));
! 1422: caddr_t newdata = (caddr_t)
! 1423: ALIGN(m->m_data + hdrlen) - hdrlen;
! 1424: m->m_len -= newdata - m->m_data;
! 1425: m->m_data = newdata;
! 1426: }
! 1427: if (m->m_len > len)
! 1428: m->m_len = len;
! 1429: awi_read_bytes(sc, off, mtod(m, u_int8_t *), m->m_len);
! 1430: off += m->m_len;
! 1431: len -= m->m_len;
! 1432: *mp = m;
! 1433: mp = &m->m_next;
! 1434: }
! 1435: return top;
! 1436: }
! 1437:
! 1438: /*
! 1439: * Initialize hardware and start firmware to accept commands.
! 1440: * Called everytime after power on firmware.
! 1441: */
! 1442:
! 1443: static int
! 1444: awi_init_hw(sc)
! 1445: struct awi_softc *sc;
! 1446: {
! 1447: u_int8_t status;
! 1448: u_int16_t intmask;
! 1449: int i, error;
! 1450:
! 1451: sc->sc_enab_intr = 0;
! 1452: sc->sc_invalid = 0; /* XXX: really? */
! 1453: awi_drvstate(sc, AWI_DRV_RESET);
! 1454:
! 1455: /* reset firmware */
! 1456: am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_CORESET);
! 1457: DELAY(100);
! 1458: awi_write_1(sc, AWI_SELFTEST, 0);
! 1459: awi_write_1(sc, AWI_CMD, 0);
! 1460: awi_write_1(sc, AWI_BANNER, 0);
! 1461: am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_CORESET);
! 1462: DELAY(100);
! 1463:
! 1464: /* wait for selftest completion */
! 1465: for (i = 0; ; i++) {
! 1466: if (i >= AWI_SELFTEST_TIMEOUT*hz/1000) {
! 1467: printf("%s: failed to complete selftest (timeout)\n",
! 1468: sc->sc_dev.dv_xname);
! 1469: return ENXIO;
! 1470: }
! 1471: status = awi_read_1(sc, AWI_SELFTEST);
! 1472: if ((status & 0xf0) == 0xf0)
! 1473: break;
! 1474: if (sc->sc_cansleep) {
! 1475: sc->sc_sleep_cnt++;
! 1476: (void)tsleep(sc, PWAIT, "awitst", 1);
! 1477: sc->sc_sleep_cnt--;
! 1478: } else {
! 1479: DELAY(1000*1000/hz);
! 1480: }
! 1481: }
! 1482: if (status != AWI_SELFTEST_PASSED) {
! 1483: printf("%s: failed to complete selftest (code %x)\n",
! 1484: sc->sc_dev.dv_xname, status);
! 1485: return ENXIO;
! 1486: }
! 1487:
! 1488: /* check banner to confirm firmware write it */
! 1489: awi_read_bytes(sc, AWI_BANNER, sc->sc_banner, AWI_BANNER_LEN);
! 1490: if (memcmp(sc->sc_banner, "PCnetMobile:", 12) != 0) {
! 1491: printf("%s: failed to complete selftest (bad banner)\n",
! 1492: sc->sc_dev.dv_xname);
! 1493: for (i = 0; i < AWI_BANNER_LEN; i++)
! 1494: printf("%s%02x", i ? ":" : "\t", sc->sc_banner[i]);
! 1495: printf("\n");
! 1496: return ENXIO;
! 1497: }
! 1498:
! 1499: /* initializing interrupt */
! 1500: sc->sc_enab_intr = 1;
! 1501: error = awi_intr_lock(sc);
! 1502: if (error)
! 1503: return error;
! 1504: intmask = AWI_INT_GROGGY | AWI_INT_SCAN_CMPLT |
! 1505: AWI_INT_TX | AWI_INT_RX | AWI_INT_CMD;
! 1506: awi_write_1(sc, AWI_INTMASK, ~intmask & 0xff);
! 1507: awi_write_1(sc, AWI_INTMASK2, 0);
! 1508: awi_write_1(sc, AWI_INTSTAT, 0);
! 1509: awi_write_1(sc, AWI_INTSTAT2, 0);
! 1510: awi_intr_unlock(sc);
! 1511: am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_ENECINT);
! 1512:
! 1513: /* issueing interface test command */
! 1514: error = awi_cmd(sc, AWI_CMD_NOP);
! 1515: if (error) {
! 1516: printf("%s: failed to complete selftest", sc->sc_dev.dv_xname);
! 1517: if (error == ENXIO)
! 1518: printf(" (no hardware)\n");
! 1519: else if (error != EWOULDBLOCK)
! 1520: printf(" (error %d)\n", error);
! 1521: else if (sc->sc_cansleep)
! 1522: printf(" (lost interrupt)\n");
! 1523: else
! 1524: printf(" (command timeout)\n");
! 1525: }
! 1526: return error;
! 1527: }
! 1528:
! 1529: /*
! 1530: * Extract the factory default MIB value from firmware and assign the driver
! 1531: * default value.
! 1532: * Called once at attaching the interface.
! 1533: */
! 1534:
! 1535: static int
! 1536: awi_init_mibs(sc)
! 1537: struct awi_softc *sc;
! 1538: {
! 1539: int i, error;
! 1540: u_int8_t *rate;
! 1541:
! 1542: if ((error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_LOCAL)) != 0 ||
! 1543: (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_ADDR)) != 0 ||
! 1544: (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MAC)) != 0 ||
! 1545: (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MGT)) != 0 ||
! 1546: (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_PHY)) != 0) {
! 1547: printf("%s: failed to get default mib value (error %d)\n",
! 1548: sc->sc_dev.dv_xname, error);
! 1549: return error;
! 1550: }
! 1551:
! 1552: rate = sc->sc_mib_phy.aSuprt_Data_Rates;
! 1553: sc->sc_tx_rate = AWI_RATE_1MBIT;
! 1554: for (i = 0; i < rate[1]; i++) {
! 1555: if (AWI_80211_RATE(rate[2 + i]) > sc->sc_tx_rate)
! 1556: sc->sc_tx_rate = AWI_80211_RATE(rate[2 + i]);
! 1557: }
! 1558: awi_init_region(sc);
! 1559: memset(&sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
! 1560: sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
! 1561: sc->sc_mib_local.Fragmentation_Dis = 1;
! 1562: sc->sc_mib_local.Accept_All_Multicast_Dis = 1;
! 1563: sc->sc_mib_local.Power_Saving_Mode_Dis = 1;
! 1564:
! 1565: /* allocate buffers */
! 1566: sc->sc_txbase = AWI_BUFFERS;
! 1567: sc->sc_txend = sc->sc_txbase +
! 1568: (AWI_TXD_SIZE + sizeof(struct ieee80211_frame) +
! 1569: sizeof(struct ether_header) + ETHERMTU) * AWI_NTXBUFS;
! 1570: LE_WRITE_4(&sc->sc_mib_local.Tx_Buffer_Offset, sc->sc_txbase);
! 1571: LE_WRITE_4(&sc->sc_mib_local.Tx_Buffer_Size,
! 1572: sc->sc_txend - sc->sc_txbase);
! 1573: LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Offset, sc->sc_txend);
! 1574: LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Size,
! 1575: AWI_BUFFERS_END - sc->sc_txend);
! 1576: sc->sc_mib_local.Network_Mode = 1;
! 1577: sc->sc_mib_local.Acting_as_AP = 0;
! 1578: return 0;
! 1579: }
! 1580:
! 1581: /*
! 1582: * Start transmitter and receiver of firmware
! 1583: * Called after awi_init_hw() to start operation.
! 1584: */
! 1585:
! 1586: static int
! 1587: awi_init_txrx(sc)
! 1588: struct awi_softc *sc;
! 1589: {
! 1590: int error;
! 1591:
! 1592: /* start transmitter */
! 1593: sc->sc_txdone = sc->sc_txnext = sc->sc_txbase;
! 1594: awi_write_4(sc, sc->sc_txbase + AWI_TXD_START, 0);
! 1595: awi_write_4(sc, sc->sc_txbase + AWI_TXD_NEXT, 0);
! 1596: awi_write_4(sc, sc->sc_txbase + AWI_TXD_LENGTH, 0);
! 1597: awi_write_1(sc, sc->sc_txbase + AWI_TXD_RATE, 0);
! 1598: awi_write_4(sc, sc->sc_txbase + AWI_TXD_NDA, 0);
! 1599: awi_write_4(sc, sc->sc_txbase + AWI_TXD_NRA, 0);
! 1600: awi_write_1(sc, sc->sc_txbase + AWI_TXD_STATE, 0);
! 1601: awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_DATA, sc->sc_txbase);
! 1602: awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_MGT, 0);
! 1603: awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_BCAST, 0);
! 1604: awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_PS, 0);
! 1605: awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_CF, 0);
! 1606: error = awi_cmd(sc, AWI_CMD_INIT_TX);
! 1607: if (error)
! 1608: return error;
! 1609:
! 1610: /* start receiver */
! 1611: if (sc->sc_rxpend) {
! 1612: m_freem(sc->sc_rxpend);
! 1613: sc->sc_rxpend = NULL;
! 1614: }
! 1615: error = awi_cmd(sc, AWI_CMD_INIT_RX);
! 1616: if (error)
! 1617: return error;
! 1618: sc->sc_rxdoff = awi_read_4(sc, AWI_CMD_PARAMS+AWI_CA_IRX_DATA_DESC);
! 1619: sc->sc_rxmoff = awi_read_4(sc, AWI_CMD_PARAMS+AWI_CA_IRX_PS_DESC);
! 1620: return 0;
! 1621: }
! 1622:
! 1623: static void
! 1624: awi_stop_txrx(sc)
! 1625: struct awi_softc *sc;
! 1626: {
! 1627:
! 1628: if (sc->sc_cmd_inprog)
! 1629: (void)awi_cmd_wait(sc);
! 1630: (void)awi_cmd(sc, AWI_CMD_KILL_RX);
! 1631: (void)awi_cmd_wait(sc);
! 1632: sc->sc_cmd_inprog = AWI_CMD_FLUSH_TX;
! 1633: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_DATA, 1);
! 1634: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_MGT, 0);
! 1635: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_BCAST, 0);
! 1636: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_PS, 0);
! 1637: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_CF, 0);
! 1638: (void)awi_cmd(sc, AWI_CMD_FLUSH_TX);
! 1639: (void)awi_cmd_wait(sc);
! 1640: }
! 1641:
! 1642: int
! 1643: awi_init_region(sc)
! 1644: struct awi_softc *sc;
! 1645: {
! 1646:
! 1647: if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
! 1648: switch (sc->sc_mib_phy.aCurrent_Reg_Domain) {
! 1649: case AWI_REG_DOMAIN_US:
! 1650: case AWI_REG_DOMAIN_CA:
! 1651: case AWI_REG_DOMAIN_EU:
! 1652: sc->sc_scan_min = 0;
! 1653: sc->sc_scan_max = 77;
! 1654: break;
! 1655: case AWI_REG_DOMAIN_ES:
! 1656: sc->sc_scan_min = 0;
! 1657: sc->sc_scan_max = 26;
! 1658: break;
! 1659: case AWI_REG_DOMAIN_FR:
! 1660: sc->sc_scan_min = 0;
! 1661: sc->sc_scan_max = 32;
! 1662: break;
! 1663: case AWI_REG_DOMAIN_JP:
! 1664: sc->sc_scan_min = 6;
! 1665: sc->sc_scan_max = 17;
! 1666: break;
! 1667: default:
! 1668: return EINVAL;
! 1669: }
! 1670: sc->sc_scan_set = sc->sc_scan_cur % 3 + 1;
! 1671: } else {
! 1672: switch (sc->sc_mib_phy.aCurrent_Reg_Domain) {
! 1673: case AWI_REG_DOMAIN_US:
! 1674: case AWI_REG_DOMAIN_CA:
! 1675: sc->sc_scan_min = 1;
! 1676: sc->sc_scan_max = 11;
! 1677: sc->sc_scan_cur = 3;
! 1678: break;
! 1679: case AWI_REG_DOMAIN_EU:
! 1680: sc->sc_scan_min = 1;
! 1681: sc->sc_scan_max = 13;
! 1682: sc->sc_scan_cur = 3;
! 1683: break;
! 1684: case AWI_REG_DOMAIN_ES:
! 1685: sc->sc_scan_min = 10;
! 1686: sc->sc_scan_max = 11;
! 1687: sc->sc_scan_cur = 10;
! 1688: break;
! 1689: case AWI_REG_DOMAIN_FR:
! 1690: sc->sc_scan_min = 10;
! 1691: sc->sc_scan_max = 13;
! 1692: sc->sc_scan_cur = 10;
! 1693: break;
! 1694: case AWI_REG_DOMAIN_JP:
! 1695: sc->sc_scan_min = 14;
! 1696: sc->sc_scan_max = 14;
! 1697: sc->sc_scan_cur = 14;
! 1698: break;
! 1699: default:
! 1700: return EINVAL;
! 1701: }
! 1702: }
! 1703: sc->sc_ownch = sc->sc_scan_cur;
! 1704: return 0;
! 1705: }
! 1706:
! 1707: static int
! 1708: awi_start_scan(sc)
! 1709: struct awi_softc *sc;
! 1710: {
! 1711: int error = 0;
! 1712: struct awi_bss *bp;
! 1713:
! 1714: while ((bp = TAILQ_FIRST(&sc->sc_scan)) != NULL) {
! 1715: TAILQ_REMOVE(&sc->sc_scan, bp, list);
! 1716: free(bp, M_DEVBUF);
! 1717: }
! 1718: if (!sc->sc_mib_local.Network_Mode && sc->sc_no_bssid) {
! 1719: memset(&sc->sc_bss, 0, sizeof(sc->sc_bss));
! 1720: sc->sc_bss.essid[0] = IEEE80211_ELEMID_SSID;
! 1721: if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
! 1722: sc->sc_bss.chanset = sc->sc_ownch % 3 + 1;
! 1723: sc->sc_bss.pattern = sc->sc_ownch;
! 1724: sc->sc_bss.index = 1;
! 1725: sc->sc_bss.dwell_time = 200; /*XXX*/
! 1726: } else
! 1727: sc->sc_bss.chanset = sc->sc_ownch;
! 1728: sc->sc_status = AWI_ST_SETSS;
! 1729: error = awi_set_ss(sc);
! 1730: } else {
! 1731: if (sc->sc_mib_local.Network_Mode)
! 1732: awi_drvstate(sc, AWI_DRV_INFSC);
! 1733: else
! 1734: awi_drvstate(sc, AWI_DRV_ADHSC);
! 1735: sc->sc_start_bss = 0;
! 1736: sc->sc_active_scan = 1;
! 1737: sc->sc_mgt_timer = AWI_ASCAN_WAIT / 1000;
! 1738: sc->sc_ifp->if_timer = 1;
! 1739: sc->sc_status = AWI_ST_SCAN;
! 1740: error = awi_cmd_scan(sc);
! 1741: }
! 1742: return error;
! 1743: }
! 1744:
! 1745: static int
! 1746: awi_next_scan(sc)
! 1747: struct awi_softc *sc;
! 1748: {
! 1749: int error;
! 1750:
! 1751: for (;;) {
! 1752: /*
! 1753: * The pattern parameter for FH phy should be incremented
! 1754: * by 3. But BayStack 650 Access Points apparently always
! 1755: * assign hop pattern set parameter to 1 for any pattern.
! 1756: * So we try all combinations of pattern/set parameters.
! 1757: * Since this causes no error, it may be a bug of
! 1758: * PCnetMobile firmware.
! 1759: */
! 1760: sc->sc_scan_cur++;
! 1761: if (sc->sc_scan_cur > sc->sc_scan_max) {
! 1762: sc->sc_scan_cur = sc->sc_scan_min;
! 1763: if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
! 1764: sc->sc_scan_set = sc->sc_scan_set % 3 + 1;
! 1765: }
! 1766: error = awi_cmd_scan(sc);
! 1767: if (error != EINVAL)
! 1768: break;
! 1769: }
! 1770: return error;
! 1771: }
! 1772:
! 1773: static void
! 1774: awi_stop_scan(sc)
! 1775: struct awi_softc *sc;
! 1776: {
! 1777: struct ifnet *ifp = sc->sc_ifp;
! 1778: struct awi_bss *bp, *sbp;
! 1779: int fail;
! 1780:
! 1781: bp = TAILQ_FIRST(&sc->sc_scan);
! 1782: if (bp == NULL) {
! 1783: notfound:
! 1784: if (sc->sc_active_scan) {
! 1785: if (ifp->if_flags & IFF_DEBUG)
! 1786: printf("%s: entering passive scan mode\n",
! 1787: sc->sc_dev.dv_xname);
! 1788: sc->sc_active_scan = 0;
! 1789: }
! 1790: sc->sc_mgt_timer = AWI_PSCAN_WAIT / 1000;
! 1791: ifp->if_timer = 1;
! 1792: (void)awi_next_scan(sc);
! 1793: return;
! 1794: }
! 1795: sbp = NULL;
! 1796: if (ifp->if_flags & IFF_DEBUG)
! 1797: printf("%s:\tmacaddr ch/pat sig flag wep essid\n",
! 1798: sc->sc_dev.dv_xname);
! 1799: for (; bp != NULL; bp = TAILQ_NEXT(bp, list)) {
! 1800: if (bp->fails) {
! 1801: /*
! 1802: * The configuration of the access points may change
! 1803: * during my scan. So we retries to associate with
! 1804: * it unless there are any suitable AP.
! 1805: */
! 1806: if (bp->fails++ < 3)
! 1807: continue;
! 1808: bp->fails = 0;
! 1809: }
! 1810: fail = 0;
! 1811: /*
! 1812: * Since the firmware apparently scans not only the specified
! 1813: * channel of SCAN command but all available channel within
! 1814: * the region, we should filter out unnecessary responses here.
! 1815: */
! 1816: if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
! 1817: if (bp->pattern < sc->sc_scan_min ||
! 1818: bp->pattern > sc->sc_scan_max)
! 1819: fail |= 0x01;
! 1820: } else {
! 1821: if (bp->chanset < sc->sc_scan_min ||
! 1822: bp->chanset > sc->sc_scan_max)
! 1823: fail |= 0x01;
! 1824: }
! 1825: if (sc->sc_mib_local.Network_Mode) {
! 1826: if (!(bp->capinfo & IEEE80211_CAPINFO_ESS) ||
! 1827: (bp->capinfo & IEEE80211_CAPINFO_IBSS))
! 1828: fail |= 0x02;
! 1829: } else {
! 1830: if ((bp->capinfo & IEEE80211_CAPINFO_ESS) ||
! 1831: !(bp->capinfo & IEEE80211_CAPINFO_IBSS))
! 1832: fail |= 0x02;
! 1833: }
! 1834: if (sc->sc_wep_algo == NULL) {
! 1835: if (bp->capinfo & IEEE80211_CAPINFO_PRIVACY)
! 1836: fail |= 0x04;
! 1837: } else {
! 1838: if (!(bp->capinfo & IEEE80211_CAPINFO_PRIVACY))
! 1839: fail |= 0x04;
! 1840: }
! 1841: if (sc->sc_mib_mac.aDesired_ESS_ID[1] != 0 &&
! 1842: memcmp(&sc->sc_mib_mac.aDesired_ESS_ID, bp->essid,
! 1843: sizeof(bp->essid)) != 0)
! 1844: fail |= 0x08;
! 1845: if (ifp->if_flags & IFF_DEBUG) {
! 1846: printf(" %c %s", fail ? '-' : '+',
! 1847: ether_sprintf(bp->esrc));
! 1848: if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
! 1849: printf(" %2d/%d%c", bp->pattern, bp->chanset,
! 1850: fail & 0x01 ? '!' : ' ');
! 1851: else
! 1852: printf(" %4d%c", bp->chanset,
! 1853: fail & 0x01 ? '!' : ' ');
! 1854: printf(" %+4d", bp->rssi);
! 1855: printf(" %4s%c",
! 1856: (bp->capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
! 1857: (bp->capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
! 1858: "????",
! 1859: fail & 0x02 ? '!' : ' ');
! 1860: printf(" %3s%c ",
! 1861: (bp->capinfo & IEEE80211_CAPINFO_PRIVACY) ? "wep" :
! 1862: "no",
! 1863: fail & 0x04 ? '!' : ' ');
! 1864: awi_print_essid(bp->essid);
! 1865: printf("%s\n", fail & 0x08 ? "!" : "");
! 1866: }
! 1867: if (!fail) {
! 1868: if (sbp == NULL || bp->rssi > sbp->rssi)
! 1869: sbp = bp;
! 1870: }
! 1871: }
! 1872: if (sbp == NULL)
! 1873: goto notfound;
! 1874: sc->sc_bss = *sbp;
! 1875: (void)awi_set_ss(sc);
! 1876: }
! 1877:
! 1878: static void
! 1879: awi_recv_beacon(sc, m0, rxts, rssi)
! 1880: struct awi_softc *sc;
! 1881: struct mbuf *m0;
! 1882: u_int32_t rxts;
! 1883: u_int8_t rssi;
! 1884: {
! 1885: struct ieee80211_frame *wh;
! 1886: struct awi_bss *bp;
! 1887: u_int8_t *frame, *eframe;
! 1888: u_int8_t *tstamp, *bintval, *capinfo, *ssid, *rates, *parms;
! 1889:
! 1890: if (sc->sc_status != AWI_ST_SCAN)
! 1891: return;
! 1892: wh = mtod(m0, struct ieee80211_frame *);
! 1893:
! 1894: frame = (u_int8_t *)&wh[1];
! 1895: eframe = mtod(m0, u_int8_t *) + m0->m_len;
! 1896: /*
! 1897: * XXX:
! 1898: * timestamp [8]
! 1899: * beacon interval [2]
! 1900: * capability information [2]
! 1901: * ssid [tlv]
! 1902: * supported rates [tlv]
! 1903: * parameter set [tlv]
! 1904: * ...
! 1905: */
! 1906: if (frame + 12 > eframe) {
! 1907: #ifdef AWI_DEBUG
! 1908: if (awi_verbose)
! 1909: printf("awi_recv_beacon: frame too short \n");
! 1910: #endif
! 1911: return;
! 1912: }
! 1913: tstamp = frame;
! 1914: frame += 8;
! 1915: bintval = frame;
! 1916: frame += 2;
! 1917: capinfo = frame;
! 1918: frame += 2;
! 1919:
! 1920: ssid = rates = parms = NULL;
! 1921: while (frame < eframe) {
! 1922: switch (*frame) {
! 1923: case IEEE80211_ELEMID_SSID:
! 1924: ssid = frame;
! 1925: break;
! 1926: case IEEE80211_ELEMID_RATES:
! 1927: rates = frame;
! 1928: break;
! 1929: case IEEE80211_ELEMID_FHPARMS:
! 1930: case IEEE80211_ELEMID_DSPARMS:
! 1931: parms = frame;
! 1932: break;
! 1933: }
! 1934: frame += frame[1] + 2;
! 1935: }
! 1936: if (ssid == NULL || rates == NULL || parms == NULL) {
! 1937: #ifdef AWI_DEBUG
! 1938: if (awi_verbose)
! 1939: printf("awi_recv_beacon: ssid=%p, rates=%p, parms=%p\n",
! 1940: ssid, rates, parms);
! 1941: #endif
! 1942: return;
! 1943: }
! 1944: if (ssid[1] > IEEE80211_NWID_LEN) {
! 1945: #ifdef AWI_DEBUG
! 1946: if (awi_verbose)
! 1947: printf("awi_recv_beacon: bad ssid len: %d from %s\n",
! 1948: ssid[1], ether_sprintf(wh->i_addr2));
! 1949: #endif
! 1950: return;
! 1951: }
! 1952:
! 1953: for (bp = TAILQ_FIRST(&sc->sc_scan); bp != NULL;
! 1954: bp = TAILQ_NEXT(bp, list)) {
! 1955: if (memcmp(bp->esrc, wh->i_addr2, ETHER_ADDR_LEN) == 0 &&
! 1956: memcmp(bp->bssid, wh->i_addr3, ETHER_ADDR_LEN) == 0)
! 1957: break;
! 1958: }
! 1959: if (bp == NULL) {
! 1960: bp = malloc(sizeof(struct awi_bss), M_DEVBUF, M_NOWAIT);
! 1961: if (bp == NULL)
! 1962: return;
! 1963: TAILQ_INSERT_TAIL(&sc->sc_scan, bp, list);
! 1964: memcpy(bp->esrc, wh->i_addr2, ETHER_ADDR_LEN);
! 1965: memcpy(bp->bssid, wh->i_addr3, ETHER_ADDR_LEN);
! 1966: memset(bp->essid, 0, sizeof(bp->essid));
! 1967: memcpy(bp->essid, ssid, 2 + ssid[1]);
! 1968: }
! 1969: bp->rssi = rssi;
! 1970: bp->rxtime = rxts;
! 1971: memcpy(bp->timestamp, tstamp, sizeof(bp->timestamp));
! 1972: bp->interval = LE_READ_2(bintval);
! 1973: bp->capinfo = LE_READ_2(capinfo);
! 1974: if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
! 1975: bp->chanset = parms[4];
! 1976: bp->pattern = parms[5];
! 1977: bp->index = parms[6];
! 1978: bp->dwell_time = LE_READ_2(parms + 2);
! 1979: } else {
! 1980: bp->chanset = parms[2];
! 1981: bp->pattern = 0;
! 1982: bp->index = 0;
! 1983: bp->dwell_time = 0;
! 1984: }
! 1985: if (sc->sc_mgt_timer == 0)
! 1986: awi_stop_scan(sc);
! 1987: }
! 1988:
! 1989: static int
! 1990: awi_set_ss(sc)
! 1991: struct awi_softc *sc;
! 1992: {
! 1993: struct ifnet *ifp = sc->sc_ifp;
! 1994: struct awi_bss *bp;
! 1995: int error;
! 1996:
! 1997: sc->sc_status = AWI_ST_SETSS;
! 1998: bp = &sc->sc_bss;
! 1999: if (ifp->if_flags & IFF_DEBUG) {
! 2000: printf("%s: ch %d pat %d id %d dw %d iv %d bss %s ssid ",
! 2001: sc->sc_dev.dv_xname, bp->chanset,
! 2002: bp->pattern, bp->index, bp->dwell_time, bp->interval,
! 2003: ether_sprintf(bp->bssid));
! 2004: awi_print_essid(bp->essid);
! 2005: printf("\n");
! 2006: }
! 2007: memcpy(&sc->sc_mib_mgt.aCurrent_BSS_ID, bp->bssid, ETHER_ADDR_LEN);
! 2008: memcpy(&sc->sc_mib_mgt.aCurrent_ESS_ID, bp->essid,
! 2009: AWI_ESS_ID_SIZE);
! 2010: LE_WRITE_2(&sc->sc_mib_mgt.aBeacon_Period, bp->interval);
! 2011: error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT);
! 2012: return error;
! 2013: }
! 2014:
! 2015: static void
! 2016: awi_try_sync(sc)
! 2017: struct awi_softc *sc;
! 2018: {
! 2019: struct awi_bss *bp;
! 2020:
! 2021: sc->sc_status = AWI_ST_SYNC;
! 2022: bp = &sc->sc_bss;
! 2023:
! 2024: if (sc->sc_cmd_inprog) {
! 2025: if (awi_cmd_wait(sc))
! 2026: return;
! 2027: }
! 2028: sc->sc_cmd_inprog = AWI_CMD_SYNC;
! 2029: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_SET, bp->chanset);
! 2030: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_PATTERN, bp->pattern);
! 2031: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_IDX, bp->index);
! 2032: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_STARTBSS,
! 2033: sc->sc_start_bss ? 1 : 0);
! 2034: awi_write_2(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_DWELL, bp->dwell_time);
! 2035: awi_write_2(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_MBZ, 0);
! 2036: awi_write_bytes(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_TIMESTAMP,
! 2037: bp->timestamp, 8);
! 2038: awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_REFTIME, bp->rxtime);
! 2039: (void)awi_cmd(sc, AWI_CMD_SYNC);
! 2040: }
! 2041:
! 2042: static void
! 2043: awi_sync_done(sc)
! 2044: struct awi_softc *sc;
! 2045: {
! 2046: struct ifnet *ifp = sc->sc_ifp;
! 2047:
! 2048: if (sc->sc_mib_local.Network_Mode) {
! 2049: awi_drvstate(sc, AWI_DRV_INFSY);
! 2050: awi_send_auth(sc, 1);
! 2051: } else {
! 2052: if (ifp->if_flags & IFF_DEBUG) {
! 2053: printf("%s: synced with", sc->sc_dev.dv_xname);
! 2054: if (sc->sc_no_bssid)
! 2055: printf(" no-bssid");
! 2056: else {
! 2057: printf(" %s ssid ",
! 2058: ether_sprintf(sc->sc_bss.bssid));
! 2059: awi_print_essid(sc->sc_bss.essid);
! 2060: }
! 2061: if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
! 2062: printf(" at chanset %d pattern %d\n",
! 2063: sc->sc_bss.chanset, sc->sc_bss.pattern);
! 2064: else
! 2065: printf(" at channel %d\n", sc->sc_bss.chanset);
! 2066: }
! 2067: awi_drvstate(sc, AWI_DRV_ADHSY);
! 2068: sc->sc_status = AWI_ST_RUNNING;
! 2069: ifp->if_flags |= IFF_RUNNING;
! 2070: awi_start(ifp);
! 2071: }
! 2072: }
! 2073:
! 2074: static void
! 2075: awi_send_deauth(sc)
! 2076: struct awi_softc *sc;
! 2077: {
! 2078: struct ifnet *ifp = sc->sc_ifp;
! 2079: struct mbuf *m;
! 2080: struct ieee80211_frame *wh;
! 2081: u_int8_t *deauth;
! 2082:
! 2083: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 2084: if (m == NULL)
! 2085: return;
! 2086: if (ifp->if_flags & IFF_DEBUG)
! 2087: printf("%s: sending deauth to %s\n", sc->sc_dev.dv_xname,
! 2088: ether_sprintf(sc->sc_bss.bssid));
! 2089:
! 2090: wh = mtod(m, struct ieee80211_frame *);
! 2091: wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
! 2092: IEEE80211_FC0_SUBTYPE_AUTH;
! 2093: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
! 2094: LE_WRITE_2(wh->i_dur, 0);
! 2095: LE_WRITE_2(wh->i_seq, 0);
! 2096: memcpy(wh->i_addr1, sc->sc_bss.bssid, ETHER_ADDR_LEN);
! 2097: memcpy(wh->i_addr2, sc->sc_mib_addr.aMAC_Address, ETHER_ADDR_LEN);
! 2098: memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN);
! 2099:
! 2100: deauth = (u_int8_t *)&wh[1];
! 2101: LE_WRITE_2(deauth, IEEE80211_REASON_AUTH_LEAVE);
! 2102: deauth += 2;
! 2103:
! 2104: m->m_pkthdr.len = m->m_len = deauth - mtod(m, u_int8_t *);
! 2105: IF_ENQUEUE(&sc->sc_mgtq, m);
! 2106: awi_start(ifp);
! 2107: awi_drvstate(sc, AWI_DRV_INFTOSS);
! 2108: }
! 2109:
! 2110: static void
! 2111: awi_send_auth(sc, seq)
! 2112: struct awi_softc *sc;
! 2113: int seq;
! 2114: {
! 2115: struct ifnet *ifp = sc->sc_ifp;
! 2116: struct mbuf *m;
! 2117: struct ieee80211_frame *wh;
! 2118: u_int8_t *auth;
! 2119:
! 2120: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 2121: if (m == NULL)
! 2122: return;
! 2123: sc->sc_status = AWI_ST_AUTH;
! 2124: if (ifp->if_flags & IFF_DEBUG)
! 2125: printf("%s: sending auth to %s\n", sc->sc_dev.dv_xname,
! 2126: ether_sprintf(sc->sc_bss.bssid));
! 2127:
! 2128: wh = mtod(m, struct ieee80211_frame *);
! 2129: wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
! 2130: IEEE80211_FC0_SUBTYPE_AUTH;
! 2131: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
! 2132: LE_WRITE_2(wh->i_dur, 0);
! 2133: LE_WRITE_2(wh->i_seq, 0);
! 2134: memcpy(wh->i_addr1, sc->sc_bss.esrc, ETHER_ADDR_LEN);
! 2135: memcpy(wh->i_addr2, sc->sc_mib_addr.aMAC_Address, ETHER_ADDR_LEN);
! 2136: memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN);
! 2137:
! 2138: auth = (u_int8_t *)&wh[1];
! 2139: /* algorithm number */
! 2140: LE_WRITE_2(auth, IEEE80211_AUTH_ALG_OPEN);
! 2141: auth += 2;
! 2142: /* sequence number */
! 2143: LE_WRITE_2(auth, seq);
! 2144: auth += 2;
! 2145: /* status */
! 2146: LE_WRITE_2(auth, 0);
! 2147: auth += 2;
! 2148:
! 2149: m->m_pkthdr.len = m->m_len = auth - mtod(m, u_int8_t *);
! 2150: IF_ENQUEUE(&sc->sc_mgtq, m);
! 2151: awi_start(ifp);
! 2152:
! 2153: sc->sc_mgt_timer = AWI_TRANS_TIMEOUT / 1000;
! 2154: ifp->if_timer = 1;
! 2155: }
! 2156:
! 2157: static void
! 2158: awi_recv_auth(sc, m0)
! 2159: struct awi_softc *sc;
! 2160: struct mbuf *m0;
! 2161: {
! 2162: struct ieee80211_frame *wh;
! 2163: u_int8_t *auth, *eframe;
! 2164: struct awi_bss *bp;
! 2165: u_int16_t status;
! 2166:
! 2167: wh = mtod(m0, struct ieee80211_frame *);
! 2168: auth = (u_int8_t *)&wh[1];
! 2169: eframe = mtod(m0, u_int8_t *) + m0->m_len;
! 2170: if (sc->sc_ifp->if_flags & IFF_DEBUG)
! 2171: printf("%s: receive auth from %s\n", sc->sc_dev.dv_xname,
! 2172: ether_sprintf(wh->i_addr2));
! 2173:
! 2174: /* algorithm number */
! 2175: if (LE_READ_2(auth) != IEEE80211_AUTH_ALG_OPEN)
! 2176: return;
! 2177: auth += 2;
! 2178: if (!sc->sc_mib_local.Network_Mode) {
! 2179: if (sc->sc_status != AWI_ST_RUNNING)
! 2180: return;
! 2181: if (LE_READ_2(auth) == 1)
! 2182: awi_send_auth(sc, 2);
! 2183: return;
! 2184: }
! 2185: if (sc->sc_status != AWI_ST_AUTH)
! 2186: return;
! 2187: /* sequence number */
! 2188: if (LE_READ_2(auth) != 2)
! 2189: return;
! 2190: auth += 2;
! 2191: /* status */
! 2192: status = LE_READ_2(auth);
! 2193: if (status != 0) {
! 2194: printf("%s: authentication failed (reason %d)\n",
! 2195: sc->sc_dev.dv_xname, status);
! 2196: for (bp = TAILQ_FIRST(&sc->sc_scan); bp != NULL;
! 2197: bp = TAILQ_NEXT(bp, list)) {
! 2198: if (memcmp(bp->esrc, sc->sc_bss.esrc, ETHER_ADDR_LEN)
! 2199: == 0) {
! 2200: bp->fails++;
! 2201: break;
! 2202: }
! 2203: }
! 2204: return;
! 2205: }
! 2206: sc->sc_mgt_timer = 0;
! 2207: awi_drvstate(sc, AWI_DRV_INFAUTH);
! 2208: awi_send_asreq(sc, 0);
! 2209: }
! 2210:
! 2211: static void
! 2212: awi_send_asreq(sc, reassoc)
! 2213: struct awi_softc *sc;
! 2214: int reassoc;
! 2215: {
! 2216: struct ifnet *ifp = sc->sc_ifp;
! 2217: struct mbuf *m;
! 2218: struct ieee80211_frame *wh;
! 2219: u_int16_t lintval;
! 2220: u_int8_t *asreq;
! 2221:
! 2222: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 2223: if (m == NULL)
! 2224: return;
! 2225: sc->sc_status = AWI_ST_ASSOC;
! 2226: if (ifp->if_flags & IFF_DEBUG)
! 2227: printf("%s: sending %sassoc req to %s\n", sc->sc_dev.dv_xname,
! 2228: reassoc ? "re" : "",
! 2229: ether_sprintf(sc->sc_bss.bssid));
! 2230:
! 2231: wh = mtod(m, struct ieee80211_frame *);
! 2232: wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT;
! 2233: if (reassoc)
! 2234: wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_REASSOC_REQ;
! 2235: else
! 2236: wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_ASSOC_REQ;
! 2237: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
! 2238: LE_WRITE_2(wh->i_dur, 0);
! 2239: LE_WRITE_2(wh->i_seq, 0);
! 2240: memcpy(wh->i_addr1, sc->sc_bss.esrc, ETHER_ADDR_LEN);
! 2241: memcpy(wh->i_addr2, sc->sc_mib_addr.aMAC_Address, ETHER_ADDR_LEN);
! 2242: memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN);
! 2243:
! 2244: asreq = (u_int8_t *)&wh[1];
! 2245:
! 2246: /* capability info */
! 2247: if (sc->sc_wep_algo == NULL)
! 2248: LE_WRITE_2(asreq, IEEE80211_CAPINFO_CF_POLLABLE);
! 2249: else
! 2250: LE_WRITE_2(asreq,
! 2251: IEEE80211_CAPINFO_CF_POLLABLE | IEEE80211_CAPINFO_PRIVACY);
! 2252: asreq += 2;
! 2253: /* listen interval */
! 2254: lintval = LE_READ_2(&sc->sc_mib_mgt.aListen_Interval);
! 2255: LE_WRITE_2(asreq, lintval);
! 2256: asreq += 2;
! 2257: if (reassoc) {
! 2258: /* current AP address */
! 2259: memcpy(asreq, sc->sc_bss.bssid, ETHER_ADDR_LEN);
! 2260: asreq += ETHER_ADDR_LEN;
! 2261: }
! 2262: /* ssid */
! 2263: memcpy(asreq, sc->sc_bss.essid, 2 + sc->sc_bss.essid[1]);
! 2264: asreq += 2 + asreq[1];
! 2265: /* supported rates */
! 2266: memcpy(asreq, &sc->sc_mib_phy.aSuprt_Data_Rates, 4);
! 2267: asreq += 2 + asreq[1];
! 2268:
! 2269: m->m_pkthdr.len = m->m_len = asreq - mtod(m, u_int8_t *);
! 2270: IF_ENQUEUE(&sc->sc_mgtq, m);
! 2271: awi_start(ifp);
! 2272:
! 2273: sc->sc_mgt_timer = AWI_TRANS_TIMEOUT / 1000;
! 2274: ifp->if_timer = 1;
! 2275: }
! 2276:
! 2277: static void
! 2278: awi_recv_asresp(sc, m0)
! 2279: struct awi_softc *sc;
! 2280: struct mbuf *m0;
! 2281: {
! 2282: struct ieee80211_frame *wh;
! 2283: u_int8_t *asresp, *eframe;
! 2284: u_int16_t status;
! 2285: u_int8_t rate, *phy_rates;
! 2286: struct awi_bss *bp;
! 2287: int i, j;
! 2288:
! 2289: wh = mtod(m0, struct ieee80211_frame *);
! 2290: asresp = (u_int8_t *)&wh[1];
! 2291: eframe = mtod(m0, u_int8_t *) + m0->m_len;
! 2292: if (sc->sc_ifp->if_flags & IFF_DEBUG)
! 2293: printf("%s: receive assoc resp from %s\n", sc->sc_dev.dv_xname,
! 2294: ether_sprintf(wh->i_addr2));
! 2295:
! 2296: if (!sc->sc_mib_local.Network_Mode)
! 2297: return;
! 2298:
! 2299: if (sc->sc_status != AWI_ST_ASSOC)
! 2300: return;
! 2301: /* capability info */
! 2302: asresp += 2;
! 2303: /* status */
! 2304: status = LE_READ_2(asresp);
! 2305: if (status != 0) {
! 2306: printf("%s: association failed (reason %d)\n",
! 2307: sc->sc_dev.dv_xname, status);
! 2308: for (bp = TAILQ_FIRST(&sc->sc_scan); bp != NULL;
! 2309: bp = TAILQ_NEXT(bp, list)) {
! 2310: if (memcmp(bp->esrc, sc->sc_bss.esrc, ETHER_ADDR_LEN)
! 2311: == 0) {
! 2312: bp->fails++;
! 2313: break;
! 2314: }
! 2315: }
! 2316: return;
! 2317: }
! 2318: asresp += 2;
! 2319: /* association id */
! 2320: asresp += 2;
! 2321: /* supported rates */
! 2322: rate = AWI_RATE_1MBIT;
! 2323: for (i = 0; i < asresp[1]; i++) {
! 2324: if (AWI_80211_RATE(asresp[2 + i]) <= rate)
! 2325: continue;
! 2326: phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
! 2327: for (j = 0; j < phy_rates[1]; j++) {
! 2328: if (AWI_80211_RATE(asresp[2 + i]) ==
! 2329: AWI_80211_RATE(phy_rates[2 + j]))
! 2330: rate = AWI_80211_RATE(asresp[2 + i]);
! 2331: }
! 2332: }
! 2333: if (sc->sc_ifp->if_flags & IFF_DEBUG) {
! 2334: printf("%s: associated with %s ssid ",
! 2335: sc->sc_dev.dv_xname, ether_sprintf(sc->sc_bss.bssid));
! 2336: awi_print_essid(sc->sc_bss.essid);
! 2337: if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
! 2338: printf(" chanset %d pattern %d\n",
! 2339: sc->sc_bss.chanset, sc->sc_bss.pattern);
! 2340: else
! 2341: printf(" channel %d\n", sc->sc_bss.chanset);
! 2342: }
! 2343: sc->sc_tx_rate = rate;
! 2344: sc->sc_mgt_timer = 0;
! 2345: sc->sc_rx_timer = 10;
! 2346: sc->sc_ifp->if_timer = 1;
! 2347: sc->sc_status = AWI_ST_RUNNING;
! 2348: sc->sc_ifp->if_flags |= IFF_RUNNING;
! 2349: awi_drvstate(sc, AWI_DRV_INFASSOC);
! 2350: awi_start(sc->sc_ifp);
! 2351: }
! 2352:
! 2353: static int
! 2354: awi_mib(sc, cmd, mib)
! 2355: struct awi_softc *sc;
! 2356: u_int8_t cmd;
! 2357: u_int8_t mib;
! 2358: {
! 2359: int error;
! 2360: u_int8_t size, *ptr;
! 2361:
! 2362: switch (mib) {
! 2363: case AWI_MIB_LOCAL:
! 2364: ptr = (u_int8_t *)&sc->sc_mib_local;
! 2365: size = sizeof(sc->sc_mib_local);
! 2366: break;
! 2367: case AWI_MIB_ADDR:
! 2368: ptr = (u_int8_t *)&sc->sc_mib_addr;
! 2369: size = sizeof(sc->sc_mib_addr);
! 2370: break;
! 2371: case AWI_MIB_MAC:
! 2372: ptr = (u_int8_t *)&sc->sc_mib_mac;
! 2373: size = sizeof(sc->sc_mib_mac);
! 2374: break;
! 2375: case AWI_MIB_STAT:
! 2376: ptr = (u_int8_t *)&sc->sc_mib_stat;
! 2377: size = sizeof(sc->sc_mib_stat);
! 2378: break;
! 2379: case AWI_MIB_MGT:
! 2380: ptr = (u_int8_t *)&sc->sc_mib_mgt;
! 2381: size = sizeof(sc->sc_mib_mgt);
! 2382: break;
! 2383: case AWI_MIB_PHY:
! 2384: ptr = (u_int8_t *)&sc->sc_mib_phy;
! 2385: size = sizeof(sc->sc_mib_phy);
! 2386: break;
! 2387: default:
! 2388: return EINVAL;
! 2389: }
! 2390: if (sc->sc_cmd_inprog) {
! 2391: error = awi_cmd_wait(sc);
! 2392: if (error) {
! 2393: if (error == EWOULDBLOCK)
! 2394: printf("awi_mib: cmd %d inprog",
! 2395: sc->sc_cmd_inprog);
! 2396: return error;
! 2397: }
! 2398: }
! 2399: sc->sc_cmd_inprog = cmd;
! 2400: if (cmd == AWI_CMD_SET_MIB)
! 2401: awi_write_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, ptr, size);
! 2402: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, mib);
! 2403: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, size);
! 2404: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, 0);
! 2405: error = awi_cmd(sc, cmd);
! 2406: if (error)
! 2407: return error;
! 2408: if (cmd == AWI_CMD_GET_MIB) {
! 2409: awi_read_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, ptr, size);
! 2410: #ifdef AWI_DEBUG
! 2411: if (awi_verbose) {
! 2412: int i;
! 2413:
! 2414: printf("awi_mib: #%d:", mib);
! 2415: for (i = 0; i < size; i++)
! 2416: printf(" %02x", ptr[i]);
! 2417: printf("\n");
! 2418: }
! 2419: #endif
! 2420: }
! 2421: return 0;
! 2422: }
! 2423:
! 2424: static int
! 2425: awi_cmd_scan(sc)
! 2426: struct awi_softc *sc;
! 2427: {
! 2428: int error;
! 2429: u_int8_t scan_mode;
! 2430:
! 2431: if (sc->sc_active_scan)
! 2432: scan_mode = AWI_SCAN_ACTIVE;
! 2433: else
! 2434: scan_mode = AWI_SCAN_PASSIVE;
! 2435: if (sc->sc_mib_mgt.aScan_Mode != scan_mode) {
! 2436: sc->sc_mib_mgt.aScan_Mode = scan_mode;
! 2437: error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT);
! 2438: return error;
! 2439: }
! 2440:
! 2441: if (sc->sc_cmd_inprog) {
! 2442: error = awi_cmd_wait(sc);
! 2443: if (error)
! 2444: return error;
! 2445: }
! 2446: sc->sc_cmd_inprog = AWI_CMD_SCAN;
! 2447: awi_write_2(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_DURATION,
! 2448: sc->sc_active_scan ? AWI_ASCAN_DURATION : AWI_PSCAN_DURATION);
! 2449: if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
! 2450: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SET,
! 2451: sc->sc_scan_set);
! 2452: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_PATTERN,
! 2453: sc->sc_scan_cur);
! 2454: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_IDX, 1);
! 2455: } else {
! 2456: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SET,
! 2457: sc->sc_scan_cur);
! 2458: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_PATTERN, 0);
! 2459: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_IDX, 0);
! 2460: }
! 2461: awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SUSP, 0);
! 2462: return awi_cmd(sc, AWI_CMD_SCAN);
! 2463: }
! 2464:
! 2465: static int
! 2466: awi_cmd(sc, cmd)
! 2467: struct awi_softc *sc;
! 2468: u_int8_t cmd;
! 2469: {
! 2470: u_int8_t status;
! 2471: int error = 0;
! 2472:
! 2473: sc->sc_cmd_inprog = cmd;
! 2474: awi_write_1(sc, AWI_CMD_STATUS, AWI_STAT_IDLE);
! 2475: awi_write_1(sc, AWI_CMD, cmd);
! 2476: if (sc->sc_status != AWI_ST_INIT)
! 2477: return 0;
! 2478: error = awi_cmd_wait(sc);
! 2479: if (error)
! 2480: return error;
! 2481: status = awi_read_1(sc, AWI_CMD_STATUS);
! 2482: awi_write_1(sc, AWI_CMD, 0);
! 2483: switch (status) {
! 2484: case AWI_STAT_OK:
! 2485: break;
! 2486: case AWI_STAT_BADPARM:
! 2487: return EINVAL;
! 2488: default:
! 2489: printf("%s: command %d failed %x\n",
! 2490: sc->sc_dev.dv_xname, cmd, status);
! 2491: return ENXIO;
! 2492: }
! 2493: return 0;
! 2494: }
! 2495:
! 2496: static void
! 2497: awi_cmd_done(sc)
! 2498: struct awi_softc *sc;
! 2499: {
! 2500: u_int8_t cmd, status;
! 2501:
! 2502: status = awi_read_1(sc, AWI_CMD_STATUS);
! 2503: if (status == AWI_STAT_IDLE)
! 2504: return; /* stray interrupt */
! 2505:
! 2506: cmd = sc->sc_cmd_inprog;
! 2507: sc->sc_cmd_inprog = 0;
! 2508: if (sc->sc_status == AWI_ST_INIT) {
! 2509: wakeup(sc);
! 2510: return;
! 2511: }
! 2512: awi_write_1(sc, AWI_CMD, 0);
! 2513:
! 2514: if (status != AWI_STAT_OK) {
! 2515: printf("%s: command %d failed %x\n",
! 2516: sc->sc_dev.dv_xname, cmd, status);
! 2517: return;
! 2518: }
! 2519: switch (sc->sc_status) {
! 2520: case AWI_ST_SCAN:
! 2521: if (cmd == AWI_CMD_SET_MIB)
! 2522: awi_cmd_scan(sc); /* retry */
! 2523: break;
! 2524: case AWI_ST_SETSS:
! 2525: awi_try_sync(sc);
! 2526: break;
! 2527: case AWI_ST_SYNC:
! 2528: awi_sync_done(sc);
! 2529: break;
! 2530: default:
! 2531: break;
! 2532: }
! 2533: }
! 2534:
! 2535: static int
! 2536: awi_next_txd(sc, len, framep, ntxdp)
! 2537: struct awi_softc *sc;
! 2538: int len;
! 2539: u_int32_t *framep, *ntxdp;
! 2540: {
! 2541: u_int32_t txd, ntxd, frame;
! 2542:
! 2543: txd = sc->sc_txnext;
! 2544: frame = txd + AWI_TXD_SIZE;
! 2545: if (frame + len > sc->sc_txend)
! 2546: frame = sc->sc_txbase;
! 2547: ntxd = frame + len;
! 2548: if (ntxd + AWI_TXD_SIZE > sc->sc_txend)
! 2549: ntxd = sc->sc_txbase;
! 2550: *framep = frame;
! 2551: *ntxdp = ntxd;
! 2552: /*
! 2553: * Determine if there are any room in ring buffer.
! 2554: * --- send wait, === new data, +++ conflict (ENOBUFS)
! 2555: * base........................end
! 2556: * done----txd=====ntxd OK
! 2557: * --txd=====done++++ntxd-- full
! 2558: * --txd=====ntxd done-- OK
! 2559: * ==ntxd done----txd=== OK
! 2560: * ==done++++ntxd----txd=== full
! 2561: * ++ntxd txd=====done++ full
! 2562: */
! 2563: if (txd < ntxd) {
! 2564: if (txd < sc->sc_txdone && ntxd + AWI_TXD_SIZE > sc->sc_txdone)
! 2565: return ENOBUFS;
! 2566: } else {
! 2567: if (txd < sc->sc_txdone || ntxd + AWI_TXD_SIZE > sc->sc_txdone)
! 2568: return ENOBUFS;
! 2569: }
! 2570: return 0;
! 2571: }
! 2572:
! 2573: static int
! 2574: awi_lock(sc)
! 2575: struct awi_softc *sc;
! 2576: {
! 2577: int error = 0;
! 2578:
! 2579: if (curproc == NULL) {
! 2580: /*
! 2581: * XXX
! 2582: * Though driver ioctl should be called with context,
! 2583: * KAME ipv6 stack calls ioctl in interrupt for now.
! 2584: * We simply abort the request if there are other
! 2585: * ioctl requests in progress.
! 2586: */
! 2587: if (sc->sc_busy) {
! 2588: return EWOULDBLOCK;
! 2589: if (sc->sc_invalid)
! 2590: return ENXIO;
! 2591: }
! 2592: sc->sc_busy = 1;
! 2593: sc->sc_cansleep = 0;
! 2594: return 0;
! 2595: }
! 2596: while (sc->sc_busy) {
! 2597: if (sc->sc_invalid)
! 2598: return ENXIO;
! 2599: sc->sc_sleep_cnt++;
! 2600: error = tsleep(sc, PWAIT | PCATCH, "awilck", 0);
! 2601: sc->sc_sleep_cnt--;
! 2602: if (error)
! 2603: return error;
! 2604: }
! 2605: sc->sc_busy = 1;
! 2606: sc->sc_cansleep = 1;
! 2607: return 0;
! 2608: }
! 2609:
! 2610: static void
! 2611: awi_unlock(sc)
! 2612: struct awi_softc *sc;
! 2613: {
! 2614: sc->sc_busy = 0;
! 2615: sc->sc_cansleep = 0;
! 2616: if (sc->sc_sleep_cnt)
! 2617: wakeup(sc);
! 2618: }
! 2619:
! 2620: static int
! 2621: awi_intr_lock(sc)
! 2622: struct awi_softc *sc;
! 2623: {
! 2624: u_int8_t status;
! 2625: int i, retry;
! 2626:
! 2627: status = 1;
! 2628: for (retry = 0; retry < 10; retry++) {
! 2629: for (i = 0; i < AWI_LOCKOUT_TIMEOUT*1000/5; i++) {
! 2630: status = awi_read_1(sc, AWI_LOCKOUT_HOST);
! 2631: if (status == 0)
! 2632: break;
! 2633: DELAY(5);
! 2634: }
! 2635: if (status != 0)
! 2636: break;
! 2637: awi_write_1(sc, AWI_LOCKOUT_MAC, 1);
! 2638: status = awi_read_1(sc, AWI_LOCKOUT_HOST);
! 2639: if (status == 0)
! 2640: break;
! 2641: awi_write_1(sc, AWI_LOCKOUT_MAC, 0);
! 2642: }
! 2643: if (status != 0) {
! 2644: printf("%s: failed to lock interrupt\n",
! 2645: sc->sc_dev.dv_xname);
! 2646: return ENXIO;
! 2647: }
! 2648: return 0;
! 2649: }
! 2650:
! 2651: static void
! 2652: awi_intr_unlock(sc)
! 2653: struct awi_softc *sc;
! 2654: {
! 2655:
! 2656: awi_write_1(sc, AWI_LOCKOUT_MAC, 0);
! 2657: }
! 2658:
! 2659: static int
! 2660: awi_cmd_wait(sc)
! 2661: struct awi_softc *sc;
! 2662: {
! 2663: int i, error = 0;
! 2664:
! 2665: i = 0;
! 2666: while (sc->sc_cmd_inprog) {
! 2667: if (sc->sc_invalid)
! 2668: return ENXIO;
! 2669: if (awi_read_1(sc, AWI_CMD) != sc->sc_cmd_inprog) {
! 2670: printf("%s: failed to access hardware\n",
! 2671: sc->sc_dev.dv_xname);
! 2672: sc->sc_invalid = 1;
! 2673: return ENXIO;
! 2674: }
! 2675: if (sc->sc_cansleep) {
! 2676: sc->sc_sleep_cnt++;
! 2677: error = tsleep(sc, PWAIT, "awicmd",
! 2678: AWI_CMD_TIMEOUT*hz/1000);
! 2679: sc->sc_sleep_cnt--;
! 2680: } else {
! 2681: if (awi_read_1(sc, AWI_CMD_STATUS) != AWI_STAT_IDLE) {
! 2682: awi_cmd_done(sc);
! 2683: break;
! 2684: }
! 2685: if (i++ >= AWI_CMD_TIMEOUT*1000/10)
! 2686: error = EWOULDBLOCK;
! 2687: else
! 2688: DELAY(10);
! 2689: }
! 2690: if (error)
! 2691: break;
! 2692: }
! 2693: return error;
! 2694: }
! 2695:
! 2696: static void
! 2697: awi_print_essid(essid)
! 2698: u_int8_t *essid;
! 2699: {
! 2700: int i, len;
! 2701: u_int8_t *p;
! 2702:
! 2703: len = essid[1];
! 2704: if (len > IEEE80211_NWID_LEN)
! 2705: len = IEEE80211_NWID_LEN; /*XXX*/
! 2706: /* determine printable or not */
! 2707: for (i = 0, p = essid + 2; i < len; i++, p++) {
! 2708: if (*p < ' ' || *p > 0x7e)
! 2709: break;
! 2710: }
! 2711: if (i == len) {
! 2712: printf("\"");
! 2713: for (i = 0, p = essid + 2; i < len; i++, p++)
! 2714: printf("%c", *p);
! 2715: printf("\"");
! 2716: } else {
! 2717: printf("0x");
! 2718: for (i = 0, p = essid + 2; i < len; i++, p++)
! 2719: printf("%02x", *p);
! 2720: }
! 2721: }
! 2722:
! 2723: #ifdef AWI_DEBUG
! 2724: static void
! 2725: awi_dump_pkt(sc, m, rssi)
! 2726: struct awi_softc *sc;
! 2727: struct mbuf *m;
! 2728: int rssi;
! 2729: {
! 2730: struct ieee80211_frame *wh;
! 2731: int i, l;
! 2732:
! 2733: wh = mtod(m, struct ieee80211_frame *);
! 2734:
! 2735: if (awi_dump_mask != 0 &&
! 2736: ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK)==IEEE80211_FC1_DIR_NODS) &&
! 2737: ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)==IEEE80211_FC0_TYPE_MGT)) {
! 2738: if ((AWI_DUMP_MASK(wh->i_fc[0]) & awi_dump_mask) != 0)
! 2739: return;
! 2740: }
! 2741: if (awi_dump_mask < 0 &&
! 2742: (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)==IEEE80211_FC0_TYPE_DATA)
! 2743: return;
! 2744:
! 2745: if (rssi < 0)
! 2746: printf("tx: ");
! 2747: else
! 2748: printf("rx: ");
! 2749: switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
! 2750: case IEEE80211_FC1_DIR_NODS:
! 2751: printf("NODS %s", ether_sprintf(wh->i_addr2));
! 2752: printf("->%s", ether_sprintf(wh->i_addr1));
! 2753: printf("(%s)", ether_sprintf(wh->i_addr3));
! 2754: break;
! 2755: case IEEE80211_FC1_DIR_TODS:
! 2756: printf("TODS %s", ether_sprintf(wh->i_addr2));
! 2757: printf("->%s", ether_sprintf(wh->i_addr3));
! 2758: printf("(%s)", ether_sprintf(wh->i_addr1));
! 2759: break;
! 2760: case IEEE80211_FC1_DIR_FROMDS:
! 2761: printf("FRDS %s", ether_sprintf(wh->i_addr3));
! 2762: printf("->%s", ether_sprintf(wh->i_addr1));
! 2763: printf("(%s)", ether_sprintf(wh->i_addr2));
! 2764: break;
! 2765: case IEEE80211_FC1_DIR_DSTODS:
! 2766: printf("DSDS %s", ether_sprintf((u_int8_t *)&wh[1]));
! 2767: printf("->%s", ether_sprintf(wh->i_addr3));
! 2768: printf("(%s", ether_sprintf(wh->i_addr2));
! 2769: printf("->%s)", ether_sprintf(wh->i_addr1));
! 2770: break;
! 2771: }
! 2772: switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
! 2773: case IEEE80211_FC0_TYPE_DATA:
! 2774: printf(" data");
! 2775: break;
! 2776: case IEEE80211_FC0_TYPE_MGT:
! 2777: switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
! 2778: case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
! 2779: printf(" probe_req");
! 2780: break;
! 2781: case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
! 2782: printf(" probe_resp");
! 2783: break;
! 2784: case IEEE80211_FC0_SUBTYPE_BEACON:
! 2785: printf(" beacon");
! 2786: break;
! 2787: case IEEE80211_FC0_SUBTYPE_AUTH:
! 2788: printf(" auth");
! 2789: break;
! 2790: case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
! 2791: printf(" assoc_req");
! 2792: break;
! 2793: case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
! 2794: printf(" assoc_resp");
! 2795: break;
! 2796: case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
! 2797: printf(" reassoc_req");
! 2798: break;
! 2799: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
! 2800: printf(" reassoc_resp");
! 2801: break;
! 2802: case IEEE80211_FC0_SUBTYPE_DEAUTH:
! 2803: printf(" deauth");
! 2804: break;
! 2805: case IEEE80211_FC0_SUBTYPE_DISASSOC:
! 2806: printf(" disassoc");
! 2807: break;
! 2808: default:
! 2809: printf(" mgt#%d",
! 2810: wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
! 2811: break;
! 2812: }
! 2813: break;
! 2814: default:
! 2815: printf(" type#%d",
! 2816: wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
! 2817: break;
! 2818: }
! 2819: if (wh->i_fc[1] & IEEE80211_FC1_WEP)
! 2820: printf(" WEP");
! 2821: if (rssi >= 0)
! 2822: printf(" +%d", rssi);
! 2823: printf("\n");
! 2824: if (awi_dump_len > 0) {
! 2825: l = m->m_len;
! 2826: if (l > awi_dump_len + sizeof(*wh))
! 2827: l = awi_dump_len + sizeof(*wh);
! 2828: i = sizeof(*wh);
! 2829: if (awi_dump_hdr)
! 2830: i = 0;
! 2831: for (; i < l; i++) {
! 2832: if ((i & 1) == 0)
! 2833: printf(" ");
! 2834: printf("%02x", mtod(m, u_int8_t *)[i]);
! 2835: }
! 2836: printf("\n");
! 2837: }
! 2838: }
! 2839: #endif
CVSweb