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
|
||||
* 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"
|
||||
#if NIS > 0
|
||||
|
||||
#include "bpfilter.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 "ioctl.h"
|
||||
#include "mbuf.h"
|
||||
#include "socket.h"
|
||||
#include "syslog.h"
|
||||
|
||||
#include "net/if.h"
|
||||
#include "net/if_dl.h"
|
||||
#include "net/if_types.h"
|
||||
#include "net/netisr.h"
|
||||
#include "net/route.h"
|
||||
|
||||
#ifdef INET
|
||||
#include "netinet/in.h"
|
||||
@ -72,36 +44,33 @@
|
||||
#include "netns/ns_if.h"
|
||||
#endif
|
||||
|
||||
#if NBPFILTER > 0
|
||||
#include "net/bpf.h"
|
||||
#include "net/bpfdesc.h"
|
||||
#endif
|
||||
|
||||
#include "i386/isa/isa_device.h"
|
||||
#include "i386/isa/if_isreg.h"
|
||||
#include "i386/isa/icu.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_MAX_LEN 1518
|
||||
#define ETHER_ADDR_LEN 6
|
||||
|
||||
|
||||
/*
|
||||
* Ethernet software status per interface.
|
||||
*
|
||||
* 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, ...
|
||||
*/
|
||||
struct is_softc {
|
||||
struct arpcom ns_ac; /* Ethernet common part */
|
||||
#define is_if ns_ac.ac_if /* network-visible interface */
|
||||
#define is_addr ns_ac.ac_enaddr /* hardware Ethernet address */
|
||||
struct arpcom arpcom; /* Ethernet common part */
|
||||
int iobase; /* IO base address of card */
|
||||
struct mds *rd;
|
||||
struct mds *td;
|
||||
@ -110,10 +79,27 @@ struct is_softc {
|
||||
int last_rd;
|
||||
int last_td;
|
||||
int no_td;
|
||||
caddr_t bpf; /* BPF "magic cookie" */
|
||||
|
||||
} is_softc[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)
|
||||
int unit;
|
||||
u_short port;
|
||||
@ -137,15 +123,14 @@ u_short isrdcsr(unit,port)
|
||||
return(inw(iobase+RDP));
|
||||
}
|
||||
|
||||
isprobe(isdev)
|
||||
struct isa_device *isdev;
|
||||
is_probe(isa_dev)
|
||||
struct isa_device *isa_dev;
|
||||
{
|
||||
int val,i,s;
|
||||
int unit = isdev->id_unit ;
|
||||
int unit = isa_dev->id_unit ;
|
||||
register struct is_softc *is = &is_softc[unit];
|
||||
|
||||
is->iobase = isdev->id_iobase;
|
||||
s = splimp();
|
||||
is->iobase = isa_dev->id_iobase;
|
||||
|
||||
/* Stop the lance chip, put it known state */
|
||||
iswrcsr(unit,0,STOP);
|
||||
@ -160,9 +145,9 @@ isprobe(isdev)
|
||||
iswrcsr(unit,3, 0);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
@ -171,13 +156,15 @@ isprobe(isdev)
|
||||
/*
|
||||
* Reset of interface.
|
||||
*/
|
||||
isreset(unit, uban)
|
||||
int unit, uban;
|
||||
int is_reset(int unit)
|
||||
{
|
||||
int s;
|
||||
if (unit >= NIS)
|
||||
return;
|
||||
s = splnet();
|
||||
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
|
||||
* to accept packets. We get the ethernet address here.
|
||||
*/
|
||||
isattach(isdev)
|
||||
struct isa_device *isdev;
|
||||
int is_attach(isa_dev)
|
||||
struct isa_device *isa_dev;
|
||||
{
|
||||
int unit = isdev->id_unit;
|
||||
register struct is_softc *is = &is_softc[unit];
|
||||
register struct ifnet *ifp = &is->is_if;
|
||||
int unit = isa_dev->id_unit;
|
||||
struct is_softc *is = &is_softc[unit];
|
||||
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_name = isdriver.name ;
|
||||
ifp->if_mtu = ETHERMTU;
|
||||
printf (" ethernet address %s", ether_sprintf(is->is_addr)) ;
|
||||
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_start = isstart;
|
||||
ifp->if_ioctl = isioctl;
|
||||
ifp->if_reset = isreset;
|
||||
ifp->if_watchdog = 0;
|
||||
ifp->if_start = is_start;
|
||||
ifp->if_ioctl = is_ioctl;
|
||||
ifp->if_reset = is_reset;
|
||||
ifp->if_watchdog = is_watchdog;
|
||||
|
||||
/* Set up DMA */
|
||||
isa_dmacascade(isa_dev->id_drq);
|
||||
|
||||
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;
|
||||
|
||||
/* 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].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
|
||||
* and transmit/receive descriptor rings.
|
||||
*/
|
||||
isinit(unit)
|
||||
is_init(unit)
|
||||
int unit;
|
||||
{
|
||||
register struct is_softc *is = &is_softc[unit];
|
||||
struct ifnet *ifp = &is->is_if;
|
||||
struct ifnet *ifp = &is->arpcom.ac_if;
|
||||
int s;
|
||||
register i;
|
||||
|
||||
/* Address not known */
|
||||
if (ifp->if_addrlist == (struct ifaddr *)0) return;
|
||||
|
||||
s = splnet();
|
||||
is->last_rd = is->last_td = is->no_td = 0;
|
||||
s = splimp();
|
||||
|
||||
/* Set up lance's memory area */
|
||||
init_mem(unit);
|
||||
@ -296,6 +321,20 @@ isinit(unit)
|
||||
/* Stop Lance to get access to other registers */
|
||||
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 */
|
||||
iswrcsr(unit,3,0);
|
||||
|
||||
@ -314,13 +353,15 @@ isinit(unit)
|
||||
if (isrdcsr(unit,0)&IDON) {
|
||||
/* Start lance */
|
||||
iswrcsr(unit,0,STRT|IDON|INEA);
|
||||
is->is_if.if_flags |= IFF_RUNNING;
|
||||
isstart(ifp);
|
||||
ifp->if_flags |= IFF_RUNNING;
|
||||
ifp->if_flags &= ~IFF_OACTIVE;
|
||||
|
||||
is_start(ifp);
|
||||
}
|
||||
else
|
||||
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.
|
||||
* called only at splimp or interrupt level.
|
||||
*/
|
||||
isstart(ifp)
|
||||
is_start(ifp)
|
||||
struct ifnet *ifp;
|
||||
{
|
||||
int unit = ifp->if_unit;
|
||||
@ -341,7 +382,7 @@ isstart(ifp)
|
||||
struct mds *cdm;
|
||||
|
||||
|
||||
if ((is->is_if.if_flags & IFF_RUNNING) == 0)
|
||||
if ((is->arpcom.ac_if.if_flags & IFF_RUNNING) == 0)
|
||||
return;
|
||||
|
||||
do {
|
||||
@ -349,7 +390,7 @@ isstart(ifp)
|
||||
if (cdm->flags&OWN)
|
||||
return;
|
||||
|
||||
IF_DEQUEUE(&is->is_if.if_snd, m);
|
||||
IF_DEQUEUE(&is->arpcom.ac_if.if_snd, m);
|
||||
|
||||
if (m == 0)
|
||||
return;
|
||||
@ -365,6 +406,72 @@ isstart(ifp)
|
||||
buffer += 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);
|
||||
len = MAX(len,ETHER_MIN_LEN);
|
||||
@ -385,7 +492,7 @@ isstart(ifp)
|
||||
is->last_td=0;
|
||||
}while(++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
|
||||
printf("no_td = %x, last_td = %x\n",is->no_td, is->last_td);
|
||||
#endif
|
||||
@ -415,19 +522,23 @@ isintr(unit)
|
||||
}
|
||||
if (!(isr&RXON)) {
|
||||
printf("!(isr&RXON)\n");
|
||||
isreset(unit);
|
||||
is_reset(unit);
|
||||
return(1);
|
||||
}
|
||||
if (!(isr&TXON)) {
|
||||
printf("!(isr&TXON)\n");
|
||||
isreset(unit);
|
||||
is_reset(unit);
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (isr&RINT) {
|
||||
isrint(unit);
|
||||
/* reset watchdog timer */
|
||||
is->arpcom.ac_if.if_timer = 0;
|
||||
is_rint(unit);
|
||||
}
|
||||
if (isr&TINT) {
|
||||
/* reset watchdog timer */
|
||||
is->arpcom.ac_if.if_timer = 0;
|
||||
iswrcsr(unit,0,TINT|INEA);
|
||||
istint(unit);
|
||||
}
|
||||
@ -438,7 +549,7 @@ istint(unit)
|
||||
int 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;
|
||||
struct mds *cdm;
|
||||
|
||||
@ -455,17 +566,17 @@ istint(unit)
|
||||
return;
|
||||
}
|
||||
loopcount++;
|
||||
is->is_if.if_flags &= ~IFF_OACTIVE;
|
||||
is->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
|
||||
}while(--is->no_td > 0);
|
||||
isstart(ifp);
|
||||
is_start(ifp);
|
||||
|
||||
}
|
||||
|
||||
#define NEXTRDS \
|
||||
if (++rmd == NRBUF) rmd=0, cdm=is->rd; else ++cdm
|
||||
|
||||
isrint(unit)
|
||||
int unit;
|
||||
/* only called from one place, so may as well integrate */
|
||||
static inline void is_rint(int unit)
|
||||
{
|
||||
register struct is_softc *is=&is_softc[unit];
|
||||
register int rmd = is->last_rd;
|
||||
@ -503,7 +614,7 @@ isrint(unit)
|
||||
is->last_rd = rmd;
|
||||
printf("is%d:Chained buffer\n",unit);
|
||||
if ((cdm->flags & (OWN|ERR|STP|ENP)) != ENP) {
|
||||
isreset(unit);
|
||||
is_reset(unit);
|
||||
return;
|
||||
}
|
||||
}else
|
||||
@ -522,53 +633,78 @@ isrint(unit)
|
||||
#endif
|
||||
} /* while */
|
||||
is->last_rd = rmd;
|
||||
} /* isrint */
|
||||
} /* is_rint */
|
||||
|
||||
|
||||
/*
|
||||
* Pass a packet to the higher levels.
|
||||
* We deal with the trailer protocol here.
|
||||
*/
|
||||
isread(is, buf, len)
|
||||
register struct is_softc *is;
|
||||
char *buf;
|
||||
int len;
|
||||
static inline void isread(struct is_softc *is, char *buf, int len)
|
||||
{
|
||||
register struct ether_header *eh;
|
||||
struct mbuf *m;
|
||||
int off, resid;
|
||||
register struct ifqueue *inq;
|
||||
register struct ether_header *eh;
|
||||
struct mbuf *m;
|
||||
int off, resid;
|
||||
register struct ifqueue *inq;
|
||||
|
||||
/*
|
||||
* Deal with trailer protocol: if type is trailer type
|
||||
* get true type from first 16-bit word past data.
|
||||
* Remember that type was trailer by setting off.
|
||||
*/
|
||||
eh = (struct ether_header *)buf;
|
||||
eh->ether_type = ntohs((u_short)eh->ether_type);
|
||||
len = len - sizeof(struct ether_header) - 4;
|
||||
#define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
|
||||
if (eh->ether_type >= ETHERTYPE_TRAIL &&
|
||||
eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
|
||||
off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
|
||||
if (off >= ETHERMTU) return; /* sanity */
|
||||
eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
|
||||
resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
|
||||
if (off + resid > len) return; /* sanity */
|
||||
len = off + resid;
|
||||
} else off = 0;
|
||||
/*
|
||||
* Deal with trailer protocol: if type is trailer type
|
||||
* get true type from first 16-bit word past data.
|
||||
* Remember that type was trailer by setting off.
|
||||
*/
|
||||
eh = (struct ether_header *)buf;
|
||||
eh->ether_type = ntohs((u_short)eh->ether_type);
|
||||
len = len - sizeof(struct ether_header) - 4;
|
||||
#define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
|
||||
if (eh->ether_type >= ETHERTYPE_TRAIL &&
|
||||
eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
|
||||
off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
|
||||
if (off >= ETHERMTU) return; /* sanity */
|
||||
eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
|
||||
resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
|
||||
if (off + resid > len) return; /* sanity */
|
||||
len = off + resid;
|
||||
} else off = 0;
|
||||
|
||||
if (len == 0) return;
|
||||
if (len == 0) return;
|
||||
|
||||
/*
|
||||
* Pull packet off interface. Off is nonzero if packet
|
||||
* has trailing header; neget will then force this header
|
||||
* 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.
|
||||
*/
|
||||
m = isget(buf, len, off, &is->is_if);
|
||||
if (m == 0) return;
|
||||
/*
|
||||
* Pull packet off interface. Off is nonzero if packet
|
||||
* has trailing header; neget will then force this header
|
||||
* 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.
|
||||
*/
|
||||
m = isget(buf, len, off, &is->arpcom.ac_if);
|
||||
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 *
|
||||
isget(buf, totlen, off0, ifp)
|
||||
caddr_t buf;
|
||||
int totlen, off0;
|
||||
struct ifnet *ifp;
|
||||
caddr_t buf;
|
||||
int totlen, off0;
|
||||
struct ifnet *ifp;
|
||||
{
|
||||
struct mbuf *top, **mp, *m, *p;
|
||||
int off = off0, len;
|
||||
register caddr_t cp = buf;
|
||||
char *epkt;
|
||||
struct mbuf *top, **mp, *m, *p;
|
||||
int off = off0, len;
|
||||
register caddr_t cp = buf;
|
||||
char *epkt;
|
||||
|
||||
buf += sizeof(struct ether_header);
|
||||
cp = buf;
|
||||
epkt = cp + totlen;
|
||||
buf += sizeof(struct ether_header);
|
||||
cp = buf;
|
||||
epkt = cp + totlen;
|
||||
|
||||
|
||||
if (off) {
|
||||
cp += off + 2 * sizeof(u_short);
|
||||
totlen -= 2 * sizeof(u_short);
|
||||
}
|
||||
if (off) {
|
||||
cp += off + 2 * sizeof(u_short);
|
||||
totlen -= 2 * sizeof(u_short);
|
||||
}
|
||||
|
||||
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
||||
if (m == 0)
|
||||
return (0);
|
||||
m->m_pkthdr.rcvif = ifp;
|
||||
m->m_pkthdr.len = totlen;
|
||||
m->m_len = MHLEN;
|
||||
|
||||
top = 0;
|
||||
mp = ⊤
|
||||
while (totlen > 0) {
|
||||
if (top) {
|
||||
MGET(m, M_DONTWAIT, MT_DATA);
|
||||
if (m == 0) {
|
||||
m_freem(top);
|
||||
return (0);
|
||||
}
|
||||
m->m_len = MLEN;
|
||||
}
|
||||
len = min(totlen, epkt - cp);
|
||||
if (len >= MINCLSIZE) {
|
||||
MCLGET(m, M_DONTWAIT);
|
||||
if (m->m_flags & M_EXT)
|
||||
m->m_len = len = min(len, MCLBYTES);
|
||||
else
|
||||
len = m->m_len;
|
||||
} else {
|
||||
/*
|
||||
* Place initial small packet/header at end of mbuf.
|
||||
*/
|
||||
if (len < m->m_len) {
|
||||
if (top == 0 && len + max_linkhdr <= m->m_len)
|
||||
m->m_data += max_linkhdr;
|
||||
m->m_len = len;
|
||||
} else
|
||||
len = m->m_len;
|
||||
}
|
||||
bcopy(cp, mtod(m, caddr_t), (unsigned)len);
|
||||
cp += len;
|
||||
*mp = m;
|
||||
mp = &m->m_next;
|
||||
totlen -= len;
|
||||
if (cp == epkt)
|
||||
cp = buf;
|
||||
}
|
||||
return (top);
|
||||
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
||||
if (m == 0)
|
||||
return (0);
|
||||
m->m_pkthdr.rcvif = ifp;
|
||||
m->m_pkthdr.len = totlen;
|
||||
m->m_len = MHLEN;
|
||||
top = 0;
|
||||
mp = ⊤
|
||||
while (totlen > 0) {
|
||||
if (top) {
|
||||
MGET(m, M_DONTWAIT, MT_DATA);
|
||||
if (m == 0) {
|
||||
m_freem(top);
|
||||
return (0);
|
||||
}
|
||||
m->m_len = MLEN;
|
||||
}
|
||||
len = min(totlen, epkt - cp);
|
||||
if (len >= MINCLSIZE) {
|
||||
MCLGET(m, M_DONTWAIT);
|
||||
if (m->m_flags & M_EXT)
|
||||
m->m_len = len = min(len, MCLBYTES);
|
||||
else
|
||||
len = m->m_len;
|
||||
} else {
|
||||
/*
|
||||
* Place initial small packet/header at end of mbuf.
|
||||
*/
|
||||
if (len < m->m_len) {
|
||||
if (top == 0 && len + max_linkhdr <= m->m_len)
|
||||
m->m_data += max_linkhdr;
|
||||
m->m_len = len;
|
||||
} else
|
||||
len = m->m_len;
|
||||
}
|
||||
bcopy(cp, mtod(m, caddr_t), (unsigned)len);
|
||||
cp += len;
|
||||
*mp = m;
|
||||
mp = &m->m_next;
|
||||
totlen -= len;
|
||||
if (cp == epkt)
|
||||
cp = buf;
|
||||
}
|
||||
return (top);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process an ioctl request.
|
||||
*/
|
||||
isioctl(ifp, cmd, data)
|
||||
is_ioctl(ifp, cmd, data)
|
||||
register struct ifnet *ifp;
|
||||
int cmd;
|
||||
caddr_t data;
|
||||
@ -664,8 +800,9 @@ isioctl(ifp, cmd, data)
|
||||
int unit = ifp->if_unit;
|
||||
struct is_softc *is = &is_softc[unit];
|
||||
struct ifreq *ifr = (struct ifreq *)data;
|
||||
int s = splimp(), error = 0;
|
||||
int s, error = 0;
|
||||
|
||||
s = splnet();
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
@ -675,60 +812,94 @@ isioctl(ifp, cmd, data)
|
||||
switch (ifa->ifa_addr->sa_family) {
|
||||
#ifdef 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 =
|
||||
IA_SIN(ifa)->sin_addr;
|
||||
arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
|
||||
break;
|
||||
#endif
|
||||
#ifdef NS
|
||||
/*
|
||||
* XXX - This code is probably wrong
|
||||
*/
|
||||
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))
|
||||
ina->x_host = *(union ns_host *)(is->is_addr);
|
||||
ina->x_host = *(union ns_host *)(is->arpcom.ac_enaddr);
|
||||
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,
|
||||
(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;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
isinit(ifp->if_unit);
|
||||
is_init(ifp->if_unit);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SIOCSIFFLAGS:
|
||||
/*
|
||||
* If interface is marked down and it is running, then stop it
|
||||
*/
|
||||
if ((ifp->if_flags & IFF_UP) == 0 &&
|
||||
ifp->if_flags & IFF_RUNNING) {
|
||||
ifp->if_flags &= ~IFF_RUNNING;
|
||||
iswrcsr(unit,0,STOP);
|
||||
} else if (ifp->if_flags & IFF_UP &&
|
||||
(ifp->if_flags & IFF_RUNNING) == 0)
|
||||
isinit(ifp->if_unit);
|
||||
ifp->if_flags &= ~IFF_RUNNING;
|
||||
} else {
|
||||
/*
|
||||
* 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;
|
||||
|
||||
#ifdef notdef
|
||||
case SIOCGHWADDR:
|
||||
bcopy((caddr_t)is->is_addr, (caddr_t) &ifr->ifr_data,
|
||||
sizeof(is->is_addr));
|
||||
bcopy((caddr_t)is->arpcom.ac_enaddr, (caddr_t) &ifr->ifr_data,
|
||||
sizeof(is->arpcom.ac_enaddr));
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
error = EINVAL;
|
||||
}
|
||||
splx(s);
|
||||
(void) splx(s);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user