Added bpf support to if_is.c (Isolan driver)

This commit is contained in:
Paul Richards 1993-06-19 08:24:14 +00:00
parent 4ba5f2985d
commit ee4a642ef6

View File

@ -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 = &top;
mp = &top; 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);
} }