Added bpf support to if_is.c (Isolan driver)
This commit is contained in:
parent
4ba5f2985d
commit
ee4a642ef6
@ -1,39 +1,3 @@
|
|||||||
/*-
|
|
||||||
* Copyright (c) 1990, 1991 William F. Jolitz.
|
|
||||||
* Copyright (c) 1990 The Regents of the University of California.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* 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 University of
|
|
||||||
* California, Berkeley and its contributors.
|
|
||||||
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
|
|
||||||
*
|
|
||||||
* @(#)if_is.c
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Isolan AT 4141-0 Ethernet driver
|
* Isolan AT 4141-0 Ethernet driver
|
||||||
* Isolink 4110
|
* Isolink 4110
|
||||||
@ -42,22 +6,30 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* TODO
|
||||||
|
|
||||||
|
1) Add bpf and multicast support
|
||||||
|
2) Use better allocation of memory to card
|
||||||
|
3) Advertise for more packets until all transmit buffers are full
|
||||||
|
4) Add more of the timers/coutner e.g. arpcom.opackets etc.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "is.h"
|
#include "is.h"
|
||||||
#if NIS > 0
|
#if NIS > 0
|
||||||
|
|
||||||
|
#include "bpfilter.h"
|
||||||
|
|
||||||
#include "param.h"
|
#include "param.h"
|
||||||
#include "systm.h"
|
|
||||||
#include "mbuf.h"
|
|
||||||
#include "buf.h"
|
|
||||||
#include "protosw.h"
|
|
||||||
#include "socket.h"
|
|
||||||
#include "ioctl.h"
|
|
||||||
#include "errno.h"
|
#include "errno.h"
|
||||||
|
#include "ioctl.h"
|
||||||
|
#include "mbuf.h"
|
||||||
|
#include "socket.h"
|
||||||
#include "syslog.h"
|
#include "syslog.h"
|
||||||
|
|
||||||
#include "net/if.h"
|
#include "net/if.h"
|
||||||
|
#include "net/if_dl.h"
|
||||||
|
#include "net/if_types.h"
|
||||||
#include "net/netisr.h"
|
#include "net/netisr.h"
|
||||||
#include "net/route.h"
|
|
||||||
|
|
||||||
#ifdef INET
|
#ifdef INET
|
||||||
#include "netinet/in.h"
|
#include "netinet/in.h"
|
||||||
@ -72,36 +44,33 @@
|
|||||||
#include "netns/ns_if.h"
|
#include "netns/ns_if.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if NBPFILTER > 0
|
||||||
|
#include "net/bpf.h"
|
||||||
|
#include "net/bpfdesc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "i386/isa/isa_device.h"
|
#include "i386/isa/isa_device.h"
|
||||||
#include "i386/isa/if_isreg.h"
|
#include "i386/isa/if_isreg.h"
|
||||||
#include "i386/isa/icu.h"
|
#include "i386/isa/icu.h"
|
||||||
|
|
||||||
#include "vm/vm.h"
|
#include "vm/vm.h"
|
||||||
|
|
||||||
/* Function prototypes */
|
|
||||||
int isprobe(), isattach();
|
|
||||||
int isioctl(),isinit(),isstart();
|
|
||||||
|
|
||||||
struct isa_driver isdriver = {
|
|
||||||
isprobe, isattach, "is",
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct mbuf *isget();
|
|
||||||
|
|
||||||
#define ETHER_MIN_LEN 64
|
#define ETHER_MIN_LEN 64
|
||||||
|
#define ETHER_MAX_LEN 1518
|
||||||
|
#define ETHER_ADDR_LEN 6
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ethernet software status per interface.
|
* Ethernet software status per interface.
|
||||||
*
|
*
|
||||||
* Each interface is referenced by a network interface structure,
|
* Each interface is referenced by a network interface structure,
|
||||||
* is_if, which the routing code uses to locate the interface.
|
* arpcom.ac_if, which the routing code uses to locate the interface.
|
||||||
* This structure contains the output queue for the interface, its address, ...
|
* This structure contains the output queue for the interface, its address, ...
|
||||||
*/
|
*/
|
||||||
struct is_softc {
|
struct is_softc {
|
||||||
struct arpcom ns_ac; /* Ethernet common part */
|
struct arpcom arpcom; /* Ethernet common part */
|
||||||
#define is_if ns_ac.ac_if /* network-visible interface */
|
|
||||||
#define is_addr ns_ac.ac_enaddr /* hardware Ethernet address */
|
|
||||||
int iobase; /* IO base address of card */
|
int iobase; /* IO base address of card */
|
||||||
struct mds *rd;
|
struct mds *rd;
|
||||||
struct mds *td;
|
struct mds *td;
|
||||||
@ -110,10 +79,27 @@ struct is_softc {
|
|||||||
int last_rd;
|
int last_rd;
|
||||||
int last_td;
|
int last_td;
|
||||||
int no_td;
|
int no_td;
|
||||||
|
caddr_t bpf; /* BPF "magic cookie" */
|
||||||
|
|
||||||
} is_softc[NIS] ;
|
} is_softc[NIS] ;
|
||||||
|
|
||||||
struct init_block init_block[NIS];
|
struct init_block init_block[NIS];
|
||||||
|
|
||||||
|
/* Function prototypes */
|
||||||
|
int is_probe(),is_attach(),is_watchdog();
|
||||||
|
int is_ioctl(),is_init(),is_start();
|
||||||
|
|
||||||
|
static inline void is_rint(int unit);
|
||||||
|
static inline void isread(struct is_softc*, char*, int);
|
||||||
|
|
||||||
|
struct mbuf *isget();
|
||||||
|
|
||||||
|
struct isa_driver isdriver = {
|
||||||
|
is_probe,
|
||||||
|
is_attach,
|
||||||
|
"is"
|
||||||
|
};
|
||||||
|
|
||||||
iswrcsr(unit,port,val)
|
iswrcsr(unit,port,val)
|
||||||
int unit;
|
int unit;
|
||||||
u_short port;
|
u_short port;
|
||||||
@ -137,15 +123,14 @@ u_short isrdcsr(unit,port)
|
|||||||
return(inw(iobase+RDP));
|
return(inw(iobase+RDP));
|
||||||
}
|
}
|
||||||
|
|
||||||
isprobe(isdev)
|
is_probe(isa_dev)
|
||||||
struct isa_device *isdev;
|
struct isa_device *isa_dev;
|
||||||
{
|
{
|
||||||
int val,i,s;
|
int val,i,s;
|
||||||
int unit = isdev->id_unit ;
|
int unit = isa_dev->id_unit ;
|
||||||
register struct is_softc *is = &is_softc[unit];
|
register struct is_softc *is = &is_softc[unit];
|
||||||
|
|
||||||
is->iobase = isdev->id_iobase;
|
is->iobase = isa_dev->id_iobase;
|
||||||
s = splimp();
|
|
||||||
|
|
||||||
/* Stop the lance chip, put it known state */
|
/* Stop the lance chip, put it known state */
|
||||||
iswrcsr(unit,0,STOP);
|
iswrcsr(unit,0,STOP);
|
||||||
@ -160,9 +145,9 @@ isprobe(isdev)
|
|||||||
iswrcsr(unit,3, 0);
|
iswrcsr(unit,3, 0);
|
||||||
|
|
||||||
/* Extract board address */
|
/* Extract board address */
|
||||||
for(i=0; i < 6; i++) is->is_addr[i] = inb(is->iobase+(i*2));
|
for(i=0;i<ETHER_ADDR_LEN;i++)
|
||||||
|
is->arpcom.ac_enaddr[i]=inb(is->iobase+(i*2));
|
||||||
|
|
||||||
splx(s);
|
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,13 +156,15 @@ isprobe(isdev)
|
|||||||
/*
|
/*
|
||||||
* Reset of interface.
|
* Reset of interface.
|
||||||
*/
|
*/
|
||||||
isreset(unit, uban)
|
int is_reset(int unit)
|
||||||
int unit, uban;
|
|
||||||
{
|
{
|
||||||
|
int s;
|
||||||
if (unit >= NIS)
|
if (unit >= NIS)
|
||||||
return;
|
return;
|
||||||
|
s = splnet();
|
||||||
printf("is%d: reset\n", unit);
|
printf("is%d: reset\n", unit);
|
||||||
isinit(unit);
|
is_init(unit);
|
||||||
|
s = splx();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -185,28 +172,71 @@ isreset(unit, uban)
|
|||||||
* record. System will initialize the interface when it is ready
|
* record. System will initialize the interface when it is ready
|
||||||
* to accept packets. We get the ethernet address here.
|
* to accept packets. We get the ethernet address here.
|
||||||
*/
|
*/
|
||||||
isattach(isdev)
|
int is_attach(isa_dev)
|
||||||
struct isa_device *isdev;
|
struct isa_device *isa_dev;
|
||||||
{
|
{
|
||||||
int unit = isdev->id_unit;
|
int unit = isa_dev->id_unit;
|
||||||
register struct is_softc *is = &is_softc[unit];
|
struct is_softc *is = &is_softc[unit];
|
||||||
register struct ifnet *ifp = &is->is_if;
|
struct ifnet *ifp = &is->arpcom.ac_if;
|
||||||
|
struct ifaddr *ifa;
|
||||||
|
struct sockaddr_dl *sdl;
|
||||||
|
|
||||||
|
|
||||||
/* Set up DMA */
|
|
||||||
isa_dmacascade(isdev->id_drq);
|
|
||||||
|
|
||||||
ifp->if_unit = unit;
|
ifp->if_unit = unit;
|
||||||
ifp->if_name = isdriver.name ;
|
ifp->if_name = isdriver.name ;
|
||||||
ifp->if_mtu = ETHERMTU;
|
ifp->if_mtu = ETHERMTU;
|
||||||
printf (" ethernet address %s", ether_sprintf(is->is_addr)) ;
|
|
||||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
|
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
|
||||||
ifp->if_init = isinit;
|
ifp->if_init = is_init;
|
||||||
ifp->if_output = ether_output;
|
ifp->if_output = ether_output;
|
||||||
ifp->if_start = isstart;
|
ifp->if_start = is_start;
|
||||||
ifp->if_ioctl = isioctl;
|
ifp->if_ioctl = is_ioctl;
|
||||||
ifp->if_reset = isreset;
|
ifp->if_reset = is_reset;
|
||||||
ifp->if_watchdog = 0;
|
ifp->if_watchdog = is_watchdog;
|
||||||
|
|
||||||
|
/* Set up DMA */
|
||||||
|
isa_dmacascade(isa_dev->id_drq);
|
||||||
|
|
||||||
if_attach(ifp);
|
if_attach(ifp);
|
||||||
|
|
||||||
|
#if NBPFILTER > 0
|
||||||
|
bpfattach(&is->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Search down the ifa address list looking for the AF_LINK type
|
||||||
|
entry
|
||||||
|
*/
|
||||||
|
ifa = ifp->if_addrlist;
|
||||||
|
while ((ifa != 0) && (ifa->ifa_addr != 0) &&
|
||||||
|
(ifa->ifa_addr->sa_family != AF_LINK))
|
||||||
|
ifa = ifa->ifa_next;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we find an AF_LINK type entry, we will fill
|
||||||
|
* in the hardware address for this interface.
|
||||||
|
*/
|
||||||
|
if ((ifa != 0) && (ifa->ifa_addr != 0)) {
|
||||||
|
/*
|
||||||
|
* Fill in the link level address for this interface
|
||||||
|
*/
|
||||||
|
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
|
||||||
|
sdl->sdl_type = IFT_ETHER;
|
||||||
|
sdl->sdl_alen = ETHER_ADDR_LEN;
|
||||||
|
sdl->sdl_slen = 0;
|
||||||
|
bcopy(is->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf (" ethernet address %s", ether_sprintf(is->arpcom.ac_enaddr)) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
is_watchdog(unit)
|
||||||
|
int unit;
|
||||||
|
{
|
||||||
|
log(LOG_ERR, "is%d: device timeout\n", unit);
|
||||||
|
|
||||||
|
is_reset(unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -235,13 +265,7 @@ static u_char lance_mem[NIS][MAXMEM];
|
|||||||
|
|
||||||
init_block[unit].mode = 0;
|
init_block[unit].mode = 0;
|
||||||
|
|
||||||
/* Get ethernet address */
|
|
||||||
for (i=0; i<6; i++)
|
|
||||||
init_block[unit].padr[i] = is_softc[unit].is_addr[i];
|
|
||||||
|
|
||||||
/* Clear multicast address for now */
|
|
||||||
for (i=0; i<8; i++)
|
|
||||||
init_block[unit].ladrf[i] = 0;
|
|
||||||
|
|
||||||
init_block[unit].rdra = kvtop(is->rd);
|
init_block[unit].rdra = kvtop(is->rd);
|
||||||
init_block[unit].rlen = ((kvtop(is->rd) >> 16) & 0xff) | (RLEN<<13);
|
init_block[unit].rlen = ((kvtop(is->rd) >> 16) & 0xff) | (RLEN<<13);
|
||||||
@ -277,18 +301,19 @@ static u_char lance_mem[NIS][MAXMEM];
|
|||||||
* Initialization of interface; set up initialization block
|
* Initialization of interface; set up initialization block
|
||||||
* and transmit/receive descriptor rings.
|
* and transmit/receive descriptor rings.
|
||||||
*/
|
*/
|
||||||
isinit(unit)
|
is_init(unit)
|
||||||
int unit;
|
int unit;
|
||||||
{
|
{
|
||||||
register struct is_softc *is = &is_softc[unit];
|
register struct is_softc *is = &is_softc[unit];
|
||||||
struct ifnet *ifp = &is->is_if;
|
struct ifnet *ifp = &is->arpcom.ac_if;
|
||||||
int s;
|
int s;
|
||||||
register i;
|
register i;
|
||||||
|
|
||||||
|
/* Address not known */
|
||||||
if (ifp->if_addrlist == (struct ifaddr *)0) return;
|
if (ifp->if_addrlist == (struct ifaddr *)0) return;
|
||||||
|
|
||||||
|
s = splnet();
|
||||||
is->last_rd = is->last_td = is->no_td = 0;
|
is->last_rd = is->last_td = is->no_td = 0;
|
||||||
s = splimp();
|
|
||||||
|
|
||||||
/* Set up lance's memory area */
|
/* Set up lance's memory area */
|
||||||
init_mem(unit);
|
init_mem(unit);
|
||||||
@ -296,6 +321,20 @@ isinit(unit)
|
|||||||
/* Stop Lance to get access to other registers */
|
/* Stop Lance to get access to other registers */
|
||||||
iswrcsr(unit,0,STOP);
|
iswrcsr(unit,0,STOP);
|
||||||
|
|
||||||
|
/* Get ethernet address */
|
||||||
|
for (i=0; i<ETHER_ADDR_LEN; i++)
|
||||||
|
init_block[unit].padr[i] = is->arpcom.ac_enaddr[i];
|
||||||
|
|
||||||
|
#if NBPFILTER > 0
|
||||||
|
/*
|
||||||
|
* Initialize multicast address hashing registers to accept
|
||||||
|
* all multicasts (only used when in promiscuous mode)
|
||||||
|
*/
|
||||||
|
for (i = 0; i < 8; ++i)
|
||||||
|
init_block[unit].ladrf[i] = 0xff;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* I wish I knew what this was */
|
/* I wish I knew what this was */
|
||||||
iswrcsr(unit,3,0);
|
iswrcsr(unit,3,0);
|
||||||
|
|
||||||
@ -314,13 +353,15 @@ isinit(unit)
|
|||||||
if (isrdcsr(unit,0)&IDON) {
|
if (isrdcsr(unit,0)&IDON) {
|
||||||
/* Start lance */
|
/* Start lance */
|
||||||
iswrcsr(unit,0,STRT|IDON|INEA);
|
iswrcsr(unit,0,STRT|IDON|INEA);
|
||||||
is->is_if.if_flags |= IFF_RUNNING;
|
ifp->if_flags |= IFF_RUNNING;
|
||||||
isstart(ifp);
|
ifp->if_flags &= ~IFF_OACTIVE;
|
||||||
|
|
||||||
|
is_start(ifp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printf("Isolink card failed to initialise\n");
|
printf("Isolink card failed to initialise\n");
|
||||||
|
|
||||||
splx(s);
|
(void) splx(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -329,7 +370,7 @@ isinit(unit)
|
|||||||
* and map it to the interface before starting the output.
|
* and map it to the interface before starting the output.
|
||||||
* called only at splimp or interrupt level.
|
* called only at splimp or interrupt level.
|
||||||
*/
|
*/
|
||||||
isstart(ifp)
|
is_start(ifp)
|
||||||
struct ifnet *ifp;
|
struct ifnet *ifp;
|
||||||
{
|
{
|
||||||
int unit = ifp->if_unit;
|
int unit = ifp->if_unit;
|
||||||
@ -341,7 +382,7 @@ isstart(ifp)
|
|||||||
struct mds *cdm;
|
struct mds *cdm;
|
||||||
|
|
||||||
|
|
||||||
if ((is->is_if.if_flags & IFF_RUNNING) == 0)
|
if ((is->arpcom.ac_if.if_flags & IFF_RUNNING) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@ -349,7 +390,7 @@ isstart(ifp)
|
|||||||
if (cdm->flags&OWN)
|
if (cdm->flags&OWN)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
IF_DEQUEUE(&is->is_if.if_snd, m);
|
IF_DEQUEUE(&is->arpcom.ac_if.if_snd, m);
|
||||||
|
|
||||||
if (m == 0)
|
if (m == 0)
|
||||||
return;
|
return;
|
||||||
@ -365,6 +406,72 @@ isstart(ifp)
|
|||||||
buffer += m->m_len;
|
buffer += m->m_len;
|
||||||
len += m->m_len;
|
len += m->m_len;
|
||||||
}
|
}
|
||||||
|
#if NBPFILTER > 0
|
||||||
|
if (is->bpf) {
|
||||||
|
u_short etype;
|
||||||
|
int off, datasize, resid;
|
||||||
|
struct ether_header *eh;
|
||||||
|
struct trailer_header {
|
||||||
|
u_short ether_type;
|
||||||
|
u_short ether_residual;
|
||||||
|
} trailer_header;
|
||||||
|
char ether_packet[ETHER_MAX_LEN];
|
||||||
|
char *ep;
|
||||||
|
|
||||||
|
ep = ether_packet;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We handle trailers below:
|
||||||
|
* Copy ether header first, then residual data,
|
||||||
|
* then data. Put all this in a temporary buffer
|
||||||
|
* 'ether_packet' and send off to bpf. Since the
|
||||||
|
* system has generated this packet, we assume
|
||||||
|
* that all of the offsets in the packet are
|
||||||
|
* correct; if they're not, the system will almost
|
||||||
|
* certainly crash in m_copydata.
|
||||||
|
* We make no assumptions about how the data is
|
||||||
|
* arranged in the mbuf chain (i.e. how much
|
||||||
|
* data is in each mbuf, if mbuf clusters are
|
||||||
|
* used, etc.), which is why we use m_copydata
|
||||||
|
* to get the ether header rather than assume
|
||||||
|
* that this is located in the first mbuf.
|
||||||
|
*/
|
||||||
|
/* copy ether header */
|
||||||
|
m_copydata(m0, 0, sizeof(struct ether_header), ep);
|
||||||
|
eh = (struct ether_header *) ep;
|
||||||
|
ep += sizeof(struct ether_header);
|
||||||
|
etype = ntohs(eh->ether_type);
|
||||||
|
if (etype >= ETHERTYPE_TRAIL &&
|
||||||
|
etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
|
||||||
|
datasize = ((etype - ETHERTYPE_TRAIL) << 9);
|
||||||
|
off = datasize + sizeof(struct ether_header);
|
||||||
|
|
||||||
|
/* copy trailer_header into a data structure */
|
||||||
|
m_copydata(m0, off, sizeof(struct trailer_header),
|
||||||
|
&trailer_header.ether_type);
|
||||||
|
|
||||||
|
/* copy residual data */
|
||||||
|
resid = trailer_header.ether_residual -
|
||||||
|
sizeof(struct trailer_header);
|
||||||
|
resid = ntohs(resid);
|
||||||
|
m_copydata(m0, off+sizeof(struct trailer_header),
|
||||||
|
resid, ep);
|
||||||
|
ep += resid;
|
||||||
|
|
||||||
|
/* copy data */
|
||||||
|
m_copydata(m0, sizeof(struct ether_header),
|
||||||
|
datasize, ep);
|
||||||
|
ep += datasize;
|
||||||
|
|
||||||
|
/* restore original ether packet type */
|
||||||
|
eh->ether_type = trailer_header.ether_type;
|
||||||
|
|
||||||
|
bpf_tap(is->bpf, ether_packet, ep - ether_packet);
|
||||||
|
} else
|
||||||
|
bpf_mtap(is->bpf, m0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
m_freem(m0);
|
m_freem(m0);
|
||||||
len = MAX(len,ETHER_MIN_LEN);
|
len = MAX(len,ETHER_MIN_LEN);
|
||||||
@ -385,7 +492,7 @@ isstart(ifp)
|
|||||||
is->last_td=0;
|
is->last_td=0;
|
||||||
}while(++is->no_td < NTBUF);
|
}while(++is->no_td < NTBUF);
|
||||||
is->no_td = NTBUF;
|
is->no_td = NTBUF;
|
||||||
is->is_if.if_flags |= IFF_OACTIVE;
|
is->arpcom.ac_if.if_flags |= IFF_OACTIVE;
|
||||||
#if ISDEBUG >4
|
#if ISDEBUG >4
|
||||||
printf("no_td = %x, last_td = %x\n",is->no_td, is->last_td);
|
printf("no_td = %x, last_td = %x\n",is->no_td, is->last_td);
|
||||||
#endif
|
#endif
|
||||||
@ -415,19 +522,23 @@ isintr(unit)
|
|||||||
}
|
}
|
||||||
if (!(isr&RXON)) {
|
if (!(isr&RXON)) {
|
||||||
printf("!(isr&RXON)\n");
|
printf("!(isr&RXON)\n");
|
||||||
isreset(unit);
|
is_reset(unit);
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
if (!(isr&TXON)) {
|
if (!(isr&TXON)) {
|
||||||
printf("!(isr&TXON)\n");
|
printf("!(isr&TXON)\n");
|
||||||
isreset(unit);
|
is_reset(unit);
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isr&RINT) {
|
if (isr&RINT) {
|
||||||
isrint(unit);
|
/* reset watchdog timer */
|
||||||
|
is->arpcom.ac_if.if_timer = 0;
|
||||||
|
is_rint(unit);
|
||||||
}
|
}
|
||||||
if (isr&TINT) {
|
if (isr&TINT) {
|
||||||
|
/* reset watchdog timer */
|
||||||
|
is->arpcom.ac_if.if_timer = 0;
|
||||||
iswrcsr(unit,0,TINT|INEA);
|
iswrcsr(unit,0,TINT|INEA);
|
||||||
istint(unit);
|
istint(unit);
|
||||||
}
|
}
|
||||||
@ -438,7 +549,7 @@ istint(unit)
|
|||||||
int unit;
|
int unit;
|
||||||
{
|
{
|
||||||
struct is_softc *is = &is_softc[unit];
|
struct is_softc *is = &is_softc[unit];
|
||||||
register struct ifnet *ifp = &is->is_if;
|
register struct ifnet *ifp = &is->arpcom.ac_if;
|
||||||
int i,loopcount=0;
|
int i,loopcount=0;
|
||||||
struct mds *cdm;
|
struct mds *cdm;
|
||||||
|
|
||||||
@ -455,17 +566,17 @@ istint(unit)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
loopcount++;
|
loopcount++;
|
||||||
is->is_if.if_flags &= ~IFF_OACTIVE;
|
is->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
|
||||||
}while(--is->no_td > 0);
|
}while(--is->no_td > 0);
|
||||||
isstart(ifp);
|
is_start(ifp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NEXTRDS \
|
#define NEXTRDS \
|
||||||
if (++rmd == NRBUF) rmd=0, cdm=is->rd; else ++cdm
|
if (++rmd == NRBUF) rmd=0, cdm=is->rd; else ++cdm
|
||||||
|
|
||||||
isrint(unit)
|
/* only called from one place, so may as well integrate */
|
||||||
int unit;
|
static inline void is_rint(int unit)
|
||||||
{
|
{
|
||||||
register struct is_softc *is=&is_softc[unit];
|
register struct is_softc *is=&is_softc[unit];
|
||||||
register int rmd = is->last_rd;
|
register int rmd = is->last_rd;
|
||||||
@ -503,7 +614,7 @@ isrint(unit)
|
|||||||
is->last_rd = rmd;
|
is->last_rd = rmd;
|
||||||
printf("is%d:Chained buffer\n",unit);
|
printf("is%d:Chained buffer\n",unit);
|
||||||
if ((cdm->flags & (OWN|ERR|STP|ENP)) != ENP) {
|
if ((cdm->flags & (OWN|ERR|STP|ENP)) != ENP) {
|
||||||
isreset(unit);
|
is_reset(unit);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}else
|
}else
|
||||||
@ -522,53 +633,78 @@ isrint(unit)
|
|||||||
#endif
|
#endif
|
||||||
} /* while */
|
} /* while */
|
||||||
is->last_rd = rmd;
|
is->last_rd = rmd;
|
||||||
} /* isrint */
|
} /* is_rint */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pass a packet to the higher levels.
|
* Pass a packet to the higher levels.
|
||||||
* We deal with the trailer protocol here.
|
* We deal with the trailer protocol here.
|
||||||
*/
|
*/
|
||||||
isread(is, buf, len)
|
static inline void isread(struct is_softc *is, char *buf, int len)
|
||||||
register struct is_softc *is;
|
|
||||||
char *buf;
|
|
||||||
int len;
|
|
||||||
{
|
{
|
||||||
register struct ether_header *eh;
|
register struct ether_header *eh;
|
||||||
struct mbuf *m;
|
struct mbuf *m;
|
||||||
int off, resid;
|
int off, resid;
|
||||||
register struct ifqueue *inq;
|
register struct ifqueue *inq;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Deal with trailer protocol: if type is trailer type
|
* Deal with trailer protocol: if type is trailer type
|
||||||
* get true type from first 16-bit word past data.
|
* get true type from first 16-bit word past data.
|
||||||
* Remember that type was trailer by setting off.
|
* Remember that type was trailer by setting off.
|
||||||
*/
|
*/
|
||||||
eh = (struct ether_header *)buf;
|
eh = (struct ether_header *)buf;
|
||||||
eh->ether_type = ntohs((u_short)eh->ether_type);
|
eh->ether_type = ntohs((u_short)eh->ether_type);
|
||||||
len = len - sizeof(struct ether_header) - 4;
|
len = len - sizeof(struct ether_header) - 4;
|
||||||
#define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
|
#define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
|
||||||
if (eh->ether_type >= ETHERTYPE_TRAIL &&
|
if (eh->ether_type >= ETHERTYPE_TRAIL &&
|
||||||
eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
|
eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
|
||||||
off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
|
off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
|
||||||
if (off >= ETHERMTU) return; /* sanity */
|
if (off >= ETHERMTU) return; /* sanity */
|
||||||
eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
|
eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
|
||||||
resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
|
resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
|
||||||
if (off + resid > len) return; /* sanity */
|
if (off + resid > len) return; /* sanity */
|
||||||
len = off + resid;
|
len = off + resid;
|
||||||
} else off = 0;
|
} else off = 0;
|
||||||
|
|
||||||
if (len == 0) return;
|
if (len == 0) return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pull packet off interface. Off is nonzero if packet
|
* Pull packet off interface. Off is nonzero if packet
|
||||||
* has trailing header; neget will then force this header
|
* has trailing header; neget will then force this header
|
||||||
* information to be at the front, but we still have to drop
|
* information to be at the front, but we still have to drop
|
||||||
* the type and length which are at the front of any trailer data.
|
* the type and length which are at the front of any trailer data.
|
||||||
*/
|
*/
|
||||||
m = isget(buf, len, off, &is->is_if);
|
m = isget(buf, len, off, &is->arpcom.ac_if);
|
||||||
if (m == 0) return;
|
if (m == 0) return;
|
||||||
|
#if NBPFILTER > 0
|
||||||
|
/*
|
||||||
|
* Check if there's a BPF listener on this interface.
|
||||||
|
* If so, hand off the raw packet to bpf.
|
||||||
|
*/
|
||||||
|
if (is->bpf) {
|
||||||
|
bpf_mtap(is->bpf, m);
|
||||||
|
|
||||||
ether_input(&is->is_if, eh, m);
|
/*
|
||||||
|
* Note that the interface cannot be in promiscuous mode if
|
||||||
|
* there are no BPF listeners. And if we are in promiscuous
|
||||||
|
* mode, we have to check if this packet is really ours.
|
||||||
|
*
|
||||||
|
* XXX This test does not support multicasts.
|
||||||
|
*/
|
||||||
|
if ((is->arpcom.ac_if.if_flags & IFF_PROMISC) &&
|
||||||
|
bcmp(eh->ether_dhost, is->arpcom.ac_enaddr,
|
||||||
|
sizeof(eh->ether_dhost)) != 0 &&
|
||||||
|
bcmp(eh->ether_dhost, etherbroadcastaddr,
|
||||||
|
sizeof(eh->ether_dhost)) != 0) {
|
||||||
|
|
||||||
|
m_freem(m);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
ether_input(&is->arpcom.ac_if, eh, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -586,76 +722,76 @@ isread(is, buf, len)
|
|||||||
*/
|
*/
|
||||||
struct mbuf *
|
struct mbuf *
|
||||||
isget(buf, totlen, off0, ifp)
|
isget(buf, totlen, off0, ifp)
|
||||||
caddr_t buf;
|
caddr_t buf;
|
||||||
int totlen, off0;
|
int totlen, off0;
|
||||||
struct ifnet *ifp;
|
struct ifnet *ifp;
|
||||||
{
|
{
|
||||||
struct mbuf *top, **mp, *m, *p;
|
struct mbuf *top, **mp, *m, *p;
|
||||||
int off = off0, len;
|
int off = off0, len;
|
||||||
register caddr_t cp = buf;
|
register caddr_t cp = buf;
|
||||||
char *epkt;
|
char *epkt;
|
||||||
|
|
||||||
buf += sizeof(struct ether_header);
|
buf += sizeof(struct ether_header);
|
||||||
cp = buf;
|
cp = buf;
|
||||||
epkt = cp + totlen;
|
epkt = cp + totlen;
|
||||||
|
|
||||||
|
|
||||||
if (off) {
|
if (off) {
|
||||||
cp += off + 2 * sizeof(u_short);
|
cp += off + 2 * sizeof(u_short);
|
||||||
totlen -= 2 * sizeof(u_short);
|
totlen -= 2 * sizeof(u_short);
|
||||||
}
|
}
|
||||||
|
|
||||||
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
||||||
if (m == 0)
|
if (m == 0)
|
||||||
return (0);
|
return (0);
|
||||||
m->m_pkthdr.rcvif = ifp;
|
m->m_pkthdr.rcvif = ifp;
|
||||||
m->m_pkthdr.len = totlen;
|
m->m_pkthdr.len = totlen;
|
||||||
m->m_len = MHLEN;
|
m->m_len = MHLEN;
|
||||||
|
top = 0;
|
||||||
top = 0;
|
mp = ⊤
|
||||||
mp = ⊤
|
while (totlen > 0) {
|
||||||
while (totlen > 0) {
|
if (top) {
|
||||||
if (top) {
|
MGET(m, M_DONTWAIT, MT_DATA);
|
||||||
MGET(m, M_DONTWAIT, MT_DATA);
|
if (m == 0) {
|
||||||
if (m == 0) {
|
m_freem(top);
|
||||||
m_freem(top);
|
return (0);
|
||||||
return (0);
|
}
|
||||||
}
|
m->m_len = MLEN;
|
||||||
m->m_len = MLEN;
|
}
|
||||||
}
|
len = min(totlen, epkt - cp);
|
||||||
len = min(totlen, epkt - cp);
|
if (len >= MINCLSIZE) {
|
||||||
if (len >= MINCLSIZE) {
|
MCLGET(m, M_DONTWAIT);
|
||||||
MCLGET(m, M_DONTWAIT);
|
if (m->m_flags & M_EXT)
|
||||||
if (m->m_flags & M_EXT)
|
m->m_len = len = min(len, MCLBYTES);
|
||||||
m->m_len = len = min(len, MCLBYTES);
|
else
|
||||||
else
|
len = m->m_len;
|
||||||
len = m->m_len;
|
} else {
|
||||||
} else {
|
/*
|
||||||
/*
|
* Place initial small packet/header at end of mbuf.
|
||||||
* Place initial small packet/header at end of mbuf.
|
*/
|
||||||
*/
|
if (len < m->m_len) {
|
||||||
if (len < m->m_len) {
|
if (top == 0 && len + max_linkhdr <= m->m_len)
|
||||||
if (top == 0 && len + max_linkhdr <= m->m_len)
|
m->m_data += max_linkhdr;
|
||||||
m->m_data += max_linkhdr;
|
m->m_len = len;
|
||||||
m->m_len = len;
|
} else
|
||||||
} else
|
len = m->m_len;
|
||||||
len = m->m_len;
|
}
|
||||||
}
|
bcopy(cp, mtod(m, caddr_t), (unsigned)len);
|
||||||
bcopy(cp, mtod(m, caddr_t), (unsigned)len);
|
cp += len;
|
||||||
cp += len;
|
*mp = m;
|
||||||
*mp = m;
|
mp = &m->m_next;
|
||||||
mp = &m->m_next;
|
totlen -= len;
|
||||||
totlen -= len;
|
if (cp == epkt)
|
||||||
if (cp == epkt)
|
cp = buf;
|
||||||
cp = buf;
|
}
|
||||||
}
|
return (top);
|
||||||
return (top);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process an ioctl request.
|
* Process an ioctl request.
|
||||||
*/
|
*/
|
||||||
isioctl(ifp, cmd, data)
|
is_ioctl(ifp, cmd, data)
|
||||||
register struct ifnet *ifp;
|
register struct ifnet *ifp;
|
||||||
int cmd;
|
int cmd;
|
||||||
caddr_t data;
|
caddr_t data;
|
||||||
@ -664,8 +800,9 @@ isioctl(ifp, cmd, data)
|
|||||||
int unit = ifp->if_unit;
|
int unit = ifp->if_unit;
|
||||||
struct is_softc *is = &is_softc[unit];
|
struct is_softc *is = &is_softc[unit];
|
||||||
struct ifreq *ifr = (struct ifreq *)data;
|
struct ifreq *ifr = (struct ifreq *)data;
|
||||||
int s = splimp(), error = 0;
|
int s, error = 0;
|
||||||
|
|
||||||
|
s = splnet();
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
|
||||||
@ -675,60 +812,94 @@ isioctl(ifp, cmd, data)
|
|||||||
switch (ifa->ifa_addr->sa_family) {
|
switch (ifa->ifa_addr->sa_family) {
|
||||||
#ifdef INET
|
#ifdef INET
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
isinit(ifp->if_unit); /* before arpwhohas */
|
is_init(ifp->if_unit); /* before arpwhohas */
|
||||||
|
/*
|
||||||
|
* See if another station has *our* IP address.
|
||||||
|
* i.e.: There is an address conflict! If a
|
||||||
|
* conflict exists, a message is sent to the
|
||||||
|
* console.
|
||||||
|
*/
|
||||||
((struct arpcom *)ifp)->ac_ipaddr =
|
((struct arpcom *)ifp)->ac_ipaddr =
|
||||||
IA_SIN(ifa)->sin_addr;
|
IA_SIN(ifa)->sin_addr;
|
||||||
arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
|
arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef NS
|
#ifdef NS
|
||||||
|
/*
|
||||||
|
* XXX - This code is probably wrong
|
||||||
|
*/
|
||||||
case AF_NS:
|
case AF_NS:
|
||||||
{
|
{
|
||||||
register struct is_addr *ina = &(IA_SNS(ifa)->sns_addr);
|
register struct arpcom.ac_enaddr *ina = &(IA_SNS(ifa)->sns_addr);
|
||||||
|
|
||||||
if (ns_nullhost(*ina))
|
if (ns_nullhost(*ina))
|
||||||
ina->x_host = *(union ns_host *)(is->is_addr);
|
ina->x_host = *(union ns_host *)(is->arpcom.ac_enaddr);
|
||||||
else {
|
else {
|
||||||
/*
|
/*
|
||||||
* The manual says we can't change the address
|
|
||||||
* while the receiver is armed,
|
|
||||||
* so reset everything
|
|
||||||
*/
|
*/
|
||||||
ifp->if_flags &= ~IFF_RUNNING;
|
|
||||||
bcopy((caddr_t)ina->x_host.c_host,
|
bcopy((caddr_t)ina->x_host.c_host,
|
||||||
(caddr_t)is->is_addr, sizeof(is->is_addr));
|
(caddr_t)is->arpcom.ac_enaddr, sizeof(is->arpcom.ac_enaddr));
|
||||||
}
|
}
|
||||||
isinit(ifp->if_unit); /* does ne_setaddr() */
|
/*
|
||||||
|
* Set new address
|
||||||
|
*/
|
||||||
|
is_init(ifp->if_unit);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
isinit(ifp->if_unit);
|
is_init(ifp->if_unit);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SIOCSIFFLAGS:
|
case SIOCSIFFLAGS:
|
||||||
|
/*
|
||||||
|
* If interface is marked down and it is running, then stop it
|
||||||
|
*/
|
||||||
if ((ifp->if_flags & IFF_UP) == 0 &&
|
if ((ifp->if_flags & IFF_UP) == 0 &&
|
||||||
ifp->if_flags & IFF_RUNNING) {
|
ifp->if_flags & IFF_RUNNING) {
|
||||||
ifp->if_flags &= ~IFF_RUNNING;
|
|
||||||
iswrcsr(unit,0,STOP);
|
iswrcsr(unit,0,STOP);
|
||||||
} else if (ifp->if_flags & IFF_UP &&
|
ifp->if_flags &= ~IFF_RUNNING;
|
||||||
(ifp->if_flags & IFF_RUNNING) == 0)
|
} else {
|
||||||
isinit(ifp->if_unit);
|
/*
|
||||||
|
* If interface is marked up and it is stopped, then start it
|
||||||
|
*/
|
||||||
|
if ((ifp->if_flags & IFF_UP) &&
|
||||||
|
(ifp->if_flags & IFF_RUNNING) == 0)
|
||||||
|
is_init(ifp->if_unit);
|
||||||
|
}
|
||||||
|
#if NBPFILTER > 0
|
||||||
|
if (ifp->if_flags & IFF_PROMISC) {
|
||||||
|
/*
|
||||||
|
* Set promiscuous mode on interface.
|
||||||
|
* XXX - for multicasts to work, we would need to
|
||||||
|
* write 1's in all bits of multicast
|
||||||
|
* hashing array. For now we assume that
|
||||||
|
* this was done in is_init().
|
||||||
|
*/
|
||||||
|
init_block[unit].mode = PROM;
|
||||||
|
} else
|
||||||
|
/*
|
||||||
|
* XXX - for multicasts to work, we would need to
|
||||||
|
* rewrite the multicast hashing array with the
|
||||||
|
* proper hash (would have been destroyed above).
|
||||||
|
*/
|
||||||
|
{ /* Don't know about this */};
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef notdef
|
#ifdef notdef
|
||||||
case SIOCGHWADDR:
|
case SIOCGHWADDR:
|
||||||
bcopy((caddr_t)is->is_addr, (caddr_t) &ifr->ifr_data,
|
bcopy((caddr_t)is->arpcom.ac_enaddr, (caddr_t) &ifr->ifr_data,
|
||||||
sizeof(is->is_addr));
|
sizeof(is->arpcom.ac_enaddr));
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
}
|
}
|
||||||
splx(s);
|
(void) splx(s);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user