Add extra argument to VOP_BMAP.
[unix-history] / usr / src / sys / net / bpf.c
index 9fd85cb..4dc1630 100644 (file)
@@ -1,35 +1,43 @@
-/*-
- * Copyright (c) 1991 The Regents of the University of California.
+/*
+ * Copyright (c) 1990, 1991 Regents of the University of California.
  * All rights reserved.
  *
  * This code is derived from the Stanford/CMU enet packet filter,
  * (net/enet.c) distributed as part of 4.3BSD, and code contributed
  * All rights reserved.
  *
  * This code is derived from the Stanford/CMU enet packet filter,
  * (net/enet.c) distributed as part of 4.3BSD, and code contributed
- * to Berkeley by Steven McCanne of Lawrence Berkeley Laboratory.
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence 
+ * Berkeley Laboratory.
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)bpf.c       7.3 (Berkeley) %G%
+ *      @(#)bpf.c      7.12 (Berkeley) %G%
  *
  * static char rcsid[] =
  *
  * static char rcsid[] =
- * "$Header: bpf.c,v 1.23 91/01/30 18:22:13 mccanne Exp $";
+ * "$Header: bpf.c,v 1.33 91/10/27 21:21:58 mccanne Exp $";
  */
 
 #include "bpfilter.h"
 
  */
 
 #include "bpfilter.h"
 
-#if (NBPFILTER > 0)
+#if NBPFILTER > 0
+
+#ifndef __GNUC__
+#define inline
+#else
+#define inline __inline
+#endif
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/mbuf.h>
 #include <sys/buf.h>
 #include <sys/dir.h>
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/mbuf.h>
 #include <sys/buf.h>
 #include <sys/dir.h>
+#include <sys/time.h>
 #include <sys/proc.h>
 #include <sys/user.h>
 #include <sys/ioctl.h>
 #include <sys/map.h>
 
 #include <sys/file.h>
 #include <sys/proc.h>
 #include <sys/user.h>
 #include <sys/ioctl.h>
 #include <sys/map.h>
 
 #include <sys/file.h>
-#ifdef sparc
+#if defined(sparc) && BSD < 199103
 #include <sys/stream.h>
 #endif
 #include <sys/tty.h>
 #include <sys/stream.h>
 #endif
 #include <sys/tty.h>
 #include <netinet/if_ether.h>
 #include <sys/kernel.h>
 
 #include <netinet/if_ether.h>
 #include <sys/kernel.h>
 
+/*
+ * Older BSDs don't have kernel malloc.
+ */
+#if BSD < 199103
+extern bcopy();
+static caddr_t bpf_alloc();
+#include <net/bpf_compat.h>
+#define BPF_BUFSIZE (MCLBYTES-8)
+#define UIOMOVE(cp, len, code, uio) uiomove(cp, len, code, uio)
+#else
+#define BPF_BUFSIZE 4096
+#define UIOMOVE(cp, len, code, uio) uiomove(cp, len, uio)
+#endif
+
 #define PRINET  26                     /* interruptible */
 
 /*
  * The default read buffer size is patchable.
  */
 #define PRINET  26                     /* interruptible */
 
 /*
  * The default read buffer size is patchable.
  */
-int bpf_bufsize = MCLBYTES;
+int bpf_bufsize = BPF_BUFSIZE;
 
 /*
  *  bpf_iflist is the list of interfaces; each corresponds to an ifnet
  *  bpf_dtab holds the descriptors, indexed by minor device #
 
 /*
  *  bpf_iflist is the list of interfaces; each corresponds to an ifnet
  *  bpf_dtab holds the descriptors, indexed by minor device #
- *
- * We really don't need NBPFILTER bpf_if entries, but this eliminates
- * the need to account for all possible drivers here.
- * This problem will go away when these structures are allocated dynamically.
  */
  */
-static struct bpf_if   *bpf_iflist;
-static struct bpf_d    bpf_dtab[NBPFILTER];
+struct bpf_if  *bpf_iflist;
+struct bpf_d   bpf_dtab[NBPFILTER];
 
 static void    bpf_ifname();
 static void    catchpacket();
 
 static void    bpf_ifname();
 static void    catchpacket();
+static void    bpf_freed();
 static int     bpf_setif();
 static int     bpf_initd();
 static int     bpf_setif();
 static int     bpf_initd();
+static int     bpf_allocbufs();
 
 static int
 
 static int
-bpf_movein(uio, linktype, mp, sockp)
+bpf_movein(uio, linktype, mp, sockp, datlen)
        register struct uio *uio;
        register struct uio *uio;
-       int linktype;
+       int linktype, *datlen;
        register struct mbuf **mp;
        register struct sockaddr *sockp;
 {
        register struct mbuf **mp;
        register struct sockaddr *sockp;
 {
@@ -93,6 +113,7 @@ bpf_movein(uio, linktype, mp, sockp)
         * for the link level header.
         */
        switch (linktype) {
         * for the link level header.
         */
        switch (linktype) {
+
        case DLT_SLIP:
                sockp->sa_family = AF_INET;
                hlen = 0;
        case DLT_SLIP:
                sockp->sa_family = AF_INET;
                hlen = 0;
@@ -104,17 +125,23 @@ bpf_movein(uio, linktype, mp, sockp)
                hlen = sizeof(struct ether_header);
                break;
 
                hlen = sizeof(struct ether_header);
                break;
 
-       case DLT_FDDI:
+       case DLT_FDDI:
                sockp->sa_family = AF_UNSPEC;
                /* XXX 4(FORMAC)+6(dst)+6(src)+3(LLC)+5(SNAP) */
                hlen = 24;
                break;
 
                sockp->sa_family = AF_UNSPEC;
                /* XXX 4(FORMAC)+6(dst)+6(src)+3(LLC)+5(SNAP) */
                hlen = 24;
                break;
 
+       case DLT_NULL:
+               sockp->sa_family = AF_UNSPEC;
+               hlen = 0;
+               break;
+
        default:
                return (EIO);
        }
 
        len = uio->uio_resid;
        default:
                return (EIO);
        }
 
        len = uio->uio_resid;
+       *datlen = len - hlen;
        if ((unsigned)len > MCLBYTES)
                return (EIO);
 
        if ((unsigned)len > MCLBYTES)
                return (EIO);
 
@@ -122,8 +149,13 @@ bpf_movein(uio, linktype, mp, sockp)
        if (m == 0)
                return (ENOBUFS);
        if (len > MLEN) {
        if (m == 0)
                return (ENOBUFS);
        if (len > MLEN) {
+#if BSD >= 199103
                MCLGET(m, M_WAIT);
                if ((m->m_flags & M_EXT) == 0) {
                MCLGET(m, M_WAIT);
                if ((m->m_flags & M_EXT) == 0) {
+#else
+               MCLGET(m);
+               if (m->m_len != MCLBYTES) {
+#endif
                        error = ENOBUFS;
                        goto bad;
                }
                        error = ENOBUFS;
                        goto bad;
                }
@@ -133,16 +165,19 @@ bpf_movein(uio, linktype, mp, sockp)
        /*
         * Make room for link header.
         */
        /*
         * Make room for link header.
         */
-       if (hlen) {
+       if (hlen != 0) {
                m->m_len -= hlen;
                m->m_len -= hlen;
+#if BSD >= 199103
                m->m_data += hlen; /* XXX */
                m->m_data += hlen; /* XXX */
-
-               error = uiomove((caddr_t)sockp->sa_data, hlen, uio);
+#else
+               m->m_off += hlen;
+#endif
+               error = UIOMOVE((caddr_t)sockp->sa_data, hlen, UIO_WRITE, uio);
                if (error)
                        goto bad;
        }
                if (error)
                        goto bad;
        }
-       error = uiomove(mtod(m, caddr_t), len - hlen, uio);
-       if (!error) 
+       error = UIOMOVE(mtod(m, caddr_t), len - hlen, UIO_WRITE, uio);
+       if (!error)
                return (0);
  bad:
        m_freem(m);
                return (0);
  bad:
        m_freem(m);
@@ -150,7 +185,7 @@ bpf_movein(uio, linktype, mp, sockp)
 }
 
 /*
 }
 
 /*
- * Attach 'd' to the bpf interface 'bp', i.e. make 'd' listen on 'bp'.
+ * Attach file to the bpf interface, i.e. make d listen on bp.
  * Must be called at splimp.
  */
 static void
  * Must be called at splimp.
  */
 static void
@@ -158,19 +193,21 @@ bpf_attachd(d, bp)
        struct bpf_d *d;
        struct bpf_if *bp;
 {
        struct bpf_d *d;
        struct bpf_if *bp;
 {
-       /* Point d at bp. */
+       /*
+        * Point d at bp, and add d to the interface's list of listeners.
+        * Finally, point the driver's bpf cookie at the interface so
+        * it will divert packets to bpf.
+        */
        d->bd_bif = bp;
        d->bd_bif = bp;
-
-       /* Add d to bp's list of listeners. */
        d->bd_next = bp->bif_dlist;
        bp->bif_dlist = d;
 
        d->bd_next = bp->bif_dlist;
        bp->bif_dlist = d;
 
-       /*
-        * Let the driver know we're here (if it doesn't already).
-        */
        *bp->bif_driverp = bp;
 }
 
        *bp->bif_driverp = bp;
 }
 
+/*
+ * Detach a file from its interface.
+ */
 static void
 bpf_detachd(d)
        struct bpf_d *d;
 static void
 bpf_detachd(d)
        struct bpf_d *d;
@@ -191,9 +228,9 @@ bpf_detachd(d)
                         * the driver into promiscuous mode, but can't
                         * take it out.
                         */
                         * the driver into promiscuous mode, but can't
                         * take it out.
                         */
-                       panic("bpf_detachd: ifpromisc failed");
+                       panic("bpf: ifpromisc failed");
        }
        }
-       /* Remove 'd' from the interface's descriptor list. */
+       /* Remove d from the interface's descriptor list. */
        p = &bp->bif_dlist;
        while (*p != d) {
                p = &(*p)->bd_next;
        p = &bp->bif_dlist;
        while (*p != d) {
                p = &(*p)->bd_next;
@@ -211,7 +248,7 @@ bpf_detachd(d)
 
 
 /*
 
 
 /*
- * Mark a descriptor free by making it point to itself. 
+ * Mark a descriptor free by making it point to itself.
  * This is probably cheaper than marking with a constant since
  * the address should be in a register anyway.
  */
  * This is probably cheaper than marking with a constant since
  * the address should be in a register anyway.
  */
@@ -220,10 +257,8 @@ bpf_detachd(d)
 #define D_MARKUSED(d) ((d)->bd_next = 0)
 
 /*
 #define D_MARKUSED(d) ((d)->bd_next = 0)
 
 /*
- *  bpfopen - open ethernet device
- *
- *  Errors:    ENXIO   - illegal minor device number
- *             EBUSY   - too many files open
+ * Open ethernet device.  Returns ENXIO for illegal minor device number,
+ * EBUSY if file is open by another process.
  */
 /* ARGSUSED */
 int
  */
 /* ARGSUSED */
 int
@@ -231,31 +266,22 @@ bpfopen(dev, flag)
        dev_t dev;
        int flag;
 {
        dev_t dev;
        int flag;
 {
-       int error, s;
        register struct bpf_d *d;
        register struct bpf_d *d;
-       
+
        if (minor(dev) >= NBPFILTER)
                return (ENXIO);
        if (minor(dev) >= NBPFILTER)
                return (ENXIO);
-
        /*
         * Each minor can be opened by only one process.  If the requested
         * minor is in use, return EBUSY.
         */
        /*
         * Each minor can be opened by only one process.  If the requested
         * minor is in use, return EBUSY.
         */
-       s = splimp();
        d = &bpf_dtab[minor(dev)];
        d = &bpf_dtab[minor(dev)];
-       if (!D_ISFREE(d)) {
-               splx(s);
+       if (!D_ISFREE(d))
                return (EBUSY);
                return (EBUSY);
-       } else
-               /* Mark "free" and do most initialization. */
-               bzero((char *)d, sizeof(*d));
-       splx(s);
 
 
-       error = bpf_initd(d);
-       if (error) {
-               D_MARKFREE(d);
-               return (error);
-       }
+       /* Mark "free" and do most initialization. */
+       bzero((char *)d, sizeof(*d));
+       d->bd_bufsize = bpf_bufsize;
+
        return (0);
 }
 
        return (0);
 }
 
@@ -264,33 +290,65 @@ bpfopen(dev, flag)
  * deallocating its buffers, and marking it free.
  */
 /* ARGSUSED */
  * deallocating its buffers, and marking it free.
  */
 /* ARGSUSED */
+int
 bpfclose(dev, flag)
        dev_t dev;
        int flag;
 {
        register struct bpf_d *d = &bpf_dtab[minor(dev)];
 bpfclose(dev, flag)
        dev_t dev;
        int flag;
 {
        register struct bpf_d *d = &bpf_dtab[minor(dev)];
-       int s;
+       register int s;
 
        s = splimp();
        if (d->bd_bif)
                bpf_detachd(d);
        splx(s);
 
        s = splimp();
        if (d->bd_bif)
                bpf_detachd(d);
        splx(s);
+       bpf_freed(d);
 
 
-       /* Free the buffer space. */
-       if (d->bd_hbuf)
-               free(d->bd_hbuf, M_DEVBUF);
-       if (d->bd_fbuf)
-               free(d->bd_fbuf, M_DEVBUF);
-       free(d->bd_sbuf, M_DEVBUF);
-       if (d->bd_filter)
-               free((caddr_t)d->bd_filter, M_DEVBUF);
-       
-       D_MARKFREE(d);
+       return (0);
+}
+
+/*
+ * Support for SunOS, which does not have tsleep.
+ */
+#if BSD < 199103
+static
+bpf_timeout(arg)
+       caddr_t arg;
+{
+       struct bpf_d *d = (struct bpf_d *)arg;
+       d->bd_timedout = 1;
+       wakeup(arg);
+}
+
+#define BPF_SLEEP(chan, pri, s, t) bpf_sleep((struct bpf_d *)chan)
+
+int
+bpf_sleep(d)
+       register struct bpf_d *d;
+{
+       register int rto = d->bd_rtout;
+       register int st;
+
+       if (rto != 0) {
+               d->bd_timedout = 0;
+               timeout(bpf_timeout, (caddr_t)d, rto);
+       }
+       st = sleep((caddr_t)d, PRINET|PCATCH);
+       if (rto != 0) {
+               if (d->bd_timedout == 0)
+                       untimeout(bpf_timeout, (caddr_t)d);
+               else if (st == 0)
+                       return EWOULDBLOCK;
+       }
+       return (st != 0) ? EINTR : 0;
 }
 }
+#else
+#define BPF_SLEEP tsleep
+#endif
 
 /*
  * Rotate the packet buffers in descriptor d.  Move the store buffer
 
 /*
  * Rotate the packet buffers in descriptor d.  Move the store buffer
- * into the hold slot, and the free buffer into the store slot.  
+ * into the hold slot, and the free buffer into the store slot.
  * Zero the length of the new store buffer.
  */
 #define ROTATE_BUFFERS(d) \
  * Zero the length of the new store buffer.
  */
 #define ROTATE_BUFFERS(d) \
@@ -298,7 +356,7 @@ bpfclose(dev, flag)
        (d)->bd_hlen = (d)->bd_slen; \
        (d)->bd_sbuf = (d)->bd_fbuf; \
        (d)->bd_slen = 0; \
        (d)->bd_hlen = (d)->bd_slen; \
        (d)->bd_sbuf = (d)->bd_fbuf; \
        (d)->bd_slen = 0; \
-       (d)->bd_fbuf = 0; 
+       (d)->bd_fbuf = 0;
 /*
  *  bpfread - read next chunk of packets from buffers
  */
 /*
  *  bpfread - read next chunk of packets from buffers
  */
@@ -312,7 +370,7 @@ bpfread(dev, uio)
        int s;
 
        /*
        int s;
 
        /*
-        * Restrict application to use a buffer the same size as 
+        * Restrict application to use a buffer the same size as
         * as kernel buffers.
         */
        if (uio->uio_resid != d->bd_bufsize)
         * as kernel buffers.
         */
        if (uio->uio_resid != d->bd_bufsize)
@@ -320,9 +378,9 @@ bpfread(dev, uio)
 
        s = splimp();
        /*
 
        s = splimp();
        /*
-        * If the hold buffer is empty, then set a timer and sleep
-        * until either the timeout has occurred or enough packets have
-        * arrived to fill the store buffer.
+        * If the hold buffer is empty, then do a timed sleep, which
+        * ends when the timeout expires or when enough packets
+        * have arrived to fill the store buffer.
         */
        while (d->bd_hbuf == 0) {
                if (d->bd_immediate && d->bd_slen != 0) {
         */
        while (d->bd_hbuf == 0) {
                if (d->bd_immediate && d->bd_slen != 0) {
@@ -334,7 +392,8 @@ bpfread(dev, uio)
                        ROTATE_BUFFERS(d);
                        break;
                }
                        ROTATE_BUFFERS(d);
                        break;
                }
-               error = tsleep((caddr_t)d, PRINET|PCATCH, "bpf", d->bd_rtout);
+               error = BPF_SLEEP((caddr_t)d, PRINET|PCATCH, "bpf",
+                                 d->bd_rtout);
                if (error == EINTR || error == ERESTART) {
                        splx(s);
                        return (error);
                if (error == EINTR || error == ERESTART) {
                        splx(s);
                        return (error);
@@ -347,7 +406,7 @@ bpfread(dev, uio)
                         */
                        if (d->bd_hbuf)
                                /*
                         */
                        if (d->bd_hbuf)
                                /*
-                                * We filled up the buffer in between 
+                                * We filled up the buffer in between
                                 * getting the timeout and arriving
                                 * here, so we don't need to rotate.
                                 */
                                 * getting the timeout and arriving
                                 * here, so we don't need to rotate.
                                 */
@@ -365,36 +424,43 @@ bpfread(dev, uio)
         * At this point, we know we have something in the hold slot.
         */
        splx(s);
         * At this point, we know we have something in the hold slot.
         */
        splx(s);
-       
-       /*  
+
+       /*
         * Move data from hold buffer into user space.
         * We know the entire buffer is transferred since
         * we checked above that the read buffer is bpf_bufsize bytes.
         */
         * Move data from hold buffer into user space.
         * We know the entire buffer is transferred since
         * we checked above that the read buffer is bpf_bufsize bytes.
         */
-       error = uiomove(d->bd_hbuf, d->bd_hlen, uio);
+       error = UIOMOVE(d->bd_hbuf, d->bd_hlen, UIO_READ, uio);
 
        s = splimp();
        d->bd_fbuf = d->bd_hbuf;
        d->bd_hbuf = 0;
 
        s = splimp();
        d->bd_fbuf = d->bd_hbuf;
        d->bd_hbuf = 0;
+       d->bd_hlen = 0;
        splx(s);
        splx(s);
-       
+
        return (error);
 }
 
 
 /*
        return (error);
 }
 
 
 /*
- * If there are processes sleeping on this descriptor, wake them up.  
+ * If there are processes sleeping on this descriptor, wake them up.
  */
 static inline void
 bpf_wakeup(d)
        register struct bpf_d *d;
 {
        wakeup((caddr_t)d);
  */
 static inline void
 bpf_wakeup(d)
        register struct bpf_d *d;
 {
        wakeup((caddr_t)d);
+#if BSD >= 199103
+       selwakeup(&d->bd_sel);
+       /* XXX */
+       d->bd_sel.si_pid = 0;
+#else
        if (d->bd_selproc) {
                selwakeup(d->bd_selproc, (int)d->bd_selcoll);
                d->bd_selcoll = 0;
                d->bd_selproc = 0;
        }
        if (d->bd_selproc) {
                selwakeup(d->bd_selproc, (int)d->bd_selcoll);
                d->bd_selcoll = 0;
                d->bd_selproc = 0;
        }
+#endif
 }
 
 int
 }
 
 int
@@ -407,6 +473,7 @@ bpfwrite(dev, uio)
        struct mbuf *m;
        int error, s;
        static struct sockaddr dst;
        struct mbuf *m;
        int error, s;
        static struct sockaddr dst;
+       int datlen;
 
        if (d->bd_bif == 0)
                return (ENXIO);
 
        if (d->bd_bif == 0)
                return (ENXIO);
@@ -415,25 +482,30 @@ bpfwrite(dev, uio)
 
        if (uio->uio_resid == 0)
                return (0);
 
        if (uio->uio_resid == 0)
                return (0);
-       if (uio->uio_resid > ifp->if_mtu)
-               return (EMSGSIZE);
 
 
-       error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, &dst);
+       error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, &dst, &datlen);
        if (error)
                return (error);
 
        if (error)
                return (error);
 
+       if (datlen > ifp->if_mtu)
+               return (EMSGSIZE);
+
        s = splnet();
        s = splnet();
+#if BSD >= 199103
+       error = (*ifp->if_output)(ifp, m, &dst, (struct rtentry *)0);
+#else
        error = (*ifp->if_output)(ifp, m, &dst);
        error = (*ifp->if_output)(ifp, m, &dst);
+#endif
        splx(s);
        /*
        splx(s);
        /*
-        * The driver frees the mbuf. 
+        * The driver frees the mbuf.
         */
        return (error);
 }
 
 /*
         */
        return (error);
 }
 
 /*
- * Reset a descriptor by flushing its packet bufferand clearing the receive
- * and drop counts.  Should be called at splimp.
+ * Reset a descriptor by flushing its packet buffer and clearing the
+ * receive and drop counts.  Should be called at splimp.
  */
 static void
 reset_d(d)
  */
 static void
 reset_d(d)
@@ -445,6 +517,7 @@ reset_d(d)
                d->bd_hbuf = 0;
        }
        d->bd_slen = 0;
                d->bd_hbuf = 0;
        }
        d->bd_slen = 0;
+       d->bd_hlen = 0;
        d->bd_rcount = 0;
        d->bd_dcount = 0;
 }
        d->bd_rcount = 0;
        d->bd_dcount = 0;
 }
@@ -452,7 +525,6 @@ reset_d(d)
 /*
  *  FIONREAD           Check for read packet available.
  *  SIOCGIFADDR                Get interface address - convenient hook to driver.
 /*
  *  FIONREAD           Check for read packet available.
  *  SIOCGIFADDR                Get interface address - convenient hook to driver.
- *  BIOCGFLEN          Get max filter len.
  *  BIOCGBLEN          Get buffer len [for read()].
  *  BIOCSETF           Set ethernet read filter.
  *  BIOCFLUSH          Flush read packet buffer.
  *  BIOCGBLEN          Get buffer len [for read()].
  *  BIOCSETF           Set ethernet read filter.
  *  BIOCFLUSH          Flush read packet buffer.
@@ -464,6 +536,7 @@ reset_d(d)
  *  BIOCGRTIMEOUT      Get read timeout.
  *  BIOCGSTATS         Get packet stats.
  *  BIOCIMMEDIATE      Set immediate mode.
  *  BIOCGRTIMEOUT      Get read timeout.
  *  BIOCGSTATS         Get packet stats.
  *  BIOCIMMEDIATE      Set immediate mode.
+ *  BIOCVERSION                Get filter language version.
  */
 /* ARGSUSED */
 int
  */
 /* ARGSUSED */
 int
@@ -488,10 +561,10 @@ bpfioctl(dev, cmd, addr, flag)
        case FIONREAD:
                {
                        int n;
        case FIONREAD:
                {
                        int n;
-               
+
                        s = splimp();
                        n = d->bd_slen;
                        s = splimp();
                        n = d->bd_slen;
-                       if (d->bd_hbuf) 
+                       if (d->bd_hbuf)
                                n += d->bd_hlen;
                        splx(s);
 
                                n += d->bd_hlen;
                        splx(s);
 
@@ -507,17 +580,11 @@ bpfioctl(dev, cmd, addr, flag)
                                error = EINVAL;
                        else {
                                ifp = d->bd_bif->bif_ifp;
                                error = EINVAL;
                        else {
                                ifp = d->bd_bif->bif_ifp;
-                               error =  (*ifp->if_ioctl)(ifp, cmd, addr);
+                               error = (*ifp->if_ioctl)(ifp, cmd, addr);
                        }
                        break;
                }
 
                        }
                        break;
                }
 
-       /*
-        * Get max filter len.
-        */
-       case BIOCGFLEN:
-               *(u_int *)addr = BPF_MAXINSNS;
-               break;
        /*
         * Get buffer len [for read()].
         */
        /*
         * Get buffer len [for read()].
         */
@@ -526,9 +593,30 @@ bpfioctl(dev, cmd, addr, flag)
                break;
 
        /*
                break;
 
        /*
-        * Set ethernet read filter.
+        * Set buffer length.
         */
         */
-        case BIOCSETF:
+       case BIOCSBLEN:
+#if BSD < 199103
+               error = EINVAL;
+#else
+               if (d->bd_bif != 0)
+                       error = EINVAL;
+               else {
+                       register u_int size = *(u_int *)addr;
+
+                       if (size > BPF_MAXBUFSIZE)
+                               *(u_int *)addr = size = BPF_MAXBUFSIZE;
+                       else if (size < BPF_MINBUFSIZE)
+                               *(u_int *)addr = size = BPF_MINBUFSIZE;
+                       d->bd_bufsize = size;
+               }
+#endif
+               break;
+
+       /*
+        * Set link layer read filter.
+        */
+       case BIOCSETF:
                error = bpf_setf(d, (struct bpf_program *)addr);
                break;
 
                error = bpf_setf(d, (struct bpf_program *)addr);
                break;
 
@@ -554,8 +642,9 @@ bpfioctl(dev, cmd, addr, flag)
                }
                s = splimp();
                if (d->bd_promisc == 0) {
                }
                s = splimp();
                if (d->bd_promisc == 0) {
-                       d->bd_promisc = 1;
                        error = ifpromisc(d->bd_bif->bif_ifp, 1);
                        error = ifpromisc(d->bd_bif->bif_ifp, 1);
+                       if (error == 0)
+                               d->bd_promisc = 1;
                }
                splx(s);
                break;
                }
                splx(s);
                break;
@@ -590,7 +679,7 @@ bpfioctl(dev, cmd, addr, flag)
        /*
         * Set read timeout.
         */
        /*
         * Set read timeout.
         */
-       case BIOCSRTIMEOUT:
+       case BIOCSRTIMEOUT:
                {
                        struct timeval *tv = (struct timeval *)addr;
                        u_long msec;
                {
                        struct timeval *tv = (struct timeval *)addr;
                        u_long msec;
@@ -608,7 +697,7 @@ bpfioctl(dev, cmd, addr, flag)
        /*
         * Get read timeout.
         */
        /*
         * Get read timeout.
         */
-       case BIOCGRTIMEOUT:
+       case BIOCGRTIMEOUT:
                {
                        struct timeval *tv = (struct timeval *)addr;
                        u_long msec = d->bd_rtout;
                {
                        struct timeval *tv = (struct timeval *)addr;
                        u_long msec = d->bd_rtout;
@@ -637,12 +726,21 @@ bpfioctl(dev, cmd, addr, flag)
        case BIOCIMMEDIATE:
                d->bd_immediate = *(u_int *)addr;
                break;
        case BIOCIMMEDIATE:
                d->bd_immediate = *(u_int *)addr;
                break;
+
+       case BIOCVERSION:
+               {
+                       struct bpf_version *bv = (struct bpf_version *)addr;
+
+                       bv->bv_major = BPF_MAJOR_VERSION;
+                       bv->bv_minor = BPF_MINOR_VERSION;
+                       break;
+               }
        }
        return (error);
 }
 
        }
        return (error);
 }
 
-/* 
- * Set d's packet filter program to 'fp'.  If 'd' already has a filter,
+/*
+ * Set d's packet filter program to fp.  If this file already has a filter,
  * free it and replace it.  Returns EINVAL for bogus requests.
  */
 int
  * free it and replace it.  Returns EINVAL for bogus requests.
  */
 int
@@ -672,10 +770,8 @@ bpf_setf(d, fp)
 
        size = flen * sizeof(*fp->bf_insns);
        fcode = (struct bpf_insn *)malloc(size, M_DEVBUF, M_WAITOK);
 
        size = flen * sizeof(*fp->bf_insns);
        fcode = (struct bpf_insn *)malloc(size, M_DEVBUF, M_WAITOK);
-       if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size))
-               return (EINVAL);
-       
-       if (bpf_validate(fcode, (int)flen)) {
+       if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 &&
+           bpf_validate(fcode, (int)flen)) {
                s = splimp();
                d->bd_filter = fcode;
                reset_d(d);
                s = splimp();
                d->bd_filter = fcode;
                reset_d(d);
@@ -690,8 +786,9 @@ bpf_setf(d, fp)
 }
 
 /*
 }
 
 /*
- * Detach 'd' from its current interface (if attached at all) and attach to 
- * the interface named 'name'.  Return ioctl error code or 0.
+ * Detach a file from its current interface (if attached at all) and attach
+ * to the interface indicated by the name stored in ifr.
+ * Return an errno or 0.
  */
 static int
 bpf_setif(d, ifr)
  */
 static int
 bpf_setif(d, ifr)
@@ -700,11 +797,11 @@ bpf_setif(d, ifr)
 {
        struct bpf_if *bp;
        char *cp;
 {
        struct bpf_if *bp;
        char *cp;
-       int unit, s;
+       int unit, s, error;
 
        /*
         * Separate string into name part and unit number.  Put a null
 
        /*
         * Separate string into name part and unit number.  Put a null
-        * byte at the end of the name part, and compute the number. 
+        * byte at the end of the name part, and compute the number.
         * If the a unit number is unspecified, the default is 0,
         * as initialized above.  XXX This should be common code.
         */
         * If the a unit number is unspecified, the default is 0,
         * as initialized above.  XXX This should be common code.
         */
@@ -726,20 +823,28 @@ bpf_setif(d, ifr)
        for (bp = bpf_iflist; bp != 0; bp = bp->bif_next) {
                struct ifnet *ifp = bp->bif_ifp;
 
        for (bp = bpf_iflist; bp != 0; bp = bp->bif_next) {
                struct ifnet *ifp = bp->bif_ifp;
 
-               if (ifp == 0 || unit != ifp->if_unit 
+               if (ifp == 0 || unit != ifp->if_unit
                    || strcmp(ifp->if_name, ifr->ifr_name) != 0)
                        continue;
                /*
                    || strcmp(ifp->if_name, ifr->ifr_name) != 0)
                        continue;
                /*
-                * We found the requested interface.  If we're
-                * already attached to it, just flush the buffer.
+                * We found the requested interface.
                 * If it's not up, return an error.
                 * If it's not up, return an error.
+                * Allocate the packet buffers if we need to.
+                * If we're already attached to requested interface,
+                * just flush the buffer.
                 */
                if ((ifp->if_flags & IFF_UP) == 0)
                        return (ENETDOWN);
                 */
                if ((ifp->if_flags & IFF_UP) == 0)
                        return (ENETDOWN);
+
+               if (d->bd_sbuf == 0) {
+                       error = bpf_allocbufs(d);
+                       if (error != 0)
+                               return (error);
+               }
                s = splimp();
                if (bp != d->bd_bif) {
                        if (d->bd_bif)
                s = splimp();
                if (bp != d->bd_bif) {
                        if (d->bd_bif)
-                               /* 
+                               /*
                                 * Detach if attached to something else.
                                 */
                                bpf_detachd(d);
                                 * Detach if attached to something else.
                                 */
                                bpf_detachd(d);
@@ -755,8 +860,8 @@ bpf_setif(d, ifr)
 }
 
 /*
 }
 
 /*
- * Lookup the name of the 'ifp' interface and return it in 'ifr->ifr_name'.
- * We augment the ifp's base name with its unit number.
+ * Convert an interface name plus unit number of an ifp to a single
+ * name which is returned in the ifr.
  */
 static void
 bpf_ifname(ifp, ifr)
  */
 static void
 bpf_ifname(ifp, ifr)
@@ -767,36 +872,51 @@ bpf_ifname(ifp, ifr)
        char *d = ifr->ifr_name;
 
        while (*d++ = *s++)
        char *d = ifr->ifr_name;
 
        while (*d++ = *s++)
-               ;
+               continue;
        /* XXX Assume that unit number is less than 10. */
        *d++ = ifp->if_unit + '0';
        *d = '\0';
 }
 
        /* XXX Assume that unit number is less than 10. */
        *d++ = ifp->if_unit + '0';
        *d = '\0';
 }
 
+/*
+ * The new select interface passes down the proc pointer; the old select
+ * stubs had to grab it out of the user struct.  This glue allows either case.
+ */
+#if BSD >= 199103
+#define bpf_select bpfselect
+#else
+int
+bpfselect(dev, rw)
+       register dev_t dev;
+       int rw;
+{
+       return (bpf_select(dev, rw, u.u_procp));
+}
+#endif
+
 /*
  * Support for select() system call
  * Inspired by the code in tty.c for the same purpose.
  *
 /*
  * Support for select() system call
  * Inspired by the code in tty.c for the same purpose.
  *
- * bpfselect - returns true iff the specific operation
- *     will not block indefinitely.  Otherwise, return
- *     false but make a note that a selwakeup() must be done.
+ * Return true iff the specific operation will not block indefinitely.
+ * Otherwise, return false but make a note that a selwakeup() must be done.
  */
 int
  */
 int
-bpfselect(dev, rw, p)
+bpf_select(dev, rw, p)
        register dev_t dev;
        int rw;
        struct proc *p;
 {
        register struct bpf_d *d;
        register int s;
        register dev_t dev;
        int rw;
        struct proc *p;
 {
        register struct bpf_d *d;
        register int s;
-       
+
        if (rw != FREAD)
                return (0);
        /*
         * An imitation of the FIONREAD ioctl code.
         */
        d = &bpf_dtab[minor(dev)];
        if (rw != FREAD)
                return (0);
        /*
         * An imitation of the FIONREAD ioctl code.
         */
        d = &bpf_dtab[minor(dev)];
-       
+
        s = splimp();
        if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0)) {
                /*
        s = splimp();
        if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0)) {
                /*
@@ -805,9 +925,12 @@ bpfselect(dev, rw, p)
                splx(s);
                return (1);
        }
                splx(s);
                return (1);
        }
+#if BSD >= 199103
+       selrecord(p, &d->bd_sel);
+#else
        /*
         * No data ready.  If there's already a select() waiting on this
        /*
         * No data ready.  If there's already a select() waiting on this
-        * minor device then this is a collision.  This shouldn't happen 
+        * minor device then this is a collision.  This shouldn't happen
         * because minors really should not be shared, but if a process
         * forks while one of these is open, it is possible that both
         * processes could select on the same descriptor.
         * because minors really should not be shared, but if a process
         * forks while one of these is open, it is possible that both
         * processes could select on the same descriptor.
@@ -816,13 +939,16 @@ bpfselect(dev, rw, p)
                d->bd_selcoll = 1;
        else
                d->bd_selproc = p;
                d->bd_selcoll = 1;
        else
                d->bd_selproc = p;
-
-       splx(s);        
+#endif
+       splx(s);
        return (0);
 }
 
 /*
        return (0);
 }
 
 /*
- * bpf_tap - incoming linkage from device drivers
+ * Incoming linkage from device drivers.  Process the packet pkt, of length
+ * pktlen, which is stored in a contiguous buffer.  The packet is parsed
+ * by each process' filter, and if accepted, stashed into the corresponding
+ * buffer.
  */
 void
 bpf_tap(arg, pkt, pktlen)
  */
 void
 bpf_tap(arg, pkt, pktlen)
@@ -863,7 +989,7 @@ bpf_mcopy(src, dst, len)
        while (len > 0) {
                if (m == 0)
                        panic("bpf_mcopy");
        while (len > 0) {
                if (m == 0)
                        panic("bpf_mcopy");
-               count = MIN(m->m_len, len);
+               count = min(m->m_len, len);
                bcopy(mtod(m, caddr_t), (caddr_t)dst, count);
                m = m->m_next;
                dst += count;
                bcopy(mtod(m, caddr_t), (caddr_t)dst, count);
                m = m->m_next;
                dst += count;
@@ -872,8 +998,7 @@ bpf_mcopy(src, dst, len)
 }
 
 /*
 }
 
 /*
- * bpf_mtap - incoming linkage from device drivers, when packet
- *   is in an mbuf chain
+ * Incoming linkage from device drivers, when packet is in an mbuf chain.
  */
 void
 bpf_mtap(arg, m)
  */
 void
 bpf_mtap(arg, m)
@@ -886,7 +1011,7 @@ bpf_mtap(arg, m)
        struct mbuf *m0;
 
        pktlen = 0;
        struct mbuf *m0;
 
        pktlen = 0;
-       for (m0 = m; m0 != m; m0 = m0->m_next)
+       for (m0 = m; m0 != 0; m0 = m0->m_next)
                pktlen += m0->m_len;
 
        for (d = bp->bif_dlist; d != 0; d = d->bd_next) {
                pktlen += m0->m_len;
 
        for (d = bp->bif_dlist; d != 0; d = d->bd_next) {
@@ -900,10 +1025,10 @@ bpf_mtap(arg, m)
 /*
  * Move the packet data from interface memory (pkt) into the
  * store buffer.  Return 1 if it's time to wakeup a listener (buffer full),
 /*
  * Move the packet data from interface memory (pkt) into the
  * store buffer.  Return 1 if it's time to wakeup a listener (buffer full),
- * otherwise 0.  'copy' is the routine called to do the actual data 
- * transfer.  'bcopy' is passed in to copy contiguous chunks, while
- * 'bpf_mcopy' is passed in to copy mbuf chains.  In the latter
- * case, 'pkt' is really an mbuf.
+ * otherwise 0.  "copy" is the routine called to do the actual data
+ * transfer.  bcopy is passed in to copy contiguous chunks, while
+ * bpf_mcopy is passed in to copy mbuf chains.  In the latter case,
+ * pkt is really an mbuf.
  */
 static void
 catchpacket(d, pkt, pktlen, snaplen, cpfn)
  */
 static void
 catchpacket(d, pkt, pktlen, snaplen, cpfn)
@@ -921,13 +1046,9 @@ catchpacket(d, pkt, pktlen, snaplen, cpfn)
         * much.  Otherwise, transfer the whole packet (unless
         * we hit the buffer size limit).
         */
         * much.  Otherwise, transfer the whole packet (unless
         * we hit the buffer size limit).
         */
-       if (snaplen <= pktlen)
-               totlen = snaplen + hdrlen;
-       else {
-               totlen = pktlen + hdrlen;
-               if (totlen > d->bd_bufsize)
-                       totlen = d->bd_bufsize;
-       }
+       totlen = hdrlen + min(snaplen, pktlen);
+       if (totlen > d->bd_bufsize)
+               totlen = d->bd_bufsize;
 
        /*
         * Round up the end of the previous packet to the next longword.
 
        /*
         * Round up the end of the previous packet to the next longword.
@@ -940,8 +1061,8 @@ catchpacket(d, pkt, pktlen, snaplen, cpfn)
                 * pending reads.
                 */
                if (d->bd_fbuf == 0) {
                 * pending reads.
                 */
                if (d->bd_fbuf == 0) {
-                       /* 
-                        * We haven't completed the previous read yet, 
+                       /*
+                        * We haven't completed the previous read yet,
                         * so drop the packet.
                         */
                        ++d->bd_dcount;
                         * so drop the packet.
                         */
                        ++d->bd_dcount;
@@ -951,7 +1072,7 @@ catchpacket(d, pkt, pktlen, snaplen, cpfn)
                bpf_wakeup(d);
                curlen = 0;
        }
                bpf_wakeup(d);
                curlen = 0;
        }
-       else if (d->bd_immediate) 
+       else if (d->bd_immediate)
                /*
                 * Immediate mode is set.  A packet arrived so any
                 * reads should be woken up.
                /*
                 * Immediate mode is set.  A packet arrived so any
                 * reads should be woken up.
@@ -962,14 +1083,12 @@ catchpacket(d, pkt, pktlen, snaplen, cpfn)
         * Append the bpf header.
         */
        hp = (struct bpf_hdr *)(d->bd_sbuf + curlen);
         * Append the bpf header.
         */
        hp = (struct bpf_hdr *)(d->bd_sbuf + curlen);
-#ifdef sun
-       uniqtime(&hp->bh_tstamp);
-#else
-#ifdef hp300
+#if BSD >= 199103
        microtime(&hp->bh_tstamp);
        microtime(&hp->bh_tstamp);
+#elif defined(sun)
+       uniqtime(&hp->bh_tstamp);
 #else
        hp->bh_tstamp = time;
 #else
        hp->bh_tstamp = time;
-#endif
 #endif
        hp->bh_datalen = pktlen;
        hp->bh_hdrlen = hdrlen;
 #endif
        hp->bh_datalen = pktlen;
        hp->bh_hdrlen = hdrlen;
@@ -980,14 +1099,13 @@ catchpacket(d, pkt, pktlen, snaplen, cpfn)
        d->bd_slen = curlen + totlen;
 }
 
        d->bd_slen = curlen + totlen;
 }
 
-/* 
+/*
  * Initialize all nonzero fields of a descriptor.
  */
 static int
  * Initialize all nonzero fields of a descriptor.
  */
 static int
-bpf_initd(d)
+bpf_allocbufs(d)
        register struct bpf_d *d;
 {
        register struct bpf_d *d;
 {
-       d->bd_bufsize = bpf_bufsize;
        d->bd_fbuf = (caddr_t)malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK);
        if (d->bd_fbuf == 0)
                return (ENOBUFS);
        d->bd_fbuf = (caddr_t)malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK);
        if (d->bd_fbuf == 0)
                return (ENOBUFS);
@@ -1003,8 +1121,35 @@ bpf_initd(d)
 }
 
 /*
 }
 
 /*
- * Register 'ifp' with bpf.  XXX
- * and 'driverp' is a pointer to the 'struct bpf_if *' in the driver's softc.
+ * Free buffers currently in use by a descriptor.
+ * Called on close.
+ */
+static void
+bpf_freed(d)
+       register struct bpf_d *d;
+{
+       /*
+        * We don't need to lock out interrupts since this descriptor has
+        * been detached from its interface and it yet hasn't been marked
+        * free.
+        */
+       if (d->bd_sbuf != 0) {
+               free(d->bd_sbuf, M_DEVBUF);
+               if (d->bd_hbuf != 0)
+                       free(d->bd_hbuf, M_DEVBUF);
+               if (d->bd_fbuf != 0)
+                       free(d->bd_fbuf, M_DEVBUF);
+       }
+       if (d->bd_filter)
+               free((caddr_t)d->bd_filter, M_DEVBUF);
+
+       D_MARKFREE(d);
+}
+
+/*
+ * Attach an interface to bpf.  driverp is a pointer to a (struct bpf_if *)
+ * in the driver's softc; dlt is the link layer type; hdrlen is the fixed
+ * size of the link header (variable length headers not yet supported).
  */
 void
 bpfattach(driverp, ifp, dlt, hdrlen)
  */
 void
 bpfattach(driverp, ifp, dlt, hdrlen)
@@ -1014,8 +1159,14 @@ bpfattach(driverp, ifp, dlt, hdrlen)
 {
        struct bpf_if *bp;
        int i;
 {
        struct bpf_if *bp;
        int i;
+#if BSD < 199103
+       static struct bpf_if bpf_ifs[NBPFILTER];
+       static int bpfifno;
 
 
+       bp = (bpfifno < NBPFILTER) ? &bpf_ifs[bpfifno++] : 0;
+#else
        bp = (struct bpf_if *)malloc(sizeof(*bp), M_DEVBUF, M_DONTWAIT);
        bp = (struct bpf_if *)malloc(sizeof(*bp), M_DEVBUF, M_DONTWAIT);
+#endif
        if (bp == 0)
                panic("bpfattach");
 
        if (bp == 0)
                panic("bpfattach");
 
@@ -1031,8 +1182,8 @@ bpfattach(driverp, ifp, dlt, hdrlen)
 
        /*
         * Compute the length of the bpf header.  This is not necessarily
 
        /*
         * Compute the length of the bpf header.  This is not necessarily
-        * equal to SIZEOF_BPF_HDR because we want to insert spacing such 
-        * that the network layer header begins on a longword boundary (for 
+        * equal to SIZEOF_BPF_HDR because we want to insert spacing such
+        * that the network layer header begins on a longword boundary (for
         * performance reasons and to alleviate alignment restrictions).
         */
        bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
         * performance reasons and to alleviate alignment restrictions).
         */
        bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
@@ -1047,12 +1198,13 @@ bpfattach(driverp, ifp, dlt, hdrlen)
        printf("bpf: %s%d attached\n", ifp->if_name, ifp->if_unit);
 }
 
        printf("bpf: %s%d attached\n", ifp->if_name, ifp->if_unit);
 }
 
+#if BSD >= 199103
 /* XXX This routine belongs in net/if.c. */
 /*
 /* XXX This routine belongs in net/if.c. */
 /*
- * Set/clear promiscuous mode on interface ifp based on the truth value`
+ * Set/clear promiscuous mode on interface ifp based on the truth value
  * of pswitch.  The calls are reference counted so that only the first
  * of pswitch.  The calls are reference counted so that only the first
- * on request actually has an effect, as does the final off request.
- * Results are undefined if the off and on requests are not matched.
+ * "on" request actually has an effect, as does the final "off" request.
+ * Results are undefined if the "off" and "on" requests are not matched.
  */
 int
 ifpromisc(ifp, pswitch)
  */
 int
 ifpromisc(ifp, pswitch)
@@ -1060,7 +1212,7 @@ ifpromisc(ifp, pswitch)
        int pswitch;
 {
        struct ifreq ifr;
        int pswitch;
 {
        struct ifreq ifr;
-       /* 
+       /*
         * If the device is not configured up, we cannot put it in
         * promiscuous mode.
         */
         * If the device is not configured up, we cannot put it in
         * promiscuous mode.
         */
@@ -1079,5 +1231,36 @@ ifpromisc(ifp, pswitch)
        ifr.ifr_flags = ifp->if_flags;
        return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
 }
        ifr.ifr_flags = ifp->if_flags;
        return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr));
 }
+#endif
 
 
-#endif (NBPFILTER > 0)
+#if BSD < 199103
+/*
+ * Allocate some memory for bpf.  This is temporary SunOS support, and
+ * is admittedly a hack.
+ * If resources unavaiable, return 0.
+ */
+static caddr_t
+bpf_alloc(size, canwait)
+       register int size;
+       register int canwait;
+{
+       register struct mbuf *m;
+
+       if ((unsigned)size > (MCLBYTES-8))
+               return 0;
+
+       MGET(m, canwait, MT_DATA);
+       if (m == 0)
+               return 0;
+       if ((unsigned)size > (MLEN-8)) {
+               MCLGET(m);
+               if (m->m_len != MCLBYTES) {
+                       m_freem(m);
+                       return 0;
+               }
+       }
+       *mtod(m, struct mbuf **) = m;
+       return mtod(m, caddr_t) + 8;
+}
+#endif
+#endif