summaryrefslogtreecommitdiffstats
path: root/sys/i386/isa/if_is.c
diff options
context:
space:
mode:
authorpaul <paul@FreeBSD.org>1993-06-19 08:24:14 +0000
committerpaul <paul@FreeBSD.org>1993-06-19 08:24:14 +0000
commitb6baa5d4b0a3e022e1b815163466b4e2d77b93c4 (patch)
tree8a6f89d69a8a951228fc735e05f99989e657a317 /sys/i386/isa/if_is.c
parent46e423f4fa26d642bb57e911acd93582e2096b39 (diff)
downloadFreeBSD-src-b6baa5d4b0a3e022e1b815163466b4e2d77b93c4.zip
FreeBSD-src-b6baa5d4b0a3e022e1b815163466b4e2d77b93c4.tar.gz
Added bpf support to if_is.c (Isolan driver)
Diffstat (limited to 'sys/i386/isa/if_is.c')
-rw-r--r--sys/i386/isa/if_is.c623
1 files changed, 397 insertions, 226 deletions
diff --git a/sys/i386/isa/if_is.c b/sys/i386/isa/if_is.c
index 3dfcb15..e08da3b 100644
--- a/sys/i386/isa/if_is.c
+++ b/sys/i386/isa/if_is.c
@@ -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 "errno.h"
+#include "ioctl.h"
#include "mbuf.h"
-#include "buf.h"
-#include "protosw.h"
#include "socket.h"
-#include "ioctl.h"
-#include "errno.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;
-
- /*
- * 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;
-
- /*
- * 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;
-
- ether_input(&is->is_if, eh, m);
+ 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;
+
+ 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->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);
+
+ /*
+ * 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;
-
- buf += sizeof(struct ether_header);
- cp = buf;
- epkt = cp + totlen;
-
-
- 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 = &top;
- 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);
+ 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;
+
+
+ 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 = &top;
+ 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);
}
OpenPOWER on IntegriCloud