mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-16 15:11:52 +00:00
Significant bugfix and upgrade for the Wavelan (wl) driver.
This now includes code to handle the 2.4GHz WaveModem-based cards. Submitted by: Jim Binkley <jrb@cs.pdx.edu>
This commit is contained in:
parent
01238b11a8
commit
10731762e6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=27817
@ -1,3 +1,4 @@
|
|||||||
|
/* $Id$ */
|
||||||
/*
|
/*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@ -33,6 +34,12 @@
|
|||||||
* Pruned heading comments for relevance.
|
* Pruned heading comments for relevance.
|
||||||
* Ripped out all the 'interface counters' cruft.
|
* Ripped out all the 'interface counters' cruft.
|
||||||
* Cut the missing-interrupt timer back to 100ms.
|
* Cut the missing-interrupt timer back to 100ms.
|
||||||
|
* 2.2.1 update:
|
||||||
|
* now supports all multicast mode (mrouted will work),
|
||||||
|
* but unfortunately must do that by going into promiscuous mode
|
||||||
|
* NWID sysctl added so that normally promiscuous mode is NWID-specific
|
||||||
|
* but can be made NWID-inspecific
|
||||||
|
* 7/14/97 jrb
|
||||||
*
|
*
|
||||||
* Work done:
|
* Work done:
|
||||||
* Ported to FreeBSD, got promiscuous mode working with bpfs,
|
* Ported to FreeBSD, got promiscuous mode working with bpfs,
|
||||||
@ -77,19 +84,45 @@
|
|||||||
* device wl0 at isa? port 0x300 net irq ? vector wlintr
|
* device wl0 at isa? port 0x300 net irq ? vector wlintr
|
||||||
*
|
*
|
||||||
* Ifdefs:
|
* Ifdefs:
|
||||||
* 1. IF_CNTRS - haven't tried it. Can get out various bits of info
|
* 1. WLDEBUG. (off) - if turned on enables IFF_DEBUG set via ifconfig debug
|
||||||
* from the rf-modem.
|
* 2. MULTICAST (on) - turned on and works up to and including mrouted
|
||||||
* 2. WLDEBUG if turned on enables IFF_DEBUG set via ifconfig debug
|
* 3. WLCACHE (off) - define to turn on a signal strength
|
||||||
* 3. MULTICAST - turned on and works in a few simple tests.
|
* (and other metric) cache that is indexed by sender MAC address.
|
||||||
|
* Apps can read this out to learn the remote signal strength of a
|
||||||
|
* sender. Note that it has a switch so that it only stores
|
||||||
|
* broadcast/multicast senders but it could be set to store unicast
|
||||||
|
* too only. Size is hardwired in if_wl_wavelan.h
|
||||||
*
|
*
|
||||||
* one further note: promiscuous mode is a curious thing. In this driver,
|
* one further note: promiscuous mode is a curious thing. In this driver,
|
||||||
* promiscuous mode apparently will catch ALL packets and ignore the NWID
|
* promiscuous mode apparently CAN catch ALL packets and ignore the NWID
|
||||||
* setting. This is probably more useful in a sense (for snoopers) if
|
* setting. This is probably more useful in a sense (for snoopers) if
|
||||||
* you are interested in all traffic as opposed to if you are interested
|
* you are interested in all traffic as opposed to if you are interested
|
||||||
* in just your own.
|
* in just your own. There is a driver specific sysctl to turn promiscuous
|
||||||
|
* from just promiscuous to wildly promiscuous...
|
||||||
|
*
|
||||||
|
* This driver also knows how to load the synthesizers in the 2.4 Gz
|
||||||
|
* ISA Half-card, Product number 847647476 (USA/FCC IEEE Channel set).
|
||||||
|
* This product consists of a "mothercard" that contains the 82586,
|
||||||
|
* NVRAM that holds the PSA, and the ISA-buss interface custom ASIC.
|
||||||
|
* The radio transceiver is a "daughtercard" called the WaveMODEM which
|
||||||
|
* connects to the mothercard through two single-inline connectors: a
|
||||||
|
* 20-pin connector provides DC-power and modem signals, and a 3-pin
|
||||||
|
* connector which exports the antenna connection. The code herein
|
||||||
|
* loads the receive and transmit synthesizers and the corresponding
|
||||||
|
* transmitter output power value from an EEPROM controlled through
|
||||||
|
* additional registers via the MMC. The EEPROM address selected
|
||||||
|
* are those whose values are preset by the DOS utility programs
|
||||||
|
* provided with the product, and this provides compatible operation
|
||||||
|
* with the DOS Packet Driver software. A future modification will
|
||||||
|
* add the necessary functionality to this driver and to the wlconfig
|
||||||
|
* utility to completely replace the DOS Configuration Utilities.
|
||||||
|
* The 2.4 Gz WaveMODEM is described in document number 407-024692/E,
|
||||||
|
* and is available through Lucent Technologies OEM supply channels.
|
||||||
|
* --RAB 1997/06/08.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MULTICAST 1
|
#define MULTICAST 1
|
||||||
|
#define WLCACHE 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Olivetti PC586 Mach Ethernet driver v1.0
|
* Olivetti PC586 Mach Ethernet driver v1.0
|
||||||
@ -173,9 +206,13 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||||||
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <net/if_dl.h>
|
#include <net/if_dl.h>
|
||||||
|
/* #include <net/if_types.h>*/
|
||||||
|
|
||||||
#ifdef INET
|
#ifdef INET
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/in_systm.h>
|
||||||
|
#include <netinet/in_var.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
#include <netinet/if_ether.h>
|
#include <netinet/if_ether.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -183,6 +220,7 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||||||
#include <net/bpf.h>
|
#include <net/bpf.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <machine/cpufunc.h>
|
||||||
#include <machine/clock.h>
|
#include <machine/clock.h>
|
||||||
|
|
||||||
#include <i386/isa/isa_device.h>
|
#include <i386/isa/isa_device.h>
|
||||||
@ -211,6 +249,15 @@ struct wl_softc{
|
|||||||
u_short end_rbd;
|
u_short end_rbd;
|
||||||
u_short hacr; /* latest host adapter CR command */
|
u_short hacr; /* latest host adapter CR command */
|
||||||
short mode;
|
short mode;
|
||||||
|
u_char chan24; /* 2.4 Gz: channel number/EEPROM Area # */
|
||||||
|
u_short freq24; /* 2.4 Gz: resulting frequency */
|
||||||
|
#ifdef WLCACHE
|
||||||
|
int w_sigitems; /* number of cached entries */
|
||||||
|
/* array of cache entries */
|
||||||
|
struct w_sigcache w_sigcache[ MAXCACHEITEMS ];
|
||||||
|
int w_nextcache; /* next free cache entry */
|
||||||
|
int w_wrapindex; /* next "free" cache entry */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
static struct wl_softc wl_softc[NWL];
|
static struct wl_softc wl_softc[NWL];
|
||||||
|
|
||||||
@ -227,11 +274,21 @@ struct isa_driver wldriver = {
|
|||||||
/*
|
/*
|
||||||
* XXX The Wavelan appears to be prone to dropping stuff if you talk to
|
* XXX The Wavelan appears to be prone to dropping stuff if you talk to
|
||||||
* it too fast. This disgusting hack inserts a delay after each packet
|
* it too fast. This disgusting hack inserts a delay after each packet
|
||||||
* is queued that helps avoid this behaviour on fast systems.
|
* is queued which helps avoid this behaviour on fast systems.
|
||||||
*/
|
*/
|
||||||
static int wl_xmit_delay = 0;
|
static int wl_xmit_delay = 250;
|
||||||
SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
|
SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* not XXX, but ZZZ (bizarre).
|
||||||
|
* promiscuous mode can be toggled to ignore NWIDs. By default,
|
||||||
|
* it does not. Caution should be exercised about combining
|
||||||
|
* this mode with IFF_ALLMULTI which puts this driver in
|
||||||
|
* promiscuous mode.
|
||||||
|
*/
|
||||||
|
static int wl_ignore_nwid = 0;
|
||||||
|
SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Emit diagnostics about transmission problems
|
* Emit diagnostics about transmission problems
|
||||||
*/
|
*/
|
||||||
@ -247,7 +304,7 @@ SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
|
|||||||
static void wlstart(struct ifnet *ifp);
|
static void wlstart(struct ifnet *ifp);
|
||||||
static void wlinit(void *xsc);
|
static void wlinit(void *xsc);
|
||||||
static int wlioctl(struct ifnet *ifp, int cmd, caddr_t data);
|
static int wlioctl(struct ifnet *ifp, int cmd, caddr_t data);
|
||||||
static timeout_t wlwatchdog;
|
static void wlwatchdog(struct wl_softc *sc);
|
||||||
static void wlxmt(int unt, struct mbuf *m);
|
static void wlxmt(int unt, struct mbuf *m);
|
||||||
static int wldiag(int unt);
|
static int wldiag(int unt);
|
||||||
static int wlconfig(int unit);
|
static int wlconfig(int unit);
|
||||||
@ -272,6 +329,15 @@ static void wlgetpsa(int base, u_char *buf);
|
|||||||
static void wlsetpsa(int unit);
|
static void wlsetpsa(int unit);
|
||||||
static u_short wlpsacrc(u_char *buf);
|
static u_short wlpsacrc(u_char *buf);
|
||||||
static void wldump(int unit);
|
static void wldump(int unit);
|
||||||
|
#ifdef WLCACHE
|
||||||
|
static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
|
||||||
|
static void wl_cache_zero(int unit);
|
||||||
|
#endif
|
||||||
|
#ifdef MULTICAST
|
||||||
|
# if __FreeBSD < 3
|
||||||
|
static int check_allmulti(int unit);
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/* array for maping irq numbers to values for the irq parameter register */
|
/* array for maping irq numbers to values for the irq parameter register */
|
||||||
static int irqvals[16] = {
|
static int irqvals[16] = {
|
||||||
@ -331,6 +397,9 @@ wlprobe(struct isa_device *id)
|
|||||||
if (bcmp(str, inbuf, strlen(str)))
|
if (bcmp(str, inbuf, strlen(str)))
|
||||||
return(0);
|
return(0);
|
||||||
|
|
||||||
|
sc->chan24 = 0; /* 2.4 Gz: config channel */
|
||||||
|
sc->freq24 = 0; /* 2.4 Gz: frequency */
|
||||||
|
|
||||||
/* read the PSA from the board into temporary storage */
|
/* read the PSA from the board into temporary storage */
|
||||||
wlgetpsa(base, inbuf);
|
wlgetpsa(base, inbuf);
|
||||||
|
|
||||||
@ -446,9 +515,14 @@ wlattach(struct isa_device *id)
|
|||||||
#if NBPFILTER > 0
|
#if NBPFILTER > 0
|
||||||
bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
|
bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
|
bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
|
||||||
printf("%s%d: address %6D, NWID 0x%02x%02x\n", ifp->if_name, ifp->if_unit,
|
printf("%s%d: address %6D, NWID 0x%02x%02x", ifp->if_name, ifp->if_unit,
|
||||||
sc->wl_ac.ac_enaddr, ":", sc->nwid[0], sc->nwid[1]);
|
sc->wl_ac.ac_enaddr, ":", sc->nwid[0], sc->nwid[1]);
|
||||||
|
if (sc->freq24)
|
||||||
|
printf(", Freq %d MHz",sc->freq24); /* 2.4 Gz */
|
||||||
|
printf("\n"); /* 2.4 Gz */
|
||||||
|
|
||||||
|
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
wldump(unit);
|
wldump(unit);
|
||||||
@ -494,6 +568,7 @@ wlinitmmc(int unit)
|
|||||||
int base = sp->base;
|
int base = sp->base;
|
||||||
int configured;
|
int configured;
|
||||||
int mode = sp->mode;
|
int mode = sp->mode;
|
||||||
|
int i; /* 2.4 Gz */
|
||||||
|
|
||||||
/* enter 8 bit operation */
|
/* enter 8 bit operation */
|
||||||
sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
|
sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
|
||||||
@ -523,7 +598,7 @@ wlinitmmc(int unit)
|
|||||||
} else {
|
} else {
|
||||||
/* use configuration defaults from parameter storage area */
|
/* use configuration defaults from parameter storage area */
|
||||||
if (sp->psa[WLPSA_NWIDENABLE] & 1) {
|
if (sp->psa[WLPSA_NWIDENABLE] & 1) {
|
||||||
if (mode & MOD_PROM) {
|
if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
|
||||||
MMC_WRITE(MMC_LOOPT_SEL, 0x40);
|
MMC_WRITE(MMC_LOOPT_SEL, 0x40);
|
||||||
} else {
|
} else {
|
||||||
MMC_WRITE(MMC_LOOPT_SEL, 0x00);
|
MMC_WRITE(MMC_LOOPT_SEL, 0x00);
|
||||||
@ -544,6 +619,44 @@ wlinitmmc(int unit)
|
|||||||
sp->hacr = HACR_DEFAULT;
|
sp->hacr = HACR_DEFAULT;
|
||||||
CMD(unit);
|
CMD(unit);
|
||||||
CMD(unit); /* virtualpc1 needs this! */
|
CMD(unit); /* virtualpc1 needs this! */
|
||||||
|
|
||||||
|
if (sp->psa[WLPSA_COMPATNO]== /* 2.4 Gz: half-card ver */
|
||||||
|
WLPSA_COMPATNO_WL24B) { /* 2.4 Gz */
|
||||||
|
i=sp->chan24<<4; /* 2.4 Gz: position ch # */
|
||||||
|
MMC_WRITE(MMC_EEADDR,i+0x0f); /* 2.4 Gz: named ch, wc=16 */
|
||||||
|
MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Synths */
|
||||||
|
MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
|
||||||
|
for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
|
||||||
|
DELAY(40); /* 2.4 Gz */
|
||||||
|
if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
|
||||||
|
&(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
|
||||||
|
+MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
|
||||||
|
break; /* 2.4 Gz: download finished */
|
||||||
|
} /* 2.4 Gz */
|
||||||
|
if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz */
|
||||||
|
MMC_WRITE(MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */
|
||||||
|
MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Xmit Pwr */
|
||||||
|
MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
|
||||||
|
for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
|
||||||
|
DELAY(40); /* 2.4 Gz */
|
||||||
|
if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
|
||||||
|
&(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
|
||||||
|
+MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
|
||||||
|
break; /* 2.4 Gz: download finished */
|
||||||
|
} /* 2.4 Gz */
|
||||||
|
if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz */
|
||||||
|
MMC_WRITE(MMC_ANALCTRL, /* 2.4 Gz: EXT ant+polarity */
|
||||||
|
MMC_ANALCTRL_ANTPOL + /* 2.4 Gz: */
|
||||||
|
MMC_ANALCTRL_EXTANT); /* 2.4 Gz: */
|
||||||
|
i=sp->chan24<<4; /* 2.4 Gz: position ch # */
|
||||||
|
MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
|
||||||
|
MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
|
||||||
|
MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
|
||||||
|
DELAY(40); /* 2.4 Gz */
|
||||||
|
i = wlmmcread(base,MMC_EEDATALrv) /* 2.4 Gz: freq val */
|
||||||
|
+ (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz */
|
||||||
|
sp->freq24 = (i>>6)+2400; /* 2.4 Gz: save real freq */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -571,13 +684,11 @@ wlinit(void *xsc)
|
|||||||
#endif
|
#endif
|
||||||
#if __FreeBSD__ >= 3
|
#if __FreeBSD__ >= 3
|
||||||
if (ifp->if_addrhead.tqh_first == (struct ifaddr *)0) {
|
if (ifp->if_addrhead.tqh_first == (struct ifaddr *)0) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
if (ifp->if_addrlist == (struct ifaddr *)0) {
|
if (ifp->if_addrlist == (struct ifaddr *)0) {
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
oldpri = splimp();
|
oldpri = splimp();
|
||||||
if ((stat = wlhwrst(sc->unit)) == TRUE) {
|
if ((stat = wlhwrst(sc->unit)) == TRUE) {
|
||||||
sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
|
sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
|
||||||
@ -589,7 +700,7 @@ wlinit(void *xsc)
|
|||||||
|
|
||||||
sc->flags |= DSF_RUNNING;
|
sc->flags |= DSF_RUNNING;
|
||||||
sc->tbusy = 0;
|
sc->tbusy = 0;
|
||||||
untimeout(wlwatchdog, sc);
|
untimeout((timeout_func_t)wlwatchdog, sc);
|
||||||
|
|
||||||
wlstart(ifp);
|
wlstart(ifp);
|
||||||
} else {
|
} else {
|
||||||
@ -760,7 +871,7 @@ wlstart(struct ifnet *ifp)
|
|||||||
if((scb_status & 0x0700) == SCB_CUS_IDLE &&
|
if((scb_status & 0x0700) == SCB_CUS_IDLE &&
|
||||||
(cu_status & AC_SW_B) == 0){
|
(cu_status & AC_SW_B) == 0){
|
||||||
sc->tbusy = 0;
|
sc->tbusy = 0;
|
||||||
untimeout(wlwatchdog, sc);
|
untimeout((timeout_func_t)wlwatchdog, sc);
|
||||||
sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
|
sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
|
||||||
/*
|
/*
|
||||||
* This is probably just a race. The xmt'r is just
|
* This is probably just a race. The xmt'r is just
|
||||||
@ -799,7 +910,7 @@ wlstart(struct ifnet *ifp)
|
|||||||
* fails to interrupt we will restart
|
* fails to interrupt we will restart
|
||||||
*/
|
*/
|
||||||
/* try 10 ticks, not very long */
|
/* try 10 ticks, not very long */
|
||||||
timeout(wlwatchdog, sc, 10);
|
timeout((timeout_func_t)wlwatchdog, sc, 10);
|
||||||
sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
|
sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
|
||||||
sc->wl_if.if_opackets++;
|
sc->wl_if.if_opackets++;
|
||||||
wlxmt(unit, m);
|
wlxmt(unit, m);
|
||||||
@ -902,11 +1013,23 @@ u_short fd_p;
|
|||||||
m->m_pkthdr.rcvif = ifp;
|
m->m_pkthdr.rcvif = ifp;
|
||||||
m->m_pkthdr.len = 0; /* don't know this yet */
|
m->m_pkthdr.len = 0; /* don't know this yet */
|
||||||
m->m_len = MHLEN;
|
m->m_len = MHLEN;
|
||||||
if (bytes_in_msg >= MINCLSIZE) {
|
|
||||||
MCLGET(m, M_DONTWAIT);
|
/* always use a cluster. jrb
|
||||||
if (m->m_flags & M_EXT)
|
*/
|
||||||
m->m_len = MCLBYTES;
|
MCLGET(m, M_DONTWAIT);
|
||||||
|
if (m->m_flags & M_EXT) {
|
||||||
|
m->m_len = MCLBYTES;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
m_freem(m);
|
||||||
|
if (wlhwrst(unit) != TRUE) {
|
||||||
|
sc->hacr &= ~HACR_INTRON;
|
||||||
|
CMD(unit); /* turn off interrupts */
|
||||||
|
printf("wl%d read(): hwrst trouble.\n", unit);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
mlen = 0;
|
mlen = 0;
|
||||||
clen = mlen;
|
clen = mlen;
|
||||||
bytes_in_mbuf = m->m_len;
|
bytes_in_mbuf = m->m_len;
|
||||||
@ -963,6 +1086,25 @@ u_short fd_p;
|
|||||||
|
|
||||||
m->m_pkthdr.len = clen;
|
m->m_pkthdr.len = clen;
|
||||||
|
|
||||||
|
#ifdef NOTYET
|
||||||
|
/* due to fact that controller does not support
|
||||||
|
* all multicast mode, we must filter out unicast packets
|
||||||
|
* that are not for us.
|
||||||
|
*
|
||||||
|
* if we are in all multicast mode and not promiscuous mode
|
||||||
|
* and packet is unicast and not for us,
|
||||||
|
* toss the packet
|
||||||
|
*
|
||||||
|
* TBD: also discard packets where NWID does not match.
|
||||||
|
*/
|
||||||
|
if ( (sc->mode & MOD_ENAL) && ((sc->mode & MOD_PROM) != 0) &&
|
||||||
|
((eh.ether_dhost[0] & 1) == 0) /* !mcast and !bcast */ &&
|
||||||
|
(bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
|
||||||
|
sizeof(eh.ether_dhost)) != 0) ) {
|
||||||
|
m_freem(m);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if NBPFILTER > 0
|
#if NBPFILTER > 0
|
||||||
/*
|
/*
|
||||||
* Check if there's a BPF listener on this interface. If so, hand off
|
* Check if there's a BPF listener on this interface. If so, hand off
|
||||||
@ -981,9 +1123,10 @@ u_short fd_p;
|
|||||||
bpf_mtap(ifp, &m0);
|
bpf_mtap(ifp, &m0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that the interface cannot be in promiscuous mode if
|
* point of this code is that even though we are in promiscuous
|
||||||
* there are no BPF listeners. And if we are in promiscuous
|
* mode, and due to fact that bpf got packet already, we
|
||||||
* mode, we have to check if this packet is really ours.
|
* do toss unicast packet not to us so that stacks upstairs
|
||||||
|
* do not need to weed it out
|
||||||
*
|
*
|
||||||
* logic: if promiscuous mode AND not multicast/bcast AND
|
* logic: if promiscuous mode AND not multicast/bcast AND
|
||||||
* not to us, throw away
|
* not to us, throw away
|
||||||
@ -1003,6 +1146,10 @@ u_short fd_p;
|
|||||||
printf("wl%d: wlrecv %d bytes\n", unit, clen);
|
printf("wl%d: wlrecv %d bytes\n", unit, clen);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WLCACHE
|
||||||
|
wl_cache_store(unit, base, &eh, m);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* received packet is now in a chain of mbuf's. next step is
|
* received packet is now in a chain of mbuf's. next step is
|
||||||
* to pass the packet upwards.
|
* to pass the packet upwards.
|
||||||
@ -1036,8 +1183,9 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
int opri, error = 0;
|
int opri, error = 0;
|
||||||
u_short tmp;
|
u_short tmp;
|
||||||
struct proc *p = curproc; /* XXX */
|
struct proc *p = curproc; /* XXX */
|
||||||
int irq, irqval, i, isroot;
|
int irq, irqval, i, isroot, size;
|
||||||
caddr_t up;
|
caddr_t up;
|
||||||
|
char * cpt;
|
||||||
|
|
||||||
|
|
||||||
#ifdef WLDEBUG
|
#ifdef WLDEBUG
|
||||||
@ -1075,20 +1223,21 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SIOCSIFFLAGS:
|
case SIOCSIFFLAGS:
|
||||||
/* TBD. further checkout. jrb
|
if (ifp->if_flags & IFF_ALLMULTI) {
|
||||||
*/
|
|
||||||
if (ifp->if_flags & IFF_ALLMULTI)
|
|
||||||
mode |= MOD_ENAL;
|
mode |= MOD_ENAL;
|
||||||
if (ifp->if_flags & IFF_PROMISC)
|
}
|
||||||
|
if (ifp->if_flags & IFF_PROMISC) {
|
||||||
mode |= MOD_PROM;
|
mode |= MOD_PROM;
|
||||||
if(ifp->if_flags & IFF_LINK0)
|
}
|
||||||
|
if(ifp->if_flags & IFF_LINK0) {
|
||||||
mode |= MOD_PROM;
|
mode |= MOD_PROM;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* force a complete reset if the recieve multicast/
|
* force a complete reset if the recieve multicast/
|
||||||
* promiscuous mode changes so that these take
|
* promiscuous mode changes so that these take
|
||||||
* effect immediately.
|
* effect immediately.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
if (sc->mode != mode) {
|
if (sc->mode != mode) {
|
||||||
sc->mode = mode;
|
sc->mode = mode;
|
||||||
if (sc->flags & DSF_RUNNING) {
|
if (sc->flags & DSF_RUNNING) {
|
||||||
@ -1097,8 +1246,8 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* if interface is marked DOWN and still running then
|
/* if interface is marked DOWN and still running then
|
||||||
* stop it.
|
* stop it.
|
||||||
*/
|
*/
|
||||||
if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
|
if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
|
||||||
printf("wl%d ioctl(): board is not running\n", unit);
|
printf("wl%d ioctl(): board is not running\n", unit);
|
||||||
sc->flags &= ~DSF_RUNNING;
|
sc->flags &= ~DSF_RUNNING;
|
||||||
@ -1112,22 +1261,35 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* if WLDEBUG set on interface, then printf rf-modem regs
|
/* if WLDEBUG set on interface, then printf rf-modem regs
|
||||||
*/
|
*/
|
||||||
if(ifp->if_flags & IFF_DEBUG)
|
if(ifp->if_flags & IFF_DEBUG)
|
||||||
wlmmcstat(unit);
|
wlmmcstat(unit);
|
||||||
break;
|
break;
|
||||||
#if MULTICAST
|
#if MULTICAST
|
||||||
case SIOCADDMULTI:
|
case SIOCADDMULTI:
|
||||||
case SIOCDELMULTI:
|
case SIOCDELMULTI:
|
||||||
#if __FreeBSD__ >= 3
|
|
||||||
if(sc->flags & DSF_RUNNING) {
|
#if __FreeBSD__ < 3
|
||||||
sc->flags &= ~DSF_RUNNING;
|
if (cmd == SIOCADDMULTI) {
|
||||||
wlinit(sc);
|
error = ether_addmulti(ifr, &sc->wl_ac);
|
||||||
}
|
}
|
||||||
#else
|
else {
|
||||||
error = (cmd == SIOCADDMULTI) ?
|
error = ether_delmulti(ifr, &sc->wl_ac);
|
||||||
ether_addmulti(ifr, &sc->wl_ac) :
|
}
|
||||||
ether_delmulti(ifr, &sc->wl_ac);
|
|
||||||
|
/* see if we should be in all multicast mode
|
||||||
|
* note that 82586 cannot do that, must simulate with
|
||||||
|
* promiscuous mode
|
||||||
|
*/
|
||||||
|
if ( check_allmulti(unit)) {
|
||||||
|
ifp->if_flags |= IFF_ALLMULTI;
|
||||||
|
sc->mode |= MOD_ENAL;
|
||||||
|
sc->flags &= ~DSF_RUNNING;
|
||||||
|
wlinit(sc);
|
||||||
|
error = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (error == ENETRESET) {
|
if (error == ENETRESET) {
|
||||||
if(sc->flags & DSF_RUNNING) {
|
if(sc->flags & DSF_RUNNING) {
|
||||||
sc->flags &= ~DSF_RUNNING;
|
sc->flags &= ~DSF_RUNNING;
|
||||||
@ -1139,6 +1301,9 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
break;
|
break;
|
||||||
#endif MULTICAST
|
#endif MULTICAST
|
||||||
|
|
||||||
|
/* DEVICE SPECIFIC */
|
||||||
|
|
||||||
|
|
||||||
/* copy the PSA out to the caller */
|
/* copy the PSA out to the caller */
|
||||||
case SIOCGWLPSA:
|
case SIOCGWLPSA:
|
||||||
/* pointer to buffer in user space */
|
/* pointer to buffer in user space */
|
||||||
@ -1155,6 +1320,7 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/* copy the PSA in from the caller; we only copy _some_ values */
|
/* copy the PSA in from the caller; we only copy _some_ values */
|
||||||
case SIOCSWLPSA:
|
case SIOCSWLPSA:
|
||||||
/* root only */
|
/* root only */
|
||||||
@ -1227,6 +1393,56 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
|
||||||
|
case SIOCGWLEEPROM:
|
||||||
|
/* root only */
|
||||||
|
if ((error = suser(p->p_ucred, &p->p_acflag)))
|
||||||
|
break;
|
||||||
|
/* pointer to buffer in user space */
|
||||||
|
up = (void *)ifr->ifr_data;
|
||||||
|
|
||||||
|
for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
|
||||||
|
MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
|
||||||
|
MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
|
||||||
|
MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
|
||||||
|
DELAY(40); /* 2.4 Gz */
|
||||||
|
if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
|
||||||
|
wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
|
||||||
|
) return(EFAULT); /* 2.4 Gz: */
|
||||||
|
if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
|
||||||
|
wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
|
||||||
|
) return(EFAULT); /* 2.4 Gz: */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef WLCACHE
|
||||||
|
/* zero (Delete) the wl cache */
|
||||||
|
case SIOCDWLCACHE:
|
||||||
|
/* root only */
|
||||||
|
if ((error = suser(p->p_ucred, &p->p_acflag)))
|
||||||
|
break;
|
||||||
|
wl_cache_zero(unit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* read out the number of used cache elements */
|
||||||
|
case SIOCGWLCITEM:
|
||||||
|
ifr->ifr_data = (caddr_t) sc->w_sigitems;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* read out the wl cache */
|
||||||
|
case SIOCGWLCACHE:
|
||||||
|
/* pointer to buffer in user space */
|
||||||
|
up = (void *)ifr->ifr_data;
|
||||||
|
cpt = (char *) &sc->w_sigcache[0];
|
||||||
|
size = sc->w_sigitems * sizeof(struct w_sigcache);
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (subyte((up + i), *cpt++))
|
||||||
|
return(EFAULT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
}
|
}
|
||||||
@ -1246,9 +1462,8 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
wlwatchdog(void *vsc)
|
wlwatchdog(struct wl_softc *sc)
|
||||||
{
|
{
|
||||||
struct wl_softc *sc = vsc;
|
|
||||||
int unit = sc->unit;
|
int unit = sc->unit;
|
||||||
|
|
||||||
log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
|
log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
|
||||||
@ -1395,7 +1610,7 @@ int unit;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sc->tbusy = 0;
|
sc->tbusy = 0;
|
||||||
untimeout(wlwatchdog, sc);
|
untimeout((timeout_func_t)wlwatchdog, sc);
|
||||||
sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
|
sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
|
||||||
wlstart(&(sc->wl_if));
|
wlstart(&(sc->wl_if));
|
||||||
}
|
}
|
||||||
@ -1840,7 +2055,7 @@ wlconfig(int unit)
|
|||||||
struct ether_multi *enm;
|
struct ether_multi *enm;
|
||||||
struct ether_multistep step;
|
struct ether_multistep step;
|
||||||
#endif
|
#endif
|
||||||
int cnt;
|
int cnt = 0;
|
||||||
#endif MULTICAST
|
#endif MULTICAST
|
||||||
|
|
||||||
#ifdef WLDEBUG
|
#ifdef WLDEBUG
|
||||||
@ -1889,8 +2104,9 @@ wlconfig(int unit)
|
|||||||
configure.hardware = 0x0008; /* tx even w/o CD */
|
configure.hardware = 0x0008; /* tx even w/o CD */
|
||||||
configure.min_frame_len = 0x0040;
|
configure.min_frame_len = 0x0040;
|
||||||
#endif
|
#endif
|
||||||
if(sc->mode & MOD_PROM)
|
if(sc->mode & (MOD_PROM | MOD_ENAL)) {
|
||||||
configure.hardware |= 1;
|
configure.hardware |= 1;
|
||||||
|
}
|
||||||
outw(PIOR1(base), OFFSET_CU + 6);
|
outw(PIOR1(base), OFFSET_CU + 6);
|
||||||
outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
|
outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
|
||||||
|
|
||||||
@ -1901,23 +2117,26 @@ wlconfig(int unit)
|
|||||||
outw(PIOP1(base), 0); /* ac_status */
|
outw(PIOP1(base), 0); /* ac_status */
|
||||||
outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
|
outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
|
||||||
outw(PIOR1(base), OFFSET_CU + 8);
|
outw(PIOR1(base), OFFSET_CU + 8);
|
||||||
cnt = 0;
|
|
||||||
#if __FreeBSD__ >= 3
|
#if __FreeBSD__ >= 3
|
||||||
for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
|
for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
|
||||||
ifma = ifma->ifma_link.le_next) {
|
ifma = ifma->ifma_link.le_next) {
|
||||||
if (ifma->ifma_addr->sa_family != AF_LINK)
|
if (ifma->ifma_addr->sa_family != AF_LINK)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
|
addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
|
||||||
outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
|
outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
|
||||||
outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
|
outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
|
||||||
outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
|
outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
|
||||||
++cnt;
|
++cnt;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
|
ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
|
||||||
while (enm != NULL) {
|
while (enm != NULL) {
|
||||||
unsigned int lo, hi;
|
unsigned int lo, hi;
|
||||||
|
/* break if setting a multicast range, else we would crash */
|
||||||
|
if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
|
lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
|
||||||
+ enm->enm_addrlo[5];
|
+ enm->enm_addrlo[5];
|
||||||
hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
|
hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
|
||||||
@ -1929,6 +2148,16 @@ wlconfig(int unit)
|
|||||||
((lo >> 8) & 0xff00));
|
((lo >> 8) & 0xff00));
|
||||||
outw(PIOP1(base), ((lo >> 8) & 0xff) +
|
outw(PIOP1(base), ((lo >> 8) & 0xff) +
|
||||||
((lo << 8) & 0xff00));
|
((lo << 8) & 0xff00));
|
||||||
|
/* #define MCASTDEBUG */
|
||||||
|
#ifdef MCASTDEBUG
|
||||||
|
printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
|
||||||
|
enm->enm_addrlo[0],
|
||||||
|
enm->enm_addrlo[1],
|
||||||
|
enm->enm_addrlo[2],
|
||||||
|
enm->enm_addrlo[3],
|
||||||
|
enm->enm_addrlo[4],
|
||||||
|
enm->enm_addrlo[5]);
|
||||||
|
#endif
|
||||||
++cnt;
|
++cnt;
|
||||||
++lo;
|
++lo;
|
||||||
}
|
}
|
||||||
@ -2282,3 +2511,213 @@ wlpsacrc(u_char *buf)
|
|||||||
}
|
}
|
||||||
return(crc);
|
return(crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WLCACHE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wl_cache_store
|
||||||
|
*
|
||||||
|
* take input packet and cache various radio hw characteristics
|
||||||
|
* indexed by MAC address.
|
||||||
|
*
|
||||||
|
* Some things to think about:
|
||||||
|
* note that no space is malloced.
|
||||||
|
* We might hash the mac address if the cache were bigger.
|
||||||
|
* It is not clear that the cache is big enough.
|
||||||
|
* It is also not clear how big it should be.
|
||||||
|
* The cache is IP-specific. We don't care about that as
|
||||||
|
* we want it to be IP-specific.
|
||||||
|
* The last N recv. packets are saved. This will tend
|
||||||
|
* to reward agents and mobile hosts that beacon.
|
||||||
|
* That is probably fine for mobile ip.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* globals for wavelan signal strength cache */
|
||||||
|
/* this should go into softc structure above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* set true if you want to limit cache items to broadcast/mcast
|
||||||
|
* only packets (not unicast)
|
||||||
|
*/
|
||||||
|
static int wl_cache_mcastonly = 1;
|
||||||
|
SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
|
||||||
|
&wl_cache_mcastonly, 0, "");
|
||||||
|
|
||||||
|
/* set true if you want to limit cache items to IP packets only
|
||||||
|
*/
|
||||||
|
static int wl_cache_iponly = 1;
|
||||||
|
SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
|
||||||
|
&wl_cache_iponly, 0, "");
|
||||||
|
|
||||||
|
/* zero out the cache
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
wl_cache_zero(int unit)
|
||||||
|
{
|
||||||
|
register struct wl_softc *sc = WLSOFTC(unit);
|
||||||
|
|
||||||
|
bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
|
||||||
|
sc->w_sigitems = 0;
|
||||||
|
sc->w_nextcache = 0;
|
||||||
|
sc->w_wrapindex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store hw signal info in cache.
|
||||||
|
* index is MAC address, but an ip src gets stored too
|
||||||
|
* There are two filters here controllable via sysctl:
|
||||||
|
* throw out unicast (on by default, but can be turned off)
|
||||||
|
* throw out non-ip (on by default, but can be turned off)
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void wl_cache_store (int unit, int base, struct ether_header *eh,
|
||||||
|
struct mbuf *m)
|
||||||
|
{
|
||||||
|
struct ip *ip;
|
||||||
|
int i;
|
||||||
|
int signal, silence;
|
||||||
|
int w_insertcache; /* computed index for cache entry storage */
|
||||||
|
register struct wl_softc *sc = WLSOFTC(unit);
|
||||||
|
int ipflag = wl_cache_iponly;
|
||||||
|
|
||||||
|
/* filters:
|
||||||
|
* 1. ip only
|
||||||
|
* 2. configurable filter to throw out unicast packets,
|
||||||
|
* keep multicast only.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* reject if not IP packet
|
||||||
|
*/
|
||||||
|
if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if broadcast or multicast packet. we toss
|
||||||
|
* unicast packets
|
||||||
|
*/
|
||||||
|
if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find the ip header. we want to store the ip_src
|
||||||
|
* address. use the mtod macro(in mbuf.h)
|
||||||
|
* to typecast m to struct ip *
|
||||||
|
*/
|
||||||
|
if (ipflag) {
|
||||||
|
ip = mtod(m, struct ip *);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do a linear search for a matching MAC address
|
||||||
|
* in the cache table
|
||||||
|
* . MAC address is 6 bytes,
|
||||||
|
* . var w_nextcache holds total number of entries already cached
|
||||||
|
*/
|
||||||
|
for(i = 0; i < sc->w_nextcache; i++) {
|
||||||
|
if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
|
||||||
|
/* Match!,
|
||||||
|
* so we already have this entry,
|
||||||
|
* update the data, and LRU age
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* did we find a matching mac address?
|
||||||
|
* if yes, then overwrite a previously existing cache entry
|
||||||
|
*/
|
||||||
|
if (i < sc->w_nextcache ) {
|
||||||
|
w_insertcache = i;
|
||||||
|
}
|
||||||
|
/* else, have a new address entry,so
|
||||||
|
* add this new entry,
|
||||||
|
* if table full, then we need to replace entry
|
||||||
|
*/
|
||||||
|
else {
|
||||||
|
|
||||||
|
/* check for space in cache table
|
||||||
|
* note: w_nextcache also holds number of entries
|
||||||
|
* added in the cache table
|
||||||
|
*/
|
||||||
|
if ( sc->w_nextcache < MAXCACHEITEMS ) {
|
||||||
|
w_insertcache = sc->w_nextcache;
|
||||||
|
sc->w_nextcache++;
|
||||||
|
sc->w_sigitems = sc->w_nextcache;
|
||||||
|
}
|
||||||
|
/* no space found, so simply wrap with wrap index
|
||||||
|
* and "zap" the next entry
|
||||||
|
*/
|
||||||
|
else {
|
||||||
|
if (sc->w_wrapindex == MAXCACHEITEMS) {
|
||||||
|
sc->w_wrapindex = 0;
|
||||||
|
}
|
||||||
|
w_insertcache = sc->w_wrapindex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* invariant: w_insertcache now points at some slot
|
||||||
|
* in cache.
|
||||||
|
*/
|
||||||
|
if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
|
||||||
|
log(LOG_ERR,
|
||||||
|
"wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
|
||||||
|
w_insertcache, MAXCACHEITEMS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store items in cache
|
||||||
|
* .ipsrc
|
||||||
|
* .macsrc
|
||||||
|
* .signal (0..63) ,silence (0..63) ,quality (0..15)
|
||||||
|
*/
|
||||||
|
if (ipflag) {
|
||||||
|
sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
|
||||||
|
}
|
||||||
|
bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
|
||||||
|
signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
|
||||||
|
silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
|
||||||
|
sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
|
||||||
|
if (signal > 0)
|
||||||
|
sc->w_sigcache[w_insertcache].snr =
|
||||||
|
signal - silence;
|
||||||
|
else
|
||||||
|
sc->w_sigcache[w_insertcache].snr = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif /* WLCACHE */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* determine if in all multicast mode or not
|
||||||
|
*
|
||||||
|
* returns: 1 if IFF_ALLMULTI should be set
|
||||||
|
* else 0
|
||||||
|
*/
|
||||||
|
#ifdef MULTICAST
|
||||||
|
|
||||||
|
#if __FreeBSD__ < 3 /* not required */
|
||||||
|
static int
|
||||||
|
check_allmulti(int unit)
|
||||||
|
{
|
||||||
|
register struct wl_softc *sc = WLSOFTC(unit);
|
||||||
|
short base = sc->base;
|
||||||
|
struct ether_multi *enm;
|
||||||
|
struct ether_multistep step;
|
||||||
|
|
||||||
|
ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
|
||||||
|
while (enm != NULL) {
|
||||||
|
unsigned int lo, hi;
|
||||||
|
#ifdef MDEBUG
|
||||||
|
printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
|
||||||
|
enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
|
||||||
|
enm->enm_addrlo[5]);
|
||||||
|
printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
|
||||||
|
enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
|
||||||
|
enm->enm_addrhi[5]);
|
||||||
|
#endif
|
||||||
|
if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
ETHER_NEXT_MULTI(step, enm);
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* $Id$ */
|
||||||
/*
|
/*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@ -33,6 +34,12 @@
|
|||||||
* Pruned heading comments for relevance.
|
* Pruned heading comments for relevance.
|
||||||
* Ripped out all the 'interface counters' cruft.
|
* Ripped out all the 'interface counters' cruft.
|
||||||
* Cut the missing-interrupt timer back to 100ms.
|
* Cut the missing-interrupt timer back to 100ms.
|
||||||
|
* 2.2.1 update:
|
||||||
|
* now supports all multicast mode (mrouted will work),
|
||||||
|
* but unfortunately must do that by going into promiscuous mode
|
||||||
|
* NWID sysctl added so that normally promiscuous mode is NWID-specific
|
||||||
|
* but can be made NWID-inspecific
|
||||||
|
* 7/14/97 jrb
|
||||||
*
|
*
|
||||||
* Work done:
|
* Work done:
|
||||||
* Ported to FreeBSD, got promiscuous mode working with bpfs,
|
* Ported to FreeBSD, got promiscuous mode working with bpfs,
|
||||||
@ -77,19 +84,45 @@
|
|||||||
* device wl0 at isa? port 0x300 net irq ? vector wlintr
|
* device wl0 at isa? port 0x300 net irq ? vector wlintr
|
||||||
*
|
*
|
||||||
* Ifdefs:
|
* Ifdefs:
|
||||||
* 1. IF_CNTRS - haven't tried it. Can get out various bits of info
|
* 1. WLDEBUG. (off) - if turned on enables IFF_DEBUG set via ifconfig debug
|
||||||
* from the rf-modem.
|
* 2. MULTICAST (on) - turned on and works up to and including mrouted
|
||||||
* 2. WLDEBUG if turned on enables IFF_DEBUG set via ifconfig debug
|
* 3. WLCACHE (off) - define to turn on a signal strength
|
||||||
* 3. MULTICAST - turned on and works in a few simple tests.
|
* (and other metric) cache that is indexed by sender MAC address.
|
||||||
|
* Apps can read this out to learn the remote signal strength of a
|
||||||
|
* sender. Note that it has a switch so that it only stores
|
||||||
|
* broadcast/multicast senders but it could be set to store unicast
|
||||||
|
* too only. Size is hardwired in if_wl_wavelan.h
|
||||||
*
|
*
|
||||||
* one further note: promiscuous mode is a curious thing. In this driver,
|
* one further note: promiscuous mode is a curious thing. In this driver,
|
||||||
* promiscuous mode apparently will catch ALL packets and ignore the NWID
|
* promiscuous mode apparently CAN catch ALL packets and ignore the NWID
|
||||||
* setting. This is probably more useful in a sense (for snoopers) if
|
* setting. This is probably more useful in a sense (for snoopers) if
|
||||||
* you are interested in all traffic as opposed to if you are interested
|
* you are interested in all traffic as opposed to if you are interested
|
||||||
* in just your own.
|
* in just your own. There is a driver specific sysctl to turn promiscuous
|
||||||
|
* from just promiscuous to wildly promiscuous...
|
||||||
|
*
|
||||||
|
* This driver also knows how to load the synthesizers in the 2.4 Gz
|
||||||
|
* ISA Half-card, Product number 847647476 (USA/FCC IEEE Channel set).
|
||||||
|
* This product consists of a "mothercard" that contains the 82586,
|
||||||
|
* NVRAM that holds the PSA, and the ISA-buss interface custom ASIC.
|
||||||
|
* The radio transceiver is a "daughtercard" called the WaveMODEM which
|
||||||
|
* connects to the mothercard through two single-inline connectors: a
|
||||||
|
* 20-pin connector provides DC-power and modem signals, and a 3-pin
|
||||||
|
* connector which exports the antenna connection. The code herein
|
||||||
|
* loads the receive and transmit synthesizers and the corresponding
|
||||||
|
* transmitter output power value from an EEPROM controlled through
|
||||||
|
* additional registers via the MMC. The EEPROM address selected
|
||||||
|
* are those whose values are preset by the DOS utility programs
|
||||||
|
* provided with the product, and this provides compatible operation
|
||||||
|
* with the DOS Packet Driver software. A future modification will
|
||||||
|
* add the necessary functionality to this driver and to the wlconfig
|
||||||
|
* utility to completely replace the DOS Configuration Utilities.
|
||||||
|
* The 2.4 Gz WaveMODEM is described in document number 407-024692/E,
|
||||||
|
* and is available through Lucent Technologies OEM supply channels.
|
||||||
|
* --RAB 1997/06/08.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MULTICAST 1
|
#define MULTICAST 1
|
||||||
|
#define WLCACHE 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Olivetti PC586 Mach Ethernet driver v1.0
|
* Olivetti PC586 Mach Ethernet driver v1.0
|
||||||
@ -173,9 +206,13 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||||||
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <net/if_dl.h>
|
#include <net/if_dl.h>
|
||||||
|
/* #include <net/if_types.h>*/
|
||||||
|
|
||||||
#ifdef INET
|
#ifdef INET
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/in_systm.h>
|
||||||
|
#include <netinet/in_var.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
#include <netinet/if_ether.h>
|
#include <netinet/if_ether.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -183,6 +220,7 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||||||
#include <net/bpf.h>
|
#include <net/bpf.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <machine/cpufunc.h>
|
||||||
#include <machine/clock.h>
|
#include <machine/clock.h>
|
||||||
|
|
||||||
#include <i386/isa/isa_device.h>
|
#include <i386/isa/isa_device.h>
|
||||||
@ -211,6 +249,15 @@ struct wl_softc{
|
|||||||
u_short end_rbd;
|
u_short end_rbd;
|
||||||
u_short hacr; /* latest host adapter CR command */
|
u_short hacr; /* latest host adapter CR command */
|
||||||
short mode;
|
short mode;
|
||||||
|
u_char chan24; /* 2.4 Gz: channel number/EEPROM Area # */
|
||||||
|
u_short freq24; /* 2.4 Gz: resulting frequency */
|
||||||
|
#ifdef WLCACHE
|
||||||
|
int w_sigitems; /* number of cached entries */
|
||||||
|
/* array of cache entries */
|
||||||
|
struct w_sigcache w_sigcache[ MAXCACHEITEMS ];
|
||||||
|
int w_nextcache; /* next free cache entry */
|
||||||
|
int w_wrapindex; /* next "free" cache entry */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
static struct wl_softc wl_softc[NWL];
|
static struct wl_softc wl_softc[NWL];
|
||||||
|
|
||||||
@ -227,11 +274,21 @@ struct isa_driver wldriver = {
|
|||||||
/*
|
/*
|
||||||
* XXX The Wavelan appears to be prone to dropping stuff if you talk to
|
* XXX The Wavelan appears to be prone to dropping stuff if you talk to
|
||||||
* it too fast. This disgusting hack inserts a delay after each packet
|
* it too fast. This disgusting hack inserts a delay after each packet
|
||||||
* is queued that helps avoid this behaviour on fast systems.
|
* is queued which helps avoid this behaviour on fast systems.
|
||||||
*/
|
*/
|
||||||
static int wl_xmit_delay = 0;
|
static int wl_xmit_delay = 250;
|
||||||
SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
|
SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* not XXX, but ZZZ (bizarre).
|
||||||
|
* promiscuous mode can be toggled to ignore NWIDs. By default,
|
||||||
|
* it does not. Caution should be exercised about combining
|
||||||
|
* this mode with IFF_ALLMULTI which puts this driver in
|
||||||
|
* promiscuous mode.
|
||||||
|
*/
|
||||||
|
static int wl_ignore_nwid = 0;
|
||||||
|
SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Emit diagnostics about transmission problems
|
* Emit diagnostics about transmission problems
|
||||||
*/
|
*/
|
||||||
@ -247,7 +304,7 @@ SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
|
|||||||
static void wlstart(struct ifnet *ifp);
|
static void wlstart(struct ifnet *ifp);
|
||||||
static void wlinit(void *xsc);
|
static void wlinit(void *xsc);
|
||||||
static int wlioctl(struct ifnet *ifp, int cmd, caddr_t data);
|
static int wlioctl(struct ifnet *ifp, int cmd, caddr_t data);
|
||||||
static timeout_t wlwatchdog;
|
static void wlwatchdog(struct wl_softc *sc);
|
||||||
static void wlxmt(int unt, struct mbuf *m);
|
static void wlxmt(int unt, struct mbuf *m);
|
||||||
static int wldiag(int unt);
|
static int wldiag(int unt);
|
||||||
static int wlconfig(int unit);
|
static int wlconfig(int unit);
|
||||||
@ -272,6 +329,15 @@ static void wlgetpsa(int base, u_char *buf);
|
|||||||
static void wlsetpsa(int unit);
|
static void wlsetpsa(int unit);
|
||||||
static u_short wlpsacrc(u_char *buf);
|
static u_short wlpsacrc(u_char *buf);
|
||||||
static void wldump(int unit);
|
static void wldump(int unit);
|
||||||
|
#ifdef WLCACHE
|
||||||
|
static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
|
||||||
|
static void wl_cache_zero(int unit);
|
||||||
|
#endif
|
||||||
|
#ifdef MULTICAST
|
||||||
|
# if __FreeBSD < 3
|
||||||
|
static int check_allmulti(int unit);
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/* array for maping irq numbers to values for the irq parameter register */
|
/* array for maping irq numbers to values for the irq parameter register */
|
||||||
static int irqvals[16] = {
|
static int irqvals[16] = {
|
||||||
@ -331,6 +397,9 @@ wlprobe(struct isa_device *id)
|
|||||||
if (bcmp(str, inbuf, strlen(str)))
|
if (bcmp(str, inbuf, strlen(str)))
|
||||||
return(0);
|
return(0);
|
||||||
|
|
||||||
|
sc->chan24 = 0; /* 2.4 Gz: config channel */
|
||||||
|
sc->freq24 = 0; /* 2.4 Gz: frequency */
|
||||||
|
|
||||||
/* read the PSA from the board into temporary storage */
|
/* read the PSA from the board into temporary storage */
|
||||||
wlgetpsa(base, inbuf);
|
wlgetpsa(base, inbuf);
|
||||||
|
|
||||||
@ -446,9 +515,14 @@ wlattach(struct isa_device *id)
|
|||||||
#if NBPFILTER > 0
|
#if NBPFILTER > 0
|
||||||
bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
|
bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
|
bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
|
||||||
printf("%s%d: address %6D, NWID 0x%02x%02x\n", ifp->if_name, ifp->if_unit,
|
printf("%s%d: address %6D, NWID 0x%02x%02x", ifp->if_name, ifp->if_unit,
|
||||||
sc->wl_ac.ac_enaddr, ":", sc->nwid[0], sc->nwid[1]);
|
sc->wl_ac.ac_enaddr, ":", sc->nwid[0], sc->nwid[1]);
|
||||||
|
if (sc->freq24)
|
||||||
|
printf(", Freq %d MHz",sc->freq24); /* 2.4 Gz */
|
||||||
|
printf("\n"); /* 2.4 Gz */
|
||||||
|
|
||||||
|
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
wldump(unit);
|
wldump(unit);
|
||||||
@ -494,6 +568,7 @@ wlinitmmc(int unit)
|
|||||||
int base = sp->base;
|
int base = sp->base;
|
||||||
int configured;
|
int configured;
|
||||||
int mode = sp->mode;
|
int mode = sp->mode;
|
||||||
|
int i; /* 2.4 Gz */
|
||||||
|
|
||||||
/* enter 8 bit operation */
|
/* enter 8 bit operation */
|
||||||
sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
|
sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
|
||||||
@ -523,7 +598,7 @@ wlinitmmc(int unit)
|
|||||||
} else {
|
} else {
|
||||||
/* use configuration defaults from parameter storage area */
|
/* use configuration defaults from parameter storage area */
|
||||||
if (sp->psa[WLPSA_NWIDENABLE] & 1) {
|
if (sp->psa[WLPSA_NWIDENABLE] & 1) {
|
||||||
if (mode & MOD_PROM) {
|
if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
|
||||||
MMC_WRITE(MMC_LOOPT_SEL, 0x40);
|
MMC_WRITE(MMC_LOOPT_SEL, 0x40);
|
||||||
} else {
|
} else {
|
||||||
MMC_WRITE(MMC_LOOPT_SEL, 0x00);
|
MMC_WRITE(MMC_LOOPT_SEL, 0x00);
|
||||||
@ -544,6 +619,44 @@ wlinitmmc(int unit)
|
|||||||
sp->hacr = HACR_DEFAULT;
|
sp->hacr = HACR_DEFAULT;
|
||||||
CMD(unit);
|
CMD(unit);
|
||||||
CMD(unit); /* virtualpc1 needs this! */
|
CMD(unit); /* virtualpc1 needs this! */
|
||||||
|
|
||||||
|
if (sp->psa[WLPSA_COMPATNO]== /* 2.4 Gz: half-card ver */
|
||||||
|
WLPSA_COMPATNO_WL24B) { /* 2.4 Gz */
|
||||||
|
i=sp->chan24<<4; /* 2.4 Gz: position ch # */
|
||||||
|
MMC_WRITE(MMC_EEADDR,i+0x0f); /* 2.4 Gz: named ch, wc=16 */
|
||||||
|
MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Synths */
|
||||||
|
MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
|
||||||
|
for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
|
||||||
|
DELAY(40); /* 2.4 Gz */
|
||||||
|
if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
|
||||||
|
&(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
|
||||||
|
+MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
|
||||||
|
break; /* 2.4 Gz: download finished */
|
||||||
|
} /* 2.4 Gz */
|
||||||
|
if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz */
|
||||||
|
MMC_WRITE(MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */
|
||||||
|
MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Xmit Pwr */
|
||||||
|
MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
|
||||||
|
for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
|
||||||
|
DELAY(40); /* 2.4 Gz */
|
||||||
|
if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
|
||||||
|
&(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
|
||||||
|
+MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
|
||||||
|
break; /* 2.4 Gz: download finished */
|
||||||
|
} /* 2.4 Gz */
|
||||||
|
if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz */
|
||||||
|
MMC_WRITE(MMC_ANALCTRL, /* 2.4 Gz: EXT ant+polarity */
|
||||||
|
MMC_ANALCTRL_ANTPOL + /* 2.4 Gz: */
|
||||||
|
MMC_ANALCTRL_EXTANT); /* 2.4 Gz: */
|
||||||
|
i=sp->chan24<<4; /* 2.4 Gz: position ch # */
|
||||||
|
MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
|
||||||
|
MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
|
||||||
|
MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
|
||||||
|
DELAY(40); /* 2.4 Gz */
|
||||||
|
i = wlmmcread(base,MMC_EEDATALrv) /* 2.4 Gz: freq val */
|
||||||
|
+ (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz */
|
||||||
|
sp->freq24 = (i>>6)+2400; /* 2.4 Gz: save real freq */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -571,13 +684,11 @@ wlinit(void *xsc)
|
|||||||
#endif
|
#endif
|
||||||
#if __FreeBSD__ >= 3
|
#if __FreeBSD__ >= 3
|
||||||
if (ifp->if_addrhead.tqh_first == (struct ifaddr *)0) {
|
if (ifp->if_addrhead.tqh_first == (struct ifaddr *)0) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
if (ifp->if_addrlist == (struct ifaddr *)0) {
|
if (ifp->if_addrlist == (struct ifaddr *)0) {
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
oldpri = splimp();
|
oldpri = splimp();
|
||||||
if ((stat = wlhwrst(sc->unit)) == TRUE) {
|
if ((stat = wlhwrst(sc->unit)) == TRUE) {
|
||||||
sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
|
sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
|
||||||
@ -589,7 +700,7 @@ wlinit(void *xsc)
|
|||||||
|
|
||||||
sc->flags |= DSF_RUNNING;
|
sc->flags |= DSF_RUNNING;
|
||||||
sc->tbusy = 0;
|
sc->tbusy = 0;
|
||||||
untimeout(wlwatchdog, sc);
|
untimeout((timeout_func_t)wlwatchdog, sc);
|
||||||
|
|
||||||
wlstart(ifp);
|
wlstart(ifp);
|
||||||
} else {
|
} else {
|
||||||
@ -760,7 +871,7 @@ wlstart(struct ifnet *ifp)
|
|||||||
if((scb_status & 0x0700) == SCB_CUS_IDLE &&
|
if((scb_status & 0x0700) == SCB_CUS_IDLE &&
|
||||||
(cu_status & AC_SW_B) == 0){
|
(cu_status & AC_SW_B) == 0){
|
||||||
sc->tbusy = 0;
|
sc->tbusy = 0;
|
||||||
untimeout(wlwatchdog, sc);
|
untimeout((timeout_func_t)wlwatchdog, sc);
|
||||||
sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
|
sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
|
||||||
/*
|
/*
|
||||||
* This is probably just a race. The xmt'r is just
|
* This is probably just a race. The xmt'r is just
|
||||||
@ -799,7 +910,7 @@ wlstart(struct ifnet *ifp)
|
|||||||
* fails to interrupt we will restart
|
* fails to interrupt we will restart
|
||||||
*/
|
*/
|
||||||
/* try 10 ticks, not very long */
|
/* try 10 ticks, not very long */
|
||||||
timeout(wlwatchdog, sc, 10);
|
timeout((timeout_func_t)wlwatchdog, sc, 10);
|
||||||
sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
|
sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
|
||||||
sc->wl_if.if_opackets++;
|
sc->wl_if.if_opackets++;
|
||||||
wlxmt(unit, m);
|
wlxmt(unit, m);
|
||||||
@ -902,11 +1013,23 @@ u_short fd_p;
|
|||||||
m->m_pkthdr.rcvif = ifp;
|
m->m_pkthdr.rcvif = ifp;
|
||||||
m->m_pkthdr.len = 0; /* don't know this yet */
|
m->m_pkthdr.len = 0; /* don't know this yet */
|
||||||
m->m_len = MHLEN;
|
m->m_len = MHLEN;
|
||||||
if (bytes_in_msg >= MINCLSIZE) {
|
|
||||||
MCLGET(m, M_DONTWAIT);
|
/* always use a cluster. jrb
|
||||||
if (m->m_flags & M_EXT)
|
*/
|
||||||
m->m_len = MCLBYTES;
|
MCLGET(m, M_DONTWAIT);
|
||||||
|
if (m->m_flags & M_EXT) {
|
||||||
|
m->m_len = MCLBYTES;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
m_freem(m);
|
||||||
|
if (wlhwrst(unit) != TRUE) {
|
||||||
|
sc->hacr &= ~HACR_INTRON;
|
||||||
|
CMD(unit); /* turn off interrupts */
|
||||||
|
printf("wl%d read(): hwrst trouble.\n", unit);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
mlen = 0;
|
mlen = 0;
|
||||||
clen = mlen;
|
clen = mlen;
|
||||||
bytes_in_mbuf = m->m_len;
|
bytes_in_mbuf = m->m_len;
|
||||||
@ -963,6 +1086,25 @@ u_short fd_p;
|
|||||||
|
|
||||||
m->m_pkthdr.len = clen;
|
m->m_pkthdr.len = clen;
|
||||||
|
|
||||||
|
#ifdef NOTYET
|
||||||
|
/* due to fact that controller does not support
|
||||||
|
* all multicast mode, we must filter out unicast packets
|
||||||
|
* that are not for us.
|
||||||
|
*
|
||||||
|
* if we are in all multicast mode and not promiscuous mode
|
||||||
|
* and packet is unicast and not for us,
|
||||||
|
* toss the packet
|
||||||
|
*
|
||||||
|
* TBD: also discard packets where NWID does not match.
|
||||||
|
*/
|
||||||
|
if ( (sc->mode & MOD_ENAL) && ((sc->mode & MOD_PROM) != 0) &&
|
||||||
|
((eh.ether_dhost[0] & 1) == 0) /* !mcast and !bcast */ &&
|
||||||
|
(bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
|
||||||
|
sizeof(eh.ether_dhost)) != 0) ) {
|
||||||
|
m_freem(m);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if NBPFILTER > 0
|
#if NBPFILTER > 0
|
||||||
/*
|
/*
|
||||||
* Check if there's a BPF listener on this interface. If so, hand off
|
* Check if there's a BPF listener on this interface. If so, hand off
|
||||||
@ -981,9 +1123,10 @@ u_short fd_p;
|
|||||||
bpf_mtap(ifp, &m0);
|
bpf_mtap(ifp, &m0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that the interface cannot be in promiscuous mode if
|
* point of this code is that even though we are in promiscuous
|
||||||
* there are no BPF listeners. And if we are in promiscuous
|
* mode, and due to fact that bpf got packet already, we
|
||||||
* mode, we have to check if this packet is really ours.
|
* do toss unicast packet not to us so that stacks upstairs
|
||||||
|
* do not need to weed it out
|
||||||
*
|
*
|
||||||
* logic: if promiscuous mode AND not multicast/bcast AND
|
* logic: if promiscuous mode AND not multicast/bcast AND
|
||||||
* not to us, throw away
|
* not to us, throw away
|
||||||
@ -1003,6 +1146,10 @@ u_short fd_p;
|
|||||||
printf("wl%d: wlrecv %d bytes\n", unit, clen);
|
printf("wl%d: wlrecv %d bytes\n", unit, clen);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WLCACHE
|
||||||
|
wl_cache_store(unit, base, &eh, m);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* received packet is now in a chain of mbuf's. next step is
|
* received packet is now in a chain of mbuf's. next step is
|
||||||
* to pass the packet upwards.
|
* to pass the packet upwards.
|
||||||
@ -1036,8 +1183,9 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
int opri, error = 0;
|
int opri, error = 0;
|
||||||
u_short tmp;
|
u_short tmp;
|
||||||
struct proc *p = curproc; /* XXX */
|
struct proc *p = curproc; /* XXX */
|
||||||
int irq, irqval, i, isroot;
|
int irq, irqval, i, isroot, size;
|
||||||
caddr_t up;
|
caddr_t up;
|
||||||
|
char * cpt;
|
||||||
|
|
||||||
|
|
||||||
#ifdef WLDEBUG
|
#ifdef WLDEBUG
|
||||||
@ -1075,20 +1223,21 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SIOCSIFFLAGS:
|
case SIOCSIFFLAGS:
|
||||||
/* TBD. further checkout. jrb
|
if (ifp->if_flags & IFF_ALLMULTI) {
|
||||||
*/
|
|
||||||
if (ifp->if_flags & IFF_ALLMULTI)
|
|
||||||
mode |= MOD_ENAL;
|
mode |= MOD_ENAL;
|
||||||
if (ifp->if_flags & IFF_PROMISC)
|
}
|
||||||
|
if (ifp->if_flags & IFF_PROMISC) {
|
||||||
mode |= MOD_PROM;
|
mode |= MOD_PROM;
|
||||||
if(ifp->if_flags & IFF_LINK0)
|
}
|
||||||
|
if(ifp->if_flags & IFF_LINK0) {
|
||||||
mode |= MOD_PROM;
|
mode |= MOD_PROM;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* force a complete reset if the recieve multicast/
|
* force a complete reset if the recieve multicast/
|
||||||
* promiscuous mode changes so that these take
|
* promiscuous mode changes so that these take
|
||||||
* effect immediately.
|
* effect immediately.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
if (sc->mode != mode) {
|
if (sc->mode != mode) {
|
||||||
sc->mode = mode;
|
sc->mode = mode;
|
||||||
if (sc->flags & DSF_RUNNING) {
|
if (sc->flags & DSF_RUNNING) {
|
||||||
@ -1097,8 +1246,8 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* if interface is marked DOWN and still running then
|
/* if interface is marked DOWN and still running then
|
||||||
* stop it.
|
* stop it.
|
||||||
*/
|
*/
|
||||||
if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
|
if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
|
||||||
printf("wl%d ioctl(): board is not running\n", unit);
|
printf("wl%d ioctl(): board is not running\n", unit);
|
||||||
sc->flags &= ~DSF_RUNNING;
|
sc->flags &= ~DSF_RUNNING;
|
||||||
@ -1112,22 +1261,35 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* if WLDEBUG set on interface, then printf rf-modem regs
|
/* if WLDEBUG set on interface, then printf rf-modem regs
|
||||||
*/
|
*/
|
||||||
if(ifp->if_flags & IFF_DEBUG)
|
if(ifp->if_flags & IFF_DEBUG)
|
||||||
wlmmcstat(unit);
|
wlmmcstat(unit);
|
||||||
break;
|
break;
|
||||||
#if MULTICAST
|
#if MULTICAST
|
||||||
case SIOCADDMULTI:
|
case SIOCADDMULTI:
|
||||||
case SIOCDELMULTI:
|
case SIOCDELMULTI:
|
||||||
#if __FreeBSD__ >= 3
|
|
||||||
if(sc->flags & DSF_RUNNING) {
|
#if __FreeBSD__ < 3
|
||||||
sc->flags &= ~DSF_RUNNING;
|
if (cmd == SIOCADDMULTI) {
|
||||||
wlinit(sc);
|
error = ether_addmulti(ifr, &sc->wl_ac);
|
||||||
}
|
}
|
||||||
#else
|
else {
|
||||||
error = (cmd == SIOCADDMULTI) ?
|
error = ether_delmulti(ifr, &sc->wl_ac);
|
||||||
ether_addmulti(ifr, &sc->wl_ac) :
|
}
|
||||||
ether_delmulti(ifr, &sc->wl_ac);
|
|
||||||
|
/* see if we should be in all multicast mode
|
||||||
|
* note that 82586 cannot do that, must simulate with
|
||||||
|
* promiscuous mode
|
||||||
|
*/
|
||||||
|
if ( check_allmulti(unit)) {
|
||||||
|
ifp->if_flags |= IFF_ALLMULTI;
|
||||||
|
sc->mode |= MOD_ENAL;
|
||||||
|
sc->flags &= ~DSF_RUNNING;
|
||||||
|
wlinit(sc);
|
||||||
|
error = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (error == ENETRESET) {
|
if (error == ENETRESET) {
|
||||||
if(sc->flags & DSF_RUNNING) {
|
if(sc->flags & DSF_RUNNING) {
|
||||||
sc->flags &= ~DSF_RUNNING;
|
sc->flags &= ~DSF_RUNNING;
|
||||||
@ -1139,6 +1301,9 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
break;
|
break;
|
||||||
#endif MULTICAST
|
#endif MULTICAST
|
||||||
|
|
||||||
|
/* DEVICE SPECIFIC */
|
||||||
|
|
||||||
|
|
||||||
/* copy the PSA out to the caller */
|
/* copy the PSA out to the caller */
|
||||||
case SIOCGWLPSA:
|
case SIOCGWLPSA:
|
||||||
/* pointer to buffer in user space */
|
/* pointer to buffer in user space */
|
||||||
@ -1155,6 +1320,7 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/* copy the PSA in from the caller; we only copy _some_ values */
|
/* copy the PSA in from the caller; we only copy _some_ values */
|
||||||
case SIOCSWLPSA:
|
case SIOCSWLPSA:
|
||||||
/* root only */
|
/* root only */
|
||||||
@ -1227,6 +1393,56 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
|
||||||
|
case SIOCGWLEEPROM:
|
||||||
|
/* root only */
|
||||||
|
if ((error = suser(p->p_ucred, &p->p_acflag)))
|
||||||
|
break;
|
||||||
|
/* pointer to buffer in user space */
|
||||||
|
up = (void *)ifr->ifr_data;
|
||||||
|
|
||||||
|
for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
|
||||||
|
MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
|
||||||
|
MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
|
||||||
|
MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
|
||||||
|
DELAY(40); /* 2.4 Gz */
|
||||||
|
if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
|
||||||
|
wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
|
||||||
|
) return(EFAULT); /* 2.4 Gz: */
|
||||||
|
if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
|
||||||
|
wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
|
||||||
|
) return(EFAULT); /* 2.4 Gz: */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef WLCACHE
|
||||||
|
/* zero (Delete) the wl cache */
|
||||||
|
case SIOCDWLCACHE:
|
||||||
|
/* root only */
|
||||||
|
if ((error = suser(p->p_ucred, &p->p_acflag)))
|
||||||
|
break;
|
||||||
|
wl_cache_zero(unit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* read out the number of used cache elements */
|
||||||
|
case SIOCGWLCITEM:
|
||||||
|
ifr->ifr_data = (caddr_t) sc->w_sigitems;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* read out the wl cache */
|
||||||
|
case SIOCGWLCACHE:
|
||||||
|
/* pointer to buffer in user space */
|
||||||
|
up = (void *)ifr->ifr_data;
|
||||||
|
cpt = (char *) &sc->w_sigcache[0];
|
||||||
|
size = sc->w_sigitems * sizeof(struct w_sigcache);
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (subyte((up + i), *cpt++))
|
||||||
|
return(EFAULT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
}
|
}
|
||||||
@ -1246,9 +1462,8 @@ wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
wlwatchdog(void *vsc)
|
wlwatchdog(struct wl_softc *sc)
|
||||||
{
|
{
|
||||||
struct wl_softc *sc = vsc;
|
|
||||||
int unit = sc->unit;
|
int unit = sc->unit;
|
||||||
|
|
||||||
log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
|
log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
|
||||||
@ -1395,7 +1610,7 @@ int unit;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sc->tbusy = 0;
|
sc->tbusy = 0;
|
||||||
untimeout(wlwatchdog, sc);
|
untimeout((timeout_func_t)wlwatchdog, sc);
|
||||||
sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
|
sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
|
||||||
wlstart(&(sc->wl_if));
|
wlstart(&(sc->wl_if));
|
||||||
}
|
}
|
||||||
@ -1840,7 +2055,7 @@ wlconfig(int unit)
|
|||||||
struct ether_multi *enm;
|
struct ether_multi *enm;
|
||||||
struct ether_multistep step;
|
struct ether_multistep step;
|
||||||
#endif
|
#endif
|
||||||
int cnt;
|
int cnt = 0;
|
||||||
#endif MULTICAST
|
#endif MULTICAST
|
||||||
|
|
||||||
#ifdef WLDEBUG
|
#ifdef WLDEBUG
|
||||||
@ -1889,8 +2104,9 @@ wlconfig(int unit)
|
|||||||
configure.hardware = 0x0008; /* tx even w/o CD */
|
configure.hardware = 0x0008; /* tx even w/o CD */
|
||||||
configure.min_frame_len = 0x0040;
|
configure.min_frame_len = 0x0040;
|
||||||
#endif
|
#endif
|
||||||
if(sc->mode & MOD_PROM)
|
if(sc->mode & (MOD_PROM | MOD_ENAL)) {
|
||||||
configure.hardware |= 1;
|
configure.hardware |= 1;
|
||||||
|
}
|
||||||
outw(PIOR1(base), OFFSET_CU + 6);
|
outw(PIOR1(base), OFFSET_CU + 6);
|
||||||
outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
|
outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
|
||||||
|
|
||||||
@ -1901,23 +2117,26 @@ wlconfig(int unit)
|
|||||||
outw(PIOP1(base), 0); /* ac_status */
|
outw(PIOP1(base), 0); /* ac_status */
|
||||||
outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
|
outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
|
||||||
outw(PIOR1(base), OFFSET_CU + 8);
|
outw(PIOR1(base), OFFSET_CU + 8);
|
||||||
cnt = 0;
|
|
||||||
#if __FreeBSD__ >= 3
|
#if __FreeBSD__ >= 3
|
||||||
for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
|
for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
|
||||||
ifma = ifma->ifma_link.le_next) {
|
ifma = ifma->ifma_link.le_next) {
|
||||||
if (ifma->ifma_addr->sa_family != AF_LINK)
|
if (ifma->ifma_addr->sa_family != AF_LINK)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
|
addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
|
||||||
outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
|
outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
|
||||||
outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
|
outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
|
||||||
outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
|
outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
|
||||||
++cnt;
|
++cnt;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
|
ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
|
||||||
while (enm != NULL) {
|
while (enm != NULL) {
|
||||||
unsigned int lo, hi;
|
unsigned int lo, hi;
|
||||||
|
/* break if setting a multicast range, else we would crash */
|
||||||
|
if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
|
lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
|
||||||
+ enm->enm_addrlo[5];
|
+ enm->enm_addrlo[5];
|
||||||
hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
|
hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
|
||||||
@ -1929,6 +2148,16 @@ wlconfig(int unit)
|
|||||||
((lo >> 8) & 0xff00));
|
((lo >> 8) & 0xff00));
|
||||||
outw(PIOP1(base), ((lo >> 8) & 0xff) +
|
outw(PIOP1(base), ((lo >> 8) & 0xff) +
|
||||||
((lo << 8) & 0xff00));
|
((lo << 8) & 0xff00));
|
||||||
|
/* #define MCASTDEBUG */
|
||||||
|
#ifdef MCASTDEBUG
|
||||||
|
printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
|
||||||
|
enm->enm_addrlo[0],
|
||||||
|
enm->enm_addrlo[1],
|
||||||
|
enm->enm_addrlo[2],
|
||||||
|
enm->enm_addrlo[3],
|
||||||
|
enm->enm_addrlo[4],
|
||||||
|
enm->enm_addrlo[5]);
|
||||||
|
#endif
|
||||||
++cnt;
|
++cnt;
|
||||||
++lo;
|
++lo;
|
||||||
}
|
}
|
||||||
@ -2282,3 +2511,213 @@ wlpsacrc(u_char *buf)
|
|||||||
}
|
}
|
||||||
return(crc);
|
return(crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WLCACHE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wl_cache_store
|
||||||
|
*
|
||||||
|
* take input packet and cache various radio hw characteristics
|
||||||
|
* indexed by MAC address.
|
||||||
|
*
|
||||||
|
* Some things to think about:
|
||||||
|
* note that no space is malloced.
|
||||||
|
* We might hash the mac address if the cache were bigger.
|
||||||
|
* It is not clear that the cache is big enough.
|
||||||
|
* It is also not clear how big it should be.
|
||||||
|
* The cache is IP-specific. We don't care about that as
|
||||||
|
* we want it to be IP-specific.
|
||||||
|
* The last N recv. packets are saved. This will tend
|
||||||
|
* to reward agents and mobile hosts that beacon.
|
||||||
|
* That is probably fine for mobile ip.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* globals for wavelan signal strength cache */
|
||||||
|
/* this should go into softc structure above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* set true if you want to limit cache items to broadcast/mcast
|
||||||
|
* only packets (not unicast)
|
||||||
|
*/
|
||||||
|
static int wl_cache_mcastonly = 1;
|
||||||
|
SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
|
||||||
|
&wl_cache_mcastonly, 0, "");
|
||||||
|
|
||||||
|
/* set true if you want to limit cache items to IP packets only
|
||||||
|
*/
|
||||||
|
static int wl_cache_iponly = 1;
|
||||||
|
SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
|
||||||
|
&wl_cache_iponly, 0, "");
|
||||||
|
|
||||||
|
/* zero out the cache
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
wl_cache_zero(int unit)
|
||||||
|
{
|
||||||
|
register struct wl_softc *sc = WLSOFTC(unit);
|
||||||
|
|
||||||
|
bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
|
||||||
|
sc->w_sigitems = 0;
|
||||||
|
sc->w_nextcache = 0;
|
||||||
|
sc->w_wrapindex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store hw signal info in cache.
|
||||||
|
* index is MAC address, but an ip src gets stored too
|
||||||
|
* There are two filters here controllable via sysctl:
|
||||||
|
* throw out unicast (on by default, but can be turned off)
|
||||||
|
* throw out non-ip (on by default, but can be turned off)
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void wl_cache_store (int unit, int base, struct ether_header *eh,
|
||||||
|
struct mbuf *m)
|
||||||
|
{
|
||||||
|
struct ip *ip;
|
||||||
|
int i;
|
||||||
|
int signal, silence;
|
||||||
|
int w_insertcache; /* computed index for cache entry storage */
|
||||||
|
register struct wl_softc *sc = WLSOFTC(unit);
|
||||||
|
int ipflag = wl_cache_iponly;
|
||||||
|
|
||||||
|
/* filters:
|
||||||
|
* 1. ip only
|
||||||
|
* 2. configurable filter to throw out unicast packets,
|
||||||
|
* keep multicast only.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* reject if not IP packet
|
||||||
|
*/
|
||||||
|
if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if broadcast or multicast packet. we toss
|
||||||
|
* unicast packets
|
||||||
|
*/
|
||||||
|
if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find the ip header. we want to store the ip_src
|
||||||
|
* address. use the mtod macro(in mbuf.h)
|
||||||
|
* to typecast m to struct ip *
|
||||||
|
*/
|
||||||
|
if (ipflag) {
|
||||||
|
ip = mtod(m, struct ip *);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do a linear search for a matching MAC address
|
||||||
|
* in the cache table
|
||||||
|
* . MAC address is 6 bytes,
|
||||||
|
* . var w_nextcache holds total number of entries already cached
|
||||||
|
*/
|
||||||
|
for(i = 0; i < sc->w_nextcache; i++) {
|
||||||
|
if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
|
||||||
|
/* Match!,
|
||||||
|
* so we already have this entry,
|
||||||
|
* update the data, and LRU age
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* did we find a matching mac address?
|
||||||
|
* if yes, then overwrite a previously existing cache entry
|
||||||
|
*/
|
||||||
|
if (i < sc->w_nextcache ) {
|
||||||
|
w_insertcache = i;
|
||||||
|
}
|
||||||
|
/* else, have a new address entry,so
|
||||||
|
* add this new entry,
|
||||||
|
* if table full, then we need to replace entry
|
||||||
|
*/
|
||||||
|
else {
|
||||||
|
|
||||||
|
/* check for space in cache table
|
||||||
|
* note: w_nextcache also holds number of entries
|
||||||
|
* added in the cache table
|
||||||
|
*/
|
||||||
|
if ( sc->w_nextcache < MAXCACHEITEMS ) {
|
||||||
|
w_insertcache = sc->w_nextcache;
|
||||||
|
sc->w_nextcache++;
|
||||||
|
sc->w_sigitems = sc->w_nextcache;
|
||||||
|
}
|
||||||
|
/* no space found, so simply wrap with wrap index
|
||||||
|
* and "zap" the next entry
|
||||||
|
*/
|
||||||
|
else {
|
||||||
|
if (sc->w_wrapindex == MAXCACHEITEMS) {
|
||||||
|
sc->w_wrapindex = 0;
|
||||||
|
}
|
||||||
|
w_insertcache = sc->w_wrapindex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* invariant: w_insertcache now points at some slot
|
||||||
|
* in cache.
|
||||||
|
*/
|
||||||
|
if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
|
||||||
|
log(LOG_ERR,
|
||||||
|
"wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
|
||||||
|
w_insertcache, MAXCACHEITEMS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store items in cache
|
||||||
|
* .ipsrc
|
||||||
|
* .macsrc
|
||||||
|
* .signal (0..63) ,silence (0..63) ,quality (0..15)
|
||||||
|
*/
|
||||||
|
if (ipflag) {
|
||||||
|
sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
|
||||||
|
}
|
||||||
|
bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
|
||||||
|
signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
|
||||||
|
silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
|
||||||
|
sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
|
||||||
|
if (signal > 0)
|
||||||
|
sc->w_sigcache[w_insertcache].snr =
|
||||||
|
signal - silence;
|
||||||
|
else
|
||||||
|
sc->w_sigcache[w_insertcache].snr = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif /* WLCACHE */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* determine if in all multicast mode or not
|
||||||
|
*
|
||||||
|
* returns: 1 if IFF_ALLMULTI should be set
|
||||||
|
* else 0
|
||||||
|
*/
|
||||||
|
#ifdef MULTICAST
|
||||||
|
|
||||||
|
#if __FreeBSD__ < 3 /* not required */
|
||||||
|
static int
|
||||||
|
check_allmulti(int unit)
|
||||||
|
{
|
||||||
|
register struct wl_softc *sc = WLSOFTC(unit);
|
||||||
|
short base = sc->base;
|
||||||
|
struct ether_multi *enm;
|
||||||
|
struct ether_multistep step;
|
||||||
|
|
||||||
|
ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
|
||||||
|
while (enm != NULL) {
|
||||||
|
unsigned int lo, hi;
|
||||||
|
#ifdef MDEBUG
|
||||||
|
printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
|
||||||
|
enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
|
||||||
|
enm->enm_addrlo[5]);
|
||||||
|
printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
|
||||||
|
enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
|
||||||
|
enm->enm_addrhi[5]);
|
||||||
|
#endif
|
||||||
|
if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
ETHER_NEXT_MULTI(step, enm);
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user