diff options
| author | ichiro <ichiro@NetBSD.org> | 2002-01-21 11:28:18 +0000 |
|---|---|---|
| committer | ichiro <ichiro@NetBSD.org> | 2002-01-21 11:28:18 +0000 |
| commit | e08ec84292300798104ecdb0dc53bfa94e983dad (patch) | |
| tree | 4fc90f3c6704be985bb36622d98e4d3a76fafce9 /sys/dev/ic | |
| parent | 0d1261454ee9fa87f9514a3656e9dbeacefd5d38 (diff) | |
"Association Faild" was added to "Link Stat" messages.
;
Implement wi_scan into wi.c.
forces if_wi to initiate one round of access point scan.
This code was written by jrb@cs.pdx.edu, modified and bug-fixed by ichiro@netbsd.org
Diffstat (limited to 'sys/dev/ic')
| -rw-r--r-- | sys/dev/ic/wi.c | 142 | ||||
| -rw-r--r-- | sys/dev/ic/wi_ieee.h | 37 | ||||
| -rw-r--r-- | sys/dev/ic/wireg.h | 50 | ||||
| -rw-r--r-- | sys/dev/ic/wivar.h | 9 |
4 files changed, 212 insertions, 26 deletions
diff --git a/sys/dev/ic/wi.c b/sys/dev/ic/wi.c index 34a459743cc..c1ac6ac4858 100644 --- a/sys/dev/ic/wi.c +++ b/sys/dev/ic/wi.c @@ -1,4 +1,4 @@ -/* $NetBSD: wi.c,v 1.34 2002/01/20 07:26:14 ichiro Exp $ */ +/* $NetBSD: wi.c,v 1.35 2002/01/21 11:28:18 ichiro Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -70,7 +70,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.34 2002/01/20 07:26:14 ichiro Exp $"); +__KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.35 2002/01/21 11:28:18 ichiro Exp $"); #define WI_HERMES_AUTOINC_WAR /* Work around data write autoinc bug. */ #define WI_HERMES_STATS_WAR /* Work around stats counter bug. */ @@ -125,6 +125,7 @@ static int wi_write_data __P((struct wi_softc *, 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_mgmt_xmit __P((struct wi_softc *, caddr_t, int)); @@ -160,6 +161,7 @@ wi_attach(sc) 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); @@ -237,6 +239,11 @@ wi_attach(sc) 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; + /* * Find out if we support WEP on this card. */ @@ -429,14 +436,43 @@ void wi_inquire(xsc) wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_COUNTERS); } +void wi_wait_scan(xsc) + void *xsc; +{ + struct wi_softc *sc; + struct ifnet *ifp; + + sc = xsc; + ifp = &sc->sc_ethercom.ec_if; + + /* If not scanning, ignore */ + if (!sc->wi_scanning) + return; + + /* Wait for to make INQUIRE */ + if (ifp->if_flags & IFF_OACTIVE) { + callout_reset(&sc->wi_scan_sh, hz * 1, wi_wait_scan, sc); + return; + } + + /* try INQUIRE */ + if (wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS) == ETIMEDOUT) { + callout_reset(&sc->wi_scan_sh, hz * 1, wi_wait_scan, sc); + return; + } +} + void wi_update_stats(sc) struct wi_softc *sc; { 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 */ u_int16_t id; struct ifnet *ifp; u_int32_t *ptr; - int len, i; + int len, naps, i, j; u_int16_t t; ifp = &sc->sc_ethercom.ec_if; @@ -446,6 +482,64 @@ void wi_update_stats(sc) wi_read_data(sc, id, 0, (char *)&gen, 4); switch (gen.wi_type) { + case WI_INFO_SCAN_RESULTS: + if (gen.wi_len < 3) + break; + if (sc->sc_prism2) { /* Prism2 chip */ + naps = 2 * (gen.wi_len - 3) / sizeof(ap2); + naps = naps > MAXAPINFO ? MAXAPINFO : naps; + sc->wi_naps = naps; + /* Read Header */ + for(j=0; j < sizeof(ap2_header) / 2; j++) + ((u_int16_t *)&ap2_header)[j] = + CSR_READ_2(sc, WI_DATA1); + /* 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); + 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); + } + } else { /* Lucent chip */ + 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); + 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); + } + } + /* 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) ? @@ -472,7 +566,8 @@ void wi_update_stats(sc) "disconnected", "AP change", "AP out of range", - "AP in range" + "AP in range", + "Association Faild" }; if (gen.wi_len != 2) { @@ -482,7 +577,7 @@ void wi_update_stats(sc) break; } t = CSR_READ_2(sc, WI_DATA1); - if ((t < 1) || (t > 5)) { + if ((t < 1) || (t > 6)) { #ifdef WI_DEBUG printf("WI_INFO_LINK_STAT: status %d\n", t); #endif @@ -1209,6 +1304,7 @@ wi_ioctl(ifp, command, data) caddr_t data; { int s, error = 0; + int len; struct wi_softc *sc = ifp->if_softc; struct wi_req wreq; struct ifreq *ifr; @@ -1281,10 +1377,24 @@ wi_ioctl(ifp, command, data) if (error) break; if (wreq.wi_type == WI_RID_IFACE_STATS) { + wi_update_stats(sc); /* XXX native byte order */ 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 = EINVAL; + 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)) @@ -1315,6 +1425,23 @@ wi_ioctl(ifp, command, data) } else if (wreq.wi_type == WI_RID_MGMT_XMIT) { error = wi_mgmt_xmit(sc, (caddr_t)&wreq.wi_val, wreq.wi_len); + } else if (wreq.wi_type == WI_RID_SCAN_APS) { + if (wreq.wi_len != 4) { + error = EINVAL; + break; + } + if (!sc->wi_scanning) { + if (sc->sc_prism2) { + wreq.wi_type = WI_RID_SCAN_REQ; + error = wi_write_record(sc, + (struct wi_ltv_gen *)&wreq); + } + if (!error) { + sc->wi_scanning = 1; + callout_reset(&sc->wi_scan_sh, hz * 1, + wi_wait_scan, sc); + } + } } else { if (sc->sc_enabled != 0) error = wi_write_record(sc, @@ -1484,6 +1611,10 @@ wi_init(ifp) /* Enable desired port */ wi_cmd(sc, WI_CMD_ENABLE | sc->wi_portnum, 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, 1518 + sizeof(struct wi_frame) + 8, &id)) != 0) { printf("%s: tx buffer allocation failed\n", @@ -1652,6 +1783,7 @@ wi_stop(ifp, disable) wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0); callout_stop(&sc->wi_inquire_ch); + callout_stop(&sc->wi_scan_sh); if (disable) { if (sc->sc_enabled) { diff --git a/sys/dev/ic/wi_ieee.h b/sys/dev/ic/wi_ieee.h index f7d269f2573..e26efb519d2 100644 --- a/sys/dev/ic/wi_ieee.h +++ b/sys/dev/ic/wi_ieee.h @@ -1,4 +1,4 @@ -/* $NetBSD: wi_ieee.h,v 1.8 2002/01/20 04:37:04 ichiro Exp $ */ +/* $NetBSD: wi_ieee.h,v 1.9 2002/01/21 11:28:18 ichiro Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -87,6 +87,9 @@ struct wi_req { #define WI_RID_ZERO_CACHE 0x0300 #define WI_RID_READ_CACHE 0x0400 #endif +#define WI_RID_MONITOR_MODE 0x0500 +#define WI_RID_SCAN_APS 0x0600 +#define WI_RID_READ_APS 0x0700 struct wi_80211_hdr { u_int16_t frame_ctl; @@ -181,20 +184,6 @@ struct wi_counters { }; /* - * These are all the LTV record types that we can read or write - * from the WaveLAN. Not all of them are temendously useful, but I - * list as many as I know about here for completeness. - */ -#define WI_SCAN_RESULTS_MAXLEN 512 -struct wi_scan_results { - int truncated; /* incomplete data in result */ - u_int scanning; /* in hz units */ - struct timeval lastscan; /* time scan was completed */ - u_int16_t len; /* number of words */ - u_int16_t scan_results[WI_SCAN_RESULTS_MAXLEN]; -}; - -/* * Network parameters, static configuration entities. */ #define WI_RID_PORTTYPE 0xFC00 /* Connection control characteristics */ @@ -338,12 +327,26 @@ struct wi_ltv_keys { /* * Scan Information */ -#define WI_RID_SCAN_REQ 0xFCE1 -#define WI_RID_JOIN_REQ 0xFCE2 +#define WI_RID_SCAN_REQ 0xFCE1 /* Scan request (STA only) */ +#define WI_RID_JOIN_REQ 0xFCE2 /* Join request (STA only) */ #define WI_RID_AUTH_STATION 0xFCE3 /* Authenticates Station (AP) */ #define WI_RID_CHANNEL_REQ 0xFCE4 /* Channel Information Request (AP) */ #define WI_RID_SCAN_RESULTS 0xFD88 /* Scan Results Table */ +struct wi_apinfo { + int scanreason; /* ScanReason */ + char bssid[6]; /* BSSID (mac address) */ + int channel; /* Channel */ + int signal; /* Signal level */ + int noise; /* Average Noise Level*/ + int quality; /* Quality */ + int namelen; /* Length of SSID string */ + char name[32]; /* SSID string */ + int capinfo; /* Capability info. */ + int interval; /* BSS Beacon Interval */ + int rate; /* Data Rate */ +}; + /* * Modem information */ diff --git a/sys/dev/ic/wireg.h b/sys/dev/ic/wireg.h index 3e71cfb1cf5..d1bf0499db4 100644 --- a/sys/dev/ic/wireg.h +++ b/sys/dev/ic/wireg.h @@ -1,4 +1,4 @@ -/* $NetBSD: wireg.h,v 1.16 2002/01/20 06:49:32 ichiro Exp $ */ +/* $NetBSD: wireg.h,v 1.17 2002/01/21 11:28:18 ichiro Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -510,13 +510,59 @@ struct wi_ltv_mcast { */ #define WI_INFO_NOTIFY 0xF000 /* Handover address */ #define WI_INFO_COUNTERS 0xF100 /* Statistics counters */ -#define WI_INFO_SCAN_RESULTS 0xF101 /* Scan results */ +#define WI_INFO_SCAN_RESULTS 0xF101 /* Scan results table (STA only) */ #define WI_INFO_LINK_STAT 0xF200 /* Link status */ #define WI_INFO_ASSOC_STAT 0xF201 /* Association status */ #define WI_INFO_AUTH_REQUEST 0xF202 /* Authentication Request (AP) */ #define WI_INFO_POWERSAVE_COUNT 0xF203 /* PowerSave User Count (AP) */ /* + * Scan Results Table of Prism2 chip (STA only) + */ + +#define MAXAPINFO 30 +struct wi_scan_header { + u_int16_t wi_reserve; /* future use */ + u_int16_t wi_reason; /* The reason this scan was initiated + 1: Host initiated + 2: Firmware initiated + 3: Inquiry request from host */ +}; +struct wi_scan_data_p2 { + u_int16_t wi_chid; /* BSS Channel ID from Probe Res.(PR)*/ + u_int16_t wi_noise; /* Average Noise Level of the PR */ + u_int16_t wi_signal; /* Signal Level on the PR */ + u_int8_t wi_bssid[6]; /* MACaddress of BSS responder from PR */ + u_int16_t wi_interval; /* BSS beacon interval */ + u_int16_t wi_capinfo; /* BSS Capability Information + IEEE Std 802.11(1997) ,see 7.3.1.4 */ + u_int16_t wi_namelen; /* Length of SSID strings */ + u_int8_t wi_name[32]; /* SSID strings */ + u_int16_t wi_suprate[5]; /* Supported Rates element from the PR + IEEE Std 802.11(1997) ,see 7.3.2.2 */ + u_int16_t wi_rate; /* Data rate of the PR */ +#define WI_APRATE_1 0x0A /* 1 Mbps */ +#define WI_APRATE_2 0x14 /* 2 Mbps */ +#define WI_APRATE_5 0x37 /* 5.5 Mbps */ +#define WI_APRATE_11 0x6E /* 11 Mbps */ +}; + +/* + * Scan Results of Lucent chip + */ +struct wi_scan_data { + u_int16_t wi_chid; /* BSS Channel ID from PR */ + u_int16_t wi_noise; /* Average Noise Level of the PR */ + u_int16_t wi_signal; /* Signal Level on the PR */ + u_int8_t wi_bssid[6]; /* MACaddress of BSS responder from PR */ + u_int16_t wi_interval; /* BSS beacon interval */ + u_int16_t wi_capinfo; /* BSS Capability Information + IEEE Std 802.11(1997) ,see 7.3.1.4 */ + u_int16_t wi_namelen; /* Length of SSID strings */ + u_int8_t wi_name[32]; /* SSID strings */ +}; + +/* * Hermes transmit/receive frame structure */ struct wi_frame { diff --git a/sys/dev/ic/wivar.h b/sys/dev/ic/wivar.h index f769aabdbf1..1cbf04819de 100644 --- a/sys/dev/ic/wivar.h +++ b/sys/dev/ic/wivar.h @@ -1,4 +1,4 @@ -/* $NetBSD: wivar.h,v 1.7 2002/01/05 20:10:53 explorer Exp $ */ +/* $NetBSD: wivar.h,v 1.8 2002/01/21 11:28:18 ichiro Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -50,12 +50,13 @@ struct wi_softc { int sc_enabled; int sc_prism2; int sc_prism2_ver; - int sc_pci; /* attach to PCI-Bus */ + 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; u_int8_t sc_macaddr[ETHER_ADDR_LEN]; @@ -87,6 +88,10 @@ struct wi_softc { int wi_tx_key; struct wi_ltv_keys wi_keys; struct wi_counters wi_stats; + + struct wi_apinfo wi_aps[MAXAPINFO]; + int wi_naps; + int wi_scanning; /* scan mode */ }; int wi_attach __P((struct wi_softc *)); |
