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 * 4075c13541SPoul-Henning Kamp * $Id: bpf.c,v 1.48 1999/04/28 01:18:13 msmith 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 34975c13541SPoul-Henning Kamp if (p->p_prison) 35075c13541SPoul-Henning Kamp return (EPERM); 35175c13541SPoul-Henning Kamp 352df8bae1dSRodney W. Grimes if (minor(dev) >= NBPFILTER) 353df8bae1dSRodney W. Grimes return (ENXIO); 354df8bae1dSRodney W. Grimes /* 355df8bae1dSRodney W. Grimes * Each minor can be opened by only one process. If the requested 356df8bae1dSRodney W. Grimes * minor is in use, return EBUSY. 357df8bae1dSRodney W. Grimes */ 358df8bae1dSRodney W. Grimes d = &bpf_dtab[minor(dev)]; 359df8bae1dSRodney W. Grimes if (!D_ISFREE(d)) 360df8bae1dSRodney W. Grimes return (EBUSY); 361df8bae1dSRodney W. Grimes 362df8bae1dSRodney W. Grimes /* Mark "free" and do most initialization. */ 363df8bae1dSRodney W. Grimes bzero((char *)d, sizeof(*d)); 364df8bae1dSRodney W. Grimes d->bd_bufsize = bpf_bufsize; 36500a83887SPaul Traina d->bd_sig = SIGIO; 366df8bae1dSRodney W. Grimes 367df8bae1dSRodney W. Grimes return (0); 368df8bae1dSRodney W. Grimes } 369df8bae1dSRodney W. Grimes 370df8bae1dSRodney W. Grimes /* 371df8bae1dSRodney W. Grimes * Close the descriptor by detaching it from its interface, 372df8bae1dSRodney W. Grimes * deallocating its buffers, and marking it free. 373df8bae1dSRodney W. Grimes */ 374df8bae1dSRodney W. Grimes /* ARGSUSED */ 37587f6c662SJulian Elischer static int 37660039670SBruce Evans bpfclose(dev, flags, fmt, p) 377df8bae1dSRodney W. Grimes dev_t dev; 37860039670SBruce Evans int flags; 37960039670SBruce Evans int fmt; 38060039670SBruce Evans struct proc *p; 381df8bae1dSRodney W. Grimes { 382df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 383df8bae1dSRodney W. Grimes register int s; 384df8bae1dSRodney W. Grimes 385831d27a9SDon Lewis funsetown(d->bd_sigio); 386df8bae1dSRodney W. Grimes s = splimp(); 387df8bae1dSRodney W. Grimes if (d->bd_bif) 388df8bae1dSRodney W. Grimes bpf_detachd(d); 389df8bae1dSRodney W. Grimes splx(s); 390df8bae1dSRodney W. Grimes bpf_freed(d); 391df8bae1dSRodney W. Grimes 392df8bae1dSRodney W. Grimes return (0); 393df8bae1dSRodney W. Grimes } 394df8bae1dSRodney W. Grimes 395df8bae1dSRodney W. Grimes /* 396df8bae1dSRodney W. Grimes * Support for SunOS, which does not have tsleep. 397df8bae1dSRodney W. Grimes */ 398df8bae1dSRodney W. Grimes #if BSD < 199103 399df8bae1dSRodney W. Grimes static 400df8bae1dSRodney W. Grimes bpf_timeout(arg) 401df8bae1dSRodney W. Grimes caddr_t arg; 402df8bae1dSRodney W. Grimes { 403df8bae1dSRodney W. Grimes struct bpf_d *d = (struct bpf_d *)arg; 404df8bae1dSRodney W. Grimes d->bd_timedout = 1; 405df8bae1dSRodney W. Grimes wakeup(arg); 406df8bae1dSRodney W. Grimes } 407df8bae1dSRodney W. Grimes 408df8bae1dSRodney W. Grimes #define BPF_SLEEP(chan, pri, s, t) bpf_sleep((struct bpf_d *)chan) 409df8bae1dSRodney W. Grimes 410df8bae1dSRodney W. Grimes int 411df8bae1dSRodney W. Grimes bpf_sleep(d) 412df8bae1dSRodney W. Grimes register struct bpf_d *d; 413df8bae1dSRodney W. Grimes { 414df8bae1dSRodney W. Grimes register int rto = d->bd_rtout; 415df8bae1dSRodney W. Grimes register int st; 416df8bae1dSRodney W. Grimes 417df8bae1dSRodney W. Grimes if (rto != 0) { 418df8bae1dSRodney W. Grimes d->bd_timedout = 0; 419df8bae1dSRodney W. Grimes timeout(bpf_timeout, (caddr_t)d, rto); 420df8bae1dSRodney W. Grimes } 421df8bae1dSRodney W. Grimes st = sleep((caddr_t)d, PRINET|PCATCH); 422df8bae1dSRodney W. Grimes if (rto != 0) { 423df8bae1dSRodney W. Grimes if (d->bd_timedout == 0) 424df8bae1dSRodney W. Grimes untimeout(bpf_timeout, (caddr_t)d); 425df8bae1dSRodney W. Grimes else if (st == 0) 426df8bae1dSRodney W. Grimes return EWOULDBLOCK; 427df8bae1dSRodney W. Grimes } 428df8bae1dSRodney W. Grimes return (st != 0) ? EINTR : 0; 429df8bae1dSRodney W. Grimes } 430df8bae1dSRodney W. Grimes #else 431df8bae1dSRodney W. Grimes #define BPF_SLEEP tsleep 432df8bae1dSRodney W. Grimes #endif 433df8bae1dSRodney W. Grimes 434df8bae1dSRodney W. Grimes /* 435df8bae1dSRodney W. Grimes * Rotate the packet buffers in descriptor d. Move the store buffer 436df8bae1dSRodney W. Grimes * into the hold slot, and the free buffer into the store slot. 437df8bae1dSRodney W. Grimes * Zero the length of the new store buffer. 438df8bae1dSRodney W. Grimes */ 439df8bae1dSRodney W. Grimes #define ROTATE_BUFFERS(d) \ 440df8bae1dSRodney W. Grimes (d)->bd_hbuf = (d)->bd_sbuf; \ 441df8bae1dSRodney W. Grimes (d)->bd_hlen = (d)->bd_slen; \ 442df8bae1dSRodney W. Grimes (d)->bd_sbuf = (d)->bd_fbuf; \ 443df8bae1dSRodney W. Grimes (d)->bd_slen = 0; \ 444df8bae1dSRodney W. Grimes (d)->bd_fbuf = 0; 445df8bae1dSRodney W. Grimes /* 446df8bae1dSRodney W. Grimes * bpfread - read next chunk of packets from buffers 447df8bae1dSRodney W. Grimes */ 44887f6c662SJulian Elischer static int 44960039670SBruce Evans bpfread(dev, uio, ioflag) 450df8bae1dSRodney W. Grimes dev_t dev; 451df8bae1dSRodney W. Grimes register struct uio *uio; 45260039670SBruce Evans int ioflag; 453df8bae1dSRodney W. Grimes { 454df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 455df8bae1dSRodney W. Grimes int error; 456df8bae1dSRodney W. Grimes int s; 457df8bae1dSRodney W. Grimes 458df8bae1dSRodney W. Grimes /* 459df8bae1dSRodney W. Grimes * Restrict application to use a buffer the same size as 460df8bae1dSRodney W. Grimes * as kernel buffers. 461df8bae1dSRodney W. Grimes */ 462df8bae1dSRodney W. Grimes if (uio->uio_resid != d->bd_bufsize) 463df8bae1dSRodney W. Grimes return (EINVAL); 464df8bae1dSRodney W. Grimes 465df8bae1dSRodney W. Grimes s = splimp(); 466df8bae1dSRodney W. Grimes /* 467df8bae1dSRodney W. Grimes * If the hold buffer is empty, then do a timed sleep, which 468df8bae1dSRodney W. Grimes * ends when the timeout expires or when enough packets 469df8bae1dSRodney W. Grimes * have arrived to fill the store buffer. 470df8bae1dSRodney W. Grimes */ 471df8bae1dSRodney W. Grimes while (d->bd_hbuf == 0) { 472df8bae1dSRodney W. Grimes if (d->bd_immediate && d->bd_slen != 0) { 473df8bae1dSRodney W. Grimes /* 474df8bae1dSRodney W. Grimes * A packet(s) either arrived since the previous 475df8bae1dSRodney W. Grimes * read or arrived while we were asleep. 476df8bae1dSRodney W. Grimes * Rotate the buffers and return what's here. 477df8bae1dSRodney W. Grimes */ 478df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 479df8bae1dSRodney W. Grimes break; 480df8bae1dSRodney W. Grimes } 481fba9235dSBruce Evans if (ioflag & IO_NDELAY) 482fba9235dSBruce Evans error = EWOULDBLOCK; 483fba9235dSBruce Evans else 484df8bae1dSRodney W. Grimes error = BPF_SLEEP((caddr_t)d, PRINET|PCATCH, "bpf", 485df8bae1dSRodney W. Grimes d->bd_rtout); 486df8bae1dSRodney W. Grimes if (error == EINTR || error == ERESTART) { 487df8bae1dSRodney W. Grimes splx(s); 488df8bae1dSRodney W. Grimes return (error); 489df8bae1dSRodney W. Grimes } 490df8bae1dSRodney W. Grimes if (error == EWOULDBLOCK) { 491df8bae1dSRodney W. Grimes /* 492df8bae1dSRodney W. Grimes * On a timeout, return what's in the buffer, 493df8bae1dSRodney W. Grimes * which may be nothing. If there is something 494df8bae1dSRodney W. Grimes * in the store buffer, we can rotate the buffers. 495df8bae1dSRodney W. Grimes */ 496df8bae1dSRodney W. Grimes if (d->bd_hbuf) 497df8bae1dSRodney W. Grimes /* 498df8bae1dSRodney W. Grimes * We filled up the buffer in between 499df8bae1dSRodney W. Grimes * getting the timeout and arriving 500df8bae1dSRodney W. Grimes * here, so we don't need to rotate. 501df8bae1dSRodney W. Grimes */ 502df8bae1dSRodney W. Grimes break; 503df8bae1dSRodney W. Grimes 504df8bae1dSRodney W. Grimes if (d->bd_slen == 0) { 505df8bae1dSRodney W. Grimes splx(s); 506df8bae1dSRodney W. Grimes return (0); 507df8bae1dSRodney W. Grimes } 508df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 509df8bae1dSRodney W. Grimes break; 510df8bae1dSRodney W. Grimes } 511df8bae1dSRodney W. Grimes } 512df8bae1dSRodney W. Grimes /* 513df8bae1dSRodney W. Grimes * At this point, we know we have something in the hold slot. 514df8bae1dSRodney W. Grimes */ 515df8bae1dSRodney W. Grimes splx(s); 516df8bae1dSRodney W. Grimes 517df8bae1dSRodney W. Grimes /* 518df8bae1dSRodney W. Grimes * Move data from hold buffer into user space. 519df8bae1dSRodney W. Grimes * We know the entire buffer is transferred since 520df8bae1dSRodney W. Grimes * we checked above that the read buffer is bpf_bufsize bytes. 521df8bae1dSRodney W. Grimes */ 522df8bae1dSRodney W. Grimes error = UIOMOVE(d->bd_hbuf, d->bd_hlen, UIO_READ, uio); 523df8bae1dSRodney W. Grimes 524df8bae1dSRodney W. Grimes s = splimp(); 525df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 526df8bae1dSRodney W. Grimes d->bd_hbuf = 0; 527df8bae1dSRodney W. Grimes d->bd_hlen = 0; 528df8bae1dSRodney W. Grimes splx(s); 529df8bae1dSRodney W. Grimes 530df8bae1dSRodney W. Grimes return (error); 531df8bae1dSRodney W. Grimes } 532df8bae1dSRodney W. Grimes 533df8bae1dSRodney W. Grimes 534df8bae1dSRodney W. Grimes /* 535df8bae1dSRodney W. Grimes * If there are processes sleeping on this descriptor, wake them up. 536df8bae1dSRodney W. Grimes */ 537df8bae1dSRodney W. Grimes static inline void 538df8bae1dSRodney W. Grimes bpf_wakeup(d) 539df8bae1dSRodney W. Grimes register struct bpf_d *d; 540df8bae1dSRodney W. Grimes { 541df8bae1dSRodney W. Grimes wakeup((caddr_t)d); 542831d27a9SDon Lewis if (d->bd_async && d->bd_sig && d->bd_sigio) 543831d27a9SDon Lewis pgsigio(d->bd_sigio, d->bd_sig, 0); 54400a83887SPaul Traina 545df8bae1dSRodney W. Grimes #if BSD >= 199103 546df8bae1dSRodney W. Grimes selwakeup(&d->bd_sel); 547df8bae1dSRodney W. Grimes /* XXX */ 548df8bae1dSRodney W. Grimes d->bd_sel.si_pid = 0; 549df8bae1dSRodney W. Grimes #else 550df8bae1dSRodney W. Grimes if (d->bd_selproc) { 551df8bae1dSRodney W. Grimes selwakeup(d->bd_selproc, (int)d->bd_selcoll); 552df8bae1dSRodney W. Grimes d->bd_selcoll = 0; 553df8bae1dSRodney W. Grimes d->bd_selproc = 0; 554df8bae1dSRodney W. Grimes } 555df8bae1dSRodney W. Grimes #endif 556df8bae1dSRodney W. Grimes } 557df8bae1dSRodney W. Grimes 55887f6c662SJulian Elischer static int 55960039670SBruce Evans bpfwrite(dev, uio, ioflag) 560df8bae1dSRodney W. Grimes dev_t dev; 561df8bae1dSRodney W. Grimes struct uio *uio; 56260039670SBruce Evans int ioflag; 563df8bae1dSRodney W. Grimes { 564df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 565df8bae1dSRodney W. Grimes struct ifnet *ifp; 566df8bae1dSRodney W. Grimes struct mbuf *m; 567df8bae1dSRodney W. Grimes int error, s; 568df8bae1dSRodney W. Grimes static struct sockaddr dst; 569df8bae1dSRodney W. Grimes int datlen; 570df8bae1dSRodney W. Grimes 571df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 572df8bae1dSRodney W. Grimes return (ENXIO); 573df8bae1dSRodney W. Grimes 574df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 575df8bae1dSRodney W. Grimes 576df8bae1dSRodney W. Grimes if (uio->uio_resid == 0) 577df8bae1dSRodney W. Grimes return (0); 578df8bae1dSRodney W. Grimes 579df8bae1dSRodney W. Grimes error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, &dst, &datlen); 580df8bae1dSRodney W. Grimes if (error) 581df8bae1dSRodney W. Grimes return (error); 582df8bae1dSRodney W. Grimes 583df8bae1dSRodney W. Grimes if (datlen > ifp->if_mtu) 584df8bae1dSRodney W. Grimes return (EMSGSIZE); 585df8bae1dSRodney W. Grimes 586df8bae1dSRodney W. Grimes s = splnet(); 587df8bae1dSRodney W. Grimes #if BSD >= 199103 588df8bae1dSRodney W. Grimes error = (*ifp->if_output)(ifp, m, &dst, (struct rtentry *)0); 589df8bae1dSRodney W. Grimes #else 590df8bae1dSRodney W. Grimes error = (*ifp->if_output)(ifp, m, &dst); 591df8bae1dSRodney W. Grimes #endif 592df8bae1dSRodney W. Grimes splx(s); 593df8bae1dSRodney W. Grimes /* 594df8bae1dSRodney W. Grimes * The driver frees the mbuf. 595df8bae1dSRodney W. Grimes */ 596df8bae1dSRodney W. Grimes return (error); 597df8bae1dSRodney W. Grimes } 598df8bae1dSRodney W. Grimes 599df8bae1dSRodney W. Grimes /* 600df8bae1dSRodney W. Grimes * Reset a descriptor by flushing its packet buffer and clearing the 601df8bae1dSRodney W. Grimes * receive and drop counts. Should be called at splimp. 602df8bae1dSRodney W. Grimes */ 603df8bae1dSRodney W. Grimes static void 604df8bae1dSRodney W. Grimes reset_d(d) 605df8bae1dSRodney W. Grimes struct bpf_d *d; 606df8bae1dSRodney W. Grimes { 607df8bae1dSRodney W. Grimes if (d->bd_hbuf) { 608df8bae1dSRodney W. Grimes /* Free the hold buffer. */ 609df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 610df8bae1dSRodney W. Grimes d->bd_hbuf = 0; 611df8bae1dSRodney W. Grimes } 612df8bae1dSRodney W. Grimes d->bd_slen = 0; 613df8bae1dSRodney W. Grimes d->bd_hlen = 0; 614df8bae1dSRodney W. Grimes d->bd_rcount = 0; 615df8bae1dSRodney W. Grimes d->bd_dcount = 0; 616df8bae1dSRodney W. Grimes } 617df8bae1dSRodney W. Grimes 618df8bae1dSRodney W. Grimes /* 619df8bae1dSRodney W. Grimes * FIONREAD Check for read packet available. 620df8bae1dSRodney W. Grimes * SIOCGIFADDR Get interface address - convenient hook to driver. 621df8bae1dSRodney W. Grimes * BIOCGBLEN Get buffer len [for read()]. 622df8bae1dSRodney W. Grimes * BIOCSETF Set ethernet read filter. 623df8bae1dSRodney W. Grimes * BIOCFLUSH Flush read packet buffer. 624df8bae1dSRodney W. Grimes * BIOCPROMISC Put interface into promiscuous mode. 625df8bae1dSRodney W. Grimes * BIOCGDLT Get link layer type. 626df8bae1dSRodney W. Grimes * BIOCGETIF Get interface name. 627df8bae1dSRodney W. Grimes * BIOCSETIF Set interface. 628df8bae1dSRodney W. Grimes * BIOCSRTIMEOUT Set read timeout. 629df8bae1dSRodney W. Grimes * BIOCGRTIMEOUT Get read timeout. 630df8bae1dSRodney W. Grimes * BIOCGSTATS Get packet stats. 631df8bae1dSRodney W. Grimes * BIOCIMMEDIATE Set immediate mode. 632df8bae1dSRodney W. Grimes * BIOCVERSION Get filter language version. 633df8bae1dSRodney W. Grimes */ 634df8bae1dSRodney W. Grimes /* ARGSUSED */ 63587f6c662SJulian Elischer static int 63660039670SBruce Evans bpfioctl(dev, cmd, addr, flags, p) 637df8bae1dSRodney W. Grimes dev_t dev; 638ecbb00a2SDoug Rabson u_long cmd; 639df8bae1dSRodney W. Grimes caddr_t addr; 64060039670SBruce Evans int flags; 64160039670SBruce Evans struct proc *p; 642df8bae1dSRodney W. Grimes { 643df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 644df8bae1dSRodney W. Grimes int s, error = 0; 645df8bae1dSRodney W. Grimes 646df8bae1dSRodney W. Grimes switch (cmd) { 647df8bae1dSRodney W. Grimes 648df8bae1dSRodney W. Grimes default: 649df8bae1dSRodney W. Grimes error = EINVAL; 650df8bae1dSRodney W. Grimes break; 651df8bae1dSRodney W. Grimes 652df8bae1dSRodney W. Grimes /* 653df8bae1dSRodney W. Grimes * Check for read packet available. 654df8bae1dSRodney W. Grimes */ 655df8bae1dSRodney W. Grimes case FIONREAD: 656df8bae1dSRodney W. Grimes { 657df8bae1dSRodney W. Grimes int n; 658df8bae1dSRodney W. Grimes 659df8bae1dSRodney W. Grimes s = splimp(); 660df8bae1dSRodney W. Grimes n = d->bd_slen; 661df8bae1dSRodney W. Grimes if (d->bd_hbuf) 662df8bae1dSRodney W. Grimes n += d->bd_hlen; 663df8bae1dSRodney W. Grimes splx(s); 664df8bae1dSRodney W. Grimes 665df8bae1dSRodney W. Grimes *(int *)addr = n; 666df8bae1dSRodney W. Grimes break; 667df8bae1dSRodney W. Grimes } 668df8bae1dSRodney W. Grimes 669df8bae1dSRodney W. Grimes case SIOCGIFADDR: 670df8bae1dSRodney W. Grimes { 671df8bae1dSRodney W. Grimes struct ifnet *ifp; 672df8bae1dSRodney W. Grimes 673df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 674df8bae1dSRodney W. Grimes error = EINVAL; 675df8bae1dSRodney W. Grimes else { 676df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 677df8bae1dSRodney W. Grimes error = (*ifp->if_ioctl)(ifp, cmd, addr); 678df8bae1dSRodney W. Grimes } 679df8bae1dSRodney W. Grimes break; 680df8bae1dSRodney W. Grimes } 681df8bae1dSRodney W. Grimes 682df8bae1dSRodney W. Grimes /* 683df8bae1dSRodney W. Grimes * Get buffer len [for read()]. 684df8bae1dSRodney W. Grimes */ 685df8bae1dSRodney W. Grimes case BIOCGBLEN: 686df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bufsize; 687df8bae1dSRodney W. Grimes break; 688df8bae1dSRodney W. Grimes 689df8bae1dSRodney W. Grimes /* 690df8bae1dSRodney W. Grimes * Set buffer length. 691df8bae1dSRodney W. Grimes */ 692df8bae1dSRodney W. Grimes case BIOCSBLEN: 693df8bae1dSRodney W. Grimes #if BSD < 199103 694df8bae1dSRodney W. Grimes error = EINVAL; 695df8bae1dSRodney W. Grimes #else 696df8bae1dSRodney W. Grimes if (d->bd_bif != 0) 697df8bae1dSRodney W. Grimes error = EINVAL; 698df8bae1dSRodney W. Grimes else { 699df8bae1dSRodney W. Grimes register u_int size = *(u_int *)addr; 700df8bae1dSRodney W. Grimes 701df8bae1dSRodney W. Grimes if (size > BPF_MAXBUFSIZE) 702df8bae1dSRodney W. Grimes *(u_int *)addr = size = BPF_MAXBUFSIZE; 703df8bae1dSRodney W. Grimes else if (size < BPF_MINBUFSIZE) 704df8bae1dSRodney W. Grimes *(u_int *)addr = size = BPF_MINBUFSIZE; 705df8bae1dSRodney W. Grimes d->bd_bufsize = size; 706df8bae1dSRodney W. Grimes } 707df8bae1dSRodney W. Grimes #endif 708df8bae1dSRodney W. Grimes break; 709df8bae1dSRodney W. Grimes 710df8bae1dSRodney W. Grimes /* 711df8bae1dSRodney W. Grimes * Set link layer read filter. 712df8bae1dSRodney W. Grimes */ 713df8bae1dSRodney W. Grimes case BIOCSETF: 714df8bae1dSRodney W. Grimes error = bpf_setf(d, (struct bpf_program *)addr); 715df8bae1dSRodney W. Grimes break; 716df8bae1dSRodney W. Grimes 717df8bae1dSRodney W. Grimes /* 718df8bae1dSRodney W. Grimes * Flush read packet buffer. 719df8bae1dSRodney W. Grimes */ 720df8bae1dSRodney W. Grimes case BIOCFLUSH: 721df8bae1dSRodney W. Grimes s = splimp(); 722df8bae1dSRodney W. Grimes reset_d(d); 723df8bae1dSRodney W. Grimes splx(s); 724df8bae1dSRodney W. Grimes break; 725df8bae1dSRodney W. Grimes 726df8bae1dSRodney W. Grimes /* 727df8bae1dSRodney W. Grimes * Put interface into promiscuous mode. 728df8bae1dSRodney W. Grimes */ 729df8bae1dSRodney W. Grimes case BIOCPROMISC: 730df8bae1dSRodney W. Grimes if (d->bd_bif == 0) { 731df8bae1dSRodney W. Grimes /* 732df8bae1dSRodney W. Grimes * No interface attached yet. 733df8bae1dSRodney W. Grimes */ 734df8bae1dSRodney W. Grimes error = EINVAL; 735df8bae1dSRodney W. Grimes break; 736df8bae1dSRodney W. Grimes } 737df8bae1dSRodney W. Grimes s = splimp(); 738df8bae1dSRodney W. Grimes if (d->bd_promisc == 0) { 739df8bae1dSRodney W. Grimes error = ifpromisc(d->bd_bif->bif_ifp, 1); 740df8bae1dSRodney W. Grimes if (error == 0) 741df8bae1dSRodney W. Grimes d->bd_promisc = 1; 742df8bae1dSRodney W. Grimes } 743df8bae1dSRodney W. Grimes splx(s); 744df8bae1dSRodney W. Grimes break; 745df8bae1dSRodney W. Grimes 746df8bae1dSRodney W. Grimes /* 747df8bae1dSRodney W. Grimes * Get device parameters. 748df8bae1dSRodney W. Grimes */ 749df8bae1dSRodney W. Grimes case BIOCGDLT: 750df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 751df8bae1dSRodney W. Grimes error = EINVAL; 752df8bae1dSRodney W. Grimes else 753df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bif->bif_dlt; 754df8bae1dSRodney W. Grimes break; 755df8bae1dSRodney W. Grimes 756df8bae1dSRodney W. Grimes /* 757df8bae1dSRodney W. Grimes * Set interface name. 758df8bae1dSRodney W. Grimes */ 759df8bae1dSRodney W. Grimes case BIOCGETIF: 760df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 761df8bae1dSRodney W. Grimes error = EINVAL; 762df8bae1dSRodney W. Grimes else 763df8bae1dSRodney W. Grimes bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr); 764df8bae1dSRodney W. Grimes break; 765df8bae1dSRodney W. Grimes 766df8bae1dSRodney W. Grimes /* 767df8bae1dSRodney W. Grimes * Set interface. 768df8bae1dSRodney W. Grimes */ 769df8bae1dSRodney W. Grimes case BIOCSETIF: 770df8bae1dSRodney W. Grimes error = bpf_setif(d, (struct ifreq *)addr); 771df8bae1dSRodney W. Grimes break; 772df8bae1dSRodney W. Grimes 773df8bae1dSRodney W. Grimes /* 774df8bae1dSRodney W. Grimes * Set read timeout. 775df8bae1dSRodney W. Grimes */ 776df8bae1dSRodney W. Grimes case BIOCSRTIMEOUT: 777df8bae1dSRodney W. Grimes { 778df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 779df8bae1dSRodney W. Grimes 780bdc2cdc5SAlexander Langer /* 781bdc2cdc5SAlexander Langer * Subtract 1 tick from tvtohz() since this isn't 782bdc2cdc5SAlexander Langer * a one-shot timer. 783bdc2cdc5SAlexander Langer */ 784bdc2cdc5SAlexander Langer if ((error = itimerfix(tv)) == 0) 785bdc2cdc5SAlexander Langer d->bd_rtout = tvtohz(tv) - 1; 786df8bae1dSRodney W. Grimes break; 787df8bae1dSRodney W. Grimes } 788df8bae1dSRodney W. Grimes 789df8bae1dSRodney W. Grimes /* 790df8bae1dSRodney W. Grimes * Get read timeout. 791df8bae1dSRodney W. Grimes */ 792df8bae1dSRodney W. Grimes case BIOCGRTIMEOUT: 793df8bae1dSRodney W. Grimes { 794df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 795df8bae1dSRodney W. Grimes 796bdc2cdc5SAlexander Langer tv->tv_sec = d->bd_rtout / hz; 797bdc2cdc5SAlexander Langer tv->tv_usec = (d->bd_rtout % hz) * tick; 798df8bae1dSRodney W. Grimes break; 799df8bae1dSRodney W. Grimes } 800df8bae1dSRodney W. Grimes 801df8bae1dSRodney W. Grimes /* 802df8bae1dSRodney W. Grimes * Get packet stats. 803df8bae1dSRodney W. Grimes */ 804df8bae1dSRodney W. Grimes case BIOCGSTATS: 805df8bae1dSRodney W. Grimes { 806df8bae1dSRodney W. Grimes struct bpf_stat *bs = (struct bpf_stat *)addr; 807df8bae1dSRodney W. Grimes 808df8bae1dSRodney W. Grimes bs->bs_recv = d->bd_rcount; 809df8bae1dSRodney W. Grimes bs->bs_drop = d->bd_dcount; 810df8bae1dSRodney W. Grimes break; 811df8bae1dSRodney W. Grimes } 812df8bae1dSRodney W. Grimes 813df8bae1dSRodney W. Grimes /* 814df8bae1dSRodney W. Grimes * Set immediate mode. 815df8bae1dSRodney W. Grimes */ 816df8bae1dSRodney W. Grimes case BIOCIMMEDIATE: 817df8bae1dSRodney W. Grimes d->bd_immediate = *(u_int *)addr; 818df8bae1dSRodney W. Grimes break; 819df8bae1dSRodney W. Grimes 820df8bae1dSRodney W. Grimes case BIOCVERSION: 821df8bae1dSRodney W. Grimes { 822df8bae1dSRodney W. Grimes struct bpf_version *bv = (struct bpf_version *)addr; 823df8bae1dSRodney W. Grimes 824df8bae1dSRodney W. Grimes bv->bv_major = BPF_MAJOR_VERSION; 825df8bae1dSRodney W. Grimes bv->bv_minor = BPF_MINOR_VERSION; 826df8bae1dSRodney W. Grimes break; 827df8bae1dSRodney W. Grimes } 82800a83887SPaul Traina 82900a83887SPaul Traina case FIONBIO: /* Non-blocking I/O */ 83000a83887SPaul Traina break; 83100a83887SPaul Traina 83200a83887SPaul Traina case FIOASYNC: /* Send signal on receive packets */ 83300a83887SPaul Traina d->bd_async = *(int *)addr; 83400a83887SPaul Traina break; 83500a83887SPaul Traina 836831d27a9SDon Lewis case FIOSETOWN: 837831d27a9SDon Lewis error = fsetown(*(int *)addr, &d->bd_sigio); 83800a83887SPaul Traina break; 83900a83887SPaul Traina 840831d27a9SDon Lewis case FIOGETOWN: 841831d27a9SDon Lewis *(int *)addr = fgetown(d->bd_sigio); 842831d27a9SDon Lewis break; 843831d27a9SDon Lewis 844831d27a9SDon Lewis /* This is deprecated, FIOSETOWN should be used instead. */ 845831d27a9SDon Lewis case TIOCSPGRP: 846831d27a9SDon Lewis error = fsetown(-(*(int *)addr), &d->bd_sigio); 847831d27a9SDon Lewis break; 848831d27a9SDon Lewis 849831d27a9SDon Lewis /* This is deprecated, FIOGETOWN should be used instead. */ 85000a83887SPaul Traina case TIOCGPGRP: 851831d27a9SDon Lewis *(int *)addr = -fgetown(d->bd_sigio); 85200a83887SPaul Traina break; 85300a83887SPaul Traina 85400a83887SPaul Traina case BIOCSRSIG: /* Set receive signal */ 85500a83887SPaul Traina { 85600a83887SPaul Traina u_int sig; 85700a83887SPaul Traina 85800a83887SPaul Traina sig = *(u_int *)addr; 85900a83887SPaul Traina 86000a83887SPaul Traina if (sig >= NSIG) 86100a83887SPaul Traina error = EINVAL; 86200a83887SPaul Traina else 86300a83887SPaul Traina d->bd_sig = sig; 86400a83887SPaul Traina break; 86500a83887SPaul Traina } 86600a83887SPaul Traina case BIOCGRSIG: 86700a83887SPaul Traina *(u_int *)addr = d->bd_sig; 86800a83887SPaul Traina break; 869df8bae1dSRodney W. Grimes } 870df8bae1dSRodney W. Grimes return (error); 871df8bae1dSRodney W. Grimes } 872df8bae1dSRodney W. Grimes 873df8bae1dSRodney W. Grimes /* 874df8bae1dSRodney W. Grimes * Set d's packet filter program to fp. If this file already has a filter, 875df8bae1dSRodney W. Grimes * free it and replace it. Returns EINVAL for bogus requests. 876df8bae1dSRodney W. Grimes */ 877f708ef1bSPoul-Henning Kamp static int 878df8bae1dSRodney W. Grimes bpf_setf(d, fp) 879df8bae1dSRodney W. Grimes struct bpf_d *d; 880df8bae1dSRodney W. Grimes struct bpf_program *fp; 881df8bae1dSRodney W. Grimes { 882df8bae1dSRodney W. Grimes struct bpf_insn *fcode, *old; 883df8bae1dSRodney W. Grimes u_int flen, size; 884df8bae1dSRodney W. Grimes int s; 885df8bae1dSRodney W. Grimes 886df8bae1dSRodney W. Grimes old = d->bd_filter; 887df8bae1dSRodney W. Grimes if (fp->bf_insns == 0) { 888df8bae1dSRodney W. Grimes if (fp->bf_len != 0) 889df8bae1dSRodney W. Grimes return (EINVAL); 890df8bae1dSRodney W. Grimes s = splimp(); 891df8bae1dSRodney W. Grimes d->bd_filter = 0; 892df8bae1dSRodney W. Grimes reset_d(d); 893df8bae1dSRodney W. Grimes splx(s); 894df8bae1dSRodney W. Grimes if (old != 0) 895df8bae1dSRodney W. Grimes free((caddr_t)old, M_DEVBUF); 896df8bae1dSRodney W. Grimes return (0); 897df8bae1dSRodney W. Grimes } 898df8bae1dSRodney W. Grimes flen = fp->bf_len; 899df8bae1dSRodney W. Grimes if (flen > BPF_MAXINSNS) 900df8bae1dSRodney W. Grimes return (EINVAL); 901df8bae1dSRodney W. Grimes 902df8bae1dSRodney W. Grimes size = flen * sizeof(*fp->bf_insns); 903df8bae1dSRodney W. Grimes fcode = (struct bpf_insn *)malloc(size, M_DEVBUF, M_WAITOK); 904df8bae1dSRodney W. Grimes if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 && 905df8bae1dSRodney W. Grimes bpf_validate(fcode, (int)flen)) { 906df8bae1dSRodney W. Grimes s = splimp(); 907df8bae1dSRodney W. Grimes d->bd_filter = fcode; 908df8bae1dSRodney W. Grimes reset_d(d); 909df8bae1dSRodney W. Grimes splx(s); 910df8bae1dSRodney W. Grimes if (old != 0) 911df8bae1dSRodney W. Grimes free((caddr_t)old, M_DEVBUF); 912df8bae1dSRodney W. Grimes 913df8bae1dSRodney W. Grimes return (0); 914df8bae1dSRodney W. Grimes } 915df8bae1dSRodney W. Grimes free((caddr_t)fcode, M_DEVBUF); 916df8bae1dSRodney W. Grimes return (EINVAL); 917df8bae1dSRodney W. Grimes } 918df8bae1dSRodney W. Grimes 919df8bae1dSRodney W. Grimes /* 920df8bae1dSRodney W. Grimes * Detach a file from its current interface (if attached at all) and attach 921df8bae1dSRodney W. Grimes * to the interface indicated by the name stored in ifr. 922df8bae1dSRodney W. Grimes * Return an errno or 0. 923df8bae1dSRodney W. Grimes */ 924df8bae1dSRodney W. Grimes static int 925df8bae1dSRodney W. Grimes bpf_setif(d, ifr) 926df8bae1dSRodney W. Grimes struct bpf_d *d; 927df8bae1dSRodney W. Grimes struct ifreq *ifr; 928df8bae1dSRodney W. Grimes { 929df8bae1dSRodney W. Grimes struct bpf_if *bp; 9309b44ff22SGarrett Wollman int s, error; 9319b44ff22SGarrett Wollman struct ifnet *theywant; 932df8bae1dSRodney W. Grimes 9339b44ff22SGarrett Wollman theywant = ifunit(ifr->ifr_name); 9349b44ff22SGarrett Wollman if (theywant == 0) 9359b44ff22SGarrett Wollman return ENXIO; 9369b44ff22SGarrett Wollman 937df8bae1dSRodney W. Grimes /* 938df8bae1dSRodney W. Grimes * Look through attached interfaces for the named one. 939df8bae1dSRodney W. Grimes */ 940df8bae1dSRodney W. Grimes for (bp = bpf_iflist; bp != 0; bp = bp->bif_next) { 941df8bae1dSRodney W. Grimes struct ifnet *ifp = bp->bif_ifp; 942df8bae1dSRodney W. Grimes 9439b44ff22SGarrett Wollman if (ifp == 0 || ifp != theywant) 944df8bae1dSRodney W. Grimes continue; 945df8bae1dSRodney W. Grimes /* 946df8bae1dSRodney W. Grimes * We found the requested interface. 947df8bae1dSRodney W. Grimes * If it's not up, return an error. 948df8bae1dSRodney W. Grimes * Allocate the packet buffers if we need to. 949df8bae1dSRodney W. Grimes * If we're already attached to requested interface, 950df8bae1dSRodney W. Grimes * just flush the buffer. 951df8bae1dSRodney W. Grimes */ 952df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_UP) == 0) 953df8bae1dSRodney W. Grimes return (ENETDOWN); 954df8bae1dSRodney W. Grimes 955df8bae1dSRodney W. Grimes if (d->bd_sbuf == 0) { 956df8bae1dSRodney W. Grimes error = bpf_allocbufs(d); 957df8bae1dSRodney W. Grimes if (error != 0) 958df8bae1dSRodney W. Grimes return (error); 959df8bae1dSRodney W. Grimes } 960df8bae1dSRodney W. Grimes s = splimp(); 961df8bae1dSRodney W. Grimes if (bp != d->bd_bif) { 962df8bae1dSRodney W. Grimes if (d->bd_bif) 963df8bae1dSRodney W. Grimes /* 964df8bae1dSRodney W. Grimes * Detach if attached to something else. 965df8bae1dSRodney W. Grimes */ 966df8bae1dSRodney W. Grimes bpf_detachd(d); 967df8bae1dSRodney W. Grimes 968df8bae1dSRodney W. Grimes bpf_attachd(d, bp); 969df8bae1dSRodney W. Grimes } 970df8bae1dSRodney W. Grimes reset_d(d); 971df8bae1dSRodney W. Grimes splx(s); 972df8bae1dSRodney W. Grimes return (0); 973df8bae1dSRodney W. Grimes } 974df8bae1dSRodney W. Grimes /* Not found. */ 975df8bae1dSRodney W. Grimes return (ENXIO); 976df8bae1dSRodney W. Grimes } 977df8bae1dSRodney W. Grimes 978df8bae1dSRodney W. Grimes /* 979df8bae1dSRodney W. Grimes * Convert an interface name plus unit number of an ifp to a single 980df8bae1dSRodney W. Grimes * name which is returned in the ifr. 981df8bae1dSRodney W. Grimes */ 982df8bae1dSRodney W. Grimes static void 983df8bae1dSRodney W. Grimes bpf_ifname(ifp, ifr) 984df8bae1dSRodney W. Grimes struct ifnet *ifp; 985df8bae1dSRodney W. Grimes struct ifreq *ifr; 986df8bae1dSRodney W. Grimes { 987df8bae1dSRodney W. Grimes char *s = ifp->if_name; 988df8bae1dSRodney W. Grimes char *d = ifr->ifr_name; 989df8bae1dSRodney W. Grimes 990831a80b0SMatthew Dillon while ((*d++ = *s++) != 0) 991df8bae1dSRodney W. Grimes continue; 992a76f92a8SDavid Greenman d--; /* back to the null */ 993df8bae1dSRodney W. Grimes /* XXX Assume that unit number is less than 10. */ 994df8bae1dSRodney W. Grimes *d++ = ifp->if_unit + '0'; 995df8bae1dSRodney W. Grimes *d = '\0'; 996df8bae1dSRodney W. Grimes } 997df8bae1dSRodney W. Grimes 998df8bae1dSRodney W. Grimes /* 999243ac7d8SPeter Wemm * Support for select() and poll() system calls 1000df8bae1dSRodney W. Grimes * 1001df8bae1dSRodney W. Grimes * Return true iff the specific operation will not block indefinitely. 1002df8bae1dSRodney W. Grimes * Otherwise, return false but make a note that a selwakeup() must be done. 1003df8bae1dSRodney W. Grimes */ 1004df8bae1dSRodney W. Grimes int 1005243ac7d8SPeter Wemm bpfpoll(dev, events, p) 1006df8bae1dSRodney W. Grimes register dev_t dev; 1007243ac7d8SPeter Wemm int events; 1008df8bae1dSRodney W. Grimes struct proc *p; 1009df8bae1dSRodney W. Grimes { 1010df8bae1dSRodney W. Grimes register struct bpf_d *d; 1011df8bae1dSRodney W. Grimes register int s; 1012243ac7d8SPeter Wemm int revents = 0; 1013df8bae1dSRodney W. Grimes 1014df8bae1dSRodney W. Grimes /* 1015df8bae1dSRodney W. Grimes * An imitation of the FIONREAD ioctl code. 1016df8bae1dSRodney W. Grimes */ 1017df8bae1dSRodney W. Grimes d = &bpf_dtab[minor(dev)]; 1018df8bae1dSRodney W. Grimes 1019df8bae1dSRodney W. Grimes s = splimp(); 102075c13541SPoul-Henning Kamp if (events & (POLLIN | POLLRDNORM)) { 1021243ac7d8SPeter Wemm if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0)) 1022243ac7d8SPeter Wemm revents |= events & (POLLIN | POLLRDNORM); 1023df8bae1dSRodney W. Grimes else 1024243ac7d8SPeter Wemm selrecord(p, &d->bd_sel); 102575c13541SPoul-Henning Kamp } 1026df8bae1dSRodney W. Grimes splx(s); 1027243ac7d8SPeter Wemm return (revents); 1028df8bae1dSRodney W. Grimes } 1029df8bae1dSRodney W. Grimes 1030df8bae1dSRodney W. Grimes /* 1031df8bae1dSRodney W. Grimes * Incoming linkage from device drivers. Process the packet pkt, of length 1032df8bae1dSRodney W. Grimes * pktlen, which is stored in a contiguous buffer. The packet is parsed 1033df8bae1dSRodney W. Grimes * by each process' filter, and if accepted, stashed into the corresponding 1034df8bae1dSRodney W. Grimes * buffer. 1035df8bae1dSRodney W. Grimes */ 1036df8bae1dSRodney W. Grimes void 10379b44ff22SGarrett Wollman bpf_tap(ifp, pkt, pktlen) 10389b44ff22SGarrett Wollman struct ifnet *ifp; 1039df8bae1dSRodney W. Grimes register u_char *pkt; 1040df8bae1dSRodney W. Grimes register u_int pktlen; 1041df8bae1dSRodney W. Grimes { 1042df8bae1dSRodney W. Grimes struct bpf_if *bp; 1043df8bae1dSRodney W. Grimes register struct bpf_d *d; 1044df8bae1dSRodney W. Grimes register u_int slen; 1045df8bae1dSRodney W. Grimes /* 1046df8bae1dSRodney W. Grimes * Note that the ipl does not have to be raised at this point. 1047df8bae1dSRodney W. Grimes * The only problem that could arise here is that if two different 1048df8bae1dSRodney W. Grimes * interfaces shared any data. This is not the case. 1049df8bae1dSRodney W. Grimes */ 10509b44ff22SGarrett Wollman bp = ifp->if_bpf; 1051df8bae1dSRodney W. Grimes for (d = bp->bif_dlist; d != 0; d = d->bd_next) { 1052df8bae1dSRodney W. Grimes ++d->bd_rcount; 1053df8bae1dSRodney W. Grimes slen = bpf_filter(d->bd_filter, pkt, pktlen, pktlen); 1054df8bae1dSRodney W. Grimes if (slen != 0) 1055df8bae1dSRodney W. Grimes catchpacket(d, pkt, pktlen, slen, bcopy); 1056df8bae1dSRodney W. Grimes } 1057df8bae1dSRodney W. Grimes } 1058df8bae1dSRodney W. Grimes 1059df8bae1dSRodney W. Grimes /* 1060df8bae1dSRodney W. Grimes * Copy data from an mbuf chain into a buffer. This code is derived 1061df8bae1dSRodney W. Grimes * from m_copydata in sys/uipc_mbuf.c. 1062df8bae1dSRodney W. Grimes */ 1063df8bae1dSRodney W. Grimes static void 1064df8bae1dSRodney W. Grimes bpf_mcopy(src_arg, dst_arg, len) 1065df8bae1dSRodney W. Grimes const void *src_arg; 1066df8bae1dSRodney W. Grimes void *dst_arg; 10678bcbc7dfSAlexander Langer register size_t len; 1068df8bae1dSRodney W. Grimes { 1069df8bae1dSRodney W. Grimes register const struct mbuf *m; 1070df8bae1dSRodney W. Grimes register u_int count; 1071df8bae1dSRodney W. Grimes u_char *dst; 1072df8bae1dSRodney W. Grimes 1073df8bae1dSRodney W. Grimes m = src_arg; 1074df8bae1dSRodney W. Grimes dst = dst_arg; 1075df8bae1dSRodney W. Grimes while (len > 0) { 1076df8bae1dSRodney W. Grimes if (m == 0) 1077df8bae1dSRodney W. Grimes panic("bpf_mcopy"); 1078df8bae1dSRodney W. Grimes count = min(m->m_len, len); 10790453d3cbSBruce Evans bcopy(mtod(m, void *), dst, count); 1080df8bae1dSRodney W. Grimes m = m->m_next; 1081df8bae1dSRodney W. Grimes dst += count; 1082df8bae1dSRodney W. Grimes len -= count; 1083df8bae1dSRodney W. Grimes } 1084df8bae1dSRodney W. Grimes } 1085df8bae1dSRodney W. Grimes 1086df8bae1dSRodney W. Grimes /* 1087df8bae1dSRodney W. Grimes * Incoming linkage from device drivers, when packet is in an mbuf chain. 1088df8bae1dSRodney W. Grimes */ 1089df8bae1dSRodney W. Grimes void 10909b44ff22SGarrett Wollman bpf_mtap(ifp, m) 10919b44ff22SGarrett Wollman struct ifnet *ifp; 1092df8bae1dSRodney W. Grimes struct mbuf *m; 1093df8bae1dSRodney W. Grimes { 10949b44ff22SGarrett Wollman struct bpf_if *bp = ifp->if_bpf; 1095df8bae1dSRodney W. Grimes struct bpf_d *d; 1096df8bae1dSRodney W. Grimes u_int pktlen, slen; 1097df8bae1dSRodney W. Grimes struct mbuf *m0; 1098df8bae1dSRodney W. Grimes 1099df8bae1dSRodney W. Grimes pktlen = 0; 1100df8bae1dSRodney W. Grimes for (m0 = m; m0 != 0; m0 = m0->m_next) 1101df8bae1dSRodney W. Grimes pktlen += m0->m_len; 1102df8bae1dSRodney W. Grimes 1103df8bae1dSRodney W. Grimes for (d = bp->bif_dlist; d != 0; d = d->bd_next) { 1104df8bae1dSRodney W. Grimes ++d->bd_rcount; 1105df8bae1dSRodney W. Grimes slen = bpf_filter(d->bd_filter, (u_char *)m, pktlen, 0); 1106df8bae1dSRodney W. Grimes if (slen != 0) 1107df8bae1dSRodney W. Grimes catchpacket(d, (u_char *)m, pktlen, slen, bpf_mcopy); 1108df8bae1dSRodney W. Grimes } 1109df8bae1dSRodney W. Grimes } 1110df8bae1dSRodney W. Grimes 1111df8bae1dSRodney W. Grimes /* 1112df8bae1dSRodney W. Grimes * Move the packet data from interface memory (pkt) into the 1113df8bae1dSRodney W. Grimes * store buffer. Return 1 if it's time to wakeup a listener (buffer full), 1114df8bae1dSRodney W. Grimes * otherwise 0. "copy" is the routine called to do the actual data 1115df8bae1dSRodney W. Grimes * transfer. bcopy is passed in to copy contiguous chunks, while 1116df8bae1dSRodney W. Grimes * bpf_mcopy is passed in to copy mbuf chains. In the latter case, 1117df8bae1dSRodney W. Grimes * pkt is really an mbuf. 1118df8bae1dSRodney W. Grimes */ 1119df8bae1dSRodney W. Grimes static void 1120df8bae1dSRodney W. Grimes catchpacket(d, pkt, pktlen, snaplen, cpfn) 1121df8bae1dSRodney W. Grimes register struct bpf_d *d; 1122df8bae1dSRodney W. Grimes register u_char *pkt; 1123df8bae1dSRodney W. Grimes register u_int pktlen, snaplen; 11248bcbc7dfSAlexander Langer register void (*cpfn) __P((const void *, void *, size_t)); 1125df8bae1dSRodney W. Grimes { 1126df8bae1dSRodney W. Grimes register struct bpf_hdr *hp; 1127df8bae1dSRodney W. Grimes register int totlen, curlen; 1128df8bae1dSRodney W. Grimes register int hdrlen = d->bd_bif->bif_hdrlen; 1129df8bae1dSRodney W. Grimes /* 1130df8bae1dSRodney W. Grimes * Figure out how many bytes to move. If the packet is 1131df8bae1dSRodney W. Grimes * greater or equal to the snapshot length, transfer that 1132df8bae1dSRodney W. Grimes * much. Otherwise, transfer the whole packet (unless 1133df8bae1dSRodney W. Grimes * we hit the buffer size limit). 1134df8bae1dSRodney W. Grimes */ 1135df8bae1dSRodney W. Grimes totlen = hdrlen + min(snaplen, pktlen); 1136df8bae1dSRodney W. Grimes if (totlen > d->bd_bufsize) 1137df8bae1dSRodney W. Grimes totlen = d->bd_bufsize; 1138df8bae1dSRodney W. Grimes 1139df8bae1dSRodney W. Grimes /* 1140df8bae1dSRodney W. Grimes * Round up the end of the previous packet to the next longword. 1141df8bae1dSRodney W. Grimes */ 1142df8bae1dSRodney W. Grimes curlen = BPF_WORDALIGN(d->bd_slen); 1143df8bae1dSRodney W. Grimes if (curlen + totlen > d->bd_bufsize) { 1144df8bae1dSRodney W. Grimes /* 1145df8bae1dSRodney W. Grimes * This packet will overflow the storage buffer. 1146df8bae1dSRodney W. Grimes * Rotate the buffers if we can, then wakeup any 1147df8bae1dSRodney W. Grimes * pending reads. 1148df8bae1dSRodney W. Grimes */ 1149df8bae1dSRodney W. Grimes if (d->bd_fbuf == 0) { 1150df8bae1dSRodney W. Grimes /* 1151df8bae1dSRodney W. Grimes * We haven't completed the previous read yet, 1152df8bae1dSRodney W. Grimes * so drop the packet. 1153df8bae1dSRodney W. Grimes */ 1154df8bae1dSRodney W. Grimes ++d->bd_dcount; 1155df8bae1dSRodney W. Grimes return; 1156df8bae1dSRodney W. Grimes } 1157df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 1158df8bae1dSRodney W. Grimes bpf_wakeup(d); 1159df8bae1dSRodney W. Grimes curlen = 0; 1160df8bae1dSRodney W. Grimes } 1161df8bae1dSRodney W. Grimes else if (d->bd_immediate) 1162df8bae1dSRodney W. Grimes /* 1163df8bae1dSRodney W. Grimes * Immediate mode is set. A packet arrived so any 1164df8bae1dSRodney W. Grimes * reads should be woken up. 1165df8bae1dSRodney W. Grimes */ 1166df8bae1dSRodney W. Grimes bpf_wakeup(d); 1167df8bae1dSRodney W. Grimes 1168df8bae1dSRodney W. Grimes /* 1169df8bae1dSRodney W. Grimes * Append the bpf header. 1170df8bae1dSRodney W. Grimes */ 1171df8bae1dSRodney W. Grimes hp = (struct bpf_hdr *)(d->bd_sbuf + curlen); 1172df8bae1dSRodney W. Grimes #if BSD >= 199103 1173df8bae1dSRodney W. Grimes microtime(&hp->bh_tstamp); 1174df8bae1dSRodney W. Grimes #elif defined(sun) 1175df8bae1dSRodney W. Grimes uniqtime(&hp->bh_tstamp); 1176df8bae1dSRodney W. Grimes #else 1177df8bae1dSRodney W. Grimes hp->bh_tstamp = time; 1178df8bae1dSRodney W. Grimes #endif 1179df8bae1dSRodney W. Grimes hp->bh_datalen = pktlen; 1180df8bae1dSRodney W. Grimes hp->bh_hdrlen = hdrlen; 1181df8bae1dSRodney W. Grimes /* 1182df8bae1dSRodney W. Grimes * Copy the packet data into the store buffer and update its length. 1183df8bae1dSRodney W. Grimes */ 1184df8bae1dSRodney W. Grimes (*cpfn)(pkt, (u_char *)hp + hdrlen, (hp->bh_caplen = totlen - hdrlen)); 1185df8bae1dSRodney W. Grimes d->bd_slen = curlen + totlen; 1186df8bae1dSRodney W. Grimes } 1187df8bae1dSRodney W. Grimes 1188df8bae1dSRodney W. Grimes /* 1189df8bae1dSRodney W. Grimes * Initialize all nonzero fields of a descriptor. 1190df8bae1dSRodney W. Grimes */ 1191df8bae1dSRodney W. Grimes static int 1192df8bae1dSRodney W. Grimes bpf_allocbufs(d) 1193df8bae1dSRodney W. Grimes register struct bpf_d *d; 1194df8bae1dSRodney W. Grimes { 1195df8bae1dSRodney W. Grimes d->bd_fbuf = (caddr_t)malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK); 1196df8bae1dSRodney W. Grimes if (d->bd_fbuf == 0) 1197df8bae1dSRodney W. Grimes return (ENOBUFS); 1198df8bae1dSRodney W. Grimes 1199df8bae1dSRodney W. Grimes d->bd_sbuf = (caddr_t)malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK); 1200df8bae1dSRodney W. Grimes if (d->bd_sbuf == 0) { 1201df8bae1dSRodney W. Grimes free(d->bd_fbuf, M_DEVBUF); 1202df8bae1dSRodney W. Grimes return (ENOBUFS); 1203df8bae1dSRodney W. Grimes } 1204df8bae1dSRodney W. Grimes d->bd_slen = 0; 1205df8bae1dSRodney W. Grimes d->bd_hlen = 0; 1206df8bae1dSRodney W. Grimes return (0); 1207df8bae1dSRodney W. Grimes } 1208df8bae1dSRodney W. Grimes 1209df8bae1dSRodney W. Grimes /* 1210df8bae1dSRodney W. Grimes * Free buffers currently in use by a descriptor. 1211df8bae1dSRodney W. Grimes * Called on close. 1212df8bae1dSRodney W. Grimes */ 1213df8bae1dSRodney W. Grimes static void 1214df8bae1dSRodney W. Grimes bpf_freed(d) 1215df8bae1dSRodney W. Grimes register struct bpf_d *d; 1216df8bae1dSRodney W. Grimes { 1217df8bae1dSRodney W. Grimes /* 1218df8bae1dSRodney W. Grimes * We don't need to lock out interrupts since this descriptor has 1219df8bae1dSRodney W. Grimes * been detached from its interface and it yet hasn't been marked 1220df8bae1dSRodney W. Grimes * free. 1221df8bae1dSRodney W. Grimes */ 1222df8bae1dSRodney W. Grimes if (d->bd_sbuf != 0) { 1223df8bae1dSRodney W. Grimes free(d->bd_sbuf, M_DEVBUF); 1224df8bae1dSRodney W. Grimes if (d->bd_hbuf != 0) 1225df8bae1dSRodney W. Grimes free(d->bd_hbuf, M_DEVBUF); 1226df8bae1dSRodney W. Grimes if (d->bd_fbuf != 0) 1227df8bae1dSRodney W. Grimes free(d->bd_fbuf, M_DEVBUF); 1228df8bae1dSRodney W. Grimes } 1229df8bae1dSRodney W. Grimes if (d->bd_filter) 1230df8bae1dSRodney W. Grimes free((caddr_t)d->bd_filter, M_DEVBUF); 1231df8bae1dSRodney W. Grimes 1232df8bae1dSRodney W. Grimes D_MARKFREE(d); 1233df8bae1dSRodney W. Grimes } 1234df8bae1dSRodney W. Grimes 1235df8bae1dSRodney W. Grimes /* 1236df8bae1dSRodney W. Grimes * Attach an interface to bpf. driverp is a pointer to a (struct bpf_if *) 1237df8bae1dSRodney W. Grimes * in the driver's softc; dlt is the link layer type; hdrlen is the fixed 1238df8bae1dSRodney W. Grimes * size of the link header (variable length headers not yet supported). 1239df8bae1dSRodney W. Grimes */ 1240df8bae1dSRodney W. Grimes void 12419b44ff22SGarrett Wollman bpfattach(ifp, dlt, hdrlen) 1242df8bae1dSRodney W. Grimes struct ifnet *ifp; 1243df8bae1dSRodney W. Grimes u_int dlt, hdrlen; 1244df8bae1dSRodney W. Grimes { 1245df8bae1dSRodney W. Grimes struct bpf_if *bp; 1246df8bae1dSRodney W. Grimes int i; 1247df8bae1dSRodney W. Grimes bp = (struct bpf_if *)malloc(sizeof(*bp), M_DEVBUF, M_DONTWAIT); 1248df8bae1dSRodney W. Grimes if (bp == 0) 1249df8bae1dSRodney W. Grimes panic("bpfattach"); 1250df8bae1dSRodney W. Grimes 1251df8bae1dSRodney W. Grimes bp->bif_dlist = 0; 1252df8bae1dSRodney W. Grimes bp->bif_ifp = ifp; 1253df8bae1dSRodney W. Grimes bp->bif_dlt = dlt; 1254df8bae1dSRodney W. Grimes 1255df8bae1dSRodney W. Grimes bp->bif_next = bpf_iflist; 1256df8bae1dSRodney W. Grimes bpf_iflist = bp; 1257df8bae1dSRodney W. Grimes 12589b44ff22SGarrett Wollman bp->bif_ifp->if_bpf = 0; 1259df8bae1dSRodney W. Grimes 1260df8bae1dSRodney W. Grimes /* 1261df8bae1dSRodney W. Grimes * Compute the length of the bpf header. This is not necessarily 1262df8bae1dSRodney W. Grimes * equal to SIZEOF_BPF_HDR because we want to insert spacing such 1263df8bae1dSRodney W. Grimes * that the network layer header begins on a longword boundary (for 1264df8bae1dSRodney W. Grimes * performance reasons and to alleviate alignment restrictions). 1265df8bae1dSRodney W. Grimes */ 1266df8bae1dSRodney W. Grimes bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen; 1267df8bae1dSRodney W. Grimes 1268df8bae1dSRodney W. Grimes /* 1269df8bae1dSRodney W. Grimes * Mark all the descriptors free if this hasn't been done. 1270df8bae1dSRodney W. Grimes */ 1271ed0af9bcSJulian Elischer if (!bpf_dtab_init) { 1272df8bae1dSRodney W. Grimes for (i = 0; i < NBPFILTER; ++i) 1273df8bae1dSRodney W. Grimes D_MARKFREE(&bpf_dtab[i]); 1274ed0af9bcSJulian Elischer bpf_dtab_init = 1; 1275ed0af9bcSJulian Elischer } 1276df8bae1dSRodney W. Grimes 12772eeab939SGarrett Wollman if (bootverbose) 1278df8bae1dSRodney W. Grimes printf("bpf: %s%d attached\n", ifp->if_name, ifp->if_unit); 1279df8bae1dSRodney W. Grimes } 128053ac6efbSJulian Elischer 1281ccbc58d3SMarc G. Fournier #ifdef DEVFS 128287f6c662SJulian Elischer static void *bpf_devfs_token[NBPFILTER]; 1283ccbc58d3SMarc G. Fournier #endif 128453ac6efbSJulian Elischer 1285e31abedeSBruce Evans static int bpf_devsw_installed; 128653ac6efbSJulian Elischer 1287514ede09SBruce Evans static void bpf_drvinit __P((void *unused)); 1288514ede09SBruce Evans static void 1289514ede09SBruce Evans bpf_drvinit(unused) 1290514ede09SBruce Evans void *unused; 129153ac6efbSJulian Elischer { 129253ac6efbSJulian Elischer dev_t dev; 1293ccbc58d3SMarc G. Fournier #ifdef DEVFS 129487f6c662SJulian Elischer int i; 1295ccbc58d3SMarc G. Fournier #endif 129653ac6efbSJulian Elischer 129753ac6efbSJulian Elischer if( ! bpf_devsw_installed ) { 129853ac6efbSJulian Elischer dev = makedev(CDEV_MAJOR, 0); 129953ac6efbSJulian Elischer cdevsw_add(&dev,&bpf_cdevsw, NULL); 130053ac6efbSJulian Elischer bpf_devsw_installed = 1; 130153ac6efbSJulian Elischer #ifdef DEVFS 1302ccbc58d3SMarc G. Fournier 130387f6c662SJulian Elischer for ( i = 0 ; i < NBPFILTER ; i++ ) { 130487f6c662SJulian Elischer bpf_devfs_token[i] = 1305ccbc58d3SMarc G. Fournier devfs_add_devswf(&bpf_cdevsw, i, DV_CHR, 0, 0, 1306ccbc58d3SMarc G. Fournier 0600, "bpf%d", i); 130753ac6efbSJulian Elischer } 130853ac6efbSJulian Elischer #endif 130953ac6efbSJulian Elischer } 13107198bf47SJulian Elischer } 131153ac6efbSJulian Elischer 131253ac6efbSJulian Elischer SYSINIT(bpfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,bpf_drvinit,NULL) 131353ac6efbSJulian Elischer 1314f8dc4716SMike Smith #else /* !BPFILTER */ 1315f8dc4716SMike Smith /* 1316f8dc4716SMike Smith * NOP stubs to allow bpf-using drivers to load and function. 1317f8dc4716SMike Smith * 1318f8dc4716SMike Smith * A 'better' implementation would allow the core bpf functionality 1319f8dc4716SMike Smith * to be loaded at runtime. 1320f8dc4716SMike Smith */ 1321f8dc4716SMike Smith 1322f8dc4716SMike Smith void 1323f8dc4716SMike Smith bpf_tap(ifp, pkt, pktlen) 1324f8dc4716SMike Smith struct ifnet *ifp; 1325f8dc4716SMike Smith register u_char *pkt; 1326f8dc4716SMike Smith register u_int pktlen; 1327f8dc4716SMike Smith { 1328f8dc4716SMike Smith } 1329f8dc4716SMike Smith 1330f8dc4716SMike Smith void 1331f8dc4716SMike Smith bpf_mtap(ifp, m) 1332f8dc4716SMike Smith struct ifnet *ifp; 1333f8dc4716SMike Smith struct mbuf *m; 1334f8dc4716SMike Smith { 1335f8dc4716SMike Smith } 1336f8dc4716SMike Smith 1337f8dc4716SMike Smith void 1338f8dc4716SMike Smith bpfattach(ifp, dlt, hdrlen) 1339f8dc4716SMike Smith struct ifnet *ifp; 1340f8dc4716SMike Smith u_int dlt, hdrlen; 1341f8dc4716SMike Smith { 1342f8dc4716SMike Smith } 1343f8dc4716SMike Smith 1344f8dc4716SMike Smith u_int 1345f8dc4716SMike Smith bpf_filter(pc, p, wirelen, buflen) 1346f8dc4716SMike Smith register struct bpf_insn *pc; 1347f8dc4716SMike Smith register u_char *p; 1348f8dc4716SMike Smith u_int wirelen; 1349f8dc4716SMike Smith register u_int buflen; 1350f8dc4716SMike Smith { 1351f8dc4716SMike Smith return -1; /* "no filter" behaviour */ 1352f8dc4716SMike Smith } 1353f8dc4716SMike Smith 1354df8bae1dSRodney W. Grimes #endif 1355