"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
This commit is contained in:
ichiro 2002-01-21 11:28:18 +00:00
parent 0d1261454e
commit e08ec84292
4 changed files with 212 additions and 26 deletions

View File

@ -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) {

View File

@ -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;
@ -180,20 +183,6 @@ struct wi_counters {
u_int32_t wi_rx_msg_in_bad_msg_frags;
};
/*
* 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.
*/
@ -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
*/

View File

@ -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,12 +510,58 @@ 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
*/

View File

@ -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 *));