diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 2000-08-17 16:16:32 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 2000-08-17 16:16:32 +0000 |
commit | 9372b87e9b3753b4321c4fd1e64a830b6f7d6cfa (patch) | |
tree | 56a20bc794fdf2d7200ab90ebee5a81a03ad80fd /sys/dev | |
parent | a5bdafd3e77273d8bbb56ae6eabd33da49eac255 (diff) |
replace if_awi w/ semi-current netbsd driver; still has problems
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/ic/am79c930.c | 181 | ||||
-rw-r--r-- | sys/dev/ic/am79c930reg.h | 254 | ||||
-rw-r--r-- | sys/dev/ic/am79c930var.h | 3 | ||||
-rw-r--r-- | sys/dev/ic/awi.c | 4550 | ||||
-rw-r--r-- | sys/dev/ic/awi_wep.c | 535 | ||||
-rw-r--r-- | sys/dev/ic/awireg.h | 443 | ||||
-rw-r--r-- | sys/dev/ic/awivar.h | 278 | ||||
-rw-r--r-- | sys/dev/pcmcia/files.pcmcia | 11 | ||||
-rw-r--r-- | sys/dev/pcmcia/if_awi_pcmcia.c | 361 |
9 files changed, 3611 insertions, 3005 deletions
diff --git a/sys/dev/ic/am79c930.c b/sys/dev/ic/am79c930.c index 4e8a524c08c..739d0d48078 100644 --- a/sys/dev/ic/am79c930.c +++ b/sys/dev/ic/am79c930.c @@ -1,5 +1,4 @@ -/* $NetBSD: am79c930.c,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */ -/* $OpenBSD: am79c930.c,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */ +/* $NetBSD: am79c930.c,v 1.5 2000/03/23 13:57:58 onoe Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -63,17 +62,30 @@ #include <sys/param.h> #include <sys/systm.h> -#include <sys/kernel.h> +#ifndef __FreeBSD__ #include <sys/device.h> +#endif #include <machine/cpu.h> +#ifdef __FreeBSD__ +#include <machine/bus_pio.h> +#include <machine/bus_memio.h> +#endif #include <machine/bus.h> +#ifdef __NetBSD__ #include <machine/intr.h> +#endif +#if defined(__NetBSD__) || defined(__OpenBSD__) #include <dev/ic/am79c930reg.h> #include <dev/ic/am79c930var.h> +#endif +#ifdef __FreeBSD__ +#include <dev/awi/am79c930reg.h> +#include <dev/awi/am79c930var.h> +#endif -#define AM930_DELAY(x) /*nothing*/; +#define AM930_DELAY(x) /*nothing*/ void am79c930_regdump __P((struct am79c930_softc *sc)); @@ -124,7 +136,6 @@ static void io_write_1 (sc, off, val) u_int32_t off; u_int8_t val; { - /* XXX bank-switching? */ AM930_DELAY(1); bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, ((off>>8)& 0x7f)); @@ -140,8 +151,16 @@ static void io_write_2 (sc, off, val) u_int32_t off; u_int16_t val; { - io_write_1(sc, off, val & 0xff); - io_write_1(sc, off+1, (val >> 8) & 0xff); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, + ((off>>8)& 0x7f)); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_LMA_LO, (off&0xff)); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA, val & 0xff); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA, (val>>8)&0xff); + AM930_DELAY(1); } static void io_write_4 (sc, off, val) @@ -149,11 +168,20 @@ static void io_write_4 (sc, off, val) u_int32_t off; u_int32_t val; { - /* XXX higher offset values needed for bank-switching! */ - io_write_1(sc, off, val & 0xff); - io_write_1(sc, off+1, (val >> 8) & 0xff); - io_write_1(sc, off+2, (val >> 16) & 0xff); - io_write_1(sc, off+3, (val >> 24) & 0xff); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, + ((off>>8)& 0x7f)); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_LMA_LO, (off&0xff)); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA,val & 0xff); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA,(val>>8)&0xff); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA,(val>>16)&0xff); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA,(val>>24)&0xff); + AM930_DELAY(1); } static void io_write_bytes (sc, off, ptr, len) @@ -163,10 +191,15 @@ static void io_write_bytes (sc, off, ptr, len) size_t len; { int i; - /* XXX higher offset values needed for bank-switching! */ - + + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, + ((off>>8)& 0x7f)); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_LMA_LO, (off&0xff)); + AM930_DELAY(1); for (i=0; i<len; i++) - io_write_1 (sc, off+i, ptr[i]); + bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA,ptr[i]); } static u_int8_t io_read_1 (sc, off) @@ -189,19 +222,40 @@ static u_int16_t io_read_2 (sc, off) struct am79c930_softc *sc; u_int32_t off; { - return io_read_1 (sc, off) | - (io_read_1 (sc, off+1) << 8); + u_int16_t val; + + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, + ((off>>8)& 0x7f)); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_LO, (off&0xff)); + AM930_DELAY(1); + val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA); + AM930_DELAY(1); + val |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA) << 8; + AM930_DELAY(1); + return val; } static u_int32_t io_read_4 (sc, off) struct am79c930_softc *sc; u_int32_t off; { - /* XXX bank-switching? */ - return io_read_1 (sc, off) | - (io_read_1 (sc, off+1) << 8) | - (io_read_1 (sc, off+2) << 16) | - (io_read_1 (sc, off+3) << 24); + u_int32_t val; + + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, + ((off>>8)& 0x7f)); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_LO, (off&0xff)); + AM930_DELAY(1); + val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA); + AM930_DELAY(1); + val |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA) << 8; + AM930_DELAY(1); + val |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA) << 16; + AM930_DELAY(1); + val |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA) << 24; + AM930_DELAY(1); + return val; } static void io_read_bytes (sc, off, ptr, len) @@ -212,18 +266,21 @@ static void io_read_bytes (sc, off, ptr, len) { int i; + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, + ((off>>8)& 0x7f)); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_LO, (off&0xff)); + AM930_DELAY(1); for (i=0; i<len; i++) - ptr[i] = io_read_1(sc, off+i); + ptr[i] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, + AM79C930_IODPA); } - - static void mem_write_1 (sc, off, val) struct am79c930_softc *sc; u_int32_t off; u_int8_t val; { - /* XXX higher offset values needed for bank-switching! */ bus_space_write_1(sc->sc_memt, sc->sc_memh, off, val); } @@ -232,9 +289,16 @@ static void mem_write_2 (sc, off, val) u_int32_t off; u_int16_t val; { - /* XXX higher offset values needed for bank-switching! */ - bus_space_write_1(sc->sc_memt, sc->sc_memh, off, val & 0xff); - bus_space_write_1(sc->sc_memt, sc->sc_memh, off+1, (val >> 8) & 0xff); + bus_space_tag_t t = sc->sc_memt; + bus_space_handle_t h = sc->sc_memh; + + /* could be unaligned */ + if ((off & 0x1) == 0) + bus_space_write_2(t, h, off, val); + else { + bus_space_write_1(t, h, off, val & 0xff); + bus_space_write_1(t, h, off+1, (val >> 8) & 0xff); + } } static void mem_write_4 (sc, off, val) @@ -242,11 +306,18 @@ static void mem_write_4 (sc, off, val) u_int32_t off; u_int32_t val; { - /* XXX higher offset values needed for bank-switching! */ - bus_space_write_1(sc->sc_memt, sc->sc_memh, off, val & 0xff); - bus_space_write_1(sc->sc_memt, sc->sc_memh, off+1, (val >> 8) & 0xff); - bus_space_write_1(sc->sc_memt, sc->sc_memh, off+2, (val >> 16) & 0xff); - bus_space_write_1(sc->sc_memt, sc->sc_memh, off+3, (val >> 24) & 0xff); + bus_space_tag_t t = sc->sc_memt; + bus_space_handle_t h = sc->sc_memh; + + /* could be unaligned */ + if ((off & 0x3) == 0) + bus_space_write_4(t, h, off, val); + else { + bus_space_write_1(t, h, off, val & 0xff); + bus_space_write_1(t, h, off+1, (val >> 8) & 0xff); + bus_space_write_1(t, h, off+2, (val >> 16) & 0xff); + bus_space_write_1(t, h, off+3, (val >> 24) & 0xff); + } } static void mem_write_bytes (sc, off, ptr, len) @@ -255,11 +326,7 @@ static void mem_write_bytes (sc, off, ptr, len) u_int8_t *ptr; size_t len; { - int i; - /* XXX higher offset values needed for bank-switching! */ - - for (i=0; i<len; i++) - bus_space_write_1 (sc->sc_memt, sc->sc_memh, off+i, ptr[i]); + bus_space_write_region_1 (sc->sc_memt, sc->sc_memh, off, ptr, len); } @@ -267,7 +334,6 @@ static u_int8_t mem_read_1 (sc, off) struct am79c930_softc *sc; u_int32_t off; { - /* XXX higher offset values needed for bank-switching! */ return bus_space_read_1(sc->sc_memt, sc->sc_memh, off); } @@ -275,22 +341,28 @@ static u_int16_t mem_read_2 (sc, off) struct am79c930_softc *sc; u_int32_t off; { - /* XXX higher offset values needed for bank-switching! */ - return - bus_space_read_1(sc->sc_memt, sc->sc_memh, off) | - (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+1) <<8); + /* could be unaligned */ + if ((off & 0x1) == 0) + return bus_space_read_2(sc->sc_memt, sc->sc_memh, off); + else + return + bus_space_read_1(sc->sc_memt, sc->sc_memh, off ) | + (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+1) << 8); } static u_int32_t mem_read_4 (sc, off) struct am79c930_softc *sc; u_int32_t off; { - /* XXX higher offset values needed for bank-switching! */ - return - bus_space_read_1(sc->sc_memt, sc->sc_memh, off) | - (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+1) <<8)| - (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+2) <<16) | - (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+3) <<24); + /* could be unaligned */ + if ((off & 0x3) == 0) + return bus_space_read_4(sc->sc_memt, sc->sc_memh, off); + else + return + bus_space_read_1(sc->sc_memt, sc->sc_memh, off ) | + (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+1) << 8) | + (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+2) <<16) | + (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+3) <<24); } @@ -301,12 +373,7 @@ static void mem_read_bytes (sc, off, ptr, len) u_int8_t *ptr; size_t len; { - int i; - - /* XXX higher offset values needed for bank-switching! */ - - for (i=0; i<len; i++) - ptr[i] = bus_space_read_1(sc->sc_memt, sc->sc_memh, off+i); + bus_space_read_region_1 (sc->sc_memt, sc->sc_memh, off, ptr, len); } @@ -378,3 +445,5 @@ void am79c930_chip_init (sc, how) else sc->sc_ops = &iospace_ops; } + + diff --git a/sys/dev/ic/am79c930reg.h b/sys/dev/ic/am79c930reg.h index 9dfcd537086..8441f0f9961 100644 --- a/sys/dev/ic/am79c930reg.h +++ b/sys/dev/ic/am79c930reg.h @@ -1,255 +1,4 @@ -/* $NetBSD: am79c930reg.h,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */ -/* $OpenBSD: am79c930reg.h,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */ - -/*- - * Copyright (c) 1999 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Bill Sommerfeld - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Device register definitions gleaned from from the AMD "Am79C930 - * PCnet(tm)-Mobile Single Chip Wireless LAN Media Access Controller" - * data sheet, AMD Pub #20183, Rev B, amendment/0, issue date August 1997. - * - * As of 1999/10/23, this was available from AMD's web site in PDF - * form. - */ - - -/* - * The 79c930 contains a bus interface unit, a media access - * controller, and a tranceiver attachment interface. - * The MAC contains an 80188 CPU core. - * typical devices built around this chip typically add 32k or 64k of - * memory for buffers. - * - * The 80188 runs firmware which handles most of the 802.11 gorp, and - * communicates with the host using shared data structures in this - * memory; the specifics of the shared memory layout are not covered - * in this source file; see <dev/ic/am80211fw.h> for details of that layer. - */ - -/* - * Device Registers - */ - -#define AM79C930_IO_BASE 0 -#define AM79C930_IO_SIZE 16 -#define AM79C930_IO_SIZE_BIG 40 - - -#define AM79C930_GCR 0 /* General Config Register */ - -#define AM79C930_GCR_SWRESET 0x80 /* software reset */ -#define AM79C930_GCR_CORESET 0x40 /* core reset */ -#define AM79C930_GCR_DISPWDN 0x20 /* disable powerdown */ -#define AM79C930_GCR_ECWAIT 0x10 /* embedded controller wait */ -#define AM79C930_GCR_ECINT 0x08 /* interrupt from embedded ctrlr */ -#define AM79C930_GCR_INT2EC 0x04 /* interrupt to embedded ctrlr */ -#define AM79C930_GCR_ENECINT 0x02 /* enable interrupts from e.c. */ -#define AM79C930_GCR_DAM 0x01 /* direct access mode (read only) */ - -#define AM79C930_GCR_BITS "\020\1DAM\2ENECINT\3INT2EC\4ECINT\5ECWAIT\6DISPWDN\7CORESET\010SWRESET" - -#define AM79C930_BSS 1 /* Bank Switching Select register */ - -#define AM79C930_BSS_ECATR 0x80 /* E.C. ALE test read */ -#define AM79C930_BSS_FS 0x20 /* Flash Select */ -#define AM79C930_BSS_MBS 0x18 /* Memory Bank Select */ -#define AM79C930_BSS_EIOW 0x04 /* Expand I/O Window */ -#define AM79C930_BSS_TBS 0x03 /* TAI Bank Select */ - -#define AM79C930_LMA_LO 2 /* Local Memory Address register (low byte) */ - -#define AM79C930_LMA_HI 3 /* Local Memory Address register (high byte) */ - - /* set this bit to turn off ISAPnP version */ -#define AM79C930_LMA_HI_ISAPWRDWN 0x80 - -/* - * mmm, inconsistancy in chip documentation: - * According to page 79--80, all four of the following are equivalent - * and address the single byte pointed at by BSS_{FS,MBS} | LMA_{HI,LO} - * According to tables on p63 and p67, they're the LSB through MSB - * of a 32-bit word. - */ - -#define AM79C930_IODPA 4 /* I/O Data port A */ -#define AM79C930_IODPB 5 /* I/O Data port B */ -#define AM79C930_IODPC 6 /* I/O Data port C */ -#define AM79C930_IODPD 7 /* I/O Data port D */ - - -/* - * Tranceiver Attachment Interface Registers (TIR space) - * (omitted for now, since host access to them is for diagnostic - * purposes only). - */ - -/* - * memory space goo. - */ - -#define AM79C930_MEM_SIZE 0x8000 /* 32k */ -#define AM79C930_MEM_BASE 0x0 /* starting at 0 */ -/* $NetBSD: am79c930reg.h,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */ -/* $OpenBSD: am79c930reg.h,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */ - -/*- - * Copyright (c) 1999 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Bill Sommerfeld - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Device register definitions gleaned from from the AMD "Am79C930 - * PCnet(tm)-Mobile Single Chip Wireless LAN Media Access Controller" - * data sheet, AMD Pub #20183, Rev B, amendment/0, issue date August 1997. - * - * As of 1999/10/23, this was available from AMD's web site in PDF - * form. - */ - - -/* - * The 79c930 contains a bus interface unit, a media access - * controller, and a tranceiver attachment interface. - * The MAC contains an 80188 CPU core. - * typical devices built around this chip typically add 32k or 64k of - * memory for buffers. - * - * The 80188 runs firmware which handles most of the 802.11 gorp, and - * communicates with the host using shared data structures in this - * memory; the specifics of the shared memory layout are not covered - * in this source file; see <dev/ic/am80211fw.h> for details of that layer. - */ - -/* - * Device Registers - */ - -#define AM79C930_IO_BASE 0 -#define AM79C930_IO_SIZE 16 -#define AM79C930_IO_SIZE_BIG 40 - - -#define AM79C930_GCR 0 /* General Config Register */ - -#define AM79C930_GCR_SWRESET 0x80 /* software reset */ -#define AM79C930_GCR_CORESET 0x40 /* core reset */ -#define AM79C930_GCR_DISPWDN 0x20 /* disable powerdown */ -#define AM79C930_GCR_ECWAIT 0x10 /* embedded controller wait */ -#define AM79C930_GCR_ECINT 0x08 /* interrupt from embedded ctrlr */ -#define AM79C930_GCR_INT2EC 0x04 /* interrupt to embedded ctrlr */ -#define AM79C930_GCR_ENECINT 0x02 /* enable interrupts from e.c. */ -#define AM79C930_GCR_DAM 0x01 /* direct access mode (read only) */ - -#define AM79C930_GCR_BITS "\020\1DAM\2ENECINT\3INT2EC\4ECINT\5ECWAIT\6DISPWDN\7CORESET\010SWRESET" - -#define AM79C930_BSS 1 /* Bank Switching Select register */ - -#define AM79C930_BSS_ECATR 0x80 /* E.C. ALE test read */ -#define AM79C930_BSS_FS 0x20 /* Flash Select */ -#define AM79C930_BSS_MBS 0x18 /* Memory Bank Select */ -#define AM79C930_BSS_EIOW 0x04 /* Expand I/O Window */ -#define AM79C930_BSS_TBS 0x03 /* TAI Bank Select */ - -#define AM79C930_LMA_LO 2 /* Local Memory Address register (low byte) */ - -#define AM79C930_LMA_HI 3 /* Local Memory Address register (high byte) */ - - /* set this bit to turn off ISAPnP version */ -#define AM79C930_LMA_HI_ISAPWRDWN 0x80 - -/* - * mmm, inconsistancy in chip documentation: - * According to page 79--80, all four of the following are equivalent - * and address the single byte pointed at by BSS_{FS,MBS} | LMA_{HI,LO} - * According to tables on p63 and p67, they're the LSB through MSB - * of a 32-bit word. - */ - -#define AM79C930_IODPA 4 /* I/O Data port A */ -#define AM79C930_IODPB 5 /* I/O Data port B */ -#define AM79C930_IODPC 6 /* I/O Data port C */ -#define AM79C930_IODPD 7 /* I/O Data port D */ - - -/* - * Tranceiver Attachment Interface Registers (TIR space) - * (omitted for now, since host access to them is for diagnostic - * purposes only). - */ - -/* - * memory space goo. - */ - -#define AM79C930_MEM_SIZE 0x8000 /* 32k */ -#define AM79C930_MEM_BASE 0x0 /* starting at 0 */ -/* $NetBSD: am79c930reg.h,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */ -/* $OpenBSD: am79c930reg.h,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */ +/* $NetBSD$ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -317,6 +66,7 @@ #define AM79C930_IO_BASE 0 #define AM79C930_IO_SIZE 16 #define AM79C930_IO_SIZE_BIG 40 +#define AM79C930_IO_ALIGN 0x40 /* am79c930 decodes lower 6bits */ #define AM79C930_GCR 0 /* General Config Register */ diff --git a/sys/dev/ic/am79c930var.h b/sys/dev/ic/am79c930var.h index 0d8a221126f..26b4777b0f7 100644 --- a/sys/dev/ic/am79c930var.h +++ b/sys/dev/ic/am79c930var.h @@ -1,5 +1,4 @@ -/* $NetBSD: am79c930var.h,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */ -/* $OpenBSD: am79c930var.h,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */ +/* $NetBSD$ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. diff --git a/sys/dev/ic/awi.c b/sys/dev/ic/awi.c index 97f3b609a10..eeab4b80036 100644 --- a/sys/dev/ic/awi.c +++ b/sys/dev/ic/awi.c @@ -1,5 +1,4 @@ -/* $NetBSD: awi.c,v 1.8 1999/11/09 14:58:07 sommerfeld Exp $ */ -/* $OpenBSD: awi.c,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */ +/* $NetBSD: awi.c,v 1.26 2000/07/21 04:48:55 onoe Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -75,39 +74,70 @@ * - common 802.11 media layer. */ +/* + * Driver for AMD 802.11 PCnetMobile firmware. + * Uses am79c930 chip driver to talk to firmware running on the am79c930. + * + * The initial version of the driver was written by + * Bill Sommerfeld <sommerfeld@netbsd.org>. + * Then the driver module completely rewritten to support cards with DS phy + * and to support adhoc mode by Atsushi Onoe <onoe@netbsd.org> + */ + +#ifndef __OpenBSD__ +#include "opt_inet.h" +#endif +#if defined(__FreeBSD__) && __FreeBSD__ >= 4 +#define NBPFILTER 1 +#elif defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include "bpf.h" +#define NBPFILTER NBPF +#else #include "bpfilter.h" +#endif #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/proc.h> #include <sys/socket.h> -#include <sys/ioctl.h> +#include <sys/sockio.h> #include <sys/errno.h> #include <sys/syslog.h> -#include <sys/select.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 4 +#include <sys/bus.h> +#else #include <sys/device.h> -#if NRND > 0 -#include <sys/rnd.h> #endif #include <net/if.h> #include <net/if_dl.h> +#ifndef __OpenBSD__ +#ifdef __FreeBSD__ +#include <net/ethernet.h> +#else +#include <net/if_ether.h> +#endif +#endif #include <net/if_media.h> +#include <net/if_llc.h> #ifdef INET #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/in_var.h> #include <netinet/ip.h> +#ifdef __NetBSD__ +#include <netinet/if_inarp.h> +#else #include <netinet/if_ether.h> #endif - -#ifdef NS -#include <netns/ns.h> -#include <netns/ns_if.h> #endif +#include <net/if_ieee80211.h> + #if NBPFILTER > 0 #include <net/bpf.h> #include <net/bpfdesc.h> @@ -115,2508 +145,2712 @@ #include <machine/cpu.h> #include <machine/bus.h> +#ifdef __NetBSD__ #include <machine/intr.h> +#endif +#ifdef __FreeBSD__ +#include <machine/clock.h> +#endif +#if defined(__NetBSD__) || defined(__OpenBSD__) #include <dev/ic/am79c930reg.h> #include <dev/ic/am79c930var.h> #include <dev/ic/awireg.h> #include <dev/ic/awivar.h> - -#ifndef ETHER_CRC_LEN -#define ETHER_CRC_LEN 4 +#endif +#ifdef __FreeBSD__ +#include <dev/awi/am79c930reg.h> +#include <dev/awi/am79c930var.h> +#include <dev/awi/awireg.h> +#include <dev/awi/awivar.h> #endif -void awi_insane __P((struct awi_softc *sc)); -int awi_intlock __P((struct awi_softc *sc)); -void awi_intunlock __P((struct awi_softc *sc)); -void awi_intrinit __P((struct awi_softc *sc)); -u_int8_t awi_read_intst __P((struct awi_softc *sc)); -void awi_stop __P((struct awi_softc *sc)); -void awi_flush __P((struct awi_softc *sc)); -void awi_init __P((struct awi_softc *sc)); -void awi_set_mc __P((struct awi_softc *sc)); -void awi_rxint __P((struct awi_softc *)); -void awi_txint __P((struct awi_softc *)); -void awi_tx_packet __P((struct awi_softc *, int, struct mbuf *)); - -void awi_rcv __P((struct awi_softc *, struct mbuf *, u_int32_t, u_int8_t)); -void awi_rcv_mgt __P((struct awi_softc *, struct mbuf *, u_int32_t, u_int8_t)); -void awi_rcv_data __P((struct awi_softc *, struct mbuf *)); -void awi_rcv_ctl __P((struct awi_softc *, struct mbuf *)); - -int awi_enable __P((struct awi_softc *sc)); -void awi_disable __P((struct awi_softc *sc)); - -void awi_zero __P((struct awi_softc *, u_int32_t, u_int32_t)); - -void awi_cmd __P((struct awi_softc *, u_int8_t)); -void awi_cmd_test_if __P((struct awi_softc *)); -void awi_cmd_get_mib __P((struct awi_softc *sc, u_int8_t, u_int8_t, u_int8_t)); -void awi_cmd_txinit __P((struct awi_softc *sc)); -void awi_cmd_scan __P((struct awi_softc *sc)); -void awi_scan_next __P((struct awi_softc *sc)); -void awi_try_sync __P((struct awi_softc *sc)); -void awi_cmd_set_ss __P((struct awi_softc *sc)); -void awi_cmd_set_promisc __P((struct awi_softc *sc)); -void awi_cmd_set_allmulti __P((struct awi_softc *sc)); -void awi_cmd_set_infra __P((struct awi_softc *sc)); -void awi_cmd_set_notap __P((struct awi_softc *sc)); -void awi_cmd_get_myaddr __P((struct awi_softc *sc)); - - -void awi_cmd_scan_done __P((struct awi_softc *sc, u_int8_t)); -void awi_cmd_sync_done __P((struct awi_softc *sc, u_int8_t)); -void awi_cmd_set_ss_done __P((struct awi_softc *sc, u_int8_t)); -void awi_cmd_set_allmulti_done __P((struct awi_softc *sc, u_int8_t)); -void awi_cmd_set_promisc_done __P((struct awi_softc *sc, u_int8_t)); -void awi_cmd_set_infra_done __P((struct awi_softc *sc, u_int8_t)); -void awi_cmd_set_notap_done __P((struct awi_softc *sc, u_int8_t)); -void awi_cmd_get_myaddr_done __P((struct awi_softc *sc, u_int8_t)); - -void awi_reset __P((struct awi_softc *)); -void awi_init_1 __P((struct awi_softc *)); -void awi_init_2 __P((struct awi_softc *, u_int8_t)); -void awi_mibdump __P((struct awi_softc *, u_int8_t)); -void awi_init_read_bufptrs_done __P((struct awi_softc *, u_int8_t)); -void awi_init_4 __P((struct awi_softc *, u_int8_t)); -void awi_init_5 __P((struct awi_softc *, u_int8_t)); -void awi_init_6 __P((struct awi_softc *, u_int8_t)); -void awi_running __P((struct awi_softc *)); - -void awi_init_txdescr __P((struct awi_softc *)); -void awi_init_txd __P((struct awi_softc *, int, int, int, int)); - -void awi_watchdog __P((struct ifnet *)); -void awi_start __P((struct ifnet *)); -int awi_ioctl __P((struct ifnet *, u_long, caddr_t)); -void awi_dump_rxchain __P((struct awi_softc *, char *, u_int32_t *)); - -void awi_send_frame __P((struct awi_softc *, struct mbuf *)); -void awi_send_authreq __P((struct awi_softc *)); -void awi_send_assocreq __P((struct awi_softc *)); -void awi_parse_tlv __P((u_int8_t *base, u_int8_t *end, u_int8_t **vals, u_int8_t *lens, size_t nattr)); - -u_int8_t *awi_add_rates __P((struct awi_softc *, struct mbuf *, u_int8_t *)); -u_int8_t *awi_add_ssid __P((struct awi_softc *, struct mbuf *, u_int8_t *)); -void * awi_init_hdr __P((struct awi_softc *, struct mbuf *, int, int)); - -void awi_hexdump __P((char *tag, u_int8_t *data, int len)); -void awi_card_hexdump __P((struct awi_softc *, char *tag, u_int32_t offset, int len)); - -int awi_drop_output __P((struct ifnet *, struct mbuf *, - struct sockaddr *, struct rtentry *)); -void awi_drop_input __P((struct ifnet *, struct mbuf *)); -struct mbuf *awi_output_kludge __P((struct awi_softc *, struct mbuf *)); -void awi_set_timer __P((struct awi_softc *)); -void awi_restart_scan __P((struct awi_softc *)); - -struct awi_rxd -{ - u_int32_t next; - u_int16_t len; - u_int8_t state, rate, rssi, index; - u_int32_t frame; - u_int32_t rxts; -}; - -void awi_copy_rxd __P((struct awi_softc *, u_int32_t, struct awi_rxd *)); -u_int32_t awi_parse_rxd __P((struct awi_softc *, u_int32_t, struct awi_rxd *)); +static int awi_ioctl __P((struct ifnet *ifp, u_long cmd, caddr_t data)); +#ifdef IFM_IEEE80211 +static int awi_media_rate2opt __P((struct awi_softc *sc, int rate)); +static int awi_media_opt2rate __P((struct awi_softc *sc, int opt)); +static int awi_media_change __P((struct ifnet *ifp)); +static void awi_media_status __P((struct ifnet *ifp, struct ifmediareq *imr)); +#endif +static void awi_watchdog __P((struct ifnet *ifp)); +static void awi_start __P((struct ifnet *ifp)); +static void awi_txint __P((struct awi_softc *sc)); +static struct mbuf * awi_fix_txhdr __P((struct awi_softc *sc, struct mbuf *m0)); +static struct mbuf * awi_fix_rxhdr __P((struct awi_softc *sc, struct mbuf *m0)); +static void awi_input __P((struct awi_softc *sc, struct mbuf *m, u_int32_t rxts, u_int8_t rssi)); +static void awi_rxint __P((struct awi_softc *sc)); +static struct mbuf * awi_devget __P((struct awi_softc *sc, u_int32_t off, u_int16_t len)); +static int awi_init_hw __P((struct awi_softc *sc)); +static int awi_init_mibs __P((struct awi_softc *sc)); +static int awi_init_txrx __P((struct awi_softc *sc)); +static void awi_stop_txrx __P((struct awi_softc *sc)); +static int awi_start_scan __P((struct awi_softc *sc)); +static int awi_next_scan __P((struct awi_softc *sc)); +static void awi_stop_scan __P((struct awi_softc *sc)); +static void awi_recv_beacon __P((struct awi_softc *sc, struct mbuf *m0, u_int32_t rxts, u_int8_t rssi)); +static int awi_set_ss __P((struct awi_softc *sc)); +static void awi_try_sync __P((struct awi_softc *sc)); +static void awi_sync_done __P((struct awi_softc *sc)); +static void awi_send_deauth __P((struct awi_softc *sc)); +static void awi_send_auth __P((struct awi_softc *sc, int seq)); +static void awi_recv_auth __P((struct awi_softc *sc, struct mbuf *m0)); +static void awi_send_asreq __P((struct awi_softc *sc, int reassoc)); +static void awi_recv_asresp __P((struct awi_softc *sc, struct mbuf *m0)); +static int awi_mib __P((struct awi_softc *sc, u_int8_t cmd, u_int8_t mib)); +static int awi_cmd_scan __P((struct awi_softc *sc)); +static int awi_cmd __P((struct awi_softc *sc, u_int8_t cmd)); +static void awi_cmd_done __P((struct awi_softc *sc)); +static int awi_next_txd __P((struct awi_softc *sc, int len, u_int32_t *framep, u_int32_t*ntxdp)); +static int awi_lock __P((struct awi_softc *sc)); +static void awi_unlock __P((struct awi_softc *sc)); +static int awi_intr_lock __P((struct awi_softc *sc)); +static void awi_intr_unlock __P((struct awi_softc *sc)); +static int awi_cmd_wait __P((struct awi_softc *sc)); +static void awi_print_essid __P((u_int8_t *essid)); + +#ifdef AWI_DEBUG +static void awi_dump_pkt __P((struct awi_softc *sc, struct mbuf *m, int rssi)); +int awi_verbose = 0; +int awi_dump = 0; +#define AWI_DUMP_MASK(fc0) (1 << (((fc0) & IEEE80211_FC0_SUBTYPE_MASK) >> 4)) +int awi_dump_mask = AWI_DUMP_MASK(IEEE80211_FC0_SUBTYPE_BEACON); +int awi_dump_hdr = 0; +int awi_dump_len = 28; +#endif -static const u_int8_t snap_magic[] = { 0xaa, 0xaa, 3, 0, 0, 0 }; +#if NBPFILTER > 0 +#define AWI_BPF_NORM 0 +#define AWI_BPF_RAW 1 +#ifdef __FreeBSD__ +#define AWI_BPF_MTAP(sc, m, raw) do { \ + if ((sc)->sc_ifp->if_bpf && (sc)->sc_rawbpf == (raw)) \ + bpf_mtap((sc)->sc_ifp, (m)); \ +} while (0); +#else +#define AWI_BPF_MTAP(sc, m, raw) do { \ + if ((sc)->sc_ifp->if_bpf && (sc)->sc_rawbpf == (raw)) \ + bpf_mtap((sc)->sc_ifp->if_bpf, (m)); \ +} while (0); +#endif +#else +#define AWI_BPF_MTAP(sc, m, raw) +#endif -int awi_scan_keepalive = 10; +#ifndef llc_snap +#define llc_snap llc_un.type_snap +#endif -/* - * attach (called by bus-specific front end) - * - * look for banner message - * wait for selftests to complete (up to 2s??? eeee.) - * (do this with a timeout!!??!!) - * on timeout completion: - * issue test_interface command. - * get_mib command to locate TX buffer. - * set_mib command to set any non-default variables. - * init tx first. - * init rx second with enable receiver command - * - * mac mgmt portion executes sync command to start BSS - * - */ +#ifdef __OpenBSD__ +struct cfdriver awi_cd = { + NULL, "awi", DV_IFNET +}; +#endif -/* - * device shutdown routine. - */ +#ifdef __FreeBSD__ +#if __FreeBSD__ >= 4 +devclass_t awi_devclass; +#endif -/* - * device appears to be insane. rather than hanging, whap device upside - * the head on next timeout. - */ +/* NetBSD compatible functions */ +static char * ether_sprintf __P((u_int8_t *)); -void -awi_insane(sc) - struct awi_softc *sc; +static char * +ether_sprintf(enaddr) + u_int8_t *enaddr; { - struct ifnet *ifp = sc->sc_ifp; - printf("%s: device timeout\n", sc->sc_dev.dv_xname); - - /* whap device on next timeout. */ - sc->sc_state = AWI_ST_INSANE; - ifp->if_timer = 1; -} + static char strbuf[18]; -void -awi_set_timer (sc) - struct awi_softc *sc; -{ - if (sc->sc_tx_timer || sc->sc_scan_timer || - sc->sc_mgt_timer || sc->sc_cmd_timer) - sc->sc_ifp->if_timer = 1; + sprintf(strbuf, "%6D", enaddr, ":"); + return strbuf; } - - -/* - * Copy m0 into the given TX descriptor and give the descriptor to the - * device so it starts transmiting.. - */ - -void -awi_tx_packet (sc, txd, m0) - struct awi_softc *sc; - int txd; - struct mbuf *m0; -{ - u_int32_t frame = sc->sc_txd[txd].frame; - u_int32_t len = sc->sc_txd[txd].len; - struct mbuf *m; - - for (m = m0; m != NULL; m = m->m_next) { - u_int32_t nmove; - nmove = min(len, m->m_len); - awi_write_bytes (sc, frame, m->m_data, nmove); - if (nmove != m->m_len) { - printf("%s: large frame truncated\n", - sc->sc_dev.dv_xname); - break; - } - frame += nmove; - len -= nmove; - } - - awi_init_txd (sc, - txd, - AWI_TXD_ST_OWN, - frame - sc->sc_txd[txd].frame, - AWI_RATE_1MBIT); - -#if 0 - awi_card_hexdump (sc, "txd to go", sc->sc_txd[txd].descr, - AWI_TXD_SIZE); #endif -} - -/* - * XXX KLUDGE XXX - * - * Convert ethernet-formatted frame into 802.11 data frame - * for infrastructure mode. - */ - -struct mbuf * -awi_output_kludge (sc, m0) +int +awi_attach(sc) struct awi_softc *sc; - struct mbuf *m0; { - u_int8_t *framehdr; - u_int8_t *llchdr; - u_int8_t dstaddr[ETHER_ADDR_LEN]; - struct awi_mac_header *amhdr; - u_int16_t etype; - struct ether_header *eh = mtod(m0, struct ether_header *); - -#if 0 - awi_hexdump("etherframe", m0->m_data, m0->m_len); + struct ifnet *ifp = sc->sc_ifp; + int s; + int error; +#ifdef IFM_IEEE80211 + int i; + u_int8_t *phy_rates; + int mword; + struct ifmediareq imr; #endif - bcopy(eh->ether_dhost, dstaddr, sizeof(dstaddr)); - etype = eh->ether_type; - - m_adj(m0, sizeof(struct ether_header)); - - M_PREPEND(m0, sizeof(struct awi_mac_header) + 8, M_DONTWAIT); - - if (m0 == NULL) { - printf("oops, prepend failed\n"); - return NULL; + s = splnet(); + /* + * Even if we can sleep in initialization state, + * all other processes (e.g. ifconfig) have to wait for + * completion of attaching interface. + */ + sc->sc_busy = 1; + sc->sc_status = AWI_ST_INIT; + TAILQ_INIT(&sc->sc_scan); + error = awi_init_hw(sc); + if (error) { + sc->sc_invalid = 1; + splx(s); + return error; } - - if (m0->m_len < 32) { - printf("oops, prepend only left %d bytes\n", m0->m_len); - m_freem(m0); - return NULL; + error = awi_init_mibs(sc); + splx(s); + if (error) { + sc->sc_invalid = 1; + return error; } - framehdr = mtod(m0, u_int8_t *); - amhdr = mtod(m0, struct awi_mac_header *); - - amhdr->awi_fc = IEEEWL_FC_VERS | - IEEEWL_FC_TYPE_DATA<<IEEEWL_FC_TYPE_SHIFT; - amhdr->awi_f2 = IEEEWL_FC2_TODS; - - bcopy(dstaddr, amhdr->awi_addr3, ETHER_ADDR_LEN); /* ether DST */ - bcopy(sc->sc_active_bss.bss_id, amhdr->awi_addr1, ETHER_ADDR_LEN); - bcopy(sc->sc_my_addr, amhdr->awi_addr2, ETHER_ADDR_LEN); - amhdr->awi_duration = 0; - amhdr->awi_seqctl = 0; - llchdr = (u_int8_t *) (amhdr + 1); - bcopy(snap_magic, llchdr, 6); - bcopy(&etype, llchdr+6, 2); - - return m0; -} -/* - * device start routine - * - * loop while there are free tx buffer descriptors and mbufs in the queue: - * -> copy mbufs to tx buffer and free mbufs. - * -> mark txd as good to go (OWN bit set, all others clear) - */ -void -awi_start(ifp) - struct ifnet *ifp; -{ - struct awi_softc *sc = ifp->if_softc; - struct mbuf *m0; - int opending; - - if ((ifp->if_flags & IFF_RUNNING) == 0) { - printf("%s: start called while not running\n", - sc->sc_dev.dv_xname); - return; - } - - /* - * loop through send queue, setting up tx descriptors - * until we either run out of stuff to send, or descriptors - * to send them in. - */ - opending = sc->sc_txpending; - - while (sc->sc_txpending < sc->sc_ntxd) { - /* - * Grab a packet off the queue. - */ - IF_DEQUEUE (&sc->sc_mgtq, m0); + ifp->if_softc = sc; + ifp->if_start = awi_start; + ifp->if_ioctl = awi_ioctl; + ifp->if_watchdog = awi_watchdog; + ifp->if_mtu = ETHERMTU; + ifp->if_hdrlen = sizeof(struct ieee80211_frame) + + sizeof(struct ether_header); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; +#ifdef IFF_NOTRAILERS + ifp->if_flags |= IFF_NOTRAILERS; +#endif +#ifdef __NetBSD__ + memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); +#endif +#ifdef __FreeBSD__ + ifp->if_output = ether_output; + ifp->if_snd.ifq_maxlen = ifqmaxlen; + memcpy(sc->sc_ec.ac_enaddr, sc->sc_mib_addr.aMAC_Address, + ETHER_ADDR_LEN); +#endif - if (m0 == NULL) { - /* XXX defer sending if not synched yet? */ - IF_DEQUEUE (&ifp->if_snd, m0); - if (m0 == NULL) - break; + printf("%s: IEEE802.11 %s %dMbps (firmware %s)\n", + sc->sc_dev.dv_xname, + sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH ? "FH" : "DS", + sc->sc_tx_rate / 10, sc->sc_banner); + printf("%s: address %s\n", + sc->sc_dev.dv_xname, ether_sprintf(sc->sc_mib_addr.aMAC_Address)); + if_attach(ifp); +#ifdef __OpenBSD__ + ether_ifattach(ifp); #if NBPFILTER > 0 - /* - * Pass packet to bpf if there is a listener. - */ - if (ifp->if_bpf) - bpf_mtap(ifp->if_bpf, m0); + bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); +#endif +#elif defined(__FreeBSD__) + ether_ifattach(ifp); +#if NBPFILTER > 0 + bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); +#endif +#elif defined(__NetBSD__) + ether_ifattach(ifp, sc->sc_mib_addr.aMAC_Address); +#if NBPFILTER > 0 + bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); +#endif #endif - /* - * We've got an ethernet-format frame. - * we need to mangle it into 802.11 form.. - */ - m0 = awi_output_kludge(sc, m0); - if (m0 == NULL) - continue; - } - - awi_tx_packet(sc, sc->sc_txnext, m0); - sc->sc_txpending++; - sc->sc_txnext = (sc->sc_txnext + 1) % sc->sc_ntxd; - - m_freem(m0); - } - if (sc->sc_txpending >= sc->sc_ntxd) { - /* no more slots available.. */ - ifp->if_flags |= IFF_OACTIVE; +#ifdef IFM_IEEE80211 + ifmedia_init(&sc->sc_media, 0, awi_media_change, awi_media_status); + phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates; + for (i = 0; i < phy_rates[1]; i++) { + mword = awi_media_rate2opt(sc, AWI_80211_RATE(phy_rates[2 + i])); + if (mword == 0) + continue; + mword |= IFM_IEEE80211; + ifmedia_add(&sc->sc_media, mword, 0, NULL); + ifmedia_add(&sc->sc_media, + mword | IFM_IEEE80211_ADHOC, 0, NULL); + if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_FH) + ifmedia_add(&sc->sc_media, + mword | IFM_IEEE80211_ADHOC | IFM_FLAG0, 0, NULL); } - if (sc->sc_txpending != opending) { - /* set watchdog timer in case unit flakes out */ - if (sc->sc_tx_timer == 0) - sc->sc_tx_timer = 5; - awi_set_timer(sc); - } -} + awi_media_status(ifp, &imr); + ifmedia_set(&sc->sc_media, imr.ifm_active); +#endif -int -awi_enable(sc) - struct awi_softc *sc; -{ - if (sc->sc_enabled == 0) { - if ((sc->sc_enable != NULL) && ((*sc->sc_enable)(sc) != 0)) { - printf("%s: device enable failed\n", - sc->sc_dev.dv_xname); - return (EIO); - } - awi_init(sc); - } - sc->sc_enabled = 1; - return 0; -} + /* ready to accept ioctl */ + awi_unlock(sc); -void -awi_disable(sc) - struct awi_softc *sc; -{ - if (sc->sc_enabled != 0 && sc->sc_disable != NULL) { - (*sc->sc_disable)(sc); - sc->sc_enabled = 0; - } + /* Attach is successful. */ + sc->sc_attached = 1; + return 0; } - - +#ifndef __FreeBSD__ int -awi_intlock(sc) +awi_detach(sc) struct awi_softc *sc; { - int i, j; - u_int8_t lockout; - - DELAY(5); - for (j=0; j<10; j++) { - for (i=0; i<AWI_LOCKOUT_SPIN; i++) { - lockout = awi_read_1(sc, AWI_LOCKOUT_HOST); - if (!lockout) - break; - DELAY(5); - } - if (lockout) - break; - awi_write_1 (sc, AWI_LOCKOUT_MAC, 1); - lockout = awi_read_1(sc, AWI_LOCKOUT_HOST); - - if (!lockout) - break; - /* oops, lost the race.. try again */ - awi_write_1 (sc, AWI_LOCKOUT_MAC, 0); - } - - if (lockout) { - awi_insane(sc); - return 0; - } - return 1; -} - -void -awi_intunlock(sc) - struct awi_softc *sc; -{ - awi_write_1 (sc, AWI_LOCKOUT_MAC, 0); -} - -void -awi_intrinit(sc) - struct awi_softc *sc; -{ - u_int8_t intmask; - - am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_ENECINT); - - intmask = AWI_INT_GROGGY|AWI_INT_SCAN_CMPLT| - AWI_INT_TX|AWI_INT_RX|AWI_INT_CMD; - - intmask = ~intmask; + struct ifnet *ifp = sc->sc_ifp; + int s; - if (!awi_intlock(sc)) - return; - - awi_write_1(sc, AWI_INTMASK, intmask); - awi_write_1(sc, AWI_INTMASK2, 0); + /* Succeed if there is no work to do. */ + if (!sc->sc_attached) + return (0); - awi_intunlock(sc); -} - -void awi_hexdump (char *tag, u_int8_t *data, int len) -{ - int i; - - printf("%s:", tag); - for (i=0; i<len; i++) { - printf(" %02x", data[i]); + s = splnet(); + sc->sc_invalid = 1; + awi_stop(sc); + while (sc->sc_sleep_cnt > 0) { + wakeup(sc); + (void)tsleep(sc, PWAIT, "awidet", 1); } - printf("\n"); -} - -void awi_card_hexdump (sc, tag, offset, len) - struct awi_softc *sc; - char *tag; - u_int32_t offset; - int len; -{ - int i; - - printf("%s:", tag); - for (i=0; i<len; i++) { - printf(" %02x", awi_read_1(sc, offset+i)); + if (sc->sc_wep_ctx != NULL) + free(sc->sc_wep_ctx, M_DEVBUF); +#if NBPFILTER > 0 + bpfdetach(ifp); +#endif +#ifdef IFM_IEEE80211 + ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); +#endif + ether_ifdetach(ifp); + if_detach(ifp); + if (sc->sc_enabled) { + if (sc->sc_disable) + (*sc->sc_disable)(sc); + sc->sc_enabled = 0; } - printf("\n"); + splx(s); + return 0; } -u_int8_t -awi_read_intst(sc) - struct awi_softc *sc; +int +awi_activate(self, act) + struct device *self; + enum devact act; { - u_int8_t state; - - if (!awi_intlock(sc)) - return 0; - - /* we have int lock.. */ - - state = awi_read_1 (sc, AWI_INTSTAT); - awi_write_1(sc, AWI_INTSTAT, 0); - - awi_intunlock(sc); - - return state; -} + struct awi_softc *sc = (struct awi_softc *)self; + int s, error = 0; - -void -awi_parse_tlv (u_int8_t *base, u_int8_t *end, u_int8_t **vals, u_int8_t *lens, size_t nattr) -{ - u_int8_t tag, len; + s = splnet(); + switch (act) { + case DVACT_ACTIVATE: + error = EOPNOTSUPP; + break; - int i; - - for (i=0; i<nattr; i++) { - vals[i] = NULL; - lens[i] = 0; - } - - while (base < end) { - tag = base[0]; - len = base[1]; - - base += 2; - - if (tag < nattr) { - lens[tag] = len; - vals[tag] = base; - } - base += len; + case DVACT_DEACTIVATE: + sc->sc_invalid = 1; +#ifdef __NetBSD__ + if (sc->sc_ifp) + if_deactivate(sc->sc_ifp); +#endif + break; } -} - -void -awi_send_frame (sc, m) - struct awi_softc *sc; - struct mbuf *m; -{ - IF_ENQUEUE(&sc->sc_mgtq, m); - - awi_start(sc->sc_ifp); -} - -void * -awi_init_hdr (sc, m, f1, f2) - struct awi_softc *sc; - struct mbuf *m; - int f1; - int f2; -{ - struct awi_mac_header *amhp; - - /* - * initialize 802.11 mac header in mbuf, return pointer to next byte.. - */ - - amhp = mtod(m, struct awi_mac_header *); - - amhp->awi_fc = f1; - amhp->awi_f2 = f2; - amhp->awi_duration = 0; - - bcopy(sc->sc_active_bss.bss_id, amhp->awi_addr1, ETHER_ADDR_LEN); - bcopy(sc->sc_my_addr, amhp->awi_addr2, ETHER_ADDR_LEN); - bcopy(sc->sc_active_bss.bss_id, amhp->awi_addr3, ETHER_ADDR_LEN); - - amhp->awi_seqctl = 0; - - return amhp+1; -} - - - -u_int8_t * -awi_add_rates (sc, m, ptr) - struct awi_softc *sc; - struct mbuf *m; - u_int8_t *ptr; -{ - *ptr++ = 1; /* XXX */ - *ptr++ = 1; /* XXX */ - *ptr++ = 0x82; /* XXX */ - return ptr; -} + splx(s); -u_int8_t * -awi_add_ssid (sc, m, ptr) - struct awi_softc *sc; - struct mbuf *m; - u_int8_t *ptr; -{ - int len = sc->sc_active_bss.sslen; - *ptr++ = 0; /* XXX */ - *ptr++ = len; - bcopy(sc->sc_active_bss.ssid, ptr, len); - ptr += len; - return ptr; + return error; } - - void -awi_send_authreq (sc) +awi_power(sc, why) struct awi_softc *sc; + int why; { - struct mbuf *m; - struct awi_auth_hdr *amahp; - u_int8_t *tlvptr; - - MGETHDR(m, M_DONTWAIT, MT_DATA); - - /* - * form an "association request" message. - */ - - /* - * auth alg number. 2 bytes. = 0 - * auth txn seq number = 2 bytes = 1 - * status code = 2 bytes = 0 - * challenge text (not present) - */ - - if (m == 0) - return; /* we'll try again later.. */ - - amahp = awi_init_hdr (sc, m, - (IEEEWL_FC_VERS | - (IEEEWL_FC_TYPE_MGT << IEEEWL_FC_TYPE_SHIFT) | - (IEEEWL_SUBTYPE_AUTH << IEEEWL_FC_SUBTYPE_SHIFT)), - 0); - - amahp->awi_algno[0] = 0; - amahp->awi_algno[1] = 0; - amahp->awi_seqno[0] = 1; - amahp->awi_seqno[1] = 0; - amahp->awi_status[0] = 0; - amahp->awi_status[1] = 0; - - /* - * form an "authentication" message. - */ + int s; + int ocansleep; - tlvptr = (u_int8_t *)(amahp+1); - - tlvptr = awi_add_ssid(sc, m, tlvptr); - tlvptr = awi_add_rates(sc, m, tlvptr); - - m->m_len = tlvptr - mtod(m, u_int8_t *); + if (!sc->sc_enabled) + return; - if (sc->sc_ifp->if_flags & IFF_DEBUG) { - printf("%s: sending auth request\n", - sc->sc_dev.dv_xname); - awi_hexdump("frame", m->m_data, m->m_len); + s = splnet(); + ocansleep = sc->sc_cansleep; + sc->sc_cansleep = 0; +#ifdef needtobefixed /*ONOE*/ + if (why == PWR_RESUME) { + sc->sc_enabled = 0; + awi_init(sc); + (void)awi_intr(sc); + } else { + awi_stop(sc); + if (sc->sc_disable) + (*sc->sc_disable)(sc); } - - awi_send_frame(sc, m); - - sc->sc_mgt_timer = 2; - awi_set_timer(sc); +#endif + sc->sc_cansleep = ocansleep; + splx(s); } +#endif /* __NetBSD__ */ -void -awi_send_assocreq (sc) - struct awi_softc *sc; +static int +awi_ioctl(ifp, cmd, data) + struct ifnet *ifp; + u_long cmd; + caddr_t data; { - struct mbuf *m; - struct awi_assoc_hdr *amahp; - u_int8_t *tlvptr; - - MGETHDR(m, M_DONTWAIT, MT_DATA); - - /* - * form an "association request" message. - */ - - if (m == 0) - return; /* we'll try again later.. */ - - /* - * cap info (2 bytes) - * listen interval (2 bytes) - * ssid (variable) - * supported rates (variable) - */ - - amahp = awi_init_hdr (sc, m, - IEEEWL_FC_TYPE_MGT, IEEEWL_SUBTYPE_ASSOCREQ); - - amahp->awi_cap_info[0] = 4; /* XXX magic (CF-pollable) */ - amahp->awi_cap_info[1] = 0; - amahp->awi_li[0] = 1; - amahp->awi_li[1] = 0; - - tlvptr = (u_int8_t *)(amahp+1); - - tlvptr = awi_add_ssid(sc, m, tlvptr); - tlvptr = awi_add_rates(sc, m, tlvptr); - - m->m_len = tlvptr - mtod(m, u_int8_t *); + struct awi_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + struct ifaddr *ifa = (struct ifaddr *)data; + int s, error; + struct ieee80211_nwid nwid; + u_int8_t *p; + s = splnet(); - if (sc->sc_ifp->if_flags & IFF_DEBUG) { - printf("%s: sending assoc request\n", - sc->sc_dev.dv_xname); - awi_hexdump("frame", m->m_data, m->m_len); +#ifdef __OpenBSD__ + if ((error = ether_ioctl(ifp, &sc->sc_ec, cmd, data)) > 0) { + splx(s); + return (error); } - - awi_send_frame(sc, m); - - sc->sc_mgt_timer = 2; - awi_set_timer(sc); -} - -#if 0 -void -awi_send_reassocreq (sc) -{ - - /* - * form an "reassociation request" message. - */ - - /* 2 bytes frame control - 00100000 00000000 - 2 bytes goo - 00000000 00000000 - address 1: bssid - address 2: my address - address 3: bssid - 2 bytes seq/ctl - 00000000 00000000 - - cap info (2 bytes) - listen interval (2 bytes) - current ap address (6 bytes) - ssid (variable) - supported rates (va - */ -} - #endif -void -awi_rcv_ctl (sc, m) - struct awi_softc *sc; - struct mbuf *m; -{ - printf("%s: ctl\n", sc->sc_dev.dv_xname); -} - -void -awi_rcv_data (sc, m) - struct awi_softc *sc; - struct mbuf *m; -{ - struct ifnet *ifp = sc->sc_ifp; - u_int8_t *llc; - u_int8_t *to, *from; - struct awi_mac_header *amhp; - - sc->sc_scan_timer = awi_scan_keepalive; /* user data is as good - as a beacon as a keepalive.. */ - - amhp = mtod(m, struct awi_mac_header *); - - /* - * we have: 4 bytes useless goo. - * 3 x 6 bytes MAC addresses. - * 2 bytes goo. - * 802.x LLC header, SNAP header, and data. - * - * for now, we fake up a "normal" ethernet header and feed - * this to the appropriate input routine. - */ - - llc = (u_int8_t *)(amhp+1); - - if (amhp->awi_f2 & IEEEWL_FC2_TODS) { - printf("drop packet to DS\n"); - goto drop; - } - - to = amhp->awi_addr1; - if (amhp->awi_f2 & IEEEWL_FC2_FROMDS) - from = amhp->awi_addr3; - else - from = amhp->awi_addr2; - if (memcmp (llc, snap_magic, 6) != 0) - goto drop; - - /* XXX overwrite llc with "from" address */ - /* XXX overwrite llc-6 with "to" address */ - bcopy(from, llc, ETHER_ADDR_LEN); - bcopy(to, llc-6, ETHER_ADDR_LEN); - - m_adj(m, sizeof(struct awi_mac_header) + sizeof(struct awi_llc_header) - - sizeof(struct ether_header)); - -#if NBPFILTER > 0 - /* - * Pass packet to bpf if there is a listener. - */ - if (ifp->if_bpf) - bpf_mtap(ifp->if_bpf, m); + /* serialize ioctl */ + error = awi_lock(sc); + if (error) + goto cantlock; + switch (cmd) { + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + arp_ifinit((void *)ifp, ifa); + break; #endif - -#if __NetBSD_Version__ > 104010000 - m->m_flags |= M_HASFCS; - (*ifp->if_input)(ifp, m); -#else - { - struct ether_header *eh; - eh = mtod(m, struct ether_header *); - m_adj(m, sizeof(*eh)); - m_adj(m, -ETHER_CRC_LEN); - ether_input(ifp, eh, m); - } -#endif - return; - drop: - m_freem(m); -} - -void -awi_rcv_mgt (sc, m, rxts, rssi) - struct awi_softc *sc; - struct mbuf *m; - u_int32_t rxts; - u_int8_t rssi; -{ - u_int8_t subtype; - u_int8_t *framehdr, *mgthdr, *end, *timestamp; - struct awi_auth_hdr *auhp; - struct ifnet *ifp = sc->sc_ifp; - -#define IEEEWL_MGT_NATTR 10 /* XXX */ - u_int8_t *attr[IEEEWL_MGT_NATTR]; - u_int8_t attrlen[IEEEWL_MGT_NATTR]; - u_int8_t *addr1, *addr2, *addr3; - u_int8_t *sa, *da, *bss; - - framehdr = mtod(m, u_int8_t *); - - /* - * mgt frame: - * 2 bytes frame goo - * 2 bytes duration - * 6 bytes a1 - * 6 bytes a2 - * 6 bytes a3 - * 2 bytes seq control. - * -- - * 24 bytes goo. - */ - - subtype = (framehdr[IEEEWL_FC] & IEEEWL_FC_SUBTYPE_MASK) - >> IEEEWL_FC_SUBTYPE_SHIFT; - - addr1 = framehdr + 4; /* XXX */ - addr2 = addr1+ETHER_ADDR_LEN; - addr3 = addr2+ETHER_ADDR_LEN; - - /* XXX look at to/from DS bits here!! */ - da = addr1; - sa = addr3; - bss = addr2; - - framehdr = mtod(m, u_int8_t *); - end = framehdr + m->m_len; - end -= 4; /* trim TLV */ - - mgthdr = framehdr + 24; /* XXX magic */ - - switch (subtype) { - - case IEEEWL_SUBTYPE_ASSOCRESP: - /* - * this acknowledges that the AP will be forwarding traffic - * for us.. - * - * contains: - * cap info - * status code - * AId - * supported rates. - */ - if (ifp->if_flags & IFF_DEBUG) { - printf("%s: got assoc resp\n", - sc->sc_dev.dv_xname); - awi_hexdump("assocresp", m->m_data, m->m_len); - } - awi_drvstate (sc, AWI_DRV_INFASSOC); - sc->sc_state = AWI_ST_RUNNING; - sc->sc_mgt_timer = AWI_ASSOC_REFRESH; - awi_set_timer(sc); - if (sc->sc_new_bss) { - printf("%s: associated with %s, SSID: %s\n", - sc->sc_dev.dv_xname, - ether_sprintf(sc->sc_active_bss.bss_id), - sc->sc_active_bss.ssid); - sc->sc_new_bss = 0; - } - - /* XXX set media status to "i see carrier" */ - break; - - case IEEEWL_SUBTYPE_REASSOCRESP: - /* - * this indicates that we've moved from one AP to another - * within the same DS. - */ - printf("reassoc_resp\n"); - - break; - - case IEEEWL_SUBTYPE_PROBEREQ: - /* discard */ - break; - - case IEEEWL_SUBTYPE_PROBERESP: - /* - * 8 bytes timestamp. - * 2 bytes beacon intvl. - * 2 bytes cap info. - * then tlv data.. - */ - timestamp = mgthdr; - - if (ifp->if_flags & IFF_DEBUG) { - printf("%s: got probe resp\n", - sc->sc_dev.dv_xname); - awi_hexdump("proberesp", m->m_data, m->m_len); } - /* now, into the tlv goo.. */ - mgthdr += 12; /* XXX magic */ - awi_parse_tlv (mgthdr, end, attr, attrlen, IEEEWL_MGT_NATTR); - - if (attr[IEEEWL_MGT_TLV_SSID] && - attr[IEEEWL_MGT_TLV_FHPARMS] && - attrlen[IEEEWL_MGT_TLV_SSID] < AWI_SSID_LEN) { - struct awi_bss_binding *bp = NULL; - int i; - - for (i=0; i< sc->sc_nbindings; i++) { - struct awi_bss_binding *bp1 = - &sc->sc_bindings[i]; - if (memcmp(bp1->bss_id, bss, ETHER_ADDR_LEN) == 0) { - bp = bp1; - break; - } - } - - if (bp == NULL && sc->sc_nbindings < NBND) { - bp = &sc->sc_bindings[sc->sc_nbindings++]; - } - if (bp != NULL) { - u_int8_t *fhparms = - attr[IEEEWL_MGT_TLV_FHPARMS]; - - bp->sslen = attrlen[IEEEWL_MGT_TLV_SSID]; - - bcopy(attr[IEEEWL_MGT_TLV_SSID], bp->ssid, - bp->sslen); - bp->ssid[bp->sslen] = 0; - - bcopy(bss, bp->bss_id, ETHER_ADDR_LEN); - - /* XXX more magic numbers.. */ - bp->dwell_time = fhparms[0] | (fhparms[1]<<8); - bp->chanset = fhparms[2]; - bp->pattern = fhparms[3]; - bp->index = fhparms[4]; - bp->rssi = rssi; - bp->rxtime = rxts; - bcopy(timestamp, bp->bss_timestamp, 8); + /* FALLTHROUGH */ + case SIOCSIFFLAGS: + sc->sc_format_llc = !(ifp->if_flags & IFF_LINK0); + if (!(ifp->if_flags & IFF_UP)) { + if (sc->sc_enabled) { + awi_stop(sc); + if (sc->sc_disable) + (*sc->sc_disable)(sc); + sc->sc_enabled = 0; } + break; } - + error = awi_init(sc); break; - case IEEEWL_SUBTYPE_BEACON: - if ((ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == - (IFF_DEBUG|IFF_LINK2)) { - printf("%s: beacon from %s\n", - sc->sc_dev.dv_xname, - ether_sprintf(addr2)); - awi_hexdump("beacon", m->m_data, m->m_len); - } + case SIOCADDMULTI: + case SIOCDELMULTI: +#ifdef __FreeBSD__ + error = ENETRESET; /*XXX*/ +#else + error = (cmd == SIOCADDMULTI) ? + ether_addmulti(ifr, &sc->sc_ec) : + ether_delmulti(ifr, &sc->sc_ec); +#endif /* - * Note that AP is still alive so we don't have to go looking - * for one for a while. - * - * XXX Beacons from other AP's should be recorded for - * potential use if we lose this AP.. (also, may want - * to notice if rssi of new AP is significantly - * stronger than old one and jump ship..) + * Do not rescan BSS. Rather, just reset multicast filter. */ - if ((sc->sc_state >= AWI_ST_SYNCED) && - (memcmp (addr2, sc->sc_active_bss.bss_id, - ETHER_ADDR_LEN) == 0)) { - sc->sc_scan_timer = awi_scan_keepalive; - awi_set_timer(sc); + if (error == ENETRESET) { + if (sc->sc_enabled) + error = awi_init(sc); + else + error = 0; } - break; - - case IEEEWL_SUBTYPE_DISSOC: - printf("dissoc\n"); - + case SIOCSIFMTU: + if (ifr->ifr_mtu > ETHERMTU) + error = EINVAL; + else + ifp->if_mtu = ifr->ifr_mtu; break; - - case IEEEWL_SUBTYPE_AUTH: - if (ifp->if_flags & IFF_DEBUG) { - printf("%s: got auth\n", - sc->sc_dev.dv_xname); - awi_hexdump("auth", m->m_data, m->m_len); + case SIOCS80211NWID: + error = copyin(ifr->ifr_data, &nwid, sizeof(nwid)); + if (error) + break; + if (nwid.i_len > IEEE80211_NWID_LEN) { + error = EINVAL; + break; } - /* - * woohoo! somebody likes us! - */ - - auhp = (struct awi_auth_hdr *)mgthdr; - - if ((auhp->awi_status[0] == 0) && (auhp->awi_status[1] == 0)) - { - awi_drvstate (sc, AWI_DRV_INFAUTH); - sc->sc_state = AWI_ST_AUTHED; - awi_send_assocreq (sc); + if (sc->sc_mib_mac.aDesired_ESS_ID[1] == nwid.i_len && + memcmp(&sc->sc_mib_mac.aDesired_ESS_ID[2], nwid.i_nwid, + nwid.i_len) == 0) + break; + memset(sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE); + sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID; + sc->sc_mib_mac.aDesired_ESS_ID[1] = nwid.i_len; + memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], nwid.i_nwid, + nwid.i_len); + if (sc->sc_enabled) { + awi_stop(sc); + error = awi_init(sc); } break; - - case IEEEWL_SUBTYPE_DEAUTH: - if (ifp->if_flags & IFF_DEBUG) { - printf("%s: got deauth\n", - sc->sc_dev.dv_xname); - awi_hexdump("deauth", m->m_data, m->m_len); - } - sc->sc_state = AWI_ST_SYNCED; - sc->sc_new_bss = 1; - awi_send_authreq(sc); + case SIOCG80211NWID: + if (ifp->if_flags & IFF_RUNNING) + p = sc->sc_bss.essid; + else + p = sc->sc_mib_mac.aDesired_ESS_ID; + error = copyout(p + 1, ifr->ifr_data, 1 + IEEE80211_NWID_LEN); + break; + case SIOCS80211NWKEY: + error = awi_wep_setnwkey(sc, (struct ieee80211_nwkey *)data); + break; + case SIOCG80211NWKEY: + error = awi_wep_getnwkey(sc, (struct ieee80211_nwkey *)data); break; +#ifdef IFM_IEEE80211 + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); + break; +#endif default: - printf("unk mgt subtype %x\n", subtype); +#ifdef notyet + error = awi_wicfg(ifp, cmd, data); +#else + error = EINVAL; +#endif break; } - m_freem(m); /* done.. */ + awi_unlock(sc); + cantlock: + splx(s); + return error; } - - - - -/* - * Do 802.11 receive processing. "m" contains a receive frame; - * rxts is the local receive timestamp - */ - -void -awi_rcv (sc, m, rxts, rssi) +#ifdef IFM_IEEE80211 +static int +awi_media_rate2opt(sc, rate) struct awi_softc *sc; - struct mbuf *m; - u_int32_t rxts; - u_int8_t rssi; + int rate; { - u_int8_t *framehdr; - u_int8_t framectl; - - framehdr = mtod(m, u_int8_t *); - - /* - * peek at first byte of frame header. - * check version subfield (must be zero) - * check type subfield (00 = mgt, 01 = ctl, 10 = data) - * check subtype field (next four bits) - */ - - /* - * Not counting WDS mode, the IEEE 802.11 frame header format - * has *three* MAC addresses. - * (source, destination, and BSS). - * - * The BSS indicates which wireless "cable segment" we're part of; - * we discover this dynamically.. - * - * Not content to put them in a fixed order, the exact - * ordering of these addresses depends on other attribute bits - * in the frame control word! - * - * an alternate presentation which is more self-consistent: - * address 1 is the "wireless destination" -- either the - * station address, - * for wireless->wireless traffic, or the BSS id of an AP. - * - * address 2 is the "wireless source" -- either the - * station address of a wireless node, or the BSS id of an AP. - * - * address 3 is the "other address" -- for STA->AP, the - * eventual destination; for AP->STA, the original source, and - * for ad-hoc mode, the BSS id.. - */ + int mword; - framectl = framehdr[IEEEWL_FC]; - - if ((framectl & IEEEWL_FC_VERS_MASK) != IEEEWL_FC_VERS) { - printf("wrong vers. drop"); - goto drop; - } - - switch (framectl & IEEEWL_FC_TYPE_MASK) { - case IEEEWL_FC_TYPE_MGT << IEEEWL_FC_TYPE_SHIFT: - awi_rcv_mgt (sc, m, rxts, rssi); - m = 0; + mword = 0; + switch (rate) { + case 10: + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) + mword = IFM_IEEE80211_FH1; + else + mword = IFM_IEEE80211_DS1; break; - - case IEEEWL_FC_TYPE_DATA << IEEEWL_FC_TYPE_SHIFT: - awi_rcv_data (sc, m); - m = 0; + case 20: + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) + mword = IFM_IEEE80211_FH2; + else + mword = IFM_IEEE80211_DS2; + break; + case 55: + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_DS) + mword = IFM_IEEE80211_DS5; + break; + case 110: + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_DS) + mword = IFM_IEEE80211_DS11; break; - - case IEEEWL_FC_TYPE_CTL << IEEEWL_FC_TYPE_SHIFT: - awi_rcv_ctl (sc, m); - default: - goto drop; } - - drop: - if (m) m_freem(m); + return mword; } -void -awi_copy_rxd (sc, cur, rxd) +static int +awi_media_opt2rate(sc, opt) struct awi_softc *sc; - u_int32_t cur; - struct awi_rxd *rxd; + int opt; { - if (sc->sc_ifp->if_flags & IFF_LINK0) { - printf("%x: ", cur); - awi_card_hexdump(sc, "rxd", cur, AWI_RXD_SIZE); - } - - rxd->next = awi_read_4(sc, cur + AWI_RXD_NEXT); - rxd->state = awi_read_1(sc, cur + AWI_RXD_HOST_DESC_STATE); - rxd->len = awi_read_2 (sc, cur + AWI_RXD_LEN); - rxd->rate = awi_read_1 (sc, cur + AWI_RXD_RATE); - rxd->rssi = awi_read_1 (sc, cur + AWI_RXD_RSSI); - rxd->index = awi_read_1 (sc, cur + AWI_RXD_INDEX); - rxd->frame = awi_read_4 (sc, cur + AWI_RXD_START_FRAME); - rxd->rxts = awi_read_4 (sc, cur + AWI_RXD_LOCALTIME); - - /* - * only the low order bits of "frame" and "next" are valid. - * (the documentation doesn't mention this). - */ - rxd->frame &= 0xffff; - rxd->next &= (0xffff | AWI_RXD_NEXT_LAST); + int rate; - /* - * XXX after masking, sanity check that rxd->frame and - * rxd->next lie within the receive area. - */ - if (sc->sc_ifp->if_flags & IFF_LINK0) { - printf("nxt %x frame %x state %b len %d\n", - rxd->next, rxd->frame, - rxd->state, AWI_RXD_ST_BITS, - rxd->len); + rate = 0; + switch (IFM_SUBTYPE(opt)) { + case IFM_IEEE80211_FH1: + case IFM_IEEE80211_FH2: + if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_FH) + return 0; + break; + case IFM_IEEE80211_DS1: + case IFM_IEEE80211_DS2: + case IFM_IEEE80211_DS5: + case IFM_IEEE80211_DS11: + if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_DS) + return 0; + break; } -} - -u_int32_t -awi_parse_rxd (sc, cur, rxd) - struct awi_softc *sc; - u_int32_t cur; - struct awi_rxd *rxd; -{ - struct mbuf *top; - struct ifnet *ifp = sc->sc_ifp; - u_int32_t next; - - if ((rxd->state & AWI_RXD_ST_CONSUMED) == 0) { - if (ifp->if_flags & IFF_LINK1) { - int xx = awi_read_1(sc, rxd->frame); - if (xx != (IEEEWL_FC_VERS | - (IEEEWL_FC_TYPE_MGT<<IEEEWL_FC_TYPE_SHIFT) | - (IEEEWL_SUBTYPE_BEACON << IEEEWL_FC_SUBTYPE_SHIFT))) { - char bitbuf[64]; - printf("floosh: %d state ", sc->sc_flushpkt); - snprintf(bitbuf, sizeof bitbuf, "%b", - rxd->state, AWI_RXD_ST_BITS); - awi_card_hexdump(sc, bitbuf, rxd->frame, - rxd->len); - } - - } - if ((sc->sc_flushpkt == 0) && - (sc->sc_nextpkt == NULL)) { - MGETHDR(top, M_DONTWAIT, MT_DATA); - - if (top == NULL) { - sc->sc_flushpkt = 1; - sc->sc_m = NULL; - sc->sc_mptr = NULL; - sc->sc_mleft = 0; - } else { - if (rxd->len >= MINCLSIZE) - MCLGET(top, M_DONTWAIT); - - top->m_pkthdr.rcvif = ifp; - top->m_pkthdr.len = 0; - top->m_len = 0; - - sc->sc_mleft = (top->m_flags & M_EXT) ? - MCLBYTES : MHLEN; - sc->sc_mptr = mtod(top, u_int8_t *); - sc->sc_m = top; - sc->sc_nextpkt = top; - } - } - if (sc->sc_flushpkt == 0) { - /* copy data into mbuf */ - - while (rxd->len > 0) { - int nmove = min (rxd->len, sc->sc_mleft); - - awi_read_bytes (sc, rxd->frame, sc->sc_mptr, - nmove); - - rxd->len -= nmove; - rxd->frame += nmove; - sc->sc_mleft -= nmove; - sc->sc_mptr += nmove; - - sc->sc_nextpkt->m_pkthdr.len += nmove; - sc->sc_m->m_len += nmove; - - if ((rxd->len > 0) && (sc->sc_mleft == 0)) { - struct mbuf *m1; - - /* Get next mbuf.. */ - MGET(m1, M_DONTWAIT, MT_DATA); - if (m1 == NULL) { - m_freem(sc->sc_nextpkt); - sc->sc_nextpkt = NULL; - sc->sc_flushpkt = 1; - sc->sc_m = NULL; - sc->sc_mptr = NULL; - sc->sc_mleft = 0; - break; - } - sc->sc_m->m_next = m1; - sc->sc_m = m1; - m1->m_len = 0; - - sc->sc_mleft = MLEN; - sc->sc_mptr = mtod(m1, u_int8_t *); - } - } - } - if (rxd->state & AWI_RXD_ST_LF) { - if (sc->sc_flushpkt) { - sc->sc_flushpkt = 0; - } - else if (sc->sc_nextpkt != NULL) { - struct mbuf *m = sc->sc_nextpkt; - sc->sc_nextpkt = NULL; - sc->sc_flushpkt = 0; - sc->sc_m = NULL; - sc->sc_mptr = NULL; - sc->sc_mleft = 0; - awi_rcv(sc, m, rxd->rxts, rxd->rssi); - } - } - } - rxd->state |= AWI_RXD_ST_CONSUMED; - awi_write_1(sc, cur + AWI_RXD_HOST_DESC_STATE, rxd->state); - next = cur; - if ((rxd->next & AWI_RXD_NEXT_LAST) == 0) { - rxd->state |= AWI_RXD_ST_OWN; - awi_write_1(sc, cur + AWI_RXD_HOST_DESC_STATE, rxd->state); - next = rxd->next; + switch (IFM_SUBTYPE(opt)) { + case IFM_IEEE80211_FH1: + case IFM_IEEE80211_DS1: + rate = 10; + break; + case IFM_IEEE80211_FH2: + case IFM_IEEE80211_DS2: + rate = 20; + break; + case IFM_IEEE80211_DS5: + rate = 55; + break; + case IFM_IEEE80211_DS11: + rate = 110; + break; } - return next; + return rate; } -void -awi_dump_rxchain (sc, what, descr) - struct awi_softc *sc; - char *what; - u_int32_t *descr; +/* + * Called from ifmedia_ioctl via awi_ioctl with lock obtained. + */ +static int +awi_media_change(ifp) + struct ifnet *ifp; { - u_int32_t cur, next; - struct awi_rxd rxd; - - cur = *descr; - - if (cur & AWI_RXD_NEXT_LAST) - return; - - do { - awi_copy_rxd(sc, cur, &rxd); - - next = awi_parse_rxd(sc, cur, &rxd); - if ((rxd.state & AWI_RXD_ST_OWN) && (next == cur)) { - printf("%s: loop in rxd list?", - sc->sc_dev.dv_xname); - break; + struct awi_softc *sc = ifp->if_softc; + struct ifmedia_entry *ime; + u_int8_t *phy_rates; + int i, rate, error; + + error = 0; + ime = sc->sc_media.ifm_cur; + rate = awi_media_opt2rate(sc, ime->ifm_media); + if (rate == 0) + return EINVAL; + if (rate != sc->sc_tx_rate) { + phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates; + for (i = 0; i < phy_rates[1]; i++) { + if (rate == AWI_80211_RATE(phy_rates[2 + i])) + break; } - cur = next; - } while (rxd.state & AWI_RXD_ST_OWN); - - *descr = cur; -} - -void -awi_rxint (sc) - struct awi_softc *sc; -{ - awi_dump_rxchain (sc, "mgt", &sc->sc_rx_mgt_desc); - awi_dump_rxchain (sc, "data", &sc->sc_rx_data_desc); -} - -void -awi_init_txd (sc, tx, flag, len, rate) - struct awi_softc *sc; - int tx; - int flag; - int len; - int rate; -{ - u_int32_t txdbase = sc->sc_txd[tx].descr; - u_int32_t framebase = sc->sc_txd[tx].frame; - u_int32_t nextbase = sc->sc_txd[(tx+1)%sc->sc_ntxd].descr; - - awi_write_4 (sc, txdbase + AWI_TXD_START, framebase); - awi_write_4 (sc, txdbase + AWI_TXD_NEXT, nextbase); - awi_write_4 (sc, txdbase + AWI_TXD_LENGTH, len); - awi_write_1 (sc, txdbase + AWI_TXD_RATE, rate); - /* zeroize tail end of txd */ - awi_write_4 (sc, txdbase + AWI_TXD_NDA, 0); - awi_write_4 (sc, txdbase + AWI_TXD_NRA, 0); - /* Init state last; firmware keys off of this to know when to start tx */ - awi_write_1 (sc, txdbase + AWI_TXD_STATE, flag); -} - -void -awi_init_txdescr (sc) - struct awi_softc *sc; -{ - int i; - u_int32_t offset = sc->sc_txbase; - - sc->sc_txfirst = 0; - sc->sc_txnext = 0; - - sc->sc_ntxd = sc->sc_txlen / (AWI_FRAME_SIZE + AWI_TXD_SIZE); - if (sc->sc_ntxd > NTXD) { - sc->sc_ntxd = NTXD; - printf("oops, no, only %d\n", sc->sc_ntxd); + if (i == phy_rates[1]) + return EINVAL; } - - /* Allocate TXD's */ - for (i=0; i<sc->sc_ntxd; i++) { - sc->sc_txd[i].descr = offset; - offset += AWI_TXD_SIZE; - } - /* now, allocate buffer space to each txd.. */ - for (i=0; i<sc->sc_ntxd; i++) { - sc->sc_txd[i].frame = offset; - sc->sc_txd[i].len = AWI_FRAME_SIZE; - offset += AWI_FRAME_SIZE; - + if (ime->ifm_media & IFM_IEEE80211_ADHOC) { + sc->sc_mib_local.Network_Mode = 0; + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) + sc->sc_no_bssid = 0; + else + sc->sc_no_bssid = (ime->ifm_media & IFM_FLAG0) ? 1 : 0; + } else { + sc->sc_mib_local.Network_Mode = 1; } - - /* now, initialize the TX descriptors into a circular linked list. */ - - for (i= 0; i<sc->sc_ntxd; i++) { - awi_init_txd(sc, i, 0, 0, 0); + if (sc->sc_enabled) { + awi_stop(sc); + error = awi_init(sc); } + return error; } -void -awi_txint (sc) - struct awi_softc *sc; +static void +awi_media_status(ifp, imr) + struct ifnet *ifp; + struct ifmediareq *imr; { - struct ifnet *ifp = sc->sc_ifp; - int txfirst; - - sc->sc_tx_timer = 0; - - txfirst = sc->sc_txfirst; - while (sc->sc_txpending > 0) { - u_int8_t flags = awi_read_1 (sc, sc->sc_txd[txfirst].descr + - AWI_TXD_STATE); - - if (flags & AWI_TXD_ST_OWN) - break; - - if (flags & AWI_TXD_ST_ERROR) { - /* increment oerrs */; - } + struct awi_softc *sc = ifp->if_softc; - txfirst = (txfirst + 1) % sc->sc_ntxd; - sc->sc_txpending--; + imr->ifm_status = IFM_AVALID; + if (ifp->if_flags & IFF_RUNNING) + imr->ifm_status |= IFM_ACTIVE; + imr->ifm_active = IFM_IEEE80211; + imr->ifm_active |= awi_media_rate2opt(sc, sc->sc_tx_rate); + if (sc->sc_mib_local.Network_Mode == 0) { + imr->ifm_active |= IFM_IEEE80211_ADHOC; + if (sc->sc_no_bssid) + imr->ifm_active |= IFM_FLAG0; } - - sc->sc_txfirst = txfirst; - - if (sc->sc_txpending < sc->sc_ntxd) - ifp->if_flags &= ~IFF_OACTIVE; - - /* - * see which descriptors are done.. - */ - - awi_start(sc->sc_ifp); } - - - - -/* - * device interrupt routine. - * - * lock out MAC - * loop: - * look at intr status, DTRT. - * - * on tx done, reclaim free buffers from tx, call start. - * on rx done, look at rx queue, copy to mbufs, mark as free, - * hand to ether media layer rx routine. - * on cmd done, call cmd cmpl continuation. - * - */ +#endif /* IFM_IEEE80211 */ int awi_intr(arg) void *arg; { struct awi_softc *sc = arg; - int handled = 0; + u_int16_t status; + int error, handled = 0, ocansleep; - if (sc->sc_state == AWI_ST_OFF) { - u_int8_t intstate = awi_read_intst (sc); - return intstate != 0; - } + if (!sc->sc_enabled || !sc->sc_enab_intr || sc->sc_invalid) + return 0; - /* disable power down, (and implicitly ack interrupt) */ - am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_DISPWDN); + am79c930_gcr_setbits(&sc->sc_chip, + AM79C930_GCR_DISPWDN | AM79C930_GCR_ECINT); awi_write_1(sc, AWI_DIS_PWRDN, 1); - - for (;;) { - u_int8_t intstate = awi_read_intst (sc); + ocansleep = sc->sc_cansleep; + sc->sc_cansleep = 0; - if (!intstate) + for (;;) { + error = awi_intr_lock(sc); + if (error) + break; + status = awi_read_1(sc, AWI_INTSTAT); + awi_write_1(sc, AWI_INTSTAT, 0); + awi_write_1(sc, AWI_INTSTAT, 0); + status |= awi_read_1(sc, AWI_INTSTAT2) << 8; + awi_write_1(sc, AWI_INTSTAT2, 0); + DELAY(10); + awi_intr_unlock(sc); + if (!sc->sc_cmd_inprog) + status &= ~AWI_INT_CMD; /* make sure */ + if (status == 0) break; - handled = 1; - - if (intstate & AWI_INT_RX) + if (status & AWI_INT_RX) awi_rxint(sc); - - if (intstate & AWI_INT_TX) + if (status & AWI_INT_TX) awi_txint(sc); - - if (intstate & AWI_INT_CMD) { - u_int8_t status; - - if (!(sc->sc_flags & AWI_FL_CMD_INPROG)) - printf("%s: no command in progress?\n", - sc->sc_dev.dv_xname); - status = awi_read_1(sc, AWI_CMD_STATUS); - awi_write_1 (sc, AWI_CMD, 0); - sc->sc_cmd_timer = 0; - sc->sc_flags &= ~AWI_FL_CMD_INPROG; - - if (sc->sc_completion) - (*sc->sc_completion)(sc, status); - } - if (intstate & AWI_INT_SCAN_CMPLT) { - if (sc->sc_flags & AWI_FL_CMD_INPROG) { - panic("i can't take it any more"); - } - /* - * scan completion heuristic.. - */ - if ((sc->sc_nbindings >= NBND) - || ((sc->sc_scan_timer == 0) && - (sc->sc_nbindings > 0))) - awi_try_sync(sc); - else - awi_scan_next(sc); + if (status & AWI_INT_CMD) + awi_cmd_done(sc); + if (status & AWI_INT_SCAN_CMPLT) { + if (sc->sc_status == AWI_ST_SCAN && + sc->sc_mgt_timer > 0) + (void)awi_next_scan(sc); } - } - /* reenable power down */ + sc->sc_cansleep = ocansleep; am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_DISPWDN); awi_write_1(sc, AWI_DIS_PWRDN, 0); - return handled; } -/* - * flush tx queues.. - */ - -void -awi_flush(sc) +int +awi_init(sc) struct awi_softc *sc; { + int error, ostatus; + int n; struct ifnet *ifp = sc->sc_ifp; - struct mbuf *m; +#ifdef __FreeBSD__ + struct ifmultiaddr *ifma; +#else + struct ether_multi *enm; + struct ether_multistep step; +#endif - do { - IF_DEQUEUE (&sc->sc_mgtq, m); - m_freem(m); - } while (m != NULL); - - do { - IF_DEQUEUE (&ifp->if_snd, m); - m_freem(m); - } while (m != NULL); + /* reinitialize muticast filter */ + n = 0; + ifp->if_flags |= IFF_ALLMULTI; + sc->sc_mib_local.Accept_All_Multicast_Dis = 0; + if (ifp->if_flags & IFF_PROMISC) { + sc->sc_mib_mac.aPromiscuous_Enable = 1; + goto set_mib; + } + sc->sc_mib_mac.aPromiscuous_Enable = 0; +#ifdef __FreeBSD__ + if (ifp->if_amcount != 0) + goto set_mib; + for (ifma = LIST_FIRST(&ifp->if_multiaddrs); ifma != NULL; + ifma = LIST_NEXT(ifma, ifma_link)) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + if (n == AWI_GROUP_ADDR_SIZE) + goto set_mib; + memcpy(sc->sc_mib_addr.aGroup_Addresses[n], + LLADDR((struct sockaddr_dl *)ifma->ifma_addr), + ETHER_ADDR_LEN); + n++; + } +#else + ETHER_FIRST_MULTI(step, &sc->sc_ec, enm); + while (enm != NULL) { + if (n == AWI_GROUP_ADDR_SIZE || + memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) + != 0) + goto set_mib; + memcpy(sc->sc_mib_addr.aGroup_Addresses[n], enm->enm_addrlo, + ETHER_ADDR_LEN); + n++; + ETHER_NEXT_MULTI(step, enm); + } +#endif + for (; n < AWI_GROUP_ADDR_SIZE; n++) + memset(sc->sc_mib_addr.aGroup_Addresses[n], 0, ETHER_ADDR_LEN); + ifp->if_flags &= ~IFF_ALLMULTI; + sc->sc_mib_local.Accept_All_Multicast_Dis = 1; + + set_mib: +#ifdef notdef /* allow non-encrypted frame for receiving. */ + sc->sc_mib_mgt.Wep_Required = sc->sc_wep_algo != NULL ? 1 : 0; +#endif + if (!sc->sc_enabled) { + sc->sc_enabled = 1; + if (sc->sc_enable) + (*sc->sc_enable)(sc); + sc->sc_status = AWI_ST_INIT; + error = awi_init_hw(sc); + if (error) + return error; + } + ostatus = sc->sc_status; + sc->sc_status = AWI_ST_INIT; + if ((error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_LOCAL)) != 0 || + (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_ADDR)) != 0 || + (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MAC)) != 0 || + (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT)) != 0 || + (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_PHY)) != 0) { + awi_stop(sc); + return error; + } + if (ifp->if_flags & IFF_RUNNING) + sc->sc_status = AWI_ST_RUNNING; + else { + if (ostatus == AWI_ST_INIT) { + error = awi_init_txrx(sc); + if (error) + return error; + } + error = awi_start_scan(sc); + } + return error; } - - -/* - * device stop routine - */ - void awi_stop(sc) struct awi_softc *sc; { struct ifnet *ifp = sc->sc_ifp; - - awi_flush(sc); + struct awi_bss *bp; + struct mbuf *m; - /* Turn off timer.. */ + sc->sc_status = AWI_ST_INIT; + if (!sc->sc_invalid) { + (void)awi_cmd_wait(sc); + if (sc->sc_mib_local.Network_Mode && + sc->sc_status > AWI_ST_AUTH) + awi_send_deauth(sc); + awi_stop_txrx(sc); + } + ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); ifp->if_timer = 0; - sc->sc_state = AWI_ST_OFF; - (void) awi_read_intst (sc); - /* - * XXX for pcmcia, there's no point in disabling the device, - * as it's about to be powered off.. - * for non-PCMCIA attachments, we should, however, stop - * the receiver and transmitter here. - */ + sc->sc_tx_timer = sc->sc_rx_timer = sc->sc_mgt_timer = 0; + for (;;) { + IF_DEQUEUE(&sc->sc_mgtq, m); + if (m == NULL) + break; + m_freem(m); + } + for (;;) { + IF_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + m_freem(m); + } + while ((bp = TAILQ_FIRST(&sc->sc_scan)) != NULL) { + TAILQ_REMOVE(&sc->sc_scan, bp, list); + free(bp, M_DEVBUF); + } } -/* - * Watchdog routine, triggered by timer. - * This does periodic maintainance-type tasks on the interface. - */ - -void +static void awi_watchdog(ifp) struct ifnet *ifp; { struct awi_softc *sc = ifp->if_softc; - u_int8_t test; - int i; + int ocansleep; - if (sc->sc_state == AWI_ST_OFF) - /* nothing to do */ - return; - else if (sc->sc_state == AWI_ST_INSANE) { - awi_reset(sc); - return; - } else if (sc->sc_state == AWI_ST_SELFTEST) { - /* check for selftest completion.. */ - test = awi_read_1(sc, AWI_SELFTEST); - if ((test & 0xf0) == 0xf0) { /* XXX magic numbers */ - if (test == AWI_SELFTEST_PASSED) { - awi_init_1(sc); - } else { - printf("%s: selftest failed (code %x)\n", - sc->sc_dev.dv_xname, test); - awi_reset(sc); - } - } - sc->sc_selftest_tries++; - /* still running. try again on next tick */ - if (sc->sc_selftest_tries < 5) { - ifp->if_timer = 1; - } else { - /* - * XXX should power down card, wait 1s, power it back - * up again.. - */ - printf("%s: device failed to complete selftest (code %x)\n", - sc->sc_dev.dv_xname, test); - ifp->if_timer = 0; - } + if (sc->sc_invalid) { + ifp->if_timer = 0; return; } - - /* - * command timer: if it goes to zero, device failed to respond. - * boot to the head. - */ - if (sc->sc_cmd_timer) { - sc->sc_cmd_timer--; - if (sc->sc_cmd_timer == 0) { - sc->sc_flags &= ~AWI_FL_CMD_INPROG; - - printf("%s: timeout waiting for command completion\n", - sc->sc_dev.dv_xname); - test = awi_read_1(sc, AWI_CMD_STATUS); - printf("%s: cmd status: %x\n", sc->sc_dev.dv_xname, test); - test = awi_read_1(sc, AWI_CMD); - printf("%s: cmd: %x\n", sc->sc_dev.dv_xname, test); - awi_card_hexdump(sc, "CSB", AWI_CSB, 16); - awi_reset(sc); - return; + ocansleep = sc->sc_cansleep; + sc->sc_cansleep = 0; + if (sc->sc_tx_timer && --sc->sc_tx_timer == 0) { + printf("%s: transmit timeout\n", sc->sc_dev.dv_xname); + awi_txint(sc); + } + if (sc->sc_rx_timer && --sc->sc_rx_timer == 0) { + if (ifp->if_flags & IFF_DEBUG) { + printf("%s: no recent beacons from %s; rescanning\n", + sc->sc_dev.dv_xname, + ether_sprintf(sc->sc_bss.bssid)); } + ifp->if_flags &= ~IFF_RUNNING; + awi_start_scan(sc); } - /* - * Transmit timer. If it goes to zero, device failed to deliver a - * tx complete interrupt. boot to the head. - */ - if (sc->sc_tx_timer) { - sc->sc_tx_timer--; - if ((sc->sc_tx_timer == 0) && (sc->sc_txpending)) { - awi_card_hexdump(sc, "CSB", AWI_CSB, 16); - printf("%s: transmit timeout\n", sc->sc_dev.dv_xname); - awi_card_hexdump(sc, "last_txd", AWI_LAST_TXD, 5*4); - for (i=0; i<sc->sc_ntxd; i++) { - awi_card_hexdump(sc, "txd", - sc->sc_txd[i].descr, AWI_TXD_SIZE); - } - awi_reset(sc); - return; + if (sc->sc_mgt_timer && --sc->sc_mgt_timer == 0) { + switch (sc->sc_status) { + case AWI_ST_SCAN: + awi_stop_scan(sc); + break; + case AWI_ST_AUTH: + case AWI_ST_ASSOC: + /* restart scan */ + awi_start_scan(sc); + break; + default: + break; } } - /* - * Scan timer. - * When synched, this is used to notice when we've stopped - * receiving beacons and should attempt to resynch. - * - * When unsynched, this is used to notice if we've received an - * interesting probe response and should synch up. - */ - if (sc->sc_scan_timer) { - sc->sc_scan_timer--; - if (sc->sc_scan_timer == 0) { - if (sc->sc_state == AWI_ST_SCAN) { - /* - * XXX what if device fails to deliver - * a scan-completion interrupt? - */ - } else { - printf("%s: no recent beacon from %s; rescanning\n", - sc->sc_dev.dv_xname, - ether_sprintf(sc->sc_active_bss.bss_id)); - awi_restart_scan(sc); + if (sc->sc_tx_timer == 0 && sc->sc_rx_timer == 0 && + sc->sc_mgt_timer == 0) + ifp->if_timer = 0; + else + ifp->if_timer = 1; + sc->sc_cansleep = ocansleep; +} + +static void +awi_start(ifp) + struct ifnet *ifp; +{ + struct awi_softc *sc = ifp->if_softc; + struct mbuf *m0, *m; + u_int32_t txd, frame, ntxd; + u_int8_t rate; + int len, sent = 0; + + for (;;) { + txd = sc->sc_txnext; + IF_DEQUEUE(&sc->sc_mgtq, m0); + if (m0 != NULL) { + if (awi_next_txd(sc, m0->m_pkthdr.len, &frame, &ntxd)) { + IF_PREPEND(&sc->sc_mgtq, m0); + ifp->if_flags |= IFF_OACTIVE; + break; } - } - } - - /* - * Management timer. Used to know when to send auth - * requests and associate requests. - */ - if (sc->sc_mgt_timer) { - sc->sc_mgt_timer--; - if (sc->sc_mgt_timer == 0) { - switch (sc->sc_state) - { - case AWI_ST_SYNCED: - case AWI_ST_RUNNING: - sc->sc_state = AWI_ST_SYNCED; - awi_send_authreq(sc); + } else { + if (!(ifp->if_flags & IFF_RUNNING)) break; - case AWI_ST_AUTHED: - awi_send_assocreq(sc); + IF_DEQUEUE(&ifp->if_snd, m0); + if (m0 == NULL) break; - default: - printf("weird state for mgt timeout!\n"); + len = m0->m_pkthdr.len + sizeof(struct ieee80211_frame); + if (sc->sc_format_llc) + len += sizeof(struct llc) - + sizeof(struct ether_header); + if (sc->sc_wep_algo != NULL) + len += IEEE80211_WEP_IVLEN + + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; + if (awi_next_txd(sc, len, &frame, &ntxd)) { + IF_PREPEND(&ifp->if_snd, m0); + ifp->if_flags |= IFF_OACTIVE; break; } + AWI_BPF_MTAP(sc, m0, AWI_BPF_NORM); + m0 = awi_fix_txhdr(sc, m0); + if (sc->sc_wep_algo != NULL && m0 != NULL) + m0 = awi_wep_encrypt(sc, m0, 1); + if (m0 == NULL) { + ifp->if_oerrors++; + continue; + } + ifp->if_opackets++; + } +#ifdef AWI_DEBUG + if (awi_dump) + awi_dump_pkt(sc, m0, -1); +#endif + AWI_BPF_MTAP(sc, m0, AWI_BPF_RAW); + len = 0; + for (m = m0; m != NULL; m = m->m_next) { + awi_write_bytes(sc, frame + len, mtod(m, u_int8_t *), + m->m_len); + len += m->m_len; } + m_freem(m0); + rate = sc->sc_tx_rate; /*XXX*/ + awi_write_1(sc, ntxd + AWI_TXD_STATE, 0); + awi_write_4(sc, txd + AWI_TXD_START, frame); + awi_write_4(sc, txd + AWI_TXD_NEXT, ntxd); + awi_write_4(sc, txd + AWI_TXD_LENGTH, len); + awi_write_1(sc, txd + AWI_TXD_RATE, rate); + awi_write_4(sc, txd + AWI_TXD_NDA, 0); + awi_write_4(sc, txd + AWI_TXD_NRA, 0); + awi_write_1(sc, txd + AWI_TXD_STATE, AWI_TXD_ST_OWN); + sc->sc_txnext = ntxd; + sent++; + } + if (sent) { + if (sc->sc_tx_timer == 0) + sc->sc_tx_timer = 5; + ifp->if_timer = 1; +#ifdef AWI_DEBUG + if (awi_verbose) + 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); +#endif } - awi_set_timer(sc); } -void -awi_set_mc (sc) - struct awi_softc *sc; +static void +awi_txint(sc) + struct awi_softc *sc; { - /* XXX not implemented yet.. */ -} + struct ifnet *ifp = sc->sc_ifp; + u_int8_t flags; -/* - * init routine - */ + while (sc->sc_txdone != sc->sc_txnext) { + flags = awi_read_1(sc, sc->sc_txdone + AWI_TXD_STATE); + if ((flags & AWI_TXD_ST_OWN) || !(flags & AWI_TXD_ST_DONE)) + break; + if (flags & AWI_TXD_ST_ERROR) + ifp->if_oerrors++; + sc->sc_txdone = awi_read_4(sc, sc->sc_txdone + AWI_TXD_NEXT) & + 0x7fff; + } + sc->sc_tx_timer = 0; + ifp->if_flags &= ~IFF_OACTIVE; +#ifdef AWI_DEBUG + if (awi_verbose) + printf("awi_txint: txdone %d txnext %d txbase %d txend %d\n", + sc->sc_txdone, sc->sc_txnext, sc->sc_txbase, sc->sc_txend); +#endif + awi_start(ifp); +} -/* - * ioctl routine - * SIOCSIFADDR sets IFF_UP - * SIOCIFMTU - * SIOCSIFFLAGS - * SIOCADDMULTI/SIOCDELMULTI - */ - -int -awi_ioctl(ifp, cmd, data) - register struct ifnet *ifp; - u_long cmd; - caddr_t data; +static struct mbuf * +awi_fix_txhdr(sc, m0) + struct awi_softc *sc; + struct mbuf *m0; { - struct awi_softc *sc = ifp->if_softc; - struct ifaddr *ifa = (struct ifaddr *)data; - struct ifreq *ifr = (struct ifreq *)data; - int s, error = 0; - - s = splnet(); + struct ether_header eh; + struct ieee80211_frame *wh; + struct llc *llc; - switch (cmd) { - case SIOCSIFADDR: - if ((error = awi_enable(sc)) != 0) - break; + if (m0->m_len < sizeof(eh)) { + m0 = m_pullup(m0, sizeof(eh)); + if (m0 == NULL) + return NULL; + } + memcpy(&eh, mtod(m0, caddr_t), sizeof(eh)); + if (sc->sc_format_llc) { + m_adj(m0, sizeof(struct ether_header) - sizeof(struct llc)); + llc = mtod(m0, struct llc *); + llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; + llc->llc_control = LLC_UI; + llc->llc_snap.org_code[0] = llc->llc_snap.org_code[1] = + llc->llc_snap.org_code[2] = 0; + llc->llc_snap.ether_type = eh.ether_type; + } + M_PREPEND(m0, sizeof(struct ieee80211_frame), M_DONTWAIT); + if (m0 == NULL) + return NULL; + wh = mtod(m0, struct ieee80211_frame *); + + wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; + LE_WRITE_2(wh->i_dur, 0); + LE_WRITE_2(wh->i_seq, 0); + if (sc->sc_mib_local.Network_Mode) { + wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; + memcpy(wh->i_addr1, sc->sc_bss.bssid, ETHER_ADDR_LEN); + memcpy(wh->i_addr2, eh.ether_shost, ETHER_ADDR_LEN); + memcpy(wh->i_addr3, eh.ether_dhost, ETHER_ADDR_LEN); + } else { + wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; + memcpy(wh->i_addr1, eh.ether_dhost, ETHER_ADDR_LEN); + memcpy(wh->i_addr2, eh.ether_shost, ETHER_ADDR_LEN); + memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN); + } + return m0; +} - ifp->if_flags |= IFF_UP; +static struct mbuf * +awi_fix_rxhdr(sc, m0) + struct awi_softc *sc; + struct mbuf *m0; +{ + struct ieee80211_frame wh; + struct ether_header *eh; + struct llc *llc; - /* XXX other AF support: inet6, NS, ... */ - switch (ifa->ifa_addr->sa_family) { -#ifdef INET - case AF_INET: - arp_ifinit(&sc->sc_ec, ifa); + if (m0->m_len < sizeof(wh)) { + m_freem(m0); + return NULL; + } + llc = (struct llc *)(mtod(m0, caddr_t) + sizeof(wh)); + if (llc->llc_dsap == LLC_SNAP_LSAP && + llc->llc_ssap == LLC_SNAP_LSAP && + llc->llc_control == LLC_UI && + llc->llc_snap.org_code[0] == 0 && + llc->llc_snap.org_code[1] == 0 && + llc->llc_snap.org_code[2] == 0) { + memcpy(&wh, mtod(m0, caddr_t), sizeof(wh)); + m_adj(m0, sizeof(wh) + sizeof(*llc) - sizeof(*eh)); + eh = mtod(m0, struct ether_header *); + switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + memcpy(eh->ether_dhost, wh.i_addr1, ETHER_ADDR_LEN); + memcpy(eh->ether_shost, wh.i_addr2, ETHER_ADDR_LEN); break; -#endif - default: + case IEEE80211_FC1_DIR_TODS: + memcpy(eh->ether_dhost, wh.i_addr3, ETHER_ADDR_LEN); + memcpy(eh->ether_shost, wh.i_addr2, ETHER_ADDR_LEN); break; + case IEEE80211_FC1_DIR_FROMDS: + memcpy(eh->ether_dhost, wh.i_addr1, ETHER_ADDR_LEN); + memcpy(eh->ether_shost, wh.i_addr3, ETHER_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_DSTODS: + m_freem(m0); + return NULL; } - break; - - case SIOCSIFFLAGS: - if ((ifp->if_flags & IFF_UP) == 0 && - (sc->sc_state != AWI_ST_OFF)) { - /* - * If interface is marked down and it is enabled, then - * stop it. - */ - ifp->if_flags &= ~IFF_RUNNING; - awi_stop(sc); - awi_disable(sc); - } else if ((ifp->if_flags & IFF_UP) != 0 && - (ifp->if_flags & IFF_RUNNING) == 0) { - /* - * If interface is marked up and it is stopped, then - * start it. - */ - if ((error = awi_enable(sc)) != 0) - break; - } else if ((ifp->if_flags & IFF_UP) != 0) { - /* - * Deal with other flags that change hardware - * state, i.e. IFF_PROMISC. - */ - awi_set_mc(sc); - } - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - error = (cmd == SIOCADDMULTI) ? - ether_addmulti(ifr, &sc->sc_ec) : - ether_delmulti(ifr, &sc->sc_ec); - if (error == ENETRESET) { - error = 0; - awi_set_mc(sc); + } else { + /* assuming ethernet encapsulation, just strip 802.11 header */ + m_adj(m0, sizeof(wh)); + } + if (ALIGN(mtod(m0, caddr_t) + sizeof(struct ether_header)) != + (u_int)(mtod(m0, caddr_t) + sizeof(struct ether_header))) { + /* XXX: we loose to estimate the type of encapsulation */ + struct mbuf *n, *n0, **np; + caddr_t newdata; + int off; + + n0 = NULL; + np = &n0; + off = 0; + while (m0->m_pkthdr.len > off) { + if (n0 == NULL) { + MGETHDR(n, M_DONTWAIT, MT_DATA); + if (n == NULL) { + m_freem(m0); + return NULL; + } + M_COPY_PKTHDR(n, m0); + n->m_len = MHLEN; + } else { + MGET(n, M_DONTWAIT, MT_DATA); + if (n == NULL) { + m_freem(m0); + m_freem(n0); + return NULL; + } + n->m_len = MLEN; + } + if (m0->m_pkthdr.len - off >= MINCLSIZE) { + MCLGET(n, M_DONTWAIT); + if (n->m_flags & M_EXT) + n->m_len = n->m_ext.ext_size; + } + if (n0 == NULL) { + newdata = (caddr_t) + ALIGN(n->m_data + + sizeof(struct ether_header)) + - sizeof(struct ether_header); + n->m_len -= newdata - n->m_data; + n->m_data = newdata; + } + if (n->m_len > m0->m_pkthdr.len - off) + n->m_len = m0->m_pkthdr.len - off; + m_copydata(m0, off, n->m_len, mtod(n, caddr_t)); + off += n->m_len; + *np = n; + np = &n->m_next; } - break; - - default: - error = EINVAL; - break; - + m_freem(m0); + m0 = n0; } - splx(s); - return error; - + return m0; } -int awi_activate (self, act) - struct device *self; - enum devact act; +static void +awi_input(sc, m, rxts, rssi) + struct awi_softc *sc; + struct mbuf *m; + u_int32_t rxts; + u_int8_t rssi; { - int s = splnet(); - panic("awi_activate"); - -#if 0 - switch (act) { - case DVACT_ACTIVATE: - rv = EOPNOTSUPP; - break; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211_frame *wh; +#ifndef __NetBSD__ + struct ether_header *eh; +#endif - case DVACT_DEACTIVATE: -#ifdef notyet - /* First, kill off the interface. */ - if_detach(sc->sc_ethercom.ec_if); + /* trim CRC here for WEP can find its own CRC at the end of packet. */ + m_adj(m, -ETHER_CRC_LEN); + AWI_BPF_MTAP(sc, m, AWI_BPF_RAW); + wh = mtod(m, struct ieee80211_frame *); + if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != + IEEE80211_FC0_VERSION_0) { + printf("%s; receive packet with wrong version: %x\n", + sc->sc_dev.dv_xname, wh->i_fc[0]); + m_freem(m); + ifp->if_ierrors++; + return; + } + if (wh->i_fc[1] & IEEE80211_FC1_WEP) { + m = awi_wep_encrypt(sc, m, 0); + if (m == NULL) { + ifp->if_ierrors++; + return; + } + wh = mtod(m, struct ieee80211_frame *); + } +#ifdef AWI_DEBUG + if (awi_dump) + awi_dump_pkt(sc, m, rssi); #endif - /* Now disable the interface. */ - awidisable(sc); - break; + if ((sc->sc_mib_local.Network_Mode || !sc->sc_no_bssid) && + sc->sc_status == AWI_ST_RUNNING) { + if (memcmp(wh->i_addr2, sc->sc_bss.bssid, ETHER_ADDR_LEN) == 0) { + sc->sc_rx_timer = 10; + sc->sc_bss.rssi = rssi; + } } + switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { + case IEEE80211_FC0_TYPE_DATA: + if (sc->sc_mib_local.Network_Mode) { + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) != + IEEE80211_FC1_DIR_FROMDS) { + m_freem(m); + return; + } + } else { + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) != + IEEE80211_FC1_DIR_NODS) { + m_freem(m); + return; + } + } + m = awi_fix_rxhdr(sc, m); + if (m == NULL) { + ifp->if_ierrors++; + break; + } + ifp->if_ipackets++; +#if !(defined(__FreeBSD__) && __FreeBSD__ >= 4) + AWI_BPF_MTAP(sc, m, AWI_BPF_NORM); #endif - splx(s); - +#ifdef __NetBSD__ + (*ifp->if_input)(ifp, m); +#else + eh = mtod(m, struct ether_header *); + m_adj(m, sizeof(*eh)); + ether_input(ifp, eh, m); +#endif + break; + case IEEE80211_FC0_TYPE_MGT: + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) != + IEEE80211_FC1_DIR_NODS) { + m_freem(m); + return; + } + switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { + case IEEE80211_FC0_SUBTYPE_PROBE_RESP: + case IEEE80211_FC0_SUBTYPE_BEACON: + awi_recv_beacon(sc, m, rxts, rssi); + break; + case IEEE80211_FC0_SUBTYPE_AUTH: + awi_recv_auth(sc, m); + break; + case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: + case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: + awi_recv_asresp(sc, m); + break; + case IEEE80211_FC0_SUBTYPE_DEAUTH: + if (sc->sc_mib_local.Network_Mode) + awi_send_auth(sc, 1); + break; + case IEEE80211_FC0_SUBTYPE_DISASSOC: + if (sc->sc_mib_local.Network_Mode) + awi_send_asreq(sc, 1); + break; + } + m_freem(m); + break; + case IEEE80211_FC0_TYPE_CTL: + default: + /* should not come here */ + m_freem(m); + break; + } } -int -awi_drop_output (ifp, m0, dst, rt0) - struct ifnet *ifp; - struct mbuf *m0; - struct sockaddr *dst; - struct rtentry *rt0; +static void +awi_rxint(sc) + struct awi_softc *sc; { - m_freem(m0); - return 0; -} + u_int8_t state, rate, rssi; + u_int16_t len; + u_int32_t frame, next, rxts, rxoff; + struct mbuf *m; -void -awi_drop_input (ifp, m0) - struct ifnet *ifp; - struct mbuf *m0; -{ - m_freem(m0); + rxoff = sc->sc_rxdoff; + for (;;) { + state = awi_read_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE); + if (state & AWI_RXD_ST_OWN) + break; + if (!(state & AWI_RXD_ST_CONSUMED)) { + if (state & AWI_RXD_ST_RXERROR) + sc->sc_ifp->if_ierrors++; + else { + len = awi_read_2(sc, rxoff + AWI_RXD_LEN); + rate = awi_read_1(sc, rxoff + AWI_RXD_RATE); + rssi = awi_read_1(sc, rxoff + AWI_RXD_RSSI); + frame = awi_read_4(sc, rxoff + AWI_RXD_START_FRAME) & 0x7fff; + rxts = awi_read_4(sc, rxoff + AWI_RXD_LOCALTIME); + m = awi_devget(sc, frame, len); + if (state & AWI_RXD_ST_LF) + awi_input(sc, m, rxts, rssi); + else + sc->sc_rxpend = m; + } + state |= AWI_RXD_ST_CONSUMED; + awi_write_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE, state); + } + next = awi_read_4(sc, rxoff + AWI_RXD_NEXT); + if (next & AWI_RXD_NEXT_LAST) + break; + /* make sure the next pointer is correct */ + if (next != awi_read_4(sc, rxoff + AWI_RXD_NEXT)) + break; + state |= AWI_RXD_ST_OWN; + awi_write_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE, state); + rxoff = next & 0x7fff; + } + sc->sc_rxdoff = rxoff; } -int awi_attach (sc, macaddr) +static struct mbuf * +awi_devget(sc, off, len) struct awi_softc *sc; - u_int8_t *macaddr; + u_int32_t off; + u_int16_t len; { - struct ifnet *ifp = &sc->sc_ec.ac_if; - u_int8_t version[AWI_BANNER_LEN]; - - sc->sc_ifp = ifp; - sc->sc_nextpkt = NULL; - sc->sc_m = NULL; - sc->sc_mptr = NULL; - sc->sc_mleft = 0; - sc->sc_flushpkt = 0; - - awi_read_bytes (sc, AWI_BANNER, version, AWI_BANNER_LEN); - printf("%s: firmware %s\n", sc->sc_dev.dv_xname, version); - - bcopy(macaddr, sc->sc_my_addr, ETHER_ADDR_LEN); - printf("%s: 802.11 address %s\n", sc->sc_dev.dv_xname, - ether_sprintf(sc->sc_my_addr)); - - bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); - ifp->if_softc = sc; - ifp->if_start = awi_start; - ifp->if_ioctl = awi_ioctl; - ifp->if_watchdog = awi_watchdog; - ifp->if_mtu = ETHERMTU; - /* XXX simplex may not be correct here.. */ - ifp->if_flags = - IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; - - sc->sc_mgtq.ifq_maxlen = 5; - - if_attach(ifp); - ether_ifattach(ifp); - ifp->if_hdrlen = 32; /* 802.11 headers are bigger.. */ + struct mbuf *m; + struct mbuf *top, **mp; + u_int tlen; + + top = sc->sc_rxpend; + mp = ⊤ + if (top != NULL) { + sc->sc_rxpend = NULL; + top->m_pkthdr.len += len; + m = top; + while (*mp != NULL) { + m = *mp; + mp = &m->m_next; + } + if (m->m_flags & M_EXT) + tlen = m->m_ext.ext_size; + else if (m->m_flags & M_PKTHDR) + tlen = MHLEN; + else + tlen = MLEN; + tlen -= m->m_len; + if (tlen > len) + tlen = len; + awi_read_bytes(sc, off, mtod(m, u_int8_t *) + m->m_len, tlen); + off += tlen; + len -= tlen; + } -#if NBPFILTER > 0 - bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); -#endif - return 0; + while (len > 0) { + if (top == NULL) { + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) + return NULL; + m->m_pkthdr.rcvif = sc->sc_ifp; + m->m_pkthdr.len = len; + m->m_len = MHLEN; + } else { + MGET(m, M_DONTWAIT, MT_DATA); + if (m == NULL) { + m_freem(top); + return NULL; + } + m->m_len = MLEN; + } + if (len >= MINCLSIZE) { + MCLGET(m, M_DONTWAIT); + if (m->m_flags & M_EXT) + m->m_len = m->m_ext.ext_size; + } + if (top == NULL) { + int hdrlen = sizeof(struct ieee80211_frame) + + (sc->sc_format_llc ? sizeof(struct llc) : + sizeof(struct ether_header)); + caddr_t newdata = (caddr_t) + ALIGN(m->m_data + hdrlen) - hdrlen; + m->m_len -= newdata - m->m_data; + m->m_data = newdata; + } + if (m->m_len > len) + m->m_len = len; + awi_read_bytes(sc, off, mtod(m, u_int8_t *), m->m_len); + off += m->m_len; + len -= m->m_len; + *mp = m; + mp = &m->m_next; + } + return top; } -void -awi_zero (sc, from, to) - struct awi_softc *sc; - u_int32_t from, to; -{ - u_int32_t i; - for (i=from; i<to; i++) - awi_write_1(sc, i, 0); -} +/* + * Initialize hardware and start firmware to accept commands. + * Called everytime after power on firmware. + */ -void -awi_init (sc) +static int +awi_init_hw(sc) struct awi_softc *sc; { - struct ifnet *ifp = sc->sc_ifp; - - sc->sc_scan_duration = 100; /* scan for 100ms */ - - /* - * Maybe we should randomize these.... - */ - sc->sc_scan_chanset = IEEEWL_FH_CHANSET_MIN; - sc->sc_scan_pattern = IEEEWL_FH_PATTERN_MIN; - - sc->sc_flags &= ~AWI_FL_CMD_INPROG; - - ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); - ifp->if_timer = 0; - - sc->sc_cmd_timer = 0; - sc->sc_tx_timer = 0; - sc->sc_mgt_timer = 0; - sc->sc_scan_timer = 0; - - sc->sc_nbindings = 0; - - /* - * this reset sequence doesn't seem to always do the trick. - * hard-power-cycling the card may do it.. - */ - - /* - * reset the hardware, just to be sure. - * (bring out the big hammer here..) - */ - /* XXX insert delay here? */ - - am79c930_gcr_setbits (&sc->sc_chip, AM79C930_GCR_CORESET); - delay(10); /* XXX arbitrary value */ - - /* - * clear control memory regions (firmware should do this but...) - */ - awi_zero(sc, AWI_LAST_TXD, AWI_BUFFERS); + u_int8_t status; + u_int16_t intmask; + int i, error; + sc->sc_enab_intr = 0; + sc->sc_invalid = 0; /* XXX: really? */ awi_drvstate(sc, AWI_DRV_RESET); - sc->sc_selftest_tries = 0; - /* - * release reset - */ - am79c930_gcr_clearbits (&sc->sc_chip, AM79C930_GCR_CORESET); - delay(10); - - sc->sc_state = AWI_ST_SELFTEST; - ifp->if_timer = 1; + /* reset firmware */ + am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_CORESET); + DELAY(100); + awi_write_1(sc, AWI_SELFTEST, 0); + awi_write_1(sc, AWI_CMD, 0); + awi_write_1(sc, AWI_BANNER, 0); + am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_CORESET); + DELAY(100); + + /* wait for selftest completion */ + for (i = 0; ; i++) { + if (i >= AWI_SELFTEST_TIMEOUT*hz/1000) { + printf("%s: failed to complete selftest (timeout)\n", + sc->sc_dev.dv_xname); + return ENXIO; + } + status = awi_read_1(sc, AWI_SELFTEST); + if ((status & 0xf0) == 0xf0) + break; + if (sc->sc_cansleep) { + sc->sc_sleep_cnt++; + (void)tsleep(sc, PWAIT, "awitst", 1); + sc->sc_sleep_cnt--; + } else { + DELAY(1000*1000/hz); + } + } + if (status != AWI_SELFTEST_PASSED) { + printf("%s: failed to complete selftest (code %x)\n", + sc->sc_dev.dv_xname, status); + return ENXIO; + } -} + /* check banner to confirm firmware write it */ + awi_read_bytes(sc, AWI_BANNER, sc->sc_banner, AWI_BANNER_LEN); + if (memcmp(sc->sc_banner, "PCnetMobile:", 12) != 0) { + printf("%s: failed to complete selftest (bad banner)\n", + sc->sc_dev.dv_xname); + for (i = 0; i < AWI_BANNER_LEN; i++) + printf("%s%02x", i ? ":" : "\t", sc->sc_banner[i]); + printf("\n"); + return ENXIO; + } -void -awi_cmd (sc, opcode) - struct awi_softc *sc; - u_int8_t opcode; -{ - if (sc->sc_flags & AWI_FL_CMD_INPROG) - panic("%s: command reentered", sc->sc_dev.dv_xname); - - sc->sc_flags |= AWI_FL_CMD_INPROG; - - /* issue test-interface command */ - awi_write_1(sc, AWI_CMD, opcode); - - awi_write_1(sc, AWI_CMD_STATUS, 0); - - sc->sc_cmd_timer = 2; - awi_set_timer(sc); -} + /* initializing interrupt */ + sc->sc_enab_intr = 1; + error = awi_intr_lock(sc); + if (error) + return error; + intmask = AWI_INT_GROGGY | AWI_INT_SCAN_CMPLT | + AWI_INT_TX | AWI_INT_RX | AWI_INT_CMD; + awi_write_1(sc, AWI_INTMASK, ~intmask & 0xff); + awi_write_1(sc, AWI_INTMASK2, 0); + awi_write_1(sc, AWI_INTSTAT, 0); + awi_write_1(sc, AWI_INTSTAT2, 0); + awi_intr_unlock(sc); + am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_ENECINT); -void -awi_cmd_test_if (sc) - struct awi_softc *sc; -{ - awi_cmd (sc, AWI_CMD_NOP); + /* issueing interface test command */ + error = awi_cmd(sc, AWI_CMD_NOP); + if (error) { + printf("%s: failed to complete selftest", sc->sc_dev.dv_xname); + if (error == ENXIO) + printf(" (no hardware)\n"); + else if (error != EWOULDBLOCK) + printf(" (error %d)\n", error); + else if (sc->sc_cansleep) + printf(" (lost interrupt)\n"); + else + printf(" (command timeout)\n"); + } + return error; } -void -awi_cmd_get_mib (sc, var, offset, len) +/* + * Extract the factory default MIB value from firmware and assign the driver + * default value. + * Called once at attaching the interface. + */ + +static int +awi_init_mibs(sc) struct awi_softc *sc; - u_int8_t var; - u_int8_t offset; - u_int8_t len; { - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, var); - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, len); - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, offset); + int i, error; + u_int8_t *rate; + + if ((error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_LOCAL)) != 0 || + (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_ADDR)) != 0 || + (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MAC)) != 0 || + (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MGT)) != 0 || + (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_PHY)) != 0) { + printf("%s: failed to get default mib value (error %d)\n", + sc->sc_dev.dv_xname, error); + return error; + } - awi_cmd (sc, AWI_CMD_GET_MIB); + rate = sc->sc_mib_phy.aSuprt_Data_Rates; + sc->sc_tx_rate = AWI_RATE_1MBIT; + for (i = 0; i < rate[1]; i++) { + if (AWI_80211_RATE(rate[2 + i]) > sc->sc_tx_rate) + sc->sc_tx_rate = AWI_80211_RATE(rate[2 + i]); + } + awi_init_region(sc); + memset(&sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE); + sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID; + sc->sc_mib_local.Fragmentation_Dis = 1; + sc->sc_mib_local.Accept_All_Multicast_Dis = 1; + sc->sc_mib_local.Power_Saving_Mode_Dis = 1; + + /* allocate buffers */ + sc->sc_txbase = AWI_BUFFERS; + sc->sc_txend = sc->sc_txbase + + (AWI_TXD_SIZE + sizeof(struct ieee80211_frame) + + sizeof(struct ether_header) + ETHERMTU) * AWI_NTXBUFS; + LE_WRITE_4(&sc->sc_mib_local.Tx_Buffer_Offset, sc->sc_txbase); + LE_WRITE_4(&sc->sc_mib_local.Tx_Buffer_Size, + sc->sc_txend - sc->sc_txbase); + LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Offset, sc->sc_txend); + LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Size, + AWI_BUFFERS_END - sc->sc_txend); + sc->sc_mib_local.Network_Mode = 1; + sc->sc_mib_local.Acting_as_AP = 0; + return 0; } -void -awi_cmd_txinit (sc) +/* + * Start transmitter and receiver of firmware + * Called after awi_init_hw() to start operation. + */ + +static int +awi_init_txrx(sc) struct awi_softc *sc; { + int error; + + /* start transmitter */ + sc->sc_txdone = sc->sc_txnext = sc->sc_txbase; + awi_write_4(sc, sc->sc_txbase + AWI_TXD_START, 0); + awi_write_4(sc, sc->sc_txbase + AWI_TXD_NEXT, 0); + awi_write_4(sc, sc->sc_txbase + AWI_TXD_LENGTH, 0); + awi_write_1(sc, sc->sc_txbase + AWI_TXD_RATE, 0); + awi_write_4(sc, sc->sc_txbase + AWI_TXD_NDA, 0); + awi_write_4(sc, sc->sc_txbase + AWI_TXD_NRA, 0); + awi_write_1(sc, sc->sc_txbase + AWI_TXD_STATE, 0); awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_DATA, sc->sc_txbase); awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_MGT, 0); awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_BCAST, 0); awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_PS, 0); awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_CF, 0); - - awi_cmd (sc, AWI_CMD_INIT_TX); + error = awi_cmd(sc, AWI_CMD_INIT_TX); + if (error) + return error; + + /* start receiver */ + if (sc->sc_rxpend) { + m_freem(sc->sc_rxpend); + sc->sc_rxpend = NULL; + } + error = awi_cmd(sc, AWI_CMD_INIT_RX); + if (error) + return error; + sc->sc_rxdoff = awi_read_4(sc, AWI_CMD_PARAMS+AWI_CA_IRX_DATA_DESC); + sc->sc_rxmoff = awi_read_4(sc, AWI_CMD_PARAMS+AWI_CA_IRX_PS_DESC); + return 0; } -int awi_max_chan = -1; -int awi_min_chan = 1000; -int awi_max_pattern = -1; -int awi_min_pattern = 1000; - - -/* - * timeout-driven routine: complete device init once device has passed - * selftest. - */ - -void awi_init_1 (sc) +static void +awi_stop_txrx(sc) struct awi_softc *sc; { - struct ifnet *ifp = sc->sc_ifp; - - awi_intrinit(sc); - - sc->sc_state = AWI_ST_IFTEST; - - if (ifp->if_flags & IFF_DEBUG) { - awi_card_hexdump(sc, "init_1 CSB", AWI_CSB, 16); - sc->sc_completion = awi_mibdump; - } else - sc->sc_completion = awi_init_2; - sc->sc_curmib = 0; - - awi_cmd_test_if (sc); + if (sc->sc_cmd_inprog) + (void)awi_cmd_wait(sc); + (void)awi_cmd(sc, AWI_CMD_KILL_RX); + (void)awi_cmd_wait(sc); + sc->sc_cmd_inprog = AWI_CMD_FLUSH_TX; + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_DATA, 1); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_MGT, 0); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_BCAST, 0); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_PS, 0); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_CF, 0); + (void)awi_cmd(sc, AWI_CMD_FLUSH_TX); + (void)awi_cmd_wait(sc); } -void awi_mibdump (sc, status) +int +awi_init_region(sc) struct awi_softc *sc; - u_int8_t status; { - u_int8_t mibblk[256]; - - if (status != AWI_STAT_OK) { - printf("%s: pre-mibread failed (card unhappy?)\n", - sc->sc_dev.dv_xname); - awi_reset(sc); - return; - } - - if (sc->sc_curmib != 0) { - awi_read_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, - mibblk, 72); - awi_hexdump("mib", mibblk, 72); - } - if (sc->sc_curmib > AWI_MIB_LAST) { - awi_init_2 (sc, status); + + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { + switch (sc->sc_mib_phy.aCurrent_Reg_Domain) { + case AWI_REG_DOMAIN_US: + case AWI_REG_DOMAIN_CA: + case AWI_REG_DOMAIN_EU: + sc->sc_scan_min = 0; + sc->sc_scan_max = 77; + break; + case AWI_REG_DOMAIN_ES: + sc->sc_scan_min = 0; + sc->sc_scan_max = 26; + break; + case AWI_REG_DOMAIN_FR: + sc->sc_scan_min = 0; + sc->sc_scan_max = 32; + break; + case AWI_REG_DOMAIN_JP: + sc->sc_scan_min = 6; + sc->sc_scan_max = 17; + break; + default: + return EINVAL; + } + sc->sc_scan_set = sc->sc_scan_cur % 3 + 1; } else { - sc->sc_completion = awi_mibdump; - printf("mib %d\n", sc->sc_curmib); - awi_cmd_get_mib (sc, sc->sc_curmib, 0, 30); - sc->sc_curmib++; - /* skip over reserved MIB's.. */ - if ((sc->sc_curmib == 1) || (sc->sc_curmib == 6)) - sc->sc_curmib++; + switch (sc->sc_mib_phy.aCurrent_Reg_Domain) { + case AWI_REG_DOMAIN_US: + case AWI_REG_DOMAIN_CA: + sc->sc_scan_min = 1; + sc->sc_scan_max = 11; + sc->sc_scan_cur = 3; + break; + case AWI_REG_DOMAIN_EU: + sc->sc_scan_min = 1; + sc->sc_scan_max = 13; + sc->sc_scan_cur = 3; + break; + case AWI_REG_DOMAIN_ES: + sc->sc_scan_min = 10; + sc->sc_scan_max = 11; + sc->sc_scan_cur = 10; + break; + case AWI_REG_DOMAIN_FR: + sc->sc_scan_min = 10; + sc->sc_scan_max = 13; + sc->sc_scan_cur = 10; + break; + case AWI_REG_DOMAIN_JP: + sc->sc_scan_min = 14; + sc->sc_scan_max = 14; + sc->sc_scan_cur = 14; + break; + default: + return EINVAL; + } } + sc->sc_ownch = sc->sc_scan_cur; + return 0; } - -/* - * called on completion of test-interface command in first-stage init. - */ - -void awi_init_2 (sc, status) +static int +awi_start_scan(sc) struct awi_softc *sc; - u_int8_t status; { - /* did it succeed? */ - if (status != AWI_STAT_OK) { - printf("%s: nop failed (card unhappy?)\n", - sc->sc_dev.dv_xname); - awi_reset(sc); - } - - sc->sc_state = AWI_ST_MIB_GET; - sc->sc_completion = awi_init_read_bufptrs_done; + int error = 0; + struct awi_bss *bp; - awi_cmd_get_mib (sc, AWI_MIB_LOCAL, 0, AWI_MIB_LOCAL_SIZE); + while ((bp = TAILQ_FIRST(&sc->sc_scan)) != NULL) { + TAILQ_REMOVE(&sc->sc_scan, bp, list); + free(bp, M_DEVBUF); + } + if (!sc->sc_mib_local.Network_Mode && sc->sc_no_bssid) { + memset(&sc->sc_bss, 0, sizeof(sc->sc_bss)); + sc->sc_bss.essid[0] = IEEE80211_ELEMID_SSID; + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { + sc->sc_bss.chanset = sc->sc_ownch % 3 + 1; + sc->sc_bss.pattern = sc->sc_ownch; + sc->sc_bss.index = 1; + sc->sc_bss.dwell_time = 200; /*XXX*/ + } else + sc->sc_bss.chanset = sc->sc_ownch; + sc->sc_status = AWI_ST_SETSS; + error = awi_set_ss(sc); + } else { + if (sc->sc_mib_local.Network_Mode) + awi_drvstate(sc, AWI_DRV_INFSC); + else + awi_drvstate(sc, AWI_DRV_ADHSC); + sc->sc_start_bss = 0; + sc->sc_active_scan = 1; + sc->sc_mgt_timer = AWI_ASCAN_WAIT / 1000; + sc->sc_ifp->if_timer = 1; + sc->sc_status = AWI_ST_SCAN; + error = awi_cmd_scan(sc); + } + return error; } -void awi_init_read_bufptrs_done (sc, status) +static int +awi_next_scan(sc) struct awi_softc *sc; - u_int8_t status; { - if (status != AWI_STAT_OK) { - printf("%s: get_mib failed (card unhappy?)\n", - sc->sc_dev.dv_xname); - awi_reset(sc); - } - - sc->sc_txbase = awi_read_4 (sc, - AWI_CMD_PARAMS+AWI_CA_MIB_DATA+AWI_MIB_LOCAL_TXB_OFFSET); - sc->sc_txlen = awi_read_4 (sc, - AWI_CMD_PARAMS+AWI_CA_MIB_DATA+AWI_MIB_LOCAL_TXB_SIZE); - sc->sc_rxbase = awi_read_4 (sc, - AWI_CMD_PARAMS+AWI_CA_MIB_DATA+AWI_MIB_LOCAL_RXB_OFFSET); - sc->sc_rxlen = awi_read_4 (sc, - AWI_CMD_PARAMS+AWI_CA_MIB_DATA+AWI_MIB_LOCAL_RXB_SIZE); - /* - * XXX consider repartitioning buffer space to allow for - * more efficient usage. - * 6144: 3 txds, 1476 waste (current partition) - * better splits: - * 4864: 3 txds, 196 waste - * 6400: 4 txds, 176 waste - * 7936: 5 txds, 156 waste - */ + int error; -#if 0 - printf("tx offset: %x\n", sc->sc_txbase); - printf("tx size: %x\n", sc->sc_txlen); - printf("rx offset: %x\n", sc->sc_rxbase); - printf("rx size: %x\n", sc->sc_rxlen); -#endif - - sc->sc_state = AWI_ST_MIB_SET; - awi_cmd_set_notap(sc); + for (;;) { + /* + * The pattern parameter for FH phy should be incremented + * by 3. But BayStack 650 Access Points apparently always + * assign hop pattern set parameter to 1 for any pattern. + * So we try all combinations of pattern/set parameters. + * Since this causes no error, it may be a bug of + * PCnetMobile firmware. + */ + sc->sc_scan_cur++; + if (sc->sc_scan_cur > sc->sc_scan_max) { + sc->sc_scan_cur = sc->sc_scan_min; + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) + sc->sc_scan_set = sc->sc_scan_set % 3 + 1; + } + error = awi_cmd_scan(sc); + if (error != EINVAL) + break; + } + return error; } -void awi_cmd_set_notap (sc) +static void +awi_stop_scan(sc) struct awi_softc *sc; { - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, AWI_MIB_LOCAL); - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, 1); - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, - AWI_MIB_LOCAL_ACTING_AS_AP); - - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, 0); - sc->sc_completion = awi_cmd_set_notap_done; - awi_cmd (sc, AWI_CMD_SET_MIB); -} + struct ifnet *ifp = sc->sc_ifp; + struct awi_bss *bp, *sbp; + int fail; -void awi_cmd_set_notap_done (sc, status) - struct awi_softc *sc; - u_int8_t status; -{ - if (status != AWI_STAT_OK) { - int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); - printf("%s: set_infra failed (card unhappy?); erroffset %d\n", - sc->sc_dev.dv_xname, - erroffset); - awi_reset(sc); + bp = TAILQ_FIRST(&sc->sc_scan); + if (bp == NULL) { + notfound: + if (sc->sc_active_scan) { + if (ifp->if_flags & IFF_DEBUG) + printf("%s: entering passive scan mode\n", + sc->sc_dev.dv_xname); + sc->sc_active_scan = 0; + } + sc->sc_mgt_timer = AWI_PSCAN_WAIT / 1000; + ifp->if_timer = 1; + (void)awi_next_scan(sc); return; } - awi_cmd_set_infra (sc); + sbp = NULL; + if (ifp->if_flags & IFF_DEBUG) + printf("%s:\tmacaddr ch/pat sig flag wep essid\n", + sc->sc_dev.dv_xname); + for (; bp != NULL; bp = TAILQ_NEXT(bp, list)) { + if (bp->fails) { + /* + * The configuration of the access points may change + * during my scan. So we retries to associate with + * it unless there are any suitable AP. + */ + if (bp->fails++ < 3) + continue; + bp->fails = 0; + } + fail = 0; + /* + * Since the firmware apparently scans not only the specified + * channel of SCAN command but all available channel within + * the region, we should filter out unnecessary responses here. + */ + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { + if (bp->pattern < sc->sc_scan_min || + bp->pattern > sc->sc_scan_max) + fail |= 0x01; + } else { + if (bp->chanset < sc->sc_scan_min || + bp->chanset > sc->sc_scan_max) + fail |= 0x01; + } + if (sc->sc_mib_local.Network_Mode) { + if (!(bp->capinfo & IEEE80211_CAPINFO_ESS) || + (bp->capinfo & IEEE80211_CAPINFO_IBSS)) + fail |= 0x02; + } else { + if ((bp->capinfo & IEEE80211_CAPINFO_ESS) || + !(bp->capinfo & IEEE80211_CAPINFO_IBSS)) + fail |= 0x02; + } + if (sc->sc_wep_algo == NULL) { + if (bp->capinfo & IEEE80211_CAPINFO_PRIVACY) + fail |= 0x04; + } else { + if (!(bp->capinfo & IEEE80211_CAPINFO_PRIVACY)) + fail |= 0x04; + } + if (sc->sc_mib_mac.aDesired_ESS_ID[1] != 0 && + memcmp(&sc->sc_mib_mac.aDesired_ESS_ID, bp->essid, + sizeof(bp->essid)) != 0) + fail |= 0x08; + if (ifp->if_flags & IFF_DEBUG) { + printf(" %c %s", fail ? '-' : '+', + ether_sprintf(bp->esrc)); + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) + printf(" %2d/%d%c", bp->pattern, bp->chanset, + fail & 0x01 ? '!' : ' '); + else + printf(" %4d%c", bp->chanset, + fail & 0x01 ? '!' : ' '); + printf(" %+4d", bp->rssi); + printf(" %4s%c", + (bp->capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : + (bp->capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : + "????", + fail & 0x02 ? '!' : ' '); + printf(" %3s%c ", + (bp->capinfo & IEEE80211_CAPINFO_PRIVACY) ? "wep" : + "no", + fail & 0x04 ? '!' : ' '); + awi_print_essid(bp->essid); + printf("%s\n", fail & 0x08 ? "!" : ""); + } + if (!fail) { + if (sbp == NULL || bp->rssi > sbp->rssi) + sbp = bp; + } + } + if (sbp == NULL) + goto notfound; + sc->sc_bss = *sbp; + (void)awi_set_ss(sc); } -void awi_cmd_set_infra (sc) +static void +awi_recv_beacon(sc, m0, rxts, rssi) struct awi_softc *sc; + struct mbuf *m0; + u_int32_t rxts; + u_int8_t rssi; { + struct ieee80211_frame *wh; + struct awi_bss *bp; + u_int8_t *frame, *eframe; + u_int8_t *tstamp, *bintval, *capinfo, *ssid, *rates, *parms; - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, AWI_MIB_LOCAL); - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, 1); - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, - AWI_MIB_LOCAL_INFRA_MODE); - - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, 1); - sc->sc_completion = awi_cmd_set_infra_done; - awi_cmd (sc, AWI_CMD_SET_MIB); -} + if (sc->sc_status != AWI_ST_SCAN) + return; + wh = mtod(m0, struct ieee80211_frame *); -void awi_cmd_set_infra_done (sc, status) - struct awi_softc *sc; - u_int8_t status; -{ -#if 0 - printf("set_infra done\n"); + frame = (u_int8_t *)&wh[1]; + eframe = mtod(m0, u_int8_t *) + m0->m_len; + /* + * XXX: + * timestamp [8] + * beacon interval [2] + * capability information [2] + * ssid [tlv] + * supported rates [tlv] + * parameter set [tlv] + * ... + */ + if (frame + 12 > eframe) { +#ifdef AWI_DEBUG + if (awi_verbose) + printf("awi_recv_beacon: frame too short \n"); #endif - if (status != AWI_STAT_OK) { - int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); - printf("%s: set_infra failed (card unhappy?); erroffset %d\n", - sc->sc_dev.dv_xname, - erroffset); - awi_reset(sc); return; } -#if 0 - printf("%s: set_infra done\n", sc->sc_dev.dv_xname); + tstamp = frame; + frame += 8; + bintval = frame; + frame += 2; + capinfo = frame; + frame += 2; + + ssid = rates = parms = NULL; + while (frame < eframe) { + switch (*frame) { + case IEEE80211_ELEMID_SSID: + ssid = frame; + break; + case IEEE80211_ELEMID_RATES: + rates = frame; + break; + case IEEE80211_ELEMID_FHPARMS: + case IEEE80211_ELEMID_DSPARMS: + parms = frame; + break; + } + frame += frame[1] + 2; + } + if (ssid == NULL || rates == NULL || parms == NULL) { +#ifdef AWI_DEBUG + if (awi_verbose) + printf("awi_recv_beacon: ssid=%p, rates=%p, parms=%p\n", + ssid, rates, parms); #endif - awi_cmd_set_allmulti (sc); -} + return; + } + if (ssid[1] > IEEE80211_NWID_LEN) { +#ifdef AWI_DEBUG + if (awi_verbose) + printf("awi_recv_beacon: bad ssid len: %d from %s\n", + ssid[1], ether_sprintf(wh->i_addr2)); +#endif + return; + } -void awi_cmd_set_allmulti (sc) - struct awi_softc *sc; -{ - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, AWI_MIB_LOCAL); - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, 1); - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, - AWI_MIB_LOCAL_FILTMULTI); - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, 0); - sc->sc_completion = awi_cmd_set_allmulti_done; - awi_cmd (sc, AWI_CMD_SET_MIB); + for (bp = TAILQ_FIRST(&sc->sc_scan); bp != NULL; + bp = TAILQ_NEXT(bp, list)) { + if (memcmp(bp->esrc, wh->i_addr2, ETHER_ADDR_LEN) == 0 && + memcmp(bp->bssid, wh->i_addr3, ETHER_ADDR_LEN) == 0) + break; + } + if (bp == NULL) { + bp = malloc(sizeof(struct awi_bss), M_DEVBUF, M_NOWAIT); + if (bp == NULL) + return; + TAILQ_INSERT_TAIL(&sc->sc_scan, bp, list); + memcpy(bp->esrc, wh->i_addr2, ETHER_ADDR_LEN); + memcpy(bp->bssid, wh->i_addr3, ETHER_ADDR_LEN); + memset(bp->essid, 0, sizeof(bp->essid)); + memcpy(bp->essid, ssid, 2 + ssid[1]); + } + bp->rssi = rssi; + bp->rxtime = rxts; + memcpy(bp->timestamp, tstamp, sizeof(bp->timestamp)); + bp->interval = LE_READ_2(bintval); + bp->capinfo = LE_READ_2(capinfo); + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { + bp->chanset = parms[4]; + bp->pattern = parms[5]; + bp->index = parms[6]; + bp->dwell_time = LE_READ_2(parms + 2); + } else { + bp->chanset = parms[2]; + bp->pattern = 0; + bp->index = 0; + bp->dwell_time = 0; + } + if (sc->sc_mgt_timer == 0) + awi_stop_scan(sc); } -void awi_cmd_set_allmulti_done (sc, status) +static int +awi_set_ss(sc) struct awi_softc *sc; - u_int8_t status; { - if (status != AWI_STAT_OK) { - int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); - printf("%s: set_almulti_done failed (card unhappy?); erroffset %d\n", - sc->sc_dev.dv_xname, - erroffset); - awi_reset(sc); - return; + struct ifnet *ifp = sc->sc_ifp; + struct awi_bss *bp; + int error; + + sc->sc_status = AWI_ST_SETSS; + bp = &sc->sc_bss; + if (ifp->if_flags & IFF_DEBUG) { + printf("%s: ch %d pat %d id %d dw %d iv %d bss %s ssid ", + sc->sc_dev.dv_xname, bp->chanset, + bp->pattern, bp->index, bp->dwell_time, bp->interval, + ether_sprintf(bp->bssid)); + awi_print_essid(bp->essid); + printf("\n"); } - awi_cmd_set_promisc (sc); + memcpy(&sc->sc_mib_mgt.aCurrent_BSS_ID, bp->bssid, ETHER_ADDR_LEN); + memcpy(&sc->sc_mib_mgt.aCurrent_ESS_ID, bp->essid, + AWI_ESS_ID_SIZE); + LE_WRITE_2(&sc->sc_mib_mgt.aBeacon_Period, bp->interval); + error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT); + return error; } -void awi_cmd_set_promisc (sc) +static void +awi_try_sync(sc) struct awi_softc *sc; { - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, AWI_MIB_MAC); - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, 1); - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, - AWI_MIB_MAC_PROMISC); - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, 0); /* XXX */ - sc->sc_completion = awi_cmd_set_promisc_done; - awi_cmd (sc, AWI_CMD_SET_MIB); -} + struct awi_bss *bp; -void awi_cmd_set_promisc_done (sc, status) + sc->sc_status = AWI_ST_SYNC; + bp = &sc->sc_bss; + + if (sc->sc_cmd_inprog) { + if (awi_cmd_wait(sc)) + return; + } + sc->sc_cmd_inprog = AWI_CMD_SYNC; + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_SET, bp->chanset); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_PATTERN, bp->pattern); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_IDX, bp->index); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_STARTBSS, + sc->sc_start_bss ? 1 : 0); + awi_write_2(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_DWELL, bp->dwell_time); + awi_write_2(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_MBZ, 0); + awi_write_bytes(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_TIMESTAMP, + bp->timestamp, 8); + awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_REFTIME, bp->rxtime); + (void)awi_cmd(sc, AWI_CMD_SYNC); +} + +static void +awi_sync_done(sc) struct awi_softc *sc; - u_int8_t status; { -#if 0 - printf("set promisc_done\n"); -#endif - - if (status != AWI_STAT_OK) { - int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); - printf("%s: set_promisc_done failed (card unhappy?); erroffset %d\n", - sc->sc_dev.dv_xname, - erroffset); - awi_reset(sc); - return; - } -#if 0 - printf("%s: set_promisc done\n", sc->sc_dev.dv_xname); -#endif - - awi_init_txdescr(sc); + struct ifnet *ifp = sc->sc_ifp; - sc->sc_state = AWI_ST_TXINIT; - sc->sc_completion = awi_init_4; - awi_cmd_txinit(sc); + if (sc->sc_mib_local.Network_Mode) { + awi_drvstate(sc, AWI_DRV_INFSY); + awi_send_auth(sc, 1); + } else { + if (ifp->if_flags & IFF_DEBUG) { + printf("%s: synced with", sc->sc_dev.dv_xname); + if (sc->sc_no_bssid) + printf(" no-bssid"); + else { + printf(" %s ssid ", + ether_sprintf(sc->sc_bss.bssid)); + awi_print_essid(sc->sc_bss.essid); + } + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) + printf(" at chanset %d pattern %d\n", + sc->sc_bss.chanset, sc->sc_bss.pattern); + else + printf(" at channel %d\n", sc->sc_bss.chanset); + } + awi_drvstate(sc, AWI_DRV_ADHSY); + sc->sc_status = AWI_ST_RUNNING; + ifp->if_flags |= IFF_RUNNING; + awi_start(ifp); + } } -void -awi_init_4 (sc, status) +static void +awi_send_deauth(sc) struct awi_softc *sc; - u_int8_t status; { -#if 0 - printf("%s: awi_init_4, st %x\n", sc->sc_dev.dv_xname, status); - awi_card_hexdump(sc, "init_4 CSB", AWI_CSB, 16); -#endif + struct ifnet *ifp = sc->sc_ifp; + struct mbuf *m; + struct ieee80211_frame *wh; + u_int8_t *deauth; - if (status != AWI_STAT_OK) { - int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); - printf("%s: init_tx failed (card unhappy?); erroffset %d\n", - sc->sc_dev.dv_xname, - erroffset); - awi_reset(sc); + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) return; - } - - sc->sc_state = AWI_ST_RXINIT; - sc->sc_completion = awi_init_5; - - awi_cmd (sc, AWI_CMD_INIT_RX); + if (ifp->if_flags & IFF_DEBUG) + printf("%s: sending deauth to %s\n", sc->sc_dev.dv_xname, + ether_sprintf(sc->sc_bss.bssid)); + + wh = mtod(m, struct ieee80211_frame *); + wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | + IEEE80211_FC0_SUBTYPE_AUTH; + wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; + LE_WRITE_2(wh->i_dur, 0); + LE_WRITE_2(wh->i_seq, 0); + memcpy(wh->i_addr1, sc->sc_bss.bssid, ETHER_ADDR_LEN); + memcpy(wh->i_addr2, sc->sc_mib_addr.aMAC_Address, ETHER_ADDR_LEN); + memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN); + + deauth = (u_int8_t *)&wh[1]; + LE_WRITE_2(deauth, IEEE80211_REASON_AUTH_LEAVE); + deauth += 2; + + m->m_pkthdr.len = m->m_len = deauth - mtod(m, u_int8_t *); + IF_ENQUEUE(&sc->sc_mgtq, m); + awi_start(ifp); + awi_drvstate(sc, AWI_DRV_INFTOSS); } -void awi_init_5 (sc, status) +static void +awi_send_auth(sc, seq) struct awi_softc *sc; - u_int8_t status; + int seq; { -#if 0 struct ifnet *ifp = sc->sc_ifp; -#endif - -#if 0 - printf("%s: awi_init_5, st %x\n", sc->sc_dev.dv_xname, status); - awi_card_hexdump(sc, "init_5 CSB", AWI_CSB, 16); -#endif + struct mbuf *m; + struct ieee80211_frame *wh; + u_int8_t *auth; - if (status != AWI_STAT_OK) { - printf("%s: init_rx failed (card unhappy?)\n", - sc->sc_dev.dv_xname); - awi_reset(sc); + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) return; - } - - sc->sc_rx_data_desc = awi_read_4(sc, AWI_CMD_PARAMS+AWI_CA_IRX_DATA_DESC); - sc->sc_rx_mgt_desc = awi_read_4(sc, AWI_CMD_PARAMS+AWI_CA_IRX_PS_DESC); + sc->sc_status = AWI_ST_AUTH; + if (ifp->if_flags & IFF_DEBUG) + printf("%s: sending auth to %s\n", sc->sc_dev.dv_xname, + ether_sprintf(sc->sc_bss.bssid)); + + wh = mtod(m, struct ieee80211_frame *); + wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | + IEEE80211_FC0_SUBTYPE_AUTH; + wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; + LE_WRITE_2(wh->i_dur, 0); + LE_WRITE_2(wh->i_seq, 0); + memcpy(wh->i_addr1, sc->sc_bss.esrc, ETHER_ADDR_LEN); + memcpy(wh->i_addr2, sc->sc_mib_addr.aMAC_Address, ETHER_ADDR_LEN); + memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN); + + auth = (u_int8_t *)&wh[1]; + /* algorithm number */ + LE_WRITE_2(auth, IEEE80211_AUTH_ALG_OPEN); + auth += 2; + /* sequence number */ + LE_WRITE_2(auth, seq); + auth += 2; + /* status */ + LE_WRITE_2(auth, 0); + auth += 2; + + m->m_pkthdr.len = m->m_len = auth - mtod(m, u_int8_t *); + IF_ENQUEUE(&sc->sc_mgtq, m); + awi_start(ifp); -#if 0 - printf("%s: data desc %x, mgt desc %x\n", sc->sc_dev.dv_xname, - sc->sc_rx_data_desc, sc->sc_rx_mgt_desc); -#endif - awi_restart_scan(sc); + sc->sc_mgt_timer = AWI_TRANS_TIMEOUT / 1000; + ifp->if_timer = 1; } -void awi_restart_scan (sc) +static void +awi_recv_auth(sc, m0) struct awi_softc *sc; + struct mbuf *m0; { - if (sc->sc_ifp->if_flags & IFF_DEBUG) { - printf("%s: starting scan\n", sc->sc_dev.dv_xname); + struct ieee80211_frame *wh; + u_int8_t *auth, *eframe; + struct awi_bss *bp; + u_int16_t status; + + wh = mtod(m0, struct ieee80211_frame *); + auth = (u_int8_t *)&wh[1]; + eframe = mtod(m0, u_int8_t *) + m0->m_len; + if (sc->sc_ifp->if_flags & IFF_DEBUG) + printf("%s: receive auth from %s\n", sc->sc_dev.dv_xname, + ether_sprintf(wh->i_addr2)); + + /* algorithm number */ + if (LE_READ_2(auth) != IEEE80211_AUTH_ALG_OPEN) + return; + auth += 2; + if (!sc->sc_mib_local.Network_Mode) { + if (sc->sc_status != AWI_ST_RUNNING) + return; + if (LE_READ_2(auth) == 1) + awi_send_auth(sc, 2); + return; + } + if (sc->sc_status != AWI_ST_AUTH) + return; + /* sequence number */ + if (LE_READ_2(auth) != 2) + return; + auth += 2; + /* status */ + status = LE_READ_2(auth); + if (status != 0) { + printf("%s: authentication failed (reason %d)\n", + sc->sc_dev.dv_xname, status); + for (bp = TAILQ_FIRST(&sc->sc_scan); bp != NULL; + bp = TAILQ_NEXT(bp, list)) { + if (memcmp(bp->esrc, sc->sc_bss.esrc, ETHER_ADDR_LEN) + == 0) { + bp->fails++; + break; + } + } + return; } - sc->sc_scan_timer = 2; sc->sc_mgt_timer = 0; - awi_set_timer(sc); - - sc->sc_nbindings = 0; - sc->sc_state = AWI_ST_SCAN; - awi_drvstate (sc, AWI_DRV_INFSC); - awi_cmd_scan (sc); + awi_drvstate(sc, AWI_DRV_INFAUTH); + awi_send_asreq(sc, 0); } -void -awi_cmd_scan (sc) +static void +awi_send_asreq(sc, reassoc) struct awi_softc *sc; + int reassoc; { - - awi_write_2 (sc, AWI_CMD_PARAMS+AWI_CA_SCAN_DURATION, - sc->sc_scan_duration); - awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SET, - sc->sc_scan_chanset); - awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SCAN_PATTERN, - sc->sc_scan_pattern); - awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SCAN_IDX, 1); - awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SUSP, 0); - - sc->sc_completion = awi_cmd_scan_done; - awi_cmd (sc, AWI_CMD_SCAN); + struct ifnet *ifp = sc->sc_ifp; + struct mbuf *m; + struct ieee80211_frame *wh; + u_int16_t lintval; + u_int8_t *asreq; + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) + return; + sc->sc_status = AWI_ST_ASSOC; + if (ifp->if_flags & IFF_DEBUG) + printf("%s: sending %sassoc req to %s\n", sc->sc_dev.dv_xname, + reassoc ? "re" : "", + ether_sprintf(sc->sc_bss.bssid)); + + wh = mtod(m, struct ieee80211_frame *); + wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT; + if (reassoc) + wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_REASSOC_REQ; + else + wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_ASSOC_REQ; + wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; + LE_WRITE_2(wh->i_dur, 0); + LE_WRITE_2(wh->i_seq, 0); + memcpy(wh->i_addr1, sc->sc_bss.esrc, ETHER_ADDR_LEN); + memcpy(wh->i_addr2, sc->sc_mib_addr.aMAC_Address, ETHER_ADDR_LEN); + memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN); + + asreq = (u_int8_t *)&wh[1]; + + /* capability info */ + if (sc->sc_wep_algo == NULL) + LE_WRITE_2(asreq, IEEE80211_CAPINFO_CF_POLLABLE); + else + LE_WRITE_2(asreq, + IEEE80211_CAPINFO_CF_POLLABLE | IEEE80211_CAPINFO_PRIVACY); + asreq += 2; + /* listen interval */ + lintval = LE_READ_2(&sc->sc_mib_mgt.aListen_Interval); + LE_WRITE_2(asreq, lintval); + asreq += 2; + if (reassoc) { + /* current AP address */ + memcpy(asreq, sc->sc_bss.bssid, ETHER_ADDR_LEN); + asreq += ETHER_ADDR_LEN; + } + /* ssid */ + memcpy(asreq, sc->sc_bss.essid, 2 + sc->sc_bss.essid[1]); + asreq += 2 + asreq[1]; + /* supported rates */ + memcpy(asreq, &sc->sc_mib_phy.aSuprt_Data_Rates, 4); + asreq += 2 + asreq[1]; + + m->m_pkthdr.len = m->m_len = asreq - mtod(m, u_int8_t *); + IF_ENQUEUE(&sc->sc_mgtq, m); + awi_start(ifp); + + sc->sc_mgt_timer = AWI_TRANS_TIMEOUT / 1000; + ifp->if_timer = 1; } -void -awi_cmd_scan_done (sc, status) +static void +awi_recv_asresp(sc, m0) struct awi_softc *sc; - u_int8_t status; + struct mbuf *m0; { -#if 0 - int erroffset; -#endif - if (status == AWI_STAT_OK) { - if (sc->sc_scan_chanset > awi_max_chan) - awi_max_chan = sc->sc_scan_chanset; - if (sc->sc_scan_chanset < awi_min_chan) - awi_min_chan = sc->sc_scan_chanset; - if (sc->sc_scan_pattern > awi_max_pattern) - awi_max_pattern = sc->sc_scan_pattern; - if (sc->sc_scan_pattern < awi_min_pattern) - awi_min_pattern = sc->sc_scan_pattern; - + struct ieee80211_frame *wh; + u_int8_t *asresp, *eframe; + u_int16_t status; + u_int8_t rate, *phy_rates; + struct awi_bss *bp; + int i, j; + + wh = mtod(m0, struct ieee80211_frame *); + asresp = (u_int8_t *)&wh[1]; + eframe = mtod(m0, u_int8_t *) + m0->m_len; + if (sc->sc_ifp->if_flags & IFF_DEBUG) + printf("%s: receive assoc resp from %s\n", sc->sc_dev.dv_xname, + ether_sprintf(wh->i_addr2)); + + if (!sc->sc_mib_local.Network_Mode) + return; + + if (sc->sc_status != AWI_ST_ASSOC) + return; + /* capability info */ + asresp += 2; + /* status */ + status = LE_READ_2(asresp); + if (status != 0) { + printf("%s: association failed (reason %d)\n", + sc->sc_dev.dv_xname, status); + for (bp = TAILQ_FIRST(&sc->sc_scan); bp != NULL; + bp = TAILQ_NEXT(bp, list)) { + if (memcmp(bp->esrc, sc->sc_bss.esrc, ETHER_ADDR_LEN) + == 0) { + bp->fails++; + break; + } + } return; } -#if 0 - erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); - printf("%s: scan failed; erroffset %d\n", sc->sc_dev.dv_xname, - erroffset); -#endif - /* wait for response or scan timeout.. */ + asresp += 2; + /* association id */ + asresp += 2; + /* supported rates */ + rate = AWI_RATE_1MBIT; + for (i = 0; i < asresp[1]; i++) { + if (AWI_80211_RATE(asresp[2 + i]) <= rate) + continue; + phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates; + for (j = 0; j < phy_rates[1]; j++) { + if (AWI_80211_RATE(asresp[2 + i]) == + AWI_80211_RATE(phy_rates[2 + j])) + rate = AWI_80211_RATE(asresp[2 + i]); + } + } + if (sc->sc_ifp->if_flags & IFF_DEBUG) { + printf("%s: associated with %s ssid ", + sc->sc_dev.dv_xname, ether_sprintf(sc->sc_bss.bssid)); + awi_print_essid(sc->sc_bss.essid); + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) + printf(" chanset %d pattern %d\n", + sc->sc_bss.chanset, sc->sc_bss.pattern); + else + printf(" channel %d\n", sc->sc_bss.chanset); + } + sc->sc_tx_rate = rate; + sc->sc_mgt_timer = 0; + sc->sc_rx_timer = 10; + sc->sc_ifp->if_timer = 1; + sc->sc_status = AWI_ST_RUNNING; + sc->sc_ifp->if_flags |= IFF_RUNNING; + awi_drvstate(sc, AWI_DRV_INFASSOC); + awi_start(sc->sc_ifp); } -void -awi_scan_next (sc) +static int +awi_mib(sc, cmd, mib) struct awi_softc *sc; + u_int8_t cmd; + u_int8_t mib; { - sc->sc_scan_pattern++; - if (sc->sc_scan_pattern > IEEEWL_FH_PATTERN_MAX) { - sc->sc_scan_pattern = IEEEWL_FH_PATTERN_MIN; + int error; + u_int8_t size, *ptr; - sc->sc_scan_chanset++; - if (sc->sc_scan_chanset > IEEEWL_FH_CHANSET_MAX) - sc->sc_scan_chanset = IEEEWL_FH_CHANSET_MIN; + switch (mib) { + case AWI_MIB_LOCAL: + ptr = (u_int8_t *)&sc->sc_mib_local; + size = sizeof(sc->sc_mib_local); + break; + case AWI_MIB_ADDR: + ptr = (u_int8_t *)&sc->sc_mib_addr; + size = sizeof(sc->sc_mib_addr); + break; + case AWI_MIB_MAC: + ptr = (u_int8_t *)&sc->sc_mib_mac; + size = sizeof(sc->sc_mib_mac); + break; + case AWI_MIB_STAT: + ptr = (u_int8_t *)&sc->sc_mib_stat; + size = sizeof(sc->sc_mib_stat); + break; + case AWI_MIB_MGT: + ptr = (u_int8_t *)&sc->sc_mib_mgt; + size = sizeof(sc->sc_mib_mgt); + break; + case AWI_MIB_PHY: + ptr = (u_int8_t *)&sc->sc_mib_phy; + size = sizeof(sc->sc_mib_phy); + break; + default: + return EINVAL; } -#if 0 - printf("scan: pattern %x chanset %x\n", sc->sc_scan_pattern, - sc->sc_scan_chanset); + if (sc->sc_cmd_inprog) { + error = awi_cmd_wait(sc); + if (error) { + if (error == EWOULDBLOCK) + printf("awi_mib: cmd %d inprog", + sc->sc_cmd_inprog); + return error; + } + } + sc->sc_cmd_inprog = cmd; + if (cmd == AWI_CMD_SET_MIB) + awi_write_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, ptr, size); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, mib); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, size); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, 0); + error = awi_cmd(sc, cmd); + if (error) + return error; + if (cmd == AWI_CMD_GET_MIB) { + awi_read_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, ptr, size); +#ifdef AWI_DEBUG + if (awi_verbose) { + int i; + + printf("awi_mib: #%d:", mib); + for (i = 0; i < size; i++) + printf(" %02x", ptr[i]); + printf("\n"); + } #endif - - awi_cmd_scan(sc); + } + return 0; } -void -awi_try_sync (sc) +static int +awi_cmd_scan(sc) struct awi_softc *sc; { - int max_rssi = 0, best = 0; - int i; - struct awi_bss_binding *bp = NULL; - - awi_flush(sc); + int error; + u_int8_t scan_mode; - if (sc->sc_ifp->if_flags & IFF_DEBUG) { - printf("%s: looking for best of %d\n", - sc->sc_dev.dv_xname, sc->sc_nbindings); + if (sc->sc_active_scan) + scan_mode = AWI_SCAN_ACTIVE; + else + scan_mode = AWI_SCAN_PASSIVE; + if (sc->sc_mib_mgt.aScan_Mode != scan_mode) { + sc->sc_mib_mgt.aScan_Mode = scan_mode; + error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT); + return error; } - /* pick one with best rssi */ - for (i=0; i<sc->sc_nbindings; i++) { - bp = &sc->sc_bindings[i]; - if (bp->rssi > max_rssi) { - max_rssi = bp->rssi; - best = i; - } + if (sc->sc_cmd_inprog) { + error = awi_cmd_wait(sc); + if (error) + return error; } - - if (bp == NULL) { - printf("%s: no beacons seen\n", sc->sc_dev.dv_xname); - awi_scan_next(sc); - return; + sc->sc_cmd_inprog = AWI_CMD_SCAN; + awi_write_2(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_DURATION, + sc->sc_active_scan ? AWI_ASCAN_DURATION : AWI_PSCAN_DURATION); + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SET, + sc->sc_scan_set); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_PATTERN, + sc->sc_scan_cur); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_IDX, 1); + } else { + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SET, + sc->sc_scan_cur); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_PATTERN, 0); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_IDX, 0); } + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SUSP, 0); + return awi_cmd(sc, AWI_CMD_SCAN); +} - if (sc->sc_ifp->if_flags & IFF_DEBUG) { - printf("%s: best %d\n", sc->sc_dev.dv_xname, best); - } - sc->sc_scan_timer = awi_scan_keepalive; - - bp = &sc->sc_bindings[best]; - bcopy(bp, &sc->sc_active_bss, sizeof(*bp)); - sc->sc_new_bss = 1; - - awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_SET, bp->chanset); - awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_PATTERN, bp->pattern); - awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_IDX, bp->index); - awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_STARTBSS, 0); - - awi_write_2 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_DWELL, bp->dwell_time); - awi_write_2 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_MBZ, 0); - - awi_write_bytes (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_TIMESTAMP, - bp->bss_timestamp, 8); - awi_write_4 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_REFTIME, bp->rxtime); - - sc->sc_completion = awi_cmd_sync_done; - - awi_cmd (sc, AWI_CMD_SYNC); +static int +awi_cmd(sc, cmd) + struct awi_softc *sc; + u_int8_t cmd; +{ + u_int8_t status; + int error = 0; + sc->sc_cmd_inprog = cmd; + awi_write_1(sc, AWI_CMD_STATUS, AWI_STAT_IDLE); + awi_write_1(sc, AWI_CMD, cmd); + if (sc->sc_status != AWI_ST_INIT) + return 0; + error = awi_cmd_wait(sc); + if (error) + return error; + status = awi_read_1(sc, AWI_CMD_STATUS); + awi_write_1(sc, AWI_CMD, 0); + switch (status) { + case AWI_STAT_OK: + break; + case AWI_STAT_BADPARM: + return EINVAL; + default: + printf("%s: command %d failed %x\n", + sc->sc_dev.dv_xname, cmd, status); + return ENXIO; + } + return 0; } -void -awi_cmd_sync_done (sc, status) +static void +awi_cmd_done(sc) struct awi_softc *sc; - u_int8_t status; { + u_int8_t cmd, status; + + status = awi_read_1(sc, AWI_CMD_STATUS); + if (status == AWI_STAT_IDLE) + return; /* stray interrupt */ + + cmd = sc->sc_cmd_inprog; + sc->sc_cmd_inprog = 0; + if (sc->sc_status == AWI_ST_INIT) { + wakeup(sc); + return; + } + awi_write_1(sc, AWI_CMD, 0); + if (status != AWI_STAT_OK) { - int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); - printf("%s: sync_done failed (card unhappy?); erroffset %d\n", - sc->sc_dev.dv_xname, - erroffset); - awi_reset(sc); + printf("%s: command %d failed %x\n", + sc->sc_dev.dv_xname, cmd, status); return; } + switch (sc->sc_status) { + case AWI_ST_SCAN: + if (cmd == AWI_CMD_SET_MIB) + awi_cmd_scan(sc); /* retry */ + break; + case AWI_ST_SETSS: + awi_try_sync(sc); + break; + case AWI_ST_SYNC: + awi_sync_done(sc); + break; + default: + break; + } +} +static int +awi_next_txd(sc, len, framep, ntxdp) + struct awi_softc *sc; + int len; + u_int32_t *framep, *ntxdp; +{ + u_int32_t txd, ntxd, frame; + + txd = sc->sc_txnext; + frame = txd + AWI_TXD_SIZE; + if (frame + len > sc->sc_txend) + frame = sc->sc_txbase; + ntxd = frame + len; + if (ntxd + AWI_TXD_SIZE > sc->sc_txend) + ntxd = sc->sc_txbase; + *framep = frame; + *ntxdp = ntxd; /* - * at this point, the card should be synchronized with the AP - * we heard from. tell the card what BSS and ESS it's running in.. + * Determine if there are any room in ring buffer. + * --- send wait, === new data, +++ conflict (ENOBUFS) + * base........................end + * done----txd=====ntxd OK + * --txd=====done++++ntxd-- full + * --txd=====ntxd done-- OK + * ==ntxd done----txd=== OK + * ==done++++ntxd----txd=== full + * ++ntxd txd=====done++ full */ - - awi_drvstate (sc, AWI_DRV_INFSY); - if (sc->sc_ifp->if_flags & IFF_DEBUG) { - printf("%s: sync done, setting bss/iss parameters\n", - sc->sc_dev.dv_xname); - awi_hexdump ("bss", sc->sc_active_bss.bss_id, ETHER_ADDR_LEN); - printf("ssid: %s\n", sc->sc_active_bss.ssid); + if (txd < ntxd) { + if (txd < sc->sc_txdone && ntxd + AWI_TXD_SIZE > sc->sc_txdone) + return ENOBUFS; + } else { + if (txd < sc->sc_txdone || ntxd + AWI_TXD_SIZE > sc->sc_txdone) + return ENOBUFS; } - - awi_cmd_set_ss (sc); + return 0; } +static int +awi_lock(sc) + struct awi_softc *sc; +{ + int error = 0; + + if (curproc == NULL) { + /* + * XXX + * Though driver ioctl should be called with context, + * KAME ipv6 stack calls ioctl in interrupt for now. + * We simply abort the request if there are other + * ioctl requests in progress. + */ + if (sc->sc_busy) { + return EWOULDBLOCK; + if (sc->sc_invalid) + return ENXIO; + } + sc->sc_busy = 1; + sc->sc_cansleep = 0; + return 0; + } + while (sc->sc_busy) { + if (sc->sc_invalid) + return ENXIO; + sc->sc_sleep_cnt++; + error = tsleep(sc, PWAIT | PCATCH, "awilck", 0); + sc->sc_sleep_cnt--; + if (error) + return error; + } + sc->sc_busy = 1; + sc->sc_cansleep = 1; + return 0; +} -void awi_cmd_set_ss (sc) +static void +awi_unlock(sc) struct awi_softc *sc; { - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, AWI_MIB_MAC_MGT); - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, - ETHER_ADDR_LEN + AWI_MIB_MGT_ESS_SIZE); - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, - AWI_MIB_MGT_BSS_ID); - - awi_write_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, - sc->sc_active_bss.bss_id, ETHER_ADDR_LEN); - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA+ETHER_ADDR_LEN, - 0); /* XXX */ - awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA+ETHER_ADDR_LEN+1, - sc->sc_active_bss.sslen); - awi_write_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA+8, - sc->sc_active_bss.ssid, AWI_MIB_MGT_ESS_SIZE-2); - - sc->sc_completion = awi_cmd_set_ss_done; - awi_cmd (sc, AWI_CMD_SET_MIB); + sc->sc_busy = 0; + sc->sc_cansleep = 0; + if (sc->sc_sleep_cnt) + wakeup(sc); } -void awi_cmd_set_ss_done (sc, status) +static int +awi_intr_lock(sc) struct awi_softc *sc; - u_int8_t status; { - if (status != AWI_STAT_OK) { - int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); - printf("%s: set_ss_done failed (card unhappy?); erroffset %d\n", - sc->sc_dev.dv_xname, - erroffset); - awi_reset(sc); - return; + u_int8_t status; + int i, retry; + + status = 1; + for (retry = 0; retry < 10; retry++) { + for (i = 0; i < AWI_LOCKOUT_TIMEOUT*1000/5; i++) { + status = awi_read_1(sc, AWI_LOCKOUT_HOST); + if (status == 0) + break; + DELAY(5); + } + if (status != 0) + break; + awi_write_1(sc, AWI_LOCKOUT_MAC, 1); + status = awi_read_1(sc, AWI_LOCKOUT_HOST); + if (status == 0) + break; + awi_write_1(sc, AWI_LOCKOUT_MAC, 0); } -#if 0 - printf("%s: set_ss done\n", sc->sc_dev.dv_xname); -#endif + if (status != 0) { + printf("%s: failed to lock interrupt\n", + sc->sc_dev.dv_xname); + return ENXIO; + } + return 0; +} - awi_running (sc); - - /* - * now, we *should* be getting broadcast frames.. - */ - sc->sc_state = AWI_ST_SYNCED; - awi_send_authreq (sc); - +static void +awi_intr_unlock(sc) + struct awi_softc *sc; +{ + + awi_write_1(sc, AWI_LOCKOUT_MAC, 0); } -void awi_running (sc) +static int +awi_cmd_wait(sc) struct awi_softc *sc; - { - struct ifnet *ifp = sc->sc_ifp; - - /* - * Who knows what it is to be running? - * Only he who is running knows.. - */ - ifp->if_flags |= IFF_RUNNING; - awi_start(ifp); + int i, error = 0; + + i = 0; + while (sc->sc_cmd_inprog) { + if (sc->sc_invalid) + return ENXIO; + if (awi_read_1(sc, AWI_CMD) != sc->sc_cmd_inprog) { + printf("%s: failed to access hardware\n", + sc->sc_dev.dv_xname); + sc->sc_invalid = 1; + return ENXIO; + } + if (sc->sc_cansleep) { + sc->sc_sleep_cnt++; + error = tsleep(sc, PWAIT, "awicmd", + AWI_CMD_TIMEOUT*hz/1000); + sc->sc_sleep_cnt--; + } else { + if (awi_read_1(sc, AWI_CMD_STATUS) != AWI_STAT_IDLE) { + awi_cmd_done(sc); + break; + } + if (i++ >= AWI_CMD_TIMEOUT*1000/10) + error = EWOULDBLOCK; + else + DELAY(10); + } + if (error) + break; + } + return error; } +static void +awi_print_essid(essid) + u_int8_t *essid; +{ + int i, len; + u_int8_t *p; -void awi_reset (sc) + len = essid[1]; + if (len > IEEE80211_NWID_LEN) + len = IEEE80211_NWID_LEN; /*XXX*/ + /* determine printable or not */ + for (i = 0, p = essid + 2; i < len; i++, p++) { + if (*p < ' ' || *p > 0x7e) + break; + } + if (i == len) { + printf("\""); + for (i = 0, p = essid + 2; i < len; i++, p++) + printf("%c", *p); + printf("\""); + } else { + printf("0x"); + for (i = 0, p = essid + 2; i < len; i++, p++) + printf("%02x", *p); + } +} + +#ifdef AWI_DEBUG +static void +awi_dump_pkt(sc, m, rssi) struct awi_softc *sc; + struct mbuf *m; + int rssi; { - printf("%s: reset\n", sc->sc_dev.dv_xname); + struct ieee80211_frame *wh; + int i, l; + + wh = mtod(m, struct ieee80211_frame *); + + if (awi_dump_mask != 0 && + ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK)==IEEE80211_FC1_DIR_NODS) && + ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)==IEEE80211_FC0_TYPE_MGT)) { + if ((AWI_DUMP_MASK(wh->i_fc[0]) & awi_dump_mask) != 0) + return; + } + if (awi_dump_mask < 0 && + (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)==IEEE80211_FC0_TYPE_DATA) + return; + if (rssi < 0) + printf("tx: "); + else + printf("rx: "); + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + printf("NODS %s", ether_sprintf(wh->i_addr2)); + printf("->%s", ether_sprintf(wh->i_addr1)); + printf("(%s)", ether_sprintf(wh->i_addr3)); + break; + case IEEE80211_FC1_DIR_TODS: + printf("TODS %s", ether_sprintf(wh->i_addr2)); + printf("->%s", ether_sprintf(wh->i_addr3)); + printf("(%s)", ether_sprintf(wh->i_addr1)); + break; + case IEEE80211_FC1_DIR_FROMDS: + printf("FRDS %s", ether_sprintf(wh->i_addr3)); + printf("->%s", ether_sprintf(wh->i_addr1)); + printf("(%s)", ether_sprintf(wh->i_addr2)); + break; + case IEEE80211_FC1_DIR_DSTODS: + printf("DSDS %s", ether_sprintf((u_int8_t *)&wh[1])); + printf("->%s", ether_sprintf(wh->i_addr3)); + printf("(%s", ether_sprintf(wh->i_addr2)); + printf("->%s)", ether_sprintf(wh->i_addr1)); + break; + } + switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { + case IEEE80211_FC0_TYPE_DATA: + printf(" data"); + break; + case IEEE80211_FC0_TYPE_MGT: + switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { + case IEEE80211_FC0_SUBTYPE_PROBE_REQ: + printf(" probe_req"); + break; + case IEEE80211_FC0_SUBTYPE_PROBE_RESP: + printf(" probe_resp"); + break; + case IEEE80211_FC0_SUBTYPE_BEACON: + printf(" beacon"); + break; + case IEEE80211_FC0_SUBTYPE_AUTH: + printf(" auth"); + break; + case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: + printf(" assoc_req"); + break; + case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: + printf(" assoc_resp"); + break; + case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: + printf(" reassoc_req"); + break; + case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: + printf(" reassoc_resp"); + break; + case IEEE80211_FC0_SUBTYPE_DEAUTH: + printf(" deauth"); + break; + case IEEE80211_FC0_SUBTYPE_DISASSOC: + printf(" disassoc"); + break; + default: + printf(" mgt#%d", + wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); + break; + } + break; + default: + printf(" type#%d", + wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); + break; + } + if (wh->i_fc[1] & IEEE80211_FC1_WEP) + printf(" WEP"); + if (rssi >= 0) + printf(" +%d", rssi); + printf("\n"); + if (awi_dump_len > 0) { + l = m->m_len; + if (l > awi_dump_len + sizeof(*wh)) + l = awi_dump_len + sizeof(*wh); + i = sizeof(*wh); + if (awi_dump_hdr) + i = 0; + for (; i < l; i++) { + if ((i & 1) == 0) + printf(" "); + printf("%02x", mtod(m, u_int8_t *)[i]); + } + printf("\n"); + } } +#endif diff --git a/sys/dev/ic/awi_wep.c b/sys/dev/ic/awi_wep.c new file mode 100644 index 00000000000..87f968130f2 --- /dev/null +++ b/sys/dev/ic/awi_wep.c @@ -0,0 +1,535 @@ +/* $NetBSD: awi_wep.c,v 1.2 2000/07/04 14:47:58 onoe Exp $ */ + +/* + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Atsushi Onoe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * WEP support framework for the awi driver. + * + * No actual encryption capability is provided here, but any can be added + * to awi_wep_algo table below. + * + * Note that IEEE802.11 specification states WEP uses RC4 with 40bit key, + * which is a proprietary encryption algorithm available under license + * from RSA Data Security Inc. Using another algorithm, includes null + * encryption provided here, the awi driver cannot be able to communicate + * with other stations. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/sockio.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 4 +#include <sys/bus.h> +#else +#include <sys/device.h> +#endif + +#include <net/if.h> +#include <net/if_dl.h> +#ifdef __FreeBSD__ +#include <net/ethernet.h> +#include <net/if_arp.h> +#elif defined(__OpenBSD__) +#include <netinet/in.h> +#include <netinet/if_ether.h> +#else +#include <net/if_ether.h> +#endif +#include <net/if_media.h> +#include <net/if_ieee80211.h> + +#include <machine/cpu.h> +#include <machine/bus.h> +#ifdef __FreeBSD__ +#include <machine/clock.h> +#endif + +#if defined(__NetBSD__) || defined(__OpenBSD__) +#include <dev/ic/am79c930reg.h> +#include <dev/ic/am79c930var.h> +#include <dev/ic/awireg.h> +#include <dev/ic/awivar.h> +#endif + +#ifdef __NetBSD__ +#include <crypto/arc4/arc4.h> +#endif + +#ifdef __FreeBSD__ +#include <dev/awi/am79c930reg.h> +#include <dev/awi/am79c930var.h> +#include <dev/awi/awireg.h> +#include <dev/awi/awivar.h> + +#include <crypto/rc4/rc4.h> +static __inline int +arc4_ctxlen(void) +{ + return sizeof(struct rc4_state); +} + +static __inline void +arc4_setkey(void *ctx, u_int8_t *key, int keylen) +{ + rc4_init(ctx, key, keylen); +} + +static __inline void +arc4_encrypt(void *ctx, u_int8_t *dst, u_int8_t *src, int len) +{ + rc4_crypt(ctx, dst, src, len); +} +#endif + +static void awi_crc_init __P((void)); +static u_int32_t awi_crc_update __P((u_int32_t crc, u_int8_t *buf, int len)); + +static int awi_null_ctxlen __P((void)); +static void awi_null_setkey __P((void *ctx, u_int8_t *key, int keylen)); +static void awi_null_copy __P((void *ctx, u_int8_t *dst, u_int8_t *src, int len)); + +/* XXX: the order should be known to wiconfig/user */ + +static struct awi_wep_algo awi_wep_algo[] = { +/* 0: no wep */ + { "no" }, /* dummy for no wep */ + +#if 0 +/* 1: normal wep (arc4) */ + { "arc4", arc4_ctxlen, arc4_setkey, + arc4_encrypt, arc4_encrypt }, +#endif +/* 2: debug wep (null) */ + { "null", awi_null_ctxlen, awi_null_setkey, + awi_null_copy, awi_null_copy }, + /* dummy for wep without encryption */ +}; + +int +awi_wep_setnwkey(sc, nwkey) + struct awi_softc *sc; + struct ieee80211_nwkey *nwkey; +{ + int i, len, error; + u_int8_t keybuf[AWI_MAX_KEYLEN]; + + if (nwkey->i_defkid <= 0 || + nwkey->i_defkid > IEEE80211_WEP_NKID) + return EINVAL; + error = 0; + for (i = 0; i < IEEE80211_WEP_NKID; i++) { + if (nwkey->i_key[i].i_keydat == NULL) + continue; + len = nwkey->i_key[i].i_keylen; + if (len > sizeof(keybuf)) { + error = EINVAL; + break; + } + error = copyin(nwkey->i_key[i].i_keydat, keybuf, len); + if (error) + break; + error = awi_wep_setkey(sc, i, keybuf, len); + if (error) + break; + } + if (error == 0) { + sc->sc_wep_defkid = nwkey->i_defkid - 1; + error = awi_wep_setalgo(sc, nwkey->i_wepon); + if (error == 0 && sc->sc_enabled) { + awi_stop(sc); + error = awi_init(sc); + } + } + return error; +} + +int +awi_wep_getnwkey(sc, nwkey) + struct awi_softc *sc; + struct ieee80211_nwkey *nwkey; +{ + int i, len, error, suerr; + u_int8_t keybuf[AWI_MAX_KEYLEN]; + + nwkey->i_wepon = awi_wep_getalgo(sc); + nwkey->i_defkid = sc->sc_wep_defkid + 1; + /* do not show any keys to non-root user */ +#ifdef __FreeBSD__ + suerr = suser(curproc); +#else + suerr = suser(curproc->p_ucred, &curproc->p_acflag); +#endif + error = 0; + for (i = 0; i < IEEE80211_WEP_NKID; i++) { + if (nwkey->i_key[i].i_keydat == NULL) + continue; + if (suerr) { + error = suerr; + break; + } + len = sizeof(keybuf); + error = awi_wep_getkey(sc, i, keybuf, &len); + if (error) + break; + if (nwkey->i_key[i].i_keylen < len) { + error = ENOSPC; + break; + } + nwkey->i_key[i].i_keylen = len; + error = copyout(keybuf, nwkey->i_key[i].i_keydat, len); + if (error) + break; + } + return error; +} + +int +awi_wep_getalgo(sc) + struct awi_softc *sc; +{ + + if (sc->sc_wep_algo == NULL) + return 0; + return sc->sc_wep_algo - awi_wep_algo; +} + +int +awi_wep_setalgo(sc, algo) + struct awi_softc *sc; + int algo; +{ + struct awi_wep_algo *awa; + int ctxlen; + + awi_crc_init(); /* XXX: not belongs here */ + if (algo < 0 || algo > sizeof(awi_wep_algo)/sizeof(awi_wep_algo[0])) + return EINVAL; + awa = &awi_wep_algo[algo]; + if (awa->awa_name == NULL) + return EINVAL; + if (awa->awa_ctxlen == NULL) { + awa = NULL; + ctxlen = 0; + } else + ctxlen = awa->awa_ctxlen(); + if (sc->sc_wep_ctx != NULL) { + free(sc->sc_wep_ctx, M_DEVBUF); + sc->sc_wep_ctx = NULL; + } + if (ctxlen) { + sc->sc_wep_ctx = malloc(ctxlen, M_DEVBUF, M_NOWAIT); + if (sc->sc_wep_ctx == NULL) + return ENOMEM; + } + sc->sc_wep_algo = awa; + return 0; +} + +int +awi_wep_setkey(sc, kid, key, keylen) + struct awi_softc *sc; + int kid; + unsigned char *key; + int keylen; +{ + + if (kid < 0 || kid >= IEEE80211_WEP_NKID) + return EINVAL; + if (keylen < 0 || keylen + IEEE80211_WEP_IVLEN > AWI_MAX_KEYLEN) + return EINVAL; + sc->sc_wep_keylen[kid] = keylen; + if (keylen > 0) + memcpy(sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, key, keylen); + return 0; +} + +int +awi_wep_getkey(sc, kid, key, keylen) + struct awi_softc *sc; + int kid; + unsigned char *key; + int *keylen; +{ + + if (kid < 0 || kid >= IEEE80211_WEP_NKID) + return EINVAL; + if (*keylen < sc->sc_wep_keylen[kid]) + return ENOSPC; + *keylen = sc->sc_wep_keylen[kid]; + if (*keylen > 0) + memcpy(key, sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, *keylen); + return 0; +} + +struct mbuf * +awi_wep_encrypt(sc, m0, txflag) + struct awi_softc *sc; + struct mbuf *m0; + int txflag; +{ + struct mbuf *m, *n, *n0; + struct ieee80211_frame *wh; + struct awi_wep_algo *awa; + int left, len, moff, noff, keylen, kid; + u_int32_t iv, crc; + u_int8_t *key, *ivp; + void *ctx; + u_int8_t crcbuf[IEEE80211_WEP_CRCLEN]; + + n0 = NULL; + awa = sc->sc_wep_algo; + if (awa == NULL) + goto fail; + ctx = sc->sc_wep_ctx; + m = m0; + left = m->m_pkthdr.len; + MGET(n, M_DONTWAIT, m->m_type); + n0 = n; + if (n == NULL) + goto fail; + M_COPY_PKTHDR(n, m); + len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; + if (txflag) { + n->m_pkthdr.len += len; + } else { + wh = mtod(n, struct ieee80211_frame *); + n->m_pkthdr.len -= len; + left -= len; + } + n->m_len = MHLEN; + if (n->m_pkthdr.len >= MINCLSIZE) { + MCLGET(n, M_DONTWAIT); + if (n->m_flags & M_EXT) + n->m_len = n->m_ext.ext_size; + } + len = sizeof(struct ieee80211_frame); + memcpy(mtod(n, caddr_t), mtod(m, caddr_t), len); + left -= len; + moff = len; + noff = len; + if (txflag) { + kid = sc->sc_wep_defkid; + wh = mtod(n, struct ieee80211_frame *); + wh->i_fc[1] |= IEEE80211_FC1_WEP; + iv = random(); + /* + * store IV, byte order is not the matter since it's random. + * assuming IEEE80211_WEP_IVLEN is 3 + */ + ivp = mtod(n, u_int8_t *) + noff; + ivp[0] = (iv >> 16) & 0xff; + ivp[1] = (iv >> 8) & 0xff; + ivp[2] = iv & 0xff; + ivp[3] = kid & 0x03; /* clear pad and keyid */ + noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; + } else { + ivp = mtod(m, u_int8_t *) + moff; + moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; + kid = ivp[IEEE80211_WEP_IVLEN] & 0x03; + } + key = sc->sc_wep_key[kid]; + keylen = sc->sc_wep_keylen[kid]; + /* assuming IEEE80211_WEP_IVLEN is 3 */ + key[0] = ivp[0]; + key[1] = ivp[1]; + key[2] = ivp[2]; + awa->awa_setkey(ctx, key, IEEE80211_WEP_IVLEN + keylen); + + /* encrypt with calculating CRC */ + crc = ~0; + while (left > 0) { + len = m->m_len - moff; + if (len == 0) { + m = m->m_next; + moff = 0; + continue; + } + if (len > n->m_len - noff) { + len = n->m_len - noff; + if (len == 0) { + MGET(n->m_next, M_DONTWAIT, n->m_type); + if (n->m_next == NULL) + goto fail; + n = n->m_next; + n->m_len = MLEN; + if (left >= MINCLSIZE) { + MCLGET(n, M_DONTWAIT); + if (n->m_flags & M_EXT) + n->m_len = n->m_ext.ext_size; + } + noff = 0; + continue; + } + } + if (len > left) + len = left; + if (txflag) { + awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff, + mtod(m, caddr_t) + moff, len); + crc = awi_crc_update(crc, mtod(m, caddr_t) + moff, len); + } else { + awa->awa_decrypt(ctx, mtod(n, caddr_t) + noff, + mtod(m, caddr_t) + moff, len); + crc = awi_crc_update(crc, mtod(n, caddr_t) + noff, len); + } + left -= len; + moff += len; + noff += len; + } + crc = ~crc; + if (txflag) { + LE_WRITE_4(crcbuf, crc); + if (n->m_len >= noff + sizeof(crcbuf)) + n->m_len = noff + sizeof(crcbuf); + else { + n->m_len = noff; + MGET(n->m_next, M_DONTWAIT, n->m_type); + if (n->m_next == NULL) + goto fail; + n = n->m_next; + n->m_len = sizeof(crcbuf); + noff = 0; + } + awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff, crcbuf, + sizeof(crcbuf)); + } else { + n->m_len = noff; + noff = 0; + for (; noff < sizeof(crcbuf); noff += len, m = m->m_next) { + if (m->m_len < moff + len) + len = m->m_len - moff; + if (len == 0) + continue; + awa->awa_decrypt(ctx, crcbuf + noff, + mtod(m, caddr_t) + moff, len); + } + if (crc != LE_READ_4(crcbuf)) + goto fail; + } + m_freem(m0); + return n0; + + fail: + m_freem(m0); + m_freem(n0); + return NULL; +} + +/* + * CRC 32 -- routine from RFC 2083 + */ + +/* Table of CRCs of all 8-bit messages */ +static u_int32_t awi_crc_table[256]; +static int awi_crc_table_computed = 0; + +/* Make the table for a fast CRC. */ +static void +awi_crc_init() +{ + u_int32_t c; + int n, k; + + if (awi_crc_table_computed) + return; + for (n = 0; n < 256; n++) { + c = (u_int32_t)n; + for (k = 0; k < 8; k++) { + if (c & 1) + c = 0xedb88320UL ^ (c >> 1); + else + c = c >> 1; + } + awi_crc_table[n] = c; + } + awi_crc_table_computed = 1; +} + +/* + * Update a running CRC with the bytes buf[0..len-1]--the CRC + * should be initialized to all 1's, and the transmitted value + * is the 1's complement of the final running CRC + */ + +static u_int32_t +awi_crc_update(crc, buf, len) + u_int32_t crc; + u_int8_t *buf; + int len; +{ + u_int8_t *endbuf; + + for (endbuf = buf + len; buf < endbuf; buf++) + crc = awi_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + return crc; +} + +/* + * Null -- do nothing but copy. + */ + +static int +awi_null_ctxlen() +{ + + return 0; +} + +static void +awi_null_setkey(ctx, key, keylen) + void *ctx; + u_char *key; + int keylen; +{ +} + +static void +awi_null_copy(ctx, dst, src, len) + void *ctx; + u_char *dst; + u_char *src; + int len; +{ + + memcpy(dst, src, len); +} diff --git a/sys/dev/ic/awireg.h b/sys/dev/ic/awireg.h index 76c97ee5309..9866c561e3c 100644 --- a/sys/dev/ic/awireg.h +++ b/sys/dev/ic/awireg.h @@ -1,5 +1,4 @@ -/* $NetBSD: awireg.h,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */ -/* $OpenBSD: awireg.h,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */ +/* $NetBSD: awireg.h,v 1.3 2000/03/22 11:22:22 onoe Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -58,11 +57,11 @@ */ #define AWI_LAST_TXD 0x3ec /* last completed Tx Descr */ -#define AWI_LAST_BCAST_TXD AWI_LAST_TXD+0 -#define AWI_LAST_MGT_TXD AWI_LAST_TXD+4 -#define AWI_LAST_DATA_TXD AWI_LAST_TXD+8 -#define AWI_LAST_PS_POLL_TXD AWI_LAST_TXD+12 -#define AWI_LAST_CF_POLL_TXD AWI_LAST_TXD+16 +#define AWI_LAST_BCAST_TXD AWI_LAST_TXD+0 +#define AWI_LAST_MGT_TXD AWI_LAST_TXD+4 +#define AWI_LAST_DATA_TXD AWI_LAST_TXD+8 +#define AWI_LAST_PS_POLL_TXD AWI_LAST_TXD+12 +#define AWI_LAST_CF_POLL_TXD AWI_LAST_TXD+16 /* * Banner block; null-terminated string. @@ -72,7 +71,7 @@ */ #define AWI_BANNER 0x480 /* Version string */ -#define AWI_BANNER_LEN 0x20 +#define AWI_BANNER_LEN 0x20 /* * Command block protocol: @@ -85,96 +84,94 @@ * write command status to a zero value. */ -#define AWI_CMD 0x4a0 /* Command opcode byte */ +#define AWI_CMD 0x4a0 /* Command opcode byte */ -#define AWI_CMD_IDLE 0x0 -#define AWI_CMD_NOP 0x1 +#define AWI_CMD_IDLE 0x0 +#define AWI_CMD_NOP 0x1 -#define AWI_CMD_SET_MIB 0x2 -#define AWI_CMD_GET_MIB 0x9 +#define AWI_CMD_SET_MIB 0x2 +#define AWI_CMD_GET_MIB 0x9 -#define AWI_CA_MIB_TYPE 0x0 -#define AWI_CA_MIB_SIZE 0x1 +#define AWI_CA_MIB_TYPE 0x0 +#define AWI_CA_MIB_SIZE 0x1 #define AWI_CA_MIB_INDEX 0x2 -#define AWI_CA_MIB_DATA 0x4 +#define AWI_CA_MIB_DATA 0x4 -#define AWI_MIB_LOCAL 0x0 -#define AWI_MIB_MAC_ADDR 0x2 -#define AWI_MIB_MAC 0x3 -#define AWI_MIB_MAC_STAT 0x4 -#define AWI_MIB_MAC_MGT 0x5 -#define AWI_MIB_DRVR_MAC 0x6 -#define AWI_MIB_PHY 0x7 +#define AWI_MIB_LOCAL 0x0 +#define AWI_MIB_ADDR 0x2 +#define AWI_MIB_MAC 0x3 +#define AWI_MIB_STAT 0x4 +#define AWI_MIB_MGT 0x5 +#define AWI_MIB_DRVR 0x6 +#define AWI_MIB_PHY 0x7 -#define AWI_MIB_LAST AWI_MIB_PHY - -#define AWI_CMD_INIT_TX 0x3 +#define AWI_CMD_INIT_TX 0x3 #define AWI_CA_TX_LEN 0x14 #define AWI_CA_TX_DATA 0x0 #define AWI_CA_TX_MGT 0x4 -#define AWI_CA_TX_BCAST 0x8 +#define AWI_CA_TX_BCAST 0x8 #define AWI_CA_TX_PS 0xc #define AWI_CA_TX_CF 0x10 -#define AWI_CMD_FLUSH_TX 0x4 +#define AWI_CMD_FLUSH_TX 0x4 #define AWI_CA_FTX_LEN 0x5 -#define AWI_CA_FTX_DATA 0x0 +#define AWI_CA_FTX_DATA 0x0 #define AWI_CA_FTX_MGT 0x1 #define AWI_CA_FTX_BCAST 0x2 #define AWI_CA_FTX_PS 0x3 #define AWI_CA_FTX_CF 0x4 -#define AWI_CMD_INIT_RX 0x5 +#define AWI_CMD_INIT_RX 0x5 #define AWI_CA_IRX_LEN 0x8 #define AWI_CA_IRX_DATA_DESC 0x0 /* return */ #define AWI_CA_IRX_PS_DESC 0x4 /* return */ -#define AWI_CMD_KILL_RX 0x6 +#define AWI_CMD_KILL_RX 0x6 -#define AWI_CMD_SLEEP 0x7 +#define AWI_CMD_SLEEP 0x7 #define AWI_CA_SLEEP_LEN 0x8 #define AWI_CA_WAKEUP 0x0 /* uint64 */ -#define AWI_CMD_WAKE 0x8 +#define AWI_CMD_WAKE 0x8 -#define AWI_CMD_SCAN 0xa -#define AWI_CA_SCAN_LEN 0x6 +#define AWI_CMD_SCAN 0xa +#define AWI_CA_SCAN_LEN 0x6 #define AWI_CA_SCAN_DURATION 0x0 -#define AWI_CA_SCAN_SET 0x2 +#define AWI_CA_SCAN_SET 0x2 #define AWI_CA_SCAN_PATTERN 0x3 -#define AWI_CA_SCAN_IDX 0x4 +#define AWI_CA_SCAN_IDX 0x4 #define AWI_CA_SCAN_SUSP 0x5 -#define AWI_CMD_SYNC 0xb -#define AWI_CA_SYNC_LEN 0x14 -#define AWI_CA_SYNC_SET 0x0 +#define AWI_CMD_SYNC 0xb +#define AWI_CA_SYNC_LEN 0x14 +#define AWI_CA_SYNC_SET 0x0 #define AWI_CA_SYNC_PATTERN 0x1 -#define AWI_CA_SYNC_IDX 0x2 +#define AWI_CA_SYNC_IDX 0x2 #define AWI_CA_SYNC_STARTBSS 0x3 #define AWI_CA_SYNC_DWELL 0x4 -#define AWI_CA_SYNC_MBZ 0x6 +#define AWI_CA_SYNC_MBZ 0x6 #define AWI_CA_SYNC_TIMESTAMP 0x8 #define AWI_CA_SYNC_REFTIME 0x10 -#define AWI_CMD_RESUME 0xc +#define AWI_CMD_RESUME 0xc -#define AWI_CMD_STATUS 0x4a1 /* Command status */ +#define AWI_CMD_STATUS 0x4a1 /* Command status */ -#define AWI_STAT_IDLE 0x0 -#define AWI_STAT_OK 0x1 -#define AWI_STAT_BADCMD 0x2 -#define AWI_STAT_BADPARM 0x3 -#define AWI_STAT_NOTIMP 0x4 -#define AWI_STAT_BADRES 0x5 -#define AWI_STAT_BADMODE 0x6 +#define AWI_STAT_IDLE 0x0 +#define AWI_STAT_OK 0x1 +#define AWI_STAT_BADCMD 0x2 +#define AWI_STAT_BADPARM 0x3 +#define AWI_STAT_NOTIMP 0x4 +#define AWI_STAT_BADRES 0x5 +#define AWI_STAT_BADMODE 0x6 #define AWI_ERROR_OFFSET 0x4a2 /* Offset to erroneous parameter */ #define AWI_CMD_PARAMS 0x4a4 /* Command parameters */ -#define AWI_CSB 0x4f0 /* Control/Status block */ +#define AWI_CSB 0x4f0 /* Control/Status block */ #define AWI_SELFTEST 0x4f0 @@ -184,9 +181,9 @@ #define AWI_SELFTEST_MIB 0x03 /* mib initializing */ #define AWI_SELFTEST_MIB_FAIL 0xfa -#define AWI_SELFTEST_RADIO_FAIL 0xfb +#define AWI_SELFTEST_RADIO_FAIL 0xfb #define AWI_SELFTEST_MAC_FAIL 0xfc -#define AWI_SELFTEST_FLASH_FAIL 0xfd +#define AWI_SELFTEST_FLASH_FAIL 0xfd #define AWI_SELFTEST_RAM_FAIL 0xfe #define AWI_SELFTEST_PASSED 0xff @@ -213,8 +210,6 @@ #define AWI_INT_RX 0x02 /* rx done */ #define AWI_INT_CMD 0x01 /* cmd done */ -#define AWI_INT_BITS "\20\1CMD\2RX\3TX\4SCAN\5CFPST\6DTIM\7CFPE\10GROGGY" - /* * The following are used to implement a locking protocol between host * and MAC to protect the interrupt status and mask fields. @@ -224,7 +219,7 @@ * if non-zero, clear lockout_mac, loop. */ -#define AWI_LOCKOUT_MAC 0x4f5 +#define AWI_LOCKOUT_MAC 0x4f5 #define AWI_LOCKOUT_HOST 0x4f6 @@ -232,17 +227,17 @@ #define AWI_INTMASK2 0x4fd /* Bits in AWI_INTSTAT2/INTMASK2 */ -#define AWI_INT2_RXMGT 0x80 /* mgt/ps recieved */ -#define AWI_INT2_RXDATA 0x40 /* data received */ -#define AWI_INT2_TXMGT 0x10 /* mgt tx done */ -#define AWI_INT2_TXCF 0x08f /* CF tx done */ -#define AWI_INT2_TXPS 0x04 /* PS tx done */ -#define AWI_INT2_TXBCAST 0x02 /* Broadcast tx done */ -#define AWI_INT2_TXDATA 0x01 /* data tx done */ +#define AWI_INT2_RXMGT 0x80 /* mgt/ps recieved */ +#define AWI_INT2_RXDATA 0x40 /* data received */ +#define AWI_INT2_TXMGT 0x10 /* mgt tx done */ +#define AWI_INT2_TXCF 0x08 /* CF tx done */ +#define AWI_INT2_TXPS 0x04 /* PS tx done */ +#define AWI_INT2_TXBCAST 0x02 /* Broadcast tx done */ +#define AWI_INT2_TXDATA 0x01 /* data tx done */ #define AWI_DIS_PWRDN 0x4fc /* disable powerdown if set */ -#define AWI_DRIVERSTATE 0x4fe /* driver state */ +#define AWI_DRIVERSTATE 0x4fe /* driver state */ #define AWI_DRV_STATEMASK 0x0f @@ -251,46 +246,45 @@ #define AWI_DRV_ADHSC 0x2 /* adhoc scan */ #define AWI_DRV_ADHSY 0x3 /* adhoc synced */ #define AWI_DRV_INFSC 0x4 /* inf scanning */ -#define AWI_DRV_INFAUTH 0x5 /* inf authed */ +#define AWI_DRV_INFAUTH 0x5 /* inf authed */ #define AWI_DRV_INFASSOC 0x6 /* inf associated */ -#define AWI_DRV_INFTOSS 0x7 /* inf handoff */ +#define AWI_DRV_INFTOSS 0x7 /* inf handoff */ #define AWI_DRV_APNONE 0x8 /* AP activity: no assoc */ -#define AWI_DRV_APQUIET 0xc /* AP: >=one assoc, no traffic */ +#define AWI_DRV_APQUIET 0xc /* AP: >=one assoc, no traffic */ #define AWI_DRV_APLO 0xd /* AP: >=one assoc, light tfc */ #define AWI_DRV_APMED 0xe /* AP: >=one assoc, mod tfc */ #define AWI_DRV_APHIGH 0xf /* AP: >=one assoc, heavy tfc */ -#define AWI_DRV_AUTORXLED 0x10 -#define AWI_DRV_AUTOTXLED 0x20 -#define AWI_DRV_RXLED 0x40 -#define AWI_DRV_TXLED 0x80 +#define AWI_DRV_AUTORXLED 0x10 +#define AWI_DRV_AUTOTXLED 0x20 +#define AWI_DRV_RXLED 0x40 +#define AWI_DRV_TXLED 0x80 -#define AWI_VBM 0x500 /* Virtual Bit Map */ +#define AWI_VBM 0x500 /* Virtual Bit Map */ #define AWI_BUFFERS 0x600 /* Buffers */ +#define AWI_BUFFERS_END 0x6000 /* * Receive descriptors; there are a linked list of these chained * through the "NEXT" fields, starting from XXX */ -#define AWI_RXD_SIZE 0x18 +#define AWI_RXD_SIZE 0x18 -#define AWI_RXD_NEXT 0x4 -#define AWI_RXD_NEXT_LAST 0x80000000 +#define AWI_RXD_NEXT 0x4 +#define AWI_RXD_NEXT_LAST 0x80000000 -#define AWI_RXD_HOST_DESC_STATE 0x9 +#define AWI_RXD_HOST_DESC_STATE 0x9 #define AWI_RXD_ST_OWN 0x80 /* host owns this */ #define AWI_RXD_ST_CONSUMED 0x40 /* host is done */ #define AWI_RXD_ST_LF 0x20 /* last frag */ #define AWI_RXD_ST_CRC 0x08 /* CRC error */ -#define AWI_RXD_ST_OFLO 0x02 /* possible buffer overrun */ +#define AWI_RXD_ST_OFLO 0x02 /* possible buffer overrun */ #define AWI_RXD_ST_RXERROR 0x01 /* this frame is borked; discard me */ -#define AWI_RXD_ST_BITS "\20\1ERROR\2OVERRUN\4CRC\6LF\7CONSUMED\10OWN" - #define AWI_RXD_RSSI 0xa /* 1 byte: radio strength indicator */ #define AWI_RXD_INDEX 0xb /* 1 byte: FH hop index or DS channel */ #define AWI_RXD_LOCALTIME 0xc /* 4 bytes: local time of RX */ @@ -309,19 +303,19 @@ #define AWI_TXD_LENGTH 0x08 /* length of frame */ #define AWI_TXD_STATE 0x0a /* state */ -#define AWI_TXD_ST_OWN 0x80 /* MAC owns this */ +#define AWI_TXD_ST_OWN 0x80 /* MAC owns this */ #define AWI_TXD_ST_DONE 0x40 /* MAC is done */ -#define AWI_TXD_ST_REJ 0x20 /* MAC doesn't like */ +#define AWI_TXD_ST_REJ 0x20 /* MAC doesn't like */ #define AWI_TXD_ST_MSDU 0x10 /* MSDU timeout */ #define AWI_TXD_ST_ABRT 0x08 /* TX aborted */ -#define AWI_TXD_ST_RETURNED 0x04 /* TX returned */ -#define AWI_TXD_ST_RETRY 0x02 /* TX retries exceeded */ -#define AWI_TXD_ST_ERROR 0x01 /* TX error */ +#define AWI_TXD_ST_RETURNED 0x04 /* TX returned */ +#define AWI_TXD_ST_RETRY 0x02 /* TX retries exceeded */ +#define AWI_TXD_ST_ERROR 0x01 /* TX error */ #define AWI_TXD_RATE 0x0b /* rate */ -#define AWI_RATE_1MBIT 10 -#define AWI_RATE_2MBIT 20 +#define AWI_RATE_1MBIT 10 +#define AWI_RATE_2MBIT 20 #define AWI_TXD_NDA 0x0c /* num DIFS attempts */ #define AWI_TXD_NDF 0x0d /* num DIFS failures */ @@ -332,7 +326,7 @@ #define AWI_TXD_NDTA 0x15 /* num data attempts */ #define AWI_TXD_CTL 0x16 /* control */ -#define AWI_TXD_CTL_PSN 0x80 /* preserve sequence in MAC frame */ +#define AWI_TXD_CTL_PSN 0x80 /* preserve sequence in MAC frame */ #define AWI_TXD_CTL_BURST 0x02 /* host is doing 802.11 fragmt. */ #define AWI_TXD_CTL_FRAGS 0x01 /* override normal fragmentation */ @@ -340,171 +334,126 @@ * MIB structures. */ -/* - * MIB 0: Local MIB - */ - -#define AWI_MIB_LOCAL_NOFRAG 0 -#define AWI_MIB_LOCAL_NOPLCP 1 -#define AWI_MIB_LOCAL_MACPRES 2 -#define AWI_MIB_LOCAL_RXMGTQ 3 -#define AWI_MIB_LOCAL_NOREASM 4 -#define AWI_MIB_LOCAL_NOSTRIPPLCP 5 -#define AWI_MIB_LOCAL_NORXERROR 6 -#define AWI_MIB_LOCAL_NOPWRSAVE 7 - -#define AWI_MIB_LOCAL_FILTMULTI 8 -#define AWI_MIB_LOCAL_NOSEQCHECK 9 -#define AWI_MIB_LOCAL_CFPENDFLUSHCFPQ 10 -#define AWI_MIB_LOCAL_INFRA_MODE 11 -#define AWI_MIB_LOCAL_PWD_LEVEL 12 -#define AWI_MIB_LOCAL_CFPMODE 13 - -#define AWI_MIB_LOCAL_TXB_OFFSET 14 -#define AWI_MIB_LOCAL_TXB_SIZE 18 -#define AWI_MIB_LOCAL_RXB_OFFSET 22 -#define AWI_MIB_LOCAL_RXB_SIZE 26 - -#define AWI_MIB_LOCAL_ACTING_AS_AP 30 -#define AWI_MIB_LOCAL_FILL_CFP 31 -#define AWI_MIB_LOCAL_SIZE 32 - -/* - * MAC mib - */ - -#define AWI_MIB_MAC_RTS_THRESH 4 /* 2 bytes */ -#define AWI_MIB_MAC_CW_MAX 6 -#define AWI_MIB_MAC_CW_MIN 8 -#define AWI_MIB_MAC_PROMISC 10 -#define AWI_MIB_MAC_SHORT_RETRY 16 -#define AWI_MIB_MAC_LONG_RETRY 17 -#define AWI_MIB_MAC_MAX_FRAME 18 -#define AWI_MIB_MAC_MAX_FRAG 20 -#define AWI_MIB_MAC_PROBE_DELAY 22 -#define AWI_MIB_MAC_PROBE_RESP_MIN 24 -#define AWI_MIB_MAC_PROBE_RESP_MAX 26 -#define AWI_MIB_MAC_MAX_TX_MSDU_LIFE 28 -#define AWI_MIB_MAC_MAX_RX_MSDU_LIFE 32 -#define AWI_MIB_MAC_STATION_BASE_RATE 36 -#define AWI_MIB_MAC_DES_ESSID 38 /* 34 bytes */ - -/* - * MGT mib. - */ - -#define AWI_MIB_MGT_POWER_MODE 0 -#define AWI_MIB_MGT_SCAN_MODE 1 -#define AWI_MIB_MGT_SCAN_STATE 2 -#define AWI_MIB_MGT_DTIM_PERIOD 3 -#define AWI_MIB_MGT_ATIM_WINDOW 4 -#define AWI_MIB_MGT_WEPREQ 6 -#define AWI_MIB_MGT_BEACON_PD 8 -#define AWI_MIB_MGT_PASSIVE_SCAN 10 -#define AWI_MIB_MGT_LISTEN_INT 12 -#define AWI_MIB_MGT_MEDIUP_OCC 14 -#define AWI_MIB_MGT_MAX_MPDU_TIME 16 -#define AWI_MIB_MGT_CFP_MAX_DUR 18 -#define AWI_MIB_MGT_CFP_RATE 20 -#define AWI_MIB_MGT_NO_DTMS 21 -#define AWI_MIB_MGT_STATION_ID 22 -#define AWI_MIB_MGT_BSS_ID 24 -#define AWI_MIB_MGT_ESS_ID 30 /* 34 bytes */ -#define AWI_MIB_MGT_ESS_SIZE 34 - - -/* - * MAC address group. - */ - -#define AWI_MIB_MAC_ADDR_MINE 0 -#define AWI_MIB_MAC_ADDR_MULTI0 6 -#define AWI_MIB_MAC_ADDR_MULTI1 12 -#define AWI_MIB_MAC_ADDR_MULTI2 18 -#define AWI_MIB_MAC_ADDR_MULTI3 24 - -#define AWI_MIB_MAC_ADDR_TXEN 30 - -/* - * 802.11 media layer goo. - * Should be split out into separate module independant of this driver. - */ - -#define IEEEWL_FC 0 /* frame control */ - -#define IEEEWL_FC_VERS 0 -#define IEEEWL_FC_VERS_MASK 0x03 - -#define IEEEWL_FC_TYPE_MGT 0 -#define IEEEWL_FC_TYPE_CTL 1 -#define IEEEWL_FC_TYPE_DATA 2 - -#define IEEEWL_FC_TYPE_MASK 0x0c -#define IEEEWL_FC_TYPE_SHIFT 2 - -#define IEEEWL_FC_SUBTYPE_MASK 0xf0 -#define IEEEWL_FC_SUBTYPE_SHIFT 4 - -#define IEEEWL_SUBTYPE_ASSOCREQ 0x00 -#define IEEEWL_SUBTYPE_ASSOCRESP 0x01 -#define IEEEWL_SUBTYPE_REASSOCREQ 0x02 -#define IEEEWL_SUBTYPE_REASSOCRESP 0x03 -#define IEEEWL_SUBTYPE_PROBEREQ 0x04 -#define IEEEWL_SUBTYPE_PROBERESP 0x05 - -#define IEEEWL_SUBTYPE_BEACON 0x08 -#define IEEEWL_SUBTYPE_DISSOC 0x0a -#define IEEEWL_SUBTYPE_AUTH 0x0b -#define IEEEWL_SUBTYPE_DEAUTH 0x0c - -#define IEEEWL_FC2 1 /* second byte of fc */ - -/* - * TLV tags for things we care about.. - */ -#define IEEEWL_MGT_TLV_SSID 0 -#define IEEEWL_MGT_TLV_FHPARMS 2 +#define AWI_ESS_ID_SIZE (IEEE80211_NWID_LEN+2) +struct awi_mib_local { + u_int8_t Fragmentation_Dis; + u_int8_t Add_PLCP_Dis; + u_int8_t MAC_Hdr_Prsv; + u_int8_t Rx_Mgmt_Que_En; + u_int8_t Re_Assembly_Dis; + u_int8_t Strip_PLCP_Dis; + u_int8_t Rx_Error_Dis; + u_int8_t Power_Saving_Mode_Dis; + u_int8_t Accept_All_Multicast_Dis; + u_int8_t Check_Seq_Cntl_Dis; + u_int8_t Flush_CFP_Queue_On_CF_End; + u_int8_t Network_Mode; + u_int8_t PWD_Lvl; + u_int8_t CFP_Mode; + u_int8_t Tx_Buffer_Offset[4]; + u_int8_t Tx_Buffer_Size[4]; + u_int8_t Rx_Buffer_Offset[4]; + u_int8_t Rx_Buffer_Size[4]; + u_int8_t Acting_as_AP; + u_int8_t Fill_CFP; +}; -/* - * misc frame control bits in second byte of frame control word. - * there are others, but we don't ever want to set them.. - */ +struct awi_mib_mac { + u_int8_t _Reserved1[2]; + u_int8_t _Reserved2[2]; + u_int8_t aRTS_Threshold[2]; + u_int8_t aCW_max[2]; + u_int8_t aCW_min[2]; + u_int8_t aPromiscuous_Enable; + u_int8_t _Reserved3; + u_int8_t _Reserved4[4]; + u_int8_t aShort_Retry_Limit; + u_int8_t aLong_Retry_Limit; + u_int8_t aMax_Frame_Length[2]; + u_int8_t aFragmentation_Threshold[2]; + u_int8_t aProbe_Delay[2]; + u_int8_t aMin_Probe_Response_Time[2]; + u_int8_t aMax_Probe_Response_Time[2]; + u_int8_t aMax_Transmit_MSDU_Lifetime[4]; + u_int8_t aMax_Receive_MSDU_Lifetime[4]; + u_int8_t aStation_Basic_Rate[2]; + u_int8_t aDesired_ESS_ID[AWI_ESS_ID_SIZE]; +}; -#define IEEEWL_FC2_DSMASK 0x03 - -#define IEEEWL_FC2_TODS 0x01 -#define IEEEWL_FC2_FROMDS 0x02 - -#define IEEEWL_FH_CHANSET_MIN 1 -#define IEEEWL_FH_CHANSET_MAX 3 -#define IEEEWL_FH_PATTERN_MIN 0 -#define IEEEWL_FH_PATTERN_MAX 77 - -struct awi_mac_header -{ - u_int8_t awi_fc; - u_int8_t awi_f2; - u_int16_t awi_duration; - u_int8_t awi_addr1[6]; - u_int8_t awi_addr2[6]; - u_int8_t awi_addr3[6]; - u_int16_t awi_seqctl; +struct awi_mib_stat { + u_int8_t aTransmitted_MPDU_Count[4]; + u_int8_t aTransmitted_MSDU_Count[4]; + u_int8_t aOctets_Transmitted_Cnt[4]; + u_int8_t aMulticast_Transmitted_Frame_Count[2]; + u_int8_t aBroadcast_Transmitted_Frame_Count[2]; + u_int8_t aFailed_Count[4]; + u_int8_t aRetry_Count[4]; + u_int8_t aMultiple_Retry_Count[4]; + u_int8_t aFrame_Duplicate_Count[4]; + u_int8_t aRTS_Success_Count[4]; + u_int8_t aRTS_Failure_Count[4]; + u_int8_t aACK_Failure_Count[4]; + u_int8_t aReceived_Frame_Count [4]; + u_int8_t aOctets_Received_Count[4]; + u_int8_t aMulticast_Received_Count[2]; + u_int8_t aBroadcast_Received_Count[2]; + u_int8_t aFCS_Error_Count[4]; + u_int8_t aError_Count[4]; + u_int8_t aWEP_Undecryptable_Count[4]; }; -struct awi_llc_header -{ - u_int8_t awi_llc_goo[8]; +struct awi_mib_mgt { + u_int8_t aPower_Mgt_Mode; + u_int8_t aScan_Mode; +#define AWI_SCAN_PASSIVE 0x00 +#define AWI_SCAN_ACTIVE 0x01 +#define AWI_SCAN_BACKGROUND 0x02 + u_int8_t aScan_State; + u_int8_t aDTIM_Period; + u_int8_t aATIM_Window[2]; + u_int8_t Wep_Required; + u_int8_t _Reserved1; + u_int8_t aBeacon_Period[2]; + u_int8_t aPassive_Scan_Duration[2]; + u_int8_t aListen_Interval[2]; + u_int8_t aMedium_Occupancy_Limit[2]; + u_int8_t aMax_MPDU_Time[2]; + u_int8_t aCFP_Max_Duration[2]; + u_int8_t aCFP_Rate; + u_int8_t Do_Not_Receive_DTIMs; + u_int8_t aStation_ID[2]; + u_int8_t aCurrent_BSS_ID[ETHER_ADDR_LEN]; + u_int8_t aCurrent_ESS_ID[AWI_ESS_ID_SIZE]; }; -struct awi_assoc_hdr -{ - u_int8_t awi_cap_info[2]; - u_int8_t awi_li[2]; +#define AWI_GROUP_ADDR_SIZE 4 +struct awi_mib_addr { + u_int8_t aMAC_Address[ETHER_ADDR_LEN]; + u_int8_t aGroup_Addresses[AWI_GROUP_ADDR_SIZE][ETHER_ADDR_LEN]; + u_int8_t aTransmit_Enable_Status; + u_int8_t _Reserved1; }; -struct awi_auth_hdr -{ - u_int8_t awi_algno[2]; - u_int8_t awi_seqno[2]; - u_int8_t awi_status[2]; +#define AWI_PWR_LEVEL_SIZE 4 +struct awi_mib_phy { + u_int8_t aSlot_Time[2]; + u_int8_t aSIFS[2]; + u_int8_t aMPDU_Maximum[2]; + u_int8_t aHop_Time[2]; + u_int8_t aSuprt_Data_Rates[4]; + u_int8_t aCurrent_Reg_Domain; +#define AWI_REG_DOMAIN_US 0x10 +#define AWI_REG_DOMAIN_CA 0x20 +#define AWI_REG_DOMAIN_EU 0x30 +#define AWI_REG_DOMAIN_ES 0x31 +#define AWI_REG_DOMAIN_FR 0x32 +#define AWI_REG_DOMAIN_JP 0x40 + u_int8_t aPreamble_Lngth; + u_int8_t aPLCP_Hdr_Lngth; + u_int8_t Pwr_Up_Time[AWI_PWR_LEVEL_SIZE][2]; + u_int8_t IEEE_PHY_Type; +#define AWI_PHY_TYPE_FH 1 +#define AWI_PHY_TYPE_DS 2 +#define AWI_PHY_TYPE_IR 3 + u_int8_t RCR_33A_Bits[8]; }; diff --git a/sys/dev/ic/awivar.h b/sys/dev/ic/awivar.h index d50fa7c9b66..a2ce7ef5de4 100644 --- a/sys/dev/ic/awivar.h +++ b/sys/dev/ic/awivar.h @@ -1,5 +1,4 @@ -/* $NetBSD: awivar.h,v 1.4 1999/11/09 14:58:07 sommerfeld Exp $ */ -/* $OpenBSD: awivar.h,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */ +/* $NetBSD: awivar.h,v 1.12 2000/07/21 04:48:56 onoe Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -37,120 +36,137 @@ * POSSIBILITY OF SUCH DAMAGE. */ - -enum awi_state { - AWI_ST_OFF, /* powered off */ - AWI_ST_SELFTEST, /* waiting for selftest to complete*/ - AWI_ST_IFTEST, /* waiting for interface to respond */ - AWI_ST_MIB_GET, /* fetching MIB variables */ - AWI_ST_MIB_SET, /* stuffing MIB variables */ - AWI_ST_TXINIT, /* initializing TX side */ - AWI_ST_RXINIT, /* initializing RX side */ - AWI_ST_SCAN, /* hunting for a BSS */ - AWI_ST_SYNCED, /* synced? trying to auth.. */ - /* there are probably some missing 802.11 states here.. */ - AWI_ST_AUTHED, /* authenticated */ - AWI_ST_RUNNING, /* ready to send user data.. */ - AWI_ST_INSANE, /* failed to respond.. */ +/* timer values in msec */ +#define AWI_SELFTEST_TIMEOUT 5000 +#define AWI_CMD_TIMEOUT 2000 +#define AWI_LOCKOUT_TIMEOUT 50 +#define AWI_ASCAN_DURATION 100 +#define AWI_ASCAN_WAIT 3000 +#define AWI_PSCAN_DURATION 200 +#define AWI_PSCAN_WAIT 5000 +#define AWI_TRANS_TIMEOUT 2000 + +#define AWI_NTXBUFS 4 +#define AWI_MAX_KEYLEN 16 + +enum awi_status { + AWI_ST_INIT, + AWI_ST_SCAN, + AWI_ST_SETSS, + AWI_ST_SYNC, + AWI_ST_AUTH, + AWI_ST_ASSOC, + AWI_ST_RUNNING }; -#define AWI_FL_CMD_INPROG 0x0001 - -#define AWI_SSID_LEN 33 - -struct awi_bss_binding +struct awi_bss { - u_int8_t chanset; /* channel set to use */ - u_int8_t pattern; /* hop pattern to use */ - u_int8_t index; /* index to use */ - u_int8_t rssi; /* strenght of this beacon */ - u_int16_t dwell_time; /* dwell time */ - u_int8_t bss_timestamp[8]; /* timestamp of this bss */ - u_int8_t bss_id[6]; - u_int32_t rxtime; /* unit's local time */ - u_int8_t sslen; - u_int8_t ssid[AWI_SSID_LEN]; + TAILQ_ENTRY(awi_bss) list; + u_int8_t esrc[ETHER_ADDR_LEN]; + u_int8_t chanset; /* channel set to use */ + u_int8_t pattern; /* hop pattern to use */ + u_int8_t index; /* index to use */ + u_int8_t rssi; /* strength of this beacon */ + u_int16_t dwell_time; /* dwell time */ + u_int8_t timestamp[8]; /* timestamp of this bss */ + u_int8_t bssid[ETHER_ADDR_LEN]; + u_int16_t capinfo; + u_int32_t rxtime; /* unit's local time */ + u_int16_t interval; /* beacon interval */ + u_int8_t txrate; + u_int8_t fails; + u_int8_t essid[IEEE80211_NWID_LEN + 2]; }; -#define NBND 4 -#define NTXD 4 - -struct awi_txbd -{ - u_int32_t descr; /* offset to descriptor */ - u_int32_t frame; /* offset to frame */ - u_int32_t len; /* frame length */ +struct awi_wep_algo { + char *awa_name; + int (*awa_ctxlen) __P((void)); + void (*awa_setkey) __P((void *, u_char *, int)); + void (*awa_encrypt) __P((void *, u_char *, u_char *, int)); + void (*awa_decrypt) __P((void *, u_char *, u_char *, int)); }; struct awi_softc { +#ifdef __NetBSD__ + struct device sc_dev; + struct ethercom sc_ec; + void *sc_ih; /* interrupt handler */ +#endif +#ifdef __FreeBSD__ +#if __FreeBSD__ >= 4 + struct { + char dv_xname[64]; /*XXX*/ + } sc_dev; +#else + struct device sc_dev; +#endif +#endif +#ifdef __OpenBSD__ struct device sc_dev; - struct am79c930_softc sc_chip; struct arpcom sc_ec; - int sc_enabled; - enum awi_state sc_state; - int sc_flags; void *sc_ih; /* interrupt handler */ - struct ifnet *sc_ifp; /* XXX */ +#endif + struct am79c930_softc sc_chip; + struct ifnet *sc_ifp; int (*sc_enable) __P((struct awi_softc *)); void (*sc_disable) __P((struct awi_softc *)); - void (*sc_completion) __P((struct awi_softc *, - u_int8_t)); + struct ifmedia sc_media; + enum awi_status sc_status; + unsigned int sc_enabled:1, + sc_busy:1, + sc_cansleep:1, + sc_invalid:1, + sc_enab_intr:1, + sc_format_llc:1, + sc_start_bss:1, + sc_rawbpf:1, + sc_no_bssid:1, + sc_active_scan:1, + sc_attached:1; /* attach has succeeded */ + u_int8_t sc_cmd_inprog; + int sc_sleep_cnt; + + int sc_mgt_timer; + + TAILQ_HEAD(, awi_bss) sc_scan; + u_int8_t sc_scan_cur; + u_int8_t sc_scan_min; + u_int8_t sc_scan_max; + u_int8_t sc_scan_set; + struct awi_bss sc_bss; + u_int8_t sc_ownssid[IEEE80211_NWID_LEN + 2]; + u_int8_t sc_ownch; + + int sc_rx_timer; + u_int32_t sc_rxdoff; + u_int32_t sc_rxmoff; + struct mbuf *sc_rxpend; + + int sc_tx_timer; + u_int8_t sc_tx_rate; struct ifqueue sc_mgtq; - u_int32_t sc_txbase; - u_int32_t sc_txlen; - u_int32_t sc_rxbase; - u_int32_t sc_rxlen; - - u_int32_t sc_rx_data_desc; - u_int32_t sc_rx_mgt_desc; - - u_int16_t sc_scan_duration; - u_int8_t sc_scan_chanset; - u_int8_t sc_scan_pattern; - - int sc_nbindings; - - u_int8_t sc_my_addr[6]; - - int sc_new_bss; - struct awi_bss_binding sc_active_bss; - /* - * BSS's found during a scan.. XXX doesn't need to be in-line - */ - struct awi_bss_binding sc_bindings[NBND]; - - int sc_txpending; - int sc_ntxd; - int sc_txnext; /* next txd to be given to driver */ - int sc_txfirst; /* first unsent txd dev has */ - struct awi_txbd sc_txd[NTXD]; - u_int8_t sc_curmib; - - int sc_scan_timer; - int sc_tx_timer; - int sc_mgt_timer; - int sc_cmd_timer; - int sc_selftest_tries; - - /* - * packet parsing state. - */ - - struct mbuf *sc_nextpkt; - struct mbuf *sc_m; - u_int8_t *sc_mptr; - u_int32_t sc_mleft; - int sc_flushpkt; + u_int32_t sc_txend; + u_int32_t sc_txnext; + u_int32_t sc_txdone; + + int sc_wep_keylen[IEEE80211_WEP_NKID]; /* keylen */ + u_int8_t sc_wep_key[IEEE80211_WEP_NKID][AWI_MAX_KEYLEN]; + int sc_wep_defkid; + void *sc_wep_ctx; /* work area */ + struct awi_wep_algo *sc_wep_algo; + + u_char sc_banner[AWI_BANNER_LEN]; + struct awi_mib_local sc_mib_local; + struct awi_mib_addr sc_mib_addr; + struct awi_mib_mac sc_mib_mac; + struct awi_mib_stat sc_mib_stat; + struct awi_mib_mgt sc_mib_mgt; + struct awi_mib_phy sc_mib_phy; }; -extern int awi_activate __P((struct device *, enum devact)); -extern int awi_attach __P((struct awi_softc *, u_int8_t *macaddr)); -extern void awi_init __P((struct awi_softc *)); -extern void awi_stop __P((struct awi_softc *)); - #define awi_read_1(sc, off) ((sc)->sc_chip.sc_ops->read_1)(&sc->sc_chip, off) #define awi_read_2(sc, off) ((sc)->sc_chip.sc_ops->read_2)(&sc->sc_chip, off) #define awi_read_4(sc, off) ((sc)->sc_chip.sc_ops->read_4)(&sc->sc_chip, off) @@ -167,17 +183,59 @@ extern void awi_stop __P((struct awi_softc *)); #define awi_drvstate(sc, state) \ awi_write_1(sc, AWI_DRIVERSTATE, \ - ((state) | AWI_DRV_AUTORXLED|AWI_DRV_AUTOTXLED)); - -/* Number of trips around the loop waiting for the device.. */ - -#define AWI_LOCKOUT_SPIN 10000 /* 10ms */ - -/* 24-byte mac header + 8 byte SNAP header + 1500-byte ether MTU */ -#define AWI_FRAME_SIZE 1532 - -/* refresh associations every 300s */ - -#define AWI_ASSOC_REFRESH 300 + ((state) | AWI_DRV_AUTORXLED|AWI_DRV_AUTOTXLED)) + +/* unalligned little endian access */ +#define LE_READ_2(p) \ + (((u_int8_t *)(p))[0] | (((u_int8_t *)(p))[1] << 8)) +#define LE_READ_4(p) \ + (((u_int8_t *)(p))[0] | (((u_int8_t *)(p))[1] << 8) | \ + (((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24)) +#define LE_WRITE_2(p, v) \ + ((((u_int8_t *)(p))[0] = ((u_int32_t)(v) & 0xff)), \ + (((u_int8_t *)(p))[1] = (((u_int32_t)(v) >> 8) & 0xff))) +#define LE_WRITE_4(p, v) \ + ((((u_int8_t *)(p))[0] = ((u_int32_t)(v) & 0xff)), \ + (((u_int8_t *)(p))[1] = (((u_int32_t)(v) >> 8) & 0xff)), \ + (((u_int8_t *)(p))[2] = (((u_int32_t)(v) >> 16) & 0xff)), \ + (((u_int8_t *)(p))[3] = (((u_int32_t)(v) >> 24) & 0xff))) + +#define AWI_80211_RATE(rate) (((rate) & 0x7f) * 5) + +int awi_attach __P((struct awi_softc *)); +int awi_intr __P((void *)); +void awi_reset __P((struct awi_softc *)); +#ifndef __FreeBSD__ +int awi_activate __P((struct device *, enum devact)); +int awi_detach __P((struct awi_softc *)); +void awi_power __P((struct awi_softc *, int)); +#endif + +void awi_stop __P((struct awi_softc *sc)); +int awi_init __P((struct awi_softc *sc)); +int awi_init_region __P((struct awi_softc *)); +int awi_wicfg __P((struct ifnet *, u_long, caddr_t)); + +int awi_wep_setnwkey __P((struct awi_softc *, struct ieee80211_nwkey *)); +int awi_wep_getnwkey __P((struct awi_softc *, struct ieee80211_nwkey *)); +int awi_wep_getalgo __P((struct awi_softc *)); +int awi_wep_setalgo __P((struct awi_softc *, int)); +int awi_wep_setkey __P((struct awi_softc *, int, unsigned char *, int)); +int awi_wep_getkey __P((struct awi_softc *, int, unsigned char *, int *)); +struct mbuf *awi_wep_encrypt __P((struct awi_softc *, struct mbuf *, int)); + +#ifdef __FreeBSD__ +/* Provide mem* for compat with NetBSD to fix LINT */ +static __inline int +memcmp(const void *b1, const void *b2, size_t len) +{ + return (bcmp(b1, b2, len)); +} -extern int awi_intr __P((void *)); +static __inline void * +memset(void *b, int c, size_t len) +{ + bzero(b, len); + return (b); +} +#endif diff --git a/sys/dev/pcmcia/files.pcmcia b/sys/dev/pcmcia/files.pcmcia index 1c07957361b..cea7d0a1b67 100644 --- a/sys/dev/pcmcia/files.pcmcia +++ b/sys/dev/pcmcia/files.pcmcia @@ -1,4 +1,4 @@ -# $OpenBSD: files.pcmcia,v 1.32 2000/06/19 08:58:54 fgsch Exp $ +# $OpenBSD: files.pcmcia,v 1.33 2000/08/17 16:16:31 mickey Exp $ # $NetBSD: files.pcmcia,v 1.9 1998/06/21 18:45:41 christos Exp $ # # Config.new file and device description for machine-independent PCMCIA code. @@ -77,10 +77,11 @@ file dev/pcmcia/if_wi.c wi # AMD 79c930-based 802.11 cards (including BayStack 650 FH card). device awi: ether, ifnet attach awi at pcmcia with awi_pcmcia - -file dev/pcmcia/if_awi_pcmcia.c awi_pcmcia -file dev/ic/awi.c awi -file dev/ic/am79c930.c awi +file dev/pcmcia/if_awi_pcmcia.c awi_pcmcia +file dev/ic/awi.c awi +file dev/ic/awi_wep.c awi +#file dev/ic/awi_wicfg.c awi +file dev/ic/am79c930.c awi # Raytheon(Raylink)/WebGear IEEE 802.11 FH WLAN device ray: ether, ifnet, ifmedia diff --git a/sys/dev/pcmcia/if_awi_pcmcia.c b/sys/dev/pcmcia/if_awi_pcmcia.c index 0119dced22e..7c9fb4b388d 100644 --- a/sys/dev/pcmcia/if_awi_pcmcia.c +++ b/sys/dev/pcmcia/if_awi_pcmcia.c @@ -1,5 +1,5 @@ -/* $NetBSD: if_awi_pcmcia.c,v 1.5 1999/11/06 16:43:54 sommerfeld Exp $ */ -/* $OpenBSD: if_awi_pcmcia.c,v 1.3 2000/04/24 19:43:35 niklas Exp $ */ +/* $NetBSD: if_awi_pcmcia.c,v 1.13 2000/03/22 11:22:20 onoe Exp $ */ +/* $OpenBSD: if_awi_pcmcia.c,v 1.4 2000/08/17 16:16:31 mickey Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -61,23 +61,13 @@ #include <net/if_dl.h> #include <net/if_media.h> -#ifdef INET #include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/in_var.h> -#include <netinet/ip.h> -#endif - #include <netinet/if_ether.h> -#ifdef NS -#include <netns/ns.h> -#include <netns/ns_if.h> -#endif +#include <net/if_ieee80211.h> #if NBPFILTER > 0 #include <net/bpf.h> -#include <net/bpfdesc.h> #endif #include <machine/cpu.h> @@ -93,53 +83,102 @@ #include <dev/pcmcia/pcmciavar.h> #include <dev/pcmcia/pcmciadevs.h> -int awi_pcmcia_match __P((struct device *, void *, void *)); -void awi_pcmcia_attach __P((struct device *, struct device *, void *)); -int awi_pcmcia_detach __P((struct device *, int)); - -int awi_pcmcia_get_enaddr __P((struct pcmcia_tuple *, void *)); -int awi_pcmcia_enable __P((struct awi_softc *)); -void awi_pcmcia_disable __P((struct awi_softc *)); - struct awi_pcmcia_softc { - struct awi_softc sc_awi; /* real "awi" softc */ + struct awi_softc sc_awi; /* real "awi" softc */ /* PCMCIA-specific goo */ struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ + struct pcmcia_mem_handle sc_memh; /* PCMCIA memory space info */ int sc_io_window; /* our i/o window */ + int sc_mem_window; /* our memory window */ struct pcmcia_function *sc_pf; /* our PCMCIA function */ + void *sc_powerhook; /* power hook descriptor */ }; -int awi_pcmcia_find __P((struct awi_pcmcia_softc *, - struct pcmcia_attach_args *, struct pcmcia_config_entry *)); +static int awi_pcmcia_match __P((struct device *, void *, void *)); +static void awi_pcmcia_attach __P((struct device *, struct device *, void *)); +static int awi_pcmcia_detach __P((struct device *, int)); +static int awi_pcmcia_enable __P((struct awi_softc *)); +static void awi_pcmcia_disable __P((struct awi_softc *)); +static void awi_pcmcia_powerhook __P((int, void *)); -/* Autoconfig definition of driver back-end */ -struct cfdriver awi_cd = { - NULL, "awi", DV_IFNET -}; +static int awi_pcmcia_find __P((struct awi_pcmcia_softc *, + struct pcmcia_attach_args *, struct pcmcia_config_entry *)); struct cfattach awi_pcmcia_ca = { sizeof(struct awi_pcmcia_softc), awi_pcmcia_match, awi_pcmcia_attach, - awi_pcmcia_detach, /* awi_activate */ 0 + awi_pcmcia_detach, awi_activate }; -/* - * XXX following is common to most PCMCIA NIC's and belongs - * in common code - */ +static struct awi_pcmcia_product { + u_int32_t app_vendor; /* vendor ID */ + u_int32_t app_product; /* product ID */ + const char *app_cisinfo[4]; /* CIS information */ + const char *app_name; /* product name */ +} awi_pcmcia_products[] = { + { PCMCIA_VENDOR_BAY, PCMCIA_PRODUCT_BAY_STACK_650, + PCMCIA_CIS_BAY_STACK_650, "BayStack 650" }, + + { PCMCIA_VENDOR_BAY, PCMCIA_PRODUCT_BAY_STACK_660, + PCMCIA_CIS_BAY_STACK_660, "BayStack 660" }, -struct awi_pcmcia_get_enaddr_args { - int got_enaddr; - u_int8_t enaddr[ETHER_ADDR_LEN]; + { PCMCIA_VENDOR_BAY, PCMCIA_PRODUCT_BAY_SURFER_PRO, + PCMCIA_CIS_BAY_SURFER_PRO, "AirSurfer Pro" }, + + { PCMCIA_VENDOR_AMD, PCMCIA_PRODUCT_AMD_AM79C930, + PCMCIA_CIS_AMD_AM79C930, "AMD AM79C930" }, + + { PCMCIA_VENDOR_ICOM, PCMCIA_PRODUCT_ICOM_SL200, + PCMCIA_CIS_ICOM_SL200, "Icom SL-200" }, + + { PCMCIA_VENDOR_NOKIA, PCMCIA_PRODUCT_NOKIA_C020_WLAN, + PCMCIA_CIS_NOKIA_C020_WLAN, "Nokia C020" }, + + { PCMCIA_VENDOR_FARALLON, PCMCIA_PRODUCT_FARALLON_SKYLINE, + PCMCIA_CIS_FARALLON_SKYLINE, "SkyLINE Wireless" }, + +/* { PCMCIA_VENDOR_BREEZECOM, PCMCIA_PRODUCT_BREEZECOM_BREEZENET, + PCMCIA_CIS_BREEZECOM_BREEZENET, "BreezeNet SC-PX" }, +*/ + { 0, 0, + { NULL, NULL, NULL, NULL }, NULL }, }; -int awi_pcmcia_get_enaddr __P((struct pcmcia_tuple *, void *)); +static struct awi_pcmcia_product * + awi_pcmcia_lookup __P((struct pcmcia_attach_args *)); + +static struct awi_pcmcia_product * +awi_pcmcia_lookup(pa) + struct pcmcia_attach_args *pa; +{ + struct awi_pcmcia_product *app; + + for (app = awi_pcmcia_products; app->app_name != NULL; app++) { + /* match by vendor/product id */ + if (pa->manufacturer != PCMCIA_VENDOR_INVALID && + pa->manufacturer == app->app_vendor && + pa->product != PCMCIA_PRODUCT_INVALID && + pa->product == app->app_product) + return (app); + + /* match by CIS information */ + if (pa->card->cis1_info[0] != NULL && + app->app_cisinfo[0] != NULL && + strcmp(pa->card->cis1_info[0], app->app_cisinfo[0]) == 0 && + pa->card->cis1_info[1] != NULL && + app->app_cisinfo[1] != NULL && + strcmp(pa->card->cis1_info[1], app->app_cisinfo[1]) == 0) + return (app); + } + + return (NULL); +} -int +static int awi_pcmcia_enable(sc) struct awi_softc *sc; { - struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *) sc; + struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *)sc; struct pcmcia_function *pf = psc->sc_pf; /* establish the interrupt. */ @@ -149,21 +188,28 @@ awi_pcmcia_enable(sc) sc->sc_dev.dv_xname); return (1); } - return (pcmcia_function_enable(pf)); + + if (pcmcia_function_enable(pf)) { + pcmcia_intr_disestablish(pf, sc->sc_ih); + return (1); + } + DELAY(1000); + + return (0); } -void +static void awi_pcmcia_disable(sc) struct awi_softc *sc; { - struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *) sc; + struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *)sc; struct pcmcia_function *pf = psc->sc_pf; pcmcia_intr_disestablish (pf, sc->sc_ih); pcmcia_function_disable (pf); } -int +static int awi_pcmcia_match(parent, match, aux) struct device *parent; void *match; @@ -171,17 +217,14 @@ awi_pcmcia_match(parent, match, aux) { struct pcmcia_attach_args *pa = aux; - if (pa->manufacturer != PCMCIA_VENDOR_BAY) - return (0); - - if (pa->product == PCMCIA_PRODUCT_BAY_STACK_650) + if (awi_pcmcia_lookup(pa) != NULL) return (1); return (0); } -int -awi_pcmcia_find (psc, pa, cfe) +static int +awi_pcmcia_find(psc, pa, cfe) struct awi_pcmcia_softc *psc; struct pcmcia_attach_args *pa; struct pcmcia_config_entry *cfe; @@ -189,95 +232,69 @@ awi_pcmcia_find (psc, pa, cfe) struct awi_softc *sc = &psc->sc_awi; int fail = 0; u_int8_t version[AWI_BANNER_LEN]; - + /* * see if we can read the firmware version sanely * through the i/o ports. * if not, try a different CIS string.. */ if (pcmcia_io_alloc(psc->sc_pf, cfe->iospace[0].start, - cfe->iospace[0].length, 0, &psc->sc_pcioh) != 0) + cfe->iospace[0].length, AM79C930_IO_ALIGN, + &psc->sc_pcioh) != 0) goto fail; - + if (pcmcia_io_map(psc->sc_pf, PCMCIA_WIDTH_AUTO, 0, psc->sc_pcioh.size, &psc->sc_pcioh, &psc->sc_io_window)) goto fail_io_free; /* Enable the card. */ pcmcia_function_init(psc->sc_pf, cfe); - if (pcmcia_function_enable(psc->sc_pf)) + if (pcmcia_function_enable(psc->sc_pf)) goto fail_io_unmap; - + + sc->sc_chip.sc_bustype = AM79C930_BUS_PCMCIA; sc->sc_chip.sc_iot = psc->sc_pcioh.iot; sc->sc_chip.sc_ioh = psc->sc_pcioh.ioh; am79c930_chip_init(&sc->sc_chip, 0); DELAY(1000); - awi_read_bytes (sc, AWI_BANNER, version, AWI_BANNER_LEN); + awi_read_bytes(sc, AWI_BANNER, version, AWI_BANNER_LEN); if (memcmp(version, "PCnetMobile:", 12) == 0) - return 0; - + return (0); + fail++; - pcmcia_function_disable (psc->sc_pf); - + pcmcia_function_disable(psc->sc_pf); + fail_io_unmap: fail++; - pcmcia_io_unmap (psc->sc_pf, psc->sc_io_window); - + pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window); + fail_io_free: fail++; - pcmcia_io_free (psc->sc_pf, &psc->sc_pcioh); + pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); fail: fail++; - return fail; + psc->sc_io_window = -1; + return (fail); } - - -void +static void awi_pcmcia_attach(parent, self, aux) struct device *parent, *self; void *aux; { - struct awi_pcmcia_softc *psc = (void *) self; + struct awi_pcmcia_softc *psc = (void *)self; struct awi_softc *sc = &psc->sc_awi; + struct awi_pcmcia_product *app; struct pcmcia_attach_args *pa = aux; struct pcmcia_config_entry *cfe; - struct awi_pcmcia_get_enaddr_args pgea; -#if 0 - struct pcmcia_mem_handle memh; bus_addr_t memoff; - int memwin; -#endif -#if 0 - int i, j; - - for (cfe = pa->pf->cfe_head.sqh_first, i=0; - cfe != NULL; - cfe = cfe->cfe_list.sqe_next, i++) { - printf("%d: %d memspaces, %d iospaces\n", - i, cfe->num_memspace, cfe->num_iospace); - printf("%d: number %d flags %x iftype %d iomask %lx irqmask %x maxtwins %x\n", - i, cfe->number, cfe->flags, cfe->iftype, cfe->iomask, - cfe->irqmask, cfe->maxtwins); - for (j=0; j<cfe->num_memspace; j++) { - printf("%d: mem %d: len %lx card %lx host %lx\n", - i, j, - cfe->memspace[j].length, - cfe->memspace[j].cardaddr, - cfe->memspace[j].hostaddr); - } - for (j=0; j<cfe->num_iospace; j++) { - printf("%d: io %d: len %lx start %lx\n", - i, j, - cfe->iospace[j].length, - cfe->iospace[j].start); - } - } -#endif + app = awi_pcmcia_lookup(pa); + if (app == NULL) + panic("awi_pcmcia_attach: impossible"); psc->sc_pf = pa->pf; @@ -295,122 +312,116 @@ awi_pcmcia_attach(parent, self, aux) } if (cfe == NULL) { printf(": no suitable CIS info found\n"); - return; + goto no_config_entry; } sc->sc_enabled = 1; - sc->sc_state = AWI_ST_SELFTEST; - printf(": BayStack 650 Wireless (802.11)\n"); + printf(": %s\n", app->app_name); -#if 0 - if (pcmcia_mem_alloc(psc->sc_pf, AM79C930_MEM_SIZE, &memh) != 0) { + psc->sc_mem_window = -1; + if (pcmcia_mem_alloc(psc->sc_pf, AM79C930_MEM_SIZE, + &psc->sc_memh) != 0) { printf("%s: unable to allocate memory space; using i/o only\n", sc->sc_dev.dv_xname); - } else if (pcmcia_mem_map(psc->sc_pf, PCMCIA_MEM_COMMON, - AM79C930_MEM_BASE, AM79C930_MEM_SIZE, - &memh, &memoff, &memwin)) { + } else if (pcmcia_mem_map(psc->sc_pf, + PCMCIA_MEM_COMMON, AM79C930_MEM_BASE, + AM79C930_MEM_SIZE, &psc->sc_memh, &memoff, &psc->sc_mem_window)) { printf("%s: unable to map memory space; using i/o only\n", sc->sc_dev.dv_xname); - pcmcia_mem_free(psc->sc_pf, &memh); + pcmcia_mem_free(psc->sc_pf, &psc->sc_memh); } else { - sc->sc_chip.sc_memt = memh.memt; - sc->sc_chip.sc_memh = memh.memh; + sc->sc_chip.sc_memt = psc->sc_memh.memt; + sc->sc_chip.sc_memh = psc->sc_memh.memh; am79c930_chip_init(&sc->sc_chip, 1); } -#endif - sc->sc_chip.sc_bustype = AM79C930_BUS_PCMCIA; - sc->sc_enable = awi_pcmcia_enable; sc->sc_disable = awi_pcmcia_disable; - /* Read station address. */ - pgea.got_enaddr = 0; - if (pcmcia_scan_cis(parent, awi_pcmcia_get_enaddr, &pgea) == -1) { - printf("%s: Couldn't read CIS to get ethernet address\n", - sc->sc_dev.dv_xname); - return; - } else if (!pgea.got_enaddr) { - printf("%s: Couldn't get ethernet address from CIS\n", + /* establish the interrupt. */ + sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, awi_intr, sc); + if (sc->sc_ih == NULL) { + printf("%s: couldn't establish interrupt\n", sc->sc_dev.dv_xname); - return; - } else -#ifdef DIAGNOSTIC - printf("%s: Ethernet address from CIS: %s\n", - sc->sc_dev.dv_xname, ether_sprintf(pgea.enaddr)) -#endif - ; + goto no_interrupt; + } + sc->sc_ifp = &sc->sc_ec.ac_if; + sc->sc_cansleep = 1; - awi_attach(sc, pgea.enaddr); + if (awi_attach(sc) != 0) { + printf("%s: failed to attach controller\n", + sc->sc_dev.dv_xname); + goto attach_failed; + } + psc->sc_powerhook = powerhook_establish(awi_pcmcia_powerhook, psc); -#ifndef NETBSD_ORIGINAL - awi_init(sc); - awi_stop(sc); -#endif + sc->sc_enabled = 0; + /* disable device and disestablish the interrupt */ + awi_pcmcia_disable(sc); + return; + + attach_failed: + pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih); + + no_interrupt: + /* Unmap our memory window and space */ + if (psc->sc_mem_window != -1) { + pcmcia_mem_unmap(psc->sc_pf, psc->sc_mem_window); + pcmcia_mem_free(psc->sc_pf, &psc->sc_memh); + } -#ifdef notyet /* NETBSD_ORIGINAL */ - sc->sc_state = AWI_ST_OFF; + /* Unmap our i/o window and space */ + pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window); + pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); - sc->sc_enabled = 0; - /* - * XXX This should be done once the framework has enable/disable hooks. - */ + /* Disable the function */ pcmcia_function_disable(psc->sc_pf); -#endif /* notyet */ + + no_config_entry: + psc->sc_io_window = -1; } -int +static int awi_pcmcia_detach(self, flags) struct device *self; int flags; { struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *)self; + int error; + + if (psc->sc_io_window == -1) + /* Nothing to detach. */ + return (0); + + if (psc->sc_powerhook != NULL) + powerhook_disestablish(psc->sc_powerhook); + + error = awi_detach(&psc->sc_awi); + if (error != 0) + return (error); + + /* Unmap our memory window and free memory space */ + if (psc->sc_mem_window != -1) { + pcmcia_mem_unmap(psc->sc_pf, psc->sc_mem_window); + pcmcia_mem_free(psc->sc_pf, &psc->sc_memh); + } /* Unmap our i/o window. */ pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window); /* Free our i/o space. */ pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); - -#ifdef notyet - /* - * Our softc is about to go away, so drop our reference - * to the ifnet. - */ - if_delref(psc->sc_awi.sc_ethercom.ec_if); return (0); -#else - return (EBUSY); -#endif } -/* - * XXX copied verbatim from if_mbe_pcmcia.c. - * this function should be in common pcmcia code.. - */ - -int -awi_pcmcia_get_enaddr(tuple, arg) - struct pcmcia_tuple *tuple; +static void +awi_pcmcia_powerhook(why, arg) + int why; void *arg; { - struct awi_pcmcia_get_enaddr_args *p = arg; - int i; - - if (tuple->code == PCMCIA_CISTPL_FUNCE) { - if (tuple->length < 2) /* sub code and ether addr length */ - return (0); - - if ((pcmcia_tuple_read_1(tuple, 0) != - PCMCIA_TPLFE_TYPE_LAN_NID) || - (pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN)) - return (0); + struct awi_pcmcia_softc *psc = arg; + struct awi_softc *sc = &psc->sc_awi; - for (i = 0; i < ETHER_ADDR_LEN; i++) - p->enaddr[i] = pcmcia_tuple_read_1(tuple, i + 2); - p->got_enaddr = 1; - return (1); - } - return (0); + awi_power(sc, why); } |