From d148e81e76fda3dc7f606d21a9633685fb48bd26 Mon Sep 17 00:00:00 2001 From: Atsushi Onoe Date: Thu, 15 Jan 2004 10:04:21 +0000 Subject: [PATCH] Use generic net80211 framework for awi driver. Restore awi to be workable again; it was broken.. XXX: The initialization is still unreliable yet, it sometimes fails on some card. --- sys/conf/files | 3 - sys/dev/awi/am79c930.c | 153 +- sys/dev/awi/am79c930reg.h | 4 +- sys/dev/awi/am79c930var.h | 2 +- sys/dev/awi/awi.c | 3729 ++++++++++++++--------------------- sys/dev/awi/awi_wep.c | 533 ----- sys/dev/awi/awi_wicfg.c | 634 ------ sys/dev/awi/awireg.h | 116 +- sys/dev/awi/awivar.h | 188 +- sys/dev/awi/if_awi_pccard.c | 129 +- sys/modules/awi/Makefile | 2 +- 11 files changed, 1706 insertions(+), 3787 deletions(-) delete mode 100644 sys/dev/awi/awi_wep.c delete mode 100644 sys/dev/awi/awi_wicfg.c diff --git a/sys/conf/files b/sys/conf/files index d134dd402537..b57cfdfb4c32 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -324,8 +324,6 @@ dev/ath/if_ath_pci.c optional ath pci dev/ath/if_ath_pci.c optional ath card dev/awi/am79c930.c optional awi dev/awi/awi.c optional awi -dev/awi/awi_wep.c optional awi -dev/awi/awi_wicfg.c optional awi dev/awi/if_awi_pccard.c optional awi card dev/awi/if_awi_pccard.c optional awi pccard dev/bfe/if_bfe.c optional bfe @@ -1404,7 +1402,6 @@ netgraph/ng_lmi.c optional netgraph_lmi netgraph/ng_l2tp.c optional netgraph_l2tp netgraph/ng_mppc.c optional netgraph_mppc_compression netgraph/ng_mppc.c optional netgraph_mppc_encryption -crypto/rc4/rc4.c optional awi crypto/rc4/rc4.c optional wlan crypto/rc4/rc4.c optional netgraph_mppc_encryption crypto/sha1.c optional netgraph_mppc_encryption diff --git a/sys/dev/awi/am79c930.c b/sys/dev/awi/am79c930.c index 3bf5c9e29bda..90f85c0b1acf 100644 --- a/sys/dev/awi/am79c930.c +++ b/sys/dev/awi/am79c930.c @@ -1,4 +1,5 @@ -/* $NetBSD: am79c930.c,v 1.5 2000/03/23 13:57:58 onoe Exp $ */ +/* $NetBSD: am79c930.c,v 1.9 2004/01/15 09:33:48 onoe Exp $ */ + /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. * All rights reserved. @@ -35,9 +36,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include -__FBSDID("$FreeBSD$"); - /* * Am79c930 chip driver. * @@ -62,8 +60,17 @@ __FBSDID("$FreeBSD$"); * end isr */ +#include +#ifdef __NetBSD__ +__KERNEL_RCSID(0, "$NetBSD: am79c930.c,v 1.9 2004/01/15 09:33:48 onoe Exp $"); +#endif +#ifdef __FreeBSD__ +__FBSDID("$FreeBSD$"); +#endif + #include #include +#include #ifndef __FreeBSD__ #include #endif @@ -133,10 +140,8 @@ struct am79c930_ops memspace_ops = { mem_read_bytes }; -static void io_write_1 (sc, off, val) - struct am79c930_softc *sc; - u_int32_t off; - u_int8_t val; +static void +io_write_1( struct am79c930_softc *sc, u_int32_t off, u_int8_t val) { AM930_DELAY(1); bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, @@ -148,10 +153,8 @@ static void io_write_1 (sc, off, val) AM930_DELAY(1); } -static void io_write_2 (sc, off, val) - struct am79c930_softc *sc; - u_int32_t off; - u_int16_t val; +static void +io_write_2(struct am79c930_softc *sc, u_int32_t off, u_int16_t val) { AM930_DELAY(1); bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, @@ -165,10 +168,8 @@ static void io_write_2 (sc, off, val) AM930_DELAY(1); } -static void io_write_4 (sc, off, val) - struct am79c930_softc *sc; - u_int32_t off; - u_int32_t val; +static void +io_write_4(struct am79c930_softc *sc, u_int32_t off, u_int32_t val) { AM930_DELAY(1); bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, @@ -186,11 +187,9 @@ static void io_write_4 (sc, off, val) AM930_DELAY(1); } -static void io_write_bytes (sc, off, ptr, len) - struct am79c930_softc *sc; - u_int32_t off; - u_int8_t *ptr; - size_t len; +static void +io_write_bytes(struct am79c930_softc *sc, u_int32_t off, u_int8_t *ptr, + size_t len) { int i; @@ -204,12 +203,11 @@ static void io_write_bytes (sc, off, ptr, len) bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA,ptr[i]); } -static u_int8_t io_read_1 (sc, off) - struct am79c930_softc *sc; - u_int32_t off; +static u_int8_t +io_read_1(struct am79c930_softc *sc, u_int32_t off) { u_int8_t val; - + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, ((off>>8)& 0x7f)); AM930_DELAY(1); @@ -220,9 +218,8 @@ static u_int8_t io_read_1 (sc, off) return val; } -static u_int16_t io_read_2 (sc, off) - struct am79c930_softc *sc; - u_int32_t off; +static u_int16_t +io_read_2(struct am79c930_softc *sc, u_int32_t off) { u_int16_t val; @@ -238,9 +235,8 @@ static u_int16_t io_read_2 (sc, off) return val; } -static u_int32_t io_read_4 (sc, off) - struct am79c930_softc *sc; - u_int32_t off; +static u_int32_t +io_read_4(struct am79c930_softc *sc, u_int32_t off) { u_int32_t val; @@ -260,11 +256,9 @@ static u_int32_t io_read_4 (sc, off) return val; } -static void io_read_bytes (sc, off, ptr, len) - struct am79c930_softc *sc; - u_int32_t off; - u_int8_t *ptr; - size_t len; +static void +io_read_bytes(struct am79c930_softc *sc, u_int32_t off, u_int8_t *ptr, + size_t len) { int i; @@ -278,42 +272,36 @@ static void io_read_bytes (sc, off, ptr, len) AM79C930_IODPA); } -static void mem_write_1 (sc, off, val) - struct am79c930_softc *sc; - u_int32_t off; - u_int8_t val; +static void +mem_write_1(struct am79c930_softc *sc, u_int32_t off, u_int8_t val) { bus_space_write_1(sc->sc_memt, sc->sc_memh, off, val); } -static void mem_write_2 (sc, off, val) - struct am79c930_softc *sc; - u_int32_t off; - u_int16_t val; +static +void mem_write_2(struct am79c930_softc *sc, u_int32_t off, u_int16_t val) { 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); + bus_space_write_2(t, h, off, htole16(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) - struct am79c930_softc *sc; - u_int32_t off; - u_int32_t val; +static void +mem_write_4(struct am79c930_softc *sc, u_int32_t off, u_int32_t val) { 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); + bus_space_write_4(t, h, off, htole32(val)); else { bus_space_write_1(t, h, off, val & 0xff); bus_space_write_1(t, h, off+1, (val >> 8) & 0xff); @@ -322,43 +310,37 @@ static void mem_write_4 (sc, off, val) } } -static void mem_write_bytes (sc, off, ptr, len) - struct am79c930_softc *sc; - u_int32_t off; - u_int8_t *ptr; - size_t len; +static void +mem_write_bytes(struct am79c930_softc *sc, u_int32_t off, u_int8_t *ptr, + size_t len) { bus_space_write_region_1 (sc->sc_memt, sc->sc_memh, off, ptr, len); } - -static u_int8_t mem_read_1 (sc, off) - struct am79c930_softc *sc; - u_int32_t off; +static u_int8_t +mem_read_1(struct am79c930_softc *sc, u_int32_t off) { return bus_space_read_1(sc->sc_memt, sc->sc_memh, off); } -static u_int16_t mem_read_2 (sc, off) - struct am79c930_softc *sc; - u_int32_t off; +static u_int16_t +mem_read_2(struct am79c930_softc *sc, u_int32_t off) { /* could be unaligned */ if ((off & 0x1) == 0) - return bus_space_read_2(sc->sc_memt, sc->sc_memh, off); + return le16toh(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; +static u_int32_t +mem_read_4(struct am79c930_softc *sc, u_int32_t off) { /* could be unaligned */ if ((off & 0x3) == 0) - return bus_space_read_4(sc->sc_memt, sc->sc_memh, off); + return le32toh(bus_space_read_4(sc->sc_memt, sc->sc_memh, off)); else return bus_space_read_1(sc->sc_memt, sc->sc_memh, off ) | @@ -367,27 +349,20 @@ static u_int32_t mem_read_4 (sc, off) (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+3) <<24); } - - -static void mem_read_bytes (sc, off, ptr, len) - struct am79c930_softc *sc; - u_int32_t off; - u_int8_t *ptr; - size_t len; +static void +mem_read_bytes(struct am79c930_softc *sc, u_int32_t off, u_int8_t *ptr, + size_t len) { bus_space_read_region_1 (sc->sc_memt, sc->sc_memh, off, ptr, len); } - - /* * Set bits in GCR. */ -void am79c930_gcr_setbits (sc, bits) - struct am79c930_softc *sc; - u_int8_t bits; +void +am79c930_gcr_setbits(struct am79c930_softc *sc, u_int8_t bits) { u_int8_t gcr = bus_space_read_1 (sc->sc_iot, sc->sc_ioh, AM79C930_GCR); @@ -400,9 +375,8 @@ void am79c930_gcr_setbits (sc, bits) * Clear bits in GCR. */ -void am79c930_gcr_clearbits (sc, bits) - struct am79c930_softc *sc; - u_int8_t bits; +void +am79c930_gcr_clearbits(struct am79c930_softc *sc, u_int8_t bits) { u_int8_t gcr = bus_space_read_1 (sc->sc_iot, sc->sc_ioh, AM79C930_GCR); @@ -411,15 +385,15 @@ void am79c930_gcr_clearbits (sc, bits) bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_GCR, gcr); } -u_int8_t am79c930_gcr_read (sc) - struct am79c930_softc *sc; +u_int8_t +am79c930_gcr_read(struct am79c930_softc *sc) { return bus_space_read_1 (sc->sc_iot, sc->sc_ioh, AM79C930_GCR); } #if 0 -void am79c930_regdump (sc) - struct am79c930_softc *sc; +void +am79c930_regdump(struct am79c930_softc *sc) { u_int8_t buf[8]; int i; @@ -437,9 +411,8 @@ void am79c930_regdump (sc) } #endif -void am79c930_chip_init (sc, how) - struct am79c930_softc *sc; - int how; +void +am79c930_chip_init(struct am79c930_softc *sc, int how) { /* zero the bank select register, and leave it that way.. */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_BSS, 0); @@ -448,5 +421,3 @@ void am79c930_chip_init (sc, how) else sc->sc_ops = &iospace_ops; } - - diff --git a/sys/dev/awi/am79c930reg.h b/sys/dev/awi/am79c930reg.h index 64b3e239fab1..74d38bf38b37 100644 --- a/sys/dev/awi/am79c930reg.h +++ b/sys/dev/awi/am79c930reg.h @@ -1,4 +1,4 @@ -/* $NetBSD: am79c930reg.h,v 1.3 2000/03/22 11:22:22 onoe Exp $ */ +/* $NetBSD: am79c930reg.h,v 1.4 2003/11/02 11:07:45 wiz Exp $ */ /* $FreeBSD$ */ /*- @@ -99,7 +99,7 @@ #define AM79C930_LMA_HI_ISAPWRDWN 0x80 /* - * mmm, inconsistancy in chip documentation: + * mmm, inconsistency 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 diff --git a/sys/dev/awi/am79c930var.h b/sys/dev/awi/am79c930var.h index 087ae1a6f70a..3836521f1e29 100644 --- a/sys/dev/awi/am79c930var.h +++ b/sys/dev/awi/am79c930var.h @@ -1,4 +1,4 @@ -/* $NetBSD$ */ +/* $NetBSD: am79c930var.h,v 1.3 2004/01/15 09:33:48 onoe Exp $ */ /* $FreeBSD$ */ /*- diff --git a/sys/dev/awi/awi.c b/sys/dev/awi/awi.c index bf1e7b5234f6..7d9413c903a7 100644 --- a/sys/dev/awi/awi.c +++ b/sys/dev/awi/awi.c @@ -1,6 +1,7 @@ -/* $NetBSD: awi.c,v 1.26 2000/07/21 04:48:55 onoe Exp $ */ +/* $NetBSD: awi.c,v 1.60 2004/01/15 09:39:15 onoe Exp $ */ + /*- - * Copyright (c) 1999 The NetBSD Foundation, Inc. + * Copyright (c) 1999,2000,2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -34,20 +35,13 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ - -#include -__FBSDID("$FreeBSD$"); - /* - * Driver for AMD 802.11 PCnetMobile firmware. + * Driver for AMD 802.11 firmware. * Uses am79c930 chip driver to talk to firmware running on the am79c930. - * More-or-less a generic ethernet-like if driver, with 802.11 gorp added. * - * The initial version of the driver was written by - * Bill Sommerfeld . - * Then the driver module completely rewritten to support cards with DS phy - * and to support adhoc mode by Atsushi Onoe + * More-or-less a generic ethernet-like if driver, with 802.11 gorp added. */ + /* * todo: * - flush tx queue on resynch. @@ -80,68 +74,72 @@ __FBSDID("$FreeBSD$"); * - 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 . + * Then the driver module completely rewritten to support cards with DS phy + * and to support adhoc mode by Atsushi Onoe + */ + +#include +#ifdef __NetBSD__ +__KERNEL_RCSID(0, "$NetBSD: awi.c,v 1.60 2004/01/15 09:39:15 onoe Exp $"); +#endif +#ifdef __FreeBSD__ +__FBSDID("$FreeBSD$"); +#endif + #include "opt_inet.h" +#ifdef __NetBSD__ +#include "bpfilter.h" +#endif +#ifdef __FreeBSD__ +#define NBPFILTER 1 +#endif #include #include #include #include -#include #include +#include #include #include #include -#include -#if defined(__FreeBSD__) && __FreeBSD_version >= 400000 +#include +#ifdef __FreeBSD__ #include -#else +#endif +#ifdef __NetBSD__ #include #endif #include #include +#ifdef __NetBSD__ +#include +#endif #ifdef __FreeBSD__ #include -#else -#include +#include #endif #include #include -#ifdef INET -#include -#include -#include -#include -#ifdef __NetBSD__ -#include -#else -#include -#endif -#endif - #include -#include - -#if defined(__FreeBSD__) && __FreeBSD_version >= 400000 -#define NBPFILTER 1 -#elif defined(__FreeBSD__) && __FreeBSD_version >= 300000 -#include "bpf.h" -#define NBPFILTER NBPF -#else -#include "bpfilter.h" +#ifdef __NetBSD__ +#include #endif #if NBPFILTER > 0 #include -#include #endif #include #include -#ifdef __NetBSD__ -#include -#endif #ifdef __NetBSD__ #include @@ -156,93 +154,79 @@ __FBSDID("$FreeBSD$"); #include #endif -static int awi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); -#ifdef IFM_IEEE80211 -static int awi_media_rate2opt(struct awi_softc *sc, int rate); -static int awi_media_opt2rate(struct awi_softc *sc, int opt); -static int awi_media_change(struct ifnet *ifp); -static void awi_media_status(struct ifnet *ifp, struct ifmediareq *imr); -#endif -static void awi_watchdog(struct ifnet *ifp); -static void awi_start(struct ifnet *ifp); -static void awi_txint(struct awi_softc *sc); -static struct mbuf * awi_fix_txhdr(struct awi_softc *sc, struct mbuf *m0); -static struct mbuf * awi_fix_rxhdr(struct awi_softc *sc, struct mbuf *m0); -static void awi_input(struct awi_softc *sc, struct mbuf *m, u_int32_t rxts, u_int8_t rssi); -static void awi_rxint(struct awi_softc *sc); -static struct mbuf * awi_devget(struct awi_softc *sc, u_int32_t off, u_int16_t len); -static int awi_init_hw(struct awi_softc *sc); -static int awi_init_mibs(struct awi_softc *sc); -static int awi_init_txrx(struct awi_softc *sc); -static void awi_stop_txrx(struct awi_softc *sc); -static int awi_start_scan(struct awi_softc *sc); -static int awi_next_scan(struct awi_softc *sc); -static void awi_stop_scan(struct awi_softc *sc); -static void awi_recv_beacon(struct awi_softc *sc, struct mbuf *m0, u_int32_t rxts, u_int8_t rssi); -static int awi_set_ss(struct awi_softc *sc); -static void awi_try_sync(struct awi_softc *sc); -static void awi_sync_done(struct awi_softc *sc); -static void awi_send_deauth(struct awi_softc *sc); -static void awi_send_auth(struct awi_softc *sc, int seq); -static void awi_recv_auth(struct awi_softc *sc, struct mbuf *m0); -static void awi_send_asreq(struct awi_softc *sc, int reassoc); -static void awi_recv_asresp(struct awi_softc *sc, struct mbuf *m0); -static int awi_mib(struct awi_softc *sc, u_int8_t cmd, u_int8_t mib); -static int awi_cmd_scan(struct awi_softc *sc); -static int awi_cmd(struct awi_softc *sc, u_int8_t cmd); -static void awi_cmd_done(struct awi_softc *sc); -static int awi_next_txd(struct awi_softc *sc, int len, u_int32_t *framep, u_int32_t*ntxdp); -static int awi_lock(struct awi_softc *sc); -static void awi_unlock(struct awi_softc *sc); -static int awi_intr_lock(struct awi_softc *sc); -static void awi_intr_unlock(struct awi_softc *sc); -static int awi_cmd_wait(struct awi_softc *sc); -static void awi_print_essid(u_int8_t *essid); - -#ifdef AWI_DEBUG -static void awi_dump_pkt(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 - -#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_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) +static void awi_init0(void *); #endif +static int awi_init(struct ifnet *); +static void awi_stop(struct ifnet *, int); +static void awi_start(struct ifnet *); +static void awi_watchdog(struct ifnet *); +static int awi_ioctl(struct ifnet *, u_long, caddr_t); +static int awi_media_change(struct ifnet *); +static void awi_media_status(struct ifnet *, struct ifmediareq *); +static int awi_mode_init(struct awi_softc *); +static void awi_rx_int(struct awi_softc *); +static void awi_tx_int(struct awi_softc *); +static struct mbuf *awi_devget(struct awi_softc *, u_int32_t, u_int16_t); +static int awi_hw_init(struct awi_softc *); +static int awi_init_mibs(struct awi_softc *); +static int awi_mib(struct awi_softc *, u_int8_t, u_int8_t, int); +static int awi_cmd(struct awi_softc *, u_int8_t, int); +static int awi_cmd_wait(struct awi_softc *); +static void awi_cmd_done(struct awi_softc *); +static int awi_next_txd(struct awi_softc *, int, u_int32_t *, u_int32_t *); +static int awi_lock(struct awi_softc *); +static void awi_unlock(struct awi_softc *); +static int awi_intr_lock(struct awi_softc *); +static void awi_intr_unlock(struct awi_softc *); +static int awi_newstate(struct ieee80211com *, enum ieee80211_state, int); +static void awi_recv_mgmt(struct ieee80211com *, struct mbuf *, + struct ieee80211_node *, int, int, u_int32_t); +static int awi_send_mgmt(struct ieee80211com *, struct ieee80211_node *, int, + int); +static struct mbuf *awi_ether_encap(struct awi_softc *, struct mbuf *); +static struct mbuf *awi_ether_modcap(struct awi_softc *, struct mbuf *); -#ifndef llc_snap -#define llc_snap llc_un.type_snap -#endif +/* unaligned 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))) + +struct awi_chanset awi_chanset[] = { + /* PHY type domain min max def */ + { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_JP, 6, 17, 6 }, + { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_ES, 0, 26, 1 }, + { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_FR, 0, 32, 1 }, + { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_US, 0, 77, 1 }, + { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_CA, 0, 77, 1 }, + { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_EU, 0, 77, 1 }, + { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_JP, 14, 14, 14 }, + { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_ES, 10, 11, 10 }, + { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_FR, 10, 13, 10 }, + { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_US, 1, 11, 3 }, + { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_CA, 1, 11, 3 }, + { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_EU, 1, 13, 3 }, + { 0, 0 } +}; #ifdef __FreeBSD__ -#if __FreeBSD_version >= 400000 devclass_t awi_devclass; -#endif #if __FreeBSD_version < 500043 -/* NetBSD compatible functions */ -static char * ether_sprintf(u_int8_t *); +static char *ether_sprintf(u_int8_t *); static char * -ether_sprintf(enaddr) - u_int8_t *enaddr; +ether_sprintf(u_int8_t *enaddr) { static char strbuf[18]; @@ -250,152 +234,171 @@ ether_sprintf(enaddr) return strbuf; } #endif + +#define IFQ_PURGE(ifq) IF_DRAIN(ifq) +#define IF_POLL(ifq, m) ((m) = (ifq)->ifq_head) +#define IFQ_POLL(ifq, m) IF_POLL((ifq), (m)) +#define IFQ_DEQUEUE(ifq, m) IF_DEQUEUE((ifq), (m)) + +#endif + +#ifdef AWI_DEBUG +int awi_debug = 0; + +#define DPRINTF(X) if (awi_debug) printf X +#define DPRINTF2(X) if (awi_debug > 1) printf X +#else +#define DPRINTF(X) +#define DPRINTF2(X) #endif int -awi_attach(sc) - struct awi_softc *sc; +awi_attach(struct awi_softc *sc) { - struct ifnet *ifp = sc->sc_ifp; - int s; - int error; -#ifdef IFM_IEEE80211 - int i; - u_int8_t *phy_rates; + struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = &ic->ic_if; + int s, i, error, nrate; int mword; - struct ifmediareq imr; -#endif + enum ieee80211_phymode mode; 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_attached = 0; + sc->sc_substate = AWI_ST_NONE; + if ((error = awi_hw_init(sc)) != 0) { sc->sc_invalid = 1; splx(s); return error; } error = awi_init_mibs(sc); - splx(s); - if (error) { + if (error != 0) { sc->sc_invalid = 1; + splx(s); return error; } - 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; + ifp->if_flags = #ifdef IFF_NOTRAILERS - ifp->if_flags |= IFF_NOTRAILERS; + IFF_NOTRAILERS | #endif + IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; + ifp->if_ioctl = awi_ioctl; + ifp->if_start = awi_start; + ifp->if_watchdog = awi_watchdog; #ifdef __NetBSD__ + ifp->if_init = awi_init; + ifp->if_stop = awi_stop; + IFQ_SET_READY(&ifp->if_snd); 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); + ifp->if_init = awi_init0; + ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; + if_initname(ifp, device_get_name(sc->sc_dev), + device_get_unit(sc->sc_dev)); #endif - 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)); -#ifdef __FreeBSD__ - ether_ifattach(ifp, sc->sc_mib_addr.aMAC_Address); -#else + ic->ic_caps = IEEE80211_C_WEP | IEEE80211_C_IBSS | IEEE80211_C_HOSTAP; + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { + ic->ic_phytype = IEEE80211_T_FH; + mode = IEEE80211_MODE_FH; + } else { + ic->ic_phytype = IEEE80211_T_DS; + ic->ic_caps |= IEEE80211_C_AHDEMO; + mode = IEEE80211_MODE_11B; + } + ic->ic_opmode = IEEE80211_M_STA; + nrate = sc->sc_mib_phy.aSuprt_Data_Rates[1]; + memcpy(ic->ic_sup_rates[mode].rs_rates, + sc->sc_mib_phy.aSuprt_Data_Rates + 2, nrate); + ic->ic_sup_rates[mode].rs_nrates = nrate; + IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_mib_addr.aMAC_Address); + + printf("%s: IEEE802.11 %s (firmware %s)\n", ifp->if_xname, + (ic->ic_phytype == IEEE80211_T_FH) ? "FH" : "DS", sc->sc_banner); + printf("%s: 802.11 address: %s\n", ifp->if_xname, + ether_sprintf(ic->ic_myaddr)); + +#ifdef __NetBSD__ if_attach(ifp); - 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 + ieee80211_ifattach(ifp); -#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])); + sc->sc_newstate = ic->ic_newstate; + ic->ic_newstate = awi_newstate; + + sc->sc_recv_mgmt = ic->ic_recv_mgmt; + ic->ic_recv_mgmt = awi_recv_mgmt; + + sc->sc_send_mgmt = ic->ic_send_mgmt; + ic->ic_send_mgmt = awi_send_mgmt; + + ieee80211_media_init(ifp, awi_media_change, awi_media_status); + + /* Melco compatibility mode. */ +#define ADD(s, o) ifmedia_add(&ic->ic_media, \ + IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL) + ADD(IFM_AUTO, IFM_FLAG0); + + for (i = 0; i < nrate; i++) { + mword = ieee80211_rate2media(ic, + ic->ic_sup_rates[mode].rs_rates[i], mode); 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); + ADD(mword, IFM_FLAG0); } - awi_media_status(ifp, &imr); - ifmedia_set(&sc->sc_media, imr.ifm_active); +#undef ADD + +#ifdef __NetBSD__ + if ((sc->sc_sdhook = shutdownhook_establish(awi_shutdown, sc)) == NULL) + printf("%s: WARNING: unable to establish shutdown hook\n", + ifp->if_xname); + if ((sc->sc_powerhook = powerhook_establish(awi_power, sc)) == NULL) + printf("%s: WARNING: unable to establish power hook\n", + ifp->if_xname); #endif + sc->sc_attached = 1; + splx(s); /* ready to accept ioctl */ awi_unlock(sc); - /* Attach is successful. */ - sc->sc_attached = 1; + return 0; +} + +int +awi_detach(struct awi_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ic.ic_if; + int s; + + if (!sc->sc_attached) + return 0; + + s = splnet(); + sc->sc_invalid = 1; + awi_stop(ifp, 1); + + while (sc->sc_sleep_cnt > 0) { + wakeup(sc); + (void)tsleep(sc, PWAIT, "awidet", 1); + } + ieee80211_ifdetach(ifp); +#ifdef __NetBSD__ + if_detach(ifp); + shutdownhook_disestablish(sc->sc_sdhook); + powerhook_disestablish(sc->sc_powerhook); +#endif + splx(s); return 0; } #ifdef __NetBSD__ int -awi_detach(sc) - struct awi_softc *sc; -{ - struct ifnet *ifp = sc->sc_ifp; - int s; - - /* Succeed if there is no work to do. */ - if (!sc->sc_attached) - return (0); - - s = splnet(); - sc->sc_invalid = 1; - awi_stop(sc); - while (sc->sc_sleep_cnt > 0) { - wakeup(sc); - (void)tsleep(sc, PWAIT, "awidet", 1); - } - 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; - } - splx(s); - return 0; -} - -int -awi_activate(self, act) - struct device *self; - enum devact act; +awi_activate(struct device *self, enum devact act) { struct awi_softc *sc = (struct awi_softc *)self; + struct ifnet *ifp = &sc->sc_ic.ic_if; int s, error = 0; s = splnet(); @@ -403,504 +406,79 @@ awi_activate(self, act) case DVACT_ACTIVATE: error = EOPNOTSUPP; break; - case DVACT_DEACTIVATE: sc->sc_invalid = 1; - if (sc->sc_ifp) - if_deactivate(sc->sc_ifp); + if_deactivate(ifp); break; } splx(s); - return error; } void -awi_power(sc, why) - struct awi_softc *sc; - int why; +awi_power(int why, void *arg) { + struct awi_softc *sc = arg; + struct ifnet *ifp = &sc->sc_ic.ic_if; int s; int ocansleep; - if (!sc->sc_enabled) - return; - + DPRINTF(("awi_power: %d\n", why)); 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); + switch (why) { + case PWR_SUSPEND: + case PWR_STANDBY: + awi_stop(ifp, 1); + break; + case PWR_RESUME: + if (ifp->if_flags & IFF_UP) { + awi_init(ifp); + (void)awi_intr(sc); /* make sure */ + } + break; + case PWR_SOFTSUSPEND: + case PWR_SOFTSTANDBY: + case PWR_SOFTRESUME: + break; } -#endif sc->sc_cansleep = ocansleep; splx(s); } #endif /* __NetBSD__ */ -static int -awi_ioctl(ifp, cmd, data) - struct ifnet *ifp; - u_long cmd; - caddr_t data; +void +awi_shutdown(void *arg) { - struct awi_softc *sc = ifp->if_softc; - struct ifreq *ifr = (struct ifreq *)data; - struct ifaddr *ifa = (struct ifaddr *)data; - struct ieee80211req *ireq = (struct ieee80211req *)data; - int s, error; -#ifdef SIOCS80211NWID - struct ieee80211_nwid nwid; -#endif - u_int8_t *p; - int len; - u_int8_t tmpstr[IEEE80211_NWID_LEN*2]; -#ifdef __FreeBSD_version -#if __FreeBSD_version < 500028 - struct proc *mythread = curproc; /* name a white lie */ -#else - struct thread *mythread = curthread; -#endif -#endif + struct awi_softc *sc = arg; + struct ifnet *ifp = &sc->sc_ic.ic_if; - s = splnet(); - - /* 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 - } - /* 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 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 - /* - * Do not rescan BSS. Rather, just reset multicast filter. - */ - if (error == ENETRESET) { - if (sc->sc_enabled) - error = awi_init(sc); - else - error = 0; - } - break; - case SIOCSIFMTU: - if (ifr->ifr_mtu > ETHERMTU) - error = EINVAL; - else - ifp->if_mtu = ifr->ifr_mtu; - break; -#ifdef SIOCS80211NWID - case SIOCS80211NWID: -#ifdef __FreeBSD__ - error = suser(mythread); - if (error) - break; -#endif - error = copyin(ifr->ifr_data, &nwid, sizeof(nwid)); - if (error) - break; - if (nwid.i_len > IEEE80211_NWID_LEN) { - error = EINVAL; - break; - } - 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 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; -#endif -#ifdef SIOCS80211NWKEY - case SIOCS80211NWKEY: -#ifdef __FreeBSD__ - error = suser(mythread); - if (error) - break; -#endif - error = awi_wep_setnwkey(sc, (struct ieee80211_nwkey *)data); - break; - case SIOCG80211NWKEY: - error = awi_wep_getnwkey(sc, (struct ieee80211_nwkey *)data); - break; -#endif -#ifdef IFM_IEEE80211 - case SIOCSIFMEDIA: - case SIOCGIFMEDIA: - error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); - break; -#endif -#ifdef __FreeBSD__ - case SIOCG80211: - switch(ireq->i_type) { - case IEEE80211_IOC_SSID: - if (ireq->i_val != -1 && ireq->i_val != 0) { - error = EINVAL; - break; - } - if (!sc->sc_mib_local.Network_Mode) - p = sc->sc_ownssid; - else if (ireq->i_val == -1 && - (ifp->if_flags & IFF_RUNNING)) - p = sc->sc_bss.essid; - else - p = sc->sc_mib_mac.aDesired_ESS_ID; - len = p[1]; - p += 2; - if (len > IEEE80211_NWID_LEN) { - error = EINVAL; - break; - } - if (len > 0) - error = copyout(p, ireq->i_data, len); - ireq->i_len = len; - break; - case IEEE80211_IOC_NUMSSIDS: - ireq->i_val = 1; - break; - case IEEE80211_IOC_WEP: - if (sc->sc_wep_algo != NULL) - ireq->i_val = IEEE80211_WEP_MIXED; - else - ireq->i_val = IEEE80211_WEP_OFF; - break; - case IEEE80211_IOC_WEPKEY: - if(ireq->i_val < 0 || ireq->i_val > 3) { - error = EINVAL; - break; - } - len = sizeof(tmpstr); - error = awi_wep_getkey(sc, ireq->i_val, tmpstr, &len); - if(error) - break; -#ifdef __FreeBSD__ - if (!suser(mythread)) - bzero(tmpstr, len); -#endif - ireq->i_len = len; - error = copyout(tmpstr, ireq->i_data, len); - break; - case IEEE80211_IOC_NUMWEPKEYS: - ireq->i_val = 4; - break; - case IEEE80211_IOC_WEPTXKEY: - ireq->i_val = sc->sc_wep_defkid; - break; - case IEEE80211_IOC_AUTHMODE: - ireq->i_val = IEEE80211_AUTH_OPEN; - break; - case IEEE80211_IOC_STATIONNAME: - /* not used anywhere */ - error = EINVAL; - break; - case IEEE80211_IOC_CHANNEL: - /* XXX: Handle FH cards */ - ireq->i_val = sc->sc_bss.chanset; - break; - case IEEE80211_IOC_POWERSAVE: - /* - * The powersave mode is not supported by the driver. - */ - ireq->i_val = IEEE80211_POWERSAVE_NOSUP; - break; - case IEEE80211_IOC_POWERSAVESLEEP: - error = EINVAL; - break; - default: - error = EINVAL; - break; - } - break; - case SIOCS80211: - error = suser(mythread); - if(error) - break; - switch(ireq->i_type) { - case IEEE80211_IOC_SSID: - if (ireq->i_val != 0 || - ireq->i_len > IEEE80211_NWID_LEN) { - error = EINVAL; - break; - } - bzero(tmpstr, AWI_ESS_ID_SIZE); - tmpstr[0] = IEEE80211_ELEMID_SSID; - tmpstr[1] = ireq->i_len; - error = copyin(ireq->i_data, tmpstr+2, ireq->i_len); - if(error) - break; - bcopy(tmpstr, sc->sc_mib_mac.aDesired_ESS_ID, - AWI_ESS_ID_SIZE); - bcopy(tmpstr, sc->sc_ownssid, AWI_ESS_ID_SIZE); - break; - case IEEE80211_IOC_WEP: - if(ireq->i_val == IEEE80211_WEP_OFF) - error = awi_wep_setalgo(sc, 0); - else - error = awi_wep_setalgo(sc, 1); - break; - case IEEE80211_IOC_WEPKEY: - if(ireq->i_val < 0 || ireq->i_val > 3 || - ireq->i_len > 13) { - error = EINVAL; - break; - } - error = copyin(ireq->i_data, tmpstr, ireq->i_len); - if(error) - break; - error = awi_wep_setkey(sc, ireq->i_val, tmpstr, - ireq->i_len); - break; - case IEEE80211_IOC_WEPTXKEY: - if(ireq->i_val < 0 || ireq->i_val > 3) { - error = EINVAL; - break; - } - sc->sc_wep_defkid = ireq->i_val; - break; - case IEEE80211_IOC_AUTHMODE: - if(ireq->i_val != IEEE80211_AUTH_OPEN) - error = EINVAL; - break; - case IEEE80211_IOC_STATIONNAME: - error = EPERM; - break; - case IEEE80211_IOC_CHANNEL: - if(ireq->i_val < sc->sc_scan_min || - ireq->i_val > sc->sc_scan_max) { - error = EINVAL; - break; - } - sc->sc_ownch = ireq->i_val; - break; - case IEEE80211_IOC_POWERSAVE: - if(ireq->i_val != IEEE80211_POWERSAVE_OFF) - error = EINVAL; - break; - case IEEE80211_IOC_POWERSAVESLEEP: - error = EINVAL; - break; - default: - error = EINVAL; - break; - } - /* Restart the card so the change takes effect */ - if(!error) { - if(sc->sc_enabled) { - awi_stop(sc); - error = awi_init(sc); - } - } - break; -#endif /* __FreeBSD__ */ - default: - error = awi_wicfg(ifp, cmd, data); - break; - } - awi_unlock(sc); - cantlock: - splx(s); - return error; + if (sc->sc_attached) + awi_stop(ifp, 1); } -#ifdef IFM_IEEE80211 -static int -awi_media_rate2opt(sc, rate) - struct awi_softc *sc; - int rate; -{ - int mword; - - 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 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; - } - return mword; -} - -static int -awi_media_opt2rate(sc, opt) - struct awi_softc *sc; - int opt; -{ - int rate; - - 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; - } - - 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 rate; -} - -/* - * Called from ifmedia_ioctl via awi_ioctl with lock obtained. - */ -static int -awi_media_change(ifp) - struct ifnet *ifp; -{ - 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; - } - if (i == phy_rates[1]) - return EINVAL; - } - 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; - } - if (sc->sc_enabled) { - awi_stop(sc); - error = awi_init(sc); - } - return error; -} - -static void -awi_media_status(ifp, imr) - struct ifnet *ifp; - struct ifmediareq *imr; -{ - struct awi_softc *sc = ifp->if_softc; - - 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; - } -} -#endif /* IFM_IEEE80211 */ - int -awi_intr(arg) - void *arg; +awi_intr(void *arg) { struct awi_softc *sc = arg; u_int16_t status; - int error, handled = 0, ocansleep; + int handled = 0, ocansleep; +#ifdef AWI_DEBUG + static const char *intname[] = { + "CMD", "RX", "TX", "SCAN_CMPLT", + "CFP_START", "DTIM", "CFP_ENDING", "GROGGY", + "TXDATA", "TXBCAST", "TXPS", "TXCF", + "TXMGT", "#13", "RXDATA", "RXMGT" + }; +#endif - if (!sc->sc_enabled || !sc->sc_enab_intr || sc->sc_invalid) + if (!sc->sc_enabled || !sc->sc_enab_intr || sc->sc_invalid) { + DPRINTF(("awi_intr: stray interrupt: " + "enabled %d enab_intr %d invalid %d\n", + sc->sc_enabled, sc->sc_enab_intr, sc->sc_invalid)); return 0; + } am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_DISPWDN | AM79C930_GCR_ECINT); @@ -909,8 +487,7 @@ awi_intr(arg) sc->sc_cansleep = 0; for (;;) { - error = awi_intr_lock(sc); - if (error) + if (awi_intr_lock(sc) != 0) break; status = awi_read_1(sc, AWI_INTSTAT); awi_write_1(sc, AWI_INTSTAT, 0); @@ -923,17 +500,30 @@ awi_intr(arg) status &= ~AWI_INT_CMD; /* make sure */ if (status == 0) break; +#ifdef AWI_DEBUG + if (awi_debug > 1) { + int i; + + printf("awi_intr: status 0x%04x", status); + for (i = 0; i < sizeof(intname)/sizeof(intname[0]); + i++) { + if (status & (1 << i)) + printf(" %s", intname[i]); + } + printf("\n"); + } +#endif handled = 1; if (status & AWI_INT_RX) - awi_rxint(sc); + awi_rx_int(sc); if (status & AWI_INT_TX) - awi_txint(sc); + awi_tx_int(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); + if (sc->sc_ic.ic_state == IEEE80211_S_SCAN && + sc->sc_substate == AWI_ST_NONE) + ieee80211_next_scan(&sc->sc_ic.ic_if); } } sc->sc_cansleep = ocansleep; @@ -942,13 +532,551 @@ awi_intr(arg) return handled; } -int -awi_init(sc) - struct awi_softc *sc; +#ifdef __FreeBSD__ +static void +awi_init0(void *arg) { - int error, ostatus; - int n; - struct ifnet *ifp = sc->sc_ifp; + struct awi_softc *sc = arg; + + (void)awi_init(&sc->sc_ic.ic_if); +} +#endif + +static int +awi_init(struct ifnet *ifp) +{ + struct awi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni = ic->ic_bss; + int error; + + DPRINTF(("awi_init: enabled=%d\n", sc->sc_enabled)); + if (sc->sc_enabled) { + awi_stop(ifp, 0); + } else { + if (sc->sc_enable) + (*sc->sc_enable)(sc); + sc->sc_enabled = 1; + if ((error = awi_hw_init(sc)) != 0) { + if (sc->sc_disable) + (*sc->sc_disable)(sc); + sc->sc_enabled = 0; + return error; + } + } + ic->ic_state = IEEE80211_S_INIT; + + ic->ic_flags &= ~IEEE80211_F_IBSSON; + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + sc->sc_mib_local.Network_Mode = 1; + sc->sc_mib_local.Acting_as_AP = 0; + break; + case IEEE80211_M_IBSS: + ic->ic_flags |= IEEE80211_F_IBSSON; + /* FALLTHRU */ + case IEEE80211_M_AHDEMO: + sc->sc_mib_local.Network_Mode = 0; + sc->sc_mib_local.Acting_as_AP = 0; + break; + case IEEE80211_M_HOSTAP: + sc->sc_mib_local.Network_Mode = 1; + sc->sc_mib_local.Acting_as_AP = 1; + break; + case IEEE80211_M_MONITOR: + return ENODEV; + } +#if 0 + IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl)); +#endif + 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] = ic->ic_des_esslen; + memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], ic->ic_des_essid, + ic->ic_des_esslen); + + if ((error = awi_mode_init(sc)) != 0) { + DPRINTF(("awi_init: awi_mode_init failed %d\n", error)); + awi_stop(ifp, 1); + return 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_CA_TX_DATA, sc->sc_txbase); + awi_write_4(sc, AWI_CA_TX_MGT, 0); + awi_write_4(sc, AWI_CA_TX_BCAST, 0); + awi_write_4(sc, AWI_CA_TX_PS, 0); + awi_write_4(sc, AWI_CA_TX_CF, 0); + if ((error = awi_cmd(sc, AWI_CMD_INIT_TX, AWI_WAIT)) != 0) { + DPRINTF(("awi_init: failed to start transmitter: %d\n", error)); + awi_stop(ifp, 1); + return error; + } + + /* start receiver */ + if ((error = awi_cmd(sc, AWI_CMD_INIT_RX, AWI_WAIT)) != 0) { + DPRINTF(("awi_init: failed to start receiver: %d\n", error)); + awi_stop(ifp, 1); + return error; + } + sc->sc_rxdoff = awi_read_4(sc, AWI_CA_IRX_DATA_DESC); + sc->sc_rxmoff = awi_read_4(sc, AWI_CA_IRX_PS_DESC); + + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + ic->ic_state = IEEE80211_S_INIT; + + if (ic->ic_opmode == IEEE80211_M_AHDEMO || + ic->ic_opmode == IEEE80211_M_HOSTAP) { + ni->ni_chan = ic->ic_ibss_chan; + ni->ni_intval = ic->ic_lintval; + ni->ni_rssi = 0; + ni->ni_rstamp = 0; + memset(ni->ni_tstamp, 0, sizeof(ni->ni_tstamp)); + ni->ni_rates = + ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; + IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr); + if (ic->ic_opmode == IEEE80211_M_HOSTAP) { + IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr); + ni->ni_esslen = ic->ic_des_esslen; + memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen); + ni->ni_capinfo = IEEE80211_CAPINFO_ESS; + if (ic->ic_phytype == IEEE80211_T_FH) { + ni->ni_fhdwell = 200; /* XXX */ + ni->ni_fhindex = 1; + } + } else { + ni->ni_capinfo = IEEE80211_CAPINFO_IBSS; + memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN); + ni->ni_esslen = 0; + } + if (ic->ic_flags & IEEE80211_F_WEPON) + ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY; + if (ic->ic_opmode != IEEE80211_M_AHDEMO) + ic->ic_flags |= IEEE80211_F_SIBSS; + ic->ic_state = IEEE80211_S_SCAN; /*XXX*/ + sc->sc_substate = AWI_ST_NONE; + ieee80211_new_state(ic, IEEE80211_S_RUN, -1); + } else { + /* XXX check sc->sc_cur_chan */ + ni->ni_chan = &ic->ic_channels[sc->sc_cur_chan]; + ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); + } + return 0; +} + +static void +awi_stop(struct ifnet *ifp, int disable) +{ + struct awi_softc *sc = ifp->if_softc; + + if (!sc->sc_enabled) + return; + + DPRINTF(("awi_stop(%d)\n", disable)); + + ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1); + + if (!sc->sc_invalid) { + if (sc->sc_cmd_inprog) + (void)awi_cmd_wait(sc); + (void)awi_cmd(sc, AWI_CMD_KILL_RX, AWI_WAIT); + sc->sc_cmd_inprog = AWI_CMD_FLUSH_TX; + awi_write_1(sc, AWI_CA_FTX_DATA, 1); + awi_write_1(sc, AWI_CA_FTX_MGT, 0); + awi_write_1(sc, AWI_CA_FTX_BCAST, 0); + awi_write_1(sc, AWI_CA_FTX_PS, 0); + awi_write_1(sc, AWI_CA_FTX_CF, 0); + (void)awi_cmd(sc, AWI_CMD_FLUSH_TX, AWI_WAIT); + } + ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); + ifp->if_timer = 0; + sc->sc_tx_timer = sc->sc_rx_timer = 0; + if (sc->sc_rxpend != NULL) { + m_freem(sc->sc_rxpend); + sc->sc_rxpend = NULL; + } + IFQ_PURGE(&ifp->if_snd); + + if (disable) { + if (!sc->sc_invalid) + am79c930_gcr_setbits(&sc->sc_chip, + AM79C930_GCR_CORESET); + if (sc->sc_disable) + (*sc->sc_disable)(sc); + sc->sc_enabled = 0; + } +} + +static void +awi_start(struct ifnet *ifp) +{ + struct awi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni; + struct ieee80211_frame *wh; + struct mbuf *m, *m0; + int len, dowep; + u_int32_t txd, frame, ntxd; + u_int8_t rate; + + if (!sc->sc_enabled || sc->sc_invalid) + return; + + for (;;) { + txd = sc->sc_txnext; + IF_POLL(&ic->ic_mgtq, m0); + dowep = 0; + if (m0 != NULL) { + len = m0->m_pkthdr.len; + if (awi_next_txd(sc, len, &frame, &ntxd)) { + ifp->if_flags |= IFF_OACTIVE; + break; + } + IF_DEQUEUE(&ic->ic_mgtq, m0); + } else { + if (ic->ic_state != IEEE80211_S_RUN) + break; + IFQ_POLL(&ifp->if_snd, m0); + if (m0 == NULL) + break; + /* + * Need to calculate the real length to determine + * if the transmit buffer has a room for the packet. + */ + len = m0->m_pkthdr.len + sizeof(struct ieee80211_frame); + if (!(ifp->if_flags & IFF_LINK0) && !sc->sc_adhoc_ap) + len += sizeof(struct llc) - + sizeof(struct ether_header); + if (ic->ic_flags & IEEE80211_F_WEPON) { + dowep = 1; + len += IEEE80211_WEP_IVLEN + + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; + } + if (awi_next_txd(sc, len, &frame, &ntxd)) { + ifp->if_flags |= IFF_OACTIVE; + break; + } + IFQ_DEQUEUE(&ifp->if_snd, m0); + ifp->if_opackets++; +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m0); +#endif + if ((ifp->if_flags & IFF_LINK0) || sc->sc_adhoc_ap) + m0 = awi_ether_encap(sc, m0); + else + m0 = ieee80211_encap(ifp, m0, &ni); + if (m0 == NULL) { + ifp->if_oerrors++; + continue; + } + if (ni != NULL && ni != ic->ic_bss) + ieee80211_free_node(ic, ni); + wh = mtod(m0, struct ieee80211_frame *); + if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && + (ic->ic_opmode == IEEE80211_M_HOSTAP || + ic->ic_opmode == IEEE80211_M_IBSS) && + sc->sc_adhoc_ap == 0 && + (ifp->if_flags & IFF_LINK0) == 0 && + (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == + IEEE80211_FC0_TYPE_DATA && ni == NULL) { + m_freem(m0); + ifp->if_oerrors++; + continue; + } + } +#if NBPFILTER > 0 + if (ic->ic_rawbpf) + bpf_mtap(ic->ic_rawbpf, m0); +#endif + if (dowep) { + if ((m0 = ieee80211_wep_crypt(ifp, m0, 1)) == NULL) { + ifp->if_oerrors++; + continue; + } + } +#ifdef DIAGNOSTIC + if (m0->m_pkthdr.len != len) { + printf("%s: length %d should be %d\n", + ic->ic_if.if_xname, m0->m_pkthdr.len, len); + m_freem(m0); + ifp->if_oerrors++; + continue; + } +#endif + + if ((ifp->if_flags & IFF_DEBUG) && (ifp->if_flags & IFF_LINK2)) + ieee80211_dump_pkt(m0->m_data, m0->m_len, + ic->ic_bss->ni_rates. + rs_rates[ic->ic_bss->ni_txrate] & + IEEE80211_RATE_VAL, -1); + + for (m = m0, len = 0; 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 = (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] & + IEEE80211_RATE_VAL) * 5; + 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; + + sc->sc_tx_timer = 5; + ifp->if_timer = 1; + } +} + +static void +awi_watchdog(struct ifnet *ifp) +{ + struct awi_softc *sc = ifp->if_softc; + u_int32_t prevdone; + int ocansleep; + + ifp->if_timer = 0; + if (!sc->sc_enabled || sc->sc_invalid) + return; + + ocansleep = sc->sc_cansleep; + sc->sc_cansleep = 0; + if (sc->sc_tx_timer) { + if (--sc->sc_tx_timer == 0) { + printf("%s: device timeout\n", ifp->if_xname); + prevdone = sc->sc_txdone; + awi_tx_int(sc); + if (sc->sc_txdone == prevdone) { + ifp->if_oerrors++; + awi_init(ifp); + goto out; + } + } + ifp->if_timer = 1; + } + if (sc->sc_rx_timer) { + if (--sc->sc_rx_timer == 0) { + if (sc->sc_ic.ic_state == IEEE80211_S_RUN) { + ieee80211_new_state(&sc->sc_ic, + IEEE80211_S_SCAN, -1); + goto out; + } + } else + ifp->if_timer = 1; + } + /* TODO: rate control */ + ieee80211_watchdog(ifp); + out: + sc->sc_cansleep = ocansleep; +} + +static int +awi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct awi_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + int s, error; + + s = splnet(); + /* serialize ioctl, since we may sleep */ + if ((error = awi_lock(sc)) != 0) + goto cantlock; + + switch (cmd) { + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if (sc->sc_enabled) { + /* + * To avoid rescanning another access point, + * do not call awi_init() here. Instead, + * only reflect promisc mode settings. + */ + error = awi_mode_init(sc); + } else + error = awi_init(ifp); + } else if (sc->sc_enabled) + awi_stop(ifp, 1); + break; + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc->sc_ic.ic_media, cmd); + break; + case SIOCADDMULTI: + case SIOCDELMULTI: +#ifdef __FreeBSD__ + error = ENETRESET; /* XXX */ +#else + error = (cmd == SIOCADDMULTI) ? + ether_addmulti(ifr, &sc->sc_ic.ic_ec) : + ether_delmulti(ifr, &sc->sc_ic.ic_ec); +#endif + if (error == ENETRESET) { + /* do not rescan */ + if (sc->sc_enabled) + error = awi_mode_init(sc); + else + error = 0; + } + break; + default: + error = ieee80211_ioctl(ifp, cmd, data); + if (error == ENETRESET) { + if (sc->sc_enabled) + error = awi_init(ifp); + else + error = 0; + } + break; + } + awi_unlock(sc); + cantlock: + splx(s); + return error; +} + +/* + * Called from ifmedia_ioctl via awi_ioctl with lock obtained. + * + * TBD factor with ieee80211_media_change + */ +static int +awi_media_change(struct ifnet *ifp) +{ + struct awi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; + struct ifmedia_entry *ime; + enum ieee80211_opmode newmode; + int i, rate, newadhoc_ap, error = 0; + + ime = ic->ic_media.ifm_cur; + if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) { + i = -1; + } else { + struct ieee80211_rateset *rs = + &ic->ic_sup_rates[(ic->ic_phytype == IEEE80211_T_FH) + ? IEEE80211_MODE_FH : IEEE80211_MODE_11B]; + rate = ieee80211_media2rate(ime->ifm_media); + if (rate == 0) + return EINVAL; + for (i = 0; i < rs->rs_nrates; i++) { + if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rate) + break; + } + if (i == rs->rs_nrates) + return EINVAL; + } + if (ic->ic_fixed_rate != i) { + ic->ic_fixed_rate = i; + error = ENETRESET; + } + + /* + * combination of mediaopt + * + * hostap adhoc flag0 opmode adhoc_ap comment + * + - - HOSTAP 0 HostAP + * - + - IBSS 0 IBSS + * - + + AHDEMO 0 WaveLAN adhoc + * - - + IBSS 1 Melco old Sta + * also LINK0 + * - - - STA 0 Infra Station + */ + newadhoc_ap = 0; + if (ime->ifm_media & IFM_IEEE80211_HOSTAP) + newmode = IEEE80211_M_HOSTAP; + else if (ime->ifm_media & IFM_IEEE80211_ADHOC) { + if (ic->ic_phytype == IEEE80211_T_DS && + (ime->ifm_media & IFM_FLAG0)) + newmode = IEEE80211_M_AHDEMO; + else + newmode = IEEE80211_M_IBSS; + } else if (ime->ifm_media & IFM_FLAG0) { + newmode = IEEE80211_M_IBSS; + newadhoc_ap = 1; + } else + newmode = IEEE80211_M_STA; + if (ic->ic_opmode != newmode || sc->sc_adhoc_ap != newadhoc_ap) { + ic->ic_opmode = newmode; + sc->sc_adhoc_ap = newadhoc_ap; + error = ENETRESET; + } + + if (error == ENETRESET) { + if (sc->sc_enabled) + error = awi_init(ifp); + else + error = 0; + } + return error; +} + +static void +awi_media_status(struct ifnet *ifp, struct ifmediareq *imr) +{ + struct awi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; + int rate; + enum ieee80211_phymode mode; + + imr->ifm_status = IFM_AVALID; + if (ic->ic_state == IEEE80211_S_RUN) + imr->ifm_status |= IFM_ACTIVE; + imr->ifm_active = IFM_IEEE80211; + if (ic->ic_phytype == IEEE80211_T_FH) + mode = IEEE80211_MODE_FH; + else + mode = IEEE80211_MODE_11B; + if (ic->ic_state == IEEE80211_S_RUN) { + rate = ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] & + IEEE80211_RATE_VAL; + } else { + if (ic->ic_fixed_rate == -1) + rate = 0; + else + rate = ic->ic_sup_rates[mode]. + rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL; + } + imr->ifm_active |= ieee80211_rate2media(ic, rate, mode); + switch (ic->ic_opmode) { + case IEEE80211_M_MONITOR: /* we should never reach here */ + break; + case IEEE80211_M_STA: + break; + case IEEE80211_M_IBSS: + if (sc->sc_adhoc_ap) + imr->ifm_active |= IFM_FLAG0; + else + imr->ifm_active |= IFM_IEEE80211_ADHOC; + break; + case IEEE80211_M_AHDEMO: + imr->ifm_active |= IFM_IEEE80211_ADHOC | IFM_FLAG0; + break; + case IEEE80211_M_HOSTAP: + imr->ifm_active |= IFM_IEEE80211_HOSTAP; + break; + } +} + +static int +awi_mode_init(struct awi_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ic.ic_if; + int n, error; #ifdef __FreeBSD__ struct ifmultiaddr *ifma; #else @@ -958,9 +1086,9 @@ awi_init(sc) /* 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) { + if (sc->sc_ic.ic_opmode != IEEE80211_M_HOSTAP && + (ifp->if_flags & IFF_PROMISC)) { sc->sc_mib_mac.aPromiscuous_Enable = 1; goto set_mib; } @@ -973,511 +1101,56 @@ awi_init(sc) 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); + IEEE80211_ADDR_COPY(sc->sc_mib_addr.aGroup_Addresses[n], + LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); n++; } #else - ETHER_FIRST_MULTI(step, &sc->sc_ec, enm); + ETHER_FIRST_MULTI(step, &sc->sc_ic.ic_ec, enm); while (enm != NULL) { if (n == AWI_GROUP_ADDR_SIZE || - memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) - != 0) + !IEEE80211_ADDR_EQ(enm->enm_addrlo, enm->enm_addrhi)) goto set_mib; - memcpy(sc->sc_mib_addr.aGroup_Addresses[n], enm->enm_addrlo, - ETHER_ADDR_LEN); + IEEE80211_ADDR_COPY(sc->sc_mib_addr.aGroup_Addresses[n], + enm->enm_addrlo); 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; + memset(sc->sc_mib_addr.aGroup_Addresses[n], 0, + IEEE80211_ADDR_LEN); 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); + if (sc->sc_mib_local.Accept_All_Multicast_Dis) + ifp->if_flags &= ~IFF_ALLMULTI; + else + ifp->if_flags |= IFF_ALLMULTI; + sc->sc_mib_mgt.Wep_Required = + (sc->sc_ic.ic_flags & IEEE80211_F_WEPON) ? AWI_WEP_ON : AWI_WEP_OFF; + + if ((error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_LOCAL, AWI_WAIT)) || + (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_ADDR, AWI_WAIT)) || + (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MAC, AWI_WAIT)) || + (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT, AWI_WAIT)) || + (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_PHY, AWI_WAIT))) { + DPRINTF(("awi_mode_init: MIB set failed: %d\n", error)); 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; -} - -void -awi_stop(sc) - struct awi_softc *sc; -{ - struct ifnet *ifp = sc->sc_ifp; - struct awi_bss *bp; - struct mbuf *m; - - 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_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); - } - IF_DRAIN(&ifp->if_snd); - while ((bp = TAILQ_FIRST(&sc->sc_scan)) != NULL) { - TAILQ_REMOVE(&sc->sc_scan, bp, list); - free(bp, M_DEVBUF); - } + return 0; } static void -awi_watchdog(ifp) - struct ifnet *ifp; +awi_rx_int(struct awi_softc *sc) { - struct awi_softc *sc = ifp->if_softc; - int ocansleep; - - if (sc->sc_invalid) { - ifp->if_timer = 0; - 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); - } - 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; - } - } - - 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; - } - } else { - if (!(ifp->if_flags & IFF_RUNNING)) - break; - IF_DEQUEUE(&ifp->if_snd, m0); - if (m0 == NULL) - break; - 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 - } -} - -static void -awi_txint(sc) - struct awi_softc *sc; -{ - struct ifnet *ifp = sc->sc_ifp; - u_int8_t flags; - - 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); -} - -static struct mbuf * -awi_fix_txhdr(sc, m0) - struct awi_softc *sc; - struct mbuf *m0; -{ - struct ether_header eh; + struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = &ic->ic_if; struct ieee80211_frame *wh; - struct llc *llc; - - 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; -} - -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; - - 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; - 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; - } - } else { - /* assuming ethernet encapsulation, just strip 802.11 header */ - m_adj(m0, sizeof(wh)); - } - if (ALIGN(mtod(m0, caddr_t) + sizeof(struct ether_header)) != - (uintptr_t)(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_MOVE_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; - } - m_freem(m0); - m0 = n0; - } - return m0; -} - -static void -awi_input(sc, m, rxts, rssi) - struct awi_softc *sc; - struct mbuf *m; - u_int32_t rxts; - u_int8_t rssi; -{ - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211_frame *wh; - - /* 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 - - 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_version >= 400000) - AWI_BPF_MTAP(sc, m, AWI_BPF_NORM); -#endif - (*ifp->if_input)(ifp, m); - 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; - } -} - -static void -awi_rxint(sc) - struct awi_softc *sc; -{ + struct ieee80211_node *ni; u_int8_t state, rate, rssi; u_int16_t len; - u_int32_t frame, next, rxts, rxoff; + u_int32_t frame, next, rstamp, rxoff; struct mbuf *m; rxoff = sc->sc_rxdoff; @@ -1486,24 +1159,75 @@ awi_rxint(sc) 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; + if (sc->sc_substate != AWI_ST_NONE) + goto rx_next; + if (state & AWI_RXD_ST_RXERROR) { + ifp->if_ierrors++; + goto rx_next; } + 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; + rstamp = awi_read_4(sc, rxoff + AWI_RXD_LOCALTIME); + m = awi_devget(sc, frame, len); + if (m == NULL) { + ifp->if_ierrors++; + goto rx_next; + } + if (state & AWI_RXD_ST_LF) { + /* TODO check my bss */ + if (!(sc->sc_ic.ic_flags & IEEE80211_F_SIBSS) && + sc->sc_ic.ic_state == IEEE80211_S_RUN) { + sc->sc_rx_timer = 10; + ifp->if_timer = 1; + } + if ((ifp->if_flags & IFF_DEBUG) && + (ifp->if_flags & IFF_LINK2)) + ieee80211_dump_pkt(m->m_data, m->m_len, + rate / 5, rssi); + if ((ifp->if_flags & IFF_LINK0) || + sc->sc_adhoc_ap) + m = awi_ether_modcap(sc, m); + else + m = m_pullup(m, sizeof(*wh)); + if (m == NULL) { + ifp->if_ierrors++; + goto rx_next; + } + wh = mtod(m, struct ieee80211_frame *); +#ifdef __NetBSD__ + ni = ieee80211_find_rxnode(ic, wh); +#else + if (ic->ic_opmode != IEEE80211_M_STA) { + ni = ieee80211_find_node(ic, + wh->i_addr2); + if (ni == NULL) + ni = ieee80211_ref_node( + ic->ic_bss); + } else + ni = ieee80211_ref_node(ic->ic_bss); +#endif + ieee80211_input(ifp, m, ni, rssi, rstamp); + /* + * The frame may have caused the + * node to be marked for reclamation + * (e.g. in response to a DEAUTH + * message) so use free_node here + * instead of unref_node. + */ + if (ni == ic->ic_bss) + ieee80211_unref_node(&ni); + else + ieee80211_free_node(ic, ni); + } else + sc->sc_rxpend = m; + rx_next: 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); + next = awi_read_4(sc, rxoff + AWI_RXD_NEXT); if (next & AWI_RXD_NEXT_LAST) break; /* make sure the next pointer is correct */ @@ -1516,12 +1240,32 @@ awi_rxint(sc) sc->sc_rxdoff = rxoff; } -static struct mbuf * -awi_devget(sc, off, len) - struct awi_softc *sc; - u_int32_t off; - u_int16_t len; +static void +awi_tx_int(struct awi_softc *sc) { + struct ifnet *ifp = &sc->sc_ic.ic_if; + u_int8_t flags; + + 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; + } + DPRINTF2(("awi_txint: txdone %d txnext %d txbase %d txend %d\n", + sc->sc_txdone, sc->sc_txnext, sc->sc_txbase, sc->sc_txend)); + sc->sc_tx_timer = 0; + ifp->if_flags &= ~IFF_OACTIVE; + awi_start(ifp); +} + +static struct mbuf * +awi_devget(struct awi_softc *sc, u_int32_t off, u_int16_t len) +{ + struct ifnet *ifp = &sc->sc_ic.ic_if; struct mbuf *m; struct mbuf *top, **mp; u_int tlen; @@ -1555,9 +1299,10 @@ awi_devget(sc, off, len) MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) return NULL; - m->m_pkthdr.rcvif = sc->sc_ifp; + m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = len; m->m_len = MHLEN; + m->m_flags |= M_HASFCS; } else { MGET(m, M_DONTWAIT, MT_DATA); if (m == NULL) { @@ -1573,8 +1318,7 @@ awi_devget(sc, off, len) } if (top == NULL) { int hdrlen = sizeof(struct ieee80211_frame) + - (sc->sc_format_llc ? sizeof(struct llc) : - sizeof(struct ether_header)); + sizeof(struct llc); caddr_t newdata = (caddr_t) ALIGN(m->m_data + hdrlen) - hdrlen; m->m_len -= newdata - m->m_data; @@ -1597,8 +1341,7 @@ awi_devget(sc, off, len) */ static int -awi_init_hw(sc) - struct awi_softc *sc; +awi_hw_init(struct awi_softc *sc) { u_int8_t status; u_int16_t intmask; @@ -1619,9 +1362,11 @@ awi_init_hw(sc) /* wait for selftest completion */ for (i = 0; ; i++) { + if (sc->sc_invalid) + return ENXIO; if (i >= AWI_SELFTEST_TIMEOUT*hz/1000) { printf("%s: failed to complete selftest (timeout)\n", - sc->sc_dev.dv_xname); + sc->sc_ic.ic_if.if_xname); return ENXIO; } status = awi_read_1(sc, AWI_SELFTEST); @@ -1637,7 +1382,7 @@ awi_init_hw(sc) } if (status != AWI_SELFTEST_PASSED) { printf("%s: failed to complete selftest (code %x)\n", - sc->sc_dev.dv_xname, status); + sc->sc_ic.ic_if.if_xname, status); return ENXIO; } @@ -1645,7 +1390,7 @@ awi_init_hw(sc) 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); + sc->sc_ic.ic_if.if_xname); for (i = 0; i < AWI_BANNER_LEN; i++) printf("%s%02x", i ? ":" : "\t", sc->sc_banner[i]); printf("\n"); @@ -1666,10 +1411,11 @@ awi_init_hw(sc) awi_intr_unlock(sc); am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_ENECINT); - /* issueing interface test command */ - error = awi_cmd(sc, AWI_CMD_NOP); + /* issuing interface test command */ + error = awi_cmd(sc, AWI_CMD_NOP, AWI_WAIT); if (error) { - printf("%s: failed to complete selftest", sc->sc_dev.dv_xname); + printf("%s: failed to complete selftest", + sc->sc_ic.ic_if.if_xname); if (error == ENXIO) printf(" (no hardware)\n"); else if (error != EWOULDBLOCK) @@ -1678,8 +1424,14 @@ awi_init_hw(sc) printf(" (lost interrupt)\n"); else printf(" (command timeout)\n"); + return error; } - return error; + + /* Initialize VBM */ + awi_write_1(sc, AWI_VBM_OFFSET, 0); + awi_write_1(sc, AWI_VBM_LENGTH, 1); + awi_write_1(sc, AWI_VBM_BITMAP, 0); + return 0; } /* @@ -1689,34 +1441,78 @@ awi_init_hw(sc) */ static int -awi_init_mibs(sc) - struct awi_softc *sc; +awi_init_mibs(struct awi_softc *sc) { - int i, error; - u_int8_t *rate; + int chan, i, error; + struct ieee80211com *ic = &sc->sc_ic; + struct awi_chanset *cs; - 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) { + if ((error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_LOCAL, AWI_WAIT)) || + (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_ADDR, AWI_WAIT)) || + (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MAC, AWI_WAIT)) || + (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MGT, AWI_WAIT)) || + (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_PHY, AWI_WAIT))) { printf("%s: failed to get default mib value (error %d)\n", - sc->sc_dev.dv_xname, error); + ic->ic_if.if_xname, error); return error; } - 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]); + memset(&sc->sc_ic.ic_chan_avail, 0, sizeof(sc->sc_ic.ic_chan_avail)); + for (cs = awi_chanset; ; cs++) { + if (cs->cs_type == 0) { + printf("%s: failed to set available channel\n", + ic->ic_if.if_xname); + return ENXIO; + } + if (cs->cs_type == sc->sc_mib_phy.IEEE_PHY_Type && + cs->cs_region == sc->sc_mib_phy.aCurrent_Reg_Domain) + break; } - 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; + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { + for (i = cs->cs_min; i <= cs->cs_max; i++) { + chan = IEEE80211_FH_CHAN(i % 3 + 1, i); + setbit(sc->sc_ic.ic_chan_avail, chan); + /* XXX for FHSS, does frequency matter? */ + ic->ic_channels[chan].ic_freq = 0; + ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_FHSS; + /* + * According to the IEEE 802.11 specification, + * hop pattern parameter for FH phy should be + * incremented by 3 for given hop chanset, i.e., + * the chanset parameter is calculated for given + * hop patter. However, BayStack 650 Access Points + * apparently use fixed hop chanset parameter value + * 1 for any hop pattern. So we also try this + * combination of hop chanset and pattern. + */ + chan = IEEE80211_FH_CHAN(1, i); + setbit(sc->sc_ic.ic_chan_avail, chan); + ic->ic_channels[chan].ic_freq = 0; /* XXX */ + ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_FHSS; + } + } else { + for (i = cs->cs_min; i <= cs->cs_max; i++) { + setbit(sc->sc_ic.ic_chan_avail, i); + ic->ic_channels[i].ic_freq = + ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); + ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B; + } + } + sc->sc_cur_chan = cs->cs_def; + sc->sc_mib_local.Fragmentation_Dis = 1; - sc->sc_mib_local.Accept_All_Multicast_Dis = 1; + sc->sc_mib_local.Add_PLCP_Dis = 0; + sc->sc_mib_local.MAC_Hdr_Prsv = 1; + sc->sc_mib_local.Rx_Mgmt_Que_En = 0; + sc->sc_mib_local.Re_Assembly_Dis = 1; + sc->sc_mib_local.Strip_PLCP_Dis = 0; sc->sc_mib_local.Power_Saving_Mode_Dis = 1; + sc->sc_mib_local.Accept_All_Multicast_Dis = 1; + sc->sc_mib_local.Check_Seq_Cntl_Dis = 1; + sc->sc_mib_local.Flush_CFP_Queue_On_CF_End = 0; + sc->sc_mib_local.Network_Mode = 1; + sc->sc_mib_local.PWD_Lvl = 0; + sc->sc_mib_local.CFP_Mode = 0; /* allocate buffers */ sc->sc_txbase = AWI_BUFFERS; @@ -1729,789 +1525,20 @@ awi_init_mibs(sc) 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; -} + sc->sc_mib_local.Fill_CFP = 0; -/* - * Start transmitter and receiver of firmware - * Called after awi_init_hw() to start operation. - */ + memset(&sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE); + sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID; -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); - 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; -} - -static void -awi_stop_txrx(sc) - struct awi_softc *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); -} - -int -awi_init_region(sc) - struct awi_softc *sc; -{ - - 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 { - 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; + sc->sc_mib_mgt.aPower_Mgt_Mode = 0; + sc->sc_mib_mgt.aDTIM_Period = 1; + LE_WRITE_2(&sc->sc_mib_mgt.aATIM_Window, 0); return 0; } static int -awi_start_scan(sc) - struct awi_softc *sc; -{ - int error = 0; - struct awi_bss *bp; - - 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; -} - -static int -awi_next_scan(sc) - struct awi_softc *sc; -{ - int error; - - 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; -} - -static void -awi_stop_scan(sc) - struct awi_softc *sc; -{ - struct ifnet *ifp = sc->sc_ifp; - struct awi_bss *bp, *sbp; - int fail; - - 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; - } - 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); -} - -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; - - if (sc->sc_status != AWI_ST_SCAN) - return; - wh = mtod(m0, struct ieee80211_frame *); - - 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 - return; - } - 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 - 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; - } - - TAILQ_FOREACH(bp, &sc->sc_scan, 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); -} - -static int -awi_set_ss(sc) - struct awi_softc *sc; -{ - 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"); - } - 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; -} - -static void -awi_try_sync(sc) - struct awi_softc *sc; -{ - struct awi_bss *bp; - - 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; -{ - struct ifnet *ifp = sc->sc_ifp; - - 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); - } -} - -static void -awi_send_deauth(sc) - struct awi_softc *sc; -{ - struct ifnet *ifp = sc->sc_ifp; - struct mbuf *m; - struct ieee80211_frame *wh; - u_int8_t *deauth; - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return; - 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); -} - -static void -awi_send_auth(sc, seq) - struct awi_softc *sc; - int seq; -{ - struct ifnet *ifp = sc->sc_ifp; - struct mbuf *m; - struct ieee80211_frame *wh; - u_int8_t *auth; - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) - return; - 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); - - sc->sc_mgt_timer = AWI_TRANS_TIMEOUT / 1000; - ifp->if_timer = 1; -} - -static void -awi_recv_auth(sc, m0) - struct awi_softc *sc; - struct mbuf *m0; -{ - 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); - TAILQ_FOREACH(bp, &sc->sc_scan, list) { - if (memcmp(bp->esrc, sc->sc_bss.esrc, ETHER_ADDR_LEN) - == 0) { - bp->fails++; - break; - } - } - return; - } - sc->sc_mgt_timer = 0; - awi_drvstate(sc, AWI_DRV_INFAUTH); - awi_send_asreq(sc, 0); -} - -static void -awi_send_asreq(sc, reassoc) - struct awi_softc *sc; - int reassoc; -{ - struct ifnet *ifp = sc->sc_ifp; - struct mbuf *m; - struct ieee80211_frame *wh; - u_int16_t capinfo, 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 */ - capinfo = IEEE80211_CAPINFO_CF_POLLABLE; - if (sc->sc_mib_local.Network_Mode) - capinfo |= IEEE80211_CAPINFO_ESS; - else - capinfo |= IEEE80211_CAPINFO_IBSS; - if (sc->sc_wep_algo != NULL) - capinfo |= IEEE80211_CAPINFO_PRIVACY; - LE_WRITE_2(asreq, capinfo); - 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; -} - -static void -awi_recv_asresp(sc, m0) - struct awi_softc *sc; - struct mbuf *m0; -{ - 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); - TAILQ_FOREACH(bp, &sc->sc_scan, list) { - if (memcmp(bp->esrc, sc->sc_bss.esrc, ETHER_ADDR_LEN) - == 0) { - bp->fails++; - break; - } - } - return; - } - 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); -} - -static int -awi_mib(sc, cmd, mib) - struct awi_softc *sc; - u_int8_t cmd; - u_int8_t mib; +awi_mib(struct awi_softc *sc, u_int8_t cmd, u_int8_t mib, int wflag) { int error; u_int8_t size, *ptr; @@ -2545,27 +1572,25 @@ awi_mib(sc, cmd, mib) return EINVAL; } if (sc->sc_cmd_inprog) { - error = awi_cmd_wait(sc); - if (error) { + if ((error = awi_cmd_wait(sc)) != 0) { if (error == EWOULDBLOCK) - printf("awi_mib: cmd %d inprog", - sc->sc_cmd_inprog); + DPRINTF(("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) + awi_write_bytes(sc, AWI_CA_MIB_DATA, ptr, size); + awi_write_1(sc, AWI_CA_MIB_TYPE, mib); + awi_write_1(sc, AWI_CA_MIB_SIZE, size); + awi_write_1(sc, AWI_CA_MIB_INDEX, 0); + if ((error = awi_cmd(sc, cmd, wflag)) != 0) return error; if (cmd == AWI_CMD_GET_MIB) { - awi_read_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, ptr, size); + awi_read_bytes(sc, AWI_CA_MIB_DATA, ptr, size); #ifdef AWI_DEBUG - if (awi_verbose) { + if (awi_debug) { int i; printf("awi_mib: #%d:", mib); @@ -2579,61 +1604,32 @@ awi_mib(sc, cmd, mib) } static int -awi_cmd_scan(sc) - struct awi_softc *sc; -{ - int error; - u_int8_t scan_mode; - - 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; - } - - if (sc->sc_cmd_inprog) { - error = awi_cmd_wait(sc); - if (error) - return error; - } - 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); -} - -static int -awi_cmd(sc, cmd) - struct awi_softc *sc; - u_int8_t cmd; +awi_cmd(struct awi_softc *sc, u_int8_t cmd, int wflag) { u_int8_t status; int error = 0; +#ifdef AWI_DEBUG + static const char *cmdname[] = { + "IDLE", "NOP", "SET_MIB", "INIT_TX", "FLUSH_TX", "INIT_RX", + "KILL_RX", "SLEEP", "WAKE", "GET_MIB", "SCAN", "SYNC", "RESUME" + }; +#endif +#ifdef AWI_DEBUG + if (awi_debug > 1) { + if (cmd >= sizeof(cmdname)/sizeof(cmdname[0])) + printf("awi_cmd: #%d", cmd); + else + printf("awi_cmd: %s", cmdname[cmd]); + printf(" %s\n", wflag == AWI_NOWAIT ? "nowait" : "wait"); + } +#endif 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) + if (wflag == AWI_NOWAIT) + return EINPROGRESS; + if ((error = awi_cmd_wait(sc)) != 0) return error; status = awi_read_1(sc, AWI_CMD_STATUS); awi_write_1(sc, AWI_CMD, 0); @@ -2644,15 +1640,54 @@ awi_cmd(sc, cmd) return EINVAL; default: printf("%s: command %d failed %x\n", - sc->sc_dev.dv_xname, cmd, status); + sc->sc_ic.ic_if.if_xname, cmd, status); return ENXIO; } return 0; } +static int +awi_cmd_wait(struct awi_softc *sc) +{ + 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_ic.ic_if.if_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; + } + if (error) { + DPRINTF(("awi_cmd_wait: cmd 0x%x, error %d\n", + sc->sc_cmd_inprog, error)); + } + return error; +} + static void -awi_cmd_done(sc) - struct awi_softc *sc; +awi_cmd_done(struct awi_softc *sc) { u_int8_t cmd, status; @@ -2662,38 +1697,21 @@ awi_cmd_done(sc) cmd = sc->sc_cmd_inprog; sc->sc_cmd_inprog = 0; - if (sc->sc_status == AWI_ST_INIT) { - wakeup(sc); - return; - } + wakeup(sc); awi_write_1(sc, AWI_CMD, 0); if (status != AWI_STAT_OK) { printf("%s: command %d failed %x\n", - sc->sc_dev.dv_xname, cmd, status); + sc->sc_ic.ic_if.if_xname, cmd, status); + sc->sc_substate = AWI_ST_NONE; 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; - } + if (sc->sc_substate != AWI_ST_NONE) + (void)ieee80211_new_state(&sc->sc_ic, sc->sc_nstate, -1); } static int -awi_next_txd(sc, len, framep, ntxdp) - struct awi_softc *sc; - int len; - u_int32_t *framep, *ntxdp; +awi_next_txd(struct awi_softc *sc, int len, u_int32_t *framep, u_int32_t *ntxdp) { u_int32_t txd, ntxd, frame; @@ -2728,12 +1746,16 @@ awi_next_txd(sc, len, framep, ntxdp) } static int -awi_lock(sc) - struct awi_softc *sc; +awi_lock(struct awi_softc *sc) { int error = 0; - if (curproc == NULL) { +#ifdef __NetBSD__ + if (curlwp == NULL) +#else + if (curproc == NULL) +#endif + { /* * XXX * Though driver ioctl should be called with context, @@ -2742,9 +1764,9 @@ awi_lock(sc) * ioctl requests in progress. */ if (sc->sc_busy) { - return EWOULDBLOCK; if (sc->sc_invalid) return ENXIO; + return EWOULDBLOCK; } sc->sc_busy = 1; sc->sc_cansleep = 0; @@ -2765,8 +1787,7 @@ awi_lock(sc) } static void -awi_unlock(sc) - struct awi_softc *sc; +awi_unlock(struct awi_softc *sc) { sc->sc_busy = 0; sc->sc_cansleep = 0; @@ -2775,8 +1796,7 @@ awi_unlock(sc) } static int -awi_intr_lock(sc) - struct awi_softc *sc; +awi_intr_lock(struct awi_softc *sc) { u_int8_t status; int i, retry; @@ -2784,213 +1804,364 @@ awi_intr_lock(sc) 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) + if ((status = awi_read_1(sc, AWI_LOCKOUT_HOST)) == 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) + if ((status = awi_read_1(sc, AWI_LOCKOUT_HOST)) == 0) break; awi_write_1(sc, AWI_LOCKOUT_MAC, 0); } if (status != 0) { printf("%s: failed to lock interrupt\n", - sc->sc_dev.dv_xname); + sc->sc_ic.ic_if.if_xname); return ENXIO; } return 0; } static void -awi_intr_unlock(sc) - struct awi_softc *sc; +awi_intr_unlock(struct awi_softc *sc) { awi_write_1(sc, AWI_LOCKOUT_MAC, 0); } static int -awi_cmd_wait(sc) - struct awi_softc *sc; +awi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) { - int i, error = 0; + struct awi_softc *sc = ic->ic_softc; + struct ieee80211_node *ni; + struct ifnet *ifp = &ic->ic_if; + int error; + u_int8_t newmode; + enum ieee80211_state ostate; +#ifdef AWI_DEBUG + static const char *stname[] = + { "INIT", "SCAN", "AUTH", "ASSOC", "RUN" }; + static const char *substname[] = + { "NONE", "SCAN_INIT", "SCAN_SETMIB", "SCAN_SCCMD", + "SUB_INIT", "SUB_SETSS", "SUB_SYNC" }; +#endif /* AWI_DEBUG */ - 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; + ostate = ic->ic_state; + DPRINTF(("awi_newstate: %s (%s/%s) -> %s\n", stname[ostate], + stname[sc->sc_nstate], substname[sc->sc_substate], stname[nstate])); + + /* set LED */ + switch (nstate) { + case IEEE80211_S_INIT: + awi_drvstate(sc, AWI_DRV_RESET); + break; + case IEEE80211_S_SCAN: + if (ic->ic_opmode == IEEE80211_M_IBSS || + ic->ic_opmode == IEEE80211_M_AHDEMO) + awi_drvstate(sc, AWI_DRV_ADHSC); + else + awi_drvstate(sc, AWI_DRV_INFSY); + break; + case IEEE80211_S_AUTH: + awi_drvstate(sc, AWI_DRV_INFSY); + break; + case IEEE80211_S_ASSOC: + awi_drvstate(sc, AWI_DRV_INFAUTH); + break; + case IEEE80211_S_RUN: + if (ic->ic_opmode == IEEE80211_M_IBSS || + ic->ic_opmode == IEEE80211_M_AHDEMO) + awi_drvstate(sc, AWI_DRV_ADHSY); + else + awi_drvstate(sc, AWI_DRV_INFASSOC); + break; + } + + if (nstate == IEEE80211_S_INIT) { + sc->sc_substate = AWI_ST_NONE; + ic->ic_flags &= ~IEEE80211_F_SIBSS; + return (*sc->sc_newstate)(ic, nstate, arg); + } + + /* state transition */ + if (nstate == IEEE80211_S_SCAN) { + /* SCAN substate */ + if (sc->sc_substate == AWI_ST_NONE) { + sc->sc_nstate = nstate; /* next state in transition */ + sc->sc_substate = AWI_ST_SCAN_INIT; } - 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); + switch (sc->sc_substate) { + case AWI_ST_SCAN_INIT: + sc->sc_substate = AWI_ST_SCAN_SETMIB; + switch (ostate) { + case IEEE80211_S_RUN: + /* beacon miss */ + if (ifp->if_flags & IFF_DEBUG) + printf("%s: no recent beacons from %s;" + " rescanning\n", + ifp->if_xname, + ether_sprintf(ic->ic_bss->ni_bssid)); + /* FALLTHRU */ + case IEEE80211_S_AUTH: + case IEEE80211_S_ASSOC: + case IEEE80211_S_INIT: + ieee80211_begin_scan(ifp); + /* FALLTHRU */ + case IEEE80211_S_SCAN: + /* scan next */ break; } - if (i++ >= AWI_CMD_TIMEOUT*1000/10) - error = EWOULDBLOCK; + if (ic->ic_flags & IEEE80211_F_ASCAN) + newmode = AWI_SCAN_ACTIVE; 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; - - 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; -{ - 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"); + newmode = AWI_SCAN_PASSIVE; + if (sc->sc_mib_mgt.aScan_Mode != newmode) { + sc->sc_mib_mgt.aScan_Mode = newmode; + if ((error = awi_mib(sc, AWI_CMD_SET_MIB, + AWI_MIB_MGT, AWI_NOWAIT)) != 0) + break; + } + /* FALLTHRU */ + case AWI_ST_SCAN_SETMIB: + sc->sc_substate = AWI_ST_SCAN_SCCMD; + if (sc->sc_cmd_inprog) { + if ((error = awi_cmd_wait(sc)) != 0) + break; + } + sc->sc_cmd_inprog = AWI_CMD_SCAN; + ni = ic->ic_bss; + awi_write_2(sc, AWI_CA_SCAN_DURATION, + (ic->ic_flags & IEEE80211_F_ASCAN) ? + AWI_ASCAN_DURATION : AWI_PSCAN_DURATION); + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { + awi_write_1(sc, AWI_CA_SCAN_SET, + IEEE80211_FH_CHANSET( + ieee80211_chan2ieee(ic, ni->ni_chan))); + awi_write_1(sc, AWI_CA_SCAN_PATTERN, + IEEE80211_FH_CHANPAT( + ieee80211_chan2ieee(ic, ni->ni_chan))); + awi_write_1(sc, AWI_CA_SCAN_IDX, 1); + } else { + awi_write_1(sc, AWI_CA_SCAN_SET, + ieee80211_chan2ieee(ic, ni->ni_chan)); + awi_write_1(sc, AWI_CA_SCAN_PATTERN, 0); + awi_write_1(sc, AWI_CA_SCAN_IDX, 0); + } + awi_write_1(sc, AWI_CA_SCAN_SUSP, 0); + sc->sc_cur_chan = ieee80211_chan2ieee(ic, ni->ni_chan); + if ((error = awi_cmd(sc, AWI_CMD_SCAN, AWI_NOWAIT)) + != 0) + break; + /* FALLTHRU */ + case AWI_ST_SCAN_SCCMD: + ic->ic_state = nstate; + sc->sc_substate = AWI_ST_NONE; + error = EINPROGRESS; break; default: - printf(" mgt#%d", - wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); + DPRINTF(("awi_newstate: unexpected state %s/%s\n", + stname[nstate], substname[sc->sc_substate])); + sc->sc_substate = AWI_ST_NONE; + error = EIO; break; } - break; - default: - printf(" type#%d", - wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); - break; + goto out; } - 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]); + + if (ostate == IEEE80211_S_SCAN) { + /* set SSID and channel */ + /* substate */ + if (sc->sc_substate == AWI_ST_NONE) { + sc->sc_nstate = nstate; /* next state in transition */ + sc->sc_substate = AWI_ST_SUB_INIT; } - printf("\n"); + ni = ic->ic_bss; + switch (sc->sc_substate) { + case AWI_ST_SUB_INIT: + sc->sc_substate = AWI_ST_SUB_SETSS; + IEEE80211_ADDR_COPY(&sc->sc_mib_mgt.aCurrent_BSS_ID, + ni->ni_bssid); + memset(&sc->sc_mib_mgt.aCurrent_ESS_ID, 0, + AWI_ESS_ID_SIZE); + sc->sc_mib_mgt.aCurrent_ESS_ID[0] = + IEEE80211_ELEMID_SSID; + sc->sc_mib_mgt.aCurrent_ESS_ID[1] = ni->ni_esslen; + memcpy(&sc->sc_mib_mgt.aCurrent_ESS_ID[2], + ni->ni_essid, ni->ni_esslen); + LE_WRITE_2(&sc->sc_mib_mgt.aBeacon_Period, + ni->ni_intval); + if ((error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT, + AWI_NOWAIT)) != 0) + break; + /* FALLTHRU */ + case AWI_ST_SUB_SETSS: + sc->sc_substate = AWI_ST_SUB_SYNC; + if (sc->sc_cmd_inprog) { + if ((error = awi_cmd_wait(sc)) != 0) + break; + } + sc->sc_cmd_inprog = AWI_CMD_SYNC; + if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { + awi_write_1(sc, AWI_CA_SYNC_SET, + IEEE80211_FH_CHANSET( + ieee80211_chan2ieee(ic, ni->ni_chan))); + awi_write_1(sc, AWI_CA_SYNC_PATTERN, + IEEE80211_FH_CHANPAT( + ieee80211_chan2ieee(ic, ni->ni_chan))); + awi_write_1(sc, AWI_CA_SYNC_IDX, + ni->ni_fhindex); + awi_write_2(sc, AWI_CA_SYNC_DWELL, + ni->ni_fhdwell); + } else { + awi_write_1(sc, AWI_CA_SYNC_SET, + ieee80211_chan2ieee(ic, ni->ni_chan)); + awi_write_1(sc, AWI_CA_SYNC_PATTERN, 0); + awi_write_1(sc, AWI_CA_SYNC_IDX, 0); + awi_write_2(sc, AWI_CA_SYNC_DWELL, 0); + } + if (ic->ic_flags & IEEE80211_F_SIBSS) + awi_write_1(sc, AWI_CA_SYNC_STARTBSS, 1); + else + awi_write_1(sc, AWI_CA_SYNC_STARTBSS, 0); + awi_write_2(sc, AWI_CA_SYNC_MBZ, 0); + awi_write_bytes(sc, AWI_CA_SYNC_TIMESTAMP, + ni->ni_tstamp, 8); + awi_write_4(sc, AWI_CA_SYNC_REFTIME, ni->ni_rstamp); + sc->sc_cur_chan = ieee80211_chan2ieee(ic, ni->ni_chan); + if ((error = awi_cmd(sc, AWI_CMD_SYNC, AWI_NOWAIT)) + != 0) + break; + /* FALLTHRU */ + case AWI_ST_SUB_SYNC: + sc->sc_substate = AWI_ST_NONE; + if (ic->ic_flags & IEEE80211_F_SIBSS) { + if ((error = awi_mib(sc, AWI_CMD_GET_MIB, + AWI_MIB_MGT, AWI_WAIT)) != 0) + break; + IEEE80211_ADDR_COPY(ni->ni_bssid, + &sc->sc_mib_mgt.aCurrent_BSS_ID); + } else { + if (nstate == IEEE80211_S_RUN) { + sc->sc_rx_timer = 10; + ifp->if_timer = 1; + } + } + error = 0; + break; + default: + DPRINTF(("awi_newstate: unexpected state %s/%s\n", + stname[nstate], substname[sc->sc_substate])); + sc->sc_substate = AWI_ST_NONE; + error = EIO; + break; + } + goto out; } + + sc->sc_substate = AWI_ST_NONE; + + return (*sc->sc_newstate)(ic, nstate, arg); +out: + if (error != 0) + return error; + return (*sc->sc_newstate)(ic, nstate, arg); +} + +static void +awi_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, + struct ieee80211_node *ni, + int subtype, int rssi, u_int32_t rstamp) +{ + struct awi_softc *sc = ic->ic_softc; + + /* probe request is handled by hardware */ + if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_REQ) + return; + (*sc->sc_recv_mgmt)(ic, m0, ni, subtype, rssi, rstamp); +} + +static int +awi_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, + int type, int arg) +{ + struct awi_softc *sc = ic->ic_softc; + + /* probe request is handled by hardware */ + if (type == IEEE80211_FC0_SUBTYPE_PROBE_REQ) + return 0; + return (*sc->sc_send_mgmt)(ic, ni, type, arg); +} + +static struct mbuf * +awi_ether_encap(struct awi_softc *sc, struct mbuf *m) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni = ic->ic_bss; + struct ether_header *eh; + struct ieee80211_frame *wh; + + if (m->m_len < sizeof(struct ether_header)) { + m = m_pullup(m, sizeof(struct ether_header)); + if (m == NULL) + return NULL; + } + eh = mtod(m, struct ether_header *); + M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); + if (m == NULL) + return NULL; + wh = mtod(m, struct ieee80211_frame *); + wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; + *(u_int16_t *)wh->i_dur = 0; + *(u_int16_t *)wh->i_seq = + htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT); + ni->ni_txseq++; + if (ic->ic_opmode == IEEE80211_M_IBSS || + ic->ic_opmode == IEEE80211_M_AHDEMO) { + wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; + if (sc->sc_adhoc_ap) + IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); + else + IEEE80211_ADDR_COPY(wh->i_addr1, eh->ether_dhost); + IEEE80211_ADDR_COPY(wh->i_addr2, eh->ether_shost); + IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); + } else { + wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; + IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); + IEEE80211_ADDR_COPY(wh->i_addr2, eh->ether_shost); + IEEE80211_ADDR_COPY(wh->i_addr3, eh->ether_dhost); + } + return m; +} + +static struct mbuf * +awi_ether_modcap(struct awi_softc *sc, struct mbuf *m) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ether_header eh; + struct ieee80211_frame wh; + struct llc *llc; + + if (m->m_len < sizeof(wh) + sizeof(eh)) { + m = m_pullup(m, sizeof(wh) + sizeof(eh)); + if (m == NULL) + return NULL; + } + memcpy(&wh, mtod(m, caddr_t), sizeof(wh)); + if (wh.i_fc[0] != (IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA)) + return m; + memcpy(&eh, mtod(m, caddr_t) + sizeof(wh), sizeof(eh)); + m_adj(m, sizeof(eh) - sizeof(*llc)); + if (ic->ic_opmode == IEEE80211_M_IBSS || + ic->ic_opmode == IEEE80211_M_AHDEMO) + IEEE80211_ADDR_COPY(wh.i_addr2, eh.ether_shost); + memcpy(mtod(m, caddr_t), &wh, sizeof(wh)); + llc = (struct llc *)(mtod(m, caddr_t) + sizeof(wh)); + llc->llc_dsap = 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; + llc->llc_snap.ether_type = eh.ether_type; + return m; } -#endif diff --git a/sys/dev/awi/awi_wep.c b/sys/dev/awi/awi_wep.c deleted file mode 100644 index c501b721d6b5..000000000000 --- a/sys/dev/awi/awi_wep.c +++ /dev/null @@ -1,533 +0,0 @@ -/* $NetBSD: awi_wep.c,v 1.4 2000/08/14 11:28:03 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. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__FreeBSD__) && __FreeBSD_version >= 400000 -#include -#else -#include -#endif - -#include -#include -#ifdef __FreeBSD__ -#include -#include -#else -#include -#endif -#include - -#include - -#include -#include - -#ifdef __NetBSD__ -#include -#include -#include -#include - -#include -#endif - -#ifdef __FreeBSD__ -#include -#include -#include -#include - -#include -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, src, dst, len); -} -#endif - -static void awi_crc_init(void); -static u_int32_t awi_crc_update(u_int32_t crc, u_int8_t *buf, int len); - -static int awi_null_ctxlen(void); -static void awi_null_setkey(void *ctx, u_int8_t *key, int keylen); -static void awi_null_copy(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 */ - -/* 1: normal wep (arc4) */ - { "arc4", arc4_ctxlen, arc4_setkey, - arc4_encrypt, arc4_encrypt }, - -/* 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__ -#if __FreeBSD_version < 500028 - suerr = suser(curproc); -#else - suerr = suser(curthread); -#endif -#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_MOVE_PKTHDR(n, m); - len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; - if (txflag) { - n->m_pkthdr.len += len; - } else { - 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[IEEE80211_WEP_IVLEN] = kid << 6; /* pad and keyid */ - noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; - } else { - ivp = mtod(m, u_int8_t *) + moff; - kid = ivp[IEEE80211_WEP_IVLEN] >> 6; - moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; - } - 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; - for (noff = 0; noff < sizeof(crcbuf); noff += len) { - len = sizeof(crcbuf) - noff; - if (len > m->m_len - moff) - len = m->m_len - moff; - if (len > 0) - awa->awa_decrypt(ctx, crcbuf + noff, - mtod(m, caddr_t) + moff, len); - m = m->m_next; - moff = 0; - } - 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/awi/awi_wicfg.c b/sys/dev/awi/awi_wicfg.c deleted file mode 100644 index 72b7c0ed35d4..000000000000 --- a/sys/dev/awi/awi_wicfg.c +++ /dev/null @@ -1,634 +0,0 @@ -/* $NetBSD: awi_wicfg.c,v 1.3 2000/07/06 17:22:25 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. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* - * WaveLAN compatible configuration support routines for the awi driver. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__FreeBSD__) && __FreeBSD_version >= 400000 -#include -#else -#include -#endif - -#include -#include -#ifdef __FreeBSD__ -#include -#include -#else -#include -#endif -#include - -#include - -#include -#include - -#ifdef __NetBSD__ -#include -#include -#include -#include - -#include /* XXX */ -#endif -#ifdef __FreeBSD__ -#include -#include - -#undef _KERNEL /* XXX */ -#include /* XXX */ -#define _KERNEL /* XXX */ -#include -#include -#endif - -static int awi_cfgget(struct ifnet *ifp, u_long cmd, caddr_t data); -static int awi_cfgset(struct ifnet *ifp, u_long cmd, caddr_t data); - -int -awi_wicfg(ifp, cmd, data) - struct ifnet *ifp; - u_long cmd; - caddr_t data; -{ - int error; - - switch (cmd) { - case SIOCGWAVELAN: - error = awi_cfgget(ifp, cmd, data); - break; - case SIOCSWAVELAN: -#ifdef __FreeBSD__ -#if __FreeBSD_version < 500028 - error = suser(curproc); -#else - error = suser(curthread); -#endif -#else - error = suser(curproc->p_ucred, &curproc->p_acflag); -#endif - if (error) - break; - error = awi_cfgset(ifp, cmd, data); - break; - default: - error = EINVAL; - break; - } - return error; -} - -static int -awi_cfgget(ifp, cmd, data) - struct ifnet *ifp; - u_long cmd; - caddr_t data; -{ - int i, error, keylen; - char *p; - struct awi_softc *sc = (struct awi_softc *)ifp->if_softc; - struct ifreq *ifr = (struct ifreq *)data; - struct wi_ltv_keys *keys; - struct wi_key *k; - struct wi_req wreq; -#ifdef WICACHE - struct wi_sigcache wsc; - struct awi_bss *bp; -#endif /* WICACHE */ - - error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); - if (error) - return error; - switch (wreq.wi_type) { - case WI_RID_SERIALNO: - memcpy(wreq.wi_val, sc->sc_banner, AWI_BANNER_LEN); - wreq.wi_len = (AWI_BANNER_LEN + 1) / 2; - break; - case WI_RID_NODENAME: - strcpy((char *)&wreq.wi_val[1], hostname); - wreq.wi_val[0] = strlen(hostname); - wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2; - break; - case WI_RID_OWN_SSID: - p = sc->sc_ownssid; - wreq.wi_val[0] = p[1]; - memcpy(&wreq.wi_val[1], p + 2, p[1]); - wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2; - break; - case WI_RID_CURRENT_SSID: - if (ifp->if_flags & IFF_RUNNING) { - p = sc->sc_bss.essid; - wreq.wi_val[0] = p[1]; - memcpy(&wreq.wi_val[1], p + 2, p[1]); - } else { - wreq.wi_val[0] = 0; - wreq.wi_val[1] = '\0'; - } - wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2; - break; - case WI_RID_DESIRED_SSID: - p = sc->sc_mib_mac.aDesired_ESS_ID; - wreq.wi_val[0] = p[1]; - memcpy(&wreq.wi_val[1], p + 2, p[1]); - wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2; - break; - case WI_RID_CURRENT_BSSID: - if (ifp->if_flags & IFF_RUNNING) - memcpy(wreq.wi_val, sc->sc_bss.bssid, ETHER_ADDR_LEN); - else - memset(wreq.wi_val, 0, ETHER_ADDR_LEN); - wreq.wi_len = ETHER_ADDR_LEN / 2; - break; - case WI_RID_CHANNEL_LIST: - if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { - wreq.wi_val[0] = sc->sc_scan_min; - wreq.wi_val[1] = sc->sc_scan_max; - wreq.wi_len = 2; - } else { - wreq.wi_val[0] = 0; - for (i = sc->sc_scan_min; i <= sc->sc_scan_max; i++) - wreq.wi_val[0] |= 1 << (i - 1); - wreq.wi_len = 1; - } - break; - case WI_RID_OWN_CHNL: - wreq.wi_val[0] = sc->sc_ownch; - wreq.wi_len = 1; - break; - case WI_RID_CURRENT_CHAN: - if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) - wreq.wi_val[0] = sc->sc_bss.pattern; - else - wreq.wi_val[0] = sc->sc_bss.chanset; - wreq.wi_len = 1; - break; - case WI_RID_COMMS_QUALITY: - wreq.wi_val[0] = 0; /* quality */ - wreq.wi_val[1] = sc->sc_bss.rssi; /* signal */ - wreq.wi_val[2] = 0; /* noise */ - wreq.wi_len = 3; - break; - case WI_RID_PROMISC: - wreq.wi_val[0] = sc->sc_mib_mac.aPromiscuous_Enable; - wreq.wi_len = 1; - break; - case WI_RID_PORTTYPE: - if (sc->sc_mib_local.Network_Mode) - wreq.wi_val[0] = 1; - else if (!sc->sc_no_bssid) - wreq.wi_val[0] = 2; - else - wreq.wi_val[0] = 3; - wreq.wi_len = 1; - break; - case WI_RID_MAC_NODE: - memcpy(wreq.wi_val, sc->sc_mib_addr.aMAC_Address, - ETHER_ADDR_LEN); - wreq.wi_len = ETHER_ADDR_LEN / 2; - break; - case WI_RID_TX_RATE: - case WI_RID_CUR_TX_RATE: - wreq.wi_val[0] = sc->sc_tx_rate / 10; - wreq.wi_len = 1; - break; - case WI_RID_RTS_THRESH: - wreq.wi_val[0] = LE_READ_2(&sc->sc_mib_mac.aRTS_Threshold); - wreq.wi_len = 1; - break; - case WI_RID_CREATE_IBSS: - wreq.wi_val[0] = sc->sc_start_bss; - wreq.wi_len = 1; - break; - case WI_RID_SYSTEM_SCALE: - wreq.wi_val[0] = 1; /* low density ... not supported */ - wreq.wi_len = 1; - break; - case WI_RID_PM_ENABLED: - wreq.wi_val[0] = sc->sc_mib_local.Power_Saving_Mode_Dis ? 0 : 1; - wreq.wi_len = 1; - break; - case WI_RID_MAX_SLEEP: - wreq.wi_val[0] = 0; /* not implemented */ - wreq.wi_len = 1; - break; - case WI_RID_WEP_AVAIL: - wreq.wi_val[0] = 1; - wreq.wi_len = 1; - break; - case WI_RID_ENCRYPTION: - wreq.wi_val[0] = awi_wep_getalgo(sc); - wreq.wi_len = 1; - break; - case WI_RID_TX_CRYPT_KEY: - wreq.wi_val[0] = sc->sc_wep_defkid; - wreq.wi_len = 1; - break; - case WI_RID_DEFLT_CRYPT_KEYS: - keys = (struct wi_ltv_keys *)&wreq; - /* do not show keys to non-root user */ -#ifdef __FreeBSD__ -#if __FreeBSD_version < 500028 - error = suser(curproc); -#else - error = suser(curthread); -#endif -#else - error = suser(curproc->p_ucred, &curproc->p_acflag); -#endif - if (error) { - memset(keys, 0, sizeof(*keys)); - error = 0; - break; - } - for (i = 0; i < IEEE80211_WEP_NKID; i++) { - k = &keys->wi_keys[i]; - keylen = sizeof(k->wi_keydat); - error = awi_wep_getkey(sc, i, k->wi_keydat, &keylen); - if (error) - break; - k->wi_keylen = keylen; - } - wreq.wi_len = sizeof(*keys) / 2; - break; - case WI_RID_MAX_DATALEN: - wreq.wi_val[0] = LE_READ_2(&sc->sc_mib_mac.aMax_Frame_Length); - wreq.wi_len = 1; - break; - case WI_RID_IFACE_STATS: - /* not implemented yet */ - wreq.wi_len = 0; - break; -#ifdef WICACHE - case WI_RID_READ_CACHE: - for (bp = TAILQ_FIRST(&sc->sc_scan), i = 0; - bp != NULL && i < MAXWICACHE; - bp = TAILQ_NEXT(bp, list), i++) { - memcpy(wsc.macsrc, bp->esrc, ETHER_ADDR_LEN); - /*XXX*/ - memcpy(&wsc.ipsrc, bp->bssid, sizeof(wsc.ipsrc)); - wsc.signal = bp->rssi; - wsc.noise = 0; - wsc.quality = 0; - memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i, - &wsc, sizeof(wsc)); - } - wreq.wi_len = sizeof(wsc) * i / 2; - break; -#endif /* WICACHE */ - default: - error = EINVAL; - break; - } - if (error == 0) { - wreq.wi_len++; - error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); - } - return error; -} - -static int -awi_cfgset(ifp, cmd, data) - struct ifnet *ifp; - u_long cmd; - caddr_t data; -{ - int i, error, rate, oregion; - u_int8_t *phy_rates; - struct awi_softc *sc = (struct awi_softc *)ifp->if_softc; - struct ifreq *ifr = (struct ifreq *)data; - struct wi_ltv_keys *keys; - struct wi_key *k; - struct wi_req wreq; - - error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); - if (error) - return error; - if (wreq.wi_len-- < 1) - return EINVAL; - switch (wreq.wi_type) { - case WI_RID_SERIALNO: - case WI_RID_NODENAME: - error = EPERM; - break; - case WI_RID_OWN_SSID: - if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) { - error = EINVAL; - break; - } - if (wreq.wi_val[0] > IEEE80211_NWID_LEN) { - error = EINVAL; - break; - } - memset(sc->sc_ownssid, 0, AWI_ESS_ID_SIZE); - sc->sc_ownssid[0] = IEEE80211_ELEMID_SSID; - sc->sc_ownssid[1] = wreq.wi_val[0]; - memcpy(&sc->sc_ownssid[2], &wreq.wi_val[1], wreq.wi_val[0]); - if (!sc->sc_mib_local.Network_Mode && - !sc->sc_no_bssid && sc->sc_start_bss) - error = ENETRESET; - break; - case WI_RID_CURRENT_SSID: - error = EPERM; - break; - case WI_RID_DESIRED_SSID: - if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) { - error = EINVAL; - break; - } - if (wreq.wi_val[0] > IEEE80211_NWID_LEN) { - error = EINVAL; - 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] = wreq.wi_val[0]; - memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], &wreq.wi_val[1], - wreq.wi_val[0]); - if (sc->sc_mib_local.Network_Mode || !sc->sc_no_bssid) - error = ENETRESET; - break; - case WI_RID_CURRENT_BSSID: - error = EPERM; - break; - case WI_RID_CHANNEL_LIST: - if (wreq.wi_len != 1) { - error = EINVAL; - break; - } - oregion = sc->sc_mib_phy.aCurrent_Reg_Domain; - if (wreq.wi_val[0] == oregion) - break; - sc->sc_mib_phy.aCurrent_Reg_Domain = wreq.wi_val[0]; - error = awi_init_region(sc); - if (error) { - sc->sc_mib_phy.aCurrent_Reg_Domain = oregion; - break; - } - error = ENETRESET; - break; - case WI_RID_OWN_CHNL: - if (wreq.wi_len != 1) { - error = EINVAL; - break; - } - if (wreq.wi_val[0] < sc->sc_scan_min || - wreq.wi_val[0] > sc->sc_scan_max) { - error = EINVAL; - break; - } - sc->sc_ownch = wreq.wi_val[0]; - if (!sc->sc_mib_local.Network_Mode) - error = ENETRESET; - break; - case WI_RID_CURRENT_CHAN: - error = EPERM; - break; - case WI_RID_COMMS_QUALITY: - error = EPERM; - break; - case WI_RID_PROMISC: - if (wreq.wi_len != 1) { - error = EINVAL; - break; - } - if (ifp->if_flags & IFF_PROMISC) { - if (wreq.wi_val[0] == 0) { - ifp->if_flags &= ~IFF_PROMISC; - error = ENETRESET; - } - } else { - if (wreq.wi_val[0] != 0) { - ifp->if_flags |= IFF_PROMISC; - error = ENETRESET; - } - } - break; - case WI_RID_PORTTYPE: - if (wreq.wi_len != 1) { - error = EINVAL; - break; - } - switch (wreq.wi_val[0]) { - case 1: - sc->sc_mib_local.Network_Mode = 1; - sc->sc_no_bssid = 0; - error = ENETRESET; - break; - case 2: - sc->sc_mib_local.Network_Mode = 0; - sc->sc_no_bssid = 0; - error = ENETRESET; - break; - case 3: - if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { - error = EINVAL; - break; - } - sc->sc_mib_local.Network_Mode = 0; - sc->sc_no_bssid = 1; - error = ENETRESET; - break; - default: - error = EINVAL; - break; - } - break; - case WI_RID_MAC_NODE: - /* XXX: should be implemented? */ - error = EPERM; - break; - case WI_RID_TX_RATE: - if (wreq.wi_len != 1) { - error = EINVAL; - break; - } - phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates; - switch (wreq.wi_val[0]) { - case 1: - case 2: - case 5: - case 11: - rate = wreq.wi_val[0] * 10; - if (rate == 50) - rate += 5; /*XXX*/ - break; - case 3: - case 6: - case 7: - /* auto rate */ - phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates; - rate = AWI_RATE_1MBIT; - for (i = 0; i < phy_rates[1]; i++) { - if (AWI_80211_RATE(phy_rates[2 + i]) > rate) - rate = AWI_80211_RATE(phy_rates[2 + i]); - } - break; - default: - rate = 0; - error = EINVAL; - break; - } - if (error) - break; - for (i = 0; i < phy_rates[1]; i++) { - if (rate == AWI_80211_RATE(phy_rates[2 + i])) - break; - } - if (i == phy_rates[1]) { - error = EINVAL; - break; - } - sc->sc_tx_rate = rate; - break; - case WI_RID_CUR_TX_RATE: - error = EPERM; - break; - case WI_RID_RTS_THRESH: - if (wreq.wi_len != 1) { - error = EINVAL; - break; - } - LE_WRITE_2(&sc->sc_mib_mac.aRTS_Threshold, wreq.wi_val[0]); - error = ENETRESET; - break; - case WI_RID_CREATE_IBSS: - if (wreq.wi_len != 1) { - error = EINVAL; - break; - } - sc->sc_start_bss = wreq.wi_val[0] ? 1 : 0; - error = ENETRESET; - break; - case WI_RID_SYSTEM_SCALE: - if (wreq.wi_len != 1) { - error = EINVAL; - break; - } - if (wreq.wi_val[0] != 1) - error = EINVAL; /* not supported */ - break; - case WI_RID_PM_ENABLED: - if (wreq.wi_len != 1) { - error = EINVAL; - break; - } - if (wreq.wi_val[0] != 0) - error = EINVAL; /* not implemented */ - break; - case WI_RID_MAX_SLEEP: - error = EINVAL; /* not implemented */ - break; - case WI_RID_WEP_AVAIL: - error = EPERM; - break; - case WI_RID_ENCRYPTION: - if (wreq.wi_len != 1) { - error = EINVAL; - break; - } - error = awi_wep_setalgo(sc, wreq.wi_val[0]); - if (error) - break; - error = ENETRESET; - break; - case WI_RID_TX_CRYPT_KEY: - if (wreq.wi_len != 1) { - error = EINVAL; - break; - } - if (wreq.wi_val[0] >= IEEE80211_WEP_NKID) { - error = EINVAL; - break; - } - sc->sc_wep_defkid = wreq.wi_val[1]; - break; - case WI_RID_DEFLT_CRYPT_KEYS: - if (wreq.wi_len != sizeof(*keys) / 2) { - error = EINVAL; - break; - } - keys = (struct wi_ltv_keys *)&wreq; - for (i = 0; i < IEEE80211_WEP_NKID; i++) { - k = &keys->wi_keys[i]; - error = awi_wep_setkey(sc, i, k->wi_keydat, - k->wi_keylen); - if (error) - break; - } - break; - case WI_RID_MAX_DATALEN: - if (wreq.wi_len != 1) { - error = EINVAL; - break; - } - if (wreq.wi_val[0] < 350 || wreq.wi_val[0] > 2304) { - error = EINVAL; - break; - } - LE_WRITE_2(&sc->sc_mib_mac.aMax_Frame_Length, wreq.wi_val[0]); - break; - case WI_RID_IFACE_STATS: - error = EPERM; - break; - default: - error = EINVAL; - break; - } - if (error == ENETRESET) { - if (sc->sc_enabled) { - awi_stop(sc); - error = awi_init(sc); - } else - error = 0; - } - return error; -} diff --git a/sys/dev/awi/awireg.h b/sys/dev/awi/awireg.h index dc936eb730ec..555e058b3d14 100644 --- a/sys/dev/awi/awireg.h +++ b/sys/dev/awi/awireg.h @@ -1,4 +1,4 @@ -/* $NetBSD: awireg.h,v 1.3 2000/03/22 11:22:22 onoe Exp $ */ +/* $NetBSD: awireg.h,v 1.8 2003/01/20 05:30:06 simonb Exp $ */ /* $FreeBSD$ */ /*- @@ -37,6 +37,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#ifndef _DEV_IC_AWIREG_H +#define _DEV_IC_AWIREG_H + /* * The firmware typically loaded onto Am79C930-based 802.11 interfaces * uses a 32k or larger shared memory buffer to communicate with the @@ -92,70 +95,65 @@ #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_INDEX 0x2 -#define AWI_CA_MIB_DATA 0x4 - -#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_CA_MIB_TYPE (AWI_CMD_PARAMS + 0x0) +#define AWI_CA_MIB_SIZE (AWI_CMD_PARAMS + 0x1) +#define AWI_CA_MIB_INDEX (AWI_CMD_PARAMS + 0x2) +#define AWI_CA_MIB_DATA (AWI_CMD_PARAMS + 0x4) +#define AWI_MIB_LOCAL 0 +#define AWI_MIB_ADDR 2 +#define AWI_MIB_MAC 3 +#define AWI_MIB_STAT 4 +#define AWI_MIB_MGT 5 +#define AWI_MIB_DRVR 6 +#define AWI_MIB_PHY 7 #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_PS 0xc -#define AWI_CA_TX_CF 0x10 +#define AWI_CA_TX_LEN 20 +#define AWI_CA_TX_DATA (AWI_CMD_PARAMS + 0x0) +#define AWI_CA_TX_MGT (AWI_CMD_PARAMS + 0x4) +#define AWI_CA_TX_BCAST (AWI_CMD_PARAMS + 0x8) +#define AWI_CA_TX_PS (AWI_CMD_PARAMS + 0xc) +#define AWI_CA_TX_CF (AWI_CMD_PARAMS + 0x10) #define AWI_CMD_FLUSH_TX 0x4 - -#define AWI_CA_FTX_LEN 0x5 -#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_CA_FTX_LEN 5 +#define AWI_CA_FTX_DATA (AWI_CMD_PARAMS + 0x0) +#define AWI_CA_FTX_MGT (AWI_CMD_PARAMS + 0x1) +#define AWI_CA_FTX_BCAST (AWI_CMD_PARAMS + 0x2) +#define AWI_CA_FTX_PS (AWI_CMD_PARAMS + 0x3) +#define AWI_CA_FTX_CF (AWI_CMD_PARAMS + 0x4) #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_CA_IRX_DATA_DESC (AWI_CMD_PARAMS + 0x0) /* return */ +#define AWI_CA_IRX_PS_DESC (AWI_CMD_PARAMS + 0x4) /* return */ #define AWI_CMD_KILL_RX 0x6 #define AWI_CMD_SLEEP 0x7 -#define AWI_CA_SLEEP_LEN 0x8 -#define AWI_CA_WAKEUP 0x0 /* uint64 */ +#define AWI_CA_SLEEP_LEN 8 +#define AWI_CA_WAKEUP (AWI_CMD_PARAMS + 0x0) /* uint64 */ #define AWI_CMD_WAKE 0x8 #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_PATTERN 0x3 -#define AWI_CA_SCAN_IDX 0x4 -#define AWI_CA_SCAN_SUSP 0x5 +#define AWI_CA_SCAN_LEN 6 +#define AWI_CA_SCAN_DURATION (AWI_CMD_PARAMS + 0x0) +#define AWI_CA_SCAN_SET (AWI_CMD_PARAMS + 0x2) +#define AWI_CA_SCAN_PATTERN (AWI_CMD_PARAMS + 0x3) +#define AWI_CA_SCAN_IDX (AWI_CMD_PARAMS + 0x4) +#define AWI_CA_SCAN_SUSP (AWI_CMD_PARAMS + 0x5) #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_STARTBSS 0x3 -#define AWI_CA_SYNC_DWELL 0x4 -#define AWI_CA_SYNC_MBZ 0x6 -#define AWI_CA_SYNC_TIMESTAMP 0x8 -#define AWI_CA_SYNC_REFTIME 0x10 +#define AWI_CA_SYNC_LEN 20 +#define AWI_CA_SYNC_SET (AWI_CMD_PARAMS + 0x0) +#define AWI_CA_SYNC_PATTERN (AWI_CMD_PARAMS + 0x1) +#define AWI_CA_SYNC_IDX (AWI_CMD_PARAMS + 0x2) +#define AWI_CA_SYNC_STARTBSS (AWI_CMD_PARAMS + 0x3) +#define AWI_CA_SYNC_DWELL (AWI_CMD_PARAMS + 0x4) +#define AWI_CA_SYNC_MBZ (AWI_CMD_PARAMS + 0x6) +#define AWI_CA_SYNC_TIMESTAMP (AWI_CMD_PARAMS + 0x8) +#define AWI_CA_SYNC_REFTIME (AWI_CMD_PARAMS + 0x10) #define AWI_CMD_RESUME 0xc @@ -228,7 +226,7 @@ #define AWI_INTMASK2 0x4fd /* Bits in AWI_INTSTAT2/INTMASK2 */ -#define AWI_INT2_RXMGT 0x80 /* mgt/ps recieved */ +#define AWI_INT2_RXMGT 0x80 /* mgt/ps received */ #define AWI_INT2_RXDATA 0x40 /* data received */ #define AWI_INT2_TXMGT 0x10 /* mgt tx done */ #define AWI_INT2_TXCF 0x08 /* CF tx done */ @@ -261,7 +259,9 @@ #define AWI_DRV_RXLED 0x40 #define AWI_DRV_TXLED 0x80 -#define AWI_VBM 0x500 /* Virtual Bit Map */ +#define AWI_VBM_OFFSET 0x500 /* Virtual Bit Map */ +#define AWI_VBM_LENGTH 0x501 +#define AWI_VBM_BITMAP 0x502 #define AWI_BUFFERS 0x600 /* Buffers */ #define AWI_BUFFERS_END 0x6000 @@ -357,7 +357,7 @@ struct awi_mib_local { u_int8_t Rx_Buffer_Size[4]; u_int8_t Acting_as_AP; u_int8_t Fill_CFP; -}; +} __attribute__((__packed__)); struct awi_mib_mac { u_int8_t _Reserved1[2]; @@ -379,7 +379,7 @@ struct awi_mib_mac { 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]; -}; +} __attribute__((__packed__)); struct awi_mib_stat { u_int8_t aTransmitted_MPDU_Count[4]; @@ -401,7 +401,7 @@ struct awi_mib_stat { u_int8_t aFCS_Error_Count[4]; u_int8_t aError_Count[4]; u_int8_t aWEP_Undecryptable_Count[4]; -}; +} __attribute__((__packed__)); struct awi_mib_mgt { u_int8_t aPower_Mgt_Mode; @@ -413,6 +413,8 @@ struct awi_mib_mgt { u_int8_t aDTIM_Period; u_int8_t aATIM_Window[2]; u_int8_t Wep_Required; +#define AWI_WEP_ON 0x10 +#define AWI_WEP_OFF 0x00 u_int8_t _Reserved1; u_int8_t aBeacon_Period[2]; u_int8_t aPassive_Scan_Duration[2]; @@ -425,7 +427,7 @@ struct awi_mib_mgt { 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]; -}; +} __attribute__((__packed__)); #define AWI_GROUP_ADDR_SIZE 4 struct awi_mib_addr { @@ -433,7 +435,7 @@ struct awi_mib_addr { u_int8_t aGroup_Addresses[AWI_GROUP_ADDR_SIZE][ETHER_ADDR_LEN]; u_int8_t aTransmit_Enable_Status; u_int8_t _Reserved1; -}; +} __attribute__((__packed__)); #define AWI_PWR_LEVEL_SIZE 4 struct awi_mib_phy { @@ -457,4 +459,6 @@ struct awi_mib_phy { #define AWI_PHY_TYPE_DS 2 #define AWI_PHY_TYPE_IR 3 u_int8_t RCR_33A_Bits[8]; -}; +} __attribute__((__packed__)); + +#endif /* _DEV_IC_AWIREG_H */ diff --git a/sys/dev/awi/awivar.h b/sys/dev/awi/awivar.h index 0fcf4e2d3576..b9f24e40773e 100644 --- a/sys/dev/awi/awivar.h +++ b/sys/dev/awi/awivar.h @@ -1,8 +1,8 @@ -/* $NetBSD: awivar.h,v 1.12 2000/07/21 04:48:56 onoe Exp $ */ +/* $NetBSD: awivar.h,v 1.20 2004/01/15 09:39:15 onoe Exp $ */ /* $FreeBSD$ */ /*- - * Copyright (c) 1999 The NetBSD Foundation, Inc. + * Copyright (c) 1999,2000,2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -37,6 +37,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#ifndef _DEV_IC_AWIVAR_H +#define _DEV_IC_AWIVAR_H + /* timer values in msec */ #define AWI_SELFTEST_TIMEOUT 5000 #define AWI_CMD_TIMEOUT 2000 @@ -45,96 +48,67 @@ #define AWI_ASCAN_WAIT 3000 #define AWI_PSCAN_DURATION 200 #define AWI_PSCAN_WAIT 5000 -#define AWI_TRANS_TIMEOUT 2000 +#define AWI_TRANS_TIMEOUT 5000 #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 +enum awi_sub_state { + AWI_ST_NONE, + AWI_ST_SCAN_INIT, + AWI_ST_SCAN_SETMIB, + AWI_ST_SCAN_SCCMD, + AWI_ST_SUB_INIT, + AWI_ST_SUB_SETSS, + AWI_ST_SUB_SYNC }; -struct awi_bss -{ - 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 AWI_WAIT 0 /* must wait for completion */ +#define AWI_NOWAIT 1 /* do not wait */ + +struct awi_chanset { + u_int8_t cs_type; + u_int8_t cs_region; + u_int8_t cs_min; + u_int8_t cs_max; + u_int8_t cs_def; }; -struct awi_wep_algo { - char *awa_name; - int (*awa_ctxlen)(void); - void (*awa_setkey)(void *, u_char *, int); - void (*awa_encrypt)(void *, u_char *, u_char *, int); - void (*awa_decrypt)(void *, u_char *, u_char *, int); -}; - -struct awi_softc -{ +struct awi_softc { #ifdef __NetBSD__ - struct device sc_dev; - struct ethercom sc_ec; - void *sc_ih; /* interrupt handler */ -#endif -#ifdef __FreeBSD__ -#if __FreeBSD_version >= 40000 - struct { - char dv_xname[64]; /*XXX*/ - } sc_dev; -#else struct device sc_dev; #endif - struct arpcom sc_ec; +#ifdef __FreeBSD__ + device_t sc_dev; #endif struct am79c930_softc sc_chip; - struct ifnet *sc_ifp; + struct ieee80211com sc_ic; + u_char sc_banner[AWI_BANNER_LEN]; int (*sc_enable)(struct awi_softc *); void (*sc_disable)(struct awi_softc *); + void (*sc_power)(struct awi_softc *, int); - struct ifmedia sc_media; - enum awi_status sc_status; - unsigned int sc_enabled:1, + int (*sc_newstate)(struct ieee80211com *, + enum ieee80211_state, int); + void (*sc_recv_mgmt)(struct ieee80211com *, + struct mbuf *, struct ieee80211_node *, + int, int, u_int32_t); + int (*sc_send_mgmt)(struct ieee80211com *, + struct ieee80211_node *, int, int); + + void *sc_sdhook; /* shutdown hook */ + void *sc_powerhook; /* power management hook */ + unsigned int sc_attached:1, + 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; + sc_adhoc_ap:1, + sc_invalid:1; + enum ieee80211_state sc_nstate; + enum awi_sub_state sc_substate; 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; + u_int8_t sc_cmd_inprog; + u_int8_t sc_cur_chan; int sc_rx_timer; u_int32_t sc_rxdoff; @@ -142,20 +116,11 @@ struct awi_softc 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_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; @@ -167,7 +132,8 @@ 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) -#define awi_read_bytes(sc, off, ptr, len) ((sc)->sc_chip.sc_ops->read_bytes)(&sc->sc_chip, off, ptr, len) +#define awi_read_bytes(sc, off, ptr, len) \ + ((sc)->sc_chip.sc_ops->read_bytes)(&sc->sc_chip, off, ptr, len) #define awi_write_1(sc, off, val) \ ((sc)->sc_chip.sc_ops->write_1)(&sc->sc_chip, off, val) @@ -182,59 +148,13 @@ struct awi_softc awi_write_1(sc, AWI_DRIVERSTATE, \ ((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(struct awi_softc *); -int awi_intr(void *); -void awi_reset(struct awi_softc *); +int awi_detach(struct awi_softc *); #ifdef __NetBSD__ int awi_activate(struct device *, enum devact); -int awi_detach(struct awi_softc *); -void awi_power(struct awi_softc *, int); +void awi_power(int, void *); #endif +void awi_shutdown(void *); +int awi_intr(void *); -void awi_stop(struct awi_softc *sc); -int awi_init(struct awi_softc *sc); -int awi_init_region(struct awi_softc *); -int awi_wicfg(struct ifnet *, u_long, caddr_t); - -#ifndef SIOCS80211NWKEY -/* - * This structure is part of the NetBSD public ioctl interface but - * used internally by the driver. Declare it here for non-NetBSD - * systems. - */ -/* the first member must be matched with struct ifreq */ -struct ieee80211_nwkey { - char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ - int i_wepon; /* wep enabled flag */ - int i_defkid; /* default encrypt key id */ - struct { - int i_keylen; - u_int8_t *i_keydat; - } i_key[IEEE80211_WEP_NKID]; -}; -#endif - -int awi_wep_setnwkey(struct awi_softc *, struct ieee80211_nwkey *); -int awi_wep_getnwkey(struct awi_softc *, struct ieee80211_nwkey *); -int awi_wep_getalgo(struct awi_softc *); -int awi_wep_setalgo(struct awi_softc *, int); -int awi_wep_setkey(struct awi_softc *, int, unsigned char *, int); -int awi_wep_getkey(struct awi_softc *, int, unsigned char *, int *); -struct mbuf *awi_wep_encrypt(struct awi_softc *, struct mbuf *, int); +#endif /* _DEV_IC_AWIVAR_H */ diff --git a/sys/dev/awi/if_awi_pccard.c b/sys/dev/awi/if_awi_pccard.c index 4b0887c61ed3..f29708dc2b9e 100644 --- a/sys/dev/awi/if_awi_pccard.c +++ b/sys/dev/awi/if_awi_pccard.c @@ -43,7 +43,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include #include @@ -80,6 +80,14 @@ static const struct pccard_product awi_pccard_products[] = { { NULL } }; +static int awi_pccard_match(device_t); +static int awi_pccard_probe(device_t); +static int awi_pccard_attach(device_t); +static int awi_pccard_detach(device_t); +static void awi_pccard_shutdown(device_t); +static int awi_pccard_enable(struct awi_softc *); +static void awi_pccard_disable(struct awi_softc *); + static int awi_pccard_match(device_t dev) { @@ -106,14 +114,15 @@ awi_pccard_probe(device_t dev) psc->sc_port_rid = 0; psc->sc_port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, - &psc->sc_port_rid, 0, ~0, 16, RF_ACTIVE); + &psc->sc_port_rid, 0, ~0, AM79C930_IO_SIZE, + rman_make_alignment_flags(AM79C930_IO_ALIGN) | RF_ACTIVE); if (!psc->sc_port_res) return ENOMEM; sc->sc_chip.sc_iot = rman_get_bustag(psc->sc_port_res); sc->sc_chip.sc_ioh = rman_get_bushandle(psc->sc_port_res); am79c930_chip_init(&sc->sc_chip, 0); - DELAY(1000); + tsleep(sc, PWAIT, "awiprb", 1); awi_read_bytes(sc, AWI_BANNER, psc->sc_version, AWI_BANNER_LEN); if (memcmp(psc->sc_version, "PCnetMobile:", 12) != 0) { @@ -124,6 +133,7 @@ awi_pccard_probe(device_t dev) device_set_desc(dev, psc->sc_version); bus_release_resource(dev, SYS_RES_IOPORT, psc->sc_port_rid, psc->sc_port_res); + psc->sc_port_res = 0; return error; } @@ -133,7 +143,6 @@ awi_pccard_attach(device_t dev) { struct awi_pccard_softc *psc = device_get_softc(dev); struct awi_softc *sc = &psc->sc_awi; - struct ifnet *ifp = &sc->sc_ec.ac_if; int error = 0; psc->sc_port_res = 0; @@ -141,13 +150,10 @@ awi_pccard_attach(device_t dev) psc->sc_mem_res = 0; psc->sc_intrhand = 0; - if_initname(ifp, device_get_name(dev), device_get_unit(dev)); - strlcpy(sc->sc_dev.dv_xname, ifp->if_xname, - sizeof(sc->sc_dev.dv_xname)); - psc->sc_port_rid = 0; psc->sc_port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, - &psc->sc_port_rid, 0, ~0, 16, RF_ACTIVE); + &psc->sc_port_rid, 0, ~0, 16, + rman_make_alignment_flags(64) | RF_ACTIVE); if (!psc->sc_port_res) { device_printf(dev, "awi_pccard_attach: port alloc failed\n"); goto fail; @@ -169,6 +175,7 @@ awi_pccard_attach(device_t dev) * XXX: awi needs to access memory with 8bit, * but pccardd apparently maps memory with MDF_16BITS flag. * So memory mapped access is disabled and use IO port instead. + * Also, memory mapping is not yet supported on pccard. */ psc->sc_mem_res = 0; #else @@ -182,43 +189,23 @@ awi_pccard_attach(device_t dev) } else am79c930_chip_init(&sc->sc_chip, 0); - error = bus_setup_intr(dev, psc->sc_irq_res, INTR_TYPE_NET, - (void (*)(void *))awi_intr, sc, &psc->sc_intrhand); - if (error) { - device_printf(dev, "awi_pccard_attach: intr setup failed\n"); - goto fail; - } - + sc->sc_dev = dev; sc->sc_cansleep = 1; - sc->sc_enabled = 1; - sc->sc_ifp = &sc->sc_ec.ac_if; + sc->sc_enable = awi_pccard_enable; + sc->sc_disable = awi_pccard_disable; + if (awi_pccard_enable(sc)) + goto fail; + sc->sc_enabled = 1; error = awi_attach(sc); sc->sc_enabled = 0; /*XXX*/ + awi_pccard_disable(sc); if (error == 0) return 0; device_printf(dev, "awi_pccard_attach: awi_attach failed\n"); fail: - if (psc->sc_intrhand) { - bus_teardown_intr(dev, psc->sc_irq_res, psc->sc_intrhand); - psc->sc_intrhand = 0; - } - if (psc->sc_port_res) { - bus_release_resource(dev, SYS_RES_IOPORT, psc->sc_port_rid, - psc->sc_port_res); - psc->sc_port_res = 0; - } - if (psc->sc_irq_res) { - bus_release_resource(dev, SYS_RES_IRQ, psc->sc_irq_rid, - psc->sc_irq_res); - psc->sc_irq_res = 0; - } - if (psc->sc_mem_res) { - bus_release_resource(dev, SYS_RES_MEMORY, psc->sc_mem_rid, - psc->sc_mem_res); - psc->sc_mem_res = 0; - } + awi_pccard_detach(dev); if (error == 0) error = ENXIO; return error; @@ -229,37 +216,72 @@ awi_pccard_detach(device_t dev) { struct awi_pccard_softc *psc = device_get_softc(dev); struct awi_softc *sc = &psc->sc_awi; - struct ifnet *ifp = &sc->sc_ec.ac_if; - ether_ifdetach(ifp); - ifp->if_flags &= ~IFF_RUNNING; - if (psc->sc_intrhand) { - bus_teardown_intr(dev, psc->sc_irq_res, psc->sc_intrhand); - psc->sc_intrhand = 0; - } - if (psc->sc_port_res) { - bus_release_resource(dev, SYS_RES_IOPORT, psc->sc_port_rid, - psc->sc_port_res); - psc->sc_port_res = 0; + awi_detach(sc); + if (psc->sc_mem_res) { + bus_release_resource(dev, SYS_RES_MEMORY, psc->sc_mem_rid, + psc->sc_mem_res); + psc->sc_mem_res = 0; } if (psc->sc_irq_res) { bus_release_resource(dev, SYS_RES_IRQ, psc->sc_irq_rid, psc->sc_irq_res); psc->sc_irq_res = 0; } - if (psc->sc_mem_res) { - bus_release_resource(dev, SYS_RES_MEMORY, psc->sc_mem_rid, - psc->sc_mem_res); - psc->sc_mem_res = 0; + if (psc->sc_port_res) { + bus_release_resource(dev, SYS_RES_IOPORT, psc->sc_port_rid, + psc->sc_port_res); + psc->sc_port_res = 0; } return 0; } +static void +awi_pccard_shutdown(device_t dev) +{ + struct awi_pccard_softc *psc = device_get_softc(dev); + struct awi_softc *sc = &psc->sc_awi; + + awi_shutdown(sc); +} + +static int +awi_pccard_enable(struct awi_softc *sc) +{ + device_t dev = sc->sc_dev; + struct awi_pccard_softc *psc = device_get_softc(dev); + int error; + + if (psc->sc_intrhand == 0) { + error = bus_setup_intr(dev, psc->sc_irq_res, INTR_TYPE_NET, + (void (*)(void *))awi_intr, sc, &psc->sc_intrhand); + if (error) { + device_printf(dev, + "couldn't establish interrupt error=%d\n", error); + return error; + } + } + return 0; +} + +static void +awi_pccard_disable(struct awi_softc *sc) +{ + device_t dev = sc->sc_dev; + struct awi_pccard_softc *psc = device_get_softc(dev); + + if (psc->sc_intrhand) { + bus_teardown_intr(dev, psc->sc_irq_res, psc->sc_intrhand); + psc->sc_intrhand = 0; + } +} + static device_method_t awi_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, pccard_compat_probe), DEVMETHOD(device_attach, pccard_compat_attach), DEVMETHOD(device_detach, awi_pccard_detach), + DEVMETHOD(device_shutdown, awi_pccard_shutdown), /* Card interface */ DEVMETHOD(card_compat_match, awi_pccard_match), @@ -278,4 +300,5 @@ static driver_t awi_pccard_driver = { extern devclass_t awi_devclass; DRIVER_MODULE(awi, pccard, awi_pccard_driver, awi_devclass, 0, 0); -MODULE_DEPEND(awi, rc4, 1, 1, 1); +MODULE_DEPEND(awi, wlan, 1, 1, 1); +MODULE_DEPEND(awi, pccard, 1, 1, 1); diff --git a/sys/modules/awi/Makefile b/sys/modules/awi/Makefile index 3ad8bd13067a..b0e743b7ee44 100644 --- a/sys/modules/awi/Makefile +++ b/sys/modules/awi/Makefile @@ -3,7 +3,7 @@ .PATH: ${.CURDIR}/../../dev/awi KMOD= if_awi -SRCS= am79c930.c awi.c awi_wep.c awi_wicfg.c if_awi_pccard.c +SRCS= am79c930.c awi.c if_awi_pccard.c SRCS+= bus_if.h card_if.h device_if.h opt_inet.h opt_inet.h: