summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorichiro <ichiro@NetBSD.org>2002-01-21 11:28:18 +0000
committerichiro <ichiro@NetBSD.org>2002-01-21 11:28:18 +0000
commite08ec84292300798104ecdb0dc53bfa94e983dad (patch)
tree4fc90f3c6704be985bb36622d98e4d3a76fafce9 /sys/dev/ic
parent0d1261454ee9fa87f9514a3656e9dbeacefd5d38 (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.c142
-rw-r--r--sys/dev/ic/wi_ieee.h37
-rw-r--r--sys/dev/ic/wireg.h50
-rw-r--r--sys/dev/ic/wivar.h9
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 *));