Annotation of sys/dev/ic/an.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: an.c,v 1.53 2007/01/03 18:16:43 claudio Exp $ */
! 2: /* $NetBSD: an.c,v 1.34 2005/06/20 02:49:18 atatat Exp $ */
! 3: /*
! 4: * Copyright (c) 1997, 1998, 1999
! 5: * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by Bill Paul.
! 18: * 4. Neither the name of the author nor the names of any co-contributors
! 19: * may be used to endorse or promote products derived from this software
! 20: * without specific prior written permission.
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
! 23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 25: * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
! 26: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 27: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 28: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 29: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 30: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 31: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
! 32: * THE POSSIBILITY OF SUCH DAMAGE.
! 33: *
! 34: * $FreeBSD: src/sys/dev/an/if_an.c,v 1.12 2000/11/13 23:04:12 wpaul Exp $
! 35: */
! 36: /*
! 37: * Copyright (c) 2004, 2005 David Young. All rights reserved.
! 38: * Copyright (c) 2004, 2005 OJC Technologies. All rights reserved.
! 39: * Copyright (c) 2004, 2005 Dayton Data Center Services, LLC. All
! 40: * rights reserved.
! 41: *
! 42: * Redistribution and use in source and binary forms, with or without
! 43: * modification, are permitted provided that the following conditions
! 44: * are met:
! 45: * 1. Redistributions of source code must retain the above copyright
! 46: * notice, this list of conditions and the following disclaimer.
! 47: * 2. Redistributions in binary form must reproduce the above copyright
! 48: * notice, this list of conditions and the following disclaimer in the
! 49: * documentation and/or other materials provided with the distribution.
! 50: * 3. Neither the name of the author nor the names of any co-contributors
! 51: * may be used to endorse or promote products derived from this software
! 52: * without specific prior written permission.
! 53: *
! 54: * THIS SOFTWARE IS PROVIDED BY David Young AND CONTRIBUTORS ``AS IS'' AND
! 55: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 56: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 57: * ARE DISCLAIMED. IN NO EVENT SHALL David Young AND CONTRIBUTORS
! 58: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 59: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 60: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 61: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 62: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 63: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
! 64: * THE POSSIBILITY OF SUCH DAMAGE.
! 65: */
! 66:
! 67: /*
! 68: * Aironet 4500/4800 802.11 PCMCIA/ISA/PCI driver for FreeBSD.
! 69: *
! 70: * Written by Bill Paul <wpaul@ctr.columbia.edu>
! 71: * Electrical Engineering Department
! 72: * Columbia University, New York City
! 73: */
! 74:
! 75: /*
! 76: * Ported to NetBSD from FreeBSD by Atsushi Onoe at the San Diego
! 77: * IETF meeting.
! 78: */
! 79:
! 80: #include <sys/cdefs.h>
! 81:
! 82: #include "bpfilter.h"
! 83:
! 84: #include <sys/param.h>
! 85: #include <sys/systm.h>
! 86: #include <sys/sockio.h>
! 87: #include <sys/mbuf.h>
! 88: #include <sys/kernel.h>
! 89: #include <sys/ucred.h>
! 90: #include <sys/socket.h>
! 91: #include <sys/timeout.h>
! 92: #include <sys/device.h>
! 93: #include <sys/proc.h>
! 94: #include <sys/endian.h>
! 95: #include <sys/tree.h>
! 96:
! 97: #include <machine/bus.h>
! 98:
! 99: #include <net/if.h>
! 100: #include <net/if_dl.h>
! 101: #include <net/if_llc.h>
! 102: #include <net/if_media.h>
! 103: #include <net/if_types.h>
! 104:
! 105: #ifdef INET
! 106: #include <netinet/in.h>
! 107: #include <netinet/in_systm.h>
! 108: #include <netinet/in_var.h>
! 109: #include <netinet/ip.h>
! 110: #include <netinet/if_ether.h>
! 111: #endif
! 112:
! 113: #include <net80211/ieee80211_radiotap.h>
! 114: #include <net80211/ieee80211_var.h>
! 115:
! 116: #if NBPFILTER > 0
! 117: #include <net/bpf.h>
! 118: #endif
! 119:
! 120: #include <dev/ic/anreg.h>
! 121: #include <dev/ic/anvar.h>
! 122:
! 123: struct cfdriver an_cd = {
! 124: NULL, "an", DV_IFNET
! 125: };
! 126:
! 127: int an_reset(struct an_softc *);
! 128: void an_wait(struct an_softc *);
! 129: int an_init(struct ifnet *);
! 130: void an_stop(struct ifnet *, int);
! 131: void an_start(struct ifnet *);
! 132: void an_watchdog(struct ifnet *);
! 133: int an_ioctl(struct ifnet *, u_long, caddr_t);
! 134: int an_media_change(struct ifnet *);
! 135: void an_media_status(struct ifnet *, struct ifmediareq *);
! 136:
! 137: int an_set_nwkey(struct an_softc *, struct ieee80211_nwkey *);
! 138: int an_set_nwkey_wep(struct an_softc *, struct ieee80211_nwkey *);
! 139: int an_get_nwkey(struct an_softc *, struct ieee80211_nwkey *);
! 140: int an_write_wepkey(struct an_softc *, int, struct an_wepkey *,
! 141: int);
! 142:
! 143: void an_rxeof(struct an_softc *);
! 144: void an_txeof(struct an_softc *, u_int16_t);
! 145: void an_linkstat_intr(struct an_softc *);
! 146:
! 147: int an_cmd(struct an_softc *, int, int);
! 148: int an_seek_bap(struct an_softc *, int, int);
! 149: int an_read_bap(struct an_softc *, int, int, void *, int, int);
! 150: int an_write_bap(struct an_softc *, int, int, void *, int);
! 151: int an_mwrite_bap(struct an_softc *, int, int, struct mbuf *, int);
! 152: int an_read_rid(struct an_softc *, int, void *, int *);
! 153: int an_write_rid(struct an_softc *, int, void *, int);
! 154:
! 155: int an_alloc_nicmem(struct an_softc *, int, int *);
! 156:
! 157: int an_newstate(struct ieee80211com *, enum ieee80211_state, int);
! 158:
! 159: #ifdef AN_DEBUG
! 160: int an_debug = 0;
! 161:
! 162: #define DPRINTF(X) if (an_debug) printf X
! 163: #define DPRINTF2(X) if (an_debug > 1) printf X
! 164: #else
! 165: #define DPRINTF(X)
! 166: #define DPRINTF2(X)
! 167: #endif
! 168:
! 169: #if BYTE_ORDER == BIG_ENDIAN
! 170: static __inline void
! 171: an_swap16(u_int16_t *p, int cnt)
! 172: {
! 173: for (; cnt--; p++)
! 174: *p = swap16(*p);
! 175: }
! 176: #define an_switch32(val) (val >> 16 | (val & 0xFFFF) << 16)
! 177: #else
! 178: #define an_swap16(p, cnt)
! 179: #define an_switch32(val) val
! 180: #endif
! 181:
! 182: int
! 183: an_attach(struct an_softc *sc)
! 184: {
! 185: struct ieee80211com *ic = &sc->sc_ic;
! 186: struct ifnet *ifp = &ic->ic_if;
! 187: int i;
! 188: struct an_rid_wepkey *akey;
! 189: int buflen, kid, rid;
! 190: int chan, chan_min, chan_max;
! 191:
! 192: sc->sc_invalid = 0;
! 193:
! 194: /* disable interrupts */
! 195: CSR_WRITE_2(sc, AN_INT_EN, 0);
! 196: CSR_WRITE_2(sc, AN_EVENT_ACK, 0xffff);
! 197:
! 198: // an_wait(sc);
! 199: if (an_reset(sc) != 0) {
! 200: sc->sc_invalid = 1;
! 201: return 1;
! 202: }
! 203:
! 204: /* Load factory config */
! 205: if (an_cmd(sc, AN_CMD_READCFG, 0) != 0) {
! 206: printf("%s: failed to load config data\n",
! 207: sc->sc_dev.dv_xname);
! 208: return (EIO);
! 209: }
! 210:
! 211: /* Read the current configuration */
! 212: buflen = sizeof(sc->sc_config);
! 213: if (an_read_rid(sc, AN_RID_GENCONFIG, &sc->sc_config, &buflen) != 0) {
! 214: printf("%s: read config failed\n", sc->sc_dev.dv_xname);
! 215: return(EIO);
! 216: }
! 217:
! 218: an_swap16((u_int16_t *)&sc->sc_config.an_macaddr, 3);
! 219:
! 220: /* Read the card capabilities */
! 221: buflen = sizeof(sc->sc_caps);
! 222: if (an_read_rid(sc, AN_RID_CAPABILITIES, &sc->sc_caps, &buflen) != 0) {
! 223: printf("%s: read caps failed\n", sc->sc_dev.dv_xname);
! 224: return(EIO);
! 225: }
! 226:
! 227: an_swap16((u_int16_t *)&sc->sc_caps.an_oemaddr, 3);
! 228: an_swap16((u_int16_t *)&sc->sc_caps.an_rates, 4);
! 229:
! 230: /* Read WEP settings from persistent memory */
! 231: akey = &sc->sc_buf.sc_wepkey;
! 232: buflen = sizeof(struct an_rid_wepkey);
! 233: rid = AN_RID_WEP_VOLATILE; /* first persistent key */
! 234: while (an_read_rid(sc, rid, akey, &buflen) == 0) {
! 235: an_swap16((u_int16_t *)&akey->an_mac_addr, 3);
! 236: an_swap16((u_int16_t *)&akey->an_key, 8);
! 237: kid = akey->an_key_index;
! 238: DPRINTF(("an_attach: wep rid=0x%x len=%d(%d) index=0x%04x "
! 239: "mac[0]=%02x keylen=%d\n",
! 240: rid, buflen, sizeof(*akey), kid,
! 241: akey->an_mac_addr[0], akey->an_key_len));
! 242: if (kid == 0xffff) {
! 243: sc->sc_tx_perskey = akey->an_mac_addr[0];
! 244: sc->sc_tx_key = -1;
! 245: break;
! 246: }
! 247: if (kid >= IEEE80211_WEP_NKID)
! 248: break;
! 249: sc->sc_perskeylen[kid] = akey->an_key_len;
! 250: sc->sc_wepkeys[kid].an_wep_keylen = -1;
! 251: rid = AN_RID_WEP_PERSISTENT; /* for next key */
! 252: buflen = sizeof(struct an_rid_wepkey);
! 253: }
! 254:
! 255: IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_caps.an_oemaddr);
! 256: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
! 257:
! 258: printf("%s: Firmware %x.%02x.%02x, Radio: ", ifp->if_xname,
! 259: sc->sc_caps.an_fwrev >> 8,
! 260: sc->sc_caps.an_fwrev & 0xff,
! 261: sc->sc_caps.an_fwsubrev);
! 262:
! 263: if (sc->sc_config.an_radiotype & AN_RADIOTYPE_80211_FH)
! 264: printf("802.11 FH");
! 265: else if (sc->sc_config.an_radiotype & AN_RADIOTYPE_80211_DS)
! 266: printf("802.11 DS");
! 267: else if (sc->sc_config.an_radiotype & AN_RADIOTYPE_LM2000_DS)
! 268: printf("LM2000 DS");
! 269: else
! 270: printf("unknown (%x)", sc->sc_config.an_radiotype);
! 271:
! 272: printf(", address %s\n", ether_sprintf(ic->ic_myaddr));
! 273:
! 274: ifp->if_softc = sc;
! 275: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 276: ifp->if_ioctl = an_ioctl;
! 277: ifp->if_start = an_start;
! 278: ifp->if_init = an_init;
! 279: ifp->if_watchdog = an_watchdog;
! 280: IFQ_SET_READY(&ifp->if_snd);
! 281:
! 282: ic->ic_phytype = IEEE80211_T_DS;
! 283: ic->ic_opmode = IEEE80211_M_STA;
! 284: ic->ic_caps = IEEE80211_C_WEP | IEEE80211_C_PMGT | IEEE80211_C_IBSS |
! 285: IEEE80211_C_MONITOR;
! 286: ic->ic_state = IEEE80211_S_INIT;
! 287: IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_caps.an_oemaddr);
! 288:
! 289: switch (sc->sc_caps.an_regdomain) {
! 290: default:
! 291: case AN_REGDOMAIN_USA:
! 292: case AN_REGDOMAIN_CANADA:
! 293: chan_min = 1; chan_max = 11; break;
! 294: case AN_REGDOMAIN_EUROPE:
! 295: case AN_REGDOMAIN_AUSTRALIA:
! 296: chan_min = 1; chan_max = 13; break;
! 297: case AN_REGDOMAIN_JAPAN:
! 298: chan_min = 14; chan_max = 14; break;
! 299: case AN_REGDOMAIN_SPAIN:
! 300: chan_min = 10; chan_max = 11; break;
! 301: case AN_REGDOMAIN_FRANCE:
! 302: chan_min = 10; chan_max = 13; break;
! 303: case AN_REGDOMAIN_JAPANWIDE:
! 304: chan_min = 1; chan_max = 14; break;
! 305: }
! 306:
! 307: for (chan = chan_min; chan <= chan_max; chan++) {
! 308: ic->ic_channels[chan].ic_freq =
! 309: ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ);
! 310: ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_B;
! 311: }
! 312: ic->ic_ibss_chan = &ic->ic_channels[chan_min];
! 313:
! 314: /* Find supported rate */
! 315: for (i = 0; i < sizeof(sc->sc_caps.an_rates); i++) {
! 316: if (sc->sc_caps.an_rates[i] == 0)
! 317: continue;
! 318: ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
! 319: ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates++] =
! 320: sc->sc_caps.an_rates[i];
! 321: }
! 322:
! 323: /*
! 324: * Call MI attach routine.
! 325: */
! 326: if_attach(ifp);
! 327: ieee80211_ifattach(ifp);
! 328:
! 329: sc->sc_newstate = ic->ic_newstate;
! 330: ic->ic_newstate = an_newstate;
! 331:
! 332: ieee80211_media_init(ifp, an_media_change, an_media_status);
! 333:
! 334: #if NBPFILTER > 0
! 335: bzero(&sc->sc_rxtapu, sizeof(sc->sc_rxtapu));
! 336: sc->sc_rxtap.ar_ihdr.it_len = sizeof(sc->sc_rxtapu);
! 337: sc->sc_rxtap.ar_ihdr.it_present = AN_RX_RADIOTAP_PRESENT;
! 338:
! 339: bzero(&sc->sc_txtapu, sizeof(sc->sc_txtapu));
! 340: sc->sc_txtap.at_ihdr.it_len = sizeof(sc->sc_txtapu);
! 341: sc->sc_txtap.at_ihdr.it_present = AN_TX_RADIOTAP_PRESENT;
! 342:
! 343: bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
! 344: sizeof(struct ieee80211_frame) + 64);
! 345: #endif
! 346:
! 347: sc->sc_sdhook = shutdownhook_establish(an_shutdown, sc);
! 348:
! 349: sc->sc_attached = 1;
! 350:
! 351: return(0);
! 352: }
! 353:
! 354: void
! 355: an_rxeof(struct an_softc *sc)
! 356: {
! 357: struct ieee80211com *ic = &sc->sc_ic;
! 358: struct ifnet *ifp = &ic->ic_if;
! 359: struct ieee80211_frame *wh;
! 360: struct ieee80211_node *ni;
! 361: struct an_rxframe frmhdr;
! 362: struct mbuf *m;
! 363: u_int16_t status;
! 364: int fid, gaplen, len, off;
! 365: uint8_t *gap;
! 366:
! 367: fid = CSR_READ_2(sc, AN_RX_FID);
! 368:
! 369: /* First read in the frame header */
! 370: if (an_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr), sizeof(frmhdr)) != 0) {
! 371: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
! 372: ifp->if_ierrors++;
! 373: DPRINTF(("an_rxeof: read fid %x failed\n", fid));
! 374: return;
! 375: }
! 376: an_swap16((u_int16_t *)&frmhdr.an_whdr, sizeof(struct ieee80211_frame)/2);
! 377:
! 378: status = frmhdr.an_rx_status;
! 379: if ((status & AN_STAT_ERRSTAT) != 0 &&
! 380: ic->ic_opmode != IEEE80211_M_MONITOR) {
! 381: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
! 382: ifp->if_ierrors++;
! 383: DPRINTF(("an_rxeof: fid %x status %x\n", fid, status));
! 384: return;
! 385: }
! 386:
! 387: /* the payload length field includes a 16-bit "mystery field" */
! 388: len = frmhdr.an_rx_payload_len - sizeof(uint16_t);
! 389: off = ALIGN(sizeof(struct ieee80211_frame));
! 390:
! 391: if (off + len > MCLBYTES) {
! 392: if (ic->ic_opmode != IEEE80211_M_MONITOR) {
! 393: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
! 394: ifp->if_ierrors++;
! 395: DPRINTF(("an_rxeof: oversized packet %d\n", len));
! 396: return;
! 397: }
! 398: len = 0;
! 399: }
! 400:
! 401: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 402: if (m == NULL) {
! 403: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
! 404: ifp->if_ierrors++;
! 405: DPRINTF(("an_rxeof: MGET failed\n"));
! 406: return;
! 407: }
! 408: if (off + len + AN_GAPLEN_MAX > MHLEN) {
! 409: MCLGET(m, M_DONTWAIT);
! 410: if ((m->m_flags & M_EXT) == 0) {
! 411: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
! 412: m_freem(m);
! 413: ifp->if_ierrors++;
! 414: DPRINTF(("an_rxeof: MCLGET failed\n"));
! 415: return;
! 416: }
! 417: }
! 418: m->m_data += off - sizeof(struct ieee80211_frame);
! 419:
! 420: if (ic->ic_opmode != IEEE80211_M_MONITOR) {
! 421: gaplen = frmhdr.an_gaplen;
! 422: if (gaplen > AN_GAPLEN_MAX) {
! 423: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
! 424: m_freem(m);
! 425: ifp->if_ierrors++;
! 426: DPRINTF(("%s: gap too long\n", __func__));
! 427: return;
! 428: }
! 429: /*
! 430: * We don't need the 16-bit mystery field (payload length?),
! 431: * so read it into the region reserved for the 802.11 header.
! 432: *
! 433: * When Cisco Aironet 350 cards w/ firmware version 5 or
! 434: * greater operate with certain Cisco 350 APs,
! 435: * the "gap" is filled with the SNAP header. Read
! 436: * it in after the 802.11 header.
! 437: */
! 438: gap = m->m_data + sizeof(struct ieee80211_frame) -
! 439: sizeof(uint16_t);
! 440: an_read_bap(sc, fid, -1, gap, gaplen + sizeof(u_int16_t),
! 441: gaplen + sizeof(u_int16_t));
! 442: } else
! 443: gaplen = 0;
! 444:
! 445: an_read_bap(sc, fid, -1,
! 446: m->m_data + sizeof(struct ieee80211_frame) + gaplen, len, len);
! 447: an_swap16((u_int16_t *)(m->m_data + sizeof(struct ieee80211_frame) + gaplen), (len+1)/2);
! 448: m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + gaplen +
! 449: len;
! 450:
! 451: memcpy(m->m_data, &frmhdr.an_whdr, sizeof(struct ieee80211_frame));
! 452: m->m_pkthdr.rcvif = ifp;
! 453: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
! 454:
! 455: #if NBPFILTER > 0
! 456: if (sc->sc_drvbpf) {
! 457: struct mbuf mb;
! 458: struct an_rx_radiotap_header *tap = &sc->sc_rxtap;
! 459:
! 460: tap->ar_rate = frmhdr.an_rx_rate;
! 461: tap->ar_antsignal = frmhdr.an_rx_signal_strength;
! 462: tap->ar_chan_freq = ic->ic_bss->ni_chan->ic_freq;
! 463: tap->ar_chan_flags = ic->ic_bss->ni_chan->ic_flags;
! 464:
! 465:
! 466: mb.m_data = (caddr_t)tap;
! 467: mb.m_len = sizeof(sc->sc_rxtapu);
! 468: mb.m_next = m;
! 469: mb.m_nextpkt = NULL;
! 470: mb.m_type = 0;
! 471: mb.m_flags = 0;
! 472: bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
! 473: }
! 474: #endif /* NPBFILTER > 0 */
! 475:
! 476: wh = mtod(m, struct ieee80211_frame *);
! 477: if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
! 478: /*
! 479: * WEP is decrypted by hardware. Clear WEP bit
! 480: * header for ieee80211_input().
! 481: */
! 482: wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
! 483: }
! 484:
! 485: ni = ieee80211_find_rxnode(ic, wh);
! 486: ieee80211_input(ifp, m, ni, frmhdr.an_rx_signal_strength,
! 487: an_switch32(frmhdr.an_rx_time));
! 488: ieee80211_release_node(ic, ni);
! 489: }
! 490:
! 491: void
! 492: an_txeof(struct an_softc *sc, u_int16_t status)
! 493: {
! 494: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 495: int cur, id;
! 496:
! 497: sc->sc_tx_timer = 0;
! 498: ifp->if_flags &= ~IFF_OACTIVE;
! 499:
! 500: id = CSR_READ_2(sc, AN_TX_CMP_FID);
! 501: CSR_WRITE_2(sc, AN_EVENT_ACK, status & (AN_EV_TX | AN_EV_TX_EXC));
! 502:
! 503: if (status & AN_EV_TX_EXC)
! 504: ifp->if_oerrors++;
! 505: else
! 506: ifp->if_opackets++;
! 507:
! 508: cur = sc->sc_txcur;
! 509: if (sc->sc_txd[cur].d_fid == id) {
! 510: sc->sc_txd[cur].d_inuse = 0;
! 511: DPRINTF2(("an_txeof: sent %x/%d\n", id, cur));
! 512: AN_INC(cur, AN_TX_RING_CNT);
! 513: sc->sc_txcur = cur;
! 514: } else {
! 515: for (cur = 0; cur < AN_TX_RING_CNT; cur++) {
! 516: if (id == sc->sc_txd[cur].d_fid) {
! 517: sc->sc_txd[cur].d_inuse = 0;
! 518: break;
! 519: }
! 520: }
! 521: if (ifp->if_flags & IFF_DEBUG)
! 522: printf("%s: tx mismatch: "
! 523: "expected %x(%d), actual %x(%d)\n",
! 524: sc->sc_dev.dv_xname,
! 525: sc->sc_txd[sc->sc_txcur].d_fid, sc->sc_txcur,
! 526: id, cur);
! 527: }
! 528: }
! 529:
! 530: int
! 531: an_intr(void *arg)
! 532: {
! 533: struct an_softc *sc = arg;
! 534: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 535: int i;
! 536: u_int16_t status;
! 537:
! 538: if (!sc->sc_enabled || sc->sc_invalid ||
! 539: (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 ||
! 540: (ifp->if_flags & IFF_RUNNING) == 0)
! 541: return 0;
! 542:
! 543: if ((ifp->if_flags & IFF_UP) == 0) {
! 544: CSR_WRITE_2(sc, AN_INT_EN, 0);
! 545: CSR_WRITE_2(sc, AN_EVENT_ACK, ~0);
! 546: return 1;
! 547: }
! 548:
! 549: /* maximum 10 loops per interrupt */
! 550: for (i = 0; i < 10; i++) {
! 551: if (!sc->sc_enabled || sc->sc_invalid)
! 552: return 1;
! 553: if (CSR_READ_2(sc, AN_SW0) != AN_MAGIC) {
! 554: DPRINTF(("an_intr: magic number changed: %x\n",
! 555: CSR_READ_2(sc, AN_SW0)));
! 556: sc->sc_invalid = 1;
! 557: return 1;
! 558: }
! 559: status = CSR_READ_2(sc, AN_EVENT_STAT);
! 560: CSR_WRITE_2(sc, AN_EVENT_ACK, status & ~(AN_INTRS));
! 561: if ((status & AN_INTRS) == 0)
! 562: break;
! 563:
! 564: if (status & AN_EV_RX)
! 565: an_rxeof(sc);
! 566:
! 567: if (status & (AN_EV_TX | AN_EV_TX_EXC))
! 568: an_txeof(sc, status);
! 569:
! 570: if (status & AN_EV_LINKSTAT)
! 571: an_linkstat_intr(sc);
! 572:
! 573: if ((ifp->if_flags & IFF_OACTIVE) == 0 &&
! 574: sc->sc_ic.ic_state == IEEE80211_S_RUN &&
! 575: !IFQ_IS_EMPTY(&ifp->if_snd))
! 576: an_start(ifp);
! 577: }
! 578:
! 579: return 1;
! 580: }
! 581:
! 582: /* Must be called at proper protection level! */
! 583: int
! 584: an_cmd(struct an_softc *sc, int cmd, int val)
! 585: {
! 586: int i, stat;
! 587:
! 588: /* make sure previous command completed */
! 589: if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) {
! 590: if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
! 591: printf("%s: command 0x%x busy\n", sc->sc_dev.dv_xname,
! 592: CSR_READ_2(sc, AN_COMMAND));
! 593: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
! 594: }
! 595:
! 596: CSR_WRITE_2(sc, AN_PARAM0, val);
! 597: CSR_WRITE_2(sc, AN_PARAM1, 0);
! 598: CSR_WRITE_2(sc, AN_PARAM2, 0);
! 599: CSR_WRITE_2(sc, AN_COMMAND, cmd);
! 600:
! 601: if (cmd == AN_CMD_FW_RESTART) {
! 602: /* XXX: should sleep here */
! 603: DELAY(100*1000);
! 604: }
! 605:
! 606: for (i = 0; i < AN_TIMEOUT; i++) {
! 607: if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
! 608: break;
! 609: DELAY(10);
! 610: }
! 611:
! 612: stat = CSR_READ_2(sc, AN_STATUS);
! 613:
! 614: /* clear stuck command busy if necessary */
! 615: if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY)
! 616: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
! 617:
! 618: /* Ack the command */
! 619: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
! 620:
! 621: if (i == AN_TIMEOUT) {
! 622: if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
! 623: printf("%s: command 0x%x param 0x%x timeout\n",
! 624: sc->sc_dev.dv_xname, cmd, val);
! 625: return ETIMEDOUT;
! 626: }
! 627: if (stat & AN_STAT_CMD_RESULT) {
! 628: if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
! 629: printf("%s: command 0x%x param 0x%x status 0x%x "
! 630: "resp 0x%x 0x%x 0x%x\n",
! 631: sc->sc_dev.dv_xname, cmd, val, stat,
! 632: CSR_READ_2(sc, AN_RESP0), CSR_READ_2(sc, AN_RESP1),
! 633: CSR_READ_2(sc, AN_RESP2));
! 634: return EIO;
! 635: }
! 636:
! 637: return 0;
! 638: }
! 639:
! 640: int
! 641: an_reset(struct an_softc *sc)
! 642: {
! 643:
! 644: DPRINTF(("an_reset\n"));
! 645:
! 646: if (!sc->sc_enabled)
! 647: return ENXIO;
! 648:
! 649: an_cmd(sc, AN_CMD_ENABLE, 0);
! 650: an_cmd(sc, AN_CMD_FW_RESTART, 0);
! 651: an_cmd(sc, AN_CMD_NOOP2, 0);
! 652:
! 653: if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT) {
! 654: printf("%s: reset failed\n", sc->sc_dev.dv_xname);
! 655: return ETIMEDOUT;
! 656: }
! 657:
! 658: an_cmd(sc, AN_CMD_DISABLE, 0);
! 659: return 0;
! 660: }
! 661:
! 662: void
! 663: an_linkstat_intr(struct an_softc *sc)
! 664: {
! 665: struct ieee80211com *ic = &sc->sc_ic;
! 666: u_int16_t status;
! 667:
! 668: status = CSR_READ_2(sc, AN_LINKSTAT);
! 669: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_LINKSTAT);
! 670: DPRINTF(("an_linkstat_intr: status 0x%x\n", status));
! 671:
! 672: if (status == AN_LINKSTAT_ASSOCIATED) {
! 673: if (ic->ic_state != IEEE80211_S_RUN ||
! 674: ic->ic_opmode == IEEE80211_M_IBSS)
! 675: ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
! 676: } else {
! 677: if (ic->ic_opmode == IEEE80211_M_STA)
! 678: ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
! 679: }
! 680: }
! 681:
! 682: /*
! 683: * Wait for firmware come up after power enabled.
! 684: */
! 685: void
! 686: an_wait(struct an_softc *sc)
! 687: {
! 688: int i;
! 689:
! 690: CSR_WRITE_2(sc, AN_COMMAND, AN_CMD_NOOP2);
! 691: for (i = 0; i < 3*hz; i++) {
! 692: if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
! 693: break;
! 694: (void)tsleep(sc, PWAIT, "anatch", 1);
! 695: }
! 696: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
! 697: }
! 698:
! 699: int
! 700: an_read_bap(struct an_softc *sc, int id, int off, void *buf, int len, int blen)
! 701: {
! 702: int error, cnt, cnt2;
! 703:
! 704: if (len == 0 || blen == 0)
! 705: return 0;
! 706: if (off == -1)
! 707: off = sc->sc_bap_off;
! 708: if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
! 709: if ((error = an_seek_bap(sc, id, off)) != 0)
! 710: return EIO;
! 711: }
! 712:
! 713: cnt = (blen + 1) / 2;
! 714: CSR_READ_MULTI_STREAM_2(sc, AN_DATA0, (u_int16_t *)buf, cnt);
! 715: for (cnt2 = (len + 1) / 2; cnt < cnt2; cnt++)
! 716: (void) CSR_READ_2(sc, AN_DATA0);
! 717: sc->sc_bap_off += cnt * 2;
! 718:
! 719: return 0;
! 720: }
! 721:
! 722: int
! 723: an_write_bap(struct an_softc *sc, int id, int off, void *buf, int buflen)
! 724: {
! 725: int error, cnt;
! 726:
! 727: if (buflen == 0)
! 728: return 0;
! 729: if (off == -1)
! 730: off = sc->sc_bap_off;
! 731: if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
! 732: if ((error = an_seek_bap(sc, id, off)) != 0)
! 733: return EIO;
! 734: }
! 735:
! 736: cnt = (buflen + 1) / 2;
! 737: CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0, (u_int16_t *)buf, cnt);
! 738: sc->sc_bap_off += cnt * 2;
! 739: return 0;
! 740: }
! 741:
! 742: int
! 743: an_seek_bap(struct an_softc *sc, int id, int off)
! 744: {
! 745: int i, status;
! 746:
! 747: CSR_WRITE_2(sc, AN_SEL0, id);
! 748: CSR_WRITE_2(sc, AN_OFF0, off);
! 749:
! 750: for (i = 0; ; i++) {
! 751: status = CSR_READ_2(sc, AN_OFF0);
! 752: if ((status & AN_OFF_BUSY) == 0)
! 753: break;
! 754: if (i == AN_TIMEOUT) {
! 755: printf("%s: timeout in an_seek_bap to 0x%x/0x%x\n",
! 756: sc->sc_dev.dv_xname, id, off);
! 757: sc->sc_bap_off = AN_OFF_ERR; /* invalidate */
! 758: return ETIMEDOUT;
! 759: }
! 760: DELAY(10);
! 761: }
! 762: if (status & AN_OFF_ERR) {
! 763: printf("%s: failed in an_seek_bap to 0x%x/0x%x\n",
! 764: sc->sc_dev.dv_xname, id, off);
! 765: sc->sc_bap_off = AN_OFF_ERR; /* invalidate */
! 766: return EIO;
! 767: }
! 768: sc->sc_bap_id = id;
! 769: sc->sc_bap_off = off;
! 770: return 0;
! 771: }
! 772:
! 773: int
! 774: an_mwrite_bap(struct an_softc *sc, int id, int off, struct mbuf *m, int totlen)
! 775: {
! 776: int error, len, cnt;
! 777:
! 778: if (off == -1)
! 779: off = sc->sc_bap_off;
! 780: if (id != sc->sc_bap_id || off != sc->sc_bap_off) {
! 781: if ((error = an_seek_bap(sc, id, off)) != 0)
! 782: return EIO;
! 783: }
! 784:
! 785: for (len = 0; m != NULL; m = m->m_next) {
! 786: if (m->m_len == 0)
! 787: continue;
! 788: len = min(m->m_len, totlen);
! 789:
! 790: if ((mtod(m, u_long) & 0x1) || (len & 0x1)) {
! 791: m_copydata(m, 0, totlen, (caddr_t)&sc->sc_buf.sc_txbuf);
! 792: cnt = (totlen + 1) / 2;
! 793: an_swap16((u_int16_t *)&sc->sc_buf.sc_txbuf, cnt);
! 794: CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0,
! 795: sc->sc_buf.sc_val, cnt);
! 796: off += cnt * 2;
! 797: break;
! 798: }
! 799: cnt = len / 2;
! 800: an_swap16((u_int16_t *)mtod(m, u_int16_t *), cnt);
! 801: CSR_WRITE_MULTI_STREAM_2(sc, AN_DATA0, mtod(m, u_int16_t *),
! 802: cnt);
! 803: off += len;
! 804: totlen -= len;
! 805: }
! 806: sc->sc_bap_off = off;
! 807: return 0;
! 808: }
! 809:
! 810: int
! 811: an_alloc_nicmem(struct an_softc *sc, int len, int *idp)
! 812: {
! 813: int i;
! 814:
! 815: if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) {
! 816: printf("%s: failed to allocate %d bytes on NIC\n",
! 817: sc->sc_dev.dv_xname, len);
! 818: return(ENOMEM);
! 819: }
! 820:
! 821: for (i = 0; i < AN_TIMEOUT; i++) {
! 822: if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC)
! 823: break;
! 824: if (i == AN_TIMEOUT) {
! 825: printf("%s: timeout in alloc\n", sc->sc_dev.dv_xname);
! 826: return ETIMEDOUT;
! 827: }
! 828: DELAY(10);
! 829: }
! 830:
! 831: *idp = CSR_READ_2(sc, AN_ALLOC_FID);
! 832: CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC);
! 833: return 0;
! 834: }
! 835:
! 836: int
! 837: an_read_rid(struct an_softc *sc, int rid, void *buf, int *buflenp)
! 838: {
! 839: int error;
! 840: u_int16_t len;
! 841:
! 842: /* Tell the NIC to enter record read mode. */
! 843: error = an_cmd(sc, AN_CMD_ACCESS | AN_ACCESS_READ, rid);
! 844: if (error)
! 845: return error;
! 846:
! 847: /* length in byte, including length itself */
! 848: error = an_read_bap(sc, rid, 0, &len, sizeof(len), sizeof(len));
! 849: if (error)
! 850: return error;
! 851:
! 852: len -= 2;
! 853: return an_read_bap(sc, rid, sizeof(len), buf, len, *buflenp);
! 854: }
! 855:
! 856: int
! 857: an_write_rid(struct an_softc *sc, int rid, void *buf, int buflen)
! 858: {
! 859: int error;
! 860: u_int16_t len;
! 861:
! 862: /* length in byte, including length itself */
! 863: len = buflen + 2;
! 864:
! 865: error = an_write_bap(sc, rid, 0, &len, sizeof(len));
! 866: if (error)
! 867: return error;
! 868: error = an_write_bap(sc, rid, sizeof(len), buf, buflen);
! 869: if (error)
! 870: return error;
! 871:
! 872: return an_cmd(sc, AN_CMD_ACCESS | AN_ACCESS_WRITE, rid);
! 873: }
! 874:
! 875: int
! 876: an_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
! 877: {
! 878: struct an_softc *sc = ifp->if_softc;
! 879: struct ifaddr *ifa = (struct ifaddr *)data;
! 880: int s, error = 0;
! 881:
! 882: if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
! 883: return ENXIO;
! 884:
! 885: s = splnet();
! 886:
! 887: switch(command) {
! 888: case SIOCSIFADDR:
! 889: ifp->if_flags |= IFF_UP;
! 890: switch (ifa->ifa_addr->sa_family) {
! 891: #ifdef INET
! 892: case AF_INET:
! 893: error = an_init(ifp);
! 894: arp_ifinit(&sc->sc_ic.ic_ac, ifa);
! 895: break;
! 896: #endif
! 897: default:
! 898: error = an_init(ifp);
! 899: break;
! 900: }
! 901: break;
! 902: case SIOCSIFFLAGS:
! 903: if (ifp->if_flags & IFF_UP) {
! 904: if (sc->sc_enabled) {
! 905: /*
! 906: * To avoid rescanning another access point,
! 907: * do not call an_init() here. Instead, only
! 908: * reflect promisc mode settings.
! 909: */
! 910: error = an_cmd(sc, AN_CMD_SET_MODE,
! 911: (ifp->if_flags & IFF_PROMISC) ? 0xffff : 0);
! 912: } else
! 913: error = an_init(ifp);
! 914: } else if (sc->sc_enabled)
! 915: an_stop(ifp, 1);
! 916: break;
! 917: case SIOCADDMULTI:
! 918: case SIOCDELMULTI:
! 919: /* The Aironet has no multicast filter. */
! 920: error = 0;
! 921: break;
! 922: case SIOCS80211NWKEY:
! 923: error = an_set_nwkey(sc, (struct ieee80211_nwkey *)data);
! 924: break;
! 925: case SIOCG80211NWKEY:
! 926: error = an_get_nwkey(sc, (struct ieee80211_nwkey *)data);
! 927: break;
! 928: default:
! 929: error = ieee80211_ioctl(ifp, command, data);
! 930: break;
! 931: }
! 932: if (error == ENETRESET) {
! 933: if (sc->sc_enabled)
! 934: error = an_init(ifp);
! 935: else
! 936: error = 0;
! 937: }
! 938: splx(s);
! 939: return(error);
! 940: }
! 941:
! 942: int
! 943: an_init(struct ifnet *ifp)
! 944: {
! 945: struct an_softc *sc = ifp->if_softc;
! 946: struct ieee80211com *ic = &sc->sc_ic;
! 947: int i, error, fid;
! 948:
! 949: DPRINTF(("an_init: enabled %d\n", sc->sc_enabled));
! 950: if (!sc->sc_enabled) {
! 951: if (sc->sc_enable)
! 952: (*sc->sc_enable)(sc);
! 953: an_wait(sc);
! 954: sc->sc_enabled = 1;
! 955: } else {
! 956: an_stop(ifp, 0);
! 957: if ((error = an_reset(sc)) != 0) {
! 958: printf("%s: failed to reset\n", ifp->if_xname);
! 959: an_stop(ifp, 1);
! 960: return error;
! 961: }
! 962: }
! 963: CSR_WRITE_2(sc, AN_SW0, AN_MAGIC);
! 964:
! 965: /* Allocate the TX buffers */
! 966: for (i = 0; i < AN_TX_RING_CNT; i++) {
! 967: if ((error = an_alloc_nicmem(sc, AN_TX_MAX_LEN, &fid)) != 0) {
! 968: printf("%s: failed to allocate nic memory\n",
! 969: ifp->if_xname);
! 970: an_stop(ifp, 1);
! 971: return error;
! 972: }
! 973: DPRINTF2(("an_init: txbuf %d allocated %x\n", i, fid));
! 974: sc->sc_txd[i].d_fid = fid;
! 975: sc->sc_txd[i].d_inuse = 0;
! 976: }
! 977: sc->sc_txcur = sc->sc_txnext = 0;
! 978:
! 979: IEEE80211_ADDR_COPY(sc->sc_config.an_macaddr, ic->ic_myaddr);
! 980: an_swap16((u_int16_t *)&sc->sc_config.an_macaddr, 3);
! 981: sc->sc_config.an_scanmode = AN_SCANMODE_ACTIVE;
! 982: sc->sc_config.an_authtype = AN_AUTHTYPE_OPEN; /*XXX*/
! 983: if (ic->ic_flags & IEEE80211_F_WEPON) {
! 984: sc->sc_config.an_authtype |=
! 985: AN_AUTHTYPE_PRIVACY_IN_USE;
! 986: }
! 987: sc->sc_config.an_listen_interval = ic->ic_lintval;
! 988: sc->sc_config.an_beacon_period = ic->ic_lintval;
! 989: if (ic->ic_flags & IEEE80211_F_PMGTON)
! 990: sc->sc_config.an_psave_mode = AN_PSAVE_PSP;
! 991: else
! 992: sc->sc_config.an_psave_mode = AN_PSAVE_CAM;
! 993: sc->sc_config.an_ds_channel =
! 994: ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
! 995:
! 996: switch (ic->ic_opmode) {
! 997: case IEEE80211_M_STA:
! 998: sc->sc_config.an_opmode =
! 999: AN_OPMODE_INFRASTRUCTURE_STATION;
! 1000: sc->sc_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
! 1001: break;
! 1002: case IEEE80211_M_IBSS:
! 1003: sc->sc_config.an_opmode = AN_OPMODE_IBSS_ADHOC;
! 1004: sc->sc_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
! 1005: break;
! 1006: case IEEE80211_M_MONITOR:
! 1007: sc->sc_config.an_opmode =
! 1008: AN_OPMODE_INFRASTRUCTURE_STATION;
! 1009: sc->sc_config.an_rxmode =
! 1010: AN_RXMODE_80211_MONITOR_ANYBSS;
! 1011: sc->sc_config.an_authtype = AN_AUTHTYPE_NONE;
! 1012: if (ic->ic_flags & IEEE80211_F_WEPON)
! 1013: sc->sc_config.an_authtype |=
! 1014: AN_AUTHTYPE_PRIVACY_IN_USE |
! 1015: AN_AUTHTYPE_ALLOW_UNENCRYPTED;
! 1016: break;
! 1017: default:
! 1018: printf("%s: bad opmode %d\n", ifp->if_xname, ic->ic_opmode);
! 1019: an_stop(ifp, 1);
! 1020: return EIO;
! 1021: }
! 1022: sc->sc_config.an_rxmode |= AN_RXMODE_NO_8023_HEADER;
! 1023:
! 1024: /* Set the ssid list */
! 1025: memset(&sc->sc_buf, 0, sizeof(sc->sc_buf.sc_ssidlist));
! 1026: sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid_len =
! 1027: ic->ic_des_esslen;
! 1028: if (ic->ic_des_esslen)
! 1029: memcpy(sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid,
! 1030: ic->ic_des_essid, ic->ic_des_esslen);
! 1031: an_swap16((u_int16_t *)&sc->sc_buf.sc_ssidlist.an_entry[0].an_ssid, 16);
! 1032: if (an_write_rid(sc, AN_RID_SSIDLIST, &sc->sc_buf,
! 1033: sizeof(sc->sc_buf.sc_ssidlist)) != 0) {
! 1034: printf("%s: failed to write ssid list\n", ifp->if_xname);
! 1035: an_stop(ifp, 1);
! 1036: return error;
! 1037: }
! 1038:
! 1039: /* Set the AP list */
! 1040: memset(&sc->sc_buf, 0, sizeof(sc->sc_buf.sc_aplist));
! 1041: (void)an_write_rid(sc, AN_RID_APLIST, &sc->sc_buf,
! 1042: sizeof(sc->sc_buf.sc_aplist));
! 1043:
! 1044: /* Set the encapsulation */
! 1045: for (i = 0; i < AN_ENCAP_NENTS; i++) {
! 1046: sc->sc_buf.sc_encap.an_entry[i].an_ethertype = 0;
! 1047: sc->sc_buf.sc_encap.an_entry[i].an_action =
! 1048: AN_RXENCAP_RFC1024 | AN_TXENCAP_RFC1024;
! 1049: }
! 1050: (void)an_write_rid(sc, AN_RID_ENCAP, &sc->sc_buf,
! 1051: sizeof(sc->sc_buf.sc_encap));
! 1052:
! 1053: /* Set the WEP Keys */
! 1054: if (ic->ic_flags & IEEE80211_F_WEPON)
! 1055: an_write_wepkey(sc, AN_RID_WEP_VOLATILE, sc->sc_wepkeys,
! 1056: sc->sc_tx_key);
! 1057:
! 1058: /* Set the configuration */
! 1059: if (an_write_rid(sc, AN_RID_GENCONFIG, &sc->sc_config,
! 1060: sizeof(sc->sc_config)) != 0) {
! 1061: printf("%s: failed to write config\n", ifp->if_xname);
! 1062: an_stop(ifp, 1);
! 1063: return error;
! 1064: }
! 1065:
! 1066: /* Enable the MAC */
! 1067: if (an_cmd(sc, AN_CMD_ENABLE, 0)) {
! 1068: printf("%s: failed to enable MAC\n", sc->sc_dev.dv_xname);
! 1069: an_stop(ifp, 1);
! 1070: return ENXIO;
! 1071: }
! 1072: if (ifp->if_flags & IFF_PROMISC)
! 1073: an_cmd(sc, AN_CMD_SET_MODE, 0xffff);
! 1074:
! 1075: ifp->if_flags |= IFF_RUNNING;
! 1076: ifp->if_flags &= ~IFF_OACTIVE;
! 1077: ic->ic_state = IEEE80211_S_INIT;
! 1078: if (ic->ic_opmode == IEEE80211_M_MONITOR)
! 1079: ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
! 1080:
! 1081: /* enable interrupts */
! 1082: CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS);
! 1083: return 0;
! 1084: }
! 1085:
! 1086: void
! 1087: an_start(struct ifnet *ifp)
! 1088: {
! 1089: struct an_softc *sc = (struct an_softc *)ifp->if_softc;
! 1090: struct ieee80211com *ic = &sc->sc_ic;
! 1091: struct ieee80211_node *ni;
! 1092: struct ieee80211_frame *wh;
! 1093: struct an_txframe frmhdr;
! 1094: struct mbuf *m;
! 1095: u_int16_t len;
! 1096: int cur, fid;
! 1097:
! 1098: if (!sc->sc_enabled || sc->sc_invalid) {
! 1099: DPRINTF(("an_start: noop: enabled %d invalid %d\n",
! 1100: sc->sc_enabled, sc->sc_invalid));
! 1101: return;
! 1102: }
! 1103:
! 1104: memset(&frmhdr, 0, sizeof(frmhdr));
! 1105: cur = sc->sc_txnext;
! 1106: for (;;) {
! 1107: if (ic->ic_state != IEEE80211_S_RUN) {
! 1108: DPRINTF(("an_start: not running %d\n", ic->ic_state));
! 1109: break;
! 1110: }
! 1111: IFQ_POLL(&ifp->if_snd, m);
! 1112: if (m == NULL) {
! 1113: DPRINTF2(("an_start: no pending mbuf\n"));
! 1114: break;
! 1115: }
! 1116: if (sc->sc_txd[cur].d_inuse) {
! 1117: DPRINTF2(("an_start: %x/%d busy\n",
! 1118: sc->sc_txd[cur].d_fid, cur));
! 1119: ifp->if_flags |= IFF_OACTIVE;
! 1120: break;
! 1121: }
! 1122: IFQ_DEQUEUE(&ifp->if_snd, m);
! 1123: ifp->if_opackets++;
! 1124: #if NBPFILTER > 0
! 1125: if (ifp->if_bpf)
! 1126: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 1127: #endif
! 1128: if ((m = ieee80211_encap(ifp, m, &ni)) == NULL) {
! 1129: ifp->if_oerrors++;
! 1130: continue;
! 1131: }
! 1132: if (ni != NULL)
! 1133: ieee80211_release_node(ic, ni);
! 1134: #if NBPFILTER > 0
! 1135: if (ic->ic_rawbpf)
! 1136: bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
! 1137: #endif
! 1138:
! 1139: wh = mtod(m, struct ieee80211_frame *);
! 1140: if (ic->ic_flags & IEEE80211_F_WEPON)
! 1141: wh->i_fc[1] |= IEEE80211_FC1_WEP;
! 1142: m_copydata(m, 0, sizeof(struct ieee80211_frame),
! 1143: (caddr_t)&frmhdr.an_whdr);
! 1144: an_swap16((u_int16_t *)&frmhdr.an_whdr, sizeof(struct ieee80211_frame)/2);
! 1145:
! 1146: /* insert payload length in front of llc/snap */
! 1147: len = htons(m->m_pkthdr.len - sizeof(struct ieee80211_frame));
! 1148: m_adj(m, sizeof(struct ieee80211_frame) - sizeof(len));
! 1149: if (mtod(m, u_long) & 0x01)
! 1150: memcpy(mtod(m, caddr_t), &len, sizeof(len));
! 1151: else
! 1152: *mtod(m, u_int16_t *) = len;
! 1153:
! 1154: /*
! 1155: * XXX Aironet firmware apparently convert the packet
! 1156: * with longer than 1500 bytes in length into LLC/SNAP.
! 1157: * If we have 1500 bytes in ethernet payload, it is
! 1158: * 1508 bytes including LLC/SNAP and will be inserted
! 1159: * additional LLC/SNAP header with 1501-1508 in its
! 1160: * ethertype !!
! 1161: * So we skip LLC/SNAP header and force firmware to
! 1162: * convert it to LLC/SNAP again.
! 1163: */
! 1164: m_adj(m, sizeof(struct llc));
! 1165:
! 1166: frmhdr.an_tx_ctl = AN_TXCTL_80211;
! 1167: frmhdr.an_tx_payload_len = m->m_pkthdr.len;
! 1168: frmhdr.an_gaplen = AN_TXGAP_802_11;
! 1169:
! 1170: if (ic->ic_fixed_rate != -1)
! 1171: frmhdr.an_tx_rate =
! 1172: ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
! 1173: ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
! 1174: else
! 1175: frmhdr.an_tx_rate = 0;
! 1176:
! 1177: if (sizeof(frmhdr) + AN_TXGAP_802_11 + sizeof(len) +
! 1178: m->m_pkthdr.len > AN_TX_MAX_LEN) {
! 1179: ifp->if_oerrors++;
! 1180: m_freem(m);
! 1181: continue;
! 1182: }
! 1183:
! 1184: #if NBPFILTER > 0
! 1185: if (sc->sc_drvbpf) {
! 1186: struct mbuf mb;
! 1187: struct an_tx_radiotap_header *tap = &sc->sc_txtap;
! 1188:
! 1189: tap->at_rate =
! 1190: ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate];
! 1191: tap->at_chan_freq =
! 1192: ic->ic_bss->ni_chan->ic_freq;
! 1193: tap->at_chan_flags =
! 1194: ic->ic_bss->ni_chan->ic_flags;
! 1195:
! 1196: mb.m_data = (caddr_t)tap;
! 1197: mb.m_len = sizeof(sc->sc_txtapu);
! 1198: mb.m_next = m;
! 1199: mb.m_nextpkt = NULL;
! 1200: mb.m_type = 0;
! 1201: mb.m_flags = 0;
! 1202: bpf_mtap(sc->sc_drvbpf, m, BPF_DIRECTION_OUT);
! 1203: }
! 1204: #endif
! 1205:
! 1206: fid = sc->sc_txd[cur].d_fid;
! 1207: if (an_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0) {
! 1208: ifp->if_oerrors++;
! 1209: m_freem(m);
! 1210: continue;
! 1211: }
! 1212: /* dummy write to avoid seek. */
! 1213: an_write_bap(sc, fid, -1, &frmhdr, AN_TXGAP_802_11);
! 1214: an_mwrite_bap(sc, fid, -1, m, m->m_pkthdr.len);
! 1215: m_freem(m);
! 1216:
! 1217: DPRINTF2(("an_start: send %d byte via %x/%d\n",
! 1218: ntohs(len) + sizeof(struct ieee80211_frame),
! 1219: fid, cur));
! 1220: sc->sc_txd[cur].d_inuse = 1;
! 1221: if (an_cmd(sc, AN_CMD_TX, fid)) {
! 1222: printf("%s: xmit failed\n", ifp->if_xname);
! 1223: sc->sc_txd[cur].d_inuse = 0;
! 1224: continue;
! 1225: }
! 1226: sc->sc_tx_timer = 5;
! 1227: ifp->if_timer = 1;
! 1228: AN_INC(cur, AN_TX_RING_CNT);
! 1229: sc->sc_txnext = cur;
! 1230: }
! 1231: }
! 1232:
! 1233: void
! 1234: an_stop(struct ifnet *ifp, int disable)
! 1235: {
! 1236: struct an_softc *sc = ifp->if_softc;
! 1237: int i, s;
! 1238:
! 1239: if (!sc->sc_enabled)
! 1240: return;
! 1241:
! 1242: DPRINTF(("an_stop: disable %d\n", disable));
! 1243:
! 1244: s = splnet();
! 1245: ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
! 1246: if (!sc->sc_invalid) {
! 1247: an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0);
! 1248: CSR_WRITE_2(sc, AN_INT_EN, 0);
! 1249: an_cmd(sc, AN_CMD_DISABLE, 0);
! 1250:
! 1251: for (i = 0; i < AN_TX_RING_CNT; i++)
! 1252: an_cmd(sc, AN_CMD_DEALLOC_MEM, sc->sc_txd[i].d_fid);
! 1253: }
! 1254:
! 1255: sc->sc_tx_timer = 0;
! 1256: ifp->if_timer = 0;
! 1257: ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
! 1258:
! 1259: if (disable) {
! 1260: if (sc->sc_disable)
! 1261: (*sc->sc_disable)(sc);
! 1262: sc->sc_enabled = 0;
! 1263: }
! 1264: splx(s);
! 1265: }
! 1266:
! 1267: void
! 1268: an_watchdog(struct ifnet *ifp)
! 1269: {
! 1270: struct an_softc *sc = ifp->if_softc;
! 1271:
! 1272: if (!sc->sc_enabled)
! 1273: return;
! 1274:
! 1275: if (sc->sc_tx_timer) {
! 1276: if (--sc->sc_tx_timer == 0) {
! 1277: printf("%s: device timeout\n", ifp->if_xname);
! 1278: ifp->if_oerrors++;
! 1279: an_init(ifp);
! 1280: return;
! 1281: }
! 1282: ifp->if_timer = 1;
! 1283: }
! 1284: ieee80211_watchdog(ifp);
! 1285: }
! 1286:
! 1287: void
! 1288: an_shutdown(void *self)
! 1289: {
! 1290: struct an_softc *sc = (struct an_softc *)self;
! 1291:
! 1292: if (sc->sc_attached)
! 1293: an_stop(&sc->sc_ic.ic_if, 1);
! 1294: }
! 1295:
! 1296: /* TBD factor with ieee80211_media_change */
! 1297: int
! 1298: an_media_change(struct ifnet *ifp)
! 1299: {
! 1300: struct an_softc *sc = ifp->if_softc;
! 1301: struct ieee80211com *ic = &sc->sc_ic;
! 1302: struct ifmedia_entry *ime;
! 1303: enum ieee80211_opmode newmode;
! 1304: int i, rate, error = 0;
! 1305:
! 1306: ime = ic->ic_media.ifm_cur;
! 1307: if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) {
! 1308: i = -1;
! 1309: } else {
! 1310: struct ieee80211_rateset *rs =
! 1311: &ic->ic_sup_rates[IEEE80211_MODE_11B];
! 1312: rate = ieee80211_media2rate(ime->ifm_media);
! 1313: if (rate == 0)
! 1314: return EINVAL;
! 1315: for (i = 0; i < rs->rs_nrates; i++) {
! 1316: if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rate)
! 1317: break;
! 1318: }
! 1319: if (i == rs->rs_nrates)
! 1320: return EINVAL;
! 1321: }
! 1322: if (ic->ic_fixed_rate != i) {
! 1323: ic->ic_fixed_rate = i;
! 1324: error = ENETRESET;
! 1325: }
! 1326:
! 1327: if (ime->ifm_media & IFM_IEEE80211_ADHOC)
! 1328: newmode = IEEE80211_M_IBSS;
! 1329: else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
! 1330: newmode = IEEE80211_M_HOSTAP;
! 1331: else if (ime->ifm_media & IFM_IEEE80211_MONITOR)
! 1332: newmode = IEEE80211_M_MONITOR;
! 1333: else
! 1334: newmode = IEEE80211_M_STA;
! 1335: if (ic->ic_opmode != newmode) {
! 1336: ic->ic_opmode = newmode;
! 1337: error = ENETRESET;
! 1338: }
! 1339: if (error == ENETRESET) {
! 1340: if (sc->sc_enabled)
! 1341: error = an_init(ifp);
! 1342: else
! 1343: error = 0;
! 1344: }
! 1345: ifp->if_baudrate = ifmedia_baudrate(ic->ic_media.ifm_cur->ifm_media);
! 1346:
! 1347: return error;
! 1348: }
! 1349:
! 1350: void
! 1351: an_media_status(struct ifnet *ifp, struct ifmediareq *imr)
! 1352: {
! 1353: struct an_softc *sc = ifp->if_softc;
! 1354: struct ieee80211com *ic = &sc->sc_ic;
! 1355: int rate, buflen;
! 1356:
! 1357: if (sc->sc_enabled == 0) {
! 1358: imr->ifm_active = IFM_IEEE80211 | IFM_NONE;
! 1359: imr->ifm_status = 0;
! 1360: return;
! 1361: }
! 1362:
! 1363: imr->ifm_status = IFM_AVALID;
! 1364: imr->ifm_active = IFM_IEEE80211;
! 1365: if (ic->ic_state == IEEE80211_S_RUN)
! 1366: imr->ifm_status |= IFM_ACTIVE;
! 1367: buflen = sizeof(sc->sc_buf);
! 1368: if (ic->ic_fixed_rate != -1)
! 1369: rate = ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
! 1370: ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
! 1371: else if (an_read_rid(sc, AN_RID_STATUS, &sc->sc_buf, &buflen) != 0)
! 1372: rate = 0;
! 1373: else
! 1374: rate = sc->sc_buf.sc_status.an_current_tx_rate;
! 1375: imr->ifm_active |= ieee80211_rate2media(ic, rate, IEEE80211_MODE_11B);
! 1376: switch (ic->ic_opmode) {
! 1377: case IEEE80211_M_STA:
! 1378: break;
! 1379: case IEEE80211_M_IBSS:
! 1380: imr->ifm_active |= IFM_IEEE80211_ADHOC;
! 1381: break;
! 1382: case IEEE80211_M_HOSTAP:
! 1383: imr->ifm_active |= IFM_IEEE80211_HOSTAP;
! 1384: break;
! 1385: case IEEE80211_M_MONITOR:
! 1386: imr->ifm_active |= IFM_IEEE80211_MONITOR;
! 1387: break;
! 1388: default:
! 1389: break;
! 1390: }
! 1391: }
! 1392:
! 1393: int
! 1394: an_set_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
! 1395: {
! 1396: int error;
! 1397: struct ieee80211com *ic = &sc->sc_ic;
! 1398: u_int16_t prevauth;
! 1399:
! 1400: error = 0;
! 1401: prevauth = sc->sc_config.an_authtype;
! 1402:
! 1403: switch (nwkey->i_wepon) {
! 1404: case IEEE80211_NWKEY_OPEN:
! 1405: sc->sc_config.an_authtype = AN_AUTHTYPE_OPEN;
! 1406: ic->ic_flags &= ~IEEE80211_F_WEPON;
! 1407: break;
! 1408:
! 1409: case IEEE80211_NWKEY_WEP:
! 1410: case IEEE80211_NWKEY_WEP | IEEE80211_NWKEY_PERSIST:
! 1411: error = an_set_nwkey_wep(sc, nwkey);
! 1412: if (error == 0 || error == ENETRESET) {
! 1413: sc->sc_config.an_authtype =
! 1414: AN_AUTHTYPE_OPEN | AN_AUTHTYPE_PRIVACY_IN_USE;
! 1415: ic->ic_flags |= IEEE80211_F_WEPON;
! 1416: }
! 1417: break;
! 1418:
! 1419: default:
! 1420: error = EINVAL;
! 1421: break;
! 1422: }
! 1423: if (error == 0 && prevauth != sc->sc_config.an_authtype)
! 1424: error = ENETRESET;
! 1425: return error;
! 1426: }
! 1427:
! 1428: int
! 1429: an_set_nwkey_wep(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
! 1430: {
! 1431: int i, txkey, anysetkey, needreset, error;
! 1432: struct an_wepkey keys[IEEE80211_WEP_NKID];
! 1433:
! 1434: error = 0;
! 1435: memset(keys, 0, sizeof(keys));
! 1436: anysetkey = needreset = 0;
! 1437:
! 1438: /* load argument and sanity check */
! 1439: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
! 1440: keys[i].an_wep_keylen = nwkey->i_key[i].i_keylen;
! 1441: if (keys[i].an_wep_keylen < 0)
! 1442: continue;
! 1443: if (keys[i].an_wep_keylen != 0 &&
! 1444: keys[i].an_wep_keylen < IEEE80211_WEP_KEYLEN)
! 1445: return EINVAL;
! 1446: if (keys[i].an_wep_keylen > sizeof(keys[i].an_wep_key))
! 1447: return EINVAL;
! 1448: if ((error = copyin(nwkey->i_key[i].i_keydat,
! 1449: keys[i].an_wep_key, keys[i].an_wep_keylen)) != 0)
! 1450: return error;
! 1451: anysetkey++;
! 1452: }
! 1453: txkey = nwkey->i_defkid - 1;
! 1454: if (txkey >= 0) {
! 1455: if (txkey >= IEEE80211_WEP_NKID)
! 1456: return EINVAL;
! 1457: /* default key must have a valid value */
! 1458: if (keys[txkey].an_wep_keylen == 0 ||
! 1459: (keys[txkey].an_wep_keylen < 0 &&
! 1460: sc->sc_perskeylen[txkey] == 0))
! 1461: return EINVAL;
! 1462: anysetkey++;
! 1463: }
! 1464: DPRINTF(("an_set_nwkey_wep: %s: %sold(%d:%d,%d,%d,%d) "
! 1465: "pers(%d:%d,%d,%d,%d) new(%d:%d,%d,%d,%d)\n",
! 1466: sc->sc_dev.dv_xname,
! 1467: ((nwkey->i_wepon & IEEE80211_NWKEY_PERSIST) ? "persist: " : ""),
! 1468: sc->sc_tx_key,
! 1469: sc->sc_wepkeys[0].an_wep_keylen, sc->sc_wepkeys[1].an_wep_keylen,
! 1470: sc->sc_wepkeys[2].an_wep_keylen, sc->sc_wepkeys[3].an_wep_keylen,
! 1471: sc->sc_tx_perskey,
! 1472: sc->sc_perskeylen[0], sc->sc_perskeylen[1],
! 1473: sc->sc_perskeylen[2], sc->sc_perskeylen[3],
! 1474: txkey,
! 1475: keys[0].an_wep_keylen, keys[1].an_wep_keylen,
! 1476: keys[2].an_wep_keylen, keys[3].an_wep_keylen));
! 1477: if (!(nwkey->i_wepon & IEEE80211_NWKEY_PERSIST)) {
! 1478: /* set temporary keys */
! 1479: sc->sc_tx_key = txkey;
! 1480: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
! 1481: if (keys[i].an_wep_keylen < 0)
! 1482: continue;
! 1483: memcpy(&sc->sc_wepkeys[i], &keys[i], sizeof(keys[i]));
! 1484: }
! 1485: } else {
! 1486: /* set persist keys */
! 1487: if (anysetkey) {
! 1488: /* prepare to write nvram */
! 1489: if (!sc->sc_enabled) {
! 1490: if (sc->sc_enable)
! 1491: (*sc->sc_enable)(sc);
! 1492: an_wait(sc);
! 1493: sc->sc_enabled = 1;
! 1494: error = an_write_wepkey(sc,
! 1495: AN_RID_WEP_PERSISTENT, keys, txkey);
! 1496: if (sc->sc_disable)
! 1497: (*sc->sc_disable)(sc);
! 1498: sc->sc_enabled = 0;
! 1499: } else {
! 1500: an_cmd(sc, AN_CMD_DISABLE, 0);
! 1501: error = an_write_wepkey(sc,
! 1502: AN_RID_WEP_PERSISTENT, keys, txkey);
! 1503: an_cmd(sc, AN_CMD_ENABLE, 0);
! 1504: }
! 1505: if (error)
! 1506: return error;
! 1507: }
! 1508: if (txkey >= 0)
! 1509: sc->sc_tx_perskey = txkey;
! 1510: if (sc->sc_tx_key >= 0) {
! 1511: sc->sc_tx_key = -1;
! 1512: needreset++;
! 1513: }
! 1514: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
! 1515: if (sc->sc_wepkeys[i].an_wep_keylen >= 0) {
! 1516: memset(&sc->sc_wepkeys[i].an_wep_key, 0,
! 1517: sizeof(sc->sc_wepkeys[i].an_wep_key));
! 1518: sc->sc_wepkeys[i].an_wep_keylen = -1;
! 1519: needreset++;
! 1520: }
! 1521: if (keys[i].an_wep_keylen >= 0)
! 1522: sc->sc_perskeylen[i] = keys[i].an_wep_keylen;
! 1523: }
! 1524: }
! 1525: if (needreset) {
! 1526: /* firmware restart to reload persistent key */
! 1527: an_reset(sc);
! 1528: }
! 1529: if (anysetkey || needreset)
! 1530: error = ENETRESET;
! 1531: return error;
! 1532: }
! 1533:
! 1534: int
! 1535: an_get_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
! 1536: {
! 1537: int i, error;
! 1538:
! 1539: error = 0;
! 1540: if (sc->sc_config.an_authtype & AN_AUTHTYPE_LEAP)
! 1541: nwkey->i_wepon = IEEE80211_NWKEY_EAP;
! 1542: else if (sc->sc_config.an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE)
! 1543: nwkey->i_wepon = IEEE80211_NWKEY_WEP;
! 1544: else
! 1545: nwkey->i_wepon = IEEE80211_NWKEY_OPEN;
! 1546: if (sc->sc_tx_key == -1)
! 1547: nwkey->i_defkid = sc->sc_tx_perskey + 1;
! 1548: else
! 1549: nwkey->i_defkid = sc->sc_tx_key + 1;
! 1550: if (nwkey->i_key[0].i_keydat == NULL)
! 1551: return 0;
! 1552: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
! 1553: if (nwkey->i_key[i].i_keydat == NULL)
! 1554: continue;
! 1555: /* do not show any keys to non-root user */
! 1556: if ((error = suser(curproc, 0)) != 0)
! 1557: break;
! 1558: nwkey->i_key[i].i_keylen = sc->sc_wepkeys[i].an_wep_keylen;
! 1559: if (nwkey->i_key[i].i_keylen < 0) {
! 1560: if (sc->sc_perskeylen[i] == 0)
! 1561: nwkey->i_key[i].i_keylen = 0;
! 1562: continue;
! 1563: }
! 1564: if ((error = copyout(sc->sc_wepkeys[i].an_wep_key,
! 1565: nwkey->i_key[i].i_keydat,
! 1566: sc->sc_wepkeys[i].an_wep_keylen)) != 0)
! 1567: break;
! 1568: }
! 1569: return error;
! 1570: }
! 1571:
! 1572: int
! 1573: an_write_wepkey(struct an_softc *sc, int type, struct an_wepkey *keys, int kid)
! 1574: {
! 1575: int i, error;
! 1576: struct an_rid_wepkey *akey;
! 1577:
! 1578: error = 0;
! 1579: akey = &sc->sc_buf.sc_wepkey;
! 1580: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
! 1581: memset(akey, 0, sizeof(struct an_rid_wepkey));
! 1582: if (keys[i].an_wep_keylen < 0 ||
! 1583: keys[i].an_wep_keylen > sizeof(akey->an_key))
! 1584: continue;
! 1585: akey->an_key_len = keys[i].an_wep_keylen;
! 1586: akey->an_key_index = i;
! 1587: akey->an_mac_addr[0] = 1; /* default mac */
! 1588: an_swap16((u_int16_t *)&akey->an_mac_addr, 3);
! 1589: memcpy(akey->an_key, keys[i].an_wep_key, keys[i].an_wep_keylen);
! 1590: an_swap16((u_int16_t *)&akey->an_key, 8);
! 1591: if ((error = an_write_rid(sc, type, akey, sizeof(*akey))) != 0)
! 1592: return error;
! 1593: }
! 1594: if (kid >= 0) {
! 1595: memset(akey, 0, sizeof(struct an_rid_wepkey));
! 1596: akey->an_key_index = 0xffff;
! 1597: akey->an_mac_addr[0] = kid;
! 1598: an_swap16((u_int16_t *)&akey->an_mac_addr, 3);
! 1599: akey->an_key_len = 0;
! 1600: memset(akey->an_key, 0, sizeof(akey->an_key));
! 1601: error = an_write_rid(sc, type, akey, sizeof(*akey));
! 1602: }
! 1603: return error;
! 1604: }
! 1605:
! 1606: int
! 1607: an_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
! 1608: {
! 1609: struct an_softc *sc = ic->ic_softc;
! 1610: struct ieee80211_node *ni = ic->ic_bss;
! 1611: enum ieee80211_state ostate;
! 1612: int buflen;
! 1613:
! 1614: ostate = ic->ic_state;
! 1615: DPRINTF(("an_newstate: %s -> %s\n", ieee80211_state_name[ostate],
! 1616: ieee80211_state_name[nstate]));
! 1617:
! 1618: switch (nstate) {
! 1619: case IEEE80211_S_INIT:
! 1620: ic->ic_flags &= ~IEEE80211_F_IBSSON;
! 1621: return (*sc->sc_newstate)(ic, nstate, arg);
! 1622:
! 1623: case IEEE80211_S_RUN:
! 1624: buflen = sizeof(sc->sc_buf);
! 1625: an_read_rid(sc, AN_RID_STATUS, &sc->sc_buf, &buflen);
! 1626: an_swap16((u_int16_t *)&sc->sc_buf.sc_status.an_cur_bssid, 3);
! 1627: an_swap16((u_int16_t *)&sc->sc_buf.sc_status.an_ssid, 16);
! 1628: IEEE80211_ADDR_COPY(ni->ni_bssid,
! 1629: sc->sc_buf.sc_status.an_cur_bssid);
! 1630: IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid);
! 1631: ni->ni_chan = &ic->ic_channels[
! 1632: sc->sc_buf.sc_status.an_cur_channel];
! 1633: ni->ni_esslen = sc->sc_buf.sc_status.an_ssidlen;
! 1634: if (ni->ni_esslen > IEEE80211_NWID_LEN)
! 1635: ni->ni_esslen = IEEE80211_NWID_LEN; /*XXX*/
! 1636: memcpy(ni->ni_essid, sc->sc_buf.sc_status.an_ssid,
! 1637: ni->ni_esslen);
! 1638: ni->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B]; /*XXX*/
! 1639: if (ic->ic_if.if_flags & IFF_DEBUG) {
! 1640: printf("%s: ", sc->sc_dev.dv_xname);
! 1641: if (ic->ic_opmode == IEEE80211_M_STA)
! 1642: printf("associated ");
! 1643: else
! 1644: printf("synchronized ");
! 1645: printf("with %s ssid ", ether_sprintf(ni->ni_bssid));
! 1646: ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
! 1647: printf(" channel %u start %uMb\n",
! 1648: sc->sc_buf.sc_status.an_cur_channel,
! 1649: sc->sc_buf.sc_status.an_current_tx_rate/2);
! 1650: }
! 1651: break;
! 1652:
! 1653: default:
! 1654: break;
! 1655: }
! 1656: ic->ic_state = nstate;
! 1657: /* skip standard ieee80211 handling */
! 1658: return 0;
! 1659: }
! 1660:
! 1661: int
! 1662: an_detach(struct an_softc *sc)
! 1663: {
! 1664: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 1665: int s;
! 1666:
! 1667: if (!sc->sc_attached)
! 1668: return 0;
! 1669:
! 1670: s = splnet();
! 1671: sc->sc_invalid = 1;
! 1672: an_stop(ifp, 1);
! 1673: ifmedia_delete_instance(&sc->sc_ic.ic_media, IFM_INST_ANY);
! 1674: ieee80211_ifdetach(ifp);
! 1675: if_detach(ifp);
! 1676: if (sc->sc_sdhook != NULL)
! 1677: shutdownhook_disestablish(sc->sc_sdhook);
! 1678: splx(s);
! 1679: return 0;
! 1680: }
! 1681:
CVSweb