1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1990, 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * This code is derived from the Stanford/CMU enet packet filter, 6df8bae1dSRodney W. Grimes * (net/enet.c) distributed as part of 4.3BSD, and code contributed 7df8bae1dSRodney W. Grimes * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence 8df8bae1dSRodney W. Grimes * Berkeley Laboratory. 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 19df8bae1dSRodney W. Grimes * must display the following acknowledgement: 20df8bae1dSRodney W. Grimes * This product includes software developed by the University of 21df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 22df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 23df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 24df8bae1dSRodney W. Grimes * without specific prior written permission. 25df8bae1dSRodney W. Grimes * 26df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36df8bae1dSRodney W. Grimes * SUCH DAMAGE. 37df8bae1dSRodney W. Grimes * 38df8bae1dSRodney W. Grimes * @(#)bpf.c 8.2 (Berkeley) 3/28/94 39df8bae1dSRodney W. Grimes * 40f8dc4716SMike Smith * $Id: bpf.c,v 1.47 1999/01/27 22:42:13 dillon Exp $ 41df8bae1dSRodney W. Grimes */ 42df8bae1dSRodney W. Grimes 43df8bae1dSRodney W. Grimes #include "bpfilter.h" 44df8bae1dSRodney W. Grimes 45df8bae1dSRodney W. Grimes #ifndef __GNUC__ 46df8bae1dSRodney W. Grimes #define inline 47df8bae1dSRodney W. Grimes #else 48df8bae1dSRodney W. Grimes #define inline __inline 49df8bae1dSRodney W. Grimes #endif 50df8bae1dSRodney W. Grimes 51df8bae1dSRodney W. Grimes #include <sys/param.h> 52df8bae1dSRodney W. Grimes #include <sys/systm.h> 53ce7609a4SBruce Evans #include <sys/conf.h> 544d1d4912SBruce Evans #include <sys/malloc.h> 55df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 56df8bae1dSRodney W. Grimes #include <sys/time.h> 57df8bae1dSRodney W. Grimes #include <sys/proc.h> 580310c19fSBruce Evans #include <sys/signalvar.h> 59528f627fSBruce Evans #include <sys/filio.h> 60528f627fSBruce Evans #include <sys/sockio.h> 61528f627fSBruce Evans #include <sys/ttycom.h> 62831d27a9SDon Lewis #include <sys/filedesc.h> 63df8bae1dSRodney W. Grimes 64df8bae1dSRodney W. Grimes #if defined(sparc) && BSD < 199103 65df8bae1dSRodney W. Grimes #include <sys/stream.h> 66df8bae1dSRodney W. Grimes #endif 67243ac7d8SPeter Wemm #include <sys/poll.h> 68df8bae1dSRodney W. Grimes 69df8bae1dSRodney W. Grimes #include <sys/socket.h> 70fba9235dSBruce Evans #include <sys/vnode.h> 71df8bae1dSRodney W. Grimes 72fba9235dSBruce Evans #include <net/if.h> 73df8bae1dSRodney W. Grimes #include <net/bpf.h> 74df8bae1dSRodney W. Grimes #include <net/bpfdesc.h> 75df8bae1dSRodney W. Grimes 76df8bae1dSRodney W. Grimes #include <netinet/in.h> 77df8bae1dSRodney W. Grimes #include <netinet/if_ether.h> 78df8bae1dSRodney W. Grimes #include <sys/kernel.h> 79f708ef1bSPoul-Henning Kamp #include <sys/sysctl.h> 807b778b5eSEivind Eklund 817b778b5eSEivind Eklund #include "opt_devfs.h" 827b778b5eSEivind Eklund 8353ac6efbSJulian Elischer #ifdef DEVFS 8453ac6efbSJulian Elischer #include <sys/devfsext.h> 8553ac6efbSJulian Elischer #endif /*DEVFS*/ 8687f6c662SJulian Elischer 87f8dc4716SMike Smith #if NBPFILTER > 0 8853ac6efbSJulian Elischer 89df8bae1dSRodney W. Grimes /* 90df8bae1dSRodney W. Grimes * Older BSDs don't have kernel malloc. 91df8bae1dSRodney W. Grimes */ 92df8bae1dSRodney W. Grimes #if BSD < 199103 93df8bae1dSRodney W. Grimes extern bcopy(); 94df8bae1dSRodney W. Grimes static caddr_t bpf_alloc(); 95df8bae1dSRodney W. Grimes #include <net/bpf_compat.h> 96df8bae1dSRodney W. Grimes #define BPF_BUFSIZE (MCLBYTES-8) 97df8bae1dSRodney W. Grimes #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, code, uio) 98df8bae1dSRodney W. Grimes #else 99df8bae1dSRodney W. Grimes #define BPF_BUFSIZE 4096 100df8bae1dSRodney W. Grimes #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, uio) 101df8bae1dSRodney W. Grimes #endif 102df8bae1dSRodney W. Grimes 103df8bae1dSRodney W. Grimes #define PRINET 26 /* interruptible */ 104df8bae1dSRodney W. Grimes 105df8bae1dSRodney W. Grimes /* 106df8bae1dSRodney W. Grimes * The default read buffer size is patchable. 107df8bae1dSRodney W. Grimes */ 108f708ef1bSPoul-Henning Kamp static int bpf_bufsize = BPF_BUFSIZE; 109f708ef1bSPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, bpf_bufsize, CTLFLAG_RW, 110f708ef1bSPoul-Henning Kamp &bpf_bufsize, 0, ""); 111df8bae1dSRodney W. Grimes 112df8bae1dSRodney W. Grimes /* 113df8bae1dSRodney W. Grimes * bpf_iflist is the list of interfaces; each corresponds to an ifnet 114df8bae1dSRodney W. Grimes * bpf_dtab holds the descriptors, indexed by minor device # 115df8bae1dSRodney W. Grimes */ 116f708ef1bSPoul-Henning Kamp static struct bpf_if *bpf_iflist; 117f708ef1bSPoul-Henning Kamp static struct bpf_d bpf_dtab[NBPFILTER]; 118ed0af9bcSJulian Elischer static int bpf_dtab_init; 119df8bae1dSRodney W. Grimes 120df8bae1dSRodney W. Grimes static int bpf_allocbufs __P((struct bpf_d *)); 121ce7609a4SBruce Evans static void bpf_attachd __P((struct bpf_d *d, struct bpf_if *bp)); 122ce7609a4SBruce Evans static void bpf_detachd __P((struct bpf_d *d)); 123df8bae1dSRodney W. Grimes static void bpf_freed __P((struct bpf_d *)); 124df8bae1dSRodney W. Grimes static void bpf_ifname __P((struct ifnet *, struct ifreq *)); 1258bcbc7dfSAlexander Langer static void bpf_mcopy __P((const void *, void *, size_t)); 126df8bae1dSRodney W. Grimes static int bpf_movein __P((struct uio *, int, 127df8bae1dSRodney W. Grimes struct mbuf **, struct sockaddr *, int *)); 128df8bae1dSRodney W. Grimes static int bpf_setif __P((struct bpf_d *, struct ifreq *)); 129df8bae1dSRodney W. Grimes static inline void 130df8bae1dSRodney W. Grimes bpf_wakeup __P((struct bpf_d *)); 131df8bae1dSRodney W. Grimes static void catchpacket __P((struct bpf_d *, u_char *, u_int, 1328bcbc7dfSAlexander Langer u_int, void (*)(const void *, void *, size_t))); 133df8bae1dSRodney W. Grimes static void reset_d __P((struct bpf_d *)); 134f708ef1bSPoul-Henning Kamp static int bpf_setf __P((struct bpf_d *, struct bpf_program *)); 135df8bae1dSRodney W. Grimes 13687f6c662SJulian Elischer static d_open_t bpfopen; 13787f6c662SJulian Elischer static d_close_t bpfclose; 13887f6c662SJulian Elischer static d_read_t bpfread; 13987f6c662SJulian Elischer static d_write_t bpfwrite; 14087f6c662SJulian Elischer static d_ioctl_t bpfioctl; 141243ac7d8SPeter Wemm static d_poll_t bpfpoll; 14287f6c662SJulian Elischer 14387f6c662SJulian Elischer #define CDEV_MAJOR 23 144d2f265faSPoul-Henning Kamp static struct cdevsw bpf_cdevsw = 14587f6c662SJulian Elischer { bpfopen, bpfclose, bpfread, bpfwrite, /*23*/ 14687f6c662SJulian Elischer bpfioctl, nostop, nullreset, nodevtotty,/* bpf */ 147243ac7d8SPeter Wemm bpfpoll, nommap, NULL, "bpf", NULL, -1 }; 14887f6c662SJulian Elischer 14987f6c662SJulian Elischer 150df8bae1dSRodney W. Grimes static int 151df8bae1dSRodney W. Grimes bpf_movein(uio, linktype, mp, sockp, datlen) 152df8bae1dSRodney W. Grimes register struct uio *uio; 153df8bae1dSRodney W. Grimes int linktype, *datlen; 154df8bae1dSRodney W. Grimes register struct mbuf **mp; 155df8bae1dSRodney W. Grimes register struct sockaddr *sockp; 156df8bae1dSRodney W. Grimes { 157df8bae1dSRodney W. Grimes struct mbuf *m; 158df8bae1dSRodney W. Grimes int error; 159df8bae1dSRodney W. Grimes int len; 160df8bae1dSRodney W. Grimes int hlen; 161df8bae1dSRodney W. Grimes 162df8bae1dSRodney W. Grimes /* 163df8bae1dSRodney W. Grimes * Build a sockaddr based on the data link layer type. 164df8bae1dSRodney W. Grimes * We do this at this level because the ethernet header 165df8bae1dSRodney W. Grimes * is copied directly into the data field of the sockaddr. 166df8bae1dSRodney W. Grimes * In the case of SLIP, there is no header and the packet 167df8bae1dSRodney W. Grimes * is forwarded as is. 168df8bae1dSRodney W. Grimes * Also, we are careful to leave room at the front of the mbuf 169df8bae1dSRodney W. Grimes * for the link level header. 170df8bae1dSRodney W. Grimes */ 171df8bae1dSRodney W. Grimes switch (linktype) { 172df8bae1dSRodney W. Grimes 173df8bae1dSRodney W. Grimes case DLT_SLIP: 174df8bae1dSRodney W. Grimes sockp->sa_family = AF_INET; 175df8bae1dSRodney W. Grimes hlen = 0; 176df8bae1dSRodney W. Grimes break; 177df8bae1dSRodney W. Grimes 178df8bae1dSRodney W. Grimes case DLT_EN10MB: 179df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 180df8bae1dSRodney W. Grimes /* XXX Would MAXLINKHDR be better? */ 181df8bae1dSRodney W. Grimes hlen = sizeof(struct ether_header); 182df8bae1dSRodney W. Grimes break; 183df8bae1dSRodney W. Grimes 184df8bae1dSRodney W. Grimes case DLT_FDDI: 185d41f24e7SDavid Greenman #if defined(__FreeBSD__) || defined(__bsdi__) 186d41f24e7SDavid Greenman sockp->sa_family = AF_IMPLINK; 187d41f24e7SDavid Greenman hlen = 0; 188d41f24e7SDavid Greenman #else 189df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 190df8bae1dSRodney W. Grimes /* XXX 4(FORMAC)+6(dst)+6(src)+3(LLC)+5(SNAP) */ 191df8bae1dSRodney W. Grimes hlen = 24; 192d41f24e7SDavid Greenman #endif 193df8bae1dSRodney W. Grimes break; 194df8bae1dSRodney W. Grimes 19522f05c43SAndrey A. Chernov case DLT_RAW: 196df8bae1dSRodney W. Grimes case DLT_NULL: 197df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 198df8bae1dSRodney W. Grimes hlen = 0; 199df8bae1dSRodney W. Grimes break; 200df8bae1dSRodney W. Grimes 2014f53e3ccSKenjiro Cho #ifdef __FreeBSD__ 2024f53e3ccSKenjiro Cho case DLT_ATM_RFC1483: 2034f53e3ccSKenjiro Cho /* 2044f53e3ccSKenjiro Cho * en atm driver requires 4-byte atm pseudo header. 2054f53e3ccSKenjiro Cho * though it isn't standard, vpi:vci needs to be 2064f53e3ccSKenjiro Cho * specified anyway. 2074f53e3ccSKenjiro Cho */ 2084f53e3ccSKenjiro Cho sockp->sa_family = AF_UNSPEC; 2094f53e3ccSKenjiro Cho hlen = 12; /* XXX 4(ATM_PH) + 3(LLC) + 5(SNAP) */ 2104f53e3ccSKenjiro Cho break; 2114f53e3ccSKenjiro Cho #endif 2124f53e3ccSKenjiro Cho 213df8bae1dSRodney W. Grimes default: 214df8bae1dSRodney W. Grimes return (EIO); 215df8bae1dSRodney W. Grimes } 216df8bae1dSRodney W. Grimes 217df8bae1dSRodney W. Grimes len = uio->uio_resid; 218df8bae1dSRodney W. Grimes *datlen = len - hlen; 219df8bae1dSRodney W. Grimes if ((unsigned)len > MCLBYTES) 220df8bae1dSRodney W. Grimes return (EIO); 221df8bae1dSRodney W. Grimes 222963e4c2aSGarrett Wollman MGETHDR(m, M_WAIT, MT_DATA); 223df8bae1dSRodney W. Grimes if (m == 0) 224df8bae1dSRodney W. Grimes return (ENOBUFS); 225963e4c2aSGarrett Wollman if (len > MHLEN) { 226df8bae1dSRodney W. Grimes #if BSD >= 199103 227df8bae1dSRodney W. Grimes MCLGET(m, M_WAIT); 228df8bae1dSRodney W. Grimes if ((m->m_flags & M_EXT) == 0) { 229df8bae1dSRodney W. Grimes #else 230df8bae1dSRodney W. Grimes MCLGET(m); 231df8bae1dSRodney W. Grimes if (m->m_len != MCLBYTES) { 232df8bae1dSRodney W. Grimes #endif 233df8bae1dSRodney W. Grimes error = ENOBUFS; 234df8bae1dSRodney W. Grimes goto bad; 235df8bae1dSRodney W. Grimes } 236df8bae1dSRodney W. Grimes } 237963e4c2aSGarrett Wollman m->m_pkthdr.len = m->m_len = len; 238963e4c2aSGarrett Wollman m->m_pkthdr.rcvif = NULL; 239df8bae1dSRodney W. Grimes *mp = m; 240df8bae1dSRodney W. Grimes /* 241df8bae1dSRodney W. Grimes * Make room for link header. 242df8bae1dSRodney W. Grimes */ 243df8bae1dSRodney W. Grimes if (hlen != 0) { 2444f079e2fSGarrett Wollman m->m_pkthdr.len -= hlen; 245df8bae1dSRodney W. Grimes m->m_len -= hlen; 246df8bae1dSRodney W. Grimes #if BSD >= 199103 247df8bae1dSRodney W. Grimes m->m_data += hlen; /* XXX */ 248df8bae1dSRodney W. Grimes #else 249df8bae1dSRodney W. Grimes m->m_off += hlen; 250df8bae1dSRodney W. Grimes #endif 251df8bae1dSRodney W. Grimes error = UIOMOVE((caddr_t)sockp->sa_data, hlen, UIO_WRITE, uio); 252df8bae1dSRodney W. Grimes if (error) 253df8bae1dSRodney W. Grimes goto bad; 254df8bae1dSRodney W. Grimes } 255df8bae1dSRodney W. Grimes error = UIOMOVE(mtod(m, caddr_t), len - hlen, UIO_WRITE, uio); 256df8bae1dSRodney W. Grimes if (!error) 257df8bae1dSRodney W. Grimes return (0); 258df8bae1dSRodney W. Grimes bad: 259df8bae1dSRodney W. Grimes m_freem(m); 260df8bae1dSRodney W. Grimes return (error); 261df8bae1dSRodney W. Grimes } 262df8bae1dSRodney W. Grimes 263df8bae1dSRodney W. Grimes /* 264df8bae1dSRodney W. Grimes * Attach file to the bpf interface, i.e. make d listen on bp. 265df8bae1dSRodney W. Grimes * Must be called at splimp. 266df8bae1dSRodney W. Grimes */ 267df8bae1dSRodney W. Grimes static void 268df8bae1dSRodney W. Grimes bpf_attachd(d, bp) 269df8bae1dSRodney W. Grimes struct bpf_d *d; 270df8bae1dSRodney W. Grimes struct bpf_if *bp; 271df8bae1dSRodney W. Grimes { 272df8bae1dSRodney W. Grimes /* 273df8bae1dSRodney W. Grimes * Point d at bp, and add d to the interface's list of listeners. 274df8bae1dSRodney W. Grimes * Finally, point the driver's bpf cookie at the interface so 275df8bae1dSRodney W. Grimes * it will divert packets to bpf. 276df8bae1dSRodney W. Grimes */ 277df8bae1dSRodney W. Grimes d->bd_bif = bp; 278df8bae1dSRodney W. Grimes d->bd_next = bp->bif_dlist; 279df8bae1dSRodney W. Grimes bp->bif_dlist = d; 280df8bae1dSRodney W. Grimes 2819b44ff22SGarrett Wollman bp->bif_ifp->if_bpf = bp; 282df8bae1dSRodney W. Grimes } 283df8bae1dSRodney W. Grimes 284df8bae1dSRodney W. Grimes /* 285df8bae1dSRodney W. Grimes * Detach a file from its interface. 286df8bae1dSRodney W. Grimes */ 287df8bae1dSRodney W. Grimes static void 288df8bae1dSRodney W. Grimes bpf_detachd(d) 289df8bae1dSRodney W. Grimes struct bpf_d *d; 290df8bae1dSRodney W. Grimes { 291df8bae1dSRodney W. Grimes struct bpf_d **p; 292df8bae1dSRodney W. Grimes struct bpf_if *bp; 293df8bae1dSRodney W. Grimes 294df8bae1dSRodney W. Grimes bp = d->bd_bif; 295df8bae1dSRodney W. Grimes /* 296df8bae1dSRodney W. Grimes * Check if this descriptor had requested promiscuous mode. 297df8bae1dSRodney W. Grimes * If so, turn it off. 298df8bae1dSRodney W. Grimes */ 299df8bae1dSRodney W. Grimes if (d->bd_promisc) { 300df8bae1dSRodney W. Grimes d->bd_promisc = 0; 301df8bae1dSRodney W. Grimes if (ifpromisc(bp->bif_ifp, 0)) 302df8bae1dSRodney W. Grimes /* 303df8bae1dSRodney W. Grimes * Something is really wrong if we were able to put 304df8bae1dSRodney W. Grimes * the driver into promiscuous mode, but can't 305df8bae1dSRodney W. Grimes * take it out. 306df8bae1dSRodney W. Grimes */ 307df8bae1dSRodney W. Grimes panic("bpf: ifpromisc failed"); 308df8bae1dSRodney W. Grimes } 309df8bae1dSRodney W. Grimes /* Remove d from the interface's descriptor list. */ 310df8bae1dSRodney W. Grimes p = &bp->bif_dlist; 311df8bae1dSRodney W. Grimes while (*p != d) { 312df8bae1dSRodney W. Grimes p = &(*p)->bd_next; 313df8bae1dSRodney W. Grimes if (*p == 0) 314df8bae1dSRodney W. Grimes panic("bpf_detachd: descriptor not in list"); 315df8bae1dSRodney W. Grimes } 316df8bae1dSRodney W. Grimes *p = (*p)->bd_next; 317df8bae1dSRodney W. Grimes if (bp->bif_dlist == 0) 318df8bae1dSRodney W. Grimes /* 319df8bae1dSRodney W. Grimes * Let the driver know that there are no more listeners. 320df8bae1dSRodney W. Grimes */ 3219b44ff22SGarrett Wollman d->bd_bif->bif_ifp->if_bpf = 0; 322df8bae1dSRodney W. Grimes d->bd_bif = 0; 323df8bae1dSRodney W. Grimes } 324df8bae1dSRodney W. Grimes 325df8bae1dSRodney W. Grimes 326df8bae1dSRodney W. Grimes /* 327df8bae1dSRodney W. Grimes * Mark a descriptor free by making it point to itself. 328df8bae1dSRodney W. Grimes * This is probably cheaper than marking with a constant since 329df8bae1dSRodney W. Grimes * the address should be in a register anyway. 330df8bae1dSRodney W. Grimes */ 331df8bae1dSRodney W. Grimes #define D_ISFREE(d) ((d) == (d)->bd_next) 332df8bae1dSRodney W. Grimes #define D_MARKFREE(d) ((d)->bd_next = (d)) 333df8bae1dSRodney W. Grimes #define D_MARKUSED(d) ((d)->bd_next = 0) 334df8bae1dSRodney W. Grimes 335df8bae1dSRodney W. Grimes /* 336df8bae1dSRodney W. Grimes * Open ethernet device. Returns ENXIO for illegal minor device number, 337df8bae1dSRodney W. Grimes * EBUSY if file is open by another process. 338df8bae1dSRodney W. Grimes */ 339df8bae1dSRodney W. Grimes /* ARGSUSED */ 34087f6c662SJulian Elischer static int 34160039670SBruce Evans bpfopen(dev, flags, fmt, p) 342df8bae1dSRodney W. Grimes dev_t dev; 34360039670SBruce Evans int flags; 34460039670SBruce Evans int fmt; 34560039670SBruce Evans struct proc *p; 346df8bae1dSRodney W. Grimes { 347df8bae1dSRodney W. Grimes register struct bpf_d *d; 348df8bae1dSRodney W. Grimes 349df8bae1dSRodney W. Grimes if (minor(dev) >= NBPFILTER) 350df8bae1dSRodney W. Grimes return (ENXIO); 351df8bae1dSRodney W. Grimes /* 352df8bae1dSRodney W. Grimes * Each minor can be opened by only one process. If the requested 353df8bae1dSRodney W. Grimes * minor is in use, return EBUSY. 354df8bae1dSRodney W. Grimes */ 355df8bae1dSRodney W. Grimes d = &bpf_dtab[minor(dev)]; 356df8bae1dSRodney W. Grimes if (!D_ISFREE(d)) 357df8bae1dSRodney W. Grimes return (EBUSY); 358df8bae1dSRodney W. Grimes 359df8bae1dSRodney W. Grimes /* Mark "free" and do most initialization. */ 360df8bae1dSRodney W. Grimes bzero((char *)d, sizeof(*d)); 361df8bae1dSRodney W. Grimes d->bd_bufsize = bpf_bufsize; 36200a83887SPaul Traina d->bd_sig = SIGIO; 363df8bae1dSRodney W. Grimes 364df8bae1dSRodney W. Grimes return (0); 365df8bae1dSRodney W. Grimes } 366df8bae1dSRodney W. Grimes 367df8bae1dSRodney W. Grimes /* 368df8bae1dSRodney W. Grimes * Close the descriptor by detaching it from its interface, 369df8bae1dSRodney W. Grimes * deallocating its buffers, and marking it free. 370df8bae1dSRodney W. Grimes */ 371df8bae1dSRodney W. Grimes /* ARGSUSED */ 37287f6c662SJulian Elischer static int 37360039670SBruce Evans bpfclose(dev, flags, fmt, p) 374df8bae1dSRodney W. Grimes dev_t dev; 37560039670SBruce Evans int flags; 37660039670SBruce Evans int fmt; 37760039670SBruce Evans struct proc *p; 378df8bae1dSRodney W. Grimes { 379df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 380df8bae1dSRodney W. Grimes register int s; 381df8bae1dSRodney W. Grimes 382831d27a9SDon Lewis funsetown(d->bd_sigio); 383df8bae1dSRodney W. Grimes s = splimp(); 384df8bae1dSRodney W. Grimes if (d->bd_bif) 385df8bae1dSRodney W. Grimes bpf_detachd(d); 386df8bae1dSRodney W. Grimes splx(s); 387df8bae1dSRodney W. Grimes bpf_freed(d); 388df8bae1dSRodney W. Grimes 389df8bae1dSRodney W. Grimes return (0); 390df8bae1dSRodney W. Grimes } 391df8bae1dSRodney W. Grimes 392df8bae1dSRodney W. Grimes /* 393df8bae1dSRodney W. Grimes * Support for SunOS, which does not have tsleep. 394df8bae1dSRodney W. Grimes */ 395df8bae1dSRodney W. Grimes #if BSD < 199103 396df8bae1dSRodney W. Grimes static 397df8bae1dSRodney W. Grimes bpf_timeout(arg) 398df8bae1dSRodney W. Grimes caddr_t arg; 399df8bae1dSRodney W. Grimes { 400df8bae1dSRodney W. Grimes struct bpf_d *d = (struct bpf_d *)arg; 401df8bae1dSRodney W. Grimes d->bd_timedout = 1; 402df8bae1dSRodney W. Grimes wakeup(arg); 403df8bae1dSRodney W. Grimes } 404df8bae1dSRodney W. Grimes 405df8bae1dSRodney W. Grimes #define BPF_SLEEP(chan, pri, s, t) bpf_sleep((struct bpf_d *)chan) 406df8bae1dSRodney W. Grimes 407df8bae1dSRodney W. Grimes int 408df8bae1dSRodney W. Grimes bpf_sleep(d) 409df8bae1dSRodney W. Grimes register struct bpf_d *d; 410df8bae1dSRodney W. Grimes { 411df8bae1dSRodney W. Grimes register int rto = d->bd_rtout; 412df8bae1dSRodney W. Grimes register int st; 413df8bae1dSRodney W. Grimes 414df8bae1dSRodney W. Grimes if (rto != 0) { 415df8bae1dSRodney W. Grimes d->bd_timedout = 0; 416df8bae1dSRodney W. Grimes timeout(bpf_timeout, (caddr_t)d, rto); 417df8bae1dSRodney W. Grimes } 418df8bae1dSRodney W. Grimes st = sleep((caddr_t)d, PRINET|PCATCH); 419df8bae1dSRodney W. Grimes if (rto != 0) { 420df8bae1dSRodney W. Grimes if (d->bd_timedout == 0) 421df8bae1dSRodney W. Grimes untimeout(bpf_timeout, (caddr_t)d); 422df8bae1dSRodney W. Grimes else if (st == 0) 423df8bae1dSRodney W. Grimes return EWOULDBLOCK; 424df8bae1dSRodney W. Grimes } 425df8bae1dSRodney W. Grimes return (st != 0) ? EINTR : 0; 426df8bae1dSRodney W. Grimes } 427df8bae1dSRodney W. Grimes #else 428df8bae1dSRodney W. Grimes #define BPF_SLEEP tsleep 429df8bae1dSRodney W. Grimes #endif 430df8bae1dSRodney W. Grimes 431df8bae1dSRodney W. Grimes /* 432df8bae1dSRodney W. Grimes * Rotate the packet buffers in descriptor d. Move the store buffer 433df8bae1dSRodney W. Grimes * into the hold slot, and the free buffer into the store slot. 434df8bae1dSRodney W. Grimes * Zero the length of the new store buffer. 435df8bae1dSRodney W. Grimes */ 436df8bae1dSRodney W. Grimes #define ROTATE_BUFFERS(d) \ 437df8bae1dSRodney W. Grimes (d)->bd_hbuf = (d)->bd_sbuf; \ 438df8bae1dSRodney W. Grimes (d)->bd_hlen = (d)->bd_slen; \ 439df8bae1dSRodney W. Grimes (d)->bd_sbuf = (d)->bd_fbuf; \ 440df8bae1dSRodney W. Grimes (d)->bd_slen = 0; \ 441df8bae1dSRodney W. Grimes (d)->bd_fbuf = 0; 442df8bae1dSRodney W. Grimes /* 443df8bae1dSRodney W. Grimes * bpfread - read next chunk of packets from buffers 444df8bae1dSRodney W. Grimes */ 44587f6c662SJulian Elischer static int 44660039670SBruce Evans bpfread(dev, uio, ioflag) 447df8bae1dSRodney W. Grimes dev_t dev; 448df8bae1dSRodney W. Grimes register struct uio *uio; 44960039670SBruce Evans int ioflag; 450df8bae1dSRodney W. Grimes { 451df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 452df8bae1dSRodney W. Grimes int error; 453df8bae1dSRodney W. Grimes int s; 454df8bae1dSRodney W. Grimes 455df8bae1dSRodney W. Grimes /* 456df8bae1dSRodney W. Grimes * Restrict application to use a buffer the same size as 457df8bae1dSRodney W. Grimes * as kernel buffers. 458df8bae1dSRodney W. Grimes */ 459df8bae1dSRodney W. Grimes if (uio->uio_resid != d->bd_bufsize) 460df8bae1dSRodney W. Grimes return (EINVAL); 461df8bae1dSRodney W. Grimes 462df8bae1dSRodney W. Grimes s = splimp(); 463df8bae1dSRodney W. Grimes /* 464df8bae1dSRodney W. Grimes * If the hold buffer is empty, then do a timed sleep, which 465df8bae1dSRodney W. Grimes * ends when the timeout expires or when enough packets 466df8bae1dSRodney W. Grimes * have arrived to fill the store buffer. 467df8bae1dSRodney W. Grimes */ 468df8bae1dSRodney W. Grimes while (d->bd_hbuf == 0) { 469df8bae1dSRodney W. Grimes if (d->bd_immediate && d->bd_slen != 0) { 470df8bae1dSRodney W. Grimes /* 471df8bae1dSRodney W. Grimes * A packet(s) either arrived since the previous 472df8bae1dSRodney W. Grimes * read or arrived while we were asleep. 473df8bae1dSRodney W. Grimes * Rotate the buffers and return what's here. 474df8bae1dSRodney W. Grimes */ 475df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 476df8bae1dSRodney W. Grimes break; 477df8bae1dSRodney W. Grimes } 478fba9235dSBruce Evans if (ioflag & IO_NDELAY) 479fba9235dSBruce Evans error = EWOULDBLOCK; 480fba9235dSBruce Evans else 481df8bae1dSRodney W. Grimes error = BPF_SLEEP((caddr_t)d, PRINET|PCATCH, "bpf", 482df8bae1dSRodney W. Grimes d->bd_rtout); 483df8bae1dSRodney W. Grimes if (error == EINTR || error == ERESTART) { 484df8bae1dSRodney W. Grimes splx(s); 485df8bae1dSRodney W. Grimes return (error); 486df8bae1dSRodney W. Grimes } 487df8bae1dSRodney W. Grimes if (error == EWOULDBLOCK) { 488df8bae1dSRodney W. Grimes /* 489df8bae1dSRodney W. Grimes * On a timeout, return what's in the buffer, 490df8bae1dSRodney W. Grimes * which may be nothing. If there is something 491df8bae1dSRodney W. Grimes * in the store buffer, we can rotate the buffers. 492df8bae1dSRodney W. Grimes */ 493df8bae1dSRodney W. Grimes if (d->bd_hbuf) 494df8bae1dSRodney W. Grimes /* 495df8bae1dSRodney W. Grimes * We filled up the buffer in between 496df8bae1dSRodney W. Grimes * getting the timeout and arriving 497df8bae1dSRodney W. Grimes * here, so we don't need to rotate. 498df8bae1dSRodney W. Grimes */ 499df8bae1dSRodney W. Grimes break; 500df8bae1dSRodney W. Grimes 501df8bae1dSRodney W. Grimes if (d->bd_slen == 0) { 502df8bae1dSRodney W. Grimes splx(s); 503df8bae1dSRodney W. Grimes return (0); 504df8bae1dSRodney W. Grimes } 505df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 506df8bae1dSRodney W. Grimes break; 507df8bae1dSRodney W. Grimes } 508df8bae1dSRodney W. Grimes } 509df8bae1dSRodney W. Grimes /* 510df8bae1dSRodney W. Grimes * At this point, we know we have something in the hold slot. 511df8bae1dSRodney W. Grimes */ 512df8bae1dSRodney W. Grimes splx(s); 513df8bae1dSRodney W. Grimes 514df8bae1dSRodney W. Grimes /* 515df8bae1dSRodney W. Grimes * Move data from hold buffer into user space. 516df8bae1dSRodney W. Grimes * We know the entire buffer is transferred since 517df8bae1dSRodney W. Grimes * we checked above that the read buffer is bpf_bufsize bytes. 518df8bae1dSRodney W. Grimes */ 519df8bae1dSRodney W. Grimes error = UIOMOVE(d->bd_hbuf, d->bd_hlen, UIO_READ, uio); 520df8bae1dSRodney W. Grimes 521df8bae1dSRodney W. Grimes s = splimp(); 522df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 523df8bae1dSRodney W. Grimes d->bd_hbuf = 0; 524df8bae1dSRodney W. Grimes d->bd_hlen = 0; 525df8bae1dSRodney W. Grimes splx(s); 526df8bae1dSRodney W. Grimes 527df8bae1dSRodney W. Grimes return (error); 528df8bae1dSRodney W. Grimes } 529df8bae1dSRodney W. Grimes 530df8bae1dSRodney W. Grimes 531df8bae1dSRodney W. Grimes /* 532df8bae1dSRodney W. Grimes * If there are processes sleeping on this descriptor, wake them up. 533df8bae1dSRodney W. Grimes */ 534df8bae1dSRodney W. Grimes static inline void 535df8bae1dSRodney W. Grimes bpf_wakeup(d) 536df8bae1dSRodney W. Grimes register struct bpf_d *d; 537df8bae1dSRodney W. Grimes { 538df8bae1dSRodney W. Grimes wakeup((caddr_t)d); 539831d27a9SDon Lewis if (d->bd_async && d->bd_sig && d->bd_sigio) 540831d27a9SDon Lewis pgsigio(d->bd_sigio, d->bd_sig, 0); 54100a83887SPaul Traina 542df8bae1dSRodney W. Grimes #if BSD >= 199103 543df8bae1dSRodney W. Grimes selwakeup(&d->bd_sel); 544df8bae1dSRodney W. Grimes /* XXX */ 545df8bae1dSRodney W. Grimes d->bd_sel.si_pid = 0; 546df8bae1dSRodney W. Grimes #else 547df8bae1dSRodney W. Grimes if (d->bd_selproc) { 548df8bae1dSRodney W. Grimes selwakeup(d->bd_selproc, (int)d->bd_selcoll); 549df8bae1dSRodney W. Grimes d->bd_selcoll = 0; 550df8bae1dSRodney W. Grimes d->bd_selproc = 0; 551df8bae1dSRodney W. Grimes } 552df8bae1dSRodney W. Grimes #endif 553df8bae1dSRodney W. Grimes } 554df8bae1dSRodney W. Grimes 55587f6c662SJulian Elischer static int 55660039670SBruce Evans bpfwrite(dev, uio, ioflag) 557df8bae1dSRodney W. Grimes dev_t dev; 558df8bae1dSRodney W. Grimes struct uio *uio; 55960039670SBruce Evans int ioflag; 560df8bae1dSRodney W. Grimes { 561df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 562df8bae1dSRodney W. Grimes struct ifnet *ifp; 563df8bae1dSRodney W. Grimes struct mbuf *m; 564df8bae1dSRodney W. Grimes int error, s; 565df8bae1dSRodney W. Grimes static struct sockaddr dst; 566df8bae1dSRodney W. Grimes int datlen; 567df8bae1dSRodney W. Grimes 568df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 569df8bae1dSRodney W. Grimes return (ENXIO); 570df8bae1dSRodney W. Grimes 571df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 572df8bae1dSRodney W. Grimes 573df8bae1dSRodney W. Grimes if (uio->uio_resid == 0) 574df8bae1dSRodney W. Grimes return (0); 575df8bae1dSRodney W. Grimes 576df8bae1dSRodney W. Grimes error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, &dst, &datlen); 577df8bae1dSRodney W. Grimes if (error) 578df8bae1dSRodney W. Grimes return (error); 579df8bae1dSRodney W. Grimes 580df8bae1dSRodney W. Grimes if (datlen > ifp->if_mtu) 581df8bae1dSRodney W. Grimes return (EMSGSIZE); 582df8bae1dSRodney W. Grimes 583df8bae1dSRodney W. Grimes s = splnet(); 584df8bae1dSRodney W. Grimes #if BSD >= 199103 585df8bae1dSRodney W. Grimes error = (*ifp->if_output)(ifp, m, &dst, (struct rtentry *)0); 586df8bae1dSRodney W. Grimes #else 587df8bae1dSRodney W. Grimes error = (*ifp->if_output)(ifp, m, &dst); 588df8bae1dSRodney W. Grimes #endif 589df8bae1dSRodney W. Grimes splx(s); 590df8bae1dSRodney W. Grimes /* 591df8bae1dSRodney W. Grimes * The driver frees the mbuf. 592df8bae1dSRodney W. Grimes */ 593df8bae1dSRodney W. Grimes return (error); 594df8bae1dSRodney W. Grimes } 595df8bae1dSRodney W. Grimes 596df8bae1dSRodney W. Grimes /* 597df8bae1dSRodney W. Grimes * Reset a descriptor by flushing its packet buffer and clearing the 598df8bae1dSRodney W. Grimes * receive and drop counts. Should be called at splimp. 599df8bae1dSRodney W. Grimes */ 600df8bae1dSRodney W. Grimes static void 601df8bae1dSRodney W. Grimes reset_d(d) 602df8bae1dSRodney W. Grimes struct bpf_d *d; 603df8bae1dSRodney W. Grimes { 604df8bae1dSRodney W. Grimes if (d->bd_hbuf) { 605df8bae1dSRodney W. Grimes /* Free the hold buffer. */ 606df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 607df8bae1dSRodney W. Grimes d->bd_hbuf = 0; 608df8bae1dSRodney W. Grimes } 609df8bae1dSRodney W. Grimes d->bd_slen = 0; 610df8bae1dSRodney W. Grimes d->bd_hlen = 0; 611df8bae1dSRodney W. Grimes d->bd_rcount = 0; 612df8bae1dSRodney W. Grimes d->bd_dcount = 0; 613df8bae1dSRodney W. Grimes } 614df8bae1dSRodney W. Grimes 615df8bae1dSRodney W. Grimes /* 616df8bae1dSRodney W. Grimes * FIONREAD Check for read packet available. 617df8bae1dSRodney W. Grimes * SIOCGIFADDR Get interface address - convenient hook to driver. 618df8bae1dSRodney W. Grimes * BIOCGBLEN Get buffer len [for read()]. 619df8bae1dSRodney W. Grimes * BIOCSETF Set ethernet read filter. 620df8bae1dSRodney W. Grimes * BIOCFLUSH Flush read packet buffer. 621df8bae1dSRodney W. Grimes * BIOCPROMISC Put interface into promiscuous mode. 622df8bae1dSRodney W. Grimes * BIOCGDLT Get link layer type. 623df8bae1dSRodney W. Grimes * BIOCGETIF Get interface name. 624df8bae1dSRodney W. Grimes * BIOCSETIF Set interface. 625df8bae1dSRodney W. Grimes * BIOCSRTIMEOUT Set read timeout. 626df8bae1dSRodney W. Grimes * BIOCGRTIMEOUT Get read timeout. 627df8bae1dSRodney W. Grimes * BIOCGSTATS Get packet stats. 628df8bae1dSRodney W. Grimes * BIOCIMMEDIATE Set immediate mode. 629df8bae1dSRodney W. Grimes * BIOCVERSION Get filter language version. 630df8bae1dSRodney W. Grimes */ 631df8bae1dSRodney W. Grimes /* ARGSUSED */ 63287f6c662SJulian Elischer static int 63360039670SBruce Evans bpfioctl(dev, cmd, addr, flags, p) 634df8bae1dSRodney W. Grimes dev_t dev; 635ecbb00a2SDoug Rabson u_long cmd; 636df8bae1dSRodney W. Grimes caddr_t addr; 63760039670SBruce Evans int flags; 63860039670SBruce Evans struct proc *p; 639df8bae1dSRodney W. Grimes { 640df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 641df8bae1dSRodney W. Grimes int s, error = 0; 642df8bae1dSRodney W. Grimes 643df8bae1dSRodney W. Grimes switch (cmd) { 644df8bae1dSRodney W. Grimes 645df8bae1dSRodney W. Grimes default: 646df8bae1dSRodney W. Grimes error = EINVAL; 647df8bae1dSRodney W. Grimes break; 648df8bae1dSRodney W. Grimes 649df8bae1dSRodney W. Grimes /* 650df8bae1dSRodney W. Grimes * Check for read packet available. 651df8bae1dSRodney W. Grimes */ 652df8bae1dSRodney W. Grimes case FIONREAD: 653df8bae1dSRodney W. Grimes { 654df8bae1dSRodney W. Grimes int n; 655df8bae1dSRodney W. Grimes 656df8bae1dSRodney W. Grimes s = splimp(); 657df8bae1dSRodney W. Grimes n = d->bd_slen; 658df8bae1dSRodney W. Grimes if (d->bd_hbuf) 659df8bae1dSRodney W. Grimes n += d->bd_hlen; 660df8bae1dSRodney W. Grimes splx(s); 661df8bae1dSRodney W. Grimes 662df8bae1dSRodney W. Grimes *(int *)addr = n; 663df8bae1dSRodney W. Grimes break; 664df8bae1dSRodney W. Grimes } 665df8bae1dSRodney W. Grimes 666df8bae1dSRodney W. Grimes case SIOCGIFADDR: 667df8bae1dSRodney W. Grimes { 668df8bae1dSRodney W. Grimes struct ifnet *ifp; 669df8bae1dSRodney W. Grimes 670df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 671df8bae1dSRodney W. Grimes error = EINVAL; 672df8bae1dSRodney W. Grimes else { 673df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 674df8bae1dSRodney W. Grimes error = (*ifp->if_ioctl)(ifp, cmd, addr); 675df8bae1dSRodney W. Grimes } 676df8bae1dSRodney W. Grimes break; 677df8bae1dSRodney W. Grimes } 678df8bae1dSRodney W. Grimes 679df8bae1dSRodney W. Grimes /* 680df8bae1dSRodney W. Grimes * Get buffer len [for read()]. 681df8bae1dSRodney W. Grimes */ 682df8bae1dSRodney W. Grimes case BIOCGBLEN: 683df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bufsize; 684df8bae1dSRodney W. Grimes break; 685df8bae1dSRodney W. Grimes 686df8bae1dSRodney W. Grimes /* 687df8bae1dSRodney W. Grimes * Set buffer length. 688df8bae1dSRodney W. Grimes */ 689df8bae1dSRodney W. Grimes case BIOCSBLEN: 690df8bae1dSRodney W. Grimes #if BSD < 199103 691df8bae1dSRodney W. Grimes error = EINVAL; 692df8bae1dSRodney W. Grimes #else 693df8bae1dSRodney W. Grimes if (d->bd_bif != 0) 694df8bae1dSRodney W. Grimes error = EINVAL; 695df8bae1dSRodney W. Grimes else { 696df8bae1dSRodney W. Grimes register u_int size = *(u_int *)addr; 697df8bae1dSRodney W. Grimes 698df8bae1dSRodney W. Grimes if (size > BPF_MAXBUFSIZE) 699df8bae1dSRodney W. Grimes *(u_int *)addr = size = BPF_MAXBUFSIZE; 700df8bae1dSRodney W. Grimes else if (size < BPF_MINBUFSIZE) 701df8bae1dSRodney W. Grimes *(u_int *)addr = size = BPF_MINBUFSIZE; 702df8bae1dSRodney W. Grimes d->bd_bufsize = size; 703df8bae1dSRodney W. Grimes } 704df8bae1dSRodney W. Grimes #endif 705df8bae1dSRodney W. Grimes break; 706df8bae1dSRodney W. Grimes 707df8bae1dSRodney W. Grimes /* 708df8bae1dSRodney W. Grimes * Set link layer read filter. 709df8bae1dSRodney W. Grimes */ 710df8bae1dSRodney W. Grimes case BIOCSETF: 711df8bae1dSRodney W. Grimes error = bpf_setf(d, (struct bpf_program *)addr); 712df8bae1dSRodney W. Grimes break; 713df8bae1dSRodney W. Grimes 714df8bae1dSRodney W. Grimes /* 715df8bae1dSRodney W. Grimes * Flush read packet buffer. 716df8bae1dSRodney W. Grimes */ 717df8bae1dSRodney W. Grimes case BIOCFLUSH: 718df8bae1dSRodney W. Grimes s = splimp(); 719df8bae1dSRodney W. Grimes reset_d(d); 720df8bae1dSRodney W. Grimes splx(s); 721df8bae1dSRodney W. Grimes break; 722df8bae1dSRodney W. Grimes 723df8bae1dSRodney W. Grimes /* 724df8bae1dSRodney W. Grimes * Put interface into promiscuous mode. 725df8bae1dSRodney W. Grimes */ 726df8bae1dSRodney W. Grimes case BIOCPROMISC: 727df8bae1dSRodney W. Grimes if (d->bd_bif == 0) { 728df8bae1dSRodney W. Grimes /* 729df8bae1dSRodney W. Grimes * No interface attached yet. 730df8bae1dSRodney W. Grimes */ 731df8bae1dSRodney W. Grimes error = EINVAL; 732df8bae1dSRodney W. Grimes break; 733df8bae1dSRodney W. Grimes } 734df8bae1dSRodney W. Grimes s = splimp(); 735df8bae1dSRodney W. Grimes if (d->bd_promisc == 0) { 736df8bae1dSRodney W. Grimes error = ifpromisc(d->bd_bif->bif_ifp, 1); 737df8bae1dSRodney W. Grimes if (error == 0) 738df8bae1dSRodney W. Grimes d->bd_promisc = 1; 739df8bae1dSRodney W. Grimes } 740df8bae1dSRodney W. Grimes splx(s); 741df8bae1dSRodney W. Grimes break; 742df8bae1dSRodney W. Grimes 743df8bae1dSRodney W. Grimes /* 744df8bae1dSRodney W. Grimes * Get device parameters. 745df8bae1dSRodney W. Grimes */ 746df8bae1dSRodney W. Grimes case BIOCGDLT: 747df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 748df8bae1dSRodney W. Grimes error = EINVAL; 749df8bae1dSRodney W. Grimes else 750df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bif->bif_dlt; 751df8bae1dSRodney W. Grimes break; 752df8bae1dSRodney W. Grimes 753df8bae1dSRodney W. Grimes /* 754df8bae1dSRodney W. Grimes * Set interface name. 755df8bae1dSRodney W. Grimes */ 756df8bae1dSRodney W. Grimes case BIOCGETIF: 757df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 758df8bae1dSRodney W. Grimes error = EINVAL; 759df8bae1dSRodney W. Grimes else 760df8bae1dSRodney W. Grimes bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr); 761df8bae1dSRodney W. Grimes break; 762df8bae1dSRodney W. Grimes 763df8bae1dSRodney W. Grimes /* 764df8bae1dSRodney W. Grimes * Set interface. 765df8bae1dSRodney W. Grimes */ 766df8bae1dSRodney W. Grimes case BIOCSETIF: 767df8bae1dSRodney W. Grimes error = bpf_setif(d, (struct ifreq *)addr); 768df8bae1dSRodney W. Grimes break; 769df8bae1dSRodney W. Grimes 770df8bae1dSRodney W. Grimes /* 771df8bae1dSRodney W. Grimes * Set read timeout. 772df8bae1dSRodney W. Grimes */ 773df8bae1dSRodney W. Grimes case BIOCSRTIMEOUT: 774df8bae1dSRodney W. Grimes { 775df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 776df8bae1dSRodney W. Grimes 777bdc2cdc5SAlexander Langer /* 778bdc2cdc5SAlexander Langer * Subtract 1 tick from tvtohz() since this isn't 779bdc2cdc5SAlexander Langer * a one-shot timer. 780bdc2cdc5SAlexander Langer */ 781bdc2cdc5SAlexander Langer if ((error = itimerfix(tv)) == 0) 782bdc2cdc5SAlexander Langer d->bd_rtout = tvtohz(tv) - 1; 783df8bae1dSRodney W. Grimes break; 784df8bae1dSRodney W. Grimes } 785df8bae1dSRodney W. Grimes 786df8bae1dSRodney W. Grimes /* 787df8bae1dSRodney W. Grimes * Get read timeout. 788df8bae1dSRodney W. Grimes */ 789df8bae1dSRodney W. Grimes case BIOCGRTIMEOUT: 790df8bae1dSRodney W. Grimes { 791df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 792df8bae1dSRodney W. Grimes 793bdc2cdc5SAlexander Langer tv->tv_sec = d->bd_rtout / hz; 794bdc2cdc5SAlexander Langer tv->tv_usec = (d->bd_rtout % hz) * tick; 795df8bae1dSRodney W. Grimes break; 796df8bae1dSRodney W. Grimes } 797df8bae1dSRodney W. Grimes 798df8bae1dSRodney W. Grimes /* 799df8bae1dSRodney W. Grimes * Get packet stats. 800df8bae1dSRodney W. Grimes */ 801df8bae1dSRodney W. Grimes case BIOCGSTATS: 802df8bae1dSRodney W. Grimes { 803df8bae1dSRodney W. Grimes struct bpf_stat *bs = (struct bpf_stat *)addr; 804df8bae1dSRodney W. Grimes 805df8bae1dSRodney W. Grimes bs->bs_recv = d->bd_rcount; 806df8bae1dSRodney W. Grimes bs->bs_drop = d->bd_dcount; 807df8bae1dSRodney W. Grimes break; 808df8bae1dSRodney W. Grimes } 809df8bae1dSRodney W. Grimes 810df8bae1dSRodney W. Grimes /* 811df8bae1dSRodney W. Grimes * Set immediate mode. 812df8bae1dSRodney W. Grimes */ 813df8bae1dSRodney W. Grimes case BIOCIMMEDIATE: 814df8bae1dSRodney W. Grimes d->bd_immediate = *(u_int *)addr; 815df8bae1dSRodney W. Grimes break; 816df8bae1dSRodney W. Grimes 817df8bae1dSRodney W. Grimes case BIOCVERSION: 818df8bae1dSRodney W. Grimes { 819df8bae1dSRodney W. Grimes struct bpf_version *bv = (struct bpf_version *)addr; 820df8bae1dSRodney W. Grimes 821df8bae1dSRodney W. Grimes bv->bv_major = BPF_MAJOR_VERSION; 822df8bae1dSRodney W. Grimes bv->bv_minor = BPF_MINOR_VERSION; 823df8bae1dSRodney W. Grimes break; 824df8bae1dSRodney W. Grimes } 82500a83887SPaul Traina 82600a83887SPaul Traina case FIONBIO: /* Non-blocking I/O */ 82700a83887SPaul Traina break; 82800a83887SPaul Traina 82900a83887SPaul Traina case FIOASYNC: /* Send signal on receive packets */ 83000a83887SPaul Traina d->bd_async = *(int *)addr; 83100a83887SPaul Traina break; 83200a83887SPaul Traina 833831d27a9SDon Lewis case FIOSETOWN: 834831d27a9SDon Lewis error = fsetown(*(int *)addr, &d->bd_sigio); 83500a83887SPaul Traina break; 83600a83887SPaul Traina 837831d27a9SDon Lewis case FIOGETOWN: 838831d27a9SDon Lewis *(int *)addr = fgetown(d->bd_sigio); 839831d27a9SDon Lewis break; 840831d27a9SDon Lewis 841831d27a9SDon Lewis /* This is deprecated, FIOSETOWN should be used instead. */ 842831d27a9SDon Lewis case TIOCSPGRP: 843831d27a9SDon Lewis error = fsetown(-(*(int *)addr), &d->bd_sigio); 844831d27a9SDon Lewis break; 845831d27a9SDon Lewis 846831d27a9SDon Lewis /* This is deprecated, FIOGETOWN should be used instead. */ 84700a83887SPaul Traina case TIOCGPGRP: 848831d27a9SDon Lewis *(int *)addr = -fgetown(d->bd_sigio); 84900a83887SPaul Traina break; 85000a83887SPaul Traina 85100a83887SPaul Traina case BIOCSRSIG: /* Set receive signal */ 85200a83887SPaul Traina { 85300a83887SPaul Traina u_int sig; 85400a83887SPaul Traina 85500a83887SPaul Traina sig = *(u_int *)addr; 85600a83887SPaul Traina 85700a83887SPaul Traina if (sig >= NSIG) 85800a83887SPaul Traina error = EINVAL; 85900a83887SPaul Traina else 86000a83887SPaul Traina d->bd_sig = sig; 86100a83887SPaul Traina break; 86200a83887SPaul Traina } 86300a83887SPaul Traina case BIOCGRSIG: 86400a83887SPaul Traina *(u_int *)addr = d->bd_sig; 86500a83887SPaul Traina break; 866df8bae1dSRodney W. Grimes } 867df8bae1dSRodney W. Grimes return (error); 868df8bae1dSRodney W. Grimes } 869df8bae1dSRodney W. Grimes 870df8bae1dSRodney W. Grimes /* 871df8bae1dSRodney W. Grimes * Set d's packet filter program to fp. If this file already has a filter, 872df8bae1dSRodney W. Grimes * free it and replace it. Returns EINVAL for bogus requests. 873df8bae1dSRodney W. Grimes */ 874f708ef1bSPoul-Henning Kamp static int 875df8bae1dSRodney W. Grimes bpf_setf(d, fp) 876df8bae1dSRodney W. Grimes struct bpf_d *d; 877df8bae1dSRodney W. Grimes struct bpf_program *fp; 878df8bae1dSRodney W. Grimes { 879df8bae1dSRodney W. Grimes struct bpf_insn *fcode, *old; 880df8bae1dSRodney W. Grimes u_int flen, size; 881df8bae1dSRodney W. Grimes int s; 882df8bae1dSRodney W. Grimes 883df8bae1dSRodney W. Grimes old = d->bd_filter; 884df8bae1dSRodney W. Grimes if (fp->bf_insns == 0) { 885df8bae1dSRodney W. Grimes if (fp->bf_len != 0) 886df8bae1dSRodney W. Grimes return (EINVAL); 887df8bae1dSRodney W. Grimes s = splimp(); 888df8bae1dSRodney W. Grimes d->bd_filter = 0; 889df8bae1dSRodney W. Grimes reset_d(d); 890df8bae1dSRodney W. Grimes splx(s); 891df8bae1dSRodney W. Grimes if (old != 0) 892df8bae1dSRodney W. Grimes free((caddr_t)old, M_DEVBUF); 893df8bae1dSRodney W. Grimes return (0); 894df8bae1dSRodney W. Grimes } 895df8bae1dSRodney W. Grimes flen = fp->bf_len; 896df8bae1dSRodney W. Grimes if (flen > BPF_MAXINSNS) 897df8bae1dSRodney W. Grimes return (EINVAL); 898df8bae1dSRodney W. Grimes 899df8bae1dSRodney W. Grimes size = flen * sizeof(*fp->bf_insns); 900df8bae1dSRodney W. Grimes fcode = (struct bpf_insn *)malloc(size, M_DEVBUF, M_WAITOK); 901df8bae1dSRodney W. Grimes if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 && 902df8bae1dSRodney W. Grimes bpf_validate(fcode, (int)flen)) { 903df8bae1dSRodney W. Grimes s = splimp(); 904df8bae1dSRodney W. Grimes d->bd_filter = fcode; 905df8bae1dSRodney W. Grimes reset_d(d); 906df8bae1dSRodney W. Grimes splx(s); 907df8bae1dSRodney W. Grimes if (old != 0) 908df8bae1dSRodney W. Grimes free((caddr_t)old, M_DEVBUF); 909df8bae1dSRodney W. Grimes 910df8bae1dSRodney W. Grimes return (0); 911df8bae1dSRodney W. Grimes } 912df8bae1dSRodney W. Grimes free((caddr_t)fcode, M_DEVBUF); 913df8bae1dSRodney W. Grimes return (EINVAL); 914df8bae1dSRodney W. Grimes } 915df8bae1dSRodney W. Grimes 916df8bae1dSRodney W. Grimes /* 917df8bae1dSRodney W. Grimes * Detach a file from its current interface (if attached at all) and attach 918df8bae1dSRodney W. Grimes * to the interface indicated by the name stored in ifr. 919df8bae1dSRodney W. Grimes * Return an errno or 0. 920df8bae1dSRodney W. Grimes */ 921df8bae1dSRodney W. Grimes static int 922df8bae1dSRodney W. Grimes bpf_setif(d, ifr) 923df8bae1dSRodney W. Grimes struct bpf_d *d; 924df8bae1dSRodney W. Grimes struct ifreq *ifr; 925df8bae1dSRodney W. Grimes { 926df8bae1dSRodney W. Grimes struct bpf_if *bp; 9279b44ff22SGarrett Wollman int s, error; 9289b44ff22SGarrett Wollman struct ifnet *theywant; 929df8bae1dSRodney W. Grimes 9309b44ff22SGarrett Wollman theywant = ifunit(ifr->ifr_name); 9319b44ff22SGarrett Wollman if (theywant == 0) 9329b44ff22SGarrett Wollman return ENXIO; 9339b44ff22SGarrett Wollman 934df8bae1dSRodney W. Grimes /* 935df8bae1dSRodney W. Grimes * Look through attached interfaces for the named one. 936df8bae1dSRodney W. Grimes */ 937df8bae1dSRodney W. Grimes for (bp = bpf_iflist; bp != 0; bp = bp->bif_next) { 938df8bae1dSRodney W. Grimes struct ifnet *ifp = bp->bif_ifp; 939df8bae1dSRodney W. Grimes 9409b44ff22SGarrett Wollman if (ifp == 0 || ifp != theywant) 941df8bae1dSRodney W. Grimes continue; 942df8bae1dSRodney W. Grimes /* 943df8bae1dSRodney W. Grimes * We found the requested interface. 944df8bae1dSRodney W. Grimes * If it's not up, return an error. 945df8bae1dSRodney W. Grimes * Allocate the packet buffers if we need to. 946df8bae1dSRodney W. Grimes * If we're already attached to requested interface, 947df8bae1dSRodney W. Grimes * just flush the buffer. 948df8bae1dSRodney W. Grimes */ 949df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_UP) == 0) 950df8bae1dSRodney W. Grimes return (ENETDOWN); 951df8bae1dSRodney W. Grimes 952df8bae1dSRodney W. Grimes if (d->bd_sbuf == 0) { 953df8bae1dSRodney W. Grimes error = bpf_allocbufs(d); 954df8bae1dSRodney W. Grimes if (error != 0) 955df8bae1dSRodney W. Grimes return (error); 956df8bae1dSRodney W. Grimes } 957df8bae1dSRodney W. Grimes s = splimp(); 958df8bae1dSRodney W. Grimes if (bp != d->bd_bif) { 959df8bae1dSRodney W. Grimes if (d->bd_bif) 960df8bae1dSRodney W. Grimes /* 961df8bae1dSRodney W. Grimes * Detach if attached to something else. 962df8bae1dSRodney W. Grimes */ 963df8bae1dSRodney W. Grimes bpf_detachd(d); 964df8bae1dSRodney W. Grimes 965df8bae1dSRodney W. Grimes bpf_attachd(d, bp); 966df8bae1dSRodney W. Grimes } 967df8bae1dSRodney W. Grimes reset_d(d); 968df8bae1dSRodney W. Grimes splx(s); 969df8bae1dSRodney W. Grimes return (0); 970df8bae1dSRodney W. Grimes } 971df8bae1dSRodney W. Grimes /* Not found. */ 972df8bae1dSRodney W. Grimes return (ENXIO); 973df8bae1dSRodney W. Grimes } 974df8bae1dSRodney W. Grimes 975df8bae1dSRodney W. Grimes /* 976df8bae1dSRodney W. Grimes * Convert an interface name plus unit number of an ifp to a single 977df8bae1dSRodney W. Grimes * name which is returned in the ifr. 978df8bae1dSRodney W. Grimes */ 979df8bae1dSRodney W. Grimes static void 980df8bae1dSRodney W. Grimes bpf_ifname(ifp, ifr) 981df8bae1dSRodney W. Grimes struct ifnet *ifp; 982df8bae1dSRodney W. Grimes struct ifreq *ifr; 983df8bae1dSRodney W. Grimes { 984df8bae1dSRodney W. Grimes char *s = ifp->if_name; 985df8bae1dSRodney W. Grimes char *d = ifr->ifr_name; 986df8bae1dSRodney W. Grimes 987831a80b0SMatthew Dillon while ((*d++ = *s++) != 0) 988df8bae1dSRodney W. Grimes continue; 989a76f92a8SDavid Greenman d--; /* back to the null */ 990df8bae1dSRodney W. Grimes /* XXX Assume that unit number is less than 10. */ 991df8bae1dSRodney W. Grimes *d++ = ifp->if_unit + '0'; 992df8bae1dSRodney W. Grimes *d = '\0'; 993df8bae1dSRodney W. Grimes } 994df8bae1dSRodney W. Grimes 995df8bae1dSRodney W. Grimes /* 996243ac7d8SPeter Wemm * Support for select() and poll() system calls 997df8bae1dSRodney W. Grimes * 998df8bae1dSRodney W. Grimes * Return true iff the specific operation will not block indefinitely. 999df8bae1dSRodney W. Grimes * Otherwise, return false but make a note that a selwakeup() must be done. 1000df8bae1dSRodney W. Grimes */ 1001df8bae1dSRodney W. Grimes int 1002243ac7d8SPeter Wemm bpfpoll(dev, events, p) 1003df8bae1dSRodney W. Grimes register dev_t dev; 1004243ac7d8SPeter Wemm int events; 1005df8bae1dSRodney W. Grimes struct proc *p; 1006df8bae1dSRodney W. Grimes { 1007df8bae1dSRodney W. Grimes register struct bpf_d *d; 1008df8bae1dSRodney W. Grimes register int s; 1009243ac7d8SPeter Wemm int revents = 0; 1010df8bae1dSRodney W. Grimes 1011df8bae1dSRodney W. Grimes /* 1012df8bae1dSRodney W. Grimes * An imitation of the FIONREAD ioctl code. 1013df8bae1dSRodney W. Grimes */ 1014df8bae1dSRodney W. Grimes d = &bpf_dtab[minor(dev)]; 1015df8bae1dSRodney W. Grimes 1016df8bae1dSRodney W. Grimes s = splimp(); 1017243ac7d8SPeter Wemm if (events & (POLLIN | POLLRDNORM)) 1018243ac7d8SPeter Wemm if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0)) 1019243ac7d8SPeter Wemm revents |= events & (POLLIN | POLLRDNORM); 1020df8bae1dSRodney W. Grimes else 1021243ac7d8SPeter Wemm selrecord(p, &d->bd_sel); 1022243ac7d8SPeter Wemm 1023df8bae1dSRodney W. Grimes splx(s); 1024243ac7d8SPeter Wemm return (revents); 1025df8bae1dSRodney W. Grimes } 1026df8bae1dSRodney W. Grimes 1027df8bae1dSRodney W. Grimes /* 1028df8bae1dSRodney W. Grimes * Incoming linkage from device drivers. Process the packet pkt, of length 1029df8bae1dSRodney W. Grimes * pktlen, which is stored in a contiguous buffer. The packet is parsed 1030df8bae1dSRodney W. Grimes * by each process' filter, and if accepted, stashed into the corresponding 1031df8bae1dSRodney W. Grimes * buffer. 1032df8bae1dSRodney W. Grimes */ 1033df8bae1dSRodney W. Grimes void 10349b44ff22SGarrett Wollman bpf_tap(ifp, pkt, pktlen) 10359b44ff22SGarrett Wollman struct ifnet *ifp; 1036df8bae1dSRodney W. Grimes register u_char *pkt; 1037df8bae1dSRodney W. Grimes register u_int pktlen; 1038df8bae1dSRodney W. Grimes { 1039df8bae1dSRodney W. Grimes struct bpf_if *bp; 1040df8bae1dSRodney W. Grimes register struct bpf_d *d; 1041df8bae1dSRodney W. Grimes register u_int slen; 1042df8bae1dSRodney W. Grimes /* 1043df8bae1dSRodney W. Grimes * Note that the ipl does not have to be raised at this point. 1044df8bae1dSRodney W. Grimes * The only problem that could arise here is that if two different 1045df8bae1dSRodney W. Grimes * interfaces shared any data. This is not the case. 1046df8bae1dSRodney W. Grimes */ 10479b44ff22SGarrett Wollman bp = ifp->if_bpf; 1048df8bae1dSRodney W. Grimes for (d = bp->bif_dlist; d != 0; d = d->bd_next) { 1049df8bae1dSRodney W. Grimes ++d->bd_rcount; 1050df8bae1dSRodney W. Grimes slen = bpf_filter(d->bd_filter, pkt, pktlen, pktlen); 1051df8bae1dSRodney W. Grimes if (slen != 0) 1052df8bae1dSRodney W. Grimes catchpacket(d, pkt, pktlen, slen, bcopy); 1053df8bae1dSRodney W. Grimes } 1054df8bae1dSRodney W. Grimes } 1055df8bae1dSRodney W. Grimes 1056df8bae1dSRodney W. Grimes /* 1057df8bae1dSRodney W. Grimes * Copy data from an mbuf chain into a buffer. This code is derived 1058df8bae1dSRodney W. Grimes * from m_copydata in sys/uipc_mbuf.c. 1059df8bae1dSRodney W. Grimes */ 1060df8bae1dSRodney W. Grimes static void 1061df8bae1dSRodney W. Grimes bpf_mcopy(src_arg, dst_arg, len) 1062df8bae1dSRodney W. Grimes const void *src_arg; 1063df8bae1dSRodney W. Grimes void *dst_arg; 10648bcbc7dfSAlexander Langer register size_t len; 1065df8bae1dSRodney W. Grimes { 1066df8bae1dSRodney W. Grimes register const struct mbuf *m; 1067df8bae1dSRodney W. Grimes register u_int count; 1068df8bae1dSRodney W. Grimes u_char *dst; 1069df8bae1dSRodney W. Grimes 1070df8bae1dSRodney W. Grimes m = src_arg; 1071df8bae1dSRodney W. Grimes dst = dst_arg; 1072df8bae1dSRodney W. Grimes while (len > 0) { 1073df8bae1dSRodney W. Grimes if (m == 0) 1074df8bae1dSRodney W. Grimes panic("bpf_mcopy"); 1075df8bae1dSRodney W. Grimes count = min(m->m_len, len); 10760453d3cbSBruce Evans bcopy(mtod(m, void *), dst, count); 1077df8bae1dSRodney W. Grimes m = m->m_next; 1078df8bae1dSRodney W. Grimes dst += count; 1079df8bae1dSRodney W. Grimes len -= count; 1080df8bae1dSRodney W. Grimes } 1081df8bae1dSRodney W. Grimes } 1082df8bae1dSRodney W. Grimes 1083df8bae1dSRodney W. Grimes /* 1084df8bae1dSRodney W. Grimes * Incoming linkage from device drivers, when packet is in an mbuf chain. 1085df8bae1dSRodney W. Grimes */ 1086df8bae1dSRodney W. Grimes void 10879b44ff22SGarrett Wollman bpf_mtap(ifp, m) 10889b44ff22SGarrett Wollman struct ifnet *ifp; 1089df8bae1dSRodney W. Grimes struct mbuf *m; 1090df8bae1dSRodney W. Grimes { 10919b44ff22SGarrett Wollman struct bpf_if *bp = ifp->if_bpf; 1092df8bae1dSRodney W. Grimes struct bpf_d *d; 1093df8bae1dSRodney W. Grimes u_int pktlen, slen; 1094df8bae1dSRodney W. Grimes struct mbuf *m0; 1095df8bae1dSRodney W. Grimes 1096df8bae1dSRodney W. Grimes pktlen = 0; 1097df8bae1dSRodney W. Grimes for (m0 = m; m0 != 0; m0 = m0->m_next) 1098df8bae1dSRodney W. Grimes pktlen += m0->m_len; 1099df8bae1dSRodney W. Grimes 1100df8bae1dSRodney W. Grimes for (d = bp->bif_dlist; d != 0; d = d->bd_next) { 1101df8bae1dSRodney W. Grimes ++d->bd_rcount; 1102df8bae1dSRodney W. Grimes slen = bpf_filter(d->bd_filter, (u_char *)m, pktlen, 0); 1103df8bae1dSRodney W. Grimes if (slen != 0) 1104df8bae1dSRodney W. Grimes catchpacket(d, (u_char *)m, pktlen, slen, bpf_mcopy); 1105df8bae1dSRodney W. Grimes } 1106df8bae1dSRodney W. Grimes } 1107df8bae1dSRodney W. Grimes 1108df8bae1dSRodney W. Grimes /* 1109df8bae1dSRodney W. Grimes * Move the packet data from interface memory (pkt) into the 1110df8bae1dSRodney W. Grimes * store buffer. Return 1 if it's time to wakeup a listener (buffer full), 1111df8bae1dSRodney W. Grimes * otherwise 0. "copy" is the routine called to do the actual data 1112df8bae1dSRodney W. Grimes * transfer. bcopy is passed in to copy contiguous chunks, while 1113df8bae1dSRodney W. Grimes * bpf_mcopy is passed in to copy mbuf chains. In the latter case, 1114df8bae1dSRodney W. Grimes * pkt is really an mbuf. 1115df8bae1dSRodney W. Grimes */ 1116df8bae1dSRodney W. Grimes static void 1117df8bae1dSRodney W. Grimes catchpacket(d, pkt, pktlen, snaplen, cpfn) 1118df8bae1dSRodney W. Grimes register struct bpf_d *d; 1119df8bae1dSRodney W. Grimes register u_char *pkt; 1120df8bae1dSRodney W. Grimes register u_int pktlen, snaplen; 11218bcbc7dfSAlexander Langer register void (*cpfn) __P((const void *, void *, size_t)); 1122df8bae1dSRodney W. Grimes { 1123df8bae1dSRodney W. Grimes register struct bpf_hdr *hp; 1124df8bae1dSRodney W. Grimes register int totlen, curlen; 1125df8bae1dSRodney W. Grimes register int hdrlen = d->bd_bif->bif_hdrlen; 1126df8bae1dSRodney W. Grimes /* 1127df8bae1dSRodney W. Grimes * Figure out how many bytes to move. If the packet is 1128df8bae1dSRodney W. Grimes * greater or equal to the snapshot length, transfer that 1129df8bae1dSRodney W. Grimes * much. Otherwise, transfer the whole packet (unless 1130df8bae1dSRodney W. Grimes * we hit the buffer size limit). 1131df8bae1dSRodney W. Grimes */ 1132df8bae1dSRodney W. Grimes totlen = hdrlen + min(snaplen, pktlen); 1133df8bae1dSRodney W. Grimes if (totlen > d->bd_bufsize) 1134df8bae1dSRodney W. Grimes totlen = d->bd_bufsize; 1135df8bae1dSRodney W. Grimes 1136df8bae1dSRodney W. Grimes /* 1137df8bae1dSRodney W. Grimes * Round up the end of the previous packet to the next longword. 1138df8bae1dSRodney W. Grimes */ 1139df8bae1dSRodney W. Grimes curlen = BPF_WORDALIGN(d->bd_slen); 1140df8bae1dSRodney W. Grimes if (curlen + totlen > d->bd_bufsize) { 1141df8bae1dSRodney W. Grimes /* 1142df8bae1dSRodney W. Grimes * This packet will overflow the storage buffer. 1143df8bae1dSRodney W. Grimes * Rotate the buffers if we can, then wakeup any 1144df8bae1dSRodney W. Grimes * pending reads. 1145df8bae1dSRodney W. Grimes */ 1146df8bae1dSRodney W. Grimes if (d->bd_fbuf == 0) { 1147df8bae1dSRodney W. Grimes /* 1148df8bae1dSRodney W. Grimes * We haven't completed the previous read yet, 1149df8bae1dSRodney W. Grimes * so drop the packet. 1150df8bae1dSRodney W. Grimes */ 1151df8bae1dSRodney W. Grimes ++d->bd_dcount; 1152df8bae1dSRodney W. Grimes return; 1153df8bae1dSRodney W. Grimes } 1154df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 1155df8bae1dSRodney W. Grimes bpf_wakeup(d); 1156df8bae1dSRodney W. Grimes curlen = 0; 1157df8bae1dSRodney W. Grimes } 1158df8bae1dSRodney W. Grimes else if (d->bd_immediate) 1159df8bae1dSRodney W. Grimes /* 1160df8bae1dSRodney W. Grimes * Immediate mode is set. A packet arrived so any 1161df8bae1dSRodney W. Grimes * reads should be woken up. 1162df8bae1dSRodney W. Grimes */ 1163df8bae1dSRodney W. Grimes bpf_wakeup(d); 1164df8bae1dSRodney W. Grimes 1165df8bae1dSRodney W. Grimes /* 1166df8bae1dSRodney W. Grimes * Append the bpf header. 1167df8bae1dSRodney W. Grimes */ 1168df8bae1dSRodney W. Grimes hp = (struct bpf_hdr *)(d->bd_sbuf + curlen); 1169df8bae1dSRodney W. Grimes #if BSD >= 199103 1170df8bae1dSRodney W. Grimes microtime(&hp->bh_tstamp); 1171df8bae1dSRodney W. Grimes #elif defined(sun) 1172df8bae1dSRodney W. Grimes uniqtime(&hp->bh_tstamp); 1173df8bae1dSRodney W. Grimes #else 1174df8bae1dSRodney W. Grimes hp->bh_tstamp = time; 1175df8bae1dSRodney W. Grimes #endif 1176df8bae1dSRodney W. Grimes hp->bh_datalen = pktlen; 1177df8bae1dSRodney W. Grimes hp->bh_hdrlen = hdrlen; 1178df8bae1dSRodney W. Grimes /* 1179df8bae1dSRodney W. Grimes * Copy the packet data into the store buffer and update its length. 1180df8bae1dSRodney W. Grimes */ 1181df8bae1dSRodney W. Grimes (*cpfn)(pkt, (u_char *)hp + hdrlen, (hp->bh_caplen = totlen - hdrlen)); 1182df8bae1dSRodney W. Grimes d->bd_slen = curlen + totlen; 1183df8bae1dSRodney W. Grimes } 1184df8bae1dSRodney W. Grimes 1185df8bae1dSRodney W. Grimes /* 1186df8bae1dSRodney W. Grimes * Initialize all nonzero fields of a descriptor. 1187df8bae1dSRodney W. Grimes */ 1188df8bae1dSRodney W. Grimes static int 1189df8bae1dSRodney W. Grimes bpf_allocbufs(d) 1190df8bae1dSRodney W. Grimes register struct bpf_d *d; 1191df8bae1dSRodney W. Grimes { 1192df8bae1dSRodney W. Grimes d->bd_fbuf = (caddr_t)malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK); 1193df8bae1dSRodney W. Grimes if (d->bd_fbuf == 0) 1194df8bae1dSRodney W. Grimes return (ENOBUFS); 1195df8bae1dSRodney W. Grimes 1196df8bae1dSRodney W. Grimes d->bd_sbuf = (caddr_t)malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK); 1197df8bae1dSRodney W. Grimes if (d->bd_sbuf == 0) { 1198df8bae1dSRodney W. Grimes free(d->bd_fbuf, M_DEVBUF); 1199df8bae1dSRodney W. Grimes return (ENOBUFS); 1200df8bae1dSRodney W. Grimes } 1201df8bae1dSRodney W. Grimes d->bd_slen = 0; 1202df8bae1dSRodney W. Grimes d->bd_hlen = 0; 1203df8bae1dSRodney W. Grimes return (0); 1204df8bae1dSRodney W. Grimes } 1205df8bae1dSRodney W. Grimes 1206df8bae1dSRodney W. Grimes /* 1207df8bae1dSRodney W. Grimes * Free buffers currently in use by a descriptor. 1208df8bae1dSRodney W. Grimes * Called on close. 1209df8bae1dSRodney W. Grimes */ 1210df8bae1dSRodney W. Grimes static void 1211df8bae1dSRodney W. Grimes bpf_freed(d) 1212df8bae1dSRodney W. Grimes register struct bpf_d *d; 1213df8bae1dSRodney W. Grimes { 1214df8bae1dSRodney W. Grimes /* 1215df8bae1dSRodney W. Grimes * We don't need to lock out interrupts since this descriptor has 1216df8bae1dSRodney W. Grimes * been detached from its interface and it yet hasn't been marked 1217df8bae1dSRodney W. Grimes * free. 1218df8bae1dSRodney W. Grimes */ 1219df8bae1dSRodney W. Grimes if (d->bd_sbuf != 0) { 1220df8bae1dSRodney W. Grimes free(d->bd_sbuf, M_DEVBUF); 1221df8bae1dSRodney W. Grimes if (d->bd_hbuf != 0) 1222df8bae1dSRodney W. Grimes free(d->bd_hbuf, M_DEVBUF); 1223df8bae1dSRodney W. Grimes if (d->bd_fbuf != 0) 1224df8bae1dSRodney W. Grimes free(d->bd_fbuf, M_DEVBUF); 1225df8bae1dSRodney W. Grimes } 1226df8bae1dSRodney W. Grimes if (d->bd_filter) 1227df8bae1dSRodney W. Grimes free((caddr_t)d->bd_filter, M_DEVBUF); 1228df8bae1dSRodney W. Grimes 1229df8bae1dSRodney W. Grimes D_MARKFREE(d); 1230df8bae1dSRodney W. Grimes } 1231df8bae1dSRodney W. Grimes 1232df8bae1dSRodney W. Grimes /* 1233df8bae1dSRodney W. Grimes * Attach an interface to bpf. driverp is a pointer to a (struct bpf_if *) 1234df8bae1dSRodney W. Grimes * in the driver's softc; dlt is the link layer type; hdrlen is the fixed 1235df8bae1dSRodney W. Grimes * size of the link header (variable length headers not yet supported). 1236df8bae1dSRodney W. Grimes */ 1237df8bae1dSRodney W. Grimes void 12389b44ff22SGarrett Wollman bpfattach(ifp, dlt, hdrlen) 1239df8bae1dSRodney W. Grimes struct ifnet *ifp; 1240df8bae1dSRodney W. Grimes u_int dlt, hdrlen; 1241df8bae1dSRodney W. Grimes { 1242df8bae1dSRodney W. Grimes struct bpf_if *bp; 1243df8bae1dSRodney W. Grimes int i; 1244df8bae1dSRodney W. Grimes bp = (struct bpf_if *)malloc(sizeof(*bp), M_DEVBUF, M_DONTWAIT); 1245df8bae1dSRodney W. Grimes if (bp == 0) 1246df8bae1dSRodney W. Grimes panic("bpfattach"); 1247df8bae1dSRodney W. Grimes 1248df8bae1dSRodney W. Grimes bp->bif_dlist = 0; 1249df8bae1dSRodney W. Grimes bp->bif_ifp = ifp; 1250df8bae1dSRodney W. Grimes bp->bif_dlt = dlt; 1251df8bae1dSRodney W. Grimes 1252df8bae1dSRodney W. Grimes bp->bif_next = bpf_iflist; 1253df8bae1dSRodney W. Grimes bpf_iflist = bp; 1254df8bae1dSRodney W. Grimes 12559b44ff22SGarrett Wollman bp->bif_ifp->if_bpf = 0; 1256df8bae1dSRodney W. Grimes 1257df8bae1dSRodney W. Grimes /* 1258df8bae1dSRodney W. Grimes * Compute the length of the bpf header. This is not necessarily 1259df8bae1dSRodney W. Grimes * equal to SIZEOF_BPF_HDR because we want to insert spacing such 1260df8bae1dSRodney W. Grimes * that the network layer header begins on a longword boundary (for 1261df8bae1dSRodney W. Grimes * performance reasons and to alleviate alignment restrictions). 1262df8bae1dSRodney W. Grimes */ 1263df8bae1dSRodney W. Grimes bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen; 1264df8bae1dSRodney W. Grimes 1265df8bae1dSRodney W. Grimes /* 1266df8bae1dSRodney W. Grimes * Mark all the descriptors free if this hasn't been done. 1267df8bae1dSRodney W. Grimes */ 1268ed0af9bcSJulian Elischer if (!bpf_dtab_init) { 1269df8bae1dSRodney W. Grimes for (i = 0; i < NBPFILTER; ++i) 1270df8bae1dSRodney W. Grimes D_MARKFREE(&bpf_dtab[i]); 1271ed0af9bcSJulian Elischer bpf_dtab_init = 1; 1272ed0af9bcSJulian Elischer } 1273df8bae1dSRodney W. Grimes 12742eeab939SGarrett Wollman if (bootverbose) 1275df8bae1dSRodney W. Grimes printf("bpf: %s%d attached\n", ifp->if_name, ifp->if_unit); 1276df8bae1dSRodney W. Grimes } 127753ac6efbSJulian Elischer 1278ccbc58d3SMarc G. Fournier #ifdef DEVFS 127987f6c662SJulian Elischer static void *bpf_devfs_token[NBPFILTER]; 1280ccbc58d3SMarc G. Fournier #endif 128153ac6efbSJulian Elischer 1282e31abedeSBruce Evans static int bpf_devsw_installed; 128353ac6efbSJulian Elischer 1284514ede09SBruce Evans static void bpf_drvinit __P((void *unused)); 1285514ede09SBruce Evans static void 1286514ede09SBruce Evans bpf_drvinit(unused) 1287514ede09SBruce Evans void *unused; 128853ac6efbSJulian Elischer { 128953ac6efbSJulian Elischer dev_t dev; 1290ccbc58d3SMarc G. Fournier #ifdef DEVFS 129187f6c662SJulian Elischer int i; 1292ccbc58d3SMarc G. Fournier #endif 129353ac6efbSJulian Elischer 129453ac6efbSJulian Elischer if( ! bpf_devsw_installed ) { 129553ac6efbSJulian Elischer dev = makedev(CDEV_MAJOR, 0); 129653ac6efbSJulian Elischer cdevsw_add(&dev,&bpf_cdevsw, NULL); 129753ac6efbSJulian Elischer bpf_devsw_installed = 1; 129853ac6efbSJulian Elischer #ifdef DEVFS 1299ccbc58d3SMarc G. Fournier 130087f6c662SJulian Elischer for ( i = 0 ; i < NBPFILTER ; i++ ) { 130187f6c662SJulian Elischer bpf_devfs_token[i] = 1302ccbc58d3SMarc G. Fournier devfs_add_devswf(&bpf_cdevsw, i, DV_CHR, 0, 0, 1303ccbc58d3SMarc G. Fournier 0600, "bpf%d", i); 130453ac6efbSJulian Elischer } 130553ac6efbSJulian Elischer #endif 130653ac6efbSJulian Elischer } 13077198bf47SJulian Elischer } 130853ac6efbSJulian Elischer 130953ac6efbSJulian Elischer SYSINIT(bpfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,bpf_drvinit,NULL) 131053ac6efbSJulian Elischer 1311f8dc4716SMike Smith #else /* !BPFILTER */ 1312f8dc4716SMike Smith /* 1313f8dc4716SMike Smith * NOP stubs to allow bpf-using drivers to load and function. 1314f8dc4716SMike Smith * 1315f8dc4716SMike Smith * A 'better' implementation would allow the core bpf functionality 1316f8dc4716SMike Smith * to be loaded at runtime. 1317f8dc4716SMike Smith */ 1318f8dc4716SMike Smith 1319f8dc4716SMike Smith void 1320f8dc4716SMike Smith bpf_tap(ifp, pkt, pktlen) 1321f8dc4716SMike Smith struct ifnet *ifp; 1322f8dc4716SMike Smith register u_char *pkt; 1323f8dc4716SMike Smith register u_int pktlen; 1324f8dc4716SMike Smith { 1325f8dc4716SMike Smith } 1326f8dc4716SMike Smith 1327f8dc4716SMike Smith void 1328f8dc4716SMike Smith bpf_mtap(ifp, m) 1329f8dc4716SMike Smith struct ifnet *ifp; 1330f8dc4716SMike Smith struct mbuf *m; 1331f8dc4716SMike Smith { 1332f8dc4716SMike Smith } 1333f8dc4716SMike Smith 1334f8dc4716SMike Smith void 1335f8dc4716SMike Smith bpfattach(ifp, dlt, hdrlen) 1336f8dc4716SMike Smith struct ifnet *ifp; 1337f8dc4716SMike Smith u_int dlt, hdrlen; 1338f8dc4716SMike Smith { 1339f8dc4716SMike Smith } 1340f8dc4716SMike Smith 1341f8dc4716SMike Smith u_int 1342f8dc4716SMike Smith bpf_filter(pc, p, wirelen, buflen) 1343f8dc4716SMike Smith register struct bpf_insn *pc; 1344f8dc4716SMike Smith register u_char *p; 1345f8dc4716SMike Smith u_int wirelen; 1346f8dc4716SMike Smith register u_int buflen; 1347f8dc4716SMike Smith { 1348f8dc4716SMike Smith return -1; /* "no filter" behaviour */ 1349f8dc4716SMike Smith } 1350f8dc4716SMike Smith 1351df8bae1dSRodney W. Grimes #endif 1352