diff options
| author | onoe <onoe@NetBSD.org> | 2002-09-30 06:50:35 +0000 |
|---|---|---|
| committer | onoe <onoe@NetBSD.org> | 2002-09-30 06:50:35 +0000 |
| commit | efe919010c18ebea4f5fbfb1f6e7d69e93475b47 (patch) | |
| tree | c433f5a73fa3e072b74909036ecd391bc72a4522 /sys/dev | |
| parent | 45667e55b990caaffeb582a60b3d57cb1289fe29 (diff) | |
Jumbo commit for wi driver.
- Eliminate wi_hostap.c since most of the code are duplicated with
net/if_ieee80211subr.c
- Station for Infrastructure network and IBSS also use service functions
as much as possible to be consistent with other wireless drivers.
Now WEP works for station/ibss/hostap.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/ic/wi.c | 4611 | ||||
| -rw-r--r-- | sys/dev/ic/wi_hostap.c | 1338 | ||||
| -rw-r--r-- | sys/dev/ic/wi_hostap.h | 144 | ||||
| -rw-r--r-- | sys/dev/ic/wireg.h | 310 | ||||
| -rw-r--r-- | sys/dev/ic/wivar.h | 226 |
5 files changed, 1716 insertions, 4913 deletions
diff --git a/sys/dev/ic/wi.c b/sys/dev/ic/wi.c index ca1e8686b56..2803a178fbb 100644 --- a/sys/dev/ic/wi.c +++ b/sys/dev/ic/wi.c @@ -1,4 +1,4 @@ -/* $NetBSD: wi.c,v 1.89 2002/09/30 06:29:29 onoe Exp $ */ +/* $NetBSD: wi.c,v 1.90 2002/09/30 06:50:35 onoe Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -70,7 +70,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.89 2002/09/30 06:29:29 onoe Exp $"); +__KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.90 2002/09/30 06:50:35 onoe Exp $"); #define WI_HERMES_AUTOINC_WAR /* Work around data write autoinc bug. */ #define WI_HERMES_STATS_WAR /* Work around stats counter bug. */ @@ -89,7 +89,6 @@ __KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.89 2002/09/30 06:29:29 onoe Exp $"); #include <net/if.h> #include <net/if_dl.h> -#include <net/if_llc.h> #include <net/if_media.h> #include <net/if_ether.h> #include <net/if_ieee80211.h> @@ -105,57 +104,62 @@ __KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.89 2002/09/30 06:29:29 onoe Exp $"); #include <dev/ic/wireg.h> #include <dev/ic/wivar.h> -static void wi_tap_802_11_plus __P((struct wi_softc *, struct mbuf *)); -static void wi_tap_802_3 __P((struct wi_softc *, struct mbuf *, - struct wi_frame *)); -static void wi_reset __P((struct wi_softc *)); -static int wi_ioctl __P((struct ifnet *, u_long, caddr_t)); -static void wi_start __P((struct ifnet *)); -static void wi_watchdog __P((struct ifnet *)); -static int wi_init __P((struct ifnet *)); -static void wi_stop __P((struct ifnet *, int)); -static void wi_rxeof __P((struct wi_softc *)); -static void wi_txeof __P((struct wi_softc *, int)); -static void wi_update_stats __P((struct wi_softc *)); -static void wi_setmulti __P((struct wi_softc *)); - -static int wi_cmd __P((struct wi_softc *, int, int, int, int)); -static int wi_read_record __P((struct wi_softc *, struct wi_ltv_gen *)); -static int wi_write_record __P((struct wi_softc *, struct wi_ltv_gen *)); -static int wi_read_data __P((struct wi_softc *, int, - int, caddr_t, int)); -#if defined(OPTIMIZE_RW_DATA) -static void wi_rewind __P((struct wi_softc *)); +static int wi_init(struct ifnet *); +static void wi_stop(struct ifnet *, int); +static void wi_start(struct ifnet *); +static int wi_reset(struct wi_softc *); +static void wi_watchdog(struct ifnet *); +static int wi_ioctl(struct ifnet *, u_long, caddr_t); +static int wi_media_change(struct ifnet *); +static void wi_media_status(struct ifnet *, struct ifmediareq *); + +static void wi_rx_intr(struct wi_softc *); +static void wi_tx_intr(struct wi_softc *); +static void wi_info_intr(struct wi_softc *); + +static int wi_get_cfg(struct ifnet *, u_long, caddr_t); +static int wi_set_cfg(struct ifnet *, u_long, caddr_t); +static int wi_write_txrate(struct wi_softc *); +static int wi_write_wep(struct wi_softc *); +static int wi_write_multi(struct wi_softc *); +static int wi_alloc_fid(struct wi_softc *, int, int *); +static void wi_read_nicid(struct wi_softc *); +static int wi_write_ssid(struct wi_softc *, int, u_int8_t *, int); + +static int wi_cmd(struct wi_softc *, int, int, int, int); +static int wi_seek_bap(struct wi_softc *, int, int); +static int wi_read_bap(struct wi_softc *, int, int, void *, int); +static int wi_write_bap(struct wi_softc *, int, int, void *, int); +static int wi_read_rid(struct wi_softc *, int, void *, int *); +static int wi_write_rid(struct wi_softc *, int, void *, int); + +static int wi_newstate(void *, enum ieee80211_state); + +static int wi_scan_ap(struct wi_softc *); +static void wi_scan_result(struct wi_softc *, int, int); + +static inline int +wi_write_val(struct wi_softc *sc, int rid, u_int16_t val) +{ + + val = htole16(val); + return wi_write_rid(sc, rid, &val, sizeof(val)); +} + +#ifdef WI_DEBUG +int wi_debug = 0; + +#define DPRINTF(X) if (wi_debug) printf X +#define DPRINTF2(X) if (wi_debug > 1) printf X +#else +#define DPRINTF(X) +#define DPRINTF2(X) #endif -static int wi_write_data __P((struct wi_softc *, int, - int, caddr_t, int)); -static int wi_seek __P((struct wi_softc *, int, int, int)); -static int wi_alloc_nicmem __P((struct wi_softc *, int, int *)); -static void wi_inquire __P((void *)); -static void wi_wait_scan __P((void *)); -static int wi_setdef __P((struct wi_softc *, struct wi_req *)); -static int wi_getdef __P((struct wi_softc *, struct wi_req *)); - -static int wi_media_change __P((struct ifnet *)); -static void wi_media_status __P((struct ifnet *, struct ifmediareq *)); - -static void wi_get_id __P((struct wi_softc *)); - -static int wi_set_ssid __P((struct ieee80211_nwid *, u_int8_t *, int)); -static void wi_request_fill_ssid __P((struct wi_req *, - struct ieee80211_nwid *)); -static int wi_write_ssid __P((struct wi_softc *, int, struct wi_req *, - struct ieee80211_nwid *)); -static int wi_set_nwkey __P((struct wi_softc *, struct ieee80211_nwkey *)); -static int wi_get_nwkey __P((struct wi_softc *, struct ieee80211_nwkey *)); -static int wi_sync_media __P((struct wi_softc *, int, int)); -static int wi_set_pm __P((struct wi_softc *, struct ieee80211_power *)); -static int wi_get_pm __P((struct wi_softc *, struct ieee80211_power *)); -static int wi_get_channel __P((struct wi_softc *, struct ieee80211_channel *)); -static int wi_set_channel __P((struct wi_softc *, struct ieee80211_channel *)); -static int wi_join_bss __P((struct wi_softc *)); - -struct wi_card_ident wi_card_ident[] = { + +#define WI_INTRS (WI_EV_RX | WI_EV_ALLOC | WI_EV_INFO) + +struct wi_card_ident +wi_card_ident[] = { /* CARD_ID CARD_NAME FIRM_TYPE */ { WI_NIC_LUCENT_ID, WI_NIC_LUCENT_STR, WI_LUCENT }, { WI_NIC_SONY_ID, WI_NIC_SONY_STR, WI_LUCENT }, @@ -185,59 +189,44 @@ struct wi_card_ident wi_card_ident[] = { { 0, NULL, 0 }, }; -static const u_int8_t zero_bssid[6] = {0, 0, 0, 0, 0, 0}; - int -wi_attach(sc) - struct wi_softc *sc; +wi_attach(struct wi_softc *sc) { - struct ifnet *ifp = &sc->sc_if; - const char *sep = ""; - int i, nrate; - u_int8_t *r; - struct wi_ltv_macaddr mac; - struct wi_ltv_gen gen; - struct wi_ltv_str rate; - static const u_int8_t empty_macaddr[ETHER_ADDR_LEN] = { + struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = &ic->ic_if; + int i, nrate, mword, buflen; + u_int8_t r; + u_int16_t val; + u_int8_t ratebuf[2 + IEEE80211_RATE_SIZE]; + static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; int s; s = splnet(); - callout_init(&sc->wi_inquire_ch); - callout_init(&sc->wi_scan_sh); - /* Make sure interrupts are disabled. */ CSR_WRITE_2(sc, WI_INT_EN, 0); - CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); + CSR_WRITE_2(sc, WI_EVENT_ACK, ~0); /* Reset the NIC. */ - wi_reset(sc); - - memset(&mac, 0, sizeof(mac)); - /* Read the station address. */ - mac.wi_type = WI_RID_MAC_NODE; - mac.wi_len = 4; - wi_read_record(sc, (struct wi_ltv_gen *)&mac); - memcpy(sc->sc_macaddr, mac.wi_mac_addr, ETHER_ADDR_LEN); + if (wi_reset(sc) != 0) { + splx(s); + return 1; + } - /* - * Check if we got anything meaningful. - * - * Is it really enough just checking against null ethernet address? - * Or, check against possible vendor? XXX. - */ - if (memcmp(sc->sc_macaddr, empty_macaddr, ETHER_ADDR_LEN) == 0) { - printf("could not get mac address, attach failed\n"); + buflen = IEEE80211_ADDR_LEN; + if (wi_read_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, &buflen) != 0 || + IEEE80211_ADDR_EQ(ic->ic_myaddr, empty_macaddr)) { + printf(" could not get mac address, attach failed\n"); splx(s); return 1; } - printf(" 802.11 address %s\n", ether_sprintf(sc->sc_macaddr)); + printf(" 802.11 address %s\n", ether_sprintf(ic->ic_myaddr)); /* Read NIC identification */ - wi_get_id(sc); + wi_read_nicid(sc); memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); ifp->if_softc = sc; @@ -246,200 +235,133 @@ wi_attach(sc) ifp->if_watchdog = wi_watchdog; ifp->if_init = wi_init; ifp->if_stop = wi_stop; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; -#ifdef IFF_NOTRAILERS - ifp->if_flags |= IFF_NOTRAILERS; -#endif + ifp->if_flags = + IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST | IFF_NOTRAILERS; IFQ_SET_READY(&ifp->if_snd); - (void)wi_set_ssid(&sc->wi_nodeid, WI_DEFAULT_NODENAME, - sizeof(WI_DEFAULT_NODENAME) - 1); - (void)wi_set_ssid(&sc->wi_netid, WI_DEFAULT_NETNAME, - sizeof(WI_DEFAULT_NETNAME) - 1); - (void)wi_set_ssid(&sc->wi_ibssid, WI_DEFAULT_IBSS, - sizeof(WI_DEFAULT_IBSS) - 1); - - sc->wi_portnum = WI_DEFAULT_PORT; - sc->wi_ptype = WI_PORTTYPE_BSS; - sc->wi_ap_density = WI_DEFAULT_AP_DENSITY; - sc->wi_rts_thresh = WI_DEFAULT_RTS_THRESH; - sc->wi_tx_rate = WI_DEFAULT_TX_RATE; - sc->wi_max_data_len = WI_DEFAULT_DATALEN; - sc->wi_create_ibss = WI_DEFAULT_CREATE_IBSS; - sc->wi_pm_enabled = WI_DEFAULT_PM_ENABLED; - sc->wi_max_sleep = WI_DEFAULT_MAX_SLEEP; - sc->wi_roaming = WI_DEFAULT_ROAMING; - sc->wi_authtype = WI_DEFAULT_AUTHTYPE; - - /* - * Read the default channel from the NIC. This may vary - * depending on the country where the NIC was purchased, so - * we can't hard-code a default and expect it to work for - * everyone. - */ - gen.wi_type = WI_RID_OWN_CHNL; - gen.wi_len = 2; - wi_read_record(sc, &gen); - sc->wi_create_channel = sc->wi_join_channel = le16toh(gen.wi_val); - - memset((char *)&sc->wi_stats, 0, sizeof(sc->wi_stats)); - - /* AP info was filled with 0 */ - memset((char *)&sc->wi_aps, 0, sizeof(sc->wi_aps)); - sc->wi_scanning = 0; - sc->wi_naps = 0; + ic->ic_phytype = IEEE80211_T_DS; + ic->ic_opmode = IEEE80211_M_STA; + ic->ic_flags = IEEE80211_F_HASPMGT; + ic->ic_state = IEEE80211_S_INIT; + ic->ic_newstate = wi_newstate; + + /* Find available channel */ + buflen = sizeof(val); + if (wi_read_rid(sc, WI_RID_CHANNEL_LIST, &val, &buflen) != 0) + val = htole16(0x1fff); /* assume 1-11 */ + for (i = 0; i < 16; i++) { + if (isset((u_int8_t*)&val, i)) + setbit(ic->ic_chan_avail, i + 1); + } + + /* Find default IBSS channel */ + buflen = sizeof(val); + if (wi_read_rid(sc, WI_RID_OWN_CHNL, &val, &buflen) == 0) + ic->ic_ibss_chan = le16toh(val); + else { + /* use lowest available channel */ + for (i = 0; i < 16; i++) { + if (isset(ic->ic_chan_avail, i)) + break; + } + ic->ic_ibss_chan = i; + } /* * Set flags based on firmware version. */ switch (sc->sc_firmware_type) { case WI_LUCENT: - sc->wi_flags |= WI_FLAGS_HAS_ROAMING; - if (sc->sc_sta_firmware_ver >= 60000) - sc->wi_flags |= WI_FLAGS_HAS_MOR; - if (sc->sc_sta_firmware_ver >= 60006) { - sc->wi_flags |= WI_FLAGS_HAS_IBSS; - sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS; + sc->sc_flags |= WI_FLAGS_HAS_SYSSCALE; +#ifdef WI_HERMES_AUTOINC_WAR + /* XXX: not confirmed, but never seen for recent firmware */ + if (sc->sc_sta_firmware_ver < 40000) { + sc->sc_flags |= WI_FLAGS_BUG_AUTOINC; } - sc->wi_ibss_port = htole16(1); +#endif + if (sc->sc_sta_firmware_ver >= 60000) + sc->sc_flags |= WI_FLAGS_HAS_MOR; + if (sc->sc_sta_firmware_ver >= 60006) + ic->ic_flags |= IEEE80211_F_HASIBSS; + sc->sc_ibss_port = 1; break; case WI_INTERSIL: - sc->wi_flags |= WI_FLAGS_HAS_ROAMING; + sc->sc_flags |= WI_FLAGS_HAS_ROAMING; + sc->sc_flags |= WI_FLAGS_HAS_SYSSCALE; if (sc->sc_sta_firmware_ver >= 800) { - sc->wi_flags |= WI_FLAGS_HAS_HOSTAP; - sc->wi_flags |= WI_FLAGS_HAS_IBSS; -#if 0 /* Prism firmware interprets Create IBSS differently than we thought. */ - sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS; -#endif + ic->ic_flags |= IEEE80211_F_HASHAP; + ic->ic_flags |= IEEE80211_F_HASIBSS; } - sc->wi_ibss_port = htole16(0); + sc->sc_ibss_port = 0; break; case WI_SYMBOL: - sc->wi_flags |= WI_FLAGS_HAS_DIVERSITY; - if (sc->sc_sta_firmware_ver >= 20000) - sc->wi_flags |= WI_FLAGS_HAS_IBSS; -#if 0 /* Prism firmware interprets Create IBSS differently than we thought. */ + sc->sc_flags |= WI_FLAGS_HAS_DIVERSITY; if (sc->sc_sta_firmware_ver >= 25000) - sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS; -#endif - sc->wi_ibss_port = htole16(4); + ic->ic_flags |= IEEE80211_F_HASIBSS; + sc->sc_ibss_port = 4; break; } /* * Find out if we support WEP on this card. */ - gen.wi_type = WI_RID_WEP_AVAIL; - gen.wi_len = 2; - if (wi_read_record(sc, &gen) == 0 && - gen.wi_val != le16toh(0)) - sc->wi_flags |= WI_FLAGS_HAS_WEP; - - gen.wi_type = WI_RID_CHANNEL_LIST; - gen.wi_len = 2; - if (wi_read_record(sc, &gen) == 0) - sc->wi_channels = le16toh(gen.wi_val); - else - sc->wi_channels = (1 << 14) - 1; /* assume all 14 channels */ + buflen = sizeof(val); + if (wi_read_rid(sc, WI_RID_WEP_AVAIL, &val, &buflen) == 0 && + val != htole16(0)) + ic->ic_flags |= IEEE80211_F_HASWEP; /* Find supported rates. */ - rate.wi_type = WI_RID_DATA_RATES; - rate.wi_len = 6; - if (wi_read_record(sc, (struct wi_ltv_gen *)&rate) == 0) { - nrate = le16toh(rate.wi_str[0]); - r = (u_int8_t *)&rate.wi_str[1]; - for (i = 0; i < nrate; i++) { - switch (r[i] & IEEE80211_RATE_VAL) { - case 2: - sc->wi_supprates |= WI_SUPPRATES_1M; - break; - case 4: - sc->wi_supprates |= WI_SUPPRATES_2M; - break; - case 11: - sc->wi_supprates |= WI_SUPPRATES_5M; - break; - case 22: - sc->wi_supprates |= WI_SUPPRATES_11M; - break; - } - } + buflen = sizeof(ratebuf); + if (wi_read_rid(sc, WI_RID_DATA_RATES, ratebuf, &buflen) == 0) { + nrate = le16toh(*(u_int16_t *)ratebuf); + if (nrate > IEEE80211_RATE_SIZE) + nrate = IEEE80211_RATE_SIZE; + memcpy(ic->ic_sup_rates, ratebuf + 2, nrate); } + buflen = sizeof(val); + + sc->sc_max_datalen = 2304; + sc->sc_rts_thresh = 2347; + sc->sc_system_scale = 1; + sc->sc_cnfauthmode = 1; + sc->sc_roaming_mode = 1; ifmedia_init(&sc->sc_media, 0, wi_media_change, wi_media_status); - if (sc->wi_supprates != 0) - printf("%s: supported rates: ", sc->sc_dev.dv_xname); + printf("%s: supported rates: ", sc->sc_dev.dv_xname); #define ADD(s, o) ifmedia_add(&sc->sc_media, \ IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL) -#define PRINT(n) printf("%s%s", sep, (n)); sep = ", " ADD(IFM_AUTO, 0); - if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP) + if (ic->ic_flags & IEEE80211_F_HASHAP) ADD(IFM_AUTO, IFM_IEEE80211_HOSTAP); - if (sc->wi_flags & WI_FLAGS_HAS_IBSS) + if (ic->ic_flags & IEEE80211_F_HASIBSS) ADD(IFM_AUTO, IFM_IEEE80211_ADHOC); ADD(IFM_AUTO, IFM_IEEE80211_ADHOC | IFM_FLAG0); - if (sc->wi_supprates & WI_SUPPRATES_1M) { - PRINT("1Mbps"); - ADD(IFM_IEEE80211_DS1, 0); - if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP) - ADD(IFM_IEEE80211_DS1, IFM_IEEE80211_HOSTAP); - if (sc->wi_flags & WI_FLAGS_HAS_IBSS) - ADD(IFM_IEEE80211_DS1, IFM_IEEE80211_ADHOC); - ADD(IFM_IEEE80211_DS1, IFM_IEEE80211_ADHOC | IFM_FLAG0); - } - if (sc->wi_supprates & WI_SUPPRATES_2M) { - PRINT("2Mbps"); - ADD(IFM_IEEE80211_DS2, 0); - if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP) - ADD(IFM_IEEE80211_DS2, IFM_IEEE80211_HOSTAP); - if (sc->wi_flags & WI_FLAGS_HAS_IBSS) - ADD(IFM_IEEE80211_DS2, IFM_IEEE80211_ADHOC); - ADD(IFM_IEEE80211_DS2, IFM_IEEE80211_ADHOC | IFM_FLAG0); - } - if (sc->wi_supprates & WI_SUPPRATES_5M) { - PRINT("5.5Mbps"); - ADD(IFM_IEEE80211_DS5, 0); - if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP) - ADD(IFM_IEEE80211_DS5, IFM_IEEE80211_HOSTAP); - if (sc->wi_flags & WI_FLAGS_HAS_IBSS) - ADD(IFM_IEEE80211_DS5, IFM_IEEE80211_ADHOC); - ADD(IFM_IEEE80211_DS5, IFM_IEEE80211_ADHOC | IFM_FLAG0); - } - if (sc->wi_supprates & WI_SUPPRATES_11M) { - PRINT("11Mbps"); - ADD(IFM_IEEE80211_DS11, 0); - if (sc->wi_flags & WI_FLAGS_HAS_HOSTAP) - ADD(IFM_IEEE80211_DS11, IFM_IEEE80211_HOSTAP); - if (sc->wi_flags & WI_FLAGS_HAS_IBSS) - ADD(IFM_IEEE80211_DS11, IFM_IEEE80211_ADHOC); - ADD(IFM_IEEE80211_DS11, IFM_IEEE80211_ADHOC | IFM_FLAG0); - } - if (sc->wi_supprates != 0) - printf("\n"); + for (i = 0; i < nrate; i++) { + r = ic->ic_sup_rates[i]; + mword = ieee80211_rate2media(r, IEEE80211_T_DS); + if (mword == 0) + continue; + printf("%s%d%sMbps", (i != 0 ? " " : ""), + (r & IEEE80211_RATE_VAL) / 2, ((r & 0x1) != 0 ? ".5" : "")); + ADD(mword, 0); + if (ic->ic_flags & IEEE80211_F_HASHAP) + ADD(mword, IFM_IEEE80211_HOSTAP); + if (ic->ic_flags & IEEE80211_F_HASIBSS) + ADD(mword, IFM_IEEE80211_ADHOC); + ADD(mword, IFM_IEEE80211_ADHOC | IFM_FLAG0); + } + printf("\n"); ifmedia_set(&sc->sc_media, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0)); #undef ADD -#undef PRINT /* * Call MI attach routines. */ - if_attach(ifp); - ether_ifattach(ifp, sc->sc_macaddr); - ifp->if_baudrate = IF_Mbps(2); - -#if NBPFILTER > 0 - bpfattach2(ifp, DLT_IEEE802_11, sizeof(struct ieee80211_frame), - (caddr_t*) &sc->sc_bpf80211); - if (sc->sc_firmware_type == WI_INTERSIL || - sc->sc_firmware_type == WI_SYMBOL) { - bpfattach2(ifp, DLT_PRISM_HEADER, - WI_HWSPEC_END + sizeof(struct ieee80211_frame), - (caddr_t*) &sc->sc_bpf80211plus); - } -#endif + if_attach(ifp); + ieee80211_ifattach(ifp); /* Attach is successful. */ sc->sc_attached = 1; @@ -448,889 +370,110 @@ wi_attach(sc) return 0; } -static void -wi_tap_802_11_plus(struct wi_softc *sc, struct mbuf *m) -{ - if (sc->sc_bpf80211plus) { - bpf_mtap((caddr_t) sc->sc_bpf80211plus, m); - } - if (sc->sc_bpf80211) { - - /* trim off hardware-specific frame header */ - m->m_pkthdr.len -= WI_HWSPEC_END; - m->m_len -= WI_HWSPEC_END; - m->m_data += WI_HWSPEC_END; - - bpf_mtap((caddr_t) sc->sc_bpf80211, m); - - /* restore hardware-specific frame header */ - m->m_data -= WI_HWSPEC_END; - m->m_len += WI_HWSPEC_END; - m->m_pkthdr.len += WI_HWSPEC_END; - } -} - -static void -wi_tap_802_3(struct wi_softc *sc, struct mbuf *m, struct wi_frame *hwframe) -{ - int encrypted; - struct llc llc; - struct mbuf m0, m1; - struct ether_header *eh; - - /* hand up 802.3 frame */ - if (sc->sc_if.if_bpf) { - bpf_mtap(sc->sc_if.if_bpf, m); - } - - if (m->m_len < sizeof(struct ether_header)) { - printf("%s: inconsistent 802.3 mbuf, only %d bytes", - sc->sc_dev.dv_xname, m->m_len); - return; - } - - eh = mtod(m, struct ether_header *); - - 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; - - /* add to chain one mbuf for hardware-specific and 802.11 header, - * one for SNAP. - */ - m0.m_pkthdr = m->m_pkthdr; - m0.m_flags = m->m_flags & M_COPYFLAGS; - m0.m_next = &m1; - - m1.m_next = m; - m1.m_data = (caddr_t) &llc; - m1.m_len = sizeof(struct llc); - - /* omit 802.3 header */ - m->m_len -= sizeof(struct ether_header); - m->m_data += sizeof(struct ether_header); - - /* do not indicate WEP-encryption to bpf. */ - encrypted = hwframe->wi_frame_ctl & htole16(WI_FCTL_WEP); - hwframe->wi_frame_ctl &= ~htole16(WI_FCTL_WEP); - - /* hand up hardware-specific frame */ - if (sc->sc_bpf80211plus) { - - m0.m_data = (caddr_t) hwframe; - m0.m_len = WI_SHORT_802_11_END; - - m0.m_pkthdr.len = m->m_pkthdr.len + WI_SHORT_802_11_END + - sizeof(struct llc) - sizeof(struct ether_header); - - if ((hwframe->wi_frame_ctl & htole16(WI_FCTL_FROMDS)) && - (hwframe->wi_frame_ctl & htole16(WI_FCTL_TODS))) { - m0.m_pkthdr.len += - WI_LONG_802_11_END - WI_SHORT_802_11_END; - m0.m_len += WI_LONG_802_11_END - WI_SHORT_802_11_END; - } - bpf_mtap((caddr_t) sc->sc_bpf80211plus, &m0); - } - - /* hand up 802.11 frame */ - if (sc->sc_bpf80211) { - - m0.m_data = (caddr_t) hwframe + WI_802_11_BEGIN; - m0.m_len = (WI_SHORT_802_11_END - WI_802_11_BEGIN); - - m0.m_pkthdr.len = m->m_pkthdr.len + - (WI_SHORT_802_11_END - WI_802_11_BEGIN) + - sizeof(struct llc) - sizeof(struct ether_header); - - if ((hwframe->wi_frame_ctl & htole16(WI_FCTL_FROMDS)) && - (hwframe->wi_frame_ctl & htole16(WI_FCTL_TODS))) { - m0.m_pkthdr.len += - WI_LONG_802_11_END - WI_SHORT_802_11_END; - m0.m_len += WI_LONG_802_11_END - WI_SHORT_802_11_END; - } - bpf_mtap((caddr_t) sc->sc_bpf80211, &m0); - } - - if (encrypted) { - /* restore WEP indication. */ - hwframe->wi_frame_ctl |= htole16(WI_FCTL_WEP); - } - - /* restore 802.3 header */ - m->m_data -= sizeof(struct ether_header); - m->m_len += sizeof(struct ether_header); - - return; -} - -static int -wi_rx_rfc1042(struct wi_softc *sc, int id, struct wi_frame *frame, - struct llc *llc, struct mbuf *m, int maxlen) -{ - struct ether_header *eh; - struct ifnet *ifp; - int read_ofs, read_len; - caddr_t read_ptr; - - ifp = &sc->sc_if; - eh = mtod(m, struct ether_header *); - - read_len = le16toh(frame->wi_dat_len) - sizeof(struct llc); - - if (read_len + sizeof(struct ether_header) > maxlen) { - printf("%s: wi_rx_rfc1042: oversized packet received " - "(wi_dat_len=%d, wi_status=0x%x)\n", sc->sc_dev.dv_xname, - le16toh(frame->wi_dat_len), le16toh(frame->wi_status)); - m_freem(m); - ifp->if_ierrors++; - return -1; - } - m->m_pkthdr.len = m->m_len = read_len + sizeof(struct ether_header); - - /* XXX use 802.11 dst, src, etc.? */ - (void)memcpy(&eh->ether_dhost, &frame->wi_dst_addr, ETHER_ADDR_LEN); - (void)memcpy(&eh->ether_shost, &frame->wi_src_addr, ETHER_ADDR_LEN); - eh->ether_type = llc->llc_snap.ether_type; - - read_ptr = (caddr_t) (eh + 1); - read_ofs = sizeof(struct wi_frame) + sizeof(struct llc); - - if (wi_read_data(sc, id, read_ofs, read_ptr, read_len)) { - m_freem(m); - ifp->if_ierrors++; - return -1; - } - - return 0; -} - -/* for wi_rx_ethii, llc points to 8 arbitrary bytes. */ -static int -wi_rx_ethii(struct wi_softc *sc, int id, struct wi_frame *frame, - struct llc *llc, struct mbuf *m, int maxlen) +int +wi_detach(struct wi_softc *sc) { - struct ifnet *ifp; -#if 0 - int read_ofs, read_len; - caddr_t read_ptr; -#endif - struct ether_header *eh; - - ifp = &sc->sc_if; - eh = mtod(m, struct ether_header *); - - if (le16toh(frame->wi_dat_len) + sizeof(struct ether_header) > maxlen) { - printf("%s: wi_rx_ethii: oversized packet received " - "(wi_dat_len=%d, wi_status=0x%x)\n", sc->sc_dev.dv_xname, - le16toh(frame->wi_dat_len), le16toh(frame->wi_status)); - m_freem(m); - ifp->if_ierrors++; - return -1; - } - m->m_pkthdr.len = m->m_len = sizeof(struct ether_header) + - le16toh(frame->wi_dat_len); - -#if 0 - (void)memcpy(&eh->ether_dhost, &frame->wi_dst_addr, ETHER_ADDR_LEN); - (void)memcpy(&eh->ether_shost, &frame->wi_src_addr, ETHER_ADDR_LEN); - eh->ether_type = frame->wi_len; - - read_ptr = mtod(m, caddr_t) + sizeof(struct ether_header) + - sizeof(struct llc); - read_ofs = sizeof(struct wi_frame) + sizeof(struct llc); - read_len = le16toh(frame->wi_dat_len) - sizeof(struct llc); - - if (ifp->if_flags & IFF_DEBUG) - printf("%s: frame->wi_dat_len = %d, frame->wi_len = %d\n", - sc->sc_dev.dv_xname, le16toh(frame->wi_dat_len), - frame->wi_len); - - (void)memcpy(mtod(m, caddr_t), (u_int8_t*)frame + WI_802_3_BEGIN, - sizeof(struct ether_header)); - - if (ifp->if_flags & IFF_DEBUG) - printf("%s: eh->ether_type = %d\n", sc->sc_dev.dv_xname, - eh->ether_type); - - (void)memcpy(mtod(m, caddr_t) + sizeof(struct ether_header), llc, - sizeof(struct llc)); - - if (wi_read_data(sc, id, read_ofs, read_ptr, read_len)) { -#else - if (wi_read_data(sc, id, WI_802_3_BEGIN, mtod(m, caddr_t), m->m_len)) { -#endif - m_freem(m); - ifp->if_ierrors++; - return -1; - } - if (ifp->if_flags & IFF_DEBUG) - printf("%s: 2nd eh->ether_type = %d\n", sc->sc_dev.dv_xname, - eh->ether_type); - - return 0; -} + struct ifnet *ifp = &sc->sc_ic.ic_if; + int s; -static int -wi_rx_mgmt(struct wi_softc *sc, int id, struct wi_frame *frame, struct llc *llc, - struct mbuf *m, int maxlen) -{ - int read_ofs, read_len; - caddr_t read_ptr; - struct ifnet *ifp; - - ifp = &sc->sc_if; - - if (le16toh(frame->wi_dat_len) + WI_SHORT_802_11_END > maxlen) { - printf("%s: oversized packet received in " - "Host-AP mode (wi_dat_len=%d, wi_status=0x%x)\n", - sc->sc_dev.dv_xname, - le16toh(frame->wi_dat_len), - le16toh(frame->wi_status)); - m_freem(m); - ifp->if_ierrors++; - return -1; - } + if (!sc->sc_attached) + return 0; - /* Put the whole header in there. */ - (void)memcpy(mtod(m, void *), frame, sizeof(struct wi_frame)); - (void)memcpy(mtod(m, caddr_t) + WI_SHORT_802_11_END, llc, - sizeof(struct llc)); + s = splnet(); - read_ptr = mtod(m, caddr_t) + WI_SHORT_802_11_END + sizeof(struct llc); - read_ofs = sizeof(struct wi_frame) + sizeof(struct llc); - read_len = le16toh(frame->wi_dat_len) - sizeof(struct llc); + /* Delete all remaining media. */ + ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); - if (wi_read_data(sc, id, read_ofs, read_ptr, read_len)) { - m_freem(m); - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("%s: Host-AP: failed to copy header\n", - sc->sc_dev.dv_xname); - ifp->if_ierrors++; - return -1; + ieee80211_ifdetach(ifp); + if_detach(ifp); + if (sc->sc_enabled) { + if (sc->sc_disable) + (*sc->sc_disable)(sc); + sc->sc_enabled = 0; } - - m->m_pkthdr.len = m->m_len = - WI_SHORT_802_11_END + le16toh(frame->wi_dat_len); - -#if NBPFILTER > 0 - wi_tap_802_11_plus(sc, m); -#endif - - wihap_mgmt_input(sc, frame, m); - + splx(s); return 0; } -#if defined(OPTIMIZE_RW_DATA) -static void wi_rewind(sc) - struct wi_softc *sc; -{ - sc->wi_last_chan = -1; - sc->wi_last_id = -1; - sc->wi_last_offset = -1; -} -#endif - -static void wi_rxeof(sc) - struct wi_softc *sc; +int +wi_activate(struct device *self, enum devact act) { - struct ifnet *ifp; - struct mbuf *m; - int id; - caddr_t olddata; - int maxlen; - struct wi_frame rx_frame; - struct llc llc; - - ifp = &sc->sc_if; - -#if defined(OPTIMIZE_RW_DATA) - wi_rewind(sc); -#endif - id = CSR_READ_2(sc, WI_RX_FID); - - /* First read in the frame header */ - if (wi_read_data(sc, id, 0, (caddr_t)&rx_frame, - sizeof(struct wi_frame))) { - ifp->if_ierrors++; - return; - } - if (ifp->if_flags & IFF_DEBUG) - printf("%s: rx_frame.wi_dat_len = %d\n", sc->sc_dev.dv_xname, - le16toh(rx_frame.wi_dat_len)); - /* Read optional LLC. */ - if (wi_read_data(sc, id, sizeof(struct wi_frame), (caddr_t)&llc, - min(sizeof(struct llc), le16toh(rx_frame.wi_dat_len)))) { - ifp->if_ierrors++; - return; - } - - /* Drop undecryptable or packets with receive errors. */ - if (le16toh(rx_frame.wi_status) & WI_STAT_ERRSTAT) { - ifp->if_ierrors++; - return; - } - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == NULL) { - ifp->if_ierrors++; - return; - } - MCLGET(m, M_DONTWAIT); - if (!(m->m_flags & M_EXT)) { - m_freem(m); - ifp->if_ierrors++; - return; - } - - olddata = m->m_data; - /* Align the data after the ethernet header */ - m->m_data = (caddr_t) ALIGN(m->m_data + sizeof(struct ether_header)) - - sizeof(struct ether_header); - maxlen = MCLBYTES - (m->m_data - olddata); - m->m_pkthdr.rcvif = ifp; - - switch (le16toh(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) { - case WI_STAT_TUNNEL: - case WI_STAT_1042: - - if (ifp->if_flags & IFF_DEBUG) - printf("%s: rx RFC1042\n", sc->sc_dev.dv_xname); + struct wi_softc *sc = (struct wi_softc *)self; + int rv = 0, s; - /* Convert from RFC1042 encapsulation to Ethernet II - * encapsulation. - */ - if (wi_rx_rfc1042(sc, id, &rx_frame, &llc, m, maxlen)) - return; + s = splnet(); + switch (act) { + case DVACT_ACTIVATE: + rv = EOPNOTSUPP; break; - case WI_STAT_MGMT: - if (ifp->if_flags & IFF_DEBUG) - printf("%s: rx Mgmt\n", sc->sc_dev.dv_xname); - - if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) { - (void)wi_rx_mgmt(sc, id, &rx_frame, &llc, m, maxlen); - return; - } - /* fall through */ - case WI_STAT_NORMAL: - - if (ifp->if_flags & IFF_DEBUG) - printf("%s: rx Normal\n", sc->sc_dev.dv_xname); - /* linux-wlan-ng reports that some RFC1042 frames - * are misidentified as Ethernet II frames. Check. - */ - if (le16toh(rx_frame.wi_dat_len) >= sizeof(struct llc) && - llc.llc_dsap == LLC_SNAP_LSAP && - llc.llc_ssap == LLC_SNAP_LSAP && - llc.llc_control == LLC_UI) { - if (ifp->if_flags & IFF_DEBUG) - printf("%s: actually rx RFC1042\n", - sc->sc_dev.dv_xname); - - if (wi_rx_rfc1042(sc, id, &rx_frame, &llc, m, maxlen)) - return; - } else if (wi_rx_ethii(sc, id, &rx_frame, &llc, m, maxlen)) - return; - break; - case WI_STAT_WMP_MSG: - /* XXX hand these up with DLT_PRISM_HEADER? */ - printf("%s: dropping WMP frame\n", sc->sc_dev.dv_xname); - break; - default: - /* XXX hand these up with DLT_PRISM_HEADER? */ - printf("%s: dropping unknown-encoded frame\n", - sc->sc_dev.dv_xname); + case DVACT_DEACTIVATE: + if_deactivate(&sc->sc_ic.ic_if); break; } - - ifp->if_ipackets++; - -#if NBPFILTER > 0 - /* Handle BPF listeners. */ - wi_tap_802_3(sc, m, &rx_frame); -#endif - - if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) { - /* - * Give Host-AP first crack at data packets. If it - * decides to handle it (or drop it), it will return - * non-zero. Otherwise, it is destined for this host. - */ - if (wihap_data_input(sc, &rx_frame, m)) - return; - } - - /* Receive packet. */ - (*ifp->if_input)(ifp, m); -} - -static void wi_txeof(sc, status) - struct wi_softc *sc; - int status; -{ - struct ifnet *ifp = &sc->sc_if; - - ifp->if_timer = 0; - ifp->if_flags &= ~IFF_OACTIVE; - - if (status & WI_EV_TX_EXC) - ifp->if_oerrors++; - else - ifp->if_opackets++; - - return; -} - -void wi_inquire(xsc) - void *xsc; -{ - struct wi_softc *sc; - struct ifnet *ifp; - int s; - - sc = xsc; - ifp = &sc->sc_ethercom.ec_if; - - if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0) - return; - - KASSERT(sc->sc_enabled); - - callout_reset(&sc->wi_inquire_ch, hz * 60, wi_inquire, sc); - - /* Don't do this while we're transmitting */ - if (ifp->if_flags & IFF_OACTIVE) - return; - - s = splnet(); - wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS, 0, 0); splx(s); + return rv; } -void wi_wait_scan(xsc) - void *xsc; +void +wi_power(struct wi_softc *sc, int why) { - struct wi_softc *sc; - struct ifnet *ifp; - int s, result; - - sc = xsc; - ifp = &sc->sc_ethercom.ec_if; - - /* If not scanning, ignore */ - if (!sc->wi_scanning) - return; + struct ifnet *ifp = &sc->sc_ic.ic_if; + int s; s = splnet(); - - /* Wait for sending complete to make INQUIRE */ - if (ifp->if_flags & IFF_OACTIVE) { - callout_reset(&sc->wi_scan_sh, hz * 1, wi_wait_scan, sc); - splx(s); - return; - } - - /* try INQUIRE */ - result = wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0); - if (result == ETIMEDOUT) - callout_reset(&sc->wi_scan_sh, hz * 1, wi_wait_scan, sc); - - splx(s); -} - -void wi_update_stats(sc) - struct wi_softc *sc; -{ - struct wi_req wreq; - struct wi_ltv_gen gen; - struct wi_scan_header ap2_header; /* Prism2 header */ - struct wi_scan_data_p2 ap2; /* Prism2 scantable*/ - struct wi_scan_data ap; /* Lucent scantable */ - struct wi_assoc assoc; /* Association Status */ - u_int16_t id; - struct ifnet *ifp; - u_int32_t *ptr; - int len, naps, i, j; - u_int16_t t; - - ifp = &sc->sc_ethercom.ec_if; - -#if defined(OPTIMIZE_RW_DATA) - wi_rewind(sc); -#endif - - id = CSR_READ_2(sc, WI_INFO_FID); - - if (wi_seek(sc, id, 0, WI_BAP1)) { - return; - } - - gen.wi_len = CSR_READ_2(sc, WI_DATA1); - gen.wi_type = CSR_READ_2(sc, WI_DATA1); - - switch (gen.wi_type) { - case WI_INFO_SCAN_RESULTS: - case WI_INFO_HOST_SCAN_RESULTS: - if (gen.wi_len <= 3) { - sc->wi_naps = 0; - sc->wi_scanning = 0; - break; - } - switch (sc->sc_firmware_type) { - case WI_INTERSIL: - case WI_SYMBOL: - if (sc->sc_firmware_type == WI_INTERSIL) { - naps = 2 * (gen.wi_len - 3) / sizeof(ap2); - /* Read Header */ - for(j=0; j < sizeof(ap2_header) / 2; j++) - ((u_int16_t *)&ap2_header)[j] = - CSR_READ_2(sc, WI_DATA1); - } else { /* WI_SYMBOL */ - naps = 2 * (gen.wi_len - 1) / (sizeof(ap2) + 6); - ap2_header.wi_reason = 0; - } - naps = naps > MAXAPINFO ? MAXAPINFO : naps; - sc->wi_naps = naps; - /* Read Data */ - for (i=0; i < naps; i++) { - for(j=0; j < sizeof(ap2) / 2; j++) - ((u_int16_t *)&ap2)[j] = - CSR_READ_2(sc, WI_DATA1); - if (sc->sc_firmware_type == WI_SYMBOL) { - /* 3 more words */ - for (j = 0; j < 3; j++) - CSR_READ_2(sc, WI_DATA1); - } - /* unswap 8 bit data fields: */ - for(j=0;j<sizeof(ap.wi_bssid)/2;j++) - LE16TOH(((u_int16_t *)&ap.wi_bssid[0])[j]); - for(j=0;j<sizeof(ap.wi_name)/2;j++) - LE16TOH(((u_int16_t *)&ap.wi_name[0])[j]); - sc->wi_aps[i].scanreason = ap2_header.wi_reason; - memcpy(sc->wi_aps[i].bssid, ap2.wi_bssid, 6); - sc->wi_aps[i].channel = ap2.wi_chid; - sc->wi_aps[i].signal = ap2.wi_signal; - sc->wi_aps[i].noise = ap2.wi_noise; - sc->wi_aps[i].quality = ap2.wi_signal - ap2.wi_noise; - sc->wi_aps[i].capinfo = ap2.wi_capinfo; - sc->wi_aps[i].interval = ap2.wi_interval; - sc->wi_aps[i].rate = ap2.wi_rate; - if (ap2.wi_namelen > 32) - ap2.wi_namelen = 32; - sc->wi_aps[i].namelen = ap2.wi_namelen; - memcpy(sc->wi_aps[i].name, ap2.wi_name, - ap2.wi_namelen); - } - break; - - case WI_LUCENT: - naps = 2 * gen.wi_len / sizeof(ap); - naps = naps > MAXAPINFO ? MAXAPINFO : naps; - sc->wi_naps = naps; - /* Read Data*/ - for (i=0; i < naps; i++) { - for(j=0; j < sizeof(ap) / 2; j++) - ((u_int16_t *)&ap)[j] = - CSR_READ_2(sc, WI_DATA1); - /* unswap 8 bit data fields: */ - for(j=0;j<sizeof(ap.wi_bssid)/2;j++) - HTOLE16(((u_int16_t *)&ap.wi_bssid[0])[j]); - for(j=0;j<sizeof(ap.wi_name)/2;j++) - HTOLE16(((u_int16_t *)&ap.wi_name[0])[j]); - memcpy(sc->wi_aps[i].bssid, ap.wi_bssid, 6); - sc->wi_aps[i].channel = ap.wi_chid; - sc->wi_aps[i].signal = ap.wi_signal; - sc->wi_aps[i].noise = ap.wi_noise; - sc->wi_aps[i].quality = ap.wi_signal - ap.wi_noise; - sc->wi_aps[i].capinfo = ap.wi_capinfo; - sc->wi_aps[i].interval = ap.wi_interval; - if (ap.wi_namelen > 32) - ap.wi_namelen = 32; - sc->wi_aps[i].namelen = ap.wi_namelen; - memcpy(sc->wi_aps[i].name, ap.wi_name, - ap.wi_namelen); - } - break; - } - /* Done scanning */ - sc->wi_scanning = 0; - break; - - case WI_INFO_COUNTERS: - /* some card versions have a larger stats structure */ - len = (gen.wi_len - 1 < sizeof(sc->wi_stats) / 4) ? - gen.wi_len - 1 : sizeof(sc->wi_stats) / 4; - ptr = (u_int32_t *)&sc->wi_stats; - - for (i = 0; i < len; i++) { - t = CSR_READ_2(sc, WI_DATA1); -#ifdef WI_HERMES_STATS_WAR - if (t > 0xF000) - t = ~t & 0xFFFF; -#endif - ptr[i] += t; - } - - ifp->if_collisions = sc->wi_stats.wi_tx_single_retries + - sc->wi_stats.wi_tx_multi_retries + - sc->wi_stats.wi_tx_retry_limit; + switch (why) { + case PWR_SUSPEND: + case PWR_STANDBY: + wi_stop(ifp, 1); break; - - case WI_INFO_LINK_STAT: { - static char *msg[] = { - "connected", - "disconnected", - "AP change", - "AP out of range", - "AP in range", - "association failed", - "unknown link status indication" - }; - - if (gen.wi_len != 2) { - if (ifp->if_flags & IFF_DEBUG) - printf("%s: WI_INFO_LINK_STAT: len %d\n", - sc->sc_dev.dv_xname, gen.wi_len); - break; - } - t = CSR_READ_2(sc, WI_DATA1); - - switch (t) { - case 6: /* association failed */ - if (!(sc->wi_flags & WI_FLAGS_JOINING)) - break; - - if (ifp->if_flags & IFF_DEBUG) - printf("%s: failed JOIN %s\n", - sc->sc_dev.dv_xname, - ether_sprintf(sc->wi_join_bssid)); - - bzero(&sc->wi_join_bssid, - sizeof(sc->wi_join_bssid)); - sc->wi_join_channel = 0; - sc->wi_flags &= ~WI_FLAGS_JOINING; - break; - case 2: /* disconnected */ - if (!(sc->wi_flags & WI_FLAGS_CONNECTED)) - break; - sc->wi_flags &= - ~(WI_FLAGS_CONNECTED | WI_FLAGS_AP_IN_RANGE); - bzero(&sc->wi_current_bssid, - sizeof(sc->wi_current_bssid)); - sc->wi_current_channel = 0; - break; - case 1: /* connected */ - case 3: /* AP change */ - - sc->wi_flags &= - ~(WI_FLAGS_CONNECTED | WI_FLAGS_AP_IN_RANGE); - - wreq.wi_type = WI_RID_CURRENT_BSSID; - wreq.wi_len = WI_MAX_DATALEN; - - if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) || - wreq.wi_len != 4) - break; - - (void)memcpy(&sc->wi_current_bssid, &wreq.wi_val[0], - sizeof(sc->wi_current_bssid)); - - wreq.wi_type = WI_RID_CURRENT_CHAN; - wreq.wi_len = WI_MAX_DATALEN; - - if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) || - wreq.wi_len != 2) - break; - - sc->wi_current_channel = le16toh(wreq.wi_val[0]); - - /* The only Connected/AP Change indication that - * ends a JOIN-pending condition comes with the - * same channel/BSSID as we asked to JOIN. - */ - if ((sc->wi_flags & WI_FLAGS_JOINING) && - (memcmp(&sc->wi_current_bssid, &sc->wi_join_bssid, - sizeof(sc->wi_join_bssid)) != 0 || - sc->wi_current_channel != sc->wi_join_channel)) - break; - - sc->wi_flags |= - WI_FLAGS_CONNECTED | WI_FLAGS_AP_IN_RANGE; - - sc->wi_flags &= ~WI_FLAGS_JOINING; - -#if 0 - wreq.wi_type = WI_RID_COMMQUAL; - wreq.wi_len = WI_MAX_DATALEN; - if (wi_read_record(sc, (struct wi_ltv_gen*)&wreq) == 0 - && wreq.wi_val[0] == 0) - sc->wi_flags &= ~WI_FLAGS_AP_IN_RANGE; -#endif - break; - - case 4: /* AP out of range */ - sc->wi_flags &= ~WI_FLAGS_AP_IN_RANGE; - if (sc->sc_firmware_type == WI_SYMBOL) { - wi_cmd(sc, WI_CMD_INQUIRE, - WI_INFO_HOST_SCAN_RESULTS, 0, 0); - break; - } - break; - - case 5: /* AP in range */ - sc->wi_flags |= WI_FLAGS_AP_IN_RANGE; - break; - default: - t = sizeof(msg) / sizeof(msg[0]) - 1; - break; - } - if (ifp->if_flags & IFF_DEBUG) - printf("%s: %s, BSSID %s %d\n", sc->sc_dev.dv_xname, - msg[t - 1], ether_sprintf(sc->wi_current_bssid), - sc->wi_current_channel); + case PWR_RESUME: + if (ifp->if_flags & IFF_UP) { + wi_init(ifp); + (void)wi_intr(sc); } break; - - case WI_INFO_ASSOC_STAT: { - static char *msg[] = { - "STA Associated", - "STA Reassociated", - "STA Disassociated", - "Association Failure", - "Authentication Failed" - }; - if (gen.wi_len != 10) - break; - for (i=0; i < gen.wi_len - 1; i++) - ((u_int16_t *)&assoc)[i] = CSR_READ_2(sc, WI_DATA1); - /* unswap 8 bit data fields: */ - for(j=0;j<sizeof(assoc.wi_assoc_sta)/2;j++) - HTOLE16(((u_int16_t *)&assoc.wi_assoc_sta[0])[j]); - for(j=0;j<sizeof(assoc.wi_assoc_osta)/2;j++) - HTOLE16(((u_int16_t *)&assoc.wi_assoc_osta[0])[j]); - switch (assoc.wi_assoc_stat) { - case ASSOC: - case DISASSOC: - case ASSOCFAIL: - case AUTHFAIL: - printf("%s: %s, AP = %02x:%02x:%02x:%02x:%02x:%02x\n", - sc->sc_dev.dv_xname, - msg[assoc.wi_assoc_stat - 1], - assoc.wi_assoc_sta[0]&0xff, assoc.wi_assoc_sta[1]&0xff, - assoc.wi_assoc_sta[2]&0xff, assoc.wi_assoc_sta[3]&0xff, - assoc.wi_assoc_sta[4]&0xff, assoc.wi_assoc_sta[5]&0xff); - break; - case REASSOC: - printf("%s: %s, AP = %02x:%02x:%02x:%02x:%02x:%02x, " - "OldAP = %02x:%02x:%02x:%02x:%02x:%02x\n", - sc->sc_dev.dv_xname, msg[assoc.wi_assoc_stat - 1], - assoc.wi_assoc_sta[0]&0xff, assoc.wi_assoc_sta[1]&0xff, - assoc.wi_assoc_sta[2]&0xff, assoc.wi_assoc_sta[3]&0xff, - assoc.wi_assoc_sta[4]&0xff, assoc.wi_assoc_sta[5]&0xff, - assoc.wi_assoc_osta[0]&0xff, assoc.wi_assoc_osta[1]&0xff, - assoc.wi_assoc_osta[2]&0xff, assoc.wi_assoc_osta[3]&0xff, - assoc.wi_assoc_osta[4]&0xff, assoc.wi_assoc_osta[5]&0xff); - break; - } - } - - default: -#ifdef WI_DEBUG - printf("%s: got info type: 0x%04x len=0x%04x\n", - sc->sc_dev.dv_xname, gen.wi_type,gen.wi_len); -#endif -#if 0 - for (i = 0; i < gen.wi_len; i++) { - t = CSR_READ_2(sc, WI_DATA1); - printf("[0x%02x] = 0x%04x\n", i, t); - } -#endif + case PWR_SOFTSUSPEND: + case PWR_SOFTSTANDBY: + case PWR_SOFTRESUME: break; } + splx(s); } -static int -wi_join_bss(sc) - struct wi_softc *sc; +void +wi_shutdown(struct wi_softc *sc) { - struct wi_req wreq; + struct ifnet *ifp = &sc->sc_ic.ic_if; - if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) { - return 0; - } - - if (memcmp(&sc->wi_join_bssid, &zero_bssid, sizeof(zero_bssid)) == 0 && - sc->wi_join_channel == 0 && (sc->wi_flags & WI_FLAGS_CONNECTED)) { - - return 0; - } else if (memcmp(&sc->wi_join_bssid, &sc->wi_current_bssid, - sizeof(sc->wi_join_bssid)) == 0 && - sc->wi_join_channel == sc->wi_current_channel) { - - bzero(&sc->wi_join_bssid, sizeof(sc->wi_join_bssid)); - sc->wi_join_channel = 0; - return 0; - } - - sc->wi_flags &= ~(WI_FLAGS_CONNECTED | WI_FLAGS_AP_IN_RANGE); - - /* Indications are unavailable/unreliable in IBSS mode, so - * we do not tie things up by setting WI_FLAGS_JOINING. - */ - switch (sc->wi_ptype) { - case WI_PORTTYPE_ADHOC: - case WI_PORTTYPE_IBSS: - sc->wi_flags &= ~WI_FLAGS_JOINING; - break; - default: - sc->wi_flags |= WI_FLAGS_JOINING; - } - - wreq.wi_type = WI_RID_JOIN_REQ; - wreq.wi_len = 5; - (void)memcpy(&wreq.wi_val[0], &sc->wi_join_bssid, - sizeof(sc->wi_join_bssid)); - wreq.wi_val[3] = htole16(sc->wi_join_channel); - - return wi_write_record(sc, (struct wi_ltv_gen *) &wreq); + if (sc->sc_attached) + wi_stop(ifp, 1); } -int wi_intr(arg) - void *arg; +int +wi_intr(void *arg) { - struct wi_softc *sc = arg; - struct ifnet *ifp; - u_int16_t status; - u_int16_t last_status, raw_status; - int s; - struct timeval start_time, present_time; + int i; + struct wi_softc *sc = arg; + struct ifnet *ifp = &sc->sc_ic.ic_if; + u_int16_t status, raw_status, last_status; if (sc->sc_enabled == 0 || (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 || - (sc->sc_ethercom.ec_if.if_flags & IFF_RUNNING) == 0) - return (0); - - ifp = &sc->sc_ethercom.ec_if; + (ifp->if_flags & IFF_RUNNING) == 0) + return 0; - if (!(ifp->if_flags & IFF_UP)) { + if ((ifp->if_flags & IFF_UP) == 0) { + CSR_WRITE_2(sc, WI_EVENT_ACK, ~0); CSR_WRITE_2(sc, WI_INT_EN, 0); - CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); return 1; } + /* maximum 10 loops per interrupt */ last_status = 0; - - s = splclock(); - start_time = mono_time; - splx(s); - - for (;;) { - - /* Only believe a status bit when we enter wi_intr, or when + for (i = 0; i < 10; i++) { + /* + * Only believe a status bit when we enter wi_intr, or when * the bit was "off" the last time through the loop. This is * my strategy to avoid racing the hardware/firmware if I * can re-read the event status register more quickly than @@ -1338,1763 +481,830 @@ int wi_intr(arg) */ raw_status = CSR_READ_2(sc, WI_EVENT_STAT); status = raw_status & ~last_status; - last_status = raw_status & WI_INTRS; - - if (!(raw_status & WI_INTRS)) { + if ((status & WI_INTRS) == 0) break; - } - - if (status & WI_EV_RX) { - wi_rxeof(sc); - } - - if (status & WI_EV_TX) { - wi_txeof(sc, status); - } - - if (status & WI_EV_ALLOC) { - int id; - id = CSR_READ_2(sc, WI_ALLOC_FID); - if (id == sc->wi_tx_data_id) - wi_txeof(sc, status); - } + last_status = raw_status; - if (status & WI_EV_INFO) { - wi_update_stats(sc); - } + if (status & WI_EV_RX) + wi_rx_intr(sc); - if (status & WI_EV_TX_EXC) { - wi_txeof(sc, status); - } + if (status & WI_EV_ALLOC) + wi_tx_intr(sc); - /* Remember that we no longer disable interrupts. We ack - * LAST so that we're not racing against new events to - * process the present events. It is bad to lose the - * race because an RX/TX buffer is eligible for re-use once - * we ack. Possibly I have seen RX frames too long because - * the NIC clobbered the frame-length before I read it all? - */ - CSR_WRITE_2(sc, WI_EVENT_ACK, status); + if (status & WI_EV_INFO) + wi_info_intr(sc); - s = splclock(); - present_time = mono_time; - splx(s); - - while (present_time.tv_sec > start_time.tv_sec) { - present_time.tv_usec += 1000000; - present_time.tv_sec--; - } - if (present_time.tv_usec - start_time.tv_usec >= 4000 /*4ms*/) { - break; - } + if (!(ifp->if_flags & IFF_OACTIVE) && + !IFQ_IS_EMPTY(&ifp->if_snd)) + wi_start(ifp); } - if (IFQ_IS_EMPTY(&ifp->if_snd) == 0) - wi_start(ifp); - return 1; } -/* Must be called at proper protection level! */ static int -wi_cmd(sc, cmd, val0, val1, val2) - struct wi_softc *sc; - int cmd; - int val0; - int val1; - int val2; +wi_init(struct ifnet *ifp) { - int i, s = 0; - - /* Wait 100us for the busy bit to clear. */ - for (i = 10; i--; DELAY(10)) { - if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY)) - break; - } - - if (i < 0) { - printf("%s: wi_cmd: BUSY did not clear, cmd=0x%x\n", - sc->sc_dev.dv_xname, cmd); - return EIO; - } + struct wi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; + struct wi_joinreq join; + int i; + int error = 0, wasenabled; - CSR_WRITE_2(sc, WI_PARAM0, val0); - CSR_WRITE_2(sc, WI_PARAM1, val1); - CSR_WRITE_2(sc, WI_PARAM2, val2); - CSR_WRITE_2(sc, WI_COMMAND, cmd); + DPRINTF(("wi_init: enabled %d\n", sc->sc_enabled)); + wasenabled = sc->sc_enabled; + if (!sc->sc_enabled) { + if ((error = (*sc->sc_enable)(sc)) != 0) + goto out; + sc->sc_enabled = 1; + } else + wi_stop(ifp, 0); - /* wait .4 second for the command to complete. study the - * distribution of times. - */ - for (i = 2000; i--; DELAY(200)) { - /* - * Wait for 'command complete' bit to be - * set in the event status register. - */ - s = CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD; - if (s) { - /* Ack the event and read result code. */ - s = CSR_READ_2(sc, WI_STATUS); - CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD); -#ifdef foo - if ((s & WI_CMD_CODE_MASK) != (cmd & WI_CMD_CODE_MASK)) - return(EIO); -#endif - if (s & WI_STAT_CMD_RESULT) - return(EIO); - break; - } + /* Symbol firmware cannot be initialized more than once */ + if (sc->sc_firmware_type != WI_SYMBOL || !wasenabled) { + if ((error = wi_reset(sc)) != 0) + goto out; } - if (i < 0) { - if (!sc->wi_scanning) - printf("%s: command timed out, cmd=0x%x\n", - sc->sc_dev.dv_xname, cmd); - return(ETIMEDOUT); + /* common 802.11 configuration */ + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_BSS); + break; + case IEEE80211_M_ADHOC: + wi_write_val(sc, WI_RID_PORTTYPE, sc->sc_ibss_port); + break; + case IEEE80211_M_HOSTAP: + wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_HOSTAP); + break; } - return(0); -} - -static void -wi_reset(sc) - struct wi_softc *sc; -{ - int i; - - sc->wi_flags &= - ~(WI_FLAGS_INITIALIZED | WI_FLAGS_CONNECTED | WI_FLAGS_AP_IN_RANGE); - - bzero(&sc->wi_current_bssid, sizeof(sc->wi_current_bssid)); - bzero(&sc->wi_stats, sizeof(sc->wi_stats)); - - for (i = 5; i--; DELAY(5 * 1000)) { - if (wi_cmd(sc, WI_CMD_INI, 0, 0, 0) == 0) - break; - } - - if (i < 0) - printf("%s" ": init failed\n", sc->sc_dev.dv_xname); + /* Intersil interprets this RID as joining ESS even in IBSS mode */ + if (sc->sc_firmware_type == WI_LUCENT && + (ic->ic_flags & IEEE80211_F_IBSSON) && ic->ic_des_esslen > 0) + wi_write_val(sc, WI_RID_CREATE_IBSS, 1); else - sc->wi_flags |= WI_FLAGS_INITIALIZED; - - CSR_WRITE_2(sc, WI_INT_EN, 0); - CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); - - /* Calibrate timer. */ - WI_SETVAL(WI_RID_TICK_TIME, 8); - - return; -} - -/* - * Read an LTV record from the NIC. - */ -static int wi_read_record(sc, ltv) - struct wi_softc *sc; - struct wi_ltv_gen *ltv; -{ - u_int16_t *ptr; - int len, code; - struct wi_ltv_gen *oltv, p2ltv; - - if (sc->sc_firmware_type != WI_LUCENT) { - oltv = ltv; - switch (ltv->wi_type) { - case WI_RID_ENCRYPTION: - p2ltv.wi_type = WI_RID_P2_ENCRYPTION; - p2ltv.wi_len = 2; - ltv = &p2ltv; - break; - case WI_RID_TX_CRYPT_KEY: - p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; - p2ltv.wi_len = 2; - ltv = &p2ltv; - break; - } + wi_write_val(sc, WI_RID_CREATE_IBSS, 0); + wi_write_val(sc, WI_RID_MAX_SLEEP, ic->ic_lintval); + wi_write_ssid(sc, WI_RID_DESIRED_SSID, ic->ic_des_essid, + ic->ic_des_esslen); + wi_write_val(sc, WI_RID_OWN_CHNL, ic->ic_ibss_chan); + wi_write_ssid(sc, WI_RID_OWN_SSID, ic->ic_des_essid, ic->ic_des_esslen); + wi_write_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, IEEE80211_ADDR_LEN); + wi_write_val(sc, WI_RID_PM_ENABLED, + (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0); + + /* not yet common 802.11 configuration */ + wi_write_val(sc, WI_RID_MAX_DATALEN, sc->sc_max_datalen); + wi_write_val(sc, WI_RID_RTS_THRESH, sc->sc_rts_thresh); + + /* driver specific 802.11 configuration */ + if (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE) + wi_write_val(sc, WI_RID_SYSTEM_SCALE, sc->sc_system_scale); + if (sc->sc_flags & WI_FLAGS_HAS_ROAMING) + wi_write_val(sc, WI_RID_ROAMING_MODE, sc->sc_roaming_mode); + if (sc->sc_flags & WI_FLAGS_HAS_MOR) + wi_write_val(sc, WI_RID_MICROWAVE_OVEN, sc->sc_microwave_oven); + wi_write_txrate(sc); + wi_write_ssid(sc, WI_RID_NODENAME, sc->sc_nodename, sc->sc_nodelen); + + if (ic->ic_opmode == IEEE80211_M_HOSTAP) { + /* XXX: these configurations may be intersil only */ + wi_write_val(sc, WI_RID_OWN_BEACON_INT, ic->ic_lintval); + wi_write_val(sc, WI_RID_BASIC_RATE, 0x03); /* 1, 2 */ + wi_write_val(sc, WI_RID_SUPPORT_RATE, 0x0f); /* 1, 2, 5.5, 11 */ + wi_write_val(sc, WI_RID_DTIM_PERIOD, 1); } - /* Tell the NIC to enter record read mode. */ - if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_READ, ltv->wi_type, 0, 0)) - return(EIO); - - /* Seek to the record. */ - if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1)) - return(EIO); - /* - * Read the length and record type and make sure they - * match what we expect (this verifies that we have enough - * room to hold all of the returned data). - */ - len = CSR_READ_2(sc, WI_DATA1); - if (len > ltv->wi_len) - return(ENOSPC); - code = CSR_READ_2(sc, WI_DATA1); - if (code != ltv->wi_type) - return(EIO); - - ltv->wi_len = len; - ltv->wi_type = code; - - /* A 2us delay here prevents a MCHK exception on G4 Powerbook. - * Go figure. + * Initialize promisc mode. + * Being in the Host-AP mode causes a great + * deal of pain if primisc mode is set. + * Therefore we avoid confusing the firmware + * and always reset promisc mode in Host-AP + * mode. Host-AP sees all the packets anyway. */ - - /* Now read the data. */ - ptr = <v->wi_val; - if (ltv->wi_len > 1) - CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr, ltv->wi_len - 1); - - if (ltv->wi_type == WI_RID_PORTTYPE && - sc->wi_ptype == WI_PORTTYPE_IBSS && - ltv->wi_val == sc->wi_ibss_port) { - /* - * Convert vendor IBSS port type to WI_PORTTYPE_IBSS. - * Since Lucent uses port type 1 for BSS *and* IBSS we - * have to rely on wi_ptype to distinguish this for us. - */ - ltv->wi_val = htole16(WI_PORTTYPE_IBSS); - } else if (sc->sc_firmware_type != WI_LUCENT) { - int v; - - switch (oltv->wi_type) { - case WI_RID_TX_RATE: - case WI_RID_CUR_TX_RATE: - switch (le16toh(ltv->wi_val)) { - case 1: v = 1; break; - case 2: v = 2; break; - case 3: v = 6; break; - case 4: v = 5; break; - case 7: v = 7; break; - case 8: v = 11; break; - case 15: v = 3; break; - default: v = 0x100 + le16toh(ltv->wi_val); break; - } - oltv->wi_val = htole16(v); - break; - case WI_RID_ENCRYPTION: - oltv->wi_len = 2; - if (le16toh(ltv->wi_val) & 0x01) - oltv->wi_val = htole16(1); - else - oltv->wi_val = htole16(0); - break; - case WI_RID_TX_CRYPT_KEY: - oltv->wi_len = 2; - oltv->wi_val = ltv->wi_val; - break; - case WI_RID_CNFAUTHMODE: - oltv->wi_len = 2; - if (le16toh(ltv->wi_val) & 0x01) - oltv->wi_val = htole16(1); - else if (le16toh(ltv->wi_val) & 0x02) - oltv->wi_val = htole16(2); - break; - } + if (ic->ic_opmode != IEEE80211_M_HOSTAP && + (ifp->if_flags & IFF_PROMISC) != 0) { + wi_write_val(sc, WI_RID_PROMISC, 1); + } else { + wi_write_val(sc, WI_RID_PROMISC, 0); } - return(0); -} + /* Configure WEP. */ + if (ic->ic_flags & IEEE80211_F_HASWEP) + wi_write_wep(sc); -/* - * Same as read, except we inject data instead of reading it. - */ -static int wi_write_record(sc, ltv) - struct wi_softc *sc; - struct wi_ltv_gen *ltv; -{ - u_int16_t *ptr; - int i; - struct wi_ltv_gen p2ltv; - - if (ltv->wi_type == WI_RID_PORTTYPE && - ltv->wi_val == le16toh(WI_PORTTYPE_IBSS)) { - /* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */ - p2ltv.wi_type = WI_RID_PORTTYPE; - p2ltv.wi_len = 2; - p2ltv.wi_val = sc->wi_ibss_port; - ltv = &p2ltv; - } else if (sc->sc_firmware_type != WI_LUCENT) { - int v; - - switch (ltv->wi_type) { - case WI_RID_TX_RATE: - p2ltv.wi_type = WI_RID_TX_RATE; - p2ltv.wi_len = 2; - switch (le16toh(ltv->wi_val)) { - case 1: v = 1; break; - case 2: v = 2; break; - case 3: v = 15; break; - case 5: v = 4; break; - case 6: v = 3; break; - case 7: v = 7; break; - case 11: v = 8; break; - default: return EINVAL; - } - p2ltv.wi_val = htole16(v); - ltv = &p2ltv; - break; - case WI_RID_ENCRYPTION: - p2ltv.wi_type = WI_RID_P2_ENCRYPTION; - p2ltv.wi_len = 2; - if (le16toh(ltv->wi_val)) { - uint16_t val = PRIVACY_INVOKED; - /* - * If using shared key WEP we must set the - * EXCLUDE_UNENCRYPTED bit. Symbol cards - * need this bit even when not using shared - * key. We can't just test for - * IEEE80211_AUTH_SHARED since Symbol cards - * have 2 shared key modes. - */ - if (sc->wi_authtype != IEEE80211_AUTH_OPEN || - sc->sc_firmware_type == WI_SYMBOL) - val |= EXCLUDE_UNENCRYPTED; - /* Tx encryption is broken in Host-AP mode. */ - if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) - val |= HOST_ENCRYPT; - p2ltv.wi_val = htole16(val); - } else - p2ltv.wi_val = - htole16(HOST_ENCRYPT | HOST_DECRYPT); - ltv = &p2ltv; - break; - case WI_RID_TX_CRYPT_KEY: - p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY; - p2ltv.wi_len = 2; - p2ltv.wi_val = ltv->wi_val; - ltv = &p2ltv; - break; - case WI_RID_DEFLT_CRYPT_KEYS: - { - int error; - int keylen; - struct wi_ltv_str ws; - struct wi_ltv_keys *wk = (struct wi_ltv_keys *)ltv; - - keylen = le16toh(wk->wi_keys[sc->wi_tx_key].wi_keylen); - - for (i = 0; i < 4; i++) { - memset(&ws, 0, sizeof(ws)); - ws.wi_len = (keylen > 5) ? 8 : 4; - ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i; - memcpy(ws.wi_str, - &wk->wi_keys[i].wi_keydat, keylen); - error = wi_write_record(sc, - (struct wi_ltv_gen *)&ws); - if (error) - return error; - } - return 0; - } - case WI_RID_CNFAUTHMODE: - p2ltv.wi_type = WI_RID_CNFAUTHMODE; - p2ltv.wi_len = 2; - if (le16toh(ltv->wi_val) == 1) - p2ltv.wi_val = htole16(0x01); - else if (le16toh(ltv->wi_val) == 2) - p2ltv.wi_val = htole16(0x02); - ltv = &p2ltv; - break; + /* Set multicast filter. */ + wi_write_multi(sc); + + sc->sc_buflen = IEEE80211_MAX_LEN + sizeof(struct wi_frame); + if (sc->sc_firmware_type == WI_SYMBOL) + sc->sc_buflen = 1585; /* XXX */ + for (i = 0; i < WI_NTXBUF; i++) { + error = wi_alloc_fid(sc, sc->sc_buflen, + &sc->sc_txd[i].d_fid); + if (error) { + printf("%s: tx buffer allocation failed\n", + sc->sc_dev.dv_xname); + goto out; } + DPRINTF2(("wi_init: txbuf %d allocated %x\n", i, + sc->sc_txd[i].d_fid)); + sc->sc_txd[i].d_len = 0; } - if (wi_seek(sc, ltv->wi_type, 0, WI_BAP1)) - return(EIO); - - CSR_WRITE_2(sc, WI_DATA1, ltv->wi_len); - CSR_WRITE_2(sc, WI_DATA1, ltv->wi_type); - - /* Write data */ - ptr = <v->wi_val; - if (ltv->wi_len > 1) - CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA1, ptr, ltv->wi_len - 1); - - if (wi_cmd(sc, WI_CMD_ACCESS|WI_ACCESS_WRITE, ltv->wi_type, 0, 0)) - return(EIO); + /* Enable port 0 */ + wi_cmd(sc, WI_CMD_ENABLE | WI_PORT0, 0, 0, 0); + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + if ((ic->ic_opmode == IEEE80211_M_ADHOC && + (sc->sc_flags & WI_FLAGS_NO_BSSID)) || + (ic->ic_opmode == IEEE80211_M_HOSTAP)) + wi_newstate(sc, IEEE80211_S_RUN); - return(0); -} + /* Enable interrupts */ + CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); -static int wi_seek(sc, id, off, chan) - struct wi_softc *sc; - int id, off, chan; -{ - int i; - int selreg, offreg; - int status; - -#if defined(OPTIMIZE_RW_DATA) - if (sc->wi_last_chan == chan && sc->wi_last_id == id && - sc->wi_last_offset <= off) { - while (off - sc->wi_last_offset >= len) { - CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr, len); - sc->wi_last_offset += len; - } - if (sc->wi_last_offset < off) { - CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr, - off - sc->wi_last_offset); - sc->wi_last_offset = off; - } - return 0; - } -#endif - switch (chan) { - case WI_BAP0: - selreg = WI_SEL0; - offreg = WI_OFF0; - break; - case WI_BAP1: - selreg = WI_SEL1; - offreg = WI_OFF1; - break; - default: - printf("%s: invalid data path: %x\n", - sc->sc_dev.dv_xname, chan); - return(EIO); + if (!wasenabled && ic->ic_opmode == IEEE80211_M_HOSTAP) { + /* XXX: some card need to be re-enabled for hostap */ + wi_cmd(sc, WI_CMD_DISABLE | WI_PORT0, 0, 0, 0); + wi_cmd(sc, WI_CMD_ENABLE | WI_PORT0, 0, 0, 0); } - CSR_WRITE_2(sc, selreg, id); - CSR_WRITE_2(sc, offreg, off); - - for (i = WI_TIMEOUT; i--; DELAY(10)) - if (!(CSR_READ_2(sc, offreg) & (WI_OFF_BUSY|WI_OFF_ERR))) - break; + if (ic->ic_opmode == IEEE80211_M_STA && + ((ic->ic_flags & IEEE80211_F_DESBSSID) || + ic->ic_des_chan != IEEE80211_CHAN_ANY)) { + memset(&join, 0, sizeof(join)); + if (ic->ic_flags & IEEE80211_F_DESBSSID) + IEEE80211_ADDR_COPY(&join.wi_bssid, ic->ic_des_bssid); + if (ic->ic_des_chan != IEEE80211_CHAN_ANY) + join.wi_chan = htole16(ic->ic_des_chan); + wi_write_rid(sc, WI_RID_JOIN_REQ, &join, sizeof(join)); + } - if (i < 0) { - printf("%s: timeout in wi_seek to %x/%x; last status %x\n", - sc->sc_dev.dv_xname, id, off, status); - return(ETIMEDOUT); + out: + if (error) { + printf("%s: interface not running\n", sc->sc_dev.dv_xname); + wi_stop(ifp, 1); } -#if defined(OPTIMIZE_RW_DATA) - sc->wi_last_chan = chan; - sc->wi_last_id = id; - sc->wi_last_offset = off; -#endif - return(0); + DPRINTF(("wi_init: return %d\n", error)); + return error; } -/* buf must be aligned on a u_int16_t boundary. */ -static int wi_read_data(sc, id, off, buf, len) - struct wi_softc *sc; - int id, off; - caddr_t buf; - int len; +static void +wi_stop(struct ifnet *ifp, int disable) { - u_int16_t *ptr; - - if (len <= 0) - return 0; - - if (len & 1) - len++; - - if (wi_seek(sc, id, off, WI_BAP1)) - return(EIO); + struct wi_softc *sc = ifp->if_softc; - ptr = (u_int16_t *)buf; - CSR_READ_MULTI_STREAM_2(sc, WI_DATA1, ptr, len / 2); + DPRINTF(("wi_stop: disable %d\n", disable)); + ieee80211_new_state(ifp, IEEE80211_S_INIT, -1); + if (sc->sc_enabled) { + CSR_WRITE_2(sc, WI_INT_EN, 0); + wi_cmd(sc, WI_CMD_DISABLE | WI_PORT0, 0, 0, 0); + if (disable) { + if (sc->sc_disable) + (*sc->sc_disable)(sc); + sc->sc_enabled = 0; + } + } -#if defined(OPTIMIZE_RW_DATA) - sc->wi_last_chan = WI_BAP1; - sc->wi_last_id = id; - sc->wi_last_offset = off + len; -#endif - return(0); + sc->sc_tx_timer = 0; + sc->sc_scan_timer = 0; + sc->sc_naps = 0; + ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING); + ifp->if_timer = 0; } -/* - * According to the comments in the HCF Light code, there is a bug in - * the Hermes (or possibly in certain Hermes firmware revisions) where - * the chip's internal autoincrement counter gets thrown off during - * data writes: the autoincrement is missed, causing one data word to - * be overwritten and subsequent words to be written to the wrong memory - * locations. The end result is that we could end up transmitting bogus - * frames without realizing it. The workaround for this is to write a - * couple of extra guard words after the end of the transfer, then - * attempt to read then back. If we fail to locate the guard words where - * we expect them, we preform the transfer over again. - * - * buf must be aligned on a u_int16_t boundary. - */ -static int wi_write_data(sc, id, off, buf, len) - struct wi_softc *sc; - int id, off; - caddr_t buf; - int len; +static void +wi_start(struct ifnet *ifp) { - u_int16_t *ptr; - - if (len <= 0) - return 0; + struct wi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_frame *wh; + struct mbuf *m0, *m; + struct wi_frame frmhdr; + int cur, fid, off; - if (len & 1) - len++; + if (ifp->if_flags & IFF_OACTIVE) + return; -#if !defined(OPTIMIZE_RW_DATA) && defined(WI_HERMES_AUTOINC_WAR) -again: + memset(&frmhdr, 0, sizeof(frmhdr)); + cur = sc->sc_txnext; + for (;;) { + IF_POLL(&ic->ic_mgtq, m0); + if (m0 != NULL) { + if (sc->sc_txd[cur].d_len != 0) { + ifp->if_flags |= IFF_OACTIVE; + break; + } + IF_DEQUEUE(&ic->ic_mgtq, m0); + m_copydata(m0, 4, ETHER_ADDR_LEN * 2, + (caddr_t)&frmhdr.wi_ehdr); + frmhdr.wi_ehdr.ether_type = 0; + wh = mtod(m0, struct ieee80211_frame *); + } else { + if (ic->ic_state != IEEE80211_S_RUN) + break; + IFQ_POLL(&ifp->if_snd, m0); + if (m0 == NULL) + break; + if (sc->sc_txd[cur].d_len != 0) { + ifp->if_flags |= IFF_OACTIVE; + break; + } + IFQ_DEQUEUE(&ifp->if_snd, m0); + ifp->if_opackets++; + m_copydata(m0, 0, ETHER_HDR_LEN, + (caddr_t)&frmhdr.wi_ehdr); +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m0); #endif - if (wi_seek(sc, id, off, WI_BAP0)) - return(EIO); - - ptr = (u_int16_t *)buf; - CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA0, ptr, len / 2); - -#if !defined(OPTIMIZE_RW_DATA) && defined(WI_HERMES_AUTOINC_WAR) - CSR_WRITE_2(sc, WI_DATA0, 0x1234); - CSR_WRITE_2(sc, WI_DATA0, 0x5678); - - if (wi_seek(sc, id, off + len, WI_BAP0)) - return(EIO); + if ((m0 = ieee80211_encap(ifp, m0)) == NULL) { + ifp->if_oerrors++; + continue; + } + wh = mtod(m0, struct ieee80211_frame *); + if (ic->ic_opmode == IEEE80211_M_HOSTAP && + !IEEE80211_IS_MULTICAST(wh->i_addr1) && + (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == + IEEE80211_FC0_TYPE_DATA && + ieee80211_find_node(ic, wh->i_addr1) == NULL) { + m_freem(m0); + ifp->if_oerrors++; + continue; + } + if (ic->ic_flags & IEEE80211_F_WEPON) + wh->i_fc[1] |= IEEE80211_FC1_WEP; - if (CSR_READ_2(sc, WI_DATA0) != 0x1234 || - CSR_READ_2(sc, WI_DATA0) != 0x5678) { - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("%s: auto-inc error\n", sc->sc_dev.dv_xname); - goto again; - } + } +#if NBPFILTER > 0 + if (ic->ic_rawbpf) + bpf_mtap(ic->ic_rawbpf, m0); #endif - -#if defined(OPTIMIZE_RW_DATA) - sc->wi_last_chan = WI_BAP0; - sc->wi_last_id = id; - sc->wi_last_offset = off + len; + frmhdr.wi_tx_ctl = htole16(WI_ENC_TX_802_11); + if (ic->ic_opmode == IEEE80211_M_HOSTAP && + (wh->i_fc[1] & IEEE80211_FC1_WEP)) { + if ((m0 = ieee80211_wep_crypt(ifp, m0, 1)) == NULL) { + ifp->if_oerrors++; + continue; + } + frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT); + } + m_copydata(m0, 0, sizeof(struct ieee80211_frame), + (caddr_t)&frmhdr.wi_whdr); + m_adj(m0, sizeof(struct ieee80211_frame)); + frmhdr.wi_dat_len = htole16(m0->m_pkthdr.len); +#if NBPFILTER > 0 + if (sc->sc_drvbpf) { + struct mbuf mb; + + M_COPY_PKTHDR(&mb, m0); + mb.m_data = (caddr_t)&frmhdr; + mb.m_len = sizeof(frmhdr); + mb.m_next = m0; + mb.m_pkthdr.len += mb.m_len; + bpf_mtap(sc->sc_drvbpf, &mb); + } #endif - return(0); + fid = sc->sc_txd[cur].d_fid; + wi_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)); + off = sizeof(frmhdr); + for (m = m0; m != NULL; m = m->m_next) { + if (m->m_len == 0) + continue; + wi_write_bap(sc, fid, off, m->m_data, m->m_len); + off += m->m_len; + } + m_freem(m0); + sc->sc_txd[cur].d_len = off; + if (sc->sc_txcur == cur) { + if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, fid, 0, 0)) { + printf("%s: xmit failed\n", + sc->sc_dev.dv_xname); + sc->sc_txd[cur].d_len = 0; + continue; + } + sc->sc_tx_timer = 5; + ifp->if_timer = 1; + } + sc->sc_txnext = cur = (cur + 1) % WI_NTXBUF; + } } -/* - * Allocate a region of memory inside the NIC and zero - * it out. - */ -static int wi_alloc_nicmem(sc, len, id) - struct wi_softc *sc; - int len; - int *id; -{ - int i; - -#if defined(OPTIMIZE_RW_DATA) - wi_rewind(sc); -#endif - if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len, 0, 0)) { - printf("%s: failed to allocate %d bytes on NIC\n", - sc->sc_dev.dv_xname, len); - return(ENOMEM); - } +static int +wi_reset(struct wi_softc *sc) +{ + int i, error; - for (i = WI_TIMEOUT; i--; DELAY(10)) { - if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC) + DPRINTF(("wi_reset\n")); + error = 0; + for (i = 0; i < 5; i++) { + DELAY(20*1000); /* XXX: way too long! */ + if ((error = wi_cmd(sc, WI_CMD_INI, 0, 0, 0)) == 0) break; } - - if (i < 0) { - printf("%s: TIMED OUT in alloc\n", sc->sc_dev.dv_xname); - return(ETIMEDOUT); - } - - *id = CSR_READ_2(sc, WI_ALLOC_FID); - CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); - - if (wi_seek(sc, *id, 0, WI_BAP0)) { - printf("%s: seek failed in alloc\n", sc->sc_dev.dv_xname); - return(EIO); + if (error) { + printf("%s: init failed\n", sc->sc_dev.dv_xname); + return error; } + CSR_WRITE_2(sc, WI_INT_EN, 0); + CSR_WRITE_2(sc, WI_EVENT_ACK, ~0); - for (i = 0; i < len / 2; i++) - CSR_WRITE_2(sc, WI_DATA0, 0); - - return(0); + /* Calibrate timer. */ + wi_write_val(sc, WI_RID_TICK_TIME, 0); + return 0; } -static void wi_setmulti(sc) - struct wi_softc *sc; +static void +wi_watchdog(struct ifnet *ifp) { - struct ifnet *ifp; - int i = 0; - struct wi_ltv_mcast mcast; - struct ether_multi *enm; - struct ether_multistep estep; - struct ethercom *ec = &sc->sc_ethercom; - - ifp = &sc->sc_ethercom.ec_if; - - if ((ifp->if_flags & IFF_PROMISC) != 0) { -allmulti: - ifp->if_flags |= IFF_ALLMULTI; - memset((char *)&mcast, 0, sizeof(mcast)); - mcast.wi_type = WI_RID_MCAST_LIST; - mcast.wi_len = ((ETHER_ADDR_LEN / 2) * 16) + 1; + struct wi_softc *sc = ifp->if_softc; - wi_write_record(sc, (struct wi_ltv_gen *)&mcast); + ifp->if_timer = 0; + if (!sc->sc_enabled) return; - } - i = 0; - ETHER_FIRST_MULTI(estep, ec, enm); - while (enm != NULL) { - /* Punt on ranges or too many multicast addresses. */ - if (memcmp(enm->enm_addrlo, enm->enm_addrhi, - ETHER_ADDR_LEN) != 0 || - i >= 16) - goto allmulti; - - memcpy((char *)&mcast.wi_mcast[i], enm->enm_addrlo, - ETHER_ADDR_LEN); - i++; - ETHER_NEXT_MULTI(estep, enm); - } - - ifp->if_flags &= ~IFF_ALLMULTI; - mcast.wi_type = WI_RID_MCAST_LIST; - mcast.wi_len = ((ETHER_ADDR_LEN / 2) * i) + 1; - wi_write_record(sc, (struct wi_ltv_gen *)&mcast); -} - -static int -wi_setdef(sc, wreq) - struct wi_softc *sc; - struct wi_req *wreq; -{ - struct sockaddr_dl *sdl; - struct ifnet *ifp; - int error = 0; - - ifp = &sc->sc_ethercom.ec_if; - - switch(wreq->wi_type) { - case WI_RID_MAC_NODE: - sdl = (struct sockaddr_dl *)ifp->if_sadl; - memcpy((char *)&sc->sc_macaddr, (char *)&wreq->wi_val, - ETHER_ADDR_LEN); - memcpy(LLADDR(sdl), (char *)&wreq->wi_val, ETHER_ADDR_LEN); - break; - case WI_RID_PORTTYPE: - error = wi_sync_media(sc, le16toh(wreq->wi_val[0]), - sc->wi_tx_rate); - break; - case WI_RID_TX_RATE: - error = wi_sync_media(sc, sc->wi_ptype, - le16toh(wreq->wi_val[0])); - break; - case WI_RID_MAX_DATALEN: - sc->wi_max_data_len = le16toh(wreq->wi_val[0]); - break; - case WI_RID_RTS_THRESH: - sc->wi_rts_thresh = le16toh(wreq->wi_val[0]); - break; - case WI_RID_SYSTEM_SCALE: - sc->wi_ap_density = le16toh(wreq->wi_val[0]); - break; - case WI_RID_CREATE_IBSS: - sc->wi_create_ibss = le16toh(wreq->wi_val[0]); - error = wi_sync_media(sc, sc->wi_ptype, sc->wi_tx_rate); - break; - case WI_RID_OWN_CHNL: - sc->wi_create_channel = le16toh(wreq->wi_val[0]); - break; - case WI_RID_NODENAME: - error = wi_set_ssid(&sc->wi_nodeid, - (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0])); - break; - case WI_RID_DESIRED_SSID: - error = wi_set_ssid(&sc->wi_netid, - (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0])); - break; - case WI_RID_OWN_SSID: - error = wi_set_ssid(&sc->wi_ibssid, - (u_int8_t *)&wreq->wi_val[1], le16toh(wreq->wi_val[0])); - break; - case WI_RID_PM_ENABLED: - sc->wi_pm_enabled = le16toh(wreq->wi_val[0]); - break; - case WI_RID_MICROWAVE_OVEN: - sc->wi_mor_enabled = le16toh(wreq->wi_val[0]); - break; - case WI_RID_MAX_SLEEP: - sc->wi_max_sleep = le16toh(wreq->wi_val[0]); - break; - case WI_RID_CNFAUTHMODE: - sc->wi_authtype = le16toh(wreq->wi_val[0]); - break; - case WI_RID_ROAMING_MODE: - sc->wi_roaming = le16toh(wreq->wi_val[0]); - break; - case WI_RID_ENCRYPTION: - sc->wi_use_wep = le16toh(wreq->wi_val[0]); - break; - case WI_RID_TX_CRYPT_KEY: - sc->wi_tx_key = le16toh(wreq->wi_val[0]); - break; - case WI_RID_DEFLT_CRYPT_KEYS: - memcpy((char *)&sc->wi_keys, (char *)wreq, - sizeof(struct wi_ltv_keys)); - break; - default: - error = EINVAL; - break; + if (sc->sc_tx_timer) { + if (--sc->sc_tx_timer == 0) { + printf("%s: device timeout\n", ifp->if_xname); + ifp->if_oerrors++; + wi_init(ifp); + return; + } + ifp->if_timer = 1; } - return (error); -} - -static int -wi_getdef(sc, wreq) - struct wi_softc *sc; - struct wi_req *wreq; -{ - struct sockaddr_dl *sdl; - struct ifnet *ifp; - int error = 0; - - ifp = &sc->sc_ethercom.ec_if; - - wreq->wi_len = 2; /* XXX */ - switch (wreq->wi_type) { - case WI_RID_MAC_NODE: - wreq->wi_len += ETHER_ADDR_LEN / 2 - 1; - sdl = (struct sockaddr_dl *)ifp->if_sadl; - memcpy(&wreq->wi_val, &sc->sc_macaddr, ETHER_ADDR_LEN); - memcpy(&wreq->wi_val, LLADDR(sdl), ETHER_ADDR_LEN); - break; - case WI_RID_PORTTYPE: - wreq->wi_val[0] = htole16(sc->wi_ptype); - break; - case WI_RID_TX_RATE: - wreq->wi_val[0] = htole16(sc->wi_tx_rate); - break; - case WI_RID_MAX_DATALEN: - wreq->wi_val[0] = htole16(sc->wi_max_data_len); - break; - case WI_RID_RTS_THRESH: - wreq->wi_val[0] = htole16(sc->wi_rts_thresh); - break; - case WI_RID_SYSTEM_SCALE: - wreq->wi_val[0] = htole16(sc->wi_ap_density); - break; - case WI_RID_CREATE_IBSS: - wreq->wi_val[0] = htole16(sc->wi_create_ibss); - break; - case WI_RID_OWN_CHNL: - wreq->wi_val[0] = htole16(sc->wi_create_channel); - break; - case WI_RID_NODENAME: - wi_request_fill_ssid(wreq, &sc->wi_nodeid); - break; - case WI_RID_DESIRED_SSID: - wi_request_fill_ssid(wreq, &sc->wi_netid); - break; - case WI_RID_OWN_SSID: - wi_request_fill_ssid(wreq, &sc->wi_ibssid); - break; - case WI_RID_PM_ENABLED: - wreq->wi_val[0] = htole16(sc->wi_pm_enabled); - break; - case WI_RID_MICROWAVE_OVEN: - wreq->wi_val[0] = htole16(sc->wi_mor_enabled); - break; - case WI_RID_MAX_SLEEP: - wreq->wi_val[0] = htole16(sc->wi_max_sleep); - break; - case WI_RID_CNFAUTHMODE: - wreq->wi_val[0] = htole16(sc->wi_authtype); - break; - case WI_RID_ROAMING_MODE: - wreq->wi_val[0] = htole16(sc->wi_roaming); - break; - case WI_RID_WEP_AVAIL: - wreq->wi_val[0] = (sc->wi_flags & WI_FLAGS_HAS_WEP) ? - htole16(1) : htole16(0); - break; - case WI_RID_ENCRYPTION: - wreq->wi_val[0] = htole16(sc->wi_use_wep); - break; - case WI_RID_TX_CRYPT_KEY: - wreq->wi_val[0] = htole16(sc->wi_tx_key); - break; - case WI_RID_DEFLT_CRYPT_KEYS: - wreq->wi_len += sizeof(struct wi_ltv_keys) / 2 - 1; - memcpy(wreq, &sc->wi_keys, sizeof(struct wi_ltv_keys)); - break; - default: -#if 0 - error = EIO; -#else -#ifdef WI_DEBUG - printf("%s: wi_getdef: unknown request %d\n", - sc->sc_dev.dv_xname, wreq->wi_type); -#endif -#endif - break; + if (sc->sc_scan_timer) { + if (--sc->sc_scan_timer <= WI_SCAN_WAIT - WI_SCAN_INQWAIT && + sc->sc_firmware_type == WI_INTERSIL) { + DPRINTF(("wi_watchdog: inquire scan\n")); + wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0); + } + if (sc->sc_scan_timer) + ifp->if_timer = 1; } - return (error); + /* TODO: rate control */ + ieee80211_watchdog(ifp); } static int -wi_ioctl(ifp, command, data) - struct ifnet *ifp; - u_long command; - caddr_t data; +wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { - int s, error = 0; - int len; - struct wi_softc *sc = ifp->if_softc; - struct wi_req wreq; - struct ifreq *ifr; - struct proc *p = curproc; - struct ieee80211_nwid nwid; + struct wi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; + struct ifreq *ifr = (struct ifreq *)data; + int s, error = 0; if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0) - return (ENXIO); + return ENXIO; s = splnet(); - ifr = (struct ifreq *)data; - - if (!sc->sc_attached) { - splx(s); - return(ENODEV); - } - - switch(command) { - case SIOCSWAVELAN: - case SIOCS80211NWID: - case SIOCS80211NWKEY: - case SIOCS80211POWER: - case SIOCS80211BSSID: - case SIOCS80211CHANNEL: - error = suser(p->p_ucred, &p->p_acflag); - if (error) { - splx(s); - return (error); - } - default: - break; - } - - switch (command) { - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCSIFMTU: - error = ether_ioctl(ifp, command, data); - break; + switch (cmd) { case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { - if (ifp->if_flags & IFF_RUNNING && - ifp->if_flags & IFF_PROMISC && - !(sc->wi_if_flags & IFF_PROMISC)) { - if (sc->wi_ptype != WI_PORTTYPE_HOSTAP) - WI_SETVAL(WI_RID_PROMISC, 1); - } else if (ifp->if_flags & IFF_RUNNING && - !(ifp->if_flags & IFF_PROMISC) && - sc->wi_if_flags & IFF_PROMISC) { - if (sc->wi_ptype != WI_PORTTYPE_HOSTAP) - WI_SETVAL(WI_RID_PROMISC, 0); - } else - wi_init(ifp); - } else if (ifp->if_flags & IFF_RUNNING) - wi_stop(ifp, 0); - sc->wi_if_flags = ifp->if_flags; - - if (!(ifp->if_flags & IFF_UP)) { if (sc->sc_enabled) { - if (sc->sc_disable) - (*sc->sc_disable)(sc); - sc->sc_enabled = 0; - ifp->if_flags &= ~IFF_RUNNING; - } - } - error = 0; - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - error = (command == SIOCADDMULTI) ? - ether_addmulti(ifr, &sc->sc_ethercom) : - ether_delmulti(ifr, &sc->sc_ethercom); - if (error == ENETRESET) { - if (sc->sc_enabled != 0) { /* - * Multicast list has changed. Set the - * hardware filter accordingly. + * To avoid rescanning another access point, + * do not call wi_init() here. Instead, + * only reflect promisc mode settings. */ - wi_setmulti(sc); - } - error = 0; - } + if (ic->ic_opmode != IEEE80211_M_HOSTAP && + (ifp->if_flags & IFF_PROMISC) != 0) + wi_write_val(sc, WI_RID_PROMISC, 1); + else + wi_write_val(sc, WI_RID_PROMISC, 0); + } else + error = wi_init(ifp); + } else if (sc->sc_enabled) + wi_stop(ifp, 1); break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: - error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command); + error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); break; - case SIOCGWAVELAN: - error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); - if (error) - break; - if (wreq.wi_len > WI_MAX_DATALEN) { - error = EINVAL; - break; - } - if (wreq.wi_type == WI_RID_IFACE_STATS) { - memcpy((char *)&wreq.wi_val, (char *)&sc->wi_stats, - sizeof(sc->wi_stats)); - wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1; - } else if (wreq.wi_type == WI_RID_READ_APS) { - if (sc->wi_scanning) { - error = EINPROGRESS; - break; - } else { - len = sc->wi_naps * sizeof(struct wi_apinfo); - len = len > WI_MAX_DATALEN ? WI_MAX_DATALEN : len; - len = len / sizeof(struct wi_apinfo); - memcpy((char *)&wreq.wi_val, (char *)&len, sizeof(len)); - memcpy((char *)&wreq.wi_val + sizeof(len), - (char *)&sc->wi_aps, - len * sizeof(struct wi_apinfo)); - } - } else if (wreq.wi_type == WI_RID_DEFLT_CRYPT_KEYS) { - /* For non-root user, return all-zeroes keys */ - if (suser(p->p_ucred, &p->p_acflag)) - memset((char *)&wreq, 0, - sizeof(struct wi_ltv_keys)); - else - memcpy((char *)&wreq, (char *)&sc->wi_keys, - sizeof(struct wi_ltv_keys)); - } else { - if (sc->sc_enabled == 0 || - (wreq.wi_type == WI_RID_ROAMING_MODE && - (sc->wi_flags & WI_FLAGS_HAS_ROAMING) == 0) || - (wreq.wi_type == WI_RID_CREATE_IBSS && - (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) == 0) || - (wreq.wi_type == WI_RID_MICROWAVE_OVEN && - (sc->wi_flags & WI_FLAGS_HAS_MOR) == 0)) - error = wi_getdef(sc, &wreq); - else if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) - error = EINVAL; + case SIOCADDMULTI: + case SIOCDELMULTI: + error = (cmd == SIOCADDMULTI) ? + ether_addmulti(ifr, &sc->sc_ic.ic_ec) : + ether_delmulti(ifr, &sc->sc_ic.ic_ec); + if (error == ENETRESET) { + if (sc->sc_enabled) { + /* do not rescan */ + error = wi_write_multi(sc); + } else + error = 0; } - if (error == 0) - error = copyout(&wreq, ifr->ifr_data, sizeof(wreq)); break; - case SIOCSWAVELAN: - error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); + case SIOCGIFGENERIC: + error = wi_get_cfg(ifp, cmd, data); + break; + case SIOCSIFGENERIC: + error = suser(curproc->p_ucred, &curproc->p_acflag); if (error) break; - error = EINVAL; - if (wreq.wi_len > WI_MAX_DATALEN) - break; - switch (wreq.wi_type) { - case WI_RID_IFACE_STATS: + error = wi_set_cfg(ifp, cmd, data); + if (error == ENETRESET) { if (sc->sc_enabled) - wi_inquire(sc); - break; - case WI_RID_MGMT_XMIT: - error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val, - wreq.wi_len); - break; - case WI_RID_SCAN_APS: - error = 0; - if (wreq.wi_len != 4) { - error = EINVAL; - break; - } - if (!sc->wi_scanning) { - switch (sc->sc_firmware_type) { - case WI_LUCENT: - break; - case WI_INTERSIL: - wreq.wi_type = WI_RID_SCAN_REQ; - error = wi_write_record(sc, - (struct wi_ltv_gen *)&wreq); - break; - case WI_SYMBOL: - /* - * XXX only supported on 3.x ? - */ - wreq.wi_type = WI_RID_BCAST_SCAN_REQ; - wreq.wi_val[0] = - BSCAN_BCAST | BSCAN_ONETIME; - wreq.wi_len = 2; - error = wi_write_record(sc, - (struct wi_ltv_gen *)&wreq); - break; - } - if (!error) { - sc->wi_scanning = 1; - callout_reset(&sc->wi_scan_sh, hz * 1, - wi_wait_scan, sc); - } - } - break; - default: - error = 0; - /* - * Filter stuff out based on what the - * card can do. - */ - if ((wreq.wi_type == WI_RID_ROAMING_MODE && - (sc->wi_flags & WI_FLAGS_HAS_ROAMING) == 0) || - (wreq.wi_type == WI_RID_CREATE_IBSS && - (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) == 0) || - (wreq.wi_type == WI_RID_MICROWAVE_OVEN && - (sc->wi_flags & WI_FLAGS_HAS_MOR) == 0)) - break; - - if (wreq.wi_len > WI_MAX_DATALEN) - error = EINVAL; - else if (sc->sc_enabled != 0) - error = wi_write_record(sc, - (struct wi_ltv_gen *)&wreq); - if (error == 0) - error = wi_setdef(sc, &wreq); - if (error == 0 && sc->sc_enabled != 0) - /* Reinitialize WaveLAN. */ - wi_init(ifp); - } - break; - case SIOCS80211BSSID: - - if (sc->wi_ptype != WI_PORTTYPE_IBSS && - sc->wi_ptype != WI_PORTTYPE_BSS) { - error = EINVAL; - break; - } - /* don't join twice. */ - if (sc->wi_flags & WI_FLAGS_JOINING) { - error = EAGAIN; - break; - } - - (void)memcpy(&sc->wi_join_bssid, - &((struct ieee80211_bssid *)data)->i_bssid, - sizeof(sc->wi_join_bssid)); - - error = wi_join_bss(sc); - break; - case SIOCG80211BSSID: - if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) { - (void)memcpy(&((struct ieee80211_bssid *)data)->i_bssid, - LLADDR(ifp->if_sadl), IEEE80211_ADDR_LEN); - } else { - (void)memcpy( - &((struct ieee80211_bssid *)data)->i_bssid, - &sc->wi_current_bssid, - sizeof(sc->wi_current_bssid)); - } - break; - case SIOCS80211CHANNEL: - error = wi_set_channel(sc, ((struct ieee80211_channel *)data)); - break; - case SIOCG80211CHANNEL: - error = wi_get_channel(sc, ((struct ieee80211_channel *)data)); - break; - case SIOCG80211NWID: - if (sc->sc_enabled == 0) { - /* Return the desired ID */ - error = copyout(&sc->wi_netid, ifr->ifr_data, - sizeof(sc->wi_netid)); - } else { - wreq.wi_type = WI_RID_CURRENT_SSID; - wreq.wi_len = WI_MAX_DATALEN; - if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) || - le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) - error = EINVAL; - else { - wi_set_ssid(&nwid, (u_int8_t *)&wreq.wi_val[1], - le16toh(wreq.wi_val[0])); - error = copyout(&nwid, ifr->ifr_data, - sizeof(nwid)); - } - } - break; - case SIOCS80211NWID: - error = copyin(ifr->ifr_data, &nwid, sizeof(nwid)); - if (error != 0) - break; - if (nwid.i_len > IEEE80211_NWID_LEN) { - error = EINVAL; - break; + error = wi_init(ifp); + else + error = 0; } - if (sc->wi_netid.i_len == nwid.i_len && - memcmp(sc->wi_netid.i_nwid, nwid.i_nwid, nwid.i_len) == 0) - break; - wi_set_ssid(&sc->wi_netid, nwid.i_nwid, nwid.i_len); - if (sc->sc_enabled != 0) - /* Reinitialize WaveLAN. */ - wi_init(ifp); - break; - case SIOCS80211NWKEY: - error = wi_set_nwkey(sc, (struct ieee80211_nwkey *)data); - break; - case SIOCG80211NWKEY: - error = wi_get_nwkey(sc, (struct ieee80211_nwkey *)data); break; - case SIOCS80211POWER: - error = wi_set_pm(sc, (struct ieee80211_power *)data); - break; - case SIOCG80211POWER: - error = wi_get_pm(sc, (struct ieee80211_power *)data); - break; - case SIOCHOSTAP_ADD: - case SIOCHOSTAP_DEL: - case SIOCHOSTAP_GET: - case SIOCHOSTAP_GETALL: - case SIOCHOSTAP_GFLAGS: - case SIOCHOSTAP_SFLAGS: - /* Send all Host-AP specific ioctls to the Host-AP code. */ - error = wihap_ioctl(sc, command, data); - break; - default: - error = EINVAL; + error = ieee80211_ioctl(ifp, cmd, data); + if (error == ENETRESET) { + if (sc->sc_enabled) + error = wi_init(ifp); + else + error = 0; + } break; } - splx(s); - return (error); + return error; } static int -wi_init(ifp) - struct ifnet *ifp; +wi_media_change(struct ifnet *ifp) { struct wi_softc *sc = ifp->if_softc; - struct wi_req wreq; - struct wi_ltv_macaddr mac; - int s, error, id = 0, wasenabled; - - if (!sc->sc_attached) - return(ENODEV); - - s = splnet(); - wasenabled = sc->sc_enabled; - if (!sc->sc_enabled) { - if ((error = (*sc->sc_enable)(sc)) != 0) - goto out; - sc->sc_enabled = 1; - } - - wi_stop(ifp, 0); - /* Symbol firmware cannot be initialized more than once */ - if (!(sc->sc_firmware_type == WI_SYMBOL && wasenabled)) - wi_reset(sc); - - /* Program max data length. */ - WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len); - - /* Enable/disable IBSS creation. */ - WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss); - - /* Set the port type. */ - WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype); - - /* Program the RTS/CTS threshold. */ - WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh); + struct ieee80211com *ic = &sc->sc_ic; + struct ifmedia_entry *ime; + int i, rate, error = 0; - /* Program the TX rate */ - WI_SETVAL(WI_RID_TX_RATE, sc->wi_tx_rate); - - /* Access point density */ - WI_SETVAL(WI_RID_SYSTEM_SCALE, sc->wi_ap_density); - - /* Power Management Enabled */ - WI_SETVAL(WI_RID_PM_ENABLED, sc->wi_pm_enabled); - - /* Power Managment Max Sleep */ - WI_SETVAL(WI_RID_MAX_SLEEP, sc->wi_max_sleep); - - /* Roaming type */ - if (sc->wi_flags & WI_FLAGS_HAS_ROAMING) - WI_SETVAL(WI_RID_ROAMING_MODE, sc->wi_roaming); - - /* Specify the network name */ - wi_write_ssid(sc, WI_RID_DESIRED_SSID, &wreq, &sc->wi_netid); - - /* Specify the IBSS name */ - if (sc->wi_netid.i_len != 0 && - (sc->wi_ptype == WI_PORTTYPE_HOSTAP || - (sc->wi_create_ibss && sc->wi_ptype == WI_PORTTYPE_IBSS))) - wi_write_ssid(sc, WI_RID_OWN_SSID, &wreq, &sc->wi_netid); - else - wi_write_ssid(sc, WI_RID_OWN_SSID, &wreq, &sc->wi_ibssid); - - /* Specify the frequency to use */ - WI_SETVAL(WI_RID_OWN_CHNL, sc->wi_create_channel); - - /* Program the nodename. */ - wi_write_ssid(sc, WI_RID_NODENAME, &wreq, &sc->wi_nodeid); - - /* Set our MAC address. */ - mac.wi_len = 4; - mac.wi_type = WI_RID_MAC_NODE; - memcpy(&mac.wi_mac_addr, sc->sc_macaddr, ETHER_ADDR_LEN); - wi_write_record(sc, (struct wi_ltv_gen *)&mac); - - /* - * Initialize promiscuous mode. - * Being in the Host-AP mode causes a great - * deal of pain if promiscuous mode is set. - * Therefore we avoid confusing the firmware - * and always reset promiscuous mode in Host-AP - * mode. Host-AP sees all the packets anyway. - */ - if (sc->wi_ptype != WI_PORTTYPE_HOSTAP && - (ifp->if_flags & IFF_PROMISC) != 0) { - WI_SETVAL(WI_RID_PROMISC, 1); + ime = sc->sc_media.ifm_cur; + if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) { + ic->ic_fixed_rate = -1; } else { - WI_SETVAL(WI_RID_PROMISC, 0); - } - - /* Configure WEP. */ - if (sc->wi_flags & WI_FLAGS_HAS_WEP) { - WI_SETVAL(WI_RID_ENCRYPTION, sc->wi_use_wep); - WI_SETVAL(WI_RID_TX_CRYPT_KEY, sc->wi_tx_key); - sc->wi_keys.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1; - sc->wi_keys.wi_type = WI_RID_DEFLT_CRYPT_KEYS; - wi_write_record(sc, (struct wi_ltv_gen *)&sc->wi_keys); - if (sc->sc_firmware_type != WI_LUCENT && sc->wi_use_wep) { - /* - * ONLY HWB3163 EVAL-CARD Firmware version - * less than 0.8 variant2 - * - * If promiscuous mode disable, Prism2 chip - * does not work with WEP . - * It is under investigation for details. - * (ichiro@netbsd.org) - */ - if (sc->sc_firmware_type == WI_INTERSIL && - sc->sc_sta_firmware_ver < 802 ) { - /* firm ver < 0.8 variant 2 */ - WI_SETVAL(WI_RID_PROMISC, 1); - } - WI_SETVAL(WI_RID_CNFAUTHMODE, sc->wi_authtype); + rate = ieee80211_media2rate(ime->ifm_media, IEEE80211_T_DS); + if (rate == 0) + return EINVAL; + for (i = 0; i < IEEE80211_RATE_SIZE; i++) { + if ((ic->ic_sup_rates[i] & IEEE80211_RATE_VAL) == rate) + break; } + if (i == IEEE80211_RATE_SIZE) + return EINVAL; + ic->ic_fixed_rate = i; } - /* Set multicast filter. */ - wi_setmulti(sc); - - sc->wi_flags &= ~(WI_FLAGS_JOINING | WI_FLAGS_CONNECTED | - WI_FLAGS_AP_IN_RANGE); - - /* Enable desired port */ - wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 0, 0, 0); - - /* scanning variable is modal, therefore reinit to OFF, in case it was on. */ - sc->wi_scanning=0; - sc->wi_naps=0; - - if ((error = wi_alloc_nicmem(sc, WI_TX_BUFSIZE, &id)) != 0) { - printf("%s: tx buffer allocation failed\n", - sc->sc_dev.dv_xname); - goto out; - } - sc->wi_tx_data_id = id; - - if ((error = wi_alloc_nicmem(sc, WI_TX_BUFSIZE, &id)) != 0) { - printf("%s: mgmt. buffer allocation failed\n", - sc->sc_dev.dv_xname); - goto out; + if ((ime->ifm_media & IFM_IEEE80211_ADHOC) && + (ime->ifm_media & IFM_FLAG0)) { + if (ic->ic_opmode != IEEE80211_M_ADHOC || + (sc->sc_flags & WI_FLAGS_NO_BSSID) == 0) { + ic->ic_opmode = IEEE80211_M_ADHOC; + ic->ic_flags &= ~IEEE80211_F_IBSSON; + sc->sc_flags |= WI_FLAGS_NO_BSSID; + error = ENETRESET; + } + } else if (ime->ifm_media & IFM_IEEE80211_ADHOC) { + if (ic->ic_opmode != IEEE80211_M_ADHOC || + (sc->sc_flags & WI_FLAGS_NO_BSSID)) { + ic->ic_opmode = IEEE80211_M_ADHOC; + ic->ic_flags |= IEEE80211_F_IBSSON; + sc->sc_flags &= ~WI_FLAGS_NO_BSSID; + error = ENETRESET; + } + } else if (ime->ifm_media & IFM_IEEE80211_HOSTAP) { + if (ic->ic_opmode != IEEE80211_M_HOSTAP) { + ic->ic_opmode = IEEE80211_M_HOSTAP; + ic->ic_flags &= ~IEEE80211_F_IBSSON; + sc->sc_flags &= ~WI_FLAGS_NO_BSSID; + error = ENETRESET; + } + } else { + if (ic->ic_opmode != IEEE80211_M_STA) { + ic->ic_opmode = IEEE80211_M_STA; + ic->ic_flags &= ~IEEE80211_F_IBSSON; + sc->sc_flags &= ~WI_FLAGS_NO_BSSID; + error = ENETRESET; + } } - sc->wi_tx_mgmt_id = id; - - /* Enable interrupts */ - CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); - - wihap_init(sc); - - out: - if (error) { - ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); - ifp->if_timer = 0; - printf("%s: interface not running\n", sc->sc_dev.dv_xname); - splx(s); - return error; + if (error == ENETRESET) { + if (sc->sc_enabled) + error = wi_init(ifp); + else + error = 0; } + ifp->if_baudrate = ifmedia_baudrate(sc->sc_media.ifm_cur->ifm_media); - ifp->if_flags |= IFF_RUNNING; - ifp->if_flags &= ~IFF_OACTIVE; - - callout_reset(&sc->wi_inquire_ch, hz * 60, wi_inquire, sc); - - splx(s); return 0; } -static const u_int32_t crc32_tab[] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL -}; - -#define RC4STATE 256 -#define RC4KEYLEN 16 -#define RC4SWAP(x,y) \ - do { u_int8_t t = state[x]; state[x] = state[y]; state[y] = t; } while(0) - static void -wi_do_hostencrypt(struct wi_softc *sc, caddr_t buf, int len) +wi_media_status(struct ifnet *ifp, struct ifmediareq *imr) { - u_int32_t i, crc, klen; - u_int8_t state[RC4STATE], key[RC4KEYLEN]; - u_int8_t x, y, *dat; + struct wi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; + u_int16_t val; + int rate, len; - if (!sc->wi_icv_flag) { - sc->wi_icv = arc4random(); - sc->wi_icv_flag++; - } else - sc->wi_icv++; - /* - * Skip 'bad' IVs from Fluhrer/Mantin/Shamir: - * (B, 255, N) with 3 <= B < 8 - */ - if (sc->wi_icv >= 0x03ff00 && - (sc->wi_icv & 0xf8ff00) == 0x00ff00) - sc->wi_icv += 0x000100; - - /* prepend 24bit IV to tx key, byte order does not matter */ - key[0] = sc->wi_icv >> 16; - key[1] = sc->wi_icv >> 8; - key[2] = sc->wi_icv; - - klen = le16toh(sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keylen) + - IEEE80211_WEP_IVLEN; - klen = (klen >= RC4KEYLEN) ? RC4KEYLEN : RC4KEYLEN/2; - bcopy((char *)&sc->wi_keys.wi_keys[sc->wi_tx_key].wi_keydat, - (char *)key + IEEE80211_WEP_IVLEN, klen - IEEE80211_WEP_IVLEN); - - /* rc4 keysetup */ - x = y = 0; - for (i = 0; i < RC4STATE; i++) - state[i] = i; - for (i = 0; i < RC4STATE; i++) { - y = (key[x] + state[i] + y) % RC4STATE; - RC4SWAP(i, y); - x = (x + 1) % klen; - } - - /* output: IV, tx keyid, rc4(data), rc4(crc32(data)) */ - dat = buf; - dat[0] = key[0]; - dat[1] = key[1]; - dat[2] = key[2]; - dat[3] = sc->wi_tx_key << 6; /* pad and keyid */ - dat += 4; - - /* compute rc4 over data, crc32 over data */ - crc = ~0; - x = y = 0; - for (i = 0; i < len; i++) { - x = (x + 1) % RC4STATE; - y = (state[x] + y) % RC4STATE; - RC4SWAP(x, y); - crc = crc32_tab[(crc ^ dat[i]) & 0xff] ^ (crc >> 8); - dat[i] ^= state[(state[x] + state[y]) % RC4STATE]; - } - crc = ~crc; - dat += len; - - /* append little-endian crc32 and encrypt */ - dat[0] = crc; - dat[1] = crc >> 8; - dat[2] = crc >> 16; - dat[3] = crc >> 24; - for (i = 0; i < IEEE80211_WEP_CRCLEN; i++) { - x = (x + 1) % RC4STATE; - y = (state[x] + y) % RC4STATE; - RC4SWAP(x, y); - dat[i] ^= state[(state[x] + state[y]) % RC4STATE]; + if (sc->sc_enabled == 0) { + imr->ifm_active = IFM_IEEE80211 | IFM_NONE; + imr->ifm_status = 0; + return; + } + + imr->ifm_status = IFM_AVALID; + imr->ifm_active = IFM_IEEE80211; + if (ic->ic_state == IEEE80211_S_RUN) + imr->ifm_status |= IFM_ACTIVE; + if (ic->ic_fixed_rate != -1) + rate = ic->ic_sup_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL; + else { + len = sizeof(val); + if (wi_read_rid(sc, WI_RID_CUR_TX_RATE, &val, &len) != 0) + rate = 0; + else { + /* convert to 802.11 rate */ + rate = val * 2; + if (rate == 12) + rate = 11; /* 5.5Mbps */ + } + } + imr->ifm_active |= ieee80211_rate2media(rate, IEEE80211_T_DS); + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + break; + case IEEE80211_M_ADHOC: + imr->ifm_active |= IFM_IEEE80211_ADHOC; + if ((sc->sc_flags & WI_FLAGS_NO_BSSID)) + imr->ifm_active |= IFM_FLAG0; + break; + case IEEE80211_M_HOSTAP: + imr->ifm_active |= IFM_IEEE80211_HOSTAP; + break; } } static void -wi_start(ifp) - struct ifnet *ifp; +wi_rx_intr(struct wi_softc *sc) { - struct wi_softc *sc; - struct mbuf *m0; - struct ether_header *eh; - int id; - int len; - struct wi_frame *hdr; - struct llc *llc; - u_int8_t *body, *payload; -#if defined(WI_HOSTAP_POWERSAVE) - int more_data = 0; -#endif + struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = &ic->ic_if; + struct wi_frame frmhdr; + struct mbuf *m; + struct ieee80211_frame *wh; + u_int16_t status; + int fid, len, off; - sc = ifp->if_softc; + fid = CSR_READ_2(sc, WI_RX_FID); - if (!sc->sc_attached) - return; - - if (ifp->if_flags & IFF_OACTIVE) + /* First read in the frame header */ + if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr))) { + CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); + ifp->if_ierrors++; + DPRINTF(("wi_rx_intr: read fid %x failed\n", fid)); return; + } - /* discard packets when disconnected. postpone sending packets when - * connected but out of range. + /* + * Drop undecryptable or packets with receive errors here */ - if (!(sc->wi_flags & WI_FLAGS_AP_IN_RANGE) && - (sc->wi_flags & WI_FLAGS_CONNECTED)) { + status = le16toh(frmhdr.wi_status); + if (status & WI_STAT_ERRSTAT) { + CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); + ifp->if_ierrors++; + DPRINTF(("wi_rx_intr: fid %x error status %x\n", fid, status)); return; } - hdr = (struct wi_frame *)&sc->wi_txbuf; - - body = (u_int8_t *)(hdr + 1); - - if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) { - llc = (struct llc *)(body + IEEE80211_WEP_IVLEN + - IEEE80211_WEP_KIDLEN); - } else { - llc = (struct llc *)body; - } - - payload = (u_int8_t *)(llc + 1); - nextpkt: -#if defined(WI_HOSTAP_POWERSAVE) - /* power-save queue, first. */ - if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) - m0 = wihap_dequeue(&sc->wi_hostap_info, &more_data); + len = le16toh(frmhdr.wi_dat_len); + off = ALIGN(sizeof(struct ieee80211_frame)); - if (m0 == NULL) -#endif /* WI_HOSTAP_POWERSAVE */ - IFQ_DEQUEUE(&ifp->if_snd, m0); - - if (m0 == NULL) + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) { + CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); + ifp->if_ierrors++; + DPRINTF(("wi_rx_intr: MGET failed\n")); return; - - bzero(hdr, sizeof(*hdr)); - hdr->wi_frame_ctl = htole16(WI_FTYPE_DATA); - id = sc->wi_tx_data_id; - eh = mtod(m0, struct ether_header *); - -#if defined(OPTIMIZE_RW_DATA) - wi_rewind(sc); -#endif - - if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) { - if (wihap_check_tx(sc, m0, &hdr->wi_tx_rate) == 0) - goto nextpkt; -#if defined(WI_HOSTAP_POWERSAVE) - if (more_data) - hdr->wi_frame_ctl |= htole16(WI_FCTL_PM); -#endif /* WI_HOSTAP_POWERSAVE */ } - - /* - * Use RFC1042 encoding for everything. - */ - - hdr->wi_tx_ctl |= htole16(WI_ENC_TX_802_11); - - if (sc->wi_ptype == WI_PORTTYPE_HOSTAP) { - hdr->wi_frame_ctl |= htole16(WI_FCTL_FROMDS); - memcpy(&hdr->wi_addr1, &eh->ether_dhost, - IEEE80211_ADDR_LEN); - memcpy(&hdr->wi_addr2, LLADDR(ifp->if_sadl), - IEEE80211_ADDR_LEN); - memcpy((char *)&hdr->wi_addr3, - (char *)&eh->ether_shost, IEEE80211_ADDR_LEN); - } else { - if (sc->wi_ptype == WI_PORTTYPE_BSS) { - hdr->wi_frame_ctl |= htole16(WI_FCTL_TODS); - memcpy(&hdr->wi_addr1, &sc->wi_current_bssid, - IEEE80211_ADDR_LEN); - memcpy(&hdr->wi_addr3, &eh->ether_dhost, - IEEE80211_ADDR_LEN); - } else { - memcpy(&hdr->wi_addr1, &eh->ether_dhost, - IEEE80211_ADDR_LEN); - memcpy(&hdr->wi_addr3, &sc->wi_current_bssid, - IEEE80211_ADDR_LEN); + if (off + len > MHLEN) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); + m_freem(m); + ifp->if_ierrors++; + DPRINTF(("wi_rx_intr: MCLGET failed\n")); + return; } - memcpy(&hdr->wi_addr2, &eh->ether_shost, - IEEE80211_ADDR_LEN); - } - - len = sizeof(struct llc) - sizeof(struct ether_header) + - m0->m_pkthdr.len; - - 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; - - m_copydata(m0, sizeof(struct ether_header), - m0->m_pkthdr.len - sizeof(struct ether_header), - payload); - - if (sc->wi_ptype == WI_PORTTYPE_HOSTAP && sc->wi_use_wep) { - - hdr->wi_frame_ctl |= htole16(WI_FCTL_WEP); - - wi_do_hostencrypt(sc, body, len); - - len += IEEE80211_WEP_IVLEN + - IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; } - hdr->wi_dat_len = htole16(len); + m->m_data += off - sizeof(struct ieee80211_frame); + memcpy(m->m_data, &frmhdr.wi_whdr, sizeof(struct ieee80211_frame)); + wi_read_bap(sc, fid, sizeof(frmhdr), + m->m_data + sizeof(struct ieee80211_frame), len); + m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + len; + m->m_pkthdr.rcvif = ifp; - wi_write_data(sc, id, 0, (caddr_t)&sc->wi_txbuf, - sizeof(struct wi_frame) + len); + CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX); #if NBPFILTER > 0 - /* - * If there's a BPF listener, bounce a copy of - * this frame to him. - */ - wi_tap_802_3(sc, m0, hdr); -#endif - - m_freem(m0); - - if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) - printf("%s: xmit failed\n", sc->sc_dev.dv_xname); + if (sc->sc_drvbpf) { + struct mbuf mb; - ifp->if_flags |= IFF_OACTIVE; - - /* - * Set a timeout in case the chip goes out to lunch. - */ - ifp->if_timer = 5; - - return; -} - -int -wi_mgmt_xmit(sc, data, len) - struct wi_softc *sc; - caddr_t data; - int len; -{ - struct wi_frame *tx_frame; - int id; - struct wi_80211_hdr *hdr; - caddr_t dptr; - struct mbuf *m0, *m1; - -#if defined(OPTIMIZE_RW_DATA) - wi_rewind(sc); -#endif - - if (!sc->sc_attached) - return(ENODEV); - - KASSERT(MHLEN >= sizeof(*tx_frame)); - - MGETHDR(m0, M_DONTWAIT, MT_DATA); - if (m0 == NULL) - return (ENOMEM); - MGET(m1, M_DONTWAIT, MT_DATA); - if (m1 == NULL) { - m_free(m0); - return (ENOMEM); + M_COPY_PKTHDR(&mb, m); + mb.m_data = (caddr_t)&frmhdr; + mb.m_len = sizeof(frmhdr); + mb.m_next = m; + mb.m_pkthdr.len += mb.m_len; + bpf_mtap(sc->sc_drvbpf, &mb); } - - tx_frame = mtod(m0, struct wi_frame *); - memset(tx_frame, 0, sizeof(*tx_frame)); - - hdr = (struct wi_80211_hdr *)data; - dptr = data + sizeof(struct wi_80211_hdr); - - id = sc->wi_tx_mgmt_id; - - memcpy(&tx_frame->wi_frame_ctl, hdr, sizeof(struct wi_80211_hdr)); - - tx_frame->wi_tx_ctl |= htole16(WI_ENC_TX_802_11); - tx_frame->wi_dat_len = len - sizeof(struct wi_80211_hdr); - tx_frame->wi_len = htole16(tx_frame->wi_dat_len); - - tx_frame->wi_dat_len = htole16(tx_frame->wi_dat_len); - - wi_write_data(sc, id, 0, (caddr_t)tx_frame, sizeof(*tx_frame)); - wi_write_data(sc, id, sizeof(*tx_frame), dptr, - (len - sizeof(struct wi_80211_hdr))); - - m0->m_len = WI_SHORT_802_11_END; /* XXX */ - m0->m_next = m1; - m1->m_data = dptr; /* XXX */ - m1->m_len = len - sizeof(struct wi_80211_hdr); - m1->m_next = 0; - - m0->m_pkthdr.len = m0->m_len + m1->m_len; - - wi_tap_802_11_plus(sc, m0); - - m_freem(m0); - - if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0)) { - printf("%s: xmit failed\n", sc->sc_dev.dv_xname); - return(EIO); +#endif + wh = mtod(m, struct ieee80211_frame *); + if (wh->i_fc[1] & IEEE80211_FC1_WEP) { + /* + * WEP is decrypted by hardware. Clear WEP bit + * header for ieee80211_input(). + */ + wh->i_fc[1] &= ~IEEE80211_FC1_WEP; } - - return(0); + ieee80211_input(ifp, m, 0 /*rssi*/, 0 /*rstamp*/); } static void -wi_stop(ifp, disable) - struct ifnet *ifp; +wi_tx_intr(struct wi_softc *sc) { - struct wi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = &ic->ic_if; + int fid, cur; - wihap_shutdown(sc); + fid = CSR_READ_2(sc, WI_ALLOC_FID); + CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); - if (!sc->sc_attached) + cur = sc->sc_txcur; + if (sc->sc_txd[cur].d_fid != fid) { + printf("%s: bad alloc %x != %x\n", + sc->sc_dev.dv_xname, fid, sc->sc_txd[cur].d_fid); return; - - CSR_WRITE_2(sc, WI_INT_EN, 0); - wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0, 0, 0); - - callout_stop(&sc->wi_inquire_ch); - callout_stop(&sc->wi_scan_sh); - - if (disable) { - if (sc->sc_enabled) { - if (sc->sc_disable) - (*sc->sc_disable)(sc); - sc->sc_enabled = 0; + } + sc->sc_tx_timer = 0; + sc->sc_txd[cur].d_len = 0; + sc->sc_txcur = cur = (cur + 1) % WI_NTXBUF; + if (sc->sc_txd[cur].d_len == 0) + ifp->if_flags &= ~IFF_OACTIVE; + else { + if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, sc->sc_txd[cur].d_fid, + 0, 0)) { + printf("%s: xmit failed\n", sc->sc_dev.dv_xname); + sc->sc_txd[cur].d_len = 0; + } else { + sc->sc_tx_timer = 5; + ifp->if_timer = 1; } } - - ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING); - ifp->if_timer = 0; } static void -wi_watchdog(ifp) - struct ifnet *ifp; +wi_info_intr(struct wi_softc *sc) { - struct wi_softc *sc; - - sc = ifp->if_softc; - - printf("%s: device timeout\n", sc->sc_dev.dv_xname); + struct ieee80211com *ic = &sc->sc_ic; + struct ifnet *ifp = &ic->ic_if; + int i, fid, len, off; + u_int16_t ltbuf[2]; + u_int16_t stat; + u_int32_t *ptr; + + fid = CSR_READ_2(sc, WI_INFO_FID); + wi_read_bap(sc, fid, 0, ltbuf, sizeof(ltbuf)); + + switch (le16toh(ltbuf[1])) { + + case WI_INFO_LINK_STAT: + wi_read_bap(sc, fid, sizeof(ltbuf), &stat, sizeof(stat)); + DPRINTF(("wi_info_intr: LINK_STAT 0x%x\n", le16toh(stat))); + switch (le16toh(stat)) { + case CONNECTED: + if (ic->ic_state == IEEE80211_S_RUN) + break; + /* FALLTHROUGH */ + case AP_CHANGE: + case AP_IN_RANGE: + ieee80211_new_state(ifp, IEEE80211_S_RUN, -1); + break; + case AP_OUT_OF_RANGE: + if (sc->sc_firmware_type == WI_SYMBOL && + sc->sc_scan_timer > 0) { + if (wi_cmd(sc, WI_CMD_INQUIRE, + WI_INFO_HOST_SCAN_RESULTS, 0, 0) != 0) + sc->sc_scan_timer = 0; + break; + } + /* FALLTHROUGH */ + case DISCONNECTED: + case ASSOC_FAILED: + if ((ic->ic_opmode == IEEE80211_M_ADHOC && + (sc->sc_flags & WI_FLAGS_NO_BSSID)) || + ic->ic_opmode == IEEE80211_M_HOSTAP) + ; + else + ieee80211_new_state(ifp, IEEE80211_S_INIT, -1); + break; + } + break; - wi_init(ifp); + case WI_INFO_COUNTERS: + /* some card versions have a larger stats structure */ + len = min(le16toh(ltbuf[0]) - 1, sizeof(sc->sc_stats) / 4); + ptr = (u_int32_t *)&sc->sc_stats; + off = sizeof(ltbuf); + for (i = 0; i < len; i++, off += 2, ptr++) { + wi_read_bap(sc, fid, off, &stat, sizeof(stat)); +#ifdef WI_HERMES_STATS_WAR + if (stat & 0xf000) + stat = ~stat; +#endif + *ptr += stat; + } + ifp->if_collisions = sc->sc_stats.wi_tx_single_retries + + sc->sc_stats.wi_tx_multi_retries + + sc->sc_stats.wi_tx_retry_limit; + break; - ifp->if_oerrors++; + case WI_INFO_SCAN_RESULTS: + case WI_INFO_HOST_SCAN_RESULTS: + wi_scan_result(sc, fid, le16toh(ltbuf[0])); + break; - return; + default: + DPRINTF(("wi_info_intr: got fid %x type %x len %d\n", fid, + le16toh(ltbuf[1]), le16toh(ltbuf[0]))); + break; + } + CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO); } -void -wi_shutdown(sc) - struct wi_softc *sc; +/* + * Allocate a region of memory inside the NIC and zero + * it out. + */ +static int +wi_write_multi(struct wi_softc *sc) { - int s; + struct ifnet *ifp = &sc->sc_ic.ic_if; + int n = 0; + struct wi_mcast mlist; + struct ether_multi *enm; + struct ether_multistep estep; - s = splnet(); - if (sc->sc_enabled) { - wi_stop(&sc->sc_ethercom.ec_if, 0); - if (sc->sc_disable) - (*sc->sc_disable)(sc); - sc->sc_enabled = 0; + if ((ifp->if_flags & IFF_PROMISC) != 0) { +allmulti: + ifp->if_flags |= IFF_ALLMULTI; + memset(&mlist, 0, sizeof(mlist)); + return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist, + sizeof(mlist)); } - splx(s); -} - -int -wi_activate(self, act) - struct device *self; - enum devact act; -{ - struct wi_softc *sc = (struct wi_softc *)self; - int rv = 0, s; - - s = splnet(); - switch (act) { - case DVACT_ACTIVATE: - rv = EOPNOTSUPP; - break; + n = 0; + ETHER_FIRST_MULTI(estep, &sc->sc_ic.ic_ec, enm); + while (enm != NULL) { + /* Punt on ranges or too many multicast addresses. */ + if (!IEEE80211_ADDR_EQ(enm->enm_addrlo, enm->enm_addrhi) || + n >= sizeof(mlist) / sizeof(mlist.wi_mcast[0])) + goto allmulti; - case DVACT_DEACTIVATE: - if_deactivate(&sc->sc_ethercom.ec_if); - break; + IEEE80211_ADDR_COPY(&mlist.wi_mcast[n], enm->enm_addrlo); + n++; + ETHER_NEXT_MULTI(estep, enm); } - splx(s); - return (rv); + ifp->if_flags &= ~IFF_ALLMULTI; + return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist, + IEEE80211_ADDR_LEN * n); } + static void -wi_get_id(sc) +wi_read_nicid(sc) struct wi_softc *sc; { - struct wi_ltv_ver ver; - struct wi_card_ident *id; + struct wi_card_ident *id; + char *p; + int len; + u_int16_t ver[4]; /* getting chip identity */ - memset(&ver, 0, sizeof(ver)); - ver.wi_type = WI_RID_CARD_ID; - ver.wi_len = 5; - wi_read_record(sc, (struct wi_ltv_gen *)&ver); + memset(ver, 0, sizeof(ver)); + len = sizeof(ver); + wi_read_rid(sc, WI_RID_CARD_ID, ver, &len); printf("%s: using ", sc->sc_dev.dv_xname); +DPRINTF2(("wi_read_nicid: CARD_ID: %x %x %x %x\n", le16toh(ver[0]), le16toh(ver[1]), le16toh(ver[2]), le16toh(ver[3]))); sc->sc_firmware_type = WI_NOTYPE; for (id = wi_card_ident; id->card_name != NULL; id++) { - if (le16toh(ver.wi_ver[0]) == id->card_id) { + if (le16toh(ver[0]) == id->card_id) { printf("%s", id->card_name); sc->sc_firmware_type = id->firm_type; break; } } if (sc->sc_firmware_type == WI_NOTYPE) { - if (le16toh(ver.wi_ver[0]) & 0x8000) { + if (le16toh(ver[0]) & 0x8000) { printf("Unknown PRISM2 chip"); sc->sc_firmware_type = WI_INTERSIL; } else { @@ -3105,559 +1315,796 @@ wi_get_id(sc) /* get primary firmware version (Only Prism chips) */ if (sc->sc_firmware_type != WI_LUCENT) { - memset(&ver, 0, sizeof(ver)); - ver.wi_type = WI_RID_PRI_IDENTITY; - ver.wi_len = 5; - wi_read_record(sc, (struct wi_ltv_gen *)&ver); - LE16TOH(ver.wi_ver[1]); - LE16TOH(ver.wi_ver[2]); - LE16TOH(ver.wi_ver[3]); - sc->sc_pri_firmware_ver = ver.wi_ver[2] * 10000 + - ver.wi_ver[3] * 100 + ver.wi_ver[1]; + memset(ver, 0, sizeof(ver)); + len = sizeof(ver); + wi_read_rid(sc, WI_RID_PRI_IDENTITY, ver, &len); + sc->sc_pri_firmware_ver = le16toh(ver[2]) * 10000 + + le16toh(ver[3]) * 100 + le16toh(ver[1]); +DPRINTF2(("wi_read_nicid: PRI_ID: %x %x %x %x\n", le16toh(ver[0]), le16toh(ver[1]), le16toh(ver[2]), le16toh(ver[3]))); } /* get station firmware version */ - memset(&ver, 0, sizeof(ver)); - ver.wi_type = WI_RID_STA_IDENTITY; - ver.wi_len = 5; - wi_read_record(sc, (struct wi_ltv_gen *)&ver); - LE16TOH(ver.wi_ver[1]); - LE16TOH(ver.wi_ver[2]); - LE16TOH(ver.wi_ver[3]); - sc->sc_sta_firmware_ver = ver.wi_ver[2] * 10000 + - ver.wi_ver[3] * 100 + ver.wi_ver[1]; + memset(ver, 0, sizeof(ver)); + len = sizeof(ver); + wi_read_rid(sc, WI_RID_STA_IDENTITY, ver, &len); + sc->sc_sta_firmware_ver = le16toh(ver[2]) * 10000 + + le16toh(ver[3]) * 100 + le16toh(ver[1]); +DPRINTF2(("wi_read_nicid: STA_ID: %x %x %x %x\n", le16toh(ver[0]), le16toh(ver[1]), le16toh(ver[2]), le16toh(ver[3]))); if (sc->sc_firmware_type == WI_INTERSIL && - (sc->sc_sta_firmware_ver == 10102 || sc->sc_sta_firmware_ver == 20102)) { - struct wi_ltv_str sver; - char *p; - - memset(&sver, 0, sizeof(sver)); - sver.wi_type = WI_RID_SYMBOL_IDENTITY; - sver.wi_len = 7; + (sc->sc_sta_firmware_ver == 10102 || + sc->sc_sta_firmware_ver == 20102)) { + char ident[12]; + memset(ident, 0, sizeof(ident)); + len = sizeof(ident); /* value should be the format like "V2.00-11" */ - if (wi_read_record(sc, (struct wi_ltv_gen *)&sver) == 0 && - *(p = (char *)sver.wi_str) >= 'A' && + if (wi_read_rid(sc, WI_RID_SYMBOL_IDENTITY, ident, &len) == 0 && + *(p = (char *)ident) >= 'A' && p[2] == '.' && p[5] == '-' && p[8] == '\0') { sc->sc_firmware_type = WI_SYMBOL; sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 + (p[3] - '0') * 1000 + (p[4] - '0') * 100 + (p[6] - '0') * 10 + (p[7] - '0'); } +DPRINTF2(("wi_read_nicid: SYMBOL_ID: %x %x %x %x\n", le16toh(ident[0]), le16toh(ident[1]), le16toh(ident[2]), le16toh(ident[3]))); } printf("\n%s: %s Firmware: ", sc->sc_dev.dv_xname, sc->sc_firmware_type == WI_LUCENT ? "Lucent" : (sc->sc_firmware_type == WI_SYMBOL ? "Symbol" : "Intersil")); if (sc->sc_firmware_type != WI_LUCENT) /* XXX */ - printf("Primary (%u.%u.%u), ", sc->sc_pri_firmware_ver / 10000, + printf("Primary (%u.%u.%u), ", + sc->sc_pri_firmware_ver / 10000, (sc->sc_pri_firmware_ver % 10000) / 100, sc->sc_pri_firmware_ver % 100); printf("Station (%u.%u.%u)\n", - sc->sc_sta_firmware_ver / 10000, (sc->sc_sta_firmware_ver % 10000) / 100, + sc->sc_sta_firmware_ver / 10000, + (sc->sc_sta_firmware_ver % 10000) / 100, sc->sc_sta_firmware_ver % 100); - - return; } -int -wi_detach(sc) - struct wi_softc *sc; +static int +wi_write_ssid(struct wi_softc *sc, int rid, u_int8_t *buf, int buflen) { - struct ifnet *ifp = &sc->sc_if; - int s; + struct wi_ssid ssid; - if (!sc->sc_attached) - return (0); - - s = splnet(); - callout_stop(&sc->wi_inquire_ch); - - /* Delete all remaining media. */ - ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); - - /* TBD detach all BPF listeners. */ - 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); + if (buflen > IEEE80211_NWID_LEN) + return ENOBUFS; + ssid.wi_len = htole16(buflen); + memcpy(ssid.wi_ssid, buf, buflen); + return wi_write_rid(sc, rid, &ssid, sizeof(ssid.wi_len) + buflen); } -void -wi_power(sc, why) - struct wi_softc *sc; - int why; +static int +wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data) { - int s; + struct wi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; + struct ifreq *ifr = (struct ifreq *)data; + struct wi_req wreq; + int len, n, error; - if (!sc->sc_enabled) - return; + error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); + if (error) + return error; + len = (wreq.wi_len - 1) * 2; + if (len < sizeof(u_int16_t)) + return ENOSPC; + if (len > sizeof(wreq.wi_val)) + len = sizeof(wreq.wi_val); - s = splnet(); - switch (why) { - case PWR_SUSPEND: - case PWR_STANDBY: - wi_stop(&sc->sc_if, 0); - if (sc->sc_enabled) { - if (sc->sc_disable) - (*sc->sc_disable)(sc); - } - break; - case PWR_RESUME: - sc->sc_enabled = 0; - wi_init(&sc->sc_if); - (void)wi_intr(sc); - break; - case PWR_SOFTSUSPEND: - case PWR_SOFTSTANDBY: - case PWR_SOFTRESUME: + switch (wreq.wi_type) { + + case WI_RID_IFACE_STATS: + memcpy(wreq.wi_val, &sc->sc_stats, sizeof(sc->sc_stats)); + if (len < sizeof(sc->sc_stats)) + error = ENOSPC; + else + len = sizeof(sc->sc_stats); break; - } - splx(s); -} -static int -wi_set_ssid(ws, id, len) - struct ieee80211_nwid *ws; - u_int8_t *id; - int len; -{ + case WI_RID_ENCRYPTION: + case WI_RID_TX_CRYPT_KEY: + case WI_RID_DEFLT_CRYPT_KEYS: + return ieee80211_cfgget(ifp, cmd, data); - if (len > IEEE80211_NWID_LEN) - return (EINVAL); - ws->i_len = len; - memcpy(ws->i_nwid, id, len); - return (0); -} + case WI_RID_TX_RATE: + if (ic->ic_fixed_rate < 0) + wreq.wi_val[0] = htole16(3); /*XXX*/ + else + wreq.wi_val[0] = htole16( + (ic->ic_sup_rates[ic->ic_fixed_rate] & + IEEE80211_RATE_VAL) / 2); + len = sizeof(u_int16_t); + break; -static void -wi_request_fill_ssid(wreq, ws) - struct wi_req *wreq; - struct ieee80211_nwid *ws; -{ - int len = ws->i_len; + case WI_RID_MICROWAVE_OVEN: + if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_MOR)) { + error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, + &len); + break; + } + wreq.wi_val[0] = htole16(sc->sc_microwave_oven); + len = sizeof(u_int16_t); + break; - memset(&wreq->wi_val[0], 0, sizeof(wreq->wi_val)); - wreq->wi_val[0] = htole16(len); - wreq->wi_len = roundup(len, 2) / 2 + 2; - memcpy(&wreq->wi_val[1], ws->i_nwid, len); -} + case WI_RID_ROAMING_MODE: + if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_ROAMING)) { + error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, + &len); + break; + } + wreq.wi_val[0] = htole16(sc->sc_roaming_mode); + len = sizeof(u_int16_t); + break; -static int -wi_write_ssid(sc, type, wreq, ws) - struct wi_softc *sc; - int type; - struct wi_req *wreq; - struct ieee80211_nwid *ws; -{ + case WI_RID_SYSTEM_SCALE: + if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE)) { + error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, + &len); + break; + } + wreq.wi_val[0] = htole16(sc->sc_system_scale); + len = sizeof(u_int16_t); + break; + + case WI_RID_READ_APS: + if (ic->ic_opmode == IEEE80211_M_HOSTAP) + return ieee80211_cfgget(ifp, cmd, data); + if (sc->sc_scan_timer > 0) { + error = EINPROGRESS; + break; + } + n = sc->sc_naps; + if (len < sizeof(n)) { + error = ENOSPC; + break; + } + if (len < sizeof(n) + sizeof(struct wi_apinfo) * n) + n = (len - sizeof(n)) / sizeof(struct wi_apinfo); + len = sizeof(n) + sizeof(struct wi_apinfo) * n; + memcpy(wreq.wi_val, &n, sizeof(n)); + memcpy((caddr_t)wreq.wi_val + sizeof(n), sc->sc_aps, + sizeof(struct wi_apinfo) * n); + break; - wreq->wi_type = type; - wi_request_fill_ssid(wreq, ws); - return (wi_write_record(sc, (struct wi_ltv_gen *)wreq)); + default: + if (sc->sc_enabled) { + error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, + &len); + break; + } + switch (wreq.wi_type) { + case WI_RID_MAX_DATALEN: + wreq.wi_val[0] = htole16(sc->sc_max_datalen); + len = sizeof(u_int16_t); + break; + case WI_RID_RTS_THRESH: + wreq.wi_val[0] = htole16(sc->sc_rts_thresh); + len = sizeof(u_int16_t); + break; + case WI_RID_CNFAUTHMODE: + wreq.wi_val[0] = htole16(sc->sc_cnfauthmode); + len = sizeof(u_int16_t); + break; + case WI_RID_NODENAME: + if (len < sc->sc_nodelen + sizeof(u_int16_t)) { + error = ENOSPC; + break; + } + len = sc->sc_nodelen + sizeof(u_int16_t); + wreq.wi_val[0] = htole16((sc->sc_nodelen + 1) / 2); + memcpy(&wreq.wi_val[1], sc->sc_nodename, + sc->sc_nodelen); + break; + default: + return ieee80211_cfgget(ifp, cmd, data); + } + break; + } + if (error) + return error; + wreq.wi_len = (len + 1) / 2 + 1; + return copyout(&wreq, ifr->ifr_data, (wreq.wi_len + 1) * 2); } static int -wi_sync_media(sc, ptype, txrate) - struct wi_softc *sc; - int ptype; - int txrate; +wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data) { - int media = sc->sc_media.ifm_cur->ifm_media; - int options = IFM_OPTIONS(media); - int subtype; + struct wi_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; + struct ifreq *ifr = (struct ifreq *)data; + struct wi_req wreq; + struct mbuf *m; + int i, len, error; - switch (txrate) { - case 1: - subtype = IFM_IEEE80211_DS1; + error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); + if (error) + return error; + len = (wreq.wi_len - 1) * 2; + switch (wreq.wi_type) { + case WI_RID_NODENAME: + if (le16toh(wreq.wi_val[0]) * 2 > len || + le16toh(wreq.wi_val[0]) > sizeof(sc->sc_nodename)) { + error = ENOSPC; + break; + } + if (sc->sc_enabled) { + error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val, + len); + if (error) + break; + } + sc->sc_nodelen = le16toh(wreq.wi_val[0]) * 2; + memcpy(sc->sc_nodename, &wreq.wi_val[1], sc->sc_nodelen); break; - case 2: - subtype = IFM_IEEE80211_DS2; + case WI_RID_MICROWAVE_OVEN: + case WI_RID_ROAMING_MODE: + case WI_RID_SYSTEM_SCALE: + if (wreq.wi_type == WI_RID_MICROWAVE_OVEN && + (sc->sc_flags & WI_FLAGS_HAS_MOR) == 0) + break; + if (wreq.wi_type == WI_RID_ROAMING_MODE && + (sc->sc_flags & WI_FLAGS_HAS_ROAMING) == 0) + break; + if (wreq.wi_type == WI_RID_SYSTEM_SCALE && + (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE) == 0) + break; + /* FALLTHROUGH */ + case WI_RID_RTS_THRESH: + case WI_RID_CNFAUTHMODE: + case WI_RID_MAX_DATALEN: + if (sc->sc_enabled) { + error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val, + sizeof(u_int16_t)); + if (error) + break; + } + switch (wreq.wi_type) { + case WI_RID_RTS_THRESH: + sc->sc_rts_thresh = le16toh(wreq.wi_val[0]); + break; + case WI_RID_MICROWAVE_OVEN: + sc->sc_microwave_oven = le16toh(wreq.wi_val[0]); + break; + case WI_RID_ROAMING_MODE: + sc->sc_roaming_mode = le16toh(wreq.wi_val[0]); + break; + case WI_RID_SYSTEM_SCALE: + sc->sc_system_scale = le16toh(wreq.wi_val[0]); + break; + case WI_RID_CNFAUTHMODE: + sc->sc_cnfauthmode = le16toh(wreq.wi_val[0]); + break; + case WI_RID_MAX_DATALEN: + sc->sc_max_datalen = le16toh(wreq.wi_val[0]); + break; + } break; - case 3: - subtype = IFM_AUTO; + case WI_RID_TX_RATE: + switch (le16toh(wreq.wi_val[0])) { + case 3: + ic->ic_fixed_rate = -1; + break; + default: + for (i = 0; i < IEEE80211_RATE_SIZE; i++) { + if ((ic->ic_sup_rates[i] & IEEE80211_RATE_VAL) + / 2 == le16toh(wreq.wi_val[0])) + break; + } + if (i == IEEE80211_RATE_SIZE) + return EINVAL; + ic->ic_fixed_rate = i; + } + if (sc->sc_enabled) + error = wi_write_txrate(sc); break; - case 5: - subtype = IFM_IEEE80211_DS5; + case WI_RID_SCAN_APS: + if (sc->sc_enabled && ic->ic_opmode != IEEE80211_M_HOSTAP) + error = wi_scan_ap(sc); break; - case 11: - subtype = IFM_IEEE80211_DS11; + case WI_RID_MGMT_XMIT: + if (!sc->sc_enabled) { + error = ENETDOWN; + break; + } + if (ic->ic_mgtq.ifq_len > 5) { + error = EAGAIN; + break; + } + /* XXX wi_len looks in u_int8_t, not in u_int16_t */ + m = m_devget((char *)&wreq.wi_val, wreq.wi_len, 0, ifp, NULL); + if (m == NULL) { + error = ENOMEM; + break; + } + IF_ENQUEUE(&ic->ic_mgtq, m); break; default: - subtype = IFM_MANUAL; /* Unable to represent */ + if (sc->sc_enabled) { + error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val, + len); + if (error) + break; + } + error = ieee80211_cfgset(ifp, cmd, data); break; } + return error; +} - options &= ~IFM_OMASK; - switch (ptype) { - case WI_PORTTYPE_BSS: - /* default port type */ - break; - case WI_PORTTYPE_ADHOC: - options |= IFM_IEEE80211_ADHOC | IFM_FLAG0; - break; - case WI_PORTTYPE_HOSTAP: - options |= IFM_IEEE80211_HOSTAP; - break; - case WI_PORTTYPE_IBSS: - options |= IFM_IEEE80211_ADHOC; +static int +wi_write_txrate(struct wi_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + int i; + u_int16_t rate; + + if (ic->ic_fixed_rate < 0) + rate = 0; /* auto */ + else + rate = (ic->ic_sup_rates[ic->ic_fixed_rate] & + IEEE80211_RATE_VAL) / 2; + + /* rate: 0, 1, 2, 5, 11 */ + + switch (sc->sc_firmware_type) { + case WI_LUCENT: + if (rate == 0) + rate = 3; /* auto */ break; default: - subtype = IFM_MANUAL; /* Unable to represent */ + for (i = 8; i > 0; i >>= 1) { + if (rate >= i) + break; + } + if (i == 0) + rate = 0xf; /* auto */ + else + rate = i; break; } - media = IFM_MAKEWORD(IFM_TYPE(media), subtype, options, - IFM_INST(media)); - if (ifmedia_match(&sc->sc_media, media, sc->sc_media.ifm_mask) == NULL) - return (EINVAL); - ifmedia_set(&sc->sc_media, media); - sc->wi_ptype = ptype; - sc->wi_tx_rate = txrate; - return (0); + return wi_write_val(sc, WI_RID_TX_RATE, rate); } static int -wi_media_change(ifp) - struct ifnet *ifp; +wi_write_wep(struct wi_softc *sc) { - struct wi_softc *sc = ifp->if_softc; - int otype = sc->wi_ptype; - int orate = sc->wi_tx_rate; - int ocreate_ibss = sc->wi_create_ibss; - - sc->wi_create_ibss = 0; + struct ieee80211com *ic = &sc->sc_ic; + int error = 0; + int i, keylen; + u_int16_t val; + struct wi_key wkey[IEEE80211_WEP_NKID]; - switch (sc->sc_media.ifm_cur->ifm_media & IFM_OMASK) { - case 0: - sc->wi_ptype = WI_PORTTYPE_BSS; - break; - case IFM_IEEE80211_HOSTAP: - sc->wi_ptype = WI_PORTTYPE_HOSTAP; - break; - case IFM_IEEE80211_ADHOC: - sc->wi_ptype = WI_PORTTYPE_IBSS; - if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS) - sc->wi_create_ibss = 1; + switch (sc->sc_firmware_type) { + case WI_LUCENT: + val = (ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0; + error = wi_write_val(sc, WI_RID_ENCRYPTION, val); + if (error) + break; + error = wi_write_val(sc, WI_RID_TX_CRYPT_KEY, ic->ic_wep_txkey); + if (error) + break; + memset(wkey, 0, sizeof(wkey)); + for (i = 0; i < IEEE80211_WEP_NKID; i++) { + keylen = ic->ic_nw_keys[i].wk_len; + wkey[i].wi_keylen = htole16(keylen); + memcpy(wkey[i].wi_keydat, ic->ic_nw_keys[i].wk_key, + keylen); + } + error = wi_write_rid(sc, WI_RID_DEFLT_CRYPT_KEYS, + wkey, sizeof(wkey)); break; - case IFM_IEEE80211_ADHOC | IFM_FLAG0: - sc->wi_ptype = WI_PORTTYPE_ADHOC; + + case WI_INTERSIL: + case WI_SYMBOL: + if (ic->ic_flags & IEEE80211_F_WEPON) { + /* + * ONLY HWB3163 EVAL-CARD Firmware version + * less than 0.8 variant2 + * + * If promiscuous mode disable, Prism2 chip + * does not work with WEP . + * It is under investigation for details. + * (ichiro@netbsd.org) + */ + if (sc->sc_firmware_type == WI_INTERSIL && + sc->sc_sta_firmware_ver < 802 ) { + /* firm ver < 0.8 variant 2 */ + wi_write_val(sc, WI_RID_PROMISC, 1); + } + wi_write_val(sc, WI_RID_CNFAUTHMODE, + sc->sc_cnfauthmode); + val = PRIVACY_INVOKED | EXCLUDE_UNENCRYPTED; + if (ic->ic_opmode == IEEE80211_M_HOSTAP) + val |= HOST_ENCRYPT; + } else { + wi_write_val(sc, WI_RID_CNFAUTHMODE, 1); /* open */ + val = HOST_ENCRYPT | HOST_DECRYPT; + } + error = wi_write_val(sc, WI_RID_P2_ENCRYPTION, val); + if (error) + break; + error = wi_write_val(sc, WI_RID_P2_TX_CRYPT_KEY, + ic->ic_wep_txkey); + if (error) + break; + for (i = 0; i < IEEE80211_WEP_NKID; i++) { + keylen = ic->ic_nw_keys[i].wk_len; + if (keylen > IEEE80211_WEP_KEYLEN) + keylen = 13; /* 104bit keys */ + else + keylen = IEEE80211_WEP_KEYLEN; + error = wi_write_rid(sc, WI_RID_P2_CRYPT_KEY0 + i, + ic->ic_nw_keys[i].wk_key, keylen); + if (error) + break; + } break; - default: - /* Invalid combination. */ - sc->wi_create_ibss = ocreate_ibss; - return (EINVAL); } + return error; +} - switch (IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media)) { - case IFM_IEEE80211_DS1: - sc->wi_tx_rate = 1; - break; - case IFM_IEEE80211_DS2: - sc->wi_tx_rate = 2; - break; - case IFM_AUTO: - sc->wi_tx_rate = 3; - break; - case IFM_IEEE80211_DS5: - sc->wi_tx_rate = 5; - break; - case IFM_IEEE80211_DS11: - sc->wi_tx_rate = 11; - break; +/* Must be called at proper protection level! */ +static int +wi_cmd(struct wi_softc *sc, int cmd, int val0, int val1, int val2) +{ + int i, status; + + /* wait for the busy bit to clear */ + for (i = 0; ; i++) { + if ((CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY) == 0) + break; + if (i == WI_TIMEOUT) { + printf("%s: wi_cmd: BUSY did not clear, " + "cmd=0x%x, prev=0x%x\n", sc->sc_dev.dv_xname, + cmd, CSR_READ_2(sc, WI_COMMAND)); + return EIO; + } + DELAY(1); } - if (sc->sc_enabled != 0) { - if (otype != sc->wi_ptype || - orate != sc->wi_tx_rate || - ocreate_ibss != sc->wi_create_ibss) - wi_init(ifp); + CSR_WRITE_2(sc, WI_PARAM0, val0); + CSR_WRITE_2(sc, WI_PARAM1, val1); + CSR_WRITE_2(sc, WI_PARAM2, val2); + CSR_WRITE_2(sc, WI_COMMAND, cmd); + + if (cmd == WI_CMD_INI) { + /* XXX: should sleep here. */ + DELAY(100*1000); + } + /* wait for the cmd completed bit */ + for (i = 0; i < WI_TIMEOUT; i++) { + if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD) + break; + DELAY(1); } - ifp->if_baudrate = ifmedia_baudrate(sc->sc_media.ifm_cur->ifm_media); + status = CSR_READ_2(sc, WI_STATUS); + + /* Ack the command */ + CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD); - return (0); + if (i == WI_TIMEOUT) { + printf("%s: command timed out, cmd=0x%x, arg=0x%x\n", + sc->sc_dev.dv_xname, cmd, val0); + return ETIMEDOUT; + } + + if (status & WI_STAT_CMD_RESULT) { + printf("%s: command failed, cmd=0x%x, arg=0x%x\n", + sc->sc_dev.dv_xname, cmd, val0); + return EIO; + } + return 0; } -static void -wi_media_status(ifp, imr) - struct ifnet *ifp; - struct ifmediareq *imr; +static int +wi_seek_bap(struct wi_softc *sc, int id, int off) { - struct wi_req wreq; - struct wi_softc *sc = ifp->if_softc; + int i, status; - if (sc->sc_enabled == 0) { - imr->ifm_active = IFM_IEEE80211|IFM_NONE; - imr->ifm_status = 0; - return; - } + CSR_WRITE_2(sc, WI_SEL0, id); + CSR_WRITE_2(sc, WI_OFF0, off); - if (sc->wi_tx_rate == 3) { - imr->ifm_active = IFM_IEEE80211|IFM_AUTO; - switch (sc->wi_ptype) { - case WI_PORTTYPE_ADHOC: - imr->ifm_active |= IFM_FLAG0; - /* fall through */ - case WI_PORTTYPE_IBSS: - imr->ifm_active |= IFM_IEEE80211_ADHOC; - break; - case WI_PORTTYPE_HOSTAP: - imr->ifm_active |= IFM_IEEE80211_HOSTAP; - break; - default: - /* do nothing for BSS, WDS, or unknown. */ + for (i = 0; ; i++) { + status = CSR_READ_2(sc, WI_OFF0); + if ((status & WI_OFF_BUSY) == 0) break; + if (i == WI_TIMEOUT) { + printf("%s: timeout in wi_seek to %x/%x\n", + sc->sc_dev.dv_xname, id, off); + sc->sc_bap_off = WI_OFF_ERR; /* invalidate */ + return ETIMEDOUT; } - wreq.wi_type = WI_RID_CUR_TX_RATE; - wreq.wi_len = WI_MAX_DATALEN; - if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0) { - switch(wreq.wi_val[0]) { - case 1: - imr->ifm_active |= IFM_IEEE80211_DS1; - break; - case 2: - imr->ifm_active |= IFM_IEEE80211_DS2; - break; - case 6: - imr->ifm_active |= IFM_IEEE80211_DS5; - break; - case 11: - imr->ifm_active |= IFM_IEEE80211_DS11; - break; - } - } - } else { - imr->ifm_active = sc->sc_media.ifm_cur->ifm_media; + DELAY(1); } - - imr->ifm_status = IFM_AVALID; - switch (sc->wi_ptype) { - case WI_PORTTYPE_IBSS: - /* - * XXX: It would be nice if we could give some actually - * useful status like whether we joined another IBSS or - * created one ourselves. - */ - /* fall through */ - case WI_PORTTYPE_HOSTAP: - imr->ifm_status |= IFM_ACTIVE; - break; - case WI_PORTTYPE_BSS: - default: -#if 0 - wreq.wi_type = WI_RID_COMMQUAL; - wreq.wi_len = WI_MAX_DATALEN; - if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 && - wreq.wi_val[0] != 0) -#else - if (sc->wi_flags & WI_FLAGS_CONNECTED) -#endif - imr->ifm_status |= IFM_ACTIVE; + if (status & WI_OFF_ERR) { + printf("%s: failed in wi_seek to %x/%x\n", + sc->sc_dev.dv_xname, id, off); + sc->sc_bap_off = WI_OFF_ERR; /* invalidate */ + return EIO; } + sc->sc_bap_id = id; + sc->sc_bap_off = off; + return 0; } static int -wi_set_nwkey(sc, nwkey) - struct wi_softc *sc; - struct ieee80211_nwkey *nwkey; +wi_read_bap(struct wi_softc *sc, int id, int off, void *buf, int buflen) { - int i, error; - size_t len; - struct wi_req wreq; - struct wi_ltv_keys *wk = (struct wi_ltv_keys *)&wreq; - - if ((sc->wi_flags & WI_FLAGS_HAS_WEP) == 0) - return ENODEV; - if (nwkey->i_defkid <= 0 || - nwkey->i_defkid > IEEE80211_WEP_NKID) - return EINVAL; - memcpy(wk, &sc->wi_keys, sizeof(*wk)); - 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(wk->wi_keys[i].wi_keydat)) - return EINVAL; - error = copyin(nwkey->i_key[i].i_keydat, - wk->wi_keys[i].wi_keydat, len); - if (error) - return error; - wk->wi_keys[i].wi_keylen = htole16(len); - } + int error, cnt; - wk->wi_len = (sizeof(*wk) / 2) + 1; - wk->wi_type = WI_RID_DEFLT_CRYPT_KEYS; - if (sc->sc_enabled != 0) { - error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq); - if (error) + if (buflen == 0) + return 0; + if (id != sc->sc_bap_id || off != sc->sc_bap_off) { + if ((error = wi_seek_bap(sc, id, off)) != 0) return error; } - error = wi_setdef(sc, &wreq); - if (error) - return error; + cnt = (buflen + 1) / 2; + CSR_READ_MULTI_STREAM_2(sc, WI_DATA0, (u_int16_t *)buf, cnt); + sc->sc_bap_off += cnt * 2; + return 0; +} - wreq.wi_len = 2; - wreq.wi_type = WI_RID_TX_CRYPT_KEY; - wreq.wi_val[0] = htole16(nwkey->i_defkid - 1); - if (sc->sc_enabled != 0) { - error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq); - if (error) - return error; - } - error = wi_setdef(sc, &wreq); - if (error) - return error; +static int +wi_write_bap(struct wi_softc *sc, int id, int off, void *buf, int buflen) +{ + int error, cnt; - wreq.wi_type = WI_RID_ENCRYPTION; - wreq.wi_val[0] = htole16(nwkey->i_wepon); - if (sc->sc_enabled != 0) { - error = wi_write_record(sc, (struct wi_ltv_gen *)&wreq); - if (error) + if (buflen == 0) + return 0; + +#ifdef WI_HERMES_AUTOINC_WAR + again: +#endif + if (id != sc->sc_bap_id || off != sc->sc_bap_off) { + if ((error = wi_seek_bap(sc, id, off)) != 0) return error; } - error = wi_setdef(sc, &wreq); - if (error) - return error; + cnt = (buflen + 1) / 2; + CSR_WRITE_MULTI_STREAM_2(sc, WI_DATA0, (u_int16_t *)buf, cnt); + sc->sc_bap_off += cnt * 2; - if (sc->sc_enabled != 0) - wi_init(&sc->sc_ethercom.ec_if); +#ifdef WI_HERMES_AUTOINC_WAR + /* + * According to the comments in the HCF Light code, there is a bug + * in the Hermes (or possibly in certain Hermes firmware revisions) + * where the chip's internal autoincrement counter gets thrown off + * during data writes: the autoincrement is missed, causing one + * data word to be overwritten and subsequent words to be written to + * the wrong memory locations. The end result is that we could end + * up transmitting bogus frames without realizing it. The workaround + * for this is to write a couple of extra guard words after the end + * of the transfer, then attempt to read then back. If we fail to + * locate the guard words where we expect them, we preform the + * transfer over again. + */ + if ((sc->sc_flags & WI_FLAGS_BUG_AUTOINC) && (id & 0xf000) == 0) { + CSR_WRITE_2(sc, WI_DATA0, 0x1234); + CSR_WRITE_2(sc, WI_DATA0, 0x5678); + wi_seek_bap(sc, id, sc->sc_bap_off); + sc->sc_bap_off = WI_OFF_ERR; /* invalidate */ + if (CSR_READ_2(sc, WI_DATA0) != 0x1234 || + CSR_READ_2(sc, WI_DATA0) != 0x5678) { + printf("%s: detect auto increment bug, try again\n", + sc->sc_dev.dv_xname); + goto again; + } + } +#endif return 0; } static int -wi_get_nwkey(sc, nwkey) - struct wi_softc *sc; - struct ieee80211_nwkey *nwkey; +wi_alloc_fid(struct wi_softc *sc, int len, int *idp) { - int i, len, error; - struct wi_ltv_keys *wk = &sc->wi_keys; + int i; - if ((sc->wi_flags & WI_FLAGS_HAS_WEP) == 0) - return ENODEV; - nwkey->i_wepon = sc->wi_use_wep; - nwkey->i_defkid = sc->wi_tx_key + 1; + if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len, 0, 0)) { + printf("%s: failed to allocate %d bytes on NIC\n", + sc->sc_dev.dv_xname, len); + return ENOMEM; + } - /* do not show any keys to non-root user */ - error = suser(curproc->p_ucred, &curproc->p_acflag); - for (i = 0; i < IEEE80211_WEP_NKID; i++) { - if (nwkey->i_key[i].i_keydat == NULL) - continue; - /* error holds results of suser() for the first time */ - if (error) - return error; - len = le16toh(wk->wi_keys[i].wi_keylen); - if (nwkey->i_key[i].i_keylen < len) - return ENOSPC; - nwkey->i_key[i].i_keylen = len; - error = copyout(wk->wi_keys[i].wi_keydat, - nwkey->i_key[i].i_keydat, len); - if (error) - return error; + for (i = 0; i < WI_TIMEOUT; i++) { + if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC) + break; + if (i == WI_TIMEOUT) { + printf("%s: timeout in alloc\n", sc->sc_dev.dv_xname); + return ETIMEDOUT; + } + DELAY(1); } + *idp = CSR_READ_2(sc, WI_ALLOC_FID); + CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC); return 0; } static int -wi_set_pm(struct wi_softc *sc, struct ieee80211_power *power) +wi_read_rid(struct wi_softc *sc, int rid, void *buf, int *buflenp) { + int error, len; + u_int16_t ltbuf[2]; - sc->wi_pm_enabled = power->i_enabled; - sc->wi_max_sleep = power->i_maxsleep; + /* Tell the NIC to enter record read mode. */ + error = wi_cmd(sc, WI_CMD_ACCESS | WI_ACCESS_READ, rid, 0, 0); + if (error) + return error; - if (sc->sc_enabled) - return (wi_init(&sc->sc_ethercom.ec_if)); + error = wi_read_bap(sc, rid, 0, ltbuf, sizeof(ltbuf)); + if (error) + return error; - return (0); + if (le16toh(ltbuf[1]) != rid) { + printf("%s: record read mismatch, rid=%x, got=%x\n", + sc->sc_dev.dv_xname, rid, le16toh(ltbuf[1])); + return EIO; + } + len = (le16toh(ltbuf[0]) - 1) * 2; /* already got rid */ + if (*buflenp < len) { + printf("%s: record buffer is too small, " + "rid=%x, size=%d, len=%d\n", + sc->sc_dev.dv_xname, rid, *buflenp, len); + return ENOSPC; + } + *buflenp = len; + return wi_read_bap(sc, rid, sizeof(ltbuf), buf, len); } static int -wi_get_pm(struct wi_softc *sc, struct ieee80211_power *power) +wi_write_rid(struct wi_softc *sc, int rid, void *buf, int buflen) { + int error; + u_int16_t ltbuf[2]; + + ltbuf[0] = htole16((buflen + 1) / 2 + 1); /* includes rid */ + ltbuf[1] = htole16(rid); - power->i_enabled = sc->wi_pm_enabled; - power->i_maxsleep = sc->wi_max_sleep; + error = wi_write_bap(sc, rid, 0, ltbuf, sizeof(ltbuf)); + if (error) + return error; + error = wi_write_bap(sc, rid, sizeof(ltbuf), buf, buflen); + if (error) + return error; - return (0); + return wi_cmd(sc, WI_CMD_ACCESS | WI_ACCESS_WRITE, rid, 0, 0); } static int -wi_set_channel(struct wi_softc *sc, struct ieee80211_channel *channel) +wi_newstate(void *arg, enum ieee80211_state nstate) { - int do_init = 0, error = 0; - if (channel->i_channel != 0 && - !(sc->wi_channels & (1 << (channel->i_channel - 1)))) { - return EINVAL; - } - switch (sc->wi_ptype) { - default: - case WI_PORTTYPE_IBSS: - case WI_PORTTYPE_ADHOC: /* set channel of BSS to join/create */ + struct wi_softc *sc = arg; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni = &ic->ic_bss; + int buflen; + u_int16_t val; + struct wi_ssid ssid; + enum ieee80211_state ostate; +#ifdef WI_DEBUG + static const char *stname[] = + { "INIT", "SCAN", "AUTH", "ASSOC", "RUN" }; +#endif /* WI_DEBUG */ - if (channel->i_channel != 0 && - channel->i_channel != sc->wi_create_channel) { - sc->wi_create_channel = channel->i_channel; - if (sc->sc_enabled) - do_init = 1; - } - /* fall through */ - case WI_PORTTYPE_BSS: /* set channel of BSS to join */ + ostate = ic->ic_state; + DPRINTF(("wi_newstate: %s -> %s\n", stname[ostate], stname[nstate])); - /* We are warned not to join while a join is pending. - * Our next opportunity comes after a LinkStatus notification. - */ - if (sc->wi_flags & WI_FLAGS_JOINING) { - error = EAGAIN; - break; - } - sc->wi_join_channel = channel->i_channel; - error = wi_join_bss(sc); + ic->ic_state = nstate; + switch (nstate) { + case IEEE80211_S_INIT: + ic->ic_flags &= ~IEEE80211_F_SIBSS; + return 0; + + case IEEE80211_S_RUN: + buflen = IEEE80211_ADDR_LEN; + wi_read_rid(sc, WI_RID_CURRENT_BSSID, ni->ni_bssid, &buflen); + IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid); + buflen = sizeof(val); + wi_read_rid(sc, WI_RID_CURRENT_CHAN, &val, &buflen); + ni->ni_chan = le16toh(val); + + buflen = sizeof(ssid); + wi_read_rid(sc, WI_RID_CURRENT_SSID, &ssid, &buflen); + ni->ni_esslen = le16toh(ssid.wi_len); + if (ni->ni_esslen > IEEE80211_NWID_LEN) + ni->ni_esslen = IEEE80211_NWID_LEN; /*XXX*/ + memcpy(ni->ni_essid, ssid.wi_ssid, ni->ni_esslen); break; - case WI_PORTTYPE_HOSTAP: /* set channel of BSS to create */ - if (channel->i_channel == 0) { - error = EINVAL; - break; - } - if (channel->i_channel == sc->wi_create_channel) - break; - sc->wi_create_channel = channel->i_channel; - if (sc->sc_enabled) - do_init = 1; + + case IEEE80211_S_SCAN: + case IEEE80211_S_AUTH: + case IEEE80211_S_ASSOC: break; } - if (!error && do_init) - error = wi_init(&sc->sc_if); - return error; + + /* skip standard ieee80211 handling */ + return EINPROGRESS; } static int -wi_get_channel(struct wi_softc *sc, struct ieee80211_channel *channel) +wi_scan_ap(struct wi_softc *sc) { - switch (sc->wi_ptype) { - default: - case WI_PORTTYPE_IBSS: - case WI_PORTTYPE_ADHOC: - if (!(sc->wi_flags & WI_FLAGS_CONNECTED)) { - /* return channel of BSS to create */ - channel->i_channel = sc->wi_create_channel; - break; - } - /* fall through */ - case WI_PORTTYPE_BSS: - if (sc->wi_flags & WI_FLAGS_CONNECTED) { - /* return channel of connected BSS */ - channel->i_channel = sc->wi_current_channel; - break; - } - /* return channel of BSS to join */ - channel->i_channel = sc->wi_join_channel; + int error = 0; + u_int16_t val[2]; + + if (!sc->sc_enabled) + return ENXIO; + switch (sc->sc_firmware_type) { + case WI_LUCENT: + (void)wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0); break; - case WI_PORTTYPE_HOSTAP: - /* return channel of BSS to create */ - channel->i_channel = sc->wi_create_channel; + case WI_INTERSIL: + val[0] = 0x3fff; /* channel */ + val[1] = 0x000f; /* tx rate */ + error = wi_write_rid(sc, WI_RID_SCAN_REQ, val, sizeof(val)); + break; + case WI_SYMBOL: + /* + * XXX only supported on 3.x ? + */ + val[0] = BSCAN_BCAST | BSCAN_ONETIME; + error = wi_write_rid(sc, WI_RID_BCAST_SCAN_REQ, + val, sizeof(val[0])); break; } - return 0; + if (error == 0) { + sc->sc_scan_timer = WI_SCAN_WAIT; + sc->sc_ic.ic_if.if_timer = 1; + DPRINTF(("wi_scan_ap: start scanning\n")); + } + return error; +} + +static void +wi_scan_result(struct wi_softc *sc, int fid, int cnt) +{ + int i, naps, off, szbuf; + struct wi_scan_header ws_hdr; /* Prism2 header */ + struct wi_scan_data_p2 ws_dat; /* Prism2 scantable*/ + struct wi_apinfo *ap; + + off = sizeof(u_int16_t) * 2; + memset(&ws_hdr, 0, sizeof(ws_hdr)); + switch (sc->sc_firmware_type) { + case WI_INTERSIL: + wi_read_bap(sc, fid, off, &ws_hdr, sizeof(ws_hdr)); + off += sizeof(ws_hdr); + szbuf = sizeof(struct wi_scan_data_p2); + break; + case WI_SYMBOL: + szbuf = sizeof(struct wi_scan_data_p2) + 6; + break; + case WI_LUCENT: + szbuf = sizeof(struct wi_scan_data); + break; + } + naps = (cnt * 2 + 2 - off) / szbuf; + if (naps > MAXAPINFO) + naps = MAXAPINFO; + sc->sc_naps = naps; + /* Read Data */ + ap = sc->sc_aps; + memset(&ws_dat, 0, sizeof(ws_dat)); + for (i = 0; i < naps; i++, ap++) { + wi_read_bap(sc, fid, off, &ws_dat, + (sizeof(ws_dat) < szbuf ? sizeof(ws_dat) : szbuf)); + DPRINTF2(("wi_scan_result: #%d: off %d bssid %s\n", i, off, + ether_sprintf(ws_dat.wi_bssid))); + off += szbuf; + ap->scanreason = le16toh(ws_hdr.wi_reason); + memcpy(ap->bssid, ws_dat.wi_bssid, sizeof(ap->bssid)); + ap->channel = le16toh(ws_dat.wi_chid); + ap->signal = le16toh(ws_dat.wi_signal); + ap->noise = le16toh(ws_dat.wi_noise); + ap->quality = ap->signal - ap->noise; + ap->capinfo = le16toh(ws_dat.wi_capinfo); + ap->interval = le16toh(ws_dat.wi_interval); + ap->rate = le16toh(ws_dat.wi_rate); + ap->namelen = le16toh(ws_dat.wi_namelen); + if (ap->namelen > sizeof(ap->name)) + ap->namelen = sizeof(ap->name); + memcpy(ap->name, ws_dat.wi_name, ap->namelen); + } + /* Done scanning */ + sc->sc_scan_timer = 0; + DPRINTF(("wi_scan_result: scan complete: ap %d\n", naps)); } diff --git a/sys/dev/ic/wi_hostap.c b/sys/dev/ic/wi_hostap.c deleted file mode 100644 index 2c575478748..00000000000 --- a/sys/dev/ic/wi_hostap.c +++ /dev/null @@ -1,1338 +0,0 @@ -/* $NetBSD: wi_hostap.c,v 1.3 2002/09/30 06:29:29 onoe Exp $ */ -/* $OpenBSD: if_wi_hostap.c,v 1.19 2002/06/25 01:59:52 millert Exp $ */ - -/* - * Copyright (c) 2002 - * Thomas Skibo <skibo@pacbell.net>. All rights reserved. - * - * 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 Thomas Skibo. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Thomas Skibo 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 Thomas Skibo OR HIS DRINKING PALS - * 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. - */ - -/* - * This is experimental Host AP software for Prism 2 802.11b interfaces. - * - * Much of this is based upon the "Linux Host AP driver for Intersil Prism2" - * by Jouni Malinen <jkm@ssh.com> or <jkmaline@cc.hut.fi>. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/sockio.h> -#include <sys/mbuf.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/callout.h> -#include <sys/proc.h> -#include <sys/ucred.h> -#include <sys/socket.h> -#include <sys/queue.h> -#include <sys/syslog.h> -#include <sys/sysctl.h> -#include <sys/device.h> - -#include <machine/bus.h> - -#include <net/if.h> -#include <net/if_arp.h> -#include <net/if_dl.h> -#include <net/if_llc.h> -#include <net/if_media.h> -#include <net/if_types.h> -#include <net/if_ether.h> - -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/in_var.h> -#include <netinet/ip.h> - -#include <net/if_ieee80211.h> - -#include <dev/ic/wireg.h> -#include <dev/ic/wi_ieee.h> -#include <dev/ic/wivar.h> - -void wihap_sta_timeout(void *v); -struct wihap_sta_info *wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr); -void wihap_sta_delete(struct wihap_sta_info *sta); -struct wihap_sta_info *wihap_sta_find(struct wihap_info *whi, u_int8_t *addr); -int wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[]); -void wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm, - caddr_t pkt, int len); -void wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[], - u_int16_t reason); -void wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm, - caddr_t pkt, int len); -void wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm, - caddr_t pkt, int len); -void wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[], - u_int16_t reason); -void wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm, - caddr_t pkt, int len); - -/* - * take_hword() - * - * Used for parsing management frames. The pkt pointer and length - * variables are updated after the value is removed. - */ -static __inline u_int16_t -take_hword(caddr_t *ppkt, int *plen) -{ - u_int16_t s = le16toh(* (u_int16_t *) *ppkt); - *ppkt += sizeof(u_int16_t); - *plen -= sizeof(u_int16_t); - return s; -} - -/* take_tlv() - * - * Parse out TLV element from a packet, check for underflow of packet - * or overflow of buffer, update pkt/len. - */ -static int -take_tlv(caddr_t *ppkt, int *plen, int id_expect, void *dst, int maxlen) -{ - u_int8_t id, len; - - if (*plen < 2) - return -1; - - id = ((u_int8_t *)*ppkt)[0]; - len = ((u_int8_t *)*ppkt)[1]; - - if (id != id_expect || *plen < len+2 || maxlen < len) - return -1; - - bcopy(*ppkt + 2, dst, len); - *plen -= 2 + len; - *ppkt += 2 + len; - - return (len); -} - -/* put_hword() - * Put half-word element into management frames. - */ -static __inline void -put_hword(caddr_t *ppkt, u_int16_t s) -{ - * (u_int16_t *) *ppkt = htole16(s); - *ppkt += sizeof(u_int16_t); -} - -/* put_tlv() - * Put TLV elements into management frames. - */ -static void -put_tlv(caddr_t *ppkt, u_int8_t id, void *src, u_int8_t len) -{ - (*ppkt)[0] = id; - (*ppkt)[1] = len; - bcopy(src, (*ppkt) + 2, len); - *ppkt += 2 + len; -} - -static int -put_rates(caddr_t *ppkt, u_int16_t rates) -{ - u_int8_t ratebuf[8]; - int len = 0; - - if (rates & WI_SUPPRATES_1M) - ratebuf[len++] = 0x82; - if (rates & WI_SUPPRATES_2M) - ratebuf[len++] = 0x84; - if (rates & WI_SUPPRATES_5M) - ratebuf[len++] = 0x8b; - if (rates & WI_SUPPRATES_11M) - ratebuf[len++] = 0x96; - - put_tlv(ppkt, IEEE80211_ELEMID_RATES, ratebuf, len); - return len; -} - -/* wihap_init() - * - * Initialize host AP data structures. Called even if port type is - * not AP. Caller MUST raise to splnet(). - */ -void -wihap_init(struct wi_softc *sc) -{ - int i; - struct wihap_info *whi = &sc->wi_hostap_info; - - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_init: sc=%p whi=%p\n", sc, whi); - - memset(whi, 0, sizeof(struct wihap_info)); - - if (sc->wi_ptype != WI_PORTTYPE_HOSTAP) - return; - - whi->apflags = WIHAPFL_ACTIVE; - - LIST_INIT(&whi->sta_list); - for (i = 0; i < WI_STA_HASH_SIZE; i++) - LIST_INIT(&whi->sta_hash[i]); - - whi->inactivity_time = WIHAP_DFLT_INACTIVITY_TIME; -} - -/* wihap_sta_disassoc() - * - * Send a disassociation frame to a specified station. - */ -void -wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[], u_int16_t reason) -{ - struct ifnet *ifp = &sc->sc_ethercom.ec_if; - struct wi_80211_hdr *resp_hdr; - caddr_t pkt; - - if (ifp->if_flags & IFF_DEBUG) - printf("Sending disassoc to sta %s\n", ether_sprintf(sta_addr)); - - /* Send disassoc packet. */ - resp_hdr = (struct wi_80211_hdr *)&sc->wi_txbuf; - memset(resp_hdr, 0, sizeof(struct wi_80211_hdr)); - resp_hdr->frame_ctl = WI_FTYPE_MGMT | WI_STYPE_MGMT_DISAS; - pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr); - - bcopy(sta_addr, resp_hdr->addr1, ETHER_ADDR_LEN); - bcopy(LLADDR(ifp->if_sadl), resp_hdr->addr2, ETHER_ADDR_LEN); - bcopy(LLADDR(ifp->if_sadl), resp_hdr->addr3, ETHER_ADDR_LEN); - - put_hword(&pkt, reason); - - wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf, pkt - (caddr_t)&sc->wi_txbuf); -} - -/* wihap_sta_deauth() - * - * Send a deauthentication message to a specified station. - */ -void -wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[], u_int16_t reason) -{ - struct ifnet *ifp = &sc->sc_ethercom.ec_if; - struct wi_80211_hdr *resp_hdr; - caddr_t pkt; - - if (ifp->if_flags & IFF_DEBUG) - printf("Sending deauth to sta %s\n", ether_sprintf(sta_addr)); - - /* Send deauth packet. */ - resp_hdr = (struct wi_80211_hdr *)&sc->wi_txbuf; - memset(resp_hdr, 0, sizeof(struct wi_80211_hdr)); - resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_DEAUTH); - pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr); - - bcopy(sta_addr, resp_hdr->addr1, ETHER_ADDR_LEN); - bcopy(LLADDR(ifp->if_sadl), resp_hdr->addr2, ETHER_ADDR_LEN); - bcopy(LLADDR(ifp->if_sadl), resp_hdr->addr3, ETHER_ADDR_LEN); - - put_hword(&pkt, reason); - - wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf, pkt - (caddr_t)&sc->wi_txbuf); -} - -/* wihap_shutdown() - * - * Disassociate all stations and free up data structures. - * Caller must raise to splnet(). - */ -void -wihap_shutdown(struct wi_softc *sc) -{ - struct wihap_info *whi = &sc->wi_hostap_info; - struct wihap_sta_info *sta, *next; - int s; - - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_shutdown: sc=%p whi=%p\n", sc, whi); - - if (!(whi->apflags & WIHAPFL_ACTIVE)) - return; - whi->apflags = 0; - - /* XXX: I read somewhere you can deauth all the stations with - * a single broadcast. Maybe try that someday. - */ - - s = splnet(); - sta = LIST_FIRST(&whi->sta_list); - while (sta) { - - callout_stop(&sta->tmo); - - if (sc->wi_flags & WI_FLAGS_ATTACHED) { - /* Disassociate station. */ - if (sta->flags & WI_SIFLAGS_ASSOC) - wihap_sta_disassoc(sc, sta->addr, - IEEE80211_REASON_ASSOC_LEAVE); - /* Deauth station. */ - if (sta->flags & WI_SIFLAGS_AUTHEN) - wihap_sta_deauth(sc, sta->addr, - IEEE80211_REASON_AUTH_LEAVE); - } - - /* Delete the structure. */ - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_shutdown: FREE(sta=%p)\n", sta); - next = LIST_NEXT(sta, list); - FREE(sta, M_DEVBUF); - sta = next; - } - splx(s); -} - -/* sta_hash_func() - * Hash function for finding stations from ethernet address. - */ -static __inline int -sta_hash_func(u_int8_t addr[]) -{ - return ((addr[3] + addr[4] + addr[5]) % WI_STA_HASH_SIZE); -} - -/* addr_cmp(): Maybe this is a faster way to compare addresses? */ -static __inline int -addr_cmp(u_int8_t a[], u_int8_t b[]) -{ - return (*(u_int32_t *)(a ) == *(u_int32_t *)(b) && - *(u_int16_t *)(a + 4) == *(u_int16_t *)(b + 4)); -} - -void -wihap_sta_timeout(void *v) -{ - struct wihap_sta_info *sta = v; - struct wi_softc *sc = sta->sc; - struct wihap_info *whi = &sc->wi_hostap_info; - int s; - - s = splsoftnet(); - - if (sta->flags & WI_SIFLAGS_ASSOC) { - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_timer: disassoc due to inactivity: %s\n", - ether_sprintf(sta->addr)); - - /* Disassoc station. */ - wihap_sta_disassoc(sc, sta->addr, - IEEE80211_REASON_ASSOC_EXPIRE); - sta->flags &= ~WI_SIFLAGS_ASSOC; - - callout_reset(&sta->tmo, hz * whi->inactivity_time, - wihap_sta_timeout, sta); - - } else if (sta->flags & WI_SIFLAGS_AUTHEN) { - - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_timer: deauth due to inactivity: %s\n", - ether_sprintf(sta->addr)); - - /* Deauthenticate station. */ - wihap_sta_deauth(sc, sta->addr, IEEE80211_REASON_AUTH_EXPIRE); - sta->flags &= ~WI_SIFLAGS_AUTHEN; - - /* Delete the station if it's not permanent. */ - if (!(sta->flags & WI_SIFLAGS_PERM)) - wihap_sta_delete(sta); - } - splx(s); -} - -/* wihap_sta_delete() - * Delete a single station and free up its data structure. - */ -void -wihap_sta_delete(struct wihap_sta_info *sta) -{ - struct wi_softc *sc = sta->sc; - struct wihap_info *whi = &sc->wi_hostap_info; - int i = sta->asid - 0xc001; - - callout_stop(&sta->tmo); - - whi->asid_inuse_mask[i >> 4] &= ~(1UL << (i & 0xf)); - - LIST_REMOVE(sta, list); - LIST_REMOVE(sta, hash); - if (sta->challenge) - FREE(sta->challenge, M_TEMP); -#if defined(WI_HOSTAP_POWERSAVE) - IFQ_PURGE(&sta->ps_q); -#endif - FREE(sta, M_DEVBUF); - whi->n_stations--; -} - -/* wihap_sta_alloc() - * - * Create a new station data structure and put it in the list - * and hash table. - */ -struct wihap_sta_info * -wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr) -{ - struct wihap_info *whi = &sc->wi_hostap_info; - struct wihap_sta_info *sta; - int i, hash = sta_hash_func(addr); - - /* Allocate structure. */ - MALLOC(sta, struct wihap_sta_info *, sizeof(struct wihap_sta_info), - M_DEVBUF, M_NOWAIT); - if (sta == NULL) - return (NULL); - - memset(sta, 0, sizeof(struct wihap_sta_info)); - - /* Allocate an ASID. */ - i=hash<<4; - while (whi->asid_inuse_mask[i >> 4] & (1UL << (i & 0xf))) - i = (i == (WI_STA_HASH_SIZE << 4) - 1) ? 0 : (i + 1); - whi->asid_inuse_mask[i >> 4] |= (1UL << (i & 0xf)); - sta->asid = 0xc001 + i; - - /* Insert in list and hash list. */ - LIST_INSERT_HEAD(&whi->sta_list, sta, list); - LIST_INSERT_HEAD(&whi->sta_hash[hash], sta, hash); - - sta->sc = sc; - whi->n_stations++; - bcopy(addr, &sta->addr, ETHER_ADDR_LEN); - callout_init(&sta->tmo); - callout_reset(&sta->tmo, hz * whi->inactivity_time, - wihap_sta_timeout, sta); - -#if defined(WI_HOSTAP_POWERSAVE) - /* XXX name the constant. make it configurable. */ - IFQ_SET_MAXLEN(&sta->ps_q, 3); -#endif - - return (sta); -} - -/* wihap_sta_find() - * - * Find station structure given address. - */ -struct wihap_sta_info * -wihap_sta_find(struct wihap_info *whi, u_int8_t *addr) -{ - int i; - struct wihap_sta_info *sta; - - i = sta_hash_func(addr); - LIST_FOREACH(sta, &whi->sta_hash[i], hash) - if (addr_cmp(addr, sta->addr)) - return sta; - - return (NULL); -} - -static __inline int -wihap_check_rates(struct wihap_sta_info *sta, u_int8_t rates[], int rates_len) -{ - struct wi_softc *sc = sta->sc; - int i; - - sta->rates = 0; - sta->tx_max_rate = 0; - for (i = 0; i < rates_len; i++) - switch (rates[i] & 0x7f) { - case 0x02: - sta->rates |= WI_SUPPRATES_1M; - break; - case 0x04: - sta->rates |= WI_SUPPRATES_2M; - if (sta->tx_max_rate < 1) - sta->tx_max_rate = 1; - break; - case 0x0b: - sta->rates |= WI_SUPPRATES_5M; - if (sta->tx_max_rate < 2) - sta->tx_max_rate = 2; - break; - case 0x16: - sta->rates |= WI_SUPPRATES_11M; - sta->tx_max_rate = 3; - break; - } - - sta->rates &= sc->wi_supprates; - sta->tx_curr_rate = sta->tx_max_rate; - - return (sta->rates == 0 ? -1 : 0); -} - - -/* wihap_auth_req() - * - * Handle incoming authentication request. Only handle OPEN - * requests. - */ -void -wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm, - caddr_t pkt, int len) -{ - struct ifnet *ifp = &sc->sc_ethercom.ec_if; - struct wihap_info *whi = &sc->wi_hostap_info; - struct wihap_sta_info *sta; - int i; - - u_int16_t algo; - u_int16_t seq; - u_int16_t status; - int challenge_len; - u_int32_t challenge[32]; - - struct wi_80211_hdr *resp_hdr; - - if (len < 6) - return; - - /* Break open packet. */ - algo = take_hword(&pkt, &len); - seq = take_hword(&pkt, &len); - status = take_hword(&pkt, &len); - challenge_len = 0; - if (len > 0 && (challenge_len = take_tlv(&pkt, &len, - IEEE80211_ELEMID_CHALLENGE, challenge, sizeof(challenge))) < 0) - return; - - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_auth_req: station %s algo=0x%x seq=0x%x\n", - ether_sprintf(rxfrm->wi_addr2), algo, seq); - - /* Find or create station info. */ - sta = wihap_sta_find(whi, rxfrm->wi_addr2); - if (sta == NULL) { - - /* Are we allowing new stations? - */ - if (whi->apflags & WIHAPFL_MAC_FILT) { - status = IEEE80211_STATUS_OTHER; /* XXX */ - goto fail; - } - - /* Check for too many stations. - */ - if (whi->n_stations >= WIHAP_MAX_STATIONS) { - status = IEEE80211_STATUS_TOOMANY; - goto fail; - } - - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_auth_req: new station\n"); - - /* Create new station. */ - sta = wihap_sta_alloc(sc, rxfrm->wi_addr2); - if (sta == NULL) { - /* Out of memory! */ - status = IEEE80211_STATUS_TOOMANY; - goto fail; - } - } - callout_reset(&sta->tmo, hz * whi->inactivity_time, - wihap_sta_timeout, sta); - - /* Note: it's okay to leave the station info structure around - * if the authen fails. It'll be timed out eventually. - */ - switch (algo) { - case IEEE80211_AUTH_ALG_OPEN: - if (sc->wi_authtype != IEEE80211_AUTH_OPEN) { - seq = 2; - status = IEEE80211_STATUS_ALG; - goto fail; - } - if (seq != 1) { - seq = 2; - status = IEEE80211_STATUS_SEQUENCE; - goto fail; - } - challenge_len = 0; - seq = 2; - sta->flags |= WI_SIFLAGS_AUTHEN; - break; - case IEEE80211_AUTH_ALG_SHARED: - if (sc->wi_authtype != IEEE80211_AUTH_SHARED) { - seq = 2; - status = IEEE80211_STATUS_ALG; - goto fail; - } - switch (seq) { - case 1: - /* Create a challenge frame. */ - if (!sta->challenge) { - MALLOC(sta->challenge, u_int32_t *, 128, - M_TEMP, M_NOWAIT); - if (!sta->challenge) - return; - } - for (i = 0; i < 32; i++) - challenge[i] = sta->challenge[i] = - arc4random(); - - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("\tchallenge: 0x%x 0x%x ...\n", - challenge[0], challenge[1]); - challenge_len = 128; - seq = 2; - break; - case 3: - if (challenge_len != 128 || !sta->challenge || - !(le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_WEP)) { - status = IEEE80211_STATUS_CHALLENGE; - goto fail; - } - - for (i=0; i<32; i++) - if (sta->challenge[i] != challenge[i]) { - status = IEEE80211_STATUS_CHALLENGE; - goto fail; - } - - sta->flags |= WI_SIFLAGS_AUTHEN; - FREE(sta->challenge, M_TEMP); - sta->challenge = NULL; - challenge_len = 0; - seq = 4; - break; - default: - seq = 2; - status = IEEE80211_STATUS_SEQUENCE; - goto fail; - } /* switch (seq) */ - break; - default: - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_auth_req: algorithm unsupported: 0x%x\n", - algo); - status = IEEE80211_STATUS_ALG; - goto fail; - } /* switch (algo) */ - - status = IEEE80211_STATUS_SUCCESS; - -fail: - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_auth_req: returns status=0x%x\n", status); - - /* Send response. */ - resp_hdr = (struct wi_80211_hdr *)&sc->wi_txbuf; - memset(resp_hdr, 0, sizeof(struct wi_80211_hdr)); - resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_AUTH); - bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN); - bcopy(LLADDR(ifp->if_sadl), resp_hdr->addr2, ETHER_ADDR_LEN); - bcopy(LLADDR(ifp->if_sadl), resp_hdr->addr3, ETHER_ADDR_LEN); - - pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr); - put_hword(&pkt, algo); - put_hword(&pkt, seq); - put_hword(&pkt, status); - if (challenge_len > 0) - put_tlv(&pkt, IEEE80211_ELEMID_CHALLENGE, - challenge, challenge_len); - - wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf, pkt - (caddr_t)&sc->wi_txbuf); -} - - -/* wihap_assoc_req() - * - * Handle incoming association and reassociation requests. - */ -void -wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm, - caddr_t pkt, int len) -{ - struct ifnet *ifp = &sc->sc_ethercom.ec_if; - struct wihap_info *whi = &sc->wi_hostap_info; - struct wihap_sta_info *sta; - struct wi_80211_hdr *resp_hdr; - u_int16_t capinfo; - u_int16_t lstintvl; - u_int8_t rates[8]; - int ssid_len, rates_len; - int reassociation; - struct ieee80211_nwid ssid; - u_int16_t status; - u_int16_t asid = 0; - - if (len < 8) - return; - - /* Pull out request parameters. */ - capinfo = take_hword(&pkt, &len); - lstintvl = take_hword(&pkt, &len); - - reassociation = ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_STYPE)) == - htole16(WI_STYPE_MGMT_REASREQ)); - - if (reassociation) { - if (len < 6) - return; - /* Eat the MAC address of the current AP */ - take_hword(&pkt, &len); - take_hword(&pkt, &len); - take_hword(&pkt, &len); - } - - if ((ssid_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_SSID, - ssid.i_nwid, sizeof(ssid.i_nwid)))<0) - return; - ssid.i_len = ssid_len; - if ((rates_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_RATES, - rates, sizeof(rates)))<0) - return; - - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_assoc_req: from station %s\n", - ether_sprintf(rxfrm->wi_addr2)); - - /* If SSID doesn't match, simply drop. */ - if (sc->wi_netid.i_len != ssid.i_len || - memcmp(sc->wi_netid.i_nwid, ssid.i_nwid, ssid.i_len)) { - - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_assoc_req: bad ssid: '%.*s' != '%.*s'\n", - ssid.i_len, ssid.i_nwid, sc->wi_netid.i_len, - sc->wi_netid.i_nwid); - return; - } - - /* Is this station authenticated yet? */ - sta = wihap_sta_find(whi, rxfrm->wi_addr2); - if (sta == NULL || !(sta->flags & WI_SIFLAGS_AUTHEN)) { - wihap_sta_deauth(sc, rxfrm->wi_addr2, - IEEE80211_REASON_NOT_AUTHED); - return; - } - - /* Check supported rates against ours. */ - if (wihap_check_rates(sta, rates, rates_len)<0) { - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_assoc_req: rates mismatch.\n"); - status = IEEE80211_STATUS_BASIC_RATE; - goto fail; - } - - /* Check capinfo. - * Check for ESS, not IBSS. - * Check WEP/PRIVACY flags match. - * Refuse stations requesting to be put on CF-polling list. - */ - sta->capinfo = capinfo; - status = IEEE80211_STATUS_CAPINFO; - if ((capinfo & (IEEE80211_CAPINFO_ESS | IEEE80211_CAPINFO_IBSS)) != - IEEE80211_CAPINFO_ESS) { - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_assoc_req: capinfo: not ESS: " - "capinfo=0x%x\n", capinfo); - goto fail; - - } - if ((sc->wi_use_wep && !(capinfo & IEEE80211_CAPINFO_PRIVACY)) || - (!sc->wi_use_wep && (capinfo & IEEE80211_CAPINFO_PRIVACY))) { - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_assoc_req: WEP flag mismatch: " - "capinfo=0x%x\n", capinfo); - goto fail; - } - if ((capinfo & (IEEE80211_CAPINFO_CF_POLLABLE | - IEEE80211_CAPINFO_CF_POLLREQ)) == IEEE80211_CAPINFO_CF_POLLABLE) { - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_assoc_req: polling not supported: " - "capinfo=0x%x\n", capinfo); - goto fail; - } - - /* Use ASID is allocated by whi_sta_alloc(). */ - asid = sta->asid; - - if (sta->flags & WI_SIFLAGS_ASSOC) { - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_assoc_req: already assoc'ed?\n"); - } - - sta->flags |= WI_SIFLAGS_ASSOC; - callout_reset(&sta->tmo, hz * whi->inactivity_time, - wihap_sta_timeout, sta); - status = IEEE80211_STATUS_SUCCESS; - -fail: - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_assoc_req: returns status=0x%x\n", status); - - /* Send response. */ - resp_hdr = (struct wi_80211_hdr *)&sc->wi_txbuf; - memset(resp_hdr, 0, sizeof(struct wi_80211_hdr)); - resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT); - if (reassociation) { - resp_hdr->frame_ctl |= htole16(WI_STYPE_MGMT_REASRESP); - } else { - resp_hdr->frame_ctl |= htole16(WI_STYPE_MGMT_ASRESP); - } - pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr); - - bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN); - bcopy(LLADDR(ifp->if_sadl), resp_hdr->addr2, ETHER_ADDR_LEN); - bcopy(LLADDR(ifp->if_sadl), resp_hdr->addr3, ETHER_ADDR_LEN); - - put_hword(&pkt, capinfo); - put_hword(&pkt, status); - put_hword(&pkt, asid); - rates_len = put_rates(&pkt, sc->wi_supprates); - - wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf, pkt - (caddr_t)&sc->wi_txbuf); -} - -/* wihap_deauth_req() - * - * Handle deauthentication requests. Delete the station. - */ -void -wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm, - caddr_t pkt, int len) -{ - struct wihap_info *whi = &sc->wi_hostap_info; - struct wihap_sta_info *sta; - u_int16_t reason; - - if (len<2) - return; - - reason = take_hword(&pkt, &len); - - sta = wihap_sta_find(whi, rxfrm->wi_addr2); - if (sta == NULL) { - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_deauth_req: unknown station: %s\n", - ether_sprintf(rxfrm->wi_addr2)); - } - else - wihap_sta_delete(sta); -} - -/* wihap_disassoc_req() - * - * Handle disassociation requests. Just reset the assoc flag. - * We'll free up the station resources when we get a deauth - * request or when it times out. - */ -void -wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm, - caddr_t pkt, int len) -{ - struct wihap_info *whi = &sc->wi_hostap_info; - struct wihap_sta_info *sta; - u_int16_t reason; - - if (len < 2) - return; - - reason = take_hword(&pkt, &len); - - sta = wihap_sta_find(whi, rxfrm->wi_addr2); - if (sta == NULL) { - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - printf("wihap_disassoc_req: unknown station: %s\n", - ether_sprintf(rxfrm->wi_addr2)); - } - else if (!(sta->flags & WI_SIFLAGS_AUTHEN)) { - /* - * If station is not authenticated, send deauthentication - * frame. - */ - wihap_sta_deauth(sc, rxfrm->wi_addr2, - IEEE80211_REASON_NOT_AUTHED); - return; - } - else - sta->flags &= ~WI_SIFLAGS_ASSOC; -} - -/* wihap_debug_frame_type() - * - * Print out frame type. Used in early debugging. - */ -static __inline void -wihap_debug_frame_type(struct wi_frame *rxfrm) -{ - printf("wihap_mgmt_input: len=%d ", le16toh(rxfrm->wi_dat_len)); - - if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) == - htole16(WI_FTYPE_MGMT)) { - - printf("MGMT: "); - - switch (le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE) { - case WI_STYPE_MGMT_ASREQ: - printf("assoc req: \n"); - break; - case WI_STYPE_MGMT_ASRESP: - printf("assoc resp: \n"); - break; - case WI_STYPE_MGMT_REASREQ: - printf("reassoc req: \n"); - break; - case WI_STYPE_MGMT_REASRESP: - printf("reassoc resp: \n"); - break; - case WI_STYPE_MGMT_PROBEREQ: - printf("probe req: \n"); - break; - case WI_STYPE_MGMT_PROBERESP: - printf("probe resp: \n"); - break; - case WI_STYPE_MGMT_BEACON: - printf("beacon: \n"); - break; - case WI_STYPE_MGMT_ATIM: - printf("ann traf ind \n"); - break; - case WI_STYPE_MGMT_DISAS: - printf("disassociation: \n"); - break; - case WI_STYPE_MGMT_AUTH: - printf("auth: \n"); - break; - case WI_STYPE_MGMT_DEAUTH: - printf("deauth: \n"); - break; - default: - printf("unknown (stype=0x%x)\n", - le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE); - } - - } - else { - printf("ftype=0x%x (ctl=0x%x)\n", - le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_FTYPE, - le16toh(rxfrm->wi_frame_ctl)); - } -} - -/* - * wihap_mgmt_input: - * - * Called for each management frame received in host ap mode. - * wihap_mgmt_input() is expected to free the mbuf. - */ -void -wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) -{ - caddr_t pkt; - int s, len; - - if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) - wihap_debug_frame_type(rxfrm); - - pkt = mtod(m, caddr_t) + WI_SHORT_802_11_END; - len = m->m_len - WI_SHORT_802_11_END; - - if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) != - htole16(WI_FTYPE_MGMT)) { - m_freem(m); - return; - } - - /* any of the following will mess w/ the station list */ - s = splsoftclock(); - switch (le16toh(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE) { - case WI_STYPE_MGMT_ASREQ: - wihap_assoc_req(sc, rxfrm, pkt, len); - break; - case WI_STYPE_MGMT_ASRESP: - break; - case WI_STYPE_MGMT_REASREQ: - wihap_assoc_req(sc, rxfrm, pkt, len); - break; - case WI_STYPE_MGMT_REASRESP: - break; - case WI_STYPE_MGMT_PROBEREQ: - break; - case WI_STYPE_MGMT_PROBERESP: - break; - case WI_STYPE_MGMT_BEACON: - break; - case WI_STYPE_MGMT_ATIM: - break; - case WI_STYPE_MGMT_DISAS: - wihap_disassoc_req(sc, rxfrm, pkt, len); - break; - case WI_STYPE_MGMT_AUTH: - wihap_auth_req(sc, rxfrm, pkt, len); - break; - case WI_STYPE_MGMT_DEAUTH: - wihap_deauth_req(sc, rxfrm, pkt, len); - break; - } - splx(s); - - m_freem(m); -} - -/* wihap_sta_is_assoc() - * - * Determine if a station is assoc'ed. Update its activity - * counter as a side-effect. - */ -int -wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[]) -{ - struct wihap_sta_info *sta; - - sta = wihap_sta_find(whi, addr); - if (sta != NULL && (sta->flags & WI_SIFLAGS_ASSOC)) { - /* Keep it active. */ - callout_reset(&sta->tmo, hz * whi->inactivity_time, - wihap_sta_timeout, sta); - return (1); - } - - return (0); -} - -#if defined(WI_HOSTAP_POWERSAVE) -/* wihap_dequeue() - * - * Dequeue a PS-Poll'd frame, if any. - */ -struct mbuf * -wihap_dequeue(struct wihap_info *whi, int *more_data) -{ - *more_data = 0; - /* TBD Keep a circular queue of STAs who PS Poll'd. At time of - * PS Poll, label a STA with the time of PS Poll and put it - * on the tail of the queue. In this procedure, take STAs off - * the queue whose last Poll was too long ago for a reply to - * arrive in time. Dequeue one frame from the STA on the front - * of the queue. If any frame remains on the STAs queue, set - * *more_data = 1. Otherwise, set *more_data = 0. - */ - - /* TBD Keep a second queue of STAs with PS traffic queued. Use - * the second queue to produce the TIM. Possibly age STAs. - */ - - /* TBD Remove a STA from both queues before freeing it. */ - return 0; -} -#endif /* WI_HOSTAP_POWERSAVE */ - -/* wihap_check_tx() - * - * Determine if a station is assoc'ed, get its tx rate, and update - * its activity. Return 1 (send frame), 0 (drop frame), -1 (frame - * power-save queued). - */ -int -wihap_check_tx(struct wi_softc *sc, struct mbuf *m, u_int8_t *txrate) -{ - u_int8_t *addr; - struct wihap_info *whi; - struct wihap_sta_info *sta; - static u_int8_t txratetable[] = { 10, 20, 55, 110 }; - int s; - - whi = &sc->wi_hostap_info; - addr = mtod(m, struct ether_header*)->ether_dhost; - - if (addr[0] & 0x01) { - *txrate = 0; /* XXX: multicast rate? */ - return (1); - } - - s = splsoftclock(); - sta = wihap_sta_find(whi, addr); - - if (sta == NULL || !(sta->flags & WI_SIFLAGS_ASSOC)) { - splx(s); - if (sc->sc_if.if_flags & IFF_DEBUG) - printf("%s: Host-AP: dropping unassoc dst %s\n", - sc->sc_dev.dv_xname, - ether_sprintf(addr)); - m_freem(m); - return (0); - } - - /* Keep it active. */ - callout_reset(&sta->tmo, hz * whi->inactivity_time, - wihap_sta_timeout, sta); - *txrate = txratetable[sta->tx_curr_rate]; -#if defined(WI_HOSTAP_POWERSAVE) - if ((sta->flags & WI_SIFLAGS_ASLEEP) && - !(sta->flags & WI_SIFLAGS_PSPOLL)) { - IFQ_ENQUEUE(&sta->ps_q, m); - splx(s); - return (0); - } - sta->flags &= ~WI_SIFLAGS_PSPOLL; -#endif /* WI_HOSTAP_POWERSAVE */ - splx(s); - return (1); -} - -/* - * wihap_data_input() - * - * Handle all data input on interface when in Host AP mode. - * Some packets are destined for this machine, others are - * repeated to other stations. - * - * If wihap_data_input() returns a non-zero, it has processed - * the packet and will free the mbuf. - */ -int -wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m) -{ - struct ifnet *ifp = &sc->sc_ethercom.ec_if; - struct wihap_info *whi = &sc->wi_hostap_info; - struct wihap_sta_info *sta; - int mcast, s; - - /* TODS flag must be set. */ - if (!(rxfrm->wi_frame_ctl & htole16(WI_FCTL_TODS))) { - if (ifp->if_flags & IFF_DEBUG) - printf("wihap_data_input: no TODS src=%s\n", - ether_sprintf(rxfrm->wi_addr2)); - m_freem(m); - return (1); - } - - /* Check BSSID. (Is this necessary?) */ - if (!addr_cmp(rxfrm->wi_addr1, LLADDR(ifp->if_sadl))) { - if (ifp->if_flags & IFF_DEBUG) - printf("wihap_data_input: incorrect bss: %s\n", - ether_sprintf(rxfrm->wi_addr1)); - m_freem(m); - return (1); - } - - s = splsoftclock(); - - /* Find source station. */ - sta = wihap_sta_find(whi, rxfrm->wi_addr2); - - /* Source station must be associated. */ - if (sta == NULL || !(sta->flags & WI_SIFLAGS_ASSOC)) { - if (ifp->if_flags & IFF_DEBUG) - printf("wihap_data_input: dropping unassoc src %s\n", - ether_sprintf(rxfrm->wi_addr2)); - wihap_sta_disassoc(sc, rxfrm->wi_addr2, - IEEE80211_REASON_ASSOC_LEAVE); - splx(s); - m_freem(m); - return (1); - } - - callout_reset(&sta->tmo, hz * whi->inactivity_time, - wihap_sta_timeout, sta); - sta->sig_info = le16toh(rxfrm->wi_q_info); - - splx(s); - - /* Repeat this packet to BSS? */ - mcast = (rxfrm->wi_addr3[0] & 0x01) != 0; - if (mcast || wihap_sta_is_assoc(whi, rxfrm->wi_addr3)) { - - /* If it's multicast, make a copy. */ - if (mcast) { - m = m_copym(m, 0, M_COPYALL, M_DONTWAIT); - if (m == NULL) - return (0); - m->m_flags |= M_MCAST; /* XXX */ - } - - /* Queue up for repeating. */ - if (IF_QFULL(&ifp->if_snd)) { - IF_DROP(&ifp->if_snd); - m_freem(m); - } else { - ifp->if_obytes += m->m_pkthdr.len; - if (m->m_flags & M_MCAST) - ifp->if_omcasts++; - IF_ENQUEUE(&ifp->if_snd, m); - if ((ifp->if_flags & IFF_OACTIVE) == 0) - (*ifp->if_start)(ifp); - } - return (!mcast); - } - - return (0); -} - -/* wihap_ioctl() - * - * Handle Host AP specific ioctls. Called from wi_ioctl(). - */ -int -wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data) -{ - struct proc *p = curproc; - struct ifreq *ifr = (struct ifreq *) data; - struct wihap_info *whi = &sc->wi_hostap_info; - struct wihap_sta_info *sta; - struct hostap_getall reqall; - struct hostap_sta reqsta; - struct hostap_sta stabuf; - int s, error = 0, n, flag; - - if (!(sc->sc_ethercom.ec_if.if_flags & IFF_RUNNING)) - return ENODEV; - - switch (command) { - case SIOCHOSTAP_DEL: - if ((error = suser(p->p_ucred, &p->p_acflag))) - break; - if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta)))) - break; - s = splnet(); - sta = wihap_sta_find(whi, reqsta.addr); - if (sta == NULL) - error = ENOENT; - else { - /* Disassociate station. */ - if (sta->flags & WI_SIFLAGS_ASSOC) - wihap_sta_disassoc(sc, sta->addr, - IEEE80211_REASON_ASSOC_LEAVE); - /* Deauth station. */ - if (sta->flags & WI_SIFLAGS_AUTHEN) - wihap_sta_deauth(sc, sta->addr, - IEEE80211_REASON_AUTH_LEAVE); - - wihap_sta_delete(sta); - } - splx(s); - break; - - case SIOCHOSTAP_GET: - if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta)))) - break; - s = splnet(); - sta = wihap_sta_find(whi, reqsta.addr); - if (sta == NULL) - error = ENOENT; - else { - reqsta.flags = sta->flags; - reqsta.asid = sta->asid; - reqsta.capinfo = sta->capinfo; - reqsta.sig_info = sta->sig_info; - reqsta.rates = sta->rates; - - error = copyout(&reqsta, ifr->ifr_data, - sizeof(reqsta)); - } - splx(s); - break; - - case SIOCHOSTAP_ADD: - if ((error = suser(p->p_ucred, &p->p_acflag))) - break; - if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta)))) - break; - s = splnet(); - sta = wihap_sta_find(whi, reqsta.addr); - if (sta != NULL) { - error = EEXIST; - splx(s); - break; - } - if (whi->n_stations >= WIHAP_MAX_STATIONS) { - error = ENOSPC; - splx(s); - break; - } - sta = wihap_sta_alloc(sc, reqsta.addr); - sta->flags = reqsta.flags; -#if defined(WI_HOSTAP_POWERSAVE) - sta->flags &= ~(HOSTAP_FLAGS_ASLEEP | HOSTAP_FLAGS_PSPOLL); -#endif - callout_reset(&sta->tmo, hz * whi->inactivity_time, - wihap_sta_timeout, sta); - splx(s); - break; - - case SIOCHOSTAP_SFLAGS: - if ((error = suser(p->p_ucred, &p->p_acflag))) - break; - if ((error = copyin(ifr->ifr_data, &flag, sizeof(int)))) - break; - - whi->apflags = (whi->apflags & WIHAPFL_CANTCHANGE) | - (flag & ~WIHAPFL_CANTCHANGE); - break; - - case SIOCHOSTAP_GFLAGS: - flag = (int) whi->apflags; - error = copyout(&flag, ifr->ifr_data, sizeof(int)); - break; - - case SIOCHOSTAP_GETALL: - if ((error = copyin(ifr->ifr_data, &reqall, sizeof(reqall)))) - break; - - reqall.nstations = whi->n_stations; - n = 0; - s = splnet(); - sta = LIST_FIRST(&whi->sta_list); - while (sta && reqall.size >= n+sizeof(struct hostap_sta)) { - - bcopy(sta->addr, stabuf.addr, ETHER_ADDR_LEN); - stabuf.asid = sta->asid; - stabuf.flags = sta->flags; - stabuf.capinfo = sta->capinfo; - stabuf.sig_info = sta->sig_info; - stabuf.rates = sta->rates; - - error = copyout(&stabuf, (caddr_t) reqall.addr + n, - sizeof(struct hostap_sta)); - if (error) - break; - - sta = LIST_NEXT(sta, list); - n += sizeof(struct hostap_sta); - } - splx(s); - - if (!error) - error = copyout(&reqall, ifr->ifr_data, - sizeof(reqall)); - break; - default: - printf("wihap_ioctl: i shouldn't get other ioctls!\n"); - error = EINVAL; - } - - return (error); -} diff --git a/sys/dev/ic/wi_hostap.h b/sys/dev/ic/wi_hostap.h deleted file mode 100644 index 118647bd442..00000000000 --- a/sys/dev/ic/wi_hostap.h +++ /dev/null @@ -1,144 +0,0 @@ -/* $NetBSD: wi_hostap.h,v 1.2 2002/09/23 14:31:28 thorpej Exp $ */ -/* $OpenBSD: if_wi_hostap.h,v 1.6 2002/06/08 22:19:47 millert Exp $ */ - -/* - * Copyright (c) 2002 - * Thomas Skibo <skibo@pacbell.net>. All rights reserved. - * - * 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 Thomas Skibo. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Thomas Skibo 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 Thomas Skibo OR HIS DRINKING PALS - * 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. - */ - -#ifndef __WI_HOSTAP_H__ -#define __WI_HOSTAP_H__ - -#define WIHAP_MAX_STATIONS 1800 - -struct hostap_sta { - u_int8_t addr[6]; - u_int16_t asid; - u_int16_t flags; - u_int16_t sig_info; /* 15:8 signal, 7:0 noise */ - u_int16_t capinfo; - u_int8_t rates; -}; - -#define HOSTAP_FLAGS_AUTHEN 0x0001 -#define HOSTAP_FLAGS_ASSOC 0x0002 -#define HOSTAP_FLAGS_PERM 0x0004 -#if defined(WI_HOSTAP_POWERSAVE) -#define HOSTAP_FLAGS_ASLEEP 0x0008 -#define HOSTAP_FLAGS_PSPOLL 0x0010 -#endif /* WI_HOSTAP_POWERSAVE */ - -#define SIOCHOSTAP_GET _IOWR('i', 210, struct ifreq) -#define SIOCHOSTAP_ADD _IOWR('i', 211, struct ifreq) -#define SIOCHOSTAP_DEL _IOWR('i', 212, struct ifreq) -#define SIOCHOSTAP_GETALL _IOWR('i', 213, struct ifreq) -#define SIOCHOSTAP_GFLAGS _IOWR('i', 214, struct ifreq) -#define SIOCHOSTAP_SFLAGS _IOWR('i', 215, struct ifreq) - -/* Flags for SIOCHOSTAP_GFLAGS/SFLAGS */ -#define WIHAPFL_ACTIVE 0x0001 -#define WIHAPFL_MAC_FILT 0x0002 - -/* Flags set inernally only: */ -#define WIHAPFL_CANTCHANGE (WIHAPFL_ACTIVE) - -struct hostap_getall { - int nstations; - struct hostap_sta *addr; - int size; -}; - - - -#ifdef _KERNEL -struct wihap_sta_info { - LIST_ENTRY(wihap_sta_info) list; - LIST_ENTRY(wihap_sta_info) hash; - - struct wi_softc *sc; - u_int8_t addr[6]; - u_short flags; - struct callout tmo; - - u_int16_t asid; - u_int16_t capinfo; - u_int16_t sig_info; /* 15:8 signal, 7:0 noise */ - u_int8_t rates; - u_int8_t tx_curr_rate; - u_int8_t tx_max_rate; - u_int32_t *challenge; -#if defined(WI_HOSTAP_POWERSAVE) - struct altq ps_q; -#endif -}; - -#define WI_SIFLAGS_ASSOC HOSTAP_FLAGS_ASSOC -#define WI_SIFLAGS_AUTHEN HOSTAP_FLAGS_AUTHEN -#define WI_SIFLAGS_PERM HOSTAP_FLAGS_PERM -#if defined(WI_HOSTAP_POWERSAVE) -#define WI_SIFLAGS_ASLEEP HOSTAP_FLAGS_ASLEEP -#define WI_SIFLAGS_PSPOLL HOSTAP_FLAGS_PSPOLL -#endif /* WI_HOSTAP_POWERSAVE */ - -#define WI_STA_HASH_SIZE 113 - -#if WI_STA_HASH_SIZE*16 >= 2007 /* will generate ASID's too large. */ -#error "WI_STA_HASH_SIZE too big" -#endif -#if WI_STA_HASH_SIZE*16 < WIHAP_MAX_STATIONS -#error "WI_STA_HASH_SIZE too small" -#endif - -struct wihap_info { - LIST_HEAD(sta_list, wihap_sta_info) sta_list; - LIST_HEAD(sta_hash, wihap_sta_info) sta_hash[WI_STA_HASH_SIZE]; - - u_int16_t apflags; - - int n_stations; - u_int16_t asid_inuse_mask[WI_STA_HASH_SIZE]; - - int inactivity_time; -}; - -#define WIHAP_DFLT_INACTIVITY_TIME (120) /* 2 minutes */ - -struct wi_softc; -struct wi_frame; - -int wihap_check_tx(struct wi_softc *, struct mbuf *, u_int8_t *); -int wihap_data_input(struct wi_softc *, struct wi_frame *, struct mbuf *); -int wihap_ioctl(struct wi_softc *, u_long, caddr_t); -void wihap_init(struct wi_softc *); -void wihap_mgmt_input(struct wi_softc *, struct wi_frame *, struct mbuf *); -void wihap_shutdown(struct wi_softc *); - -#endif /* _KERNEL */ -#endif /* __WI_HOSTAP_H__ */ diff --git a/sys/dev/ic/wireg.h b/sys/dev/ic/wireg.h index 0be760109a6..780328c7d93 100644 --- a/sys/dev/ic/wireg.h +++ b/sys/dev/ic/wireg.h @@ -1,4 +1,4 @@ -/* $NetBSD: wireg.h,v 1.39 2002/09/23 14:31:28 thorpej Exp $ */ +/* $NetBSD: wireg.h,v 1.40 2002/09/30 06:50:36 onoe Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -39,130 +39,12 @@ #define WI_TIMEOUT 65536 -#define WI_PORT0 0 -#define WI_PORT1 1 -#define WI_PORT2 2 -#define WI_PORT3 3 -#define WI_PORT4 4 -#define WI_PORT5 5 - -/* Default port: 0 (only 0 exists on stations) */ -#define WI_DEFAULT_PORT (WI_PORT0 << 8) - -/* Default TX rate: 2Mbps, auto fallback */ -#define WI_DEFAULT_TX_RATE 3 - -/* Default network name: ANY */ -/* - * [sommerfeld 1999/07/15] Changed from "ANY" to ""; according to Bill Fenner, - * ANY is used in MS driver user interfaces, while "" is used over the - * wire.. - */ -#define WI_DEFAULT_NETNAME "" - -#define WI_DEFAULT_AP_DENSITY 1 - -#define WI_DEFAULT_RTS_THRESH 2347 - -#define WI_DEFAULT_DATALEN 2304 - -#define WI_DEFAULT_CREATE_IBSS 0 - -#define WI_DEFAULT_PM_ENABLED 0 - -#define WI_DEFAULT_MAX_SLEEP 100 - -#define WI_DEFAULT_ROAMING 1 - -#define WI_DEFAULT_AUTHTYPE 1 - -#ifdef __NetBSD__ -#define OS_STRING_NAME "NetBSD" -#endif -#ifdef __FreeBSD__ -#define OS_STRING_NAME "FreeBSD" -#endif -#ifdef __OpenBSD__ -#define OS_STRING_NAME "OpenBSD" -#endif - -#define WI_DEFAULT_NODENAME OS_STRING_NAME " WaveLAN/IEEE node" - -#define WI_DEFAULT_IBSS OS_STRING_NAME " IBSS" - -#define WI_DEFAULT_CHAN 3 - -/* - * register space access macros - */ -#ifdef WI_AT_BIGENDIAN_BUS_HACK - /* - * XXX - ugly hack for sparc bus_space_* macro deficiencies: - * assume the bus we are accessing is big endian. - */ - -#define CSR_WRITE_4(sc, reg, val) \ - bus_space_write_4(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg) , htole32(val)) -#define CSR_WRITE_2(sc, reg, val) \ - bus_space_write_2(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg), htole16(val)) -#define CSR_WRITE_1(sc, reg, val) \ - bus_space_write_1(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg), val) - -#define CSR_READ_4(sc, reg) \ - le32toh(bus_space_read_4(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg))) -#define CSR_READ_2(sc, reg) \ - le16toh(bus_space_read_2(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg))) -#define CSR_READ_1(sc, reg) \ - bus_space_read_1(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg)) - -#else - -#define CSR_WRITE_4(sc, reg, val) \ - bus_space_write_4(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg) , val) -#define CSR_WRITE_2(sc, reg, val) \ - bus_space_write_2(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg), val) -#define CSR_WRITE_1(sc, reg, val) \ - bus_space_write_1(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg), val) - -#define CSR_READ_4(sc, reg) \ - bus_space_read_4(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg)) -#define CSR_READ_2(sc, reg) \ - bus_space_read_2(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg)) -#define CSR_READ_1(sc, reg) \ - bus_space_read_1(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg)) -#endif - -#ifndef __BUS_SPACE_HAS_STREAM_METHODS -#define bus_space_write_stream_2 bus_space_write_2 -#define bus_space_write_multi_stream_2 bus_space_write_multi_2 -#define bus_space_read_stream_2 bus_space_read_2 -#define bus_space_read_multi_stream_2 bus_space_read_multi_2 -#endif - -#define CSR_WRITE_STREAM_2(sc, reg, val) \ - bus_space_write_stream_2(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg), val) -#define CSR_WRITE_MULTI_STREAM_2(sc, reg, val, count) \ - bus_space_write_multi_stream_2(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg), val, count) -#define CSR_READ_STREAM_2(sc, reg) \ - bus_space_read_stream_2(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg)) -#define CSR_READ_MULTI_STREAM_2(sc, reg, buf, count) \ - bus_space_read_multi_stream_2(sc->sc_iot, sc->sc_ioh, \ - (sc->sc_pci? reg * 2: reg), buf, count) +#define WI_PORT0 (0 << 8) +#define WI_PORT1 (1 << 8) +#define WI_PORT2 (2 << 8) +#define WI_PORT3 (3 << 8) +#define WI_PORT4 (4 << 8) +#define WI_PORT5 (5 << 8) /* * The WaveLAN/IEEE cards contain an 802.11 MAC controller which Lucent @@ -209,8 +91,6 @@ #define WI_IOSIZE 0x40 #define WI_PCI_CBMA 0x10 /* Configuration Base Memory Address */ -#define WI_PCI_COR_OFFSET 0x4C - /* * Hermes & Prism2 register definitions */ @@ -276,10 +156,9 @@ /* * Buffer Access Path (BAP) registers. * These are I/O channels. I believe you can use each one for - * any desired purpose independently of the other. In general - * though, we use BAP1 for reading and writing LTV records and - * reading received data frames, and BAP0 for writing transmit - * frames. This is a convention though, not a rule. + * any desired purpose independently of the other. + * Currently, we only use BAP0, and perhaps BAP1 can be used + * within interrupt context. */ #define WI_SEL0 0x18 #define WI_SEL1 0x1A @@ -287,8 +166,6 @@ #define WI_OFF1 0x1E #define WI_DATA0 0x36 #define WI_DATA1 0x38 -#define WI_BAP0 WI_DATA0 -#define WI_BAP1 WI_DATA1 #define WI_OFF_BUSY 0x8000 #define WI_OFF_ERR 0x4000 @@ -312,9 +189,6 @@ #define WI_EV_TX 0x0002 /* async xmit completed succesfully */ #define WI_EV_RX 0x0001 /* async rx completed */ -#define WI_INTRS \ - (WI_EV_RX|WI_EV_TX|WI_EV_TX_EXC|WI_EV_ALLOC|WI_EV_INFO|WI_EV_INFO_DROP) - /* Host software registers */ #define WI_SW0 0x28 #define WI_SW1 0x2A @@ -361,9 +235,6 @@ #define WI_PCI_MASTER0_LEN 0x88 #define WI_PCI_MASTER0_CON 0x8C -#define WI_COR_SOFT_RESET (1 << 7) -#define WI_COR_CLEAR 0x00 - #define WI_PCI_STATUS 0x98 #define WI_PCI_MASTER1_ADDRH 0xA0 @@ -371,7 +242,8 @@ #define WI_PCI_MASTER1_LEN 0xA8 #define WI_PCI_MASTER1_CON 0xAC -#define WI_PCI_SOFT_RESET (1 << 7) +#define WI_COR_SOFT_RESET (1 << 7) +#define WI_COR_CLEAR 0x00 /* * One form of communication with the Hermes is with what Lucent calls @@ -379,48 +251,16 @@ * and type are 16 bits and are in native byte order. The value is in * multiples of 16 bits and is in little endian byte order. */ -struct wi_ltv_gen { - u_int16_t wi_len; - u_int16_t wi_type; - u_int16_t wi_val; -}; - -struct wi_ltv_str { +struct wi_lt_hdr { u_int16_t wi_len; u_int16_t wi_type; - u_int16_t wi_str[17]; + /* value is vary depends on resource id */ }; -#define WI_SETVAL(recno, val) \ - do { \ - struct wi_ltv_gen g; \ - \ - g.wi_len = 2; \ - g.wi_type = recno; \ - g.wi_val = htole16(val); \ - wi_write_record(sc, &g); \ - } while (0) - -#define WI_SETSTR(recno, str) \ - do { \ - struct wi_ltv_str s; \ - int l; \ - \ - l = (strlen(str) + 1) & ~0x1; \ - memset((char *)&s, 0, sizeof(s)); \ - s.wi_len = (l / 2) + 2; \ - s.wi_type = recno; \ - s.wi_str[0] = htole16(strlen(str)); \ - memcpy((char *)&s.wi_str[1], str, strlen(str)); \ - wi_write_record(sc, (struct wi_ltv_gen *)&s); \ - } while (0) - /* * Download buffer location and length (0xFD01). */ -struct wi_ltv_dnld_buf { - u_int16_t wi_len; - u_int16_t wi_type; +struct wi_dnld_buf { u_int16_t wi_buf_pg; /* page addr of intermediate dl buf*/ u_int16_t wi_buf_off; /* offset of idb */ u_int16_t wi_buf_len; /* len of idb */ @@ -429,9 +269,7 @@ struct wi_ltv_dnld_buf { /* * Mem sizes (0xFD02). */ -struct wi_ltv_memsz { - u_int16_t wi_len; - u_int16_t wi_type; +struct wi_memsz { u_int16_t wi_mem_ram; u_int16_t wi_mem_nvram; }; @@ -439,9 +277,7 @@ struct wi_ltv_memsz { /* * NIC Identification (0xFD0B, 0xFD20) */ -struct wi_ltv_ver { - u_int16_t wi_len; - u_int16_t wi_type; +struct wi_ver { u_int16_t wi_ver[4]; }; @@ -510,27 +346,21 @@ struct wi_ltv_ver { /* * List of intended regulatory domains (0xFD11). */ -struct wi_ltv_domains { - u_int16_t wi_len; - u_int16_t wi_type; +struct wi_domains { u_int16_t wi_domains[6]; }; /* * CIS struct (0xFD13). */ -struct wi_ltv_cis { - u_int16_t wi_len; - u_int16_t wi_type; +struct wi_cis { u_int16_t wi_cis[240]; }; /* * Communications quality (0xFD43). */ -struct wi_ltv_commqual { - u_int16_t wi_len; - u_int16_t wi_type; +struct wi_commqual { u_int16_t wi_coms_qual; u_int16_t wi_sig_lvl; u_int16_t wi_noise_lvl; @@ -539,9 +369,7 @@ struct wi_ltv_commqual { /* * Actual system scale thresholds (0xFC06, 0xFD46). */ -struct wi_ltv_scalethresh { - u_int16_t wi_len; - u_int16_t wi_type; +struct wi_scalethresh { u_int16_t wi_energy_detect; u_int16_t wi_carrier_detect; u_int16_t wi_defer; @@ -553,9 +381,7 @@ struct wi_ltv_scalethresh { /* * PCF info struct (0xFD87). */ -struct wi_ltv_pcf { - u_int16_t wi_len; - u_int16_t wi_type; +struct wi_pcf { u_int16_t wi_medium_occupancy_limit; u_int16_t wi_cfp_period; u_int16_t wi_cfp_max_duration; @@ -579,47 +405,41 @@ struct wi_ltv_pcf { /* * Mac addresses. (0xFC01, 0xFC08) */ -struct wi_ltv_macaddr { - u_int16_t wi_len; - u_int16_t wi_type; +struct wi_macaddr { u_int8_t wi_mac_addr[6]; }; /* * Station set identification (SSID). (0xFC02, 0xFC04) */ -struct wi_ltv_ssid { +struct wi_ssid { u_int16_t wi_len; - u_int16_t wi_type; - u_int16_t wi_id[17]; + u_int8_t wi_ssid[32]; }; /* * Set our station name. (0xFC0E) */ -struct wi_ltv_nodename { - u_int16_t wi_len; - u_int16_t wi_type; - u_int16_t wi_nodename[17]; +struct wi_nodename { + u_int16_t wi_nodelen; + u_int8_t wi_nodename[32]; }; /* * Multicast addresses to be put in filter. We're * allowed up to 16 addresses in the filter. (0xFC80) */ -struct wi_ltv_mcast { - u_int16_t wi_len; - u_int16_t wi_type; +struct wi_mcast { struct ether_addr wi_mcast[16]; }; /* - * Supported rates. + * Join request. (0xFCE2) */ -#define WI_SUPPRATES_1M 0x0001 -#define WI_SUPPRATES_2M 0x0002 -#define WI_SUPPRATES_5M 0x0004 -#define WI_SUPPRATES_11M 0x0008 +struct wi_joinreq { + struct ether_addr wi_bssid; + u_int16_t wi_chan; +}; /* * Information frame types. @@ -629,6 +449,12 @@ struct wi_ltv_mcast { #define WI_INFO_SCAN_RESULTS 0xF101 /* Scan results */ #define WI_INFO_HOST_SCAN_RESULTS 0xF104 /* Scan results */ #define WI_INFO_LINK_STAT 0xF200 /* Link status */ +#define CONNECTED 1 +#define DISCONNECTED 2 +#define AP_CHANGE 3 +#define AP_OUT_OF_RANGE 4 +#define AP_IN_RANGE 5 +#define ASSOC_FAILED 6 #define WI_INFO_ASSOC_STAT 0xF201 /* Association status */ struct wi_assoc { u_int16_t wi_assoc_stat; /* Association Status */ @@ -702,41 +528,13 @@ struct wi_frame { u_int16_t wi_rsvd1; /* 0x04 */ /* 0 */ u_int16_t wi_q_info; /* 0x06 */ u_int16_t wi_rsvd2; /* 0x08 */ - u_int8_t wi_tx_rtry; /* 0x0A */ /* (Prism2 Only) */ - u_int8_t wi_tx_rate; /* 0x0B */ /* (Prism2 Only) */ - u_int16_t wi_tx_ctl; /* 0x0C */ - u_int16_t wi_frame_ctl; /* 0x0E */ - u_int16_t wi_id; /* 0x10 */ - u_int8_t wi_addr1[6]; /* 0x12 */ - u_int8_t wi_addr2[6]; /* 0x18 */ - u_int8_t wi_addr3[6]; /* 0x1E */ - u_int16_t wi_seq_ctl; /* 0x24 */ - u_int8_t wi_addr4[6]; /* 0x26 */ - u_int16_t wi_dat_len; /* 0x2C */ - u_int8_t wi_dst_addr[6]; /* 0x2E */ - u_int8_t wi_src_addr[6]; /* 0x34 */ - u_int16_t wi_len; /* 0x3A */ -#if 0 - struct llc wi_llc; /* 0x3C */ /* SNAP header */ -#endif -}; - -#define WI_TX_BUFSIZE (ETHER_MAX_LEN + sizeof(struct wi_frame) + 8) - -#define WI_802_3_OFFSET 0x2E -#define WI_802_11_OFFSET 0x44 -#define WI_802_11_OFFSET_RAW 0x3C -#define WI_802_11_OFFSET_HDR 0x0E - -#define WI_HWSPEC_END 0x0E -#define WI_802_11_BEGIN 0x0E -#define WI_SHORT_802_11_END 0x26 -#define WI_LONG_802_11_END 0x2C -#define WI_802_3_BEGIN 0x2E -#define WI_802_3_END 0x3C -#define WI_DATA_BEGIN 0x3C -#define WI_LLC_BEGIN 0x3C -#define WI_LLC_END 0x44 + u_int8_t wi_tx_rtry; /* 0x0a */ /* (Prism2 Only) */ + u_int8_t wi_tx_rate; /* 0x0b */ /* (Prism2 Only) */ + u_int16_t wi_tx_ctl; /* 0x0c */ + struct ieee80211_frame_addr4 wi_whdr; /* 0x0e */ + u_int16_t wi_dat_len; /* 0x2c */ + struct ether_header wi_ehdr; /* 0x2e */ +} __attribute__((__packed__)); /* Tx Status Field */ #define WI_TXSTAT_RET_ERR 0x0001 @@ -751,12 +549,16 @@ struct wi_frame { #define WI_STAT_MAC_PORT 0x0700 #define WI_STAT_PCF 0x1000 #define WI_RXSTAT_MSG_TYPE 0xE000 -#define WI_STAT_NORMAL 0x0000 #define WI_STAT_1042 0x2000 /* RFC1042 encoded */ #define WI_STAT_TUNNEL 0x4000 /* Bridge-tunnel encoded */ #define WI_STAT_WMP_MSG 0x6000 /* WaveLAN-II management protocol */ #define WI_STAT_MGMT 0x8000 /* 802.11b management frames */ +#define WI_ENC_TX_E_II 0x0E + +#define WI_ENC_TX_1042 0x00 +#define WI_ENC_TX_TUNNEL 0xF8 + /* TxControl Field (enhanced) */ #define WI_TXCNTL_TX_OK 0x0002 #define WI_TXCNTL_TX_EX 0x0004 @@ -765,11 +567,3 @@ struct wi_frame { #define WI_ENC_TX_802_11 0x08 #define WI_TXCNTL_ALTRTRY 0x0020 #define WI_TXCNTL_NOCRYPT 0x0080 - -/* - * SNAP (sub-network access protocol) constants for transmission - * of IP datagrams over IEEE 802 networks, taken from RFC1042. - * We need these for the LLC/SNAP header fields in the TX/RX frame - * structure. - */ -#define WI_SNAP_LEN 8 diff --git a/sys/dev/ic/wivar.h b/sys/dev/ic/wivar.h index 80593dc822c..9349b8cfbfa 100644 --- a/sys/dev/ic/wivar.h +++ b/sys/dev/ic/wivar.h @@ -1,4 +1,4 @@ -/* $NetBSD: wivar.h,v 1.20 2002/09/30 06:29:30 onoe Exp $ */ +/* $NetBSD: wivar.h,v 1.21 2002/09/30 06:50:36 onoe Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -36,103 +36,76 @@ * FreeBSD driver ported to NetBSD by Bill Sommerfeld in the back of the * Oslo IETF plenary meeting. */ - -#include <dev/ic/wi_hostap.h> - struct wi_softc { struct device sc_dev; - struct ethercom sc_ethercom; - void *sc_ih; /* interrupt handler */ - int (*sc_enable) __P((struct wi_softc *)); - void (*sc_disable) __P((struct wi_softc *)); - - int sc_attached; - int sc_enabled; - int sc_firmware_type; + struct ieee80211com sc_ic; + void *sc_ih; /* interrupt handler */ + int (*sc_enable)(struct wi_softc *); + void (*sc_disable)(struct wi_softc *); + + int sc_attached; + int sc_enabled; + int sc_firmware_type; #define WI_NOTYPE 0 #define WI_LUCENT 1 #define WI_INTERSIL 2 #define WI_SYMBOL 3 - int sc_pri_firmware_ver; /* Primary firmware version */ - int sc_sta_firmware_ver; /* Station firmware version */ - int sc_pci; /* attach to PCI-Bus */ - - bus_space_tag_t sc_iot; /* bus cookie */ - bus_space_handle_t sc_ioh; /* bus i/o handle */ - - struct callout wi_inquire_ch; - struct callout wi_scan_sh; + int sc_pri_firmware_ver; /* Primary firm vers */ + int sc_sta_firmware_ver; /* Station firm vers */ + int sc_pci; /* attach to PCI-Bus */ - u_int8_t sc_macaddr[ETHER_ADDR_LEN]; - - u_int16_t wi_txbuf[(sizeof(struct wi_frame) + 2312) / 2]; + bus_space_tag_t sc_iot; /* bus cookie */ + bus_space_handle_t sc_ioh; /* bus i/o handle */ struct ifmedia sc_media; - int wi_flags; - int wi_tx_data_id; - int wi_tx_mgmt_id; - int wi_if_flags; - u_int16_t wi_ptype; - u_int16_t wi_portnum; - u_int16_t wi_max_data_len; - u_int16_t wi_rts_thresh; - u_int16_t wi_ap_density; - u_int16_t wi_tx_rate; - u_int16_t wi_create_ibss; - u_int16_t wi_channels; - u_int16_t wi_pm_enabled; - u_int16_t wi_mor_enabled; - u_int16_t wi_max_sleep; - u_int16_t wi_authtype; - u_int16_t wi_roaming; - u_int16_t wi_supprates; - - struct ieee80211_nwid wi_nodeid; - struct ieee80211_nwid wi_netid; - struct ieee80211_nwid wi_ibssid; - - int wi_use_wep; - int wi_do_host_encrypt; - int wi_tx_key; - struct wi_ltv_keys wi_keys; - struct wi_counters wi_stats; - u_int16_t wi_ibss_port; - - u_int8_t wi_current_bssid[IEEE80211_ADDR_LEN]; - u_int16_t wi_current_channel; /* current BSS channel */ - - u_int8_t wi_join_bssid[IEEE80211_ADDR_LEN]; - u_int16_t wi_join_channel; /* channel of BSS to join */ - - u_int16_t wi_create_channel;/* channel of BSS to create */ - - struct wi_apinfo wi_aps[MAXAPINFO]; - int wi_naps; - int wi_scanning; /* scan mode */ - - struct wihap_info wi_hostap_info; - u_int32_t wi_icv; - int wi_icv_flag; - - caddr_t sc_bpf80211; - caddr_t sc_bpf80211plus; + caddr_t sc_drvbpf; + int sc_flags; + int sc_bap_id; + int sc_bap_off; + + u_int16_t sc_max_datalen; + u_int16_t sc_rts_thresh; + u_int16_t sc_system_scale; + u_int16_t sc_tx_rate; + u_int16_t sc_cnfauthmode; + u_int16_t sc_roaming_mode; + u_int16_t sc_microwave_oven; + + int sc_nodelen; + char sc_nodename[IEEE80211_NWID_LEN]; + + int sc_buflen; +#define WI_NTXBUF 3 + struct sc_txdesc { + int d_fid; + int d_len; + } sc_txd[WI_NTXBUF]; + int sc_txnext; + int sc_txcur; + int sc_tx_timer; + int sc_scan_timer; + + struct wi_counters sc_stats; + u_int16_t sc_ibss_port; + + struct wi_apinfo sc_aps[MAXAPINFO]; + int sc_naps; }; -#define sc_if sc_ethercom.ec_if +#define sc_if sc_ic.ic_if + +#define WI_SCAN_INQWAIT 3 /* wait sec before inquire */ +#define WI_SCAN_WAIT 5 /* maximum scan wait */ /* Values for wi_flags. */ #define WI_FLAGS_ATTACHED 0x0001 #define WI_FLAGS_INITIALIZED 0x0002 -#define WI_FLAGS_HAS_WEP 0x0004 -#define WI_FLAGS_HAS_IBSS 0x0008 -#define WI_FLAGS_HAS_CREATE_IBSS 0x0010 -#define WI_FLAGS_HAS_MOR 0x0020 -#define WI_FLAGS_HAS_ROAMING 0x0040 -#define WI_FLAGS_HAS_DIVERSITY 0x0080 -#define WI_FLAGS_HAS_HOSTAP 0x0100 -#define WI_FLAGS_CONNECTED 0x0200 -#define WI_FLAGS_AP_IN_RANGE 0x0400 -#define WI_FLAGS_JOINING 0x0800 +#define WI_FLAGS_NO_BSSID 0x0004 +#define WI_FLAGS_HAS_MOR 0x0010 +#define WI_FLAGS_HAS_ROAMING 0x0020 +#define WI_FLAGS_HAS_DIVERSITY 0x0040 +#define WI_FLAGS_HAS_SYSSCALE 0x0080 +#define WI_FLAGS_BUG_AUTOINC 0x0100 struct wi_card_ident { u_int16_t card_id; @@ -140,11 +113,82 @@ struct wi_card_ident { u_int8_t firm_type; }; -int wi_attach __P((struct wi_softc *)); -int wi_detach __P((struct wi_softc *)); -int wi_activate __P((struct device *, enum devact)); -int wi_intr __P((void *arg)); -void wi_power __P((struct wi_softc *, int)); -void wi_shutdown __P((struct wi_softc *)); - -int wi_mgmt_xmit(struct wi_softc *, caddr_t, int); +/* + * register space access macros + */ +#ifdef WI_AT_BIGENDIAN_BUS_HACK + /* + * XXX - ugly hack for sparc bus_space_* macro deficiencies: + * assume the bus we are accessing is big endian. + */ + +#define CSR_WRITE_4(sc, reg, val) \ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg) , htole32(val)) +#define CSR_WRITE_2(sc, reg, val) \ + bus_space_write_2(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg), htole16(val)) +#define CSR_WRITE_1(sc, reg, val) \ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg), val) + +#define CSR_READ_4(sc, reg) \ + le32toh(bus_space_read_4(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg))) +#define CSR_READ_2(sc, reg) \ + le16toh(bus_space_read_2(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg))) +#define CSR_READ_1(sc, reg) \ + bus_space_read_1(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg)) + +#else + +#define CSR_WRITE_4(sc, reg, val) \ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg) , val) +#define CSR_WRITE_2(sc, reg, val) \ + bus_space_write_2(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg), val) +#define CSR_WRITE_1(sc, reg, val) \ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg), val) + +#define CSR_READ_4(sc, reg) \ + bus_space_read_4(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg)) +#define CSR_READ_2(sc, reg) \ + bus_space_read_2(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg)) +#define CSR_READ_1(sc, reg) \ + bus_space_read_1(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg)) +#endif + +#ifndef __BUS_SPACE_HAS_STREAM_METHODS +#define bus_space_write_stream_2 bus_space_write_2 +#define bus_space_write_multi_stream_2 bus_space_write_multi_2 +#define bus_space_read_stream_2 bus_space_read_2 +#define bus_space_read_multi_stream_2 bus_space_read_multi_2 +#endif + +#define CSR_WRITE_STREAM_2(sc, reg, val) \ + bus_space_write_stream_2(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg), val) +#define CSR_WRITE_MULTI_STREAM_2(sc, reg, val, count) \ + bus_space_write_multi_stream_2(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg), val, count) +#define CSR_READ_STREAM_2(sc, reg) \ + bus_space_read_stream_2(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg)) +#define CSR_READ_MULTI_STREAM_2(sc, reg, buf, count) \ + bus_space_read_multi_stream_2(sc->sc_iot, sc->sc_ioh, \ + (sc->sc_pci? reg * 2: reg), buf, count) + + +int wi_attach(struct wi_softc *); +int wi_detach(struct wi_softc *); +int wi_activate(struct device *, enum devact); +int wi_intr(void *arg); +void wi_power(struct wi_softc *, int); +void wi_shutdown(struct wi_softc *); |
