summaryrefslogtreecommitdiffstats
path: root/sys/dev/awi
diff options
context:
space:
mode:
authoronoe <onoe@FreeBSD.org>2000-08-14 13:42:38 +0000
committeronoe <onoe@FreeBSD.org>2000-08-14 13:42:38 +0000
commit258831b31a1185142cc4135b4bbb3bfbccd0d412 (patch)
treef23e4e90f595ab944f3dcc3edad784b5a67d3cf8 /sys/dev/awi
parent77028f59a2a253235465d97fdf2390830af2c19d (diff)
downloadFreeBSD-src-258831b31a1185142cc4135b4bbb3bfbccd0d412.zip
FreeBSD-src-258831b31a1185142cc4135b4bbb3bfbccd0d412.tar.gz
Add support for WEP functionality.
Add support for wi(4) compatible configuration interface. It enables wicontrol(8) to configure some 802.11 specific parameters. Some minor fixes from NetBSD. Obtained from: NetBSD current
Diffstat (limited to 'sys/dev/awi')
-rw-r--r--sys/dev/awi/awi.c792
-rw-r--r--sys/dev/awi/awi_wep.c530
-rw-r--r--sys/dev/awi/awi_wicfg.c627
-rw-r--r--sys/dev/awi/awivar.h49
4 files changed, 1629 insertions, 369 deletions
diff --git a/sys/dev/awi/awi.c b/sys/dev/awi/awi.c
index 65783c6..5e4ab1f 100644
--- a/sys/dev/awi/awi.c
+++ b/sys/dev/awi/awi.c
@@ -1,12 +1,12 @@
-/* $NetBSD: awi.c,v 1.12 2000/03/23 05:26:00 mycroft Exp $ */
+/* $NetBSD: awi.c,v 1.26 2000/07/21 04:48:55 onoe Exp $ */
/* $FreeBSD$ */
-/*
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Atsushi Onoe.
+ * by Bill Sommerfeld
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -18,8 +18,8 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
@@ -36,35 +36,64 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
+/*
+ * Driver for AMD 802.11 firmware.
+ * Uses am79c930 chip driver to talk to firmware running on the am79c930.
+ *
+ * More-or-less a generic ethernet-like if driver, with 802.11 gorp added.
+ */
+
+/*
+ * todo:
+ * - flush tx queue on resynch.
+ * - clear oactive on "down".
+ * - rewrite copy-into-mbuf code
+ * - mgmt state machine gets stuck retransmitting assoc requests.
+ * - multicast filter.
+ * - fix device reset so it's more likely to work
+ * - show status goo through ifmedia.
+ *
+ * more todo:
+ * - deal with more 802.11 frames.
+ * - send reassoc request
+ * - deal with reassoc response
+ * - send/deal with disassociation
+ * - deal with "full" access points (no room for me).
+ * - power save mode
+ *
+ * later:
+ * - SSID preferences
+ * - need ioctls for poking at the MIBs
+ * - implement ad-hoc mode (including bss creation).
+ * - decide when to do "ad hoc" vs. infrastructure mode (IFF_LINK flags?)
+ * (focus on inf. mode since that will be needed for ietf)
+ * - deal with DH vs. FH versions of the card
+ * - deal with faster cards (2mb/s)
+ * - ?WEP goo (mmm, rc4) (it looks not particularly useful).
+ * - ifmedia revision.
+ * - common 802.11 mibish things.
+ * - common 802.11 media layer.
+ */
/*
* Driver for AMD 802.11 PCnetMobile firmware.
* Uses am79c930 chip driver to talk to firmware running on the am79c930.
*
- * The awi device driver first appeared in NetBSD 1.5.
- *
* The initial version of the driver was written by
* Bill Sommerfeld <sommerfeld@netbsd.org>.
* Then the driver module completely rewritten to support cards with DS phy
* and to support adhoc mode by Atsushi Onoe <onoe@netbsd.org>
*/
-#ifdef __NetBSD__
-#include "opt_inet.h"
-#include "opt_ns.h"
-#include "bpfilter.h"
-#include "rnd.h"
-#endif
-#ifdef __FreeBSD__
-#if __FreeBSD__ >= 3
#include "opt_inet.h"
-#endif
-#if __FreeBSD__ >= 4
+#if defined(__FreeBSD__) && __FreeBSD__ >= 4
#define NBPFILTER 1
+#elif defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include "bpf.h"
+#define NBPFILTER NBPF
#else
#include "bpfilter.h"
#endif
-#endif
#include <sys/param.h>
#include <sys/systm.h>
@@ -73,22 +102,14 @@
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/socket.h>
-#ifdef __FreeBSD__
#include <sys/sockio.h>
-#else
-#include <sys/ioctl.h>
-#endif
#include <sys/errno.h>
#include <sys/syslog.h>
-#include <sys/select.h>
#if defined(__FreeBSD__) && __FreeBSD__ >= 4
#include <sys/bus.h>
#else
#include <sys/device.h>
#endif
-#if NRND > 0
-#include <sys/rnd.h>
-#endif
#include <net/if.h>
#include <net/if_dl.h>
@@ -113,11 +134,6 @@
#endif
#endif
-#ifdef NS
-#include <netns/ns.h>
-#include <netns/ns_if.h>
-#endif
-
#if NBPFILTER > 0
#include <net/bpf.h>
#include <net/bpfdesc.h>
@@ -137,14 +153,12 @@
#include <dev/ic/am79c930var.h>
#include <dev/ic/awireg.h>
#include <dev/ic/awivar.h>
-#include <dev/ic/awictl.h>
#endif
#ifdef __FreeBSD__
#include <dev/awi/am79c930reg.h>
#include <dev/awi/am79c930var.h>
#include <dev/awi/awireg.h>
#include <dev/awi/awivar.h>
-#include <dev/awi/awictl.h>
#endif
static int awi_ioctl __P((struct ifnet *ifp, u_long cmd, caddr_t data));
@@ -154,10 +168,6 @@ static int awi_media_opt2rate __P((struct awi_softc *sc, int opt));
static int awi_media_change __P((struct ifnet *ifp));
static void awi_media_status __P((struct ifnet *ifp, struct ifmediareq *imr));
#endif
-static int awi_drvget __P((struct ifnet *ifp, u_long cmd, caddr_t data));
-static int awi_drvset __P((struct ifnet *ifp, u_long cmd, caddr_t data));
-static int awi_init __P((struct awi_softc *sc));
-static void awi_stop __P((struct awi_softc *sc));
static void awi_watchdog __P((struct ifnet *ifp));
static void awi_start __P((struct ifnet *ifp));
static void awi_txint __P((struct awi_softc *sc));
@@ -165,12 +175,11 @@ static struct mbuf * awi_fix_txhdr __P((struct awi_softc *sc, struct mbuf *m0));
static struct mbuf * awi_fix_rxhdr __P((struct awi_softc *sc, struct mbuf *m0));
static void awi_input __P((struct awi_softc *sc, struct mbuf *m, u_int32_t rxts, u_int8_t rssi));
static void awi_rxint __P((struct awi_softc *sc));
-struct mbuf * awi_devget __P((struct awi_softc *sc, u_int32_t off, u_int16_t len));
+static struct mbuf * awi_devget __P((struct awi_softc *sc, u_int32_t off, u_int16_t len));
static int awi_init_hw __P((struct awi_softc *sc));
static int awi_init_mibs __P((struct awi_softc *sc));
static int awi_init_txrx __P((struct awi_softc *sc));
static void awi_stop_txrx __P((struct awi_softc *sc));
-static int awi_init_region __P((struct awi_softc *sc));
static int awi_start_scan __P((struct awi_softc *sc));
static int awi_next_scan __P((struct awi_softc *sc));
static void awi_stop_scan __P((struct awi_softc *sc));
@@ -179,7 +188,7 @@ static int awi_set_ss __P((struct awi_softc *sc));
static void awi_try_sync __P((struct awi_softc *sc));
static void awi_sync_done __P((struct awi_softc *sc));
static void awi_send_deauth __P((struct awi_softc *sc));
-static void awi_send_auth __P((struct awi_softc *sc));
+static void awi_send_auth __P((struct awi_softc *sc, int seq));
static void awi_recv_auth __P((struct awi_softc *sc, struct mbuf *m0));
static void awi_send_asreq __P((struct awi_softc *sc, int reassoc));
static void awi_recv_asresp __P((struct awi_softc *sc, struct mbuf *m0));
@@ -193,9 +202,10 @@ static void awi_unlock __P((struct awi_softc *sc));
static int awi_intr_lock __P((struct awi_softc *sc));
static void awi_intr_unlock __P((struct awi_softc *sc));
static int awi_cmd_wait __P((struct awi_softc *sc));
+static void awi_print_essid __P((u_int8_t *essid));
#ifdef AWI_DEBUG
-static void awi_dump_pkt __P((struct awi_softc *sc, struct mbuf *m, u_int8_t rssi));
+static void awi_dump_pkt __P((struct awi_softc *sc, struct mbuf *m, int rssi));
int awi_verbose = 0;
int awi_dump = 0;
#define AWI_DUMP_MASK(fc0) (1 << (((fc0) & IEEE80211_FC0_SUBTYPE_MASK) >> 4))
@@ -227,7 +237,6 @@ int awi_dump_len = 28;
#endif
#ifdef __FreeBSD__
-
#if __FreeBSD__ >= 4
devclass_t awi_devclass;
#endif
@@ -251,17 +260,16 @@ awi_attach(sc)
struct awi_softc *sc;
{
struct ifnet *ifp = sc->sc_ifp;
+ int s;
+ int error;
#ifdef IFM_IEEE80211
int i;
u_int8_t *phy_rates;
int mword;
struct ifmediareq imr;
#endif
- int s;
- int error;
s = splnet();
-
/*
* Even if we can sleep in initialization state,
* all other processes (e.g. ifconfig) have to wait for
@@ -304,10 +312,12 @@ awi_attach(sc)
ETHER_ADDR_LEN);
#endif
- printf("%s: IEEE802.11 (%s %dMbps) address %s\n",
+ printf("%s: IEEE802.11 %s %dMbps (firmware %s)\n",
sc->sc_dev.dv_xname,
sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH ? "FH" : "DS",
- sc->sc_tx_rate / 10, ether_sprintf(sc->sc_mib_addr.aMAC_Address));
+ sc->sc_tx_rate / 10, sc->sc_banner);
+ printf("%s: address %s\n",
+ sc->sc_dev.dv_xname, ether_sprintf(sc->sc_mib_addr.aMAC_Address));
#ifdef __FreeBSD__
ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
#else
@@ -329,8 +339,9 @@ awi_attach(sc)
ifmedia_add(&sc->sc_media, mword, 0, NULL);
ifmedia_add(&sc->sc_media,
mword | IFM_IEEE80211_ADHOC, 0, NULL);
- ifmedia_add(&sc->sc_media,
- mword | IFM_IEEE80211_ADHOC | IFM_FLAG0, 0, NULL);
+ if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_FH)
+ ifmedia_add(&sc->sc_media,
+ mword | IFM_IEEE80211_ADHOC | IFM_FLAG0, 0, NULL);
}
awi_media_status(ifp, &imr);
ifmedia_set(&sc->sc_media, imr.ifm_active);
@@ -338,6 +349,9 @@ awi_attach(sc)
/* ready to accept ioctl */
awi_unlock(sc);
+
+ /* Attach is successful. */
+ sc->sc_attached = 1;
return 0;
}
@@ -349,6 +363,10 @@ awi_detach(sc)
struct ifnet *ifp = sc->sc_ifp;
int s;
+ /* Succeed if there is no work to do. */
+ if (!sc->sc_attached)
+ return (0);
+
s = splnet();
sc->sc_invalid = 1;
awi_stop(sc);
@@ -356,6 +374,8 @@ awi_detach(sc)
wakeup(sc);
(void)tsleep(sc, PWAIT, "awidet", 1);
}
+ if (sc->sc_wep_ctx != NULL)
+ free(sc->sc_wep_ctx, M_DEVBUF);
#if NBPFILTER > 0
bpfdetach(ifp);
#endif
@@ -389,34 +409,44 @@ awi_activate(self, act)
case DVACT_DEACTIVATE:
sc->sc_invalid = 1;
- if_deactivate(sc->sc_ifp);
+ if (sc->sc_ifp)
+ if_deactivate(sc->sc_ifp);
break;
}
splx(s);
return error;
}
-#endif /* __NetBSD__ */
void
-awi_reset(sc)
+awi_power(sc, why)
struct awi_softc *sc;
+ int why;
{
int s;
+ int ocansleep;
if (!sc->sc_enabled)
return;
+
s = splnet();
- sc->sc_invalid = 1;
- awi_stop(sc);
- if (sc->sc_disable)
- (*sc->sc_disable)(sc);
- sc->sc_enabled = 0;
- DELAY(1000);
- sc->sc_invalid = 0;
- (void)awi_init(sc);
+ ocansleep = sc->sc_cansleep;
+ sc->sc_cansleep = 0;
+#ifdef needtobefixed /*ONOE*/
+ if (why == PWR_RESUME) {
+ sc->sc_enabled = 0;
+ awi_init(sc);
+ (void)awi_intr(sc);
+ } else {
+ awi_stop(sc);
+ if (sc->sc_disable)
+ (*sc->sc_disable)(sc);
+ }
+#endif
+ sc->sc_cansleep = ocansleep;
splx(s);
}
+#endif /* __NetBSD__ */
static int
awi_ioctl(ifp, cmd, data)
@@ -428,8 +458,7 @@ awi_ioctl(ifp, cmd, data)
struct ifreq *ifr = (struct ifreq *)data;
struct ifaddr *ifa = (struct ifaddr *)data;
int s, error;
- size_t nwidlen;
- u_int8_t nwid[IEEE80211_NWID_LEN + 1];
+ struct ieee80211_nwid nwid;
u_int8_t *p;
s = splnet();
@@ -472,6 +501,9 @@ awi_ioctl(ifp, cmd, data)
ether_addmulti(ifr, &sc->sc_ec) :
ether_delmulti(ifr, &sc->sc_ec);
#endif
+ /*
+ * Do not rescan BSS. Rather, just reset multicast filter.
+ */
if (error == ENETRESET) {
if (sc->sc_enabled)
error = awi_init(sc);
@@ -486,22 +518,27 @@ awi_ioctl(ifp, cmd, data)
ifp->if_mtu = ifr->ifr_mtu;
break;
case SIOCS80211NWID:
- error = copyinstr(ifr->ifr_data, nwid, sizeof(nwid), &nwidlen);
+#ifdef __FreeBSD__
+ error = suser(curproc);
+ if (error)
+ break;
+#endif
+ error = copyin(ifr->ifr_data, &nwid, sizeof(nwid));
if (error)
break;
- nwidlen--; /* eliminate trailing '\0' */
- if (nwidlen > IEEE80211_NWID_LEN) {
+ if (nwid.i_len > IEEE80211_NWID_LEN) {
error = EINVAL;
break;
}
- if (sc->sc_mib_mac.aDesired_ESS_ID[1] == nwidlen &&
- memcmp(&sc->sc_mib_mac.aDesired_ESS_ID[2], nwid,
- nwidlen) == 0)
+ if (sc->sc_mib_mac.aDesired_ESS_ID[1] == nwid.i_len &&
+ memcmp(&sc->sc_mib_mac.aDesired_ESS_ID[2], nwid.i_nwid,
+ nwid.i_len) == 0)
break;
memset(sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
- sc->sc_mib_mac.aDesired_ESS_ID[1] = nwidlen;
- memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], nwid, nwidlen);
+ sc->sc_mib_mac.aDesired_ESS_ID[1] = nwid.i_len;
+ memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], nwid.i_nwid,
+ nwid.i_len);
if (sc->sc_enabled) {
awi_stop(sc);
error = awi_init(sc);
@@ -512,7 +549,18 @@ awi_ioctl(ifp, cmd, data)
p = sc->sc_bss.essid;
else
p = sc->sc_mib_mac.aDesired_ESS_ID;
- error = copyout(p + 2, ifr->ifr_data, IEEE80211_NWID_LEN);
+ error = copyout(p + 1, ifr->ifr_data, 1 + IEEE80211_NWID_LEN);
+ break;
+ case SIOCS80211NWKEY:
+#ifdef __FreeBSD__
+ error = suser(curproc);
+ if (error)
+ break;
+#endif
+ error = awi_wep_setnwkey(sc, (struct ieee80211_nwkey *)data);
+ break;
+ case SIOCG80211NWKEY:
+ error = awi_wep_getnwkey(sc, (struct ieee80211_nwkey *)data);
break;
#ifdef IFM_IEEE80211
case SIOCSIFMEDIA:
@@ -520,14 +568,8 @@ awi_ioctl(ifp, cmd, data)
error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
break;
#endif
- case SIOCGDRVSPEC:
- error = awi_drvget(ifp, cmd, data);
- break;
- case SIOCSDRVSPEC:
- error = awi_drvset(ifp, cmd, data);
- break;
default:
- error = EINVAL;
+ error = awi_wicfg(ifp, cmd, data);
break;
}
awi_unlock(sc);
@@ -640,7 +682,10 @@ awi_media_change(ifp)
}
if (ime->ifm_media & IFM_IEEE80211_ADHOC) {
sc->sc_mib_local.Network_Mode = 0;
- sc->sc_no_bssid = (ime->ifm_media & IFM_FLAG0) ? 1 : 0;
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
+ sc->sc_no_bssid = 0;
+ else
+ sc->sc_no_bssid = (ime->ifm_media & IFM_FLAG0) ? 1 : 0;
} else {
sc->sc_mib_local.Network_Mode = 1;
}
@@ -671,180 +716,6 @@ awi_media_status(ifp, imr)
}
#endif /* IFM_IEEE80211 */
-static int
-awi_drvget(ifp, cmd, data)
- struct ifnet *ifp;
- u_long cmd;
- caddr_t data;
-{
- struct awi_softc *sc = ifp->if_softc;
- struct ifdrv *ifd = (struct ifdrv *)data;
- u_int8_t buf[AWICTL_BUFSIZE];
- u_int8_t *essid;
- int error = 0;
-
- switch (ifd->ifd_cmd) {
- case AWICTL_REGION:
- if (ifd->ifd_len < 1)
- return ENOSPC;
- ifd->ifd_len = 1;
- buf[0] = sc->sc_mib_phy.aCurrent_Reg_Domain;
- break;
- case AWICTL_CHANSET:
- if (ifd->ifd_len < 3)
- return ENOSPC;
- ifd->ifd_len = 3;
- buf[0] = sc->sc_bss.chanset;
- buf[1] = sc->sc_scan_min;
- buf[2] = sc->sc_scan_max;
- break;
- case AWICTL_RAWBPF:
- if (ifd->ifd_len < 1)
- return ENOSPC;
- ifd->ifd_len = 1;
- buf[0] = sc->sc_rawbpf;
- break;
- case AWICTL_DESSID:
- case AWICTL_CESSID:
- if (ifd->ifd_cmd == AWICTL_DESSID)
- essid = sc->sc_mib_mac.aDesired_ESS_ID;
- else
- essid = sc->sc_bss.essid;
- if (ifd->ifd_len < essid[1])
- return ENOSPC;
- ifd->ifd_len = essid[1];
- if (ifd->ifd_len > 0)
- memcpy(buf, essid, ifd->ifd_len);
- break;
- case AWICTL_MODE:
- if (ifd->ifd_len < 1)
- return ENOSPC;
- ifd->ifd_len = 1;
- if (sc->sc_mib_local.Network_Mode == 0) {
- if (sc->sc_no_bssid)
- buf[0] = AWICTL_MODE_NOBSSID;
- else
- buf[0] = AWICTL_MODE_ADHOC;
- } else
- buf[0] = AWICTL_MODE_INFRA;
- break;
- default:
- error = EINVAL;
- break;
- }
- if (error == 0 && ifd->ifd_len > 0)
- error = copyout(ifd->ifd_data, buf, ifd->ifd_len);
- return error;
-}
-
-static int
-awi_drvset(ifp, cmd, data)
- struct ifnet *ifp;
- u_long cmd;
- caddr_t data;
-{
- struct awi_softc *sc = ifp->if_softc;
- struct ifdrv *ifd = (struct ifdrv *)data;
- u_int8_t buf[AWICTL_BUFSIZE];
- u_int8_t oregion;
- int error = 0;
-
- if (ifd->ifd_len > sizeof(buf))
- return EINVAL;
- error = copyin(ifd->ifd_data, buf, ifd->ifd_len);
- if (error)
- return error;
-
- switch (ifd->ifd_cmd) {
- case AWICTL_REGION:
- if (ifd->ifd_len != 1)
- return EINVAL;
- oregion = sc->sc_mib_phy.aCurrent_Reg_Domain;
- if (buf[0] == oregion)
- break;
- sc->sc_mib_phy.aCurrent_Reg_Domain = buf[0];
- error = awi_init_region(sc);
- if (error) {
- sc->sc_mib_phy.aCurrent_Reg_Domain = oregion;
- break;
- }
- if (sc->sc_enabled) {
- awi_stop(sc);
- error = awi_init(sc);
- }
- break;
- case AWICTL_CHANSET:
- if (ifd->ifd_len != 3)
- return EINVAL;
- /* reset scan min/max */
- awi_init_region(sc);
- if (buf[0] < sc->sc_scan_min || buf[0] > sc->sc_scan_max ||
- buf[1] < sc->sc_scan_min || buf[1] > sc->sc_scan_max ||
- buf[2] < sc->sc_scan_min || buf[2] > sc->sc_scan_max)
- return EINVAL;
- sc->sc_scan_cur = buf[0];
- sc->sc_scan_min = buf[1];
- sc->sc_scan_max = buf[2];
- if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
- sc->sc_scan_set = sc->sc_scan_cur % 3 + 1;
- if (sc->sc_enabled) {
- awi_stop(sc);
- error = awi_init(sc);
- }
- break;
- case AWICTL_RAWBPF:
- if (ifd->ifd_len != 1)
- return EINVAL;
- sc->sc_rawbpf = buf[0];
- break;
- case AWICTL_DESSID:
- if (ifd->ifd_len > IEEE80211_NWID_LEN)
- return EINVAL;
- if (sc->sc_mib_mac.aDesired_ESS_ID[1] == ifd->ifd_len &&
- memcmp(&sc->sc_mib_mac.aDesired_ESS_ID[2], buf,
- ifd->ifd_len) == 0)
- break;
- memset(sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
- sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
- sc->sc_mib_mac.aDesired_ESS_ID[1] = ifd->ifd_len;
- memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], buf, ifd->ifd_len);
- if (sc->sc_enabled) {
- awi_stop(sc);
- error = awi_init(sc);
- }
- break;
- case AWICTL_CESSID:
- error = EINVAL;
- break;
- case AWICTL_MODE:
- switch (buf[0]) {
- case AWICTL_MODE_INFRA:
- sc->sc_mib_local.Network_Mode = 1;
- sc->sc_no_bssid = 0;
- break;
- case AWICTL_MODE_ADHOC:
- sc->sc_mib_local.Network_Mode = 0;
- sc->sc_no_bssid = 0;
- break;
- case AWICTL_MODE_NOBSSID:
- sc->sc_mib_local.Network_Mode = 0;
- sc->sc_no_bssid = 1;
- break;
- default:
- return EINVAL;
- }
- if (sc->sc_enabled) {
- awi_stop(sc);
- error = awi_init(sc);
- }
- break;
- default:
- error = EINVAL;
- break;
- }
- return error;
-}
-
int
awi_intr(arg)
void *arg;
@@ -853,7 +724,7 @@ awi_intr(arg)
u_int16_t status;
int error, handled = 0, ocansleep;
- if (sc->sc_invalid)
+ if (!sc->sc_enabled || !sc->sc_enab_intr || sc->sc_invalid)
return 0;
am79c930_gcr_setbits(&sc->sc_chip,
@@ -896,7 +767,7 @@ awi_intr(arg)
return handled;
}
-static int
+int
awi_init(sc)
struct awi_softc *sc;
{
@@ -910,6 +781,7 @@ awi_init(sc)
struct ether_multistep step;
#endif
+ /* reinitialize muticast filter */
n = 0;
ifp->if_flags |= IFF_ALLMULTI;
sc->sc_mib_local.Accept_All_Multicast_Dis = 0;
@@ -918,7 +790,6 @@ awi_init(sc)
goto set_mib;
}
sc->sc_mib_mac.aPromiscuous_Enable = 0;
- ifp->if_flags &= ~IFF_ALLMULTI;
#ifdef __FreeBSD__
if (ifp->if_amcount != 0)
goto set_mib;
@@ -946,10 +817,15 @@ awi_init(sc)
ETHER_NEXT_MULTI(step, enm);
}
#endif
+ for (; n < AWI_GROUP_ADDR_SIZE; n++)
+ memset(sc->sc_mib_addr.aGroup_Addresses[n], 0, ETHER_ADDR_LEN);
ifp->if_flags &= ~IFF_ALLMULTI;
sc->sc_mib_local.Accept_All_Multicast_Dis = 1;
set_mib:
+#ifdef notdef /* allow non-encrypted frame for receiving. */
+ sc->sc_mib_mgt.Wep_Required = sc->sc_wep_algo != NULL ? 1 : 0;
+#endif
if (!sc->sc_enabled) {
sc->sc_enabled = 1;
if (sc->sc_enable)
@@ -982,7 +858,7 @@ awi_init(sc)
return error;
}
-static void
+void
awi_stop(sc)
struct awi_softc *sc;
{
@@ -1013,8 +889,10 @@ awi_stop(sc)
break;
m_freem(m);
}
- while ((bp = TAILQ_FIRST(&sc->sc_scan)) != NULL)
+ while ((bp = TAILQ_FIRST(&sc->sc_scan)) != NULL) {
TAILQ_REMOVE(&sc->sc_scan, bp, list);
+ free(bp, M_DEVBUF);
+ }
}
static void
@@ -1036,8 +914,12 @@ awi_watchdog(ifp)
awi_txint(sc);
}
if (sc->sc_rx_timer && --sc->sc_rx_timer == 0) {
- printf("%s: no recent beacons from %s; rescanning\n",
- sc->sc_dev.dv_xname, ether_sprintf(sc->sc_bss.bssid));
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf("%s: no recent beacons from %s; rescanning\n",
+ sc->sc_dev.dv_xname,
+ ether_sprintf(sc->sc_bss.bssid));
+ }
+ ifp->if_flags &= ~IFF_RUNNING;
awi_start_scan(sc);
}
if (sc->sc_mgt_timer && --sc->sc_mgt_timer == 0) {
@@ -1088,20 +970,32 @@ awi_start(ifp)
IF_DEQUEUE(&ifp->if_snd, m0);
if (m0 == NULL)
break;
- if (awi_next_txd(sc, m0->m_pkthdr.len +
- sizeof(struct ieee80211_frame), &frame, &ntxd)) {
+ len = m0->m_pkthdr.len + sizeof(struct ieee80211_frame);
+ if (sc->sc_format_llc)
+ len += sizeof(struct llc) -
+ sizeof(struct ether_header);
+ if (sc->sc_wep_algo != NULL)
+ len += IEEE80211_WEP_IVLEN +
+ IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
+ if (awi_next_txd(sc, len, &frame, &ntxd)) {
IF_PREPEND(&ifp->if_snd, m0);
ifp->if_flags |= IFF_OACTIVE;
break;
}
AWI_BPF_MTAP(sc, m0, AWI_BPF_NORM);
m0 = awi_fix_txhdr(sc, m0);
+ if (sc->sc_wep_algo != NULL && m0 != NULL)
+ m0 = awi_wep_encrypt(sc, m0, 1);
if (m0 == NULL) {
ifp->if_oerrors++;
continue;
}
ifp->if_opackets++;
}
+#ifdef AWI_DEBUG
+ if (awi_dump)
+ awi_dump_pkt(sc, m0, -1);
+#endif
AWI_BPF_MTAP(sc, m0, AWI_BPF_RAW);
len = 0;
for (m = m0; m != NULL; m = m->m_next) {
@@ -1249,6 +1143,57 @@ awi_fix_rxhdr(sc, m0)
/* assuming ethernet encapsulation, just strip 802.11 header */
m_adj(m0, sizeof(wh));
}
+ if (ALIGN(mtod(m0, caddr_t) + sizeof(struct ether_header)) !=
+ (u_int)(mtod(m0, caddr_t) + sizeof(struct ether_header))) {
+ /* XXX: we loose to estimate the type of encapsulation */
+ struct mbuf *n, *n0, **np;
+ caddr_t newdata;
+ int off;
+
+ n0 = NULL;
+ np = &n0;
+ off = 0;
+ while (m0->m_pkthdr.len > off) {
+ if (n0 == NULL) {
+ MGETHDR(n, M_DONTWAIT, MT_DATA);
+ if (n == NULL) {
+ m_freem(m0);
+ return NULL;
+ }
+ M_COPY_PKTHDR(n, m0);
+ n->m_len = MHLEN;
+ } else {
+ MGET(n, M_DONTWAIT, MT_DATA);
+ if (n == NULL) {
+ m_freem(m0);
+ m_freem(n0);
+ return NULL;
+ }
+ n->m_len = MLEN;
+ }
+ if (m0->m_pkthdr.len - off >= MINCLSIZE) {
+ MCLGET(n, M_DONTWAIT);
+ if (n->m_flags & M_EXT)
+ n->m_len = n->m_ext.ext_size;
+ }
+ if (n0 == NULL) {
+ newdata = (caddr_t)
+ ALIGN(n->m_data
+ + sizeof(struct ether_header))
+ - sizeof(struct ether_header);
+ n->m_len -= newdata - n->m_data;
+ n->m_data = newdata;
+ }
+ if (n->m_len > m0->m_pkthdr.len - off)
+ n->m_len = m0->m_pkthdr.len - off;
+ m_copydata(m0, off, n->m_len, mtod(n, caddr_t));
+ off += n->m_len;
+ *np = n;
+ np = &n->m_next;
+ }
+ m_freem(m0);
+ m0 = n0;
+ }
return m0;
}
@@ -1265,6 +1210,8 @@ awi_input(sc, m, rxts, rssi)
struct ether_header *eh;
#endif
+ /* trim CRC here for WEP can find its own CRC at the end of packet. */
+ m_adj(m, -ETHER_CRC_LEN);
AWI_BPF_MTAP(sc, m, AWI_BPF_RAW);
wh = mtod(m, struct ieee80211_frame *);
if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
@@ -1272,8 +1219,17 @@ awi_input(sc, m, rxts, rssi)
printf("%s; receive packet with wrong version: %x\n",
sc->sc_dev.dv_xname, wh->i_fc[0]);
m_freem(m);
+ ifp->if_ierrors++;
return;
}
+ if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ m = awi_wep_encrypt(sc, m, 0);
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ return;
+ }
+ wh = mtod(m, struct ieee80211_frame *);
+ }
#ifdef AWI_DEBUG
if (awi_dump)
awi_dump_pkt(sc, m, rssi);
@@ -1307,16 +1263,14 @@ awi_input(sc, m, rxts, rssi)
break;
}
ifp->if_ipackets++;
-#ifndef __FreeBSD__
+#if !(defined(__FreeBSD__) && __FreeBSD__ >= 4)
AWI_BPF_MTAP(sc, m, AWI_BPF_NORM);
#endif
#ifdef __NetBSD__
- m->m_flags |= M_HASFCS;
(*ifp->if_input)(ifp, m);
#else
eh = mtod(m, struct ether_header *);
m_adj(m, sizeof(*eh));
- m_adj(m, -ETHER_CRC_LEN);
ether_input(ifp, eh, m);
#endif
break;
@@ -1340,7 +1294,7 @@ awi_input(sc, m, rxts, rssi)
break;
case IEEE80211_FC0_SUBTYPE_DEAUTH:
if (sc->sc_mib_local.Network_Mode)
- awi_send_auth(sc);
+ awi_send_auth(sc, 1);
break;
case IEEE80211_FC0_SUBTYPE_DISASSOC:
if (sc->sc_mib_local.Network_Mode)
@@ -1402,17 +1356,18 @@ awi_rxint(sc)
sc->sc_rxdoff = rxoff;
}
-struct mbuf *
+static struct mbuf *
awi_devget(sc, off, len)
struct awi_softc *sc;
u_int32_t off;
u_int16_t len;
{
struct mbuf *m;
- struct mbuf *top, **mp = &top;
+ struct mbuf *top, **mp;
u_int tlen;
top = sc->sc_rxpend;
+ mp = &top;
if (top != NULL) {
sc->sc_rxpend = NULL;
top->m_pkthdr.len += len;
@@ -1456,6 +1411,15 @@ awi_devget(sc, off, len)
if (m->m_flags & M_EXT)
m->m_len = m->m_ext.ext_size;
}
+ if (top == NULL) {
+ int hdrlen = sizeof(struct ieee80211_frame) +
+ (sc->sc_format_llc ? sizeof(struct llc) :
+ sizeof(struct ether_header));
+ caddr_t newdata = (caddr_t)
+ ALIGN(m->m_data + hdrlen) - hdrlen;
+ m->m_len -= newdata - m->m_data;
+ m->m_data = newdata;
+ }
if (m->m_len > len)
m->m_len = len;
awi_read_bytes(sc, off, mtod(m, u_int8_t *), m->m_len);
@@ -1479,14 +1443,17 @@ awi_init_hw(sc)
u_int8_t status;
u_int16_t intmask;
int i, error;
- u_int8_t banner[AWI_BANNER_LEN];
+ sc->sc_enab_intr = 0;
+ sc->sc_invalid = 0; /* XXX: really? */
awi_drvstate(sc, AWI_DRV_RESET);
/* reset firmware */
am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_CORESET);
DELAY(100);
awi_write_1(sc, AWI_SELFTEST, 0);
+ awi_write_1(sc, AWI_CMD, 0);
+ awi_write_1(sc, AWI_BANNER, 0);
am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_CORESET);
DELAY(100);
@@ -1515,17 +1482,18 @@ awi_init_hw(sc)
}
/* check banner to confirm firmware write it */
- awi_read_bytes(sc, AWI_BANNER, banner, AWI_BANNER_LEN);
- if (memcmp(banner, "PCnetMobile:", 12) != 0) {
+ awi_read_bytes(sc, AWI_BANNER, sc->sc_banner, AWI_BANNER_LEN);
+ if (memcmp(sc->sc_banner, "PCnetMobile:", 12) != 0) {
printf("%s: failed to complete selftest (bad banner)\n",
sc->sc_dev.dv_xname);
for (i = 0; i < AWI_BANNER_LEN; i++)
- printf("%s%02x", i ? ":" : "\t", banner[i]);
+ printf("%s%02x", i ? ":" : "\t", sc->sc_banner[i]);
printf("\n");
return ENXIO;
}
/* initializing interrupt */
+ sc->sc_enab_intr = 1;
error = awi_intr_lock(sc);
if (error)
return error;
@@ -1542,7 +1510,9 @@ awi_init_hw(sc)
error = awi_cmd(sc, AWI_CMD_NOP);
if (error) {
printf("%s: failed to complete selftest", sc->sc_dev.dv_xname);
- if (error != EWOULDBLOCK)
+ if (error == ENXIO)
+ printf(" (no hardware)\n");
+ else if (error != EWOULDBLOCK)
printf(" (error %d)\n", error);
else if (sc->sc_cansleep)
printf(" (lost interrupt)\n");
@@ -1586,6 +1556,7 @@ awi_init_mibs(sc)
sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
sc->sc_mib_local.Fragmentation_Dis = 1;
sc->sc_mib_local.Accept_All_Multicast_Dis = 1;
+ sc->sc_mib_local.Power_Saving_Mode_Dis = 1;
/* allocate buffers */
sc->sc_txbase = AWI_BUFFERS;
@@ -1650,16 +1621,21 @@ awi_stop_txrx(sc)
struct awi_softc *sc;
{
+ if (sc->sc_cmd_inprog)
+ (void)awi_cmd_wait(sc);
(void)awi_cmd(sc, AWI_CMD_KILL_RX);
+ (void)awi_cmd_wait(sc);
+ sc->sc_cmd_inprog = AWI_CMD_FLUSH_TX;
awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_DATA, 1);
awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_MGT, 0);
awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_BCAST, 0);
awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_PS, 0);
awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_CF, 0);
(void)awi_cmd(sc, AWI_CMD_FLUSH_TX);
+ (void)awi_cmd_wait(sc);
}
-static int
+int
awi_init_region(sc)
struct awi_softc *sc;
{
@@ -1687,7 +1663,6 @@ awi_init_region(sc)
default:
return EINVAL;
}
- sc->sc_scan_cur = sc->sc_scan_min;
sc->sc_scan_set = sc->sc_scan_cur % 3 + 1;
} else {
switch (sc->sc_mib_phy.aCurrent_Reg_Domain) {
@@ -1721,6 +1696,7 @@ awi_init_region(sc)
return EINVAL;
}
}
+ sc->sc_ownch = sc->sc_scan_cur;
return 0;
}
@@ -1729,19 +1705,22 @@ awi_start_scan(sc)
struct awi_softc *sc;
{
int error = 0;
+ struct awi_bss *bp;
+ while ((bp = TAILQ_FIRST(&sc->sc_scan)) != NULL) {
+ TAILQ_REMOVE(&sc->sc_scan, bp, list);
+ free(bp, M_DEVBUF);
+ }
if (!sc->sc_mib_local.Network_Mode && sc->sc_no_bssid) {
memset(&sc->sc_bss, 0, sizeof(sc->sc_bss));
- sc->sc_bss.rxtime = 0;
- memcpy(sc->sc_bss.essid, &sc->sc_mib_mac.aDesired_ESS_ID,
- sizeof(sc->sc_bss.essid));
+ sc->sc_bss.essid[0] = IEEE80211_ELEMID_SSID;
if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
- sc->sc_bss.chanset = sc->sc_scan_set;
- sc->sc_bss.pattern = sc->sc_scan_cur;
+ sc->sc_bss.chanset = sc->sc_ownch % 3 + 1;
+ sc->sc_bss.pattern = sc->sc_ownch;
sc->sc_bss.index = 1;
- sc->sc_bss.dwell_time = 19; /*XXX*/
+ sc->sc_bss.dwell_time = 200; /*XXX*/
} else
- sc->sc_bss.chanset = sc->sc_scan_cur;
+ sc->sc_bss.chanset = sc->sc_ownch;
sc->sc_status = AWI_ST_SETSS;
error = awi_set_ss(sc);
} else {
@@ -1778,7 +1757,7 @@ awi_next_scan(sc)
if (sc->sc_scan_cur > sc->sc_scan_max) {
sc->sc_scan_cur = sc->sc_scan_min;
if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
- sc->sc_scan_set = (sc->sc_scan_set + 1) % 3;
+ sc->sc_scan_set = sc->sc_scan_set % 3 + 1;
}
error = awi_cmd_scan(sc);
if (error != EINVAL)
@@ -1793,6 +1772,7 @@ awi_stop_scan(sc)
{
struct ifnet *ifp = sc->sc_ifp;
struct awi_bss *bp, *sbp;
+ int fail;
bp = TAILQ_FIRST(&sc->sc_scan);
if (bp == NULL) {
@@ -1809,6 +1789,9 @@ awi_stop_scan(sc)
return;
}
sbp = NULL;
+ if (ifp->if_flags & IFF_DEBUG)
+ printf("%s:\tmacaddr ch/pat sig flag wep essid\n",
+ sc->sc_dev.dv_xname);
for (; bp != NULL; bp = TAILQ_NEXT(bp, list)) {
if (bp->fails) {
/*
@@ -1816,14 +1799,11 @@ awi_stop_scan(sc)
* during my scan. So we retries to associate with
* it unless there are any suitable AP.
*/
- if (bp->fails < 3)
+ if (bp->fails++ < 3)
continue;
bp->fails = 0;
}
- if (sc->sc_mib_mac.aDesired_ESS_ID[1] != 0 &&
- memcmp(&sc->sc_mib_mac.aDesired_ESS_ID, bp->essid,
- sizeof(bp->essid) != 0))
- continue;
+ fail = 0;
/*
* Since the firmware apparently scans not only the specified
* channel of SCAN command but all available channel within
@@ -1832,14 +1812,58 @@ awi_stop_scan(sc)
if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
if (bp->pattern < sc->sc_scan_min ||
bp->pattern > sc->sc_scan_max)
- continue;
+ fail |= 0x01;
} else {
if (bp->chanset < sc->sc_scan_min ||
bp->chanset > sc->sc_scan_max)
- continue;
+ fail |= 0x01;
+ }
+ if (sc->sc_mib_local.Network_Mode) {
+ if (!(bp->capinfo & IEEE80211_CAPINFO_ESS) ||
+ (bp->capinfo & IEEE80211_CAPINFO_IBSS))
+ fail |= 0x02;
+ } else {
+ if ((bp->capinfo & IEEE80211_CAPINFO_ESS) ||
+ !(bp->capinfo & IEEE80211_CAPINFO_IBSS))
+ fail |= 0x02;
+ }
+ if (sc->sc_wep_algo == NULL) {
+ if (bp->capinfo & IEEE80211_CAPINFO_PRIVACY)
+ fail |= 0x04;
+ } else {
+ if (!(bp->capinfo & IEEE80211_CAPINFO_PRIVACY))
+ fail |= 0x04;
+ }
+ if (sc->sc_mib_mac.aDesired_ESS_ID[1] != 0 &&
+ memcmp(&sc->sc_mib_mac.aDesired_ESS_ID, bp->essid,
+ sizeof(bp->essid)) != 0)
+ fail |= 0x08;
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf(" %c %s", fail ? '-' : '+',
+ ether_sprintf(bp->esrc));
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
+ printf(" %2d/%d%c", bp->pattern, bp->chanset,
+ fail & 0x01 ? '!' : ' ');
+ else
+ printf(" %4d%c", bp->chanset,
+ fail & 0x01 ? '!' : ' ');
+ printf(" %+4d", bp->rssi);
+ printf(" %4s%c",
+ (bp->capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
+ (bp->capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
+ "????",
+ fail & 0x02 ? '!' : ' ');
+ printf(" %3s%c ",
+ (bp->capinfo & IEEE80211_CAPINFO_PRIVACY) ? "wep" :
+ "no",
+ fail & 0x04 ? '!' : ' ');
+ awi_print_essid(bp->essid);
+ printf("%s\n", fail & 0x08 ? "!" : "");
+ }
+ if (!fail) {
+ if (sbp == NULL || bp->rssi > sbp->rssi)
+ sbp = bp;
}
- if (sbp == NULL || bp->rssi > sbp->rssi)
- sbp = bp;
}
if (sbp == NULL)
goto notfound;
@@ -1857,8 +1881,7 @@ awi_recv_beacon(sc, m0, rxts, rssi)
struct ieee80211_frame *wh;
struct awi_bss *bp;
u_int8_t *frame, *eframe;
- u_int8_t *tstamp, *capinfo, *ssid, *rates, *parms;
- u_int16_t bintval;
+ u_int8_t *tstamp, *bintval, *capinfo, *ssid, *rates, *parms;
if (sc->sc_status != AWI_ST_SCAN)
return;
@@ -1885,31 +1908,11 @@ awi_recv_beacon(sc, m0, rxts, rssi)
}
tstamp = frame;
frame += 8;
- bintval = LE_READ_2(frame);
+ bintval = frame;
frame += 2;
capinfo = frame;
frame += 2;
- if (sc->sc_mib_local.Network_Mode) {
- if (!(capinfo[0] & IEEE80211_CAPINFO_ESS) ||
- (capinfo[0] & IEEE80211_CAPINFO_IBSS)) {
-#ifdef AWI_DEBUG
- if (awi_verbose)
- printf("awi_recv_beacon: non ESS \n");
-#endif
- return;
- }
- } else {
- if ((capinfo[0] & IEEE80211_CAPINFO_ESS) ||
- !(capinfo[0] & IEEE80211_CAPINFO_IBSS)) {
-#ifdef AWI_DEBUG
- if (awi_verbose)
- printf("awi_recv_beacon: non IBSS \n");
-#endif
- return;
- }
- }
-
ssid = rates = parms = NULL;
while (frame < eframe) {
switch (*frame) {
@@ -1962,7 +1965,8 @@ awi_recv_beacon(sc, m0, rxts, rssi)
bp->rssi = rssi;
bp->rxtime = rxts;
memcpy(bp->timestamp, tstamp, sizeof(bp->timestamp));
- bp->interval = bintval;
+ bp->interval = LE_READ_2(bintval);
+ bp->capinfo = LE_READ_2(capinfo);
if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
bp->chanset = parms[4];
bp->pattern = parms[5];
@@ -1989,10 +1993,12 @@ awi_set_ss(sc)
sc->sc_status = AWI_ST_SETSS;
bp = &sc->sc_bss;
if (ifp->if_flags & IFF_DEBUG) {
- printf("%s: ch %d pat %d id %d dw %d iv %d bss %s ssid \"%s\"\n",
+ printf("%s: ch %d pat %d id %d dw %d iv %d bss %s ssid ",
sc->sc_dev.dv_xname, bp->chanset,
bp->pattern, bp->index, bp->dwell_time, bp->interval,
- ether_sprintf(bp->bssid), bp->essid + 2);
+ ether_sprintf(bp->bssid));
+ awi_print_essid(bp->essid);
+ printf("\n");
}
memcpy(&sc->sc_mib_mgt.aCurrent_BSS_ID, bp->bssid, ETHER_ADDR_LEN);
memcpy(&sc->sc_mib_mgt.aCurrent_ESS_ID, bp->essid,
@@ -2015,7 +2021,7 @@ awi_try_sync(sc)
if (awi_cmd_wait(sc))
return;
}
- sc->sc_cmd_inprog = 1;
+ sc->sc_cmd_inprog = AWI_CMD_SYNC;
awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_SET, bp->chanset);
awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_PATTERN, bp->pattern);
awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_IDX, bp->index);
@@ -2037,11 +2043,23 @@ awi_sync_done(sc)
if (sc->sc_mib_local.Network_Mode) {
awi_drvstate(sc, AWI_DRV_INFSY);
- awi_send_auth(sc);
+ awi_send_auth(sc, 1);
} else {
- printf("%s: synced with %s ssid \"%s\" at chanset %d\n",
- sc->sc_dev.dv_xname, ether_sprintf(sc->sc_bss.bssid),
- sc->sc_bss.essid + 2, sc->sc_bss.chanset);
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf("%s: synced with", sc->sc_dev.dv_xname);
+ if (sc->sc_no_bssid)
+ printf(" no-bssid");
+ else {
+ printf(" %s ssid ",
+ ether_sprintf(sc->sc_bss.bssid));
+ awi_print_essid(sc->sc_bss.essid);
+ }
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
+ printf(" at chanset %d pattern %d\n",
+ sc->sc_bss.chanset, sc->sc_bss.pattern);
+ else
+ printf(" at channel %d\n", sc->sc_bss.chanset);
+ }
awi_drvstate(sc, AWI_DRV_ADHSY);
sc->sc_status = AWI_ST_RUNNING;
ifp->if_flags |= IFF_RUNNING;
@@ -2086,8 +2104,9 @@ awi_send_deauth(sc)
}
static void
-awi_send_auth(sc)
+awi_send_auth(sc, seq)
struct awi_softc *sc;
+ int seq;
{
struct ifnet *ifp = sc->sc_ifp;
struct mbuf *m;
@@ -2108,7 +2127,7 @@ awi_send_auth(sc)
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
LE_WRITE_2(wh->i_dur, 0);
LE_WRITE_2(wh->i_seq, 0);
- memcpy(wh->i_addr1, sc->sc_bss.bssid, ETHER_ADDR_LEN);
+ memcpy(wh->i_addr1, sc->sc_bss.esrc, ETHER_ADDR_LEN);
memcpy(wh->i_addr2, sc->sc_mib_addr.aMAC_Address, ETHER_ADDR_LEN);
memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN);
@@ -2117,7 +2136,7 @@ awi_send_auth(sc)
LE_WRITE_2(auth, IEEE80211_AUTH_ALG_OPEN);
auth += 2;
/* sequence number */
- LE_WRITE_2(auth, 1);
+ LE_WRITE_2(auth, seq);
auth += 2;
/* status */
LE_WRITE_2(auth, 0);
@@ -2148,16 +2167,19 @@ awi_recv_auth(sc, m0)
printf("%s: receive auth from %s\n", sc->sc_dev.dv_xname,
ether_sprintf(wh->i_addr2));
+ /* algorithm number */
+ if (LE_READ_2(auth) != IEEE80211_AUTH_ALG_OPEN)
+ return;
+ auth += 2;
if (!sc->sc_mib_local.Network_Mode) {
- /* XXX: 802.11 allow auth for IBSS */
+ if (sc->sc_status != AWI_ST_RUNNING)
+ return;
+ if (LE_READ_2(auth) == 1)
+ awi_send_auth(sc, 2);
return;
}
if (sc->sc_status != AWI_ST_AUTH)
return;
- /* algorithm number */
- if (LE_READ_2(auth) != IEEE80211_AUTH_ALG_OPEN)
- return;
- auth += 2;
/* sequence number */
if (LE_READ_2(auth) != 2)
return;
@@ -2211,14 +2233,18 @@ awi_send_asreq(sc, reassoc)
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
LE_WRITE_2(wh->i_dur, 0);
LE_WRITE_2(wh->i_seq, 0);
- memcpy(wh->i_addr1, sc->sc_bss.bssid, ETHER_ADDR_LEN);
+ memcpy(wh->i_addr1, sc->sc_bss.esrc, ETHER_ADDR_LEN);
memcpy(wh->i_addr2, sc->sc_mib_addr.aMAC_Address, ETHER_ADDR_LEN);
memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN);
asreq = (u_int8_t *)&wh[1];
/* capability info */
- LE_WRITE_2(asreq, IEEE80211_CAPINFO_CF_POLLABLE);
+ if (sc->sc_wep_algo == NULL)
+ LE_WRITE_2(asreq, IEEE80211_CAPINFO_CF_POLLABLE);
+ else
+ LE_WRITE_2(asreq,
+ IEEE80211_CAPINFO_CF_POLLABLE | IEEE80211_CAPINFO_PRIVACY);
asreq += 2;
/* listen interval */
lintval = LE_READ_2(&sc->sc_mib_mgt.aListen_Interval);
@@ -2300,15 +2326,16 @@ awi_recv_asresp(sc, m0)
rate = AWI_80211_RATE(asresp[2 + i]);
}
}
- printf("%s: associated with %s ssid \"%s\"",
- sc->sc_dev.dv_xname, ether_sprintf(sc->sc_bss.bssid),
- sc->sc_bss.essid + 2);
- if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
- printf(" chanset %d pattern %d",
- sc->sc_bss.chanset, sc->sc_bss.pattern);
- else
- printf(" channel %d", sc->sc_bss.chanset);
- printf(" signal %d\n", sc->sc_bss.rssi);
+ if (sc->sc_ifp->if_flags & IFF_DEBUG) {
+ printf("%s: associated with %s ssid ",
+ sc->sc_dev.dv_xname, ether_sprintf(sc->sc_bss.bssid));
+ awi_print_essid(sc->sc_bss.essid);
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
+ printf(" chanset %d pattern %d\n",
+ sc->sc_bss.chanset, sc->sc_bss.pattern);
+ else
+ printf(" channel %d\n", sc->sc_bss.chanset);
+ }
sc->sc_tx_rate = rate;
sc->sc_mgt_timer = 0;
sc->sc_rx_timer = 10;
@@ -2316,8 +2343,6 @@ awi_recv_asresp(sc, m0)
sc->sc_status = AWI_ST_RUNNING;
sc->sc_ifp->if_flags |= IFF_RUNNING;
awi_drvstate(sc, AWI_DRV_INFASSOC);
- while ((bp = TAILQ_FIRST(&sc->sc_scan)) != NULL)
- TAILQ_REMOVE(&sc->sc_scan, bp, list);
awi_start(sc->sc_ifp);
}
@@ -2361,12 +2386,13 @@ awi_mib(sc, cmd, mib)
if (sc->sc_cmd_inprog) {
error = awi_cmd_wait(sc);
if (error) {
- printf("awi_mib: cmd %d inprog\n",
- awi_read_1(sc, AWI_CMD));
+ if (error == EWOULDBLOCK)
+ printf("awi_mib: cmd %d inprog",
+ sc->sc_cmd_inprog);
return error;
}
}
- sc->sc_cmd_inprog = 1;
+ sc->sc_cmd_inprog = cmd;
if (cmd == AWI_CMD_SET_MIB)
awi_write_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, ptr, size);
awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, mib);
@@ -2413,7 +2439,7 @@ awi_cmd_scan(sc)
if (error)
return error;
}
- sc->sc_cmd_inprog = 1;
+ sc->sc_cmd_inprog = AWI_CMD_SCAN;
awi_write_2(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_DURATION,
sc->sc_active_scan ? AWI_ASCAN_DURATION : AWI_PSCAN_DURATION);
if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
@@ -2440,7 +2466,7 @@ awi_cmd(sc, cmd)
u_int8_t status;
int error = 0;
- sc->sc_cmd_inprog = 1;
+ sc->sc_cmd_inprog = cmd;
awi_write_1(sc, AWI_CMD_STATUS, AWI_STAT_IDLE);
awi_write_1(sc, AWI_CMD, cmd);
if (sc->sc_status != AWI_ST_INIT)
@@ -2473,12 +2499,12 @@ awi_cmd_done(sc)
if (status == AWI_STAT_IDLE)
return; /* stray interrupt */
+ cmd = sc->sc_cmd_inprog;
sc->sc_cmd_inprog = 0;
if (sc->sc_status == AWI_ST_INIT) {
wakeup(sc);
return;
}
- cmd = awi_read_1(sc, AWI_CMD);
awi_write_1(sc, AWI_CMD, 0);
if (status != AWI_STAT_OK) {
@@ -2546,8 +2572,6 @@ awi_lock(sc)
{
int error = 0;
- if (sc->sc_invalid)
- return ENXIO;
if (curproc == NULL) {
/*
* XXX
@@ -2556,20 +2580,23 @@ awi_lock(sc)
* We simply abort the request if there are other
* ioctl requests in progress.
*/
- if (sc->sc_busy)
+ if (sc->sc_busy) {
return EWOULDBLOCK;
+ if (sc->sc_invalid)
+ return ENXIO;
+ }
sc->sc_busy = 1;
sc->sc_cansleep = 0;
return 0;
}
while (sc->sc_busy) {
+ if (sc->sc_invalid)
+ return ENXIO;
sc->sc_sleep_cnt++;
error = tsleep(sc, PWAIT | PCATCH, "awilck", 0);
sc->sc_sleep_cnt--;
if (error)
return error;
- if (sc->sc_invalid)
- return ENXIO;
}
sc->sc_busy = 1;
sc->sc_cansleep = 1;
@@ -2635,6 +2662,12 @@ awi_cmd_wait(sc)
while (sc->sc_cmd_inprog) {
if (sc->sc_invalid)
return ENXIO;
+ if (awi_read_1(sc, AWI_CMD) != sc->sc_cmd_inprog) {
+ printf("%s: failed to access hardware\n",
+ sc->sc_dev.dv_xname);
+ sc->sc_invalid = 1;
+ return ENXIO;
+ }
if (sc->sc_cansleep) {
sc->sc_sleep_cnt++;
error = tsleep(sc, PWAIT, "awicmd",
@@ -2656,12 +2689,39 @@ awi_cmd_wait(sc)
return error;
}
+static void
+awi_print_essid(essid)
+ u_int8_t *essid;
+{
+ int i, len;
+ u_int8_t *p;
+
+ len = essid[1];
+ if (len > IEEE80211_NWID_LEN)
+ len = IEEE80211_NWID_LEN; /*XXX*/
+ /* determine printable or not */
+ for (i = 0, p = essid + 2; i < len; i++, p++) {
+ if (*p < ' ' || *p > 0x7e)
+ break;
+ }
+ if (i == len) {
+ printf("\"");
+ for (i = 0, p = essid + 2; i < len; i++, p++)
+ printf("%c", *p);
+ printf("\"");
+ } else {
+ printf("0x");
+ for (i = 0, p = essid + 2; i < len; i++, p++)
+ printf("%02x", *p);
+ }
+}
+
#ifdef AWI_DEBUG
static void
awi_dump_pkt(sc, m, rssi)
struct awi_softc *sc;
struct mbuf *m;
- u_int8_t rssi;
+ int rssi;
{
struct ieee80211_frame *wh;
int i, l;
@@ -2678,24 +2738,28 @@ awi_dump_pkt(sc, m, rssi)
(wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)==IEEE80211_FC0_TYPE_DATA)
return;
+ if (rssi < 0)
+ printf("tx: ");
+ else
+ printf("rx: ");
switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
case IEEE80211_FC1_DIR_NODS:
- printf("rx: NODS %s", ether_sprintf(wh->i_addr2));
+ printf("NODS %s", ether_sprintf(wh->i_addr2));
printf("->%s", ether_sprintf(wh->i_addr1));
printf("(%s)", ether_sprintf(wh->i_addr3));
break;
case IEEE80211_FC1_DIR_TODS:
- printf("rx: TODS %s", ether_sprintf(wh->i_addr2));
+ printf("TODS %s", ether_sprintf(wh->i_addr2));
printf("->%s", ether_sprintf(wh->i_addr3));
printf("(%s)", ether_sprintf(wh->i_addr1));
break;
case IEEE80211_FC1_DIR_FROMDS:
- printf("rx: FRDS %s", ether_sprintf(wh->i_addr3));
+ printf("FRDS %s", ether_sprintf(wh->i_addr3));
printf("->%s", ether_sprintf(wh->i_addr1));
printf("(%s)", ether_sprintf(wh->i_addr2));
break;
case IEEE80211_FC1_DIR_DSTODS:
- printf("rx: DSDS %s", ether_sprintf((u_int8_t *)&wh[1]));
+ printf("DSDS %s", ether_sprintf((u_int8_t *)&wh[1]));
printf("->%s", ether_sprintf(wh->i_addr3));
printf("(%s", ether_sprintf(wh->i_addr2));
printf("->%s)", ether_sprintf(wh->i_addr1));
@@ -2748,7 +2812,11 @@ awi_dump_pkt(sc, m, rssi)
wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
break;
}
- printf(" +%d\n", rssi);
+ if (wh->i_fc[1] & IEEE80211_FC1_WEP)
+ printf(" WEP");
+ if (rssi >= 0)
+ printf(" +%d", rssi);
+ printf("\n");
if (awi_dump_len > 0) {
l = m->m_len;
if (l > awi_dump_len + sizeof(*wh))
diff --git a/sys/dev/awi/awi_wep.c b/sys/dev/awi/awi_wep.c
new file mode 100644
index 0000000..607eceb
--- /dev/null
+++ b/sys/dev/awi/awi_wep.c
@@ -0,0 +1,530 @@
+/* $NetBSD: awi_wep.c,v 1.4 2000/08/14 11:28:03 onoe Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Atsushi Onoe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * WEP support framework for the awi driver.
+ *
+ * No actual encryption capability is provided here, but any can be added
+ * to awi_wep_algo table below.
+ *
+ * Note that IEEE802.11 specification states WEP uses RC4 with 40bit key,
+ * which is a proprietary encryption algorithm available under license
+ * from RSA Data Security Inc. Using another algorithm, includes null
+ * encryption provided here, the awi driver cannot be able to communicate
+ * with other stations.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/sockio.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 4
+#include <sys/bus.h>
+#else
+#include <sys/device.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#ifdef __FreeBSD__
+#include <net/ethernet.h>
+#include <net/if_arp.h>
+#else
+#include <net/if_ether.h>
+#endif
+#include <net/if_media.h>
+#include <net/if_ieee80211.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#ifdef __FreeBSD__
+#include <machine/clock.h>
+#endif
+
+#ifdef __NetBSD__
+#include <dev/ic/am79c930reg.h>
+#include <dev/ic/am79c930var.h>
+#include <dev/ic/awireg.h>
+#include <dev/ic/awivar.h>
+
+#include <crypto/arc4/arc4.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <dev/awi/am79c930reg.h>
+#include <dev/awi/am79c930var.h>
+#include <dev/awi/awireg.h>
+#include <dev/awi/awivar.h>
+
+#include <crypto/rc4/rc4.h>
+static __inline int
+arc4_ctxlen(void)
+{
+ return sizeof(struct rc4_state);
+}
+
+static __inline void
+arc4_setkey(void *ctx, u_int8_t *key, int keylen)
+{
+ rc4_init(ctx, key, keylen);
+}
+
+static __inline void
+arc4_encrypt(void *ctx, u_int8_t *dst, u_int8_t *src, int len)
+{
+ rc4_crypt(ctx, src, dst, len);
+}
+#endif
+
+static void awi_crc_init __P((void));
+static u_int32_t awi_crc_update __P((u_int32_t crc, u_int8_t *buf, int len));
+
+static int awi_null_ctxlen __P((void));
+static void awi_null_setkey __P((void *ctx, u_int8_t *key, int keylen));
+static void awi_null_copy __P((void *ctx, u_int8_t *dst, u_int8_t *src, int len));
+
+/* XXX: the order should be known to wiconfig/user */
+
+static struct awi_wep_algo awi_wep_algo[] = {
+/* 0: no wep */
+ { "no" }, /* dummy for no wep */
+
+/* 1: normal wep (arc4) */
+ { "arc4", arc4_ctxlen, arc4_setkey,
+ arc4_encrypt, arc4_encrypt },
+
+/* 2: debug wep (null) */
+ { "null", awi_null_ctxlen, awi_null_setkey,
+ awi_null_copy, awi_null_copy },
+ /* dummy for wep without encryption */
+};
+
+int
+awi_wep_setnwkey(sc, nwkey)
+ struct awi_softc *sc;
+ struct ieee80211_nwkey *nwkey;
+{
+ int i, len, error;
+ u_int8_t keybuf[AWI_MAX_KEYLEN];
+
+ if (nwkey->i_defkid <= 0 ||
+ nwkey->i_defkid > IEEE80211_WEP_NKID)
+ return EINVAL;
+ error = 0;
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ if (nwkey->i_key[i].i_keydat == NULL)
+ continue;
+ len = nwkey->i_key[i].i_keylen;
+ if (len > sizeof(keybuf)) {
+ error = EINVAL;
+ break;
+ }
+ error = copyin(nwkey->i_key[i].i_keydat, keybuf, len);
+ if (error)
+ break;
+ error = awi_wep_setkey(sc, i, keybuf, len);
+ if (error)
+ break;
+ }
+ if (error == 0) {
+ sc->sc_wep_defkid = nwkey->i_defkid - 1;
+ error = awi_wep_setalgo(sc, nwkey->i_wepon);
+ if (error == 0 && sc->sc_enabled) {
+ awi_stop(sc);
+ error = awi_init(sc);
+ }
+ }
+ return error;
+}
+
+int
+awi_wep_getnwkey(sc, nwkey)
+ struct awi_softc *sc;
+ struct ieee80211_nwkey *nwkey;
+{
+ int i, len, error, suerr;
+ u_int8_t keybuf[AWI_MAX_KEYLEN];
+
+ nwkey->i_wepon = awi_wep_getalgo(sc);
+ nwkey->i_defkid = sc->sc_wep_defkid + 1;
+ /* do not show any keys to non-root user */
+#ifdef __FreeBSD__
+ suerr = suser(curproc);
+#else
+ suerr = suser(curproc->p_ucred, &curproc->p_acflag);
+#endif
+ error = 0;
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ if (nwkey->i_key[i].i_keydat == NULL)
+ continue;
+ if (suerr) {
+ error = suerr;
+ break;
+ }
+ len = sizeof(keybuf);
+ error = awi_wep_getkey(sc, i, keybuf, &len);
+ if (error)
+ break;
+ if (nwkey->i_key[i].i_keylen < len) {
+ error = ENOSPC;
+ break;
+ }
+ nwkey->i_key[i].i_keylen = len;
+ error = copyout(keybuf, nwkey->i_key[i].i_keydat, len);
+ if (error)
+ break;
+ }
+ return error;
+}
+
+int
+awi_wep_getalgo(sc)
+ struct awi_softc *sc;
+{
+
+ if (sc->sc_wep_algo == NULL)
+ return 0;
+ return sc->sc_wep_algo - awi_wep_algo;
+}
+
+int
+awi_wep_setalgo(sc, algo)
+ struct awi_softc *sc;
+ int algo;
+{
+ struct awi_wep_algo *awa;
+ int ctxlen;
+
+ awi_crc_init(); /* XXX: not belongs here */
+ if (algo < 0 || algo > sizeof(awi_wep_algo)/sizeof(awi_wep_algo[0]))
+ return EINVAL;
+ awa = &awi_wep_algo[algo];
+ if (awa->awa_name == NULL)
+ return EINVAL;
+ if (awa->awa_ctxlen == NULL) {
+ awa = NULL;
+ ctxlen = 0;
+ } else
+ ctxlen = awa->awa_ctxlen();
+ if (sc->sc_wep_ctx != NULL) {
+ free(sc->sc_wep_ctx, M_DEVBUF);
+ sc->sc_wep_ctx = NULL;
+ }
+ if (ctxlen) {
+ sc->sc_wep_ctx = malloc(ctxlen, M_DEVBUF, M_NOWAIT);
+ if (sc->sc_wep_ctx == NULL)
+ return ENOMEM;
+ }
+ sc->sc_wep_algo = awa;
+ return 0;
+}
+
+int
+awi_wep_setkey(sc, kid, key, keylen)
+ struct awi_softc *sc;
+ int kid;
+ unsigned char *key;
+ int keylen;
+{
+
+ if (kid < 0 || kid >= IEEE80211_WEP_NKID)
+ return EINVAL;
+ if (keylen < 0 || keylen + IEEE80211_WEP_IVLEN > AWI_MAX_KEYLEN)
+ return EINVAL;
+ sc->sc_wep_keylen[kid] = keylen;
+ if (keylen > 0)
+ memcpy(sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, key, keylen);
+ return 0;
+}
+
+int
+awi_wep_getkey(sc, kid, key, keylen)
+ struct awi_softc *sc;
+ int kid;
+ unsigned char *key;
+ int *keylen;
+{
+
+ if (kid < 0 || kid >= IEEE80211_WEP_NKID)
+ return EINVAL;
+ if (*keylen < sc->sc_wep_keylen[kid])
+ return ENOSPC;
+ *keylen = sc->sc_wep_keylen[kid];
+ if (*keylen > 0)
+ memcpy(key, sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, *keylen);
+ return 0;
+}
+
+struct mbuf *
+awi_wep_encrypt(sc, m0, txflag)
+ struct awi_softc *sc;
+ struct mbuf *m0;
+ int txflag;
+{
+ struct mbuf *m, *n, *n0;
+ struct ieee80211_frame *wh;
+ struct awi_wep_algo *awa;
+ int left, len, moff, noff, keylen, kid;
+ u_int32_t iv, crc;
+ u_int8_t *key, *ivp;
+ void *ctx;
+ u_int8_t crcbuf[IEEE80211_WEP_CRCLEN];
+
+ n0 = NULL;
+ awa = sc->sc_wep_algo;
+ if (awa == NULL)
+ goto fail;
+ ctx = sc->sc_wep_ctx;
+ m = m0;
+ left = m->m_pkthdr.len;
+ MGET(n, M_DONTWAIT, m->m_type);
+ n0 = n;
+ if (n == NULL)
+ goto fail;
+ M_COPY_PKTHDR(n, m);
+ len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
+ if (txflag) {
+ n->m_pkthdr.len += len;
+ } else {
+ n->m_pkthdr.len -= len;
+ left -= len;
+ }
+ n->m_len = MHLEN;
+ if (n->m_pkthdr.len >= MINCLSIZE) {
+ MCLGET(n, M_DONTWAIT);
+ if (n->m_flags & M_EXT)
+ n->m_len = n->m_ext.ext_size;
+ }
+ len = sizeof(struct ieee80211_frame);
+ memcpy(mtod(n, caddr_t), mtod(m, caddr_t), len);
+ left -= len;
+ moff = len;
+ noff = len;
+ if (txflag) {
+ kid = sc->sc_wep_defkid;
+ wh = mtod(n, struct ieee80211_frame *);
+ wh->i_fc[1] |= IEEE80211_FC1_WEP;
+ iv = random();
+ /*
+ * store IV, byte order is not the matter since it's random.
+ * assuming IEEE80211_WEP_IVLEN is 3
+ */
+ ivp = mtod(n, u_int8_t *) + noff;
+ ivp[0] = (iv >> 16) & 0xff;
+ ivp[1] = (iv >> 8) & 0xff;
+ ivp[2] = iv & 0xff;
+ ivp[3] = kid & 0x03; /* clear pad and keyid */
+ noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
+ } else {
+ ivp = mtod(m, u_int8_t *) + moff;
+ moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
+ kid = ivp[IEEE80211_WEP_IVLEN] & 0x03;
+ }
+ key = sc->sc_wep_key[kid];
+ keylen = sc->sc_wep_keylen[kid];
+ /* assuming IEEE80211_WEP_IVLEN is 3 */
+ key[0] = ivp[0];
+ key[1] = ivp[1];
+ key[2] = ivp[2];
+ awa->awa_setkey(ctx, key, IEEE80211_WEP_IVLEN + keylen);
+
+ /* encrypt with calculating CRC */
+ crc = ~0;
+ while (left > 0) {
+ len = m->m_len - moff;
+ if (len == 0) {
+ m = m->m_next;
+ moff = 0;
+ continue;
+ }
+ if (len > n->m_len - noff) {
+ len = n->m_len - noff;
+ if (len == 0) {
+ MGET(n->m_next, M_DONTWAIT, n->m_type);
+ if (n->m_next == NULL)
+ goto fail;
+ n = n->m_next;
+ n->m_len = MLEN;
+ if (left >= MINCLSIZE) {
+ MCLGET(n, M_DONTWAIT);
+ if (n->m_flags & M_EXT)
+ n->m_len = n->m_ext.ext_size;
+ }
+ noff = 0;
+ continue;
+ }
+ }
+ if (len > left)
+ len = left;
+ if (txflag) {
+ awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff,
+ mtod(m, caddr_t) + moff, len);
+ crc = awi_crc_update(crc, mtod(m, caddr_t) + moff, len);
+ } else {
+ awa->awa_decrypt(ctx, mtod(n, caddr_t) + noff,
+ mtod(m, caddr_t) + moff, len);
+ crc = awi_crc_update(crc, mtod(n, caddr_t) + noff, len);
+ }
+ left -= len;
+ moff += len;
+ noff += len;
+ }
+ crc = ~crc;
+ if (txflag) {
+ LE_WRITE_4(crcbuf, crc);
+ if (n->m_len >= noff + sizeof(crcbuf))
+ n->m_len = noff + sizeof(crcbuf);
+ else {
+ n->m_len = noff;
+ MGET(n->m_next, M_DONTWAIT, n->m_type);
+ if (n->m_next == NULL)
+ goto fail;
+ n = n->m_next;
+ n->m_len = sizeof(crcbuf);
+ noff = 0;
+ }
+ awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff, crcbuf,
+ sizeof(crcbuf));
+ } else {
+ n->m_len = noff;
+ for (noff = 0; noff < sizeof(crcbuf); noff += len) {
+ len = sizeof(crcbuf) - noff;
+ if (len > m->m_len - moff)
+ len = m->m_len - moff;
+ if (len > 0)
+ awa->awa_decrypt(ctx, crcbuf + noff,
+ mtod(m, caddr_t) + moff, len);
+ m = m->m_next;
+ moff = 0;
+ }
+ if (crc != LE_READ_4(crcbuf))
+ goto fail;
+ }
+ m_freem(m0);
+ return n0;
+
+ fail:
+ m_freem(m0);
+ m_freem(n0);
+ return NULL;
+}
+
+/*
+ * CRC 32 -- routine from RFC 2083
+ */
+
+/* Table of CRCs of all 8-bit messages */
+static u_int32_t awi_crc_table[256];
+static int awi_crc_table_computed = 0;
+
+/* Make the table for a fast CRC. */
+static void
+awi_crc_init()
+{
+ u_int32_t c;
+ int n, k;
+
+ if (awi_crc_table_computed)
+ return;
+ for (n = 0; n < 256; n++) {
+ c = (u_int32_t)n;
+ for (k = 0; k < 8; k++) {
+ if (c & 1)
+ c = 0xedb88320UL ^ (c >> 1);
+ else
+ c = c >> 1;
+ }
+ awi_crc_table[n] = c;
+ }
+ awi_crc_table_computed = 1;
+}
+
+/*
+ * Update a running CRC with the bytes buf[0..len-1]--the CRC
+ * should be initialized to all 1's, and the transmitted value
+ * is the 1's complement of the final running CRC
+ */
+
+static u_int32_t
+awi_crc_update(crc, buf, len)
+ u_int32_t crc;
+ u_int8_t *buf;
+ int len;
+{
+ u_int8_t *endbuf;
+
+ for (endbuf = buf + len; buf < endbuf; buf++)
+ crc = awi_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+ return crc;
+}
+
+/*
+ * Null -- do nothing but copy.
+ */
+
+static int
+awi_null_ctxlen()
+{
+
+ return 0;
+}
+
+static void
+awi_null_setkey(ctx, key, keylen)
+ void *ctx;
+ u_char *key;
+ int keylen;
+{
+}
+
+static void
+awi_null_copy(ctx, dst, src, len)
+ void *ctx;
+ u_char *dst;
+ u_char *src;
+ int len;
+{
+
+ memcpy(dst, src, len);
+}
diff --git a/sys/dev/awi/awi_wicfg.c b/sys/dev/awi/awi_wicfg.c
new file mode 100644
index 0000000..bc2e4d7
--- /dev/null
+++ b/sys/dev/awi/awi_wicfg.c
@@ -0,0 +1,627 @@
+/* $NetBSD: awi_wicfg.c,v 1.3 2000/07/06 17:22:25 onoe Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Atsushi Onoe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * WaveLAN compatible configuration support routines for the awi driver.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/sockio.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 4
+#include <sys/bus.h>
+#else
+#include <sys/device.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#ifdef __FreeBSD__
+#include <net/ethernet.h>
+#include <net/if_arp.h>
+#else
+#include <net/if_ether.h>
+#endif
+#include <net/if_media.h>
+#include <net/if_ieee80211.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#ifdef __FreeBSD__
+#include <machine/clock.h>
+#endif
+
+#ifdef __NetBSD__
+#include <dev/ic/am79c930reg.h>
+#include <dev/ic/am79c930var.h>
+#include <dev/ic/awireg.h>
+#include <dev/ic/awivar.h>
+
+#include <dev/pcmcia/if_wi_ieee.h> /* XXX */
+#endif
+#ifdef __FreeBSD__
+#include <dev/awi/am79c930reg.h>
+#include <dev/awi/am79c930var.h>
+
+#undef _KERNEL /* XXX */
+#include <i386/include/if_wavelan_ieee.h> /* XXX */
+#define _KERNEL /* XXX */
+#include <dev/awi/awireg.h>
+#include <dev/awi/awivar.h>
+#endif
+
+static int awi_cfgget __P((struct ifnet *ifp, u_long cmd, caddr_t data));
+static int awi_cfgset __P((struct ifnet *ifp, u_long cmd, caddr_t data));
+
+int
+awi_wicfg(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ int error;
+
+ switch (cmd) {
+ case SIOCGWAVELAN:
+ error = awi_cfgget(ifp, cmd, data);
+ break;
+ case SIOCSWAVELAN:
+#ifdef __FreeBSD__
+ error = suser(curproc);
+#else
+ error = suser(curproc->p_ucred, &curproc->p_acflag);
+#endif
+ if (error)
+ break;
+ error = awi_cfgset(ifp, cmd, data);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+}
+
+static int
+awi_cfgget(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ int i, error, keylen;
+ char *p;
+ struct awi_softc *sc = (struct awi_softc *)ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct wi_ltv_keys *keys;
+ struct wi_key *k;
+ struct wi_req wreq;
+#ifdef WICACHE
+ struct wi_sigcache wsc;
+ struct awi_bss *bp;
+#endif /* WICACHE */
+
+ error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
+ if (error)
+ return error;
+ switch (wreq.wi_type) {
+ case WI_RID_SERIALNO:
+ memcpy(wreq.wi_val, sc->sc_banner, AWI_BANNER_LEN);
+ wreq.wi_len = (AWI_BANNER_LEN + 1) / 2;
+ break;
+ case WI_RID_NODENAME:
+ strcpy((char *)&wreq.wi_val[1], hostname);
+ wreq.wi_val[0] = strlen(hostname);
+ wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
+ break;
+ case WI_RID_OWN_SSID:
+ p = sc->sc_ownssid;
+ wreq.wi_val[0] = p[1];
+ memcpy(&wreq.wi_val[1], p + 2, p[1]);
+ wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
+ break;
+ case WI_RID_CURRENT_SSID:
+ if (ifp->if_flags & IFF_RUNNING) {
+ p = sc->sc_bss.essid;
+ wreq.wi_val[0] = p[1];
+ memcpy(&wreq.wi_val[1], p + 2, p[1]);
+ } else {
+ wreq.wi_val[0] = 0;
+ wreq.wi_val[1] = '\0';
+ }
+ wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
+ break;
+ case WI_RID_DESIRED_SSID:
+ p = sc->sc_mib_mac.aDesired_ESS_ID;
+ wreq.wi_val[0] = p[1];
+ memcpy(&wreq.wi_val[1], p + 2, p[1]);
+ wreq.wi_len = (1 + wreq.wi_val[0] + 1) / 2;
+ break;
+ case WI_RID_CURRENT_BSSID:
+ if (ifp->if_flags & IFF_RUNNING)
+ memcpy(wreq.wi_val, sc->sc_bss.bssid, ETHER_ADDR_LEN);
+ else
+ memset(wreq.wi_val, 0, ETHER_ADDR_LEN);
+ wreq.wi_len = ETHER_ADDR_LEN / 2;
+ break;
+ case WI_RID_CHANNEL_LIST:
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
+ wreq.wi_val[0] = sc->sc_scan_min;
+ wreq.wi_val[1] = sc->sc_scan_max;
+ wreq.wi_len = 2;
+ } else {
+ wreq.wi_val[0] = 0;
+ for (i = sc->sc_scan_min; i <= sc->sc_scan_max; i++)
+ wreq.wi_val[0] |= 1 << (i - 1);
+ wreq.wi_len = 1;
+ }
+ break;
+ case WI_RID_OWN_CHNL:
+ wreq.wi_val[0] = sc->sc_ownch;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_CURRENT_CHAN:
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
+ wreq.wi_val[0] = sc->sc_bss.pattern;
+ else
+ wreq.wi_val[0] = sc->sc_bss.chanset;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_COMMS_QUALITY:
+ wreq.wi_val[0] = 0; /* quality */
+ wreq.wi_val[1] = sc->sc_bss.rssi; /* signal */
+ wreq.wi_val[2] = 0; /* noise */
+ wreq.wi_len = 3;
+ break;
+ case WI_RID_PROMISC:
+ wreq.wi_val[0] = sc->sc_mib_mac.aPromiscuous_Enable;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_PORTTYPE:
+ if (sc->sc_mib_local.Network_Mode)
+ wreq.wi_val[0] = 1;
+ else if (!sc->sc_no_bssid)
+ wreq.wi_val[0] = 2;
+ else
+ wreq.wi_val[0] = 3;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_MAC_NODE:
+ memcpy(wreq.wi_val, sc->sc_mib_addr.aMAC_Address,
+ ETHER_ADDR_LEN);
+ wreq.wi_len = ETHER_ADDR_LEN / 2;
+ break;
+ case WI_RID_TX_RATE:
+ case WI_RID_CUR_TX_RATE:
+ wreq.wi_val[0] = sc->sc_tx_rate / 10;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_RTS_THRESH:
+ wreq.wi_val[0] = LE_READ_2(&sc->sc_mib_mac.aRTS_Threshold);
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_CREATE_IBSS:
+ wreq.wi_val[0] = sc->sc_start_bss;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_SYSTEM_SCALE:
+ wreq.wi_val[0] = 1; /* low density ... not supported */
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_PM_ENABLED:
+ wreq.wi_val[0] = sc->sc_mib_local.Power_Saving_Mode_Dis ? 0 : 1;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_MAX_SLEEP:
+ wreq.wi_val[0] = 0; /* not implemented */
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_WEP_AVAIL:
+ wreq.wi_val[0] = 1;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_ENCRYPTION:
+ wreq.wi_val[0] = awi_wep_getalgo(sc);
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_TX_CRYPT_KEY:
+ wreq.wi_val[0] = sc->sc_wep_defkid;
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_DEFLT_CRYPT_KEYS:
+ keys = (struct wi_ltv_keys *)&wreq;
+ /* do not show keys to non-root user */
+#ifdef __FreeBSD__
+ error = suser(curproc);
+#else
+ error = suser(curproc->p_ucred, &curproc->p_acflag);
+#endif
+ if (error) {
+ memset(keys, 0, sizeof(*keys));
+ error = 0;
+ break;
+ }
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ k = &keys->wi_keys[i];
+ keylen = sizeof(k->wi_keydat);
+ error = awi_wep_getkey(sc, i, k->wi_keydat, &keylen);
+ if (error)
+ break;
+ k->wi_keylen = keylen;
+ }
+ wreq.wi_len = sizeof(*keys) / 2;
+ break;
+ case WI_RID_MAX_DATALEN:
+ wreq.wi_val[0] = LE_READ_2(&sc->sc_mib_mac.aMax_Frame_Length);
+ wreq.wi_len = 1;
+ break;
+ case WI_RID_IFACE_STATS:
+ /* not implemented yet */
+ wreq.wi_len = 0;
+ break;
+#ifdef WICACHE
+ case WI_RID_READ_CACHE:
+ for (bp = TAILQ_FIRST(&sc->sc_scan), i = 0;
+ bp != NULL && i < MAXWICACHE;
+ bp = TAILQ_NEXT(bp, list), i++) {
+ memcpy(wsc.macsrc, bp->esrc, ETHER_ADDR_LEN);
+ /*XXX*/
+ memcpy(&wsc.ipsrc, bp->bssid, sizeof(wsc.ipsrc));
+ wsc.signal = bp->rssi;
+ wsc.noise = 0;
+ wsc.quality = 0;
+ memcpy((caddr_t)wreq.wi_val + sizeof(wsc) * i,
+ &wsc, sizeof(wsc));
+ }
+ wreq.wi_len = sizeof(wsc) * i / 2;
+ break;
+#endif /* WICACHE */
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (error == 0) {
+ wreq.wi_len++;
+ error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
+ }
+ return error;
+}
+
+static int
+awi_cfgset(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ int i, error, rate, oregion;
+ u_int8_t *phy_rates;
+ struct awi_softc *sc = (struct awi_softc *)ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct wi_ltv_keys *keys;
+ struct wi_key *k;
+ struct wi_req wreq;
+
+ error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
+ if (error)
+ return error;
+ if (wreq.wi_len-- < 1)
+ return EINVAL;
+ switch (wreq.wi_type) {
+ case WI_RID_SERIALNO:
+ case WI_RID_NODENAME:
+ error = EPERM;
+ break;
+ case WI_RID_OWN_SSID:
+ if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) {
+ error = EINVAL;
+ break;
+ }
+ if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
+ error = EINVAL;
+ break;
+ }
+ memset(sc->sc_ownssid, 0, AWI_ESS_ID_SIZE);
+ sc->sc_ownssid[0] = IEEE80211_ELEMID_SSID;
+ sc->sc_ownssid[1] = wreq.wi_val[0];
+ memcpy(&sc->sc_ownssid[2], &wreq.wi_val[1], wreq.wi_val[0]);
+ if (!sc->sc_mib_local.Network_Mode &&
+ !sc->sc_no_bssid && sc->sc_start_bss)
+ error = ENETRESET;
+ break;
+ case WI_RID_CURRENT_SSID:
+ error = EPERM;
+ break;
+ case WI_RID_DESIRED_SSID:
+ if (wreq.wi_len < (1 + wreq.wi_val[0] + 1) / 2) {
+ error = EINVAL;
+ break;
+ }
+ if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
+ error = EINVAL;
+ break;
+ }
+ memset(sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
+ sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
+ sc->sc_mib_mac.aDesired_ESS_ID[1] = wreq.wi_val[0];
+ memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], &wreq.wi_val[1],
+ wreq.wi_val[0]);
+ if (sc->sc_mib_local.Network_Mode || !sc->sc_no_bssid)
+ error = ENETRESET;
+ break;
+ case WI_RID_CURRENT_BSSID:
+ error = EPERM;
+ break;
+ case WI_RID_CHANNEL_LIST:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ oregion = sc->sc_mib_phy.aCurrent_Reg_Domain;
+ if (wreq.wi_val[0] == oregion)
+ break;
+ sc->sc_mib_phy.aCurrent_Reg_Domain = wreq.wi_val[0];
+ error = awi_init_region(sc);
+ if (error) {
+ sc->sc_mib_phy.aCurrent_Reg_Domain = oregion;
+ break;
+ }
+ error = ENETRESET;
+ break;
+ case WI_RID_OWN_CHNL:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ if (wreq.wi_val[0] < sc->sc_scan_min ||
+ wreq.wi_val[0] > sc->sc_scan_max) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_ownch = wreq.wi_val[0];
+ if (!sc->sc_mib_local.Network_Mode)
+ error = ENETRESET;
+ break;
+ case WI_RID_CURRENT_CHAN:
+ error = EPERM;
+ break;
+ case WI_RID_COMMS_QUALITY:
+ error = EPERM;
+ break;
+ case WI_RID_PROMISC:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ if (ifp->if_flags & IFF_PROMISC) {
+ if (wreq.wi_val[0] == 0) {
+ ifp->if_flags &= ~IFF_PROMISC;
+ error = ENETRESET;
+ }
+ } else {
+ if (wreq.wi_val[0] != 0) {
+ ifp->if_flags |= IFF_PROMISC;
+ error = ENETRESET;
+ }
+ }
+ break;
+ case WI_RID_PORTTYPE:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ switch (wreq.wi_val[0]) {
+ case 1:
+ sc->sc_mib_local.Network_Mode = 1;
+ sc->sc_no_bssid = 0;
+ error = ENETRESET;
+ break;
+ case 2:
+ sc->sc_mib_local.Network_Mode = 0;
+ sc->sc_no_bssid = 0;
+ error = ENETRESET;
+ break;
+ case 3:
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_mib_local.Network_Mode = 0;
+ sc->sc_no_bssid = 1;
+ error = ENETRESET;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ case WI_RID_MAC_NODE:
+ /* XXX: should be implemented? */
+ error = EPERM;
+ break;
+ case WI_RID_TX_RATE:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
+ switch (wreq.wi_val[0]) {
+ case 1:
+ case 2:
+ case 5:
+ case 11:
+ rate = wreq.wi_val[0] * 10;
+ if (rate == 50)
+ rate += 5; /*XXX*/
+ break;
+ case 3:
+ case 6:
+ case 7:
+ /* auto rate */
+ phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
+ rate = AWI_RATE_1MBIT;
+ for (i = 0; i < phy_rates[1]; i++) {
+ if (AWI_80211_RATE(phy_rates[2 + i]) > rate)
+ rate = AWI_80211_RATE(phy_rates[2 + i]);
+ }
+ break;
+ default:
+ rate = 0;
+ error = EINVAL;
+ break;
+ }
+ if (error)
+ break;
+ for (i = 0; i < phy_rates[1]; i++) {
+ if (rate == AWI_80211_RATE(phy_rates[2 + i]))
+ break;
+ }
+ if (i == phy_rates[1]) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_tx_rate = rate;
+ break;
+ case WI_RID_CUR_TX_RATE:
+ error = EPERM;
+ break;
+ case WI_RID_RTS_THRESH:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ LE_WRITE_2(&sc->sc_mib_mac.aRTS_Threshold, wreq.wi_val[0]);
+ error = ENETRESET;
+ break;
+ case WI_RID_CREATE_IBSS:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_start_bss = wreq.wi_val[0] ? 1 : 0;
+ error = ENETRESET;
+ break;
+ case WI_RID_SYSTEM_SCALE:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ if (wreq.wi_val[0] != 1)
+ error = EINVAL; /* not supported */
+ break;
+ case WI_RID_PM_ENABLED:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ if (wreq.wi_val[0] != 0)
+ error = EINVAL; /* not implemented */
+ break;
+ case WI_RID_MAX_SLEEP:
+ error = EINVAL; /* not implemented */
+ break;
+ case WI_RID_WEP_AVAIL:
+ error = EPERM;
+ break;
+ case WI_RID_ENCRYPTION:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ error = awi_wep_setalgo(sc, wreq.wi_val[0]);
+ if (error)
+ break;
+ error = ENETRESET;
+ break;
+ case WI_RID_TX_CRYPT_KEY:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ if (wreq.wi_val[0] >= IEEE80211_WEP_NKID) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_wep_defkid = wreq.wi_val[1];
+ break;
+ case WI_RID_DEFLT_CRYPT_KEYS:
+ if (wreq.wi_len != sizeof(*keys) / 2) {
+ error = EINVAL;
+ break;
+ }
+ keys = (struct wi_ltv_keys *)&wreq;
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ k = &keys->wi_keys[i];
+ error = awi_wep_setkey(sc, i, k->wi_keydat,
+ k->wi_keylen);
+ if (error)
+ break;
+ }
+ break;
+ case WI_RID_MAX_DATALEN:
+ if (wreq.wi_len != 1) {
+ error = EINVAL;
+ break;
+ }
+ if (wreq.wi_val[0] < 350 || wreq.wi_val[0] > 2304) {
+ error = EINVAL;
+ break;
+ }
+ LE_WRITE_2(&sc->sc_mib_mac.aMax_Frame_Length, wreq.wi_val[0]);
+ break;
+ case WI_RID_IFACE_STATS:
+ error = EPERM;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (error == ENETRESET) {
+ if (sc->sc_enabled) {
+ awi_stop(sc);
+ error = awi_init(sc);
+ } else
+ error = 0;
+ }
+ return error;
+}
diff --git a/sys/dev/awi/awivar.h b/sys/dev/awi/awivar.h
index e3c85cc..c3a0a48 100644
--- a/sys/dev/awi/awivar.h
+++ b/sys/dev/awi/awivar.h
@@ -1,12 +1,12 @@
-/* $NetBSD: awivar.h,v 1.6 2000/03/22 11:22:22 onoe Exp $ */
+/* $NetBSD: awivar.h,v 1.12 2000/07/21 04:48:56 onoe Exp $ */
/* $FreeBSD$ */
-/*
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Atsushi Onoe
+ * by Bill Sommerfeld
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -48,6 +48,7 @@
#define AWI_TRANS_TIMEOUT 2000
#define AWI_NTXBUFS 4
+#define AWI_MAX_KEYLEN 16
enum awi_status {
AWI_ST_INIT,
@@ -70,6 +71,7 @@ struct awi_bss
u_int16_t dwell_time; /* dwell time */
u_int8_t timestamp[8]; /* timestamp of this bss */
u_int8_t bssid[ETHER_ADDR_LEN];
+ u_int16_t capinfo;
u_int32_t rxtime; /* unit's local time */
u_int16_t interval; /* beacon interval */
u_int8_t txrate;
@@ -77,6 +79,14 @@ struct awi_bss
u_int8_t essid[IEEE80211_NWID_LEN + 2];
};
+struct awi_wep_algo {
+ char *awa_name;
+ int (*awa_ctxlen) __P((void));
+ void (*awa_setkey) __P((void *, u_char *, int));
+ void (*awa_encrypt) __P((void *, u_char *, u_char *, int));
+ void (*awa_decrypt) __P((void *, u_char *, u_char *, int));
+};
+
struct awi_softc
{
#ifdef __NetBSD__
@@ -93,7 +103,6 @@ struct awi_softc
struct device sc_dev;
#endif
struct arpcom sc_ec;
- struct callout_handle sc_tohandle;
#endif
struct am79c930_softc sc_chip;
struct ifnet *sc_ifp;
@@ -106,12 +115,14 @@ struct awi_softc
sc_busy:1,
sc_cansleep:1,
sc_invalid:1,
- sc_cmd_inprog:1,
+ sc_enab_intr:1,
sc_format_llc:1,
sc_start_bss:1,
sc_rawbpf:1,
sc_no_bssid:1,
- sc_active_scan:1;
+ sc_active_scan:1,
+ sc_attached:1; /* attach has succeeded */
+ u_int8_t sc_cmd_inprog;
int sc_sleep_cnt;
int sc_mgt_timer;
@@ -122,6 +133,8 @@ struct awi_softc
u_int8_t sc_scan_max;
u_int8_t sc_scan_set;
struct awi_bss sc_bss;
+ u_int8_t sc_ownssid[IEEE80211_NWID_LEN + 2];
+ u_int8_t sc_ownch;
int sc_rx_timer;
u_int32_t sc_rxdoff;
@@ -136,6 +149,13 @@ struct awi_softc
u_int32_t sc_txnext;
u_int32_t sc_txdone;
+ int sc_wep_keylen[IEEE80211_WEP_NKID]; /* keylen */
+ u_int8_t sc_wep_key[IEEE80211_WEP_NKID][AWI_MAX_KEYLEN];
+ int sc_wep_defkid;
+ void *sc_wep_ctx; /* work area */
+ struct awi_wep_algo *sc_wep_algo;
+
+ u_char sc_banner[AWI_BANNER_LEN];
struct awi_mib_local sc_mib_local;
struct awi_mib_addr sc_mib_addr;
struct awi_mib_mac sc_mib_mac;
@@ -185,9 +205,24 @@ void awi_reset __P((struct awi_softc *));
#ifdef __NetBSD__
int awi_activate __P((struct device *, enum devact));
int awi_detach __P((struct awi_softc *));
+void awi_power __P((struct awi_softc *, int));
#endif
+void awi_stop __P((struct awi_softc *sc));
+int awi_init __P((struct awi_softc *sc));
+int awi_init_region __P((struct awi_softc *));
+int awi_wicfg __P((struct ifnet *, u_long, caddr_t));
+
+int awi_wep_setnwkey __P((struct awi_softc *, struct ieee80211_nwkey *));
+int awi_wep_getnwkey __P((struct awi_softc *, struct ieee80211_nwkey *));
+int awi_wep_getalgo __P((struct awi_softc *));
+int awi_wep_setalgo __P((struct awi_softc *, int));
+int awi_wep_setkey __P((struct awi_softc *, int, unsigned char *, int));
+int awi_wep_getkey __P((struct awi_softc *, int, unsigned char *, int *));
+struct mbuf *awi_wep_encrypt __P((struct awi_softc *, struct mbuf *, int));
+
#ifdef __FreeBSD__
+/* Provide mem* for compat with NetBSD to fix LINT */
static __inline int
memcmp(const void *b1, const void *b2, size_t len)
{
OpenPOWER on IntegriCloud