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 * 404e2f199eSPoul-Henning Kamp * $Id: bpf.c,v 1.49 1999/04/28 11:37:30 phk 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 1444e2f199eSPoul-Henning Kamp static struct cdevsw bpf_cdevsw = { 1454e2f199eSPoul-Henning Kamp /* open */ bpfopen, 1464e2f199eSPoul-Henning Kamp /* close */ bpfclose, 1474e2f199eSPoul-Henning Kamp /* read */ bpfread, 1484e2f199eSPoul-Henning Kamp /* write */ bpfwrite, 1494e2f199eSPoul-Henning Kamp /* ioctl */ bpfioctl, 1504e2f199eSPoul-Henning Kamp /* stop */ nostop, 1514e2f199eSPoul-Henning Kamp /* reset */ noreset, 1524e2f199eSPoul-Henning Kamp /* devtotty */ nodevtotty, 1534e2f199eSPoul-Henning Kamp /* poll */ bpfpoll, 1544e2f199eSPoul-Henning Kamp /* mmap */ nommap, 1554e2f199eSPoul-Henning Kamp /* strategy */ nostrategy, 1564e2f199eSPoul-Henning Kamp /* name */ "bpf", 1574e2f199eSPoul-Henning Kamp /* parms */ noparms, 1584e2f199eSPoul-Henning Kamp /* maj */ CDEV_MAJOR, 1594e2f199eSPoul-Henning Kamp /* dump */ nodump, 1604e2f199eSPoul-Henning Kamp /* psize */ nopsize, 1614e2f199eSPoul-Henning Kamp /* flags */ 0, 1624e2f199eSPoul-Henning Kamp /* maxio */ 0, 1634e2f199eSPoul-Henning Kamp /* bmaj */ -1 1644e2f199eSPoul-Henning Kamp }; 16587f6c662SJulian Elischer 16687f6c662SJulian Elischer 167df8bae1dSRodney W. Grimes static int 168df8bae1dSRodney W. Grimes bpf_movein(uio, linktype, mp, sockp, datlen) 169df8bae1dSRodney W. Grimes register struct uio *uio; 170df8bae1dSRodney W. Grimes int linktype, *datlen; 171df8bae1dSRodney W. Grimes register struct mbuf **mp; 172df8bae1dSRodney W. Grimes register struct sockaddr *sockp; 173df8bae1dSRodney W. Grimes { 174df8bae1dSRodney W. Grimes struct mbuf *m; 175df8bae1dSRodney W. Grimes int error; 176df8bae1dSRodney W. Grimes int len; 177df8bae1dSRodney W. Grimes int hlen; 178df8bae1dSRodney W. Grimes 179df8bae1dSRodney W. Grimes /* 180df8bae1dSRodney W. Grimes * Build a sockaddr based on the data link layer type. 181df8bae1dSRodney W. Grimes * We do this at this level because the ethernet header 182df8bae1dSRodney W. Grimes * is copied directly into the data field of the sockaddr. 183df8bae1dSRodney W. Grimes * In the case of SLIP, there is no header and the packet 184df8bae1dSRodney W. Grimes * is forwarded as is. 185df8bae1dSRodney W. Grimes * Also, we are careful to leave room at the front of the mbuf 186df8bae1dSRodney W. Grimes * for the link level header. 187df8bae1dSRodney W. Grimes */ 188df8bae1dSRodney W. Grimes switch (linktype) { 189df8bae1dSRodney W. Grimes 190df8bae1dSRodney W. Grimes case DLT_SLIP: 191df8bae1dSRodney W. Grimes sockp->sa_family = AF_INET; 192df8bae1dSRodney W. Grimes hlen = 0; 193df8bae1dSRodney W. Grimes break; 194df8bae1dSRodney W. Grimes 195df8bae1dSRodney W. Grimes case DLT_EN10MB: 196df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 197df8bae1dSRodney W. Grimes /* XXX Would MAXLINKHDR be better? */ 198df8bae1dSRodney W. Grimes hlen = sizeof(struct ether_header); 199df8bae1dSRodney W. Grimes break; 200df8bae1dSRodney W. Grimes 201df8bae1dSRodney W. Grimes case DLT_FDDI: 202d41f24e7SDavid Greenman #if defined(__FreeBSD__) || defined(__bsdi__) 203d41f24e7SDavid Greenman sockp->sa_family = AF_IMPLINK; 204d41f24e7SDavid Greenman hlen = 0; 205d41f24e7SDavid Greenman #else 206df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 207df8bae1dSRodney W. Grimes /* XXX 4(FORMAC)+6(dst)+6(src)+3(LLC)+5(SNAP) */ 208df8bae1dSRodney W. Grimes hlen = 24; 209d41f24e7SDavid Greenman #endif 210df8bae1dSRodney W. Grimes break; 211df8bae1dSRodney W. Grimes 21222f05c43SAndrey A. Chernov case DLT_RAW: 213df8bae1dSRodney W. Grimes case DLT_NULL: 214df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 215df8bae1dSRodney W. Grimes hlen = 0; 216df8bae1dSRodney W. Grimes break; 217df8bae1dSRodney W. Grimes 2184f53e3ccSKenjiro Cho #ifdef __FreeBSD__ 2194f53e3ccSKenjiro Cho case DLT_ATM_RFC1483: 2204f53e3ccSKenjiro Cho /* 2214f53e3ccSKenjiro Cho * en atm driver requires 4-byte atm pseudo header. 2224f53e3ccSKenjiro Cho * though it isn't standard, vpi:vci needs to be 2234f53e3ccSKenjiro Cho * specified anyway. 2244f53e3ccSKenjiro Cho */ 2254f53e3ccSKenjiro Cho sockp->sa_family = AF_UNSPEC; 2264f53e3ccSKenjiro Cho hlen = 12; /* XXX 4(ATM_PH) + 3(LLC) + 5(SNAP) */ 2274f53e3ccSKenjiro Cho break; 2284f53e3ccSKenjiro Cho #endif 2294f53e3ccSKenjiro Cho 230df8bae1dSRodney W. Grimes default: 231df8bae1dSRodney W. Grimes return (EIO); 232df8bae1dSRodney W. Grimes } 233df8bae1dSRodney W. Grimes 234df8bae1dSRodney W. Grimes len = uio->uio_resid; 235df8bae1dSRodney W. Grimes *datlen = len - hlen; 236df8bae1dSRodney W. Grimes if ((unsigned)len > MCLBYTES) 237df8bae1dSRodney W. Grimes return (EIO); 238df8bae1dSRodney W. Grimes 239963e4c2aSGarrett Wollman MGETHDR(m, M_WAIT, MT_DATA); 240df8bae1dSRodney W. Grimes if (m == 0) 241df8bae1dSRodney W. Grimes return (ENOBUFS); 242963e4c2aSGarrett Wollman if (len > MHLEN) { 243df8bae1dSRodney W. Grimes #if BSD >= 199103 244df8bae1dSRodney W. Grimes MCLGET(m, M_WAIT); 245df8bae1dSRodney W. Grimes if ((m->m_flags & M_EXT) == 0) { 246df8bae1dSRodney W. Grimes #else 247df8bae1dSRodney W. Grimes MCLGET(m); 248df8bae1dSRodney W. Grimes if (m->m_len != MCLBYTES) { 249df8bae1dSRodney W. Grimes #endif 250df8bae1dSRodney W. Grimes error = ENOBUFS; 251df8bae1dSRodney W. Grimes goto bad; 252df8bae1dSRodney W. Grimes } 253df8bae1dSRodney W. Grimes } 254963e4c2aSGarrett Wollman m->m_pkthdr.len = m->m_len = len; 255963e4c2aSGarrett Wollman m->m_pkthdr.rcvif = NULL; 256df8bae1dSRodney W. Grimes *mp = m; 257df8bae1dSRodney W. Grimes /* 258df8bae1dSRodney W. Grimes * Make room for link header. 259df8bae1dSRodney W. Grimes */ 260df8bae1dSRodney W. Grimes if (hlen != 0) { 2614f079e2fSGarrett Wollman m->m_pkthdr.len -= hlen; 262df8bae1dSRodney W. Grimes m->m_len -= hlen; 263df8bae1dSRodney W. Grimes #if BSD >= 199103 264df8bae1dSRodney W. Grimes m->m_data += hlen; /* XXX */ 265df8bae1dSRodney W. Grimes #else 266df8bae1dSRodney W. Grimes m->m_off += hlen; 267df8bae1dSRodney W. Grimes #endif 268df8bae1dSRodney W. Grimes error = UIOMOVE((caddr_t)sockp->sa_data, hlen, UIO_WRITE, uio); 269df8bae1dSRodney W. Grimes if (error) 270df8bae1dSRodney W. Grimes goto bad; 271df8bae1dSRodney W. Grimes } 272df8bae1dSRodney W. Grimes error = UIOMOVE(mtod(m, caddr_t), len - hlen, UIO_WRITE, uio); 273df8bae1dSRodney W. Grimes if (!error) 274df8bae1dSRodney W. Grimes return (0); 275df8bae1dSRodney W. Grimes bad: 276df8bae1dSRodney W. Grimes m_freem(m); 277df8bae1dSRodney W. Grimes return (error); 278df8bae1dSRodney W. Grimes } 279df8bae1dSRodney W. Grimes 280df8bae1dSRodney W. Grimes /* 281df8bae1dSRodney W. Grimes * Attach file to the bpf interface, i.e. make d listen on bp. 282df8bae1dSRodney W. Grimes * Must be called at splimp. 283df8bae1dSRodney W. Grimes */ 284df8bae1dSRodney W. Grimes static void 285df8bae1dSRodney W. Grimes bpf_attachd(d, bp) 286df8bae1dSRodney W. Grimes struct bpf_d *d; 287df8bae1dSRodney W. Grimes struct bpf_if *bp; 288df8bae1dSRodney W. Grimes { 289df8bae1dSRodney W. Grimes /* 290df8bae1dSRodney W. Grimes * Point d at bp, and add d to the interface's list of listeners. 291df8bae1dSRodney W. Grimes * Finally, point the driver's bpf cookie at the interface so 292df8bae1dSRodney W. Grimes * it will divert packets to bpf. 293df8bae1dSRodney W. Grimes */ 294df8bae1dSRodney W. Grimes d->bd_bif = bp; 295df8bae1dSRodney W. Grimes d->bd_next = bp->bif_dlist; 296df8bae1dSRodney W. Grimes bp->bif_dlist = d; 297df8bae1dSRodney W. Grimes 2989b44ff22SGarrett Wollman bp->bif_ifp->if_bpf = bp; 299df8bae1dSRodney W. Grimes } 300df8bae1dSRodney W. Grimes 301df8bae1dSRodney W. Grimes /* 302df8bae1dSRodney W. Grimes * Detach a file from its interface. 303df8bae1dSRodney W. Grimes */ 304df8bae1dSRodney W. Grimes static void 305df8bae1dSRodney W. Grimes bpf_detachd(d) 306df8bae1dSRodney W. Grimes struct bpf_d *d; 307df8bae1dSRodney W. Grimes { 308df8bae1dSRodney W. Grimes struct bpf_d **p; 309df8bae1dSRodney W. Grimes struct bpf_if *bp; 310df8bae1dSRodney W. Grimes 311df8bae1dSRodney W. Grimes bp = d->bd_bif; 312df8bae1dSRodney W. Grimes /* 313df8bae1dSRodney W. Grimes * Check if this descriptor had requested promiscuous mode. 314df8bae1dSRodney W. Grimes * If so, turn it off. 315df8bae1dSRodney W. Grimes */ 316df8bae1dSRodney W. Grimes if (d->bd_promisc) { 317df8bae1dSRodney W. Grimes d->bd_promisc = 0; 318df8bae1dSRodney W. Grimes if (ifpromisc(bp->bif_ifp, 0)) 319df8bae1dSRodney W. Grimes /* 320df8bae1dSRodney W. Grimes * Something is really wrong if we were able to put 321df8bae1dSRodney W. Grimes * the driver into promiscuous mode, but can't 322df8bae1dSRodney W. Grimes * take it out. 323df8bae1dSRodney W. Grimes */ 324df8bae1dSRodney W. Grimes panic("bpf: ifpromisc failed"); 325df8bae1dSRodney W. Grimes } 326df8bae1dSRodney W. Grimes /* Remove d from the interface's descriptor list. */ 327df8bae1dSRodney W. Grimes p = &bp->bif_dlist; 328df8bae1dSRodney W. Grimes while (*p != d) { 329df8bae1dSRodney W. Grimes p = &(*p)->bd_next; 330df8bae1dSRodney W. Grimes if (*p == 0) 331df8bae1dSRodney W. Grimes panic("bpf_detachd: descriptor not in list"); 332df8bae1dSRodney W. Grimes } 333df8bae1dSRodney W. Grimes *p = (*p)->bd_next; 334df8bae1dSRodney W. Grimes if (bp->bif_dlist == 0) 335df8bae1dSRodney W. Grimes /* 336df8bae1dSRodney W. Grimes * Let the driver know that there are no more listeners. 337df8bae1dSRodney W. Grimes */ 3389b44ff22SGarrett Wollman d->bd_bif->bif_ifp->if_bpf = 0; 339df8bae1dSRodney W. Grimes d->bd_bif = 0; 340df8bae1dSRodney W. Grimes } 341df8bae1dSRodney W. Grimes 342df8bae1dSRodney W. Grimes 343df8bae1dSRodney W. Grimes /* 344df8bae1dSRodney W. Grimes * Mark a descriptor free by making it point to itself. 345df8bae1dSRodney W. Grimes * This is probably cheaper than marking with a constant since 346df8bae1dSRodney W. Grimes * the address should be in a register anyway. 347df8bae1dSRodney W. Grimes */ 348df8bae1dSRodney W. Grimes #define D_ISFREE(d) ((d) == (d)->bd_next) 349df8bae1dSRodney W. Grimes #define D_MARKFREE(d) ((d)->bd_next = (d)) 350df8bae1dSRodney W. Grimes #define D_MARKUSED(d) ((d)->bd_next = 0) 351df8bae1dSRodney W. Grimes 352df8bae1dSRodney W. Grimes /* 353df8bae1dSRodney W. Grimes * Open ethernet device. Returns ENXIO for illegal minor device number, 354df8bae1dSRodney W. Grimes * EBUSY if file is open by another process. 355df8bae1dSRodney W. Grimes */ 356df8bae1dSRodney W. Grimes /* ARGSUSED */ 35787f6c662SJulian Elischer static int 35860039670SBruce Evans bpfopen(dev, flags, fmt, p) 359df8bae1dSRodney W. Grimes dev_t dev; 36060039670SBruce Evans int flags; 36160039670SBruce Evans int fmt; 36260039670SBruce Evans struct proc *p; 363df8bae1dSRodney W. Grimes { 364df8bae1dSRodney W. Grimes register struct bpf_d *d; 365df8bae1dSRodney W. Grimes 36675c13541SPoul-Henning Kamp if (p->p_prison) 36775c13541SPoul-Henning Kamp return (EPERM); 36875c13541SPoul-Henning Kamp 369df8bae1dSRodney W. Grimes if (minor(dev) >= NBPFILTER) 370df8bae1dSRodney W. Grimes return (ENXIO); 371df8bae1dSRodney W. Grimes /* 372df8bae1dSRodney W. Grimes * Each minor can be opened by only one process. If the requested 373df8bae1dSRodney W. Grimes * minor is in use, return EBUSY. 374df8bae1dSRodney W. Grimes */ 375df8bae1dSRodney W. Grimes d = &bpf_dtab[minor(dev)]; 376df8bae1dSRodney W. Grimes if (!D_ISFREE(d)) 377df8bae1dSRodney W. Grimes return (EBUSY); 378df8bae1dSRodney W. Grimes 379df8bae1dSRodney W. Grimes /* Mark "free" and do most initialization. */ 380df8bae1dSRodney W. Grimes bzero((char *)d, sizeof(*d)); 381df8bae1dSRodney W. Grimes d->bd_bufsize = bpf_bufsize; 38200a83887SPaul Traina d->bd_sig = SIGIO; 383df8bae1dSRodney W. Grimes 384df8bae1dSRodney W. Grimes return (0); 385df8bae1dSRodney W. Grimes } 386df8bae1dSRodney W. Grimes 387df8bae1dSRodney W. Grimes /* 388df8bae1dSRodney W. Grimes * Close the descriptor by detaching it from its interface, 389df8bae1dSRodney W. Grimes * deallocating its buffers, and marking it free. 390df8bae1dSRodney W. Grimes */ 391df8bae1dSRodney W. Grimes /* ARGSUSED */ 39287f6c662SJulian Elischer static int 39360039670SBruce Evans bpfclose(dev, flags, fmt, p) 394df8bae1dSRodney W. Grimes dev_t dev; 39560039670SBruce Evans int flags; 39660039670SBruce Evans int fmt; 39760039670SBruce Evans struct proc *p; 398df8bae1dSRodney W. Grimes { 399df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 400df8bae1dSRodney W. Grimes register int s; 401df8bae1dSRodney W. Grimes 402831d27a9SDon Lewis funsetown(d->bd_sigio); 403df8bae1dSRodney W. Grimes s = splimp(); 404df8bae1dSRodney W. Grimes if (d->bd_bif) 405df8bae1dSRodney W. Grimes bpf_detachd(d); 406df8bae1dSRodney W. Grimes splx(s); 407df8bae1dSRodney W. Grimes bpf_freed(d); 408df8bae1dSRodney W. Grimes 409df8bae1dSRodney W. Grimes return (0); 410df8bae1dSRodney W. Grimes } 411df8bae1dSRodney W. Grimes 412df8bae1dSRodney W. Grimes /* 413df8bae1dSRodney W. Grimes * Support for SunOS, which does not have tsleep. 414df8bae1dSRodney W. Grimes */ 415df8bae1dSRodney W. Grimes #if BSD < 199103 416df8bae1dSRodney W. Grimes static 417df8bae1dSRodney W. Grimes bpf_timeout(arg) 418df8bae1dSRodney W. Grimes caddr_t arg; 419df8bae1dSRodney W. Grimes { 420df8bae1dSRodney W. Grimes struct bpf_d *d = (struct bpf_d *)arg; 421df8bae1dSRodney W. Grimes d->bd_timedout = 1; 422df8bae1dSRodney W. Grimes wakeup(arg); 423df8bae1dSRodney W. Grimes } 424df8bae1dSRodney W. Grimes 425df8bae1dSRodney W. Grimes #define BPF_SLEEP(chan, pri, s, t) bpf_sleep((struct bpf_d *)chan) 426df8bae1dSRodney W. Grimes 427df8bae1dSRodney W. Grimes int 428df8bae1dSRodney W. Grimes bpf_sleep(d) 429df8bae1dSRodney W. Grimes register struct bpf_d *d; 430df8bae1dSRodney W. Grimes { 431df8bae1dSRodney W. Grimes register int rto = d->bd_rtout; 432df8bae1dSRodney W. Grimes register int st; 433df8bae1dSRodney W. Grimes 434df8bae1dSRodney W. Grimes if (rto != 0) { 435df8bae1dSRodney W. Grimes d->bd_timedout = 0; 436df8bae1dSRodney W. Grimes timeout(bpf_timeout, (caddr_t)d, rto); 437df8bae1dSRodney W. Grimes } 438df8bae1dSRodney W. Grimes st = sleep((caddr_t)d, PRINET|PCATCH); 439df8bae1dSRodney W. Grimes if (rto != 0) { 440df8bae1dSRodney W. Grimes if (d->bd_timedout == 0) 441df8bae1dSRodney W. Grimes untimeout(bpf_timeout, (caddr_t)d); 442df8bae1dSRodney W. Grimes else if (st == 0) 443df8bae1dSRodney W. Grimes return EWOULDBLOCK; 444df8bae1dSRodney W. Grimes } 445df8bae1dSRodney W. Grimes return (st != 0) ? EINTR : 0; 446df8bae1dSRodney W. Grimes } 447df8bae1dSRodney W. Grimes #else 448df8bae1dSRodney W. Grimes #define BPF_SLEEP tsleep 449df8bae1dSRodney W. Grimes #endif 450df8bae1dSRodney W. Grimes 451df8bae1dSRodney W. Grimes /* 452df8bae1dSRodney W. Grimes * Rotate the packet buffers in descriptor d. Move the store buffer 453df8bae1dSRodney W. Grimes * into the hold slot, and the free buffer into the store slot. 454df8bae1dSRodney W. Grimes * Zero the length of the new store buffer. 455df8bae1dSRodney W. Grimes */ 456df8bae1dSRodney W. Grimes #define ROTATE_BUFFERS(d) \ 457df8bae1dSRodney W. Grimes (d)->bd_hbuf = (d)->bd_sbuf; \ 458df8bae1dSRodney W. Grimes (d)->bd_hlen = (d)->bd_slen; \ 459df8bae1dSRodney W. Grimes (d)->bd_sbuf = (d)->bd_fbuf; \ 460df8bae1dSRodney W. Grimes (d)->bd_slen = 0; \ 461df8bae1dSRodney W. Grimes (d)->bd_fbuf = 0; 462df8bae1dSRodney W. Grimes /* 463df8bae1dSRodney W. Grimes * bpfread - read next chunk of packets from buffers 464df8bae1dSRodney W. Grimes */ 46587f6c662SJulian Elischer static int 46660039670SBruce Evans bpfread(dev, uio, ioflag) 467df8bae1dSRodney W. Grimes dev_t dev; 468df8bae1dSRodney W. Grimes register struct uio *uio; 46960039670SBruce Evans int ioflag; 470df8bae1dSRodney W. Grimes { 471df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 472df8bae1dSRodney W. Grimes int error; 473df8bae1dSRodney W. Grimes int s; 474df8bae1dSRodney W. Grimes 475df8bae1dSRodney W. Grimes /* 476df8bae1dSRodney W. Grimes * Restrict application to use a buffer the same size as 477df8bae1dSRodney W. Grimes * as kernel buffers. 478df8bae1dSRodney W. Grimes */ 479df8bae1dSRodney W. Grimes if (uio->uio_resid != d->bd_bufsize) 480df8bae1dSRodney W. Grimes return (EINVAL); 481df8bae1dSRodney W. Grimes 482df8bae1dSRodney W. Grimes s = splimp(); 483df8bae1dSRodney W. Grimes /* 484df8bae1dSRodney W. Grimes * If the hold buffer is empty, then do a timed sleep, which 485df8bae1dSRodney W. Grimes * ends when the timeout expires or when enough packets 486df8bae1dSRodney W. Grimes * have arrived to fill the store buffer. 487df8bae1dSRodney W. Grimes */ 488df8bae1dSRodney W. Grimes while (d->bd_hbuf == 0) { 489df8bae1dSRodney W. Grimes if (d->bd_immediate && d->bd_slen != 0) { 490df8bae1dSRodney W. Grimes /* 491df8bae1dSRodney W. Grimes * A packet(s) either arrived since the previous 492df8bae1dSRodney W. Grimes * read or arrived while we were asleep. 493df8bae1dSRodney W. Grimes * Rotate the buffers and return what's here. 494df8bae1dSRodney W. Grimes */ 495df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 496df8bae1dSRodney W. Grimes break; 497df8bae1dSRodney W. Grimes } 498fba9235dSBruce Evans if (ioflag & IO_NDELAY) 499fba9235dSBruce Evans error = EWOULDBLOCK; 500fba9235dSBruce Evans else 501df8bae1dSRodney W. Grimes error = BPF_SLEEP((caddr_t)d, PRINET|PCATCH, "bpf", 502df8bae1dSRodney W. Grimes d->bd_rtout); 503df8bae1dSRodney W. Grimes if (error == EINTR || error == ERESTART) { 504df8bae1dSRodney W. Grimes splx(s); 505df8bae1dSRodney W. Grimes return (error); 506df8bae1dSRodney W. Grimes } 507df8bae1dSRodney W. Grimes if (error == EWOULDBLOCK) { 508df8bae1dSRodney W. Grimes /* 509df8bae1dSRodney W. Grimes * On a timeout, return what's in the buffer, 510df8bae1dSRodney W. Grimes * which may be nothing. If there is something 511df8bae1dSRodney W. Grimes * in the store buffer, we can rotate the buffers. 512df8bae1dSRodney W. Grimes */ 513df8bae1dSRodney W. Grimes if (d->bd_hbuf) 514df8bae1dSRodney W. Grimes /* 515df8bae1dSRodney W. Grimes * We filled up the buffer in between 516df8bae1dSRodney W. Grimes * getting the timeout and arriving 517df8bae1dSRodney W. Grimes * here, so we don't need to rotate. 518df8bae1dSRodney W. Grimes */ 519df8bae1dSRodney W. Grimes break; 520df8bae1dSRodney W. Grimes 521df8bae1dSRodney W. Grimes if (d->bd_slen == 0) { 522df8bae1dSRodney W. Grimes splx(s); 523df8bae1dSRodney W. Grimes return (0); 524df8bae1dSRodney W. Grimes } 525df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 526df8bae1dSRodney W. Grimes break; 527df8bae1dSRodney W. Grimes } 528df8bae1dSRodney W. Grimes } 529df8bae1dSRodney W. Grimes /* 530df8bae1dSRodney W. Grimes * At this point, we know we have something in the hold slot. 531df8bae1dSRodney W. Grimes */ 532df8bae1dSRodney W. Grimes splx(s); 533df8bae1dSRodney W. Grimes 534df8bae1dSRodney W. Grimes /* 535df8bae1dSRodney W. Grimes * Move data from hold buffer into user space. 536df8bae1dSRodney W. Grimes * We know the entire buffer is transferred since 537df8bae1dSRodney W. Grimes * we checked above that the read buffer is bpf_bufsize bytes. 538df8bae1dSRodney W. Grimes */ 539df8bae1dSRodney W. Grimes error = UIOMOVE(d->bd_hbuf, d->bd_hlen, UIO_READ, uio); 540df8bae1dSRodney W. Grimes 541df8bae1dSRodney W. Grimes s = splimp(); 542df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 543df8bae1dSRodney W. Grimes d->bd_hbuf = 0; 544df8bae1dSRodney W. Grimes d->bd_hlen = 0; 545df8bae1dSRodney W. Grimes splx(s); 546df8bae1dSRodney W. Grimes 547df8bae1dSRodney W. Grimes return (error); 548df8bae1dSRodney W. Grimes } 549df8bae1dSRodney W. Grimes 550df8bae1dSRodney W. Grimes 551df8bae1dSRodney W. Grimes /* 552df8bae1dSRodney W. Grimes * If there are processes sleeping on this descriptor, wake them up. 553df8bae1dSRodney W. Grimes */ 554df8bae1dSRodney W. Grimes static inline void 555df8bae1dSRodney W. Grimes bpf_wakeup(d) 556df8bae1dSRodney W. Grimes register struct bpf_d *d; 557df8bae1dSRodney W. Grimes { 558df8bae1dSRodney W. Grimes wakeup((caddr_t)d); 559831d27a9SDon Lewis if (d->bd_async && d->bd_sig && d->bd_sigio) 560831d27a9SDon Lewis pgsigio(d->bd_sigio, d->bd_sig, 0); 56100a83887SPaul Traina 562df8bae1dSRodney W. Grimes #if BSD >= 199103 563df8bae1dSRodney W. Grimes selwakeup(&d->bd_sel); 564df8bae1dSRodney W. Grimes /* XXX */ 565df8bae1dSRodney W. Grimes d->bd_sel.si_pid = 0; 566df8bae1dSRodney W. Grimes #else 567df8bae1dSRodney W. Grimes if (d->bd_selproc) { 568df8bae1dSRodney W. Grimes selwakeup(d->bd_selproc, (int)d->bd_selcoll); 569df8bae1dSRodney W. Grimes d->bd_selcoll = 0; 570df8bae1dSRodney W. Grimes d->bd_selproc = 0; 571df8bae1dSRodney W. Grimes } 572df8bae1dSRodney W. Grimes #endif 573df8bae1dSRodney W. Grimes } 574df8bae1dSRodney W. Grimes 57587f6c662SJulian Elischer static int 57660039670SBruce Evans bpfwrite(dev, uio, ioflag) 577df8bae1dSRodney W. Grimes dev_t dev; 578df8bae1dSRodney W. Grimes struct uio *uio; 57960039670SBruce Evans int ioflag; 580df8bae1dSRodney W. Grimes { 581df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 582df8bae1dSRodney W. Grimes struct ifnet *ifp; 583df8bae1dSRodney W. Grimes struct mbuf *m; 584df8bae1dSRodney W. Grimes int error, s; 585df8bae1dSRodney W. Grimes static struct sockaddr dst; 586df8bae1dSRodney W. Grimes int datlen; 587df8bae1dSRodney W. Grimes 588df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 589df8bae1dSRodney W. Grimes return (ENXIO); 590df8bae1dSRodney W. Grimes 591df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 592df8bae1dSRodney W. Grimes 593df8bae1dSRodney W. Grimes if (uio->uio_resid == 0) 594df8bae1dSRodney W. Grimes return (0); 595df8bae1dSRodney W. Grimes 596df8bae1dSRodney W. Grimes error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, &dst, &datlen); 597df8bae1dSRodney W. Grimes if (error) 598df8bae1dSRodney W. Grimes return (error); 599df8bae1dSRodney W. Grimes 600df8bae1dSRodney W. Grimes if (datlen > ifp->if_mtu) 601df8bae1dSRodney W. Grimes return (EMSGSIZE); 602df8bae1dSRodney W. Grimes 603df8bae1dSRodney W. Grimes s = splnet(); 604df8bae1dSRodney W. Grimes #if BSD >= 199103 605df8bae1dSRodney W. Grimes error = (*ifp->if_output)(ifp, m, &dst, (struct rtentry *)0); 606df8bae1dSRodney W. Grimes #else 607df8bae1dSRodney W. Grimes error = (*ifp->if_output)(ifp, m, &dst); 608df8bae1dSRodney W. Grimes #endif 609df8bae1dSRodney W. Grimes splx(s); 610df8bae1dSRodney W. Grimes /* 611df8bae1dSRodney W. Grimes * The driver frees the mbuf. 612df8bae1dSRodney W. Grimes */ 613df8bae1dSRodney W. Grimes return (error); 614df8bae1dSRodney W. Grimes } 615df8bae1dSRodney W. Grimes 616df8bae1dSRodney W. Grimes /* 617df8bae1dSRodney W. Grimes * Reset a descriptor by flushing its packet buffer and clearing the 618df8bae1dSRodney W. Grimes * receive and drop counts. Should be called at splimp. 619df8bae1dSRodney W. Grimes */ 620df8bae1dSRodney W. Grimes static void 621df8bae1dSRodney W. Grimes reset_d(d) 622df8bae1dSRodney W. Grimes struct bpf_d *d; 623df8bae1dSRodney W. Grimes { 624df8bae1dSRodney W. Grimes if (d->bd_hbuf) { 625df8bae1dSRodney W. Grimes /* Free the hold buffer. */ 626df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 627df8bae1dSRodney W. Grimes d->bd_hbuf = 0; 628df8bae1dSRodney W. Grimes } 629df8bae1dSRodney W. Grimes d->bd_slen = 0; 630df8bae1dSRodney W. Grimes d->bd_hlen = 0; 631df8bae1dSRodney W. Grimes d->bd_rcount = 0; 632df8bae1dSRodney W. Grimes d->bd_dcount = 0; 633df8bae1dSRodney W. Grimes } 634df8bae1dSRodney W. Grimes 635df8bae1dSRodney W. Grimes /* 636df8bae1dSRodney W. Grimes * FIONREAD Check for read packet available. 637df8bae1dSRodney W. Grimes * SIOCGIFADDR Get interface address - convenient hook to driver. 638df8bae1dSRodney W. Grimes * BIOCGBLEN Get buffer len [for read()]. 639df8bae1dSRodney W. Grimes * BIOCSETF Set ethernet read filter. 640df8bae1dSRodney W. Grimes * BIOCFLUSH Flush read packet buffer. 641df8bae1dSRodney W. Grimes * BIOCPROMISC Put interface into promiscuous mode. 642df8bae1dSRodney W. Grimes * BIOCGDLT Get link layer type. 643df8bae1dSRodney W. Grimes * BIOCGETIF Get interface name. 644df8bae1dSRodney W. Grimes * BIOCSETIF Set interface. 645df8bae1dSRodney W. Grimes * BIOCSRTIMEOUT Set read timeout. 646df8bae1dSRodney W. Grimes * BIOCGRTIMEOUT Get read timeout. 647df8bae1dSRodney W. Grimes * BIOCGSTATS Get packet stats. 648df8bae1dSRodney W. Grimes * BIOCIMMEDIATE Set immediate mode. 649df8bae1dSRodney W. Grimes * BIOCVERSION Get filter language version. 650df8bae1dSRodney W. Grimes */ 651df8bae1dSRodney W. Grimes /* ARGSUSED */ 65287f6c662SJulian Elischer static int 65360039670SBruce Evans bpfioctl(dev, cmd, addr, flags, p) 654df8bae1dSRodney W. Grimes dev_t dev; 655ecbb00a2SDoug Rabson u_long cmd; 656df8bae1dSRodney W. Grimes caddr_t addr; 65760039670SBruce Evans int flags; 65860039670SBruce Evans struct proc *p; 659df8bae1dSRodney W. Grimes { 660df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 661df8bae1dSRodney W. Grimes int s, error = 0; 662df8bae1dSRodney W. Grimes 663df8bae1dSRodney W. Grimes switch (cmd) { 664df8bae1dSRodney W. Grimes 665df8bae1dSRodney W. Grimes default: 666df8bae1dSRodney W. Grimes error = EINVAL; 667df8bae1dSRodney W. Grimes break; 668df8bae1dSRodney W. Grimes 669df8bae1dSRodney W. Grimes /* 670df8bae1dSRodney W. Grimes * Check for read packet available. 671df8bae1dSRodney W. Grimes */ 672df8bae1dSRodney W. Grimes case FIONREAD: 673df8bae1dSRodney W. Grimes { 674df8bae1dSRodney W. Grimes int n; 675df8bae1dSRodney W. Grimes 676df8bae1dSRodney W. Grimes s = splimp(); 677df8bae1dSRodney W. Grimes n = d->bd_slen; 678df8bae1dSRodney W. Grimes if (d->bd_hbuf) 679df8bae1dSRodney W. Grimes n += d->bd_hlen; 680df8bae1dSRodney W. Grimes splx(s); 681df8bae1dSRodney W. Grimes 682df8bae1dSRodney W. Grimes *(int *)addr = n; 683df8bae1dSRodney W. Grimes break; 684df8bae1dSRodney W. Grimes } 685df8bae1dSRodney W. Grimes 686df8bae1dSRodney W. Grimes case SIOCGIFADDR: 687df8bae1dSRodney W. Grimes { 688df8bae1dSRodney W. Grimes struct ifnet *ifp; 689df8bae1dSRodney W. Grimes 690df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 691df8bae1dSRodney W. Grimes error = EINVAL; 692df8bae1dSRodney W. Grimes else { 693df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 694df8bae1dSRodney W. Grimes error = (*ifp->if_ioctl)(ifp, cmd, addr); 695df8bae1dSRodney W. Grimes } 696df8bae1dSRodney W. Grimes break; 697df8bae1dSRodney W. Grimes } 698df8bae1dSRodney W. Grimes 699df8bae1dSRodney W. Grimes /* 700df8bae1dSRodney W. Grimes * Get buffer len [for read()]. 701df8bae1dSRodney W. Grimes */ 702df8bae1dSRodney W. Grimes case BIOCGBLEN: 703df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bufsize; 704df8bae1dSRodney W. Grimes break; 705df8bae1dSRodney W. Grimes 706df8bae1dSRodney W. Grimes /* 707df8bae1dSRodney W. Grimes * Set buffer length. 708df8bae1dSRodney W. Grimes */ 709df8bae1dSRodney W. Grimes case BIOCSBLEN: 710df8bae1dSRodney W. Grimes #if BSD < 199103 711df8bae1dSRodney W. Grimes error = EINVAL; 712df8bae1dSRodney W. Grimes #else 713df8bae1dSRodney W. Grimes if (d->bd_bif != 0) 714df8bae1dSRodney W. Grimes error = EINVAL; 715df8bae1dSRodney W. Grimes else { 716df8bae1dSRodney W. Grimes register u_int size = *(u_int *)addr; 717df8bae1dSRodney W. Grimes 718df8bae1dSRodney W. Grimes if (size > BPF_MAXBUFSIZE) 719df8bae1dSRodney W. Grimes *(u_int *)addr = size = BPF_MAXBUFSIZE; 720df8bae1dSRodney W. Grimes else if (size < BPF_MINBUFSIZE) 721df8bae1dSRodney W. Grimes *(u_int *)addr = size = BPF_MINBUFSIZE; 722df8bae1dSRodney W. Grimes d->bd_bufsize = size; 723df8bae1dSRodney W. Grimes } 724df8bae1dSRodney W. Grimes #endif 725df8bae1dSRodney W. Grimes break; 726df8bae1dSRodney W. Grimes 727df8bae1dSRodney W. Grimes /* 728df8bae1dSRodney W. Grimes * Set link layer read filter. 729df8bae1dSRodney W. Grimes */ 730df8bae1dSRodney W. Grimes case BIOCSETF: 731df8bae1dSRodney W. Grimes error = bpf_setf(d, (struct bpf_program *)addr); 732df8bae1dSRodney W. Grimes break; 733df8bae1dSRodney W. Grimes 734df8bae1dSRodney W. Grimes /* 735df8bae1dSRodney W. Grimes * Flush read packet buffer. 736df8bae1dSRodney W. Grimes */ 737df8bae1dSRodney W. Grimes case BIOCFLUSH: 738df8bae1dSRodney W. Grimes s = splimp(); 739df8bae1dSRodney W. Grimes reset_d(d); 740df8bae1dSRodney W. Grimes splx(s); 741df8bae1dSRodney W. Grimes break; 742df8bae1dSRodney W. Grimes 743df8bae1dSRodney W. Grimes /* 744df8bae1dSRodney W. Grimes * Put interface into promiscuous mode. 745df8bae1dSRodney W. Grimes */ 746df8bae1dSRodney W. Grimes case BIOCPROMISC: 747df8bae1dSRodney W. Grimes if (d->bd_bif == 0) { 748df8bae1dSRodney W. Grimes /* 749df8bae1dSRodney W. Grimes * No interface attached yet. 750df8bae1dSRodney W. Grimes */ 751df8bae1dSRodney W. Grimes error = EINVAL; 752df8bae1dSRodney W. Grimes break; 753df8bae1dSRodney W. Grimes } 754df8bae1dSRodney W. Grimes s = splimp(); 755df8bae1dSRodney W. Grimes if (d->bd_promisc == 0) { 756df8bae1dSRodney W. Grimes error = ifpromisc(d->bd_bif->bif_ifp, 1); 757df8bae1dSRodney W. Grimes if (error == 0) 758df8bae1dSRodney W. Grimes d->bd_promisc = 1; 759df8bae1dSRodney W. Grimes } 760df8bae1dSRodney W. Grimes splx(s); 761df8bae1dSRodney W. Grimes break; 762df8bae1dSRodney W. Grimes 763df8bae1dSRodney W. Grimes /* 764df8bae1dSRodney W. Grimes * Get device parameters. 765df8bae1dSRodney W. Grimes */ 766df8bae1dSRodney W. Grimes case BIOCGDLT: 767df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 768df8bae1dSRodney W. Grimes error = EINVAL; 769df8bae1dSRodney W. Grimes else 770df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bif->bif_dlt; 771df8bae1dSRodney W. Grimes break; 772df8bae1dSRodney W. Grimes 773df8bae1dSRodney W. Grimes /* 774df8bae1dSRodney W. Grimes * Set interface name. 775df8bae1dSRodney W. Grimes */ 776df8bae1dSRodney W. Grimes case BIOCGETIF: 777df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 778df8bae1dSRodney W. Grimes error = EINVAL; 779df8bae1dSRodney W. Grimes else 780df8bae1dSRodney W. Grimes bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr); 781df8bae1dSRodney W. Grimes break; 782df8bae1dSRodney W. Grimes 783df8bae1dSRodney W. Grimes /* 784df8bae1dSRodney W. Grimes * Set interface. 785df8bae1dSRodney W. Grimes */ 786df8bae1dSRodney W. Grimes case BIOCSETIF: 787df8bae1dSRodney W. Grimes error = bpf_setif(d, (struct ifreq *)addr); 788df8bae1dSRodney W. Grimes break; 789df8bae1dSRodney W. Grimes 790df8bae1dSRodney W. Grimes /* 791df8bae1dSRodney W. Grimes * Set read timeout. 792df8bae1dSRodney W. Grimes */ 793df8bae1dSRodney W. Grimes case BIOCSRTIMEOUT: 794df8bae1dSRodney W. Grimes { 795df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 796df8bae1dSRodney W. Grimes 797bdc2cdc5SAlexander Langer /* 798bdc2cdc5SAlexander Langer * Subtract 1 tick from tvtohz() since this isn't 799bdc2cdc5SAlexander Langer * a one-shot timer. 800bdc2cdc5SAlexander Langer */ 801bdc2cdc5SAlexander Langer if ((error = itimerfix(tv)) == 0) 802bdc2cdc5SAlexander Langer d->bd_rtout = tvtohz(tv) - 1; 803df8bae1dSRodney W. Grimes break; 804df8bae1dSRodney W. Grimes } 805df8bae1dSRodney W. Grimes 806df8bae1dSRodney W. Grimes /* 807df8bae1dSRodney W. Grimes * Get read timeout. 808df8bae1dSRodney W. Grimes */ 809df8bae1dSRodney W. Grimes case BIOCGRTIMEOUT: 810df8bae1dSRodney W. Grimes { 811df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 812df8bae1dSRodney W. Grimes 813bdc2cdc5SAlexander Langer tv->tv_sec = d->bd_rtout / hz; 814bdc2cdc5SAlexander Langer tv->tv_usec = (d->bd_rtout % hz) * tick; 815df8bae1dSRodney W. Grimes break; 816df8bae1dSRodney W. Grimes } 817df8bae1dSRodney W. Grimes 818df8bae1dSRodney W. Grimes /* 819df8bae1dSRodney W. Grimes * Get packet stats. 820df8bae1dSRodney W. Grimes */ 821df8bae1dSRodney W. Grimes case BIOCGSTATS: 822df8bae1dSRodney W. Grimes { 823df8bae1dSRodney W. Grimes struct bpf_stat *bs = (struct bpf_stat *)addr; 824df8bae1dSRodney W. Grimes 825df8bae1dSRodney W. Grimes bs->bs_recv = d->bd_rcount; 826df8bae1dSRodney W. Grimes bs->bs_drop = d->bd_dcount; 827df8bae1dSRodney W. Grimes break; 828df8bae1dSRodney W. Grimes } 829df8bae1dSRodney W. Grimes 830df8bae1dSRodney W. Grimes /* 831df8bae1dSRodney W. Grimes * Set immediate mode. 832df8bae1dSRodney W. Grimes */ 833df8bae1dSRodney W. Grimes case BIOCIMMEDIATE: 834df8bae1dSRodney W. Grimes d->bd_immediate = *(u_int *)addr; 835df8bae1dSRodney W. Grimes break; 836df8bae1dSRodney W. Grimes 837df8bae1dSRodney W. Grimes case BIOCVERSION: 838df8bae1dSRodney W. Grimes { 839df8bae1dSRodney W. Grimes struct bpf_version *bv = (struct bpf_version *)addr; 840df8bae1dSRodney W. Grimes 841df8bae1dSRodney W. Grimes bv->bv_major = BPF_MAJOR_VERSION; 842df8bae1dSRodney W. Grimes bv->bv_minor = BPF_MINOR_VERSION; 843df8bae1dSRodney W. Grimes break; 844df8bae1dSRodney W. Grimes } 84500a83887SPaul Traina 84600a83887SPaul Traina case FIONBIO: /* Non-blocking I/O */ 84700a83887SPaul Traina break; 84800a83887SPaul Traina 84900a83887SPaul Traina case FIOASYNC: /* Send signal on receive packets */ 85000a83887SPaul Traina d->bd_async = *(int *)addr; 85100a83887SPaul Traina break; 85200a83887SPaul Traina 853831d27a9SDon Lewis case FIOSETOWN: 854831d27a9SDon Lewis error = fsetown(*(int *)addr, &d->bd_sigio); 85500a83887SPaul Traina break; 85600a83887SPaul Traina 857831d27a9SDon Lewis case FIOGETOWN: 858831d27a9SDon Lewis *(int *)addr = fgetown(d->bd_sigio); 859831d27a9SDon Lewis break; 860831d27a9SDon Lewis 861831d27a9SDon Lewis /* This is deprecated, FIOSETOWN should be used instead. */ 862831d27a9SDon Lewis case TIOCSPGRP: 863831d27a9SDon Lewis error = fsetown(-(*(int *)addr), &d->bd_sigio); 864831d27a9SDon Lewis break; 865831d27a9SDon Lewis 866831d27a9SDon Lewis /* This is deprecated, FIOGETOWN should be used instead. */ 86700a83887SPaul Traina case TIOCGPGRP: 868831d27a9SDon Lewis *(int *)addr = -fgetown(d->bd_sigio); 86900a83887SPaul Traina break; 87000a83887SPaul Traina 87100a83887SPaul Traina case BIOCSRSIG: /* Set receive signal */ 87200a83887SPaul Traina { 87300a83887SPaul Traina u_int sig; 87400a83887SPaul Traina 87500a83887SPaul Traina sig = *(u_int *)addr; 87600a83887SPaul Traina 87700a83887SPaul Traina if (sig >= NSIG) 87800a83887SPaul Traina error = EINVAL; 87900a83887SPaul Traina else 88000a83887SPaul Traina d->bd_sig = sig; 88100a83887SPaul Traina break; 88200a83887SPaul Traina } 88300a83887SPaul Traina case BIOCGRSIG: 88400a83887SPaul Traina *(u_int *)addr = d->bd_sig; 88500a83887SPaul Traina break; 886df8bae1dSRodney W. Grimes } 887df8bae1dSRodney W. Grimes return (error); 888df8bae1dSRodney W. Grimes } 889df8bae1dSRodney W. Grimes 890df8bae1dSRodney W. Grimes /* 891df8bae1dSRodney W. Grimes * Set d's packet filter program to fp. If this file already has a filter, 892df8bae1dSRodney W. Grimes * free it and replace it. Returns EINVAL for bogus requests. 893df8bae1dSRodney W. Grimes */ 894f708ef1bSPoul-Henning Kamp static int 895df8bae1dSRodney W. Grimes bpf_setf(d, fp) 896df8bae1dSRodney W. Grimes struct bpf_d *d; 897df8bae1dSRodney W. Grimes struct bpf_program *fp; 898df8bae1dSRodney W. Grimes { 899df8bae1dSRodney W. Grimes struct bpf_insn *fcode, *old; 900df8bae1dSRodney W. Grimes u_int flen, size; 901df8bae1dSRodney W. Grimes int s; 902df8bae1dSRodney W. Grimes 903df8bae1dSRodney W. Grimes old = d->bd_filter; 904df8bae1dSRodney W. Grimes if (fp->bf_insns == 0) { 905df8bae1dSRodney W. Grimes if (fp->bf_len != 0) 906df8bae1dSRodney W. Grimes return (EINVAL); 907df8bae1dSRodney W. Grimes s = splimp(); 908df8bae1dSRodney W. Grimes d->bd_filter = 0; 909df8bae1dSRodney W. Grimes reset_d(d); 910df8bae1dSRodney W. Grimes splx(s); 911df8bae1dSRodney W. Grimes if (old != 0) 912df8bae1dSRodney W. Grimes free((caddr_t)old, M_DEVBUF); 913df8bae1dSRodney W. Grimes return (0); 914df8bae1dSRodney W. Grimes } 915df8bae1dSRodney W. Grimes flen = fp->bf_len; 916df8bae1dSRodney W. Grimes if (flen > BPF_MAXINSNS) 917df8bae1dSRodney W. Grimes return (EINVAL); 918df8bae1dSRodney W. Grimes 919df8bae1dSRodney W. Grimes size = flen * sizeof(*fp->bf_insns); 920df8bae1dSRodney W. Grimes fcode = (struct bpf_insn *)malloc(size, M_DEVBUF, M_WAITOK); 921df8bae1dSRodney W. Grimes if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 && 922df8bae1dSRodney W. Grimes bpf_validate(fcode, (int)flen)) { 923df8bae1dSRodney W. Grimes s = splimp(); 924df8bae1dSRodney W. Grimes d->bd_filter = fcode; 925df8bae1dSRodney W. Grimes reset_d(d); 926df8bae1dSRodney W. Grimes splx(s); 927df8bae1dSRodney W. Grimes if (old != 0) 928df8bae1dSRodney W. Grimes free((caddr_t)old, M_DEVBUF); 929df8bae1dSRodney W. Grimes 930df8bae1dSRodney W. Grimes return (0); 931df8bae1dSRodney W. Grimes } 932df8bae1dSRodney W. Grimes free((caddr_t)fcode, M_DEVBUF); 933df8bae1dSRodney W. Grimes return (EINVAL); 934df8bae1dSRodney W. Grimes } 935df8bae1dSRodney W. Grimes 936df8bae1dSRodney W. Grimes /* 937df8bae1dSRodney W. Grimes * Detach a file from its current interface (if attached at all) and attach 938df8bae1dSRodney W. Grimes * to the interface indicated by the name stored in ifr. 939df8bae1dSRodney W. Grimes * Return an errno or 0. 940df8bae1dSRodney W. Grimes */ 941df8bae1dSRodney W. Grimes static int 942df8bae1dSRodney W. Grimes bpf_setif(d, ifr) 943df8bae1dSRodney W. Grimes struct bpf_d *d; 944df8bae1dSRodney W. Grimes struct ifreq *ifr; 945df8bae1dSRodney W. Grimes { 946df8bae1dSRodney W. Grimes struct bpf_if *bp; 9479b44ff22SGarrett Wollman int s, error; 9489b44ff22SGarrett Wollman struct ifnet *theywant; 949df8bae1dSRodney W. Grimes 9509b44ff22SGarrett Wollman theywant = ifunit(ifr->ifr_name); 9519b44ff22SGarrett Wollman if (theywant == 0) 9529b44ff22SGarrett Wollman return ENXIO; 9539b44ff22SGarrett Wollman 954df8bae1dSRodney W. Grimes /* 955df8bae1dSRodney W. Grimes * Look through attached interfaces for the named one. 956df8bae1dSRodney W. Grimes */ 957df8bae1dSRodney W. Grimes for (bp = bpf_iflist; bp != 0; bp = bp->bif_next) { 958df8bae1dSRodney W. Grimes struct ifnet *ifp = bp->bif_ifp; 959df8bae1dSRodney W. Grimes 9609b44ff22SGarrett Wollman if (ifp == 0 || ifp != theywant) 961df8bae1dSRodney W. Grimes continue; 962df8bae1dSRodney W. Grimes /* 963df8bae1dSRodney W. Grimes * We found the requested interface. 964df8bae1dSRodney W. Grimes * If it's not up, return an error. 965df8bae1dSRodney W. Grimes * Allocate the packet buffers if we need to. 966df8bae1dSRodney W. Grimes * If we're already attached to requested interface, 967df8bae1dSRodney W. Grimes * just flush the buffer. 968df8bae1dSRodney W. Grimes */ 969df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_UP) == 0) 970df8bae1dSRodney W. Grimes return (ENETDOWN); 971df8bae1dSRodney W. Grimes 972df8bae1dSRodney W. Grimes if (d->bd_sbuf == 0) { 973df8bae1dSRodney W. Grimes error = bpf_allocbufs(d); 974df8bae1dSRodney W. Grimes if (error != 0) 975df8bae1dSRodney W. Grimes return (error); 976df8bae1dSRodney W. Grimes } 977df8bae1dSRodney W. Grimes s = splimp(); 978df8bae1dSRodney W. Grimes if (bp != d->bd_bif) { 979df8bae1dSRodney W. Grimes if (d->bd_bif) 980df8bae1dSRodney W. Grimes /* 981df8bae1dSRodney W. Grimes * Detach if attached to something else. 982df8bae1dSRodney W. Grimes */ 983df8bae1dSRodney W. Grimes bpf_detachd(d); 984df8bae1dSRodney W. Grimes 985df8bae1dSRodney W. Grimes bpf_attachd(d, bp); 986df8bae1dSRodney W. Grimes } 987df8bae1dSRodney W. Grimes reset_d(d); 988df8bae1dSRodney W. Grimes splx(s); 989df8bae1dSRodney W. Grimes return (0); 990df8bae1dSRodney W. Grimes } 991df8bae1dSRodney W. Grimes /* Not found. */ 992df8bae1dSRodney W. Grimes return (ENXIO); 993df8bae1dSRodney W. Grimes } 994df8bae1dSRodney W. Grimes 995df8bae1dSRodney W. Grimes /* 996df8bae1dSRodney W. Grimes * Convert an interface name plus unit number of an ifp to a single 997df8bae1dSRodney W. Grimes * name which is returned in the ifr. 998df8bae1dSRodney W. Grimes */ 999df8bae1dSRodney W. Grimes static void 1000df8bae1dSRodney W. Grimes bpf_ifname(ifp, ifr) 1001df8bae1dSRodney W. Grimes struct ifnet *ifp; 1002df8bae1dSRodney W. Grimes struct ifreq *ifr; 1003df8bae1dSRodney W. Grimes { 1004df8bae1dSRodney W. Grimes char *s = ifp->if_name; 1005df8bae1dSRodney W. Grimes char *d = ifr->ifr_name; 1006df8bae1dSRodney W. Grimes 1007831a80b0SMatthew Dillon while ((*d++ = *s++) != 0) 1008df8bae1dSRodney W. Grimes continue; 1009a76f92a8SDavid Greenman d--; /* back to the null */ 1010df8bae1dSRodney W. Grimes /* XXX Assume that unit number is less than 10. */ 1011df8bae1dSRodney W. Grimes *d++ = ifp->if_unit + '0'; 1012df8bae1dSRodney W. Grimes *d = '\0'; 1013df8bae1dSRodney W. Grimes } 1014df8bae1dSRodney W. Grimes 1015df8bae1dSRodney W. Grimes /* 1016243ac7d8SPeter Wemm * Support for select() and poll() system calls 1017df8bae1dSRodney W. Grimes * 1018df8bae1dSRodney W. Grimes * Return true iff the specific operation will not block indefinitely. 1019df8bae1dSRodney W. Grimes * Otherwise, return false but make a note that a selwakeup() must be done. 1020df8bae1dSRodney W. Grimes */ 1021df8bae1dSRodney W. Grimes int 1022243ac7d8SPeter Wemm bpfpoll(dev, events, p) 1023df8bae1dSRodney W. Grimes register dev_t dev; 1024243ac7d8SPeter Wemm int events; 1025df8bae1dSRodney W. Grimes struct proc *p; 1026df8bae1dSRodney W. Grimes { 1027df8bae1dSRodney W. Grimes register struct bpf_d *d; 1028df8bae1dSRodney W. Grimes register int s; 1029243ac7d8SPeter Wemm int revents = 0; 1030df8bae1dSRodney W. Grimes 1031df8bae1dSRodney W. Grimes /* 1032df8bae1dSRodney W. Grimes * An imitation of the FIONREAD ioctl code. 1033df8bae1dSRodney W. Grimes */ 1034df8bae1dSRodney W. Grimes d = &bpf_dtab[minor(dev)]; 1035df8bae1dSRodney W. Grimes 1036df8bae1dSRodney W. Grimes s = splimp(); 103775c13541SPoul-Henning Kamp if (events & (POLLIN | POLLRDNORM)) { 1038243ac7d8SPeter Wemm if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0)) 1039243ac7d8SPeter Wemm revents |= events & (POLLIN | POLLRDNORM); 1040df8bae1dSRodney W. Grimes else 1041243ac7d8SPeter Wemm selrecord(p, &d->bd_sel); 104275c13541SPoul-Henning Kamp } 1043df8bae1dSRodney W. Grimes splx(s); 1044243ac7d8SPeter Wemm return (revents); 1045df8bae1dSRodney W. Grimes } 1046df8bae1dSRodney W. Grimes 1047df8bae1dSRodney W. Grimes /* 1048df8bae1dSRodney W. Grimes * Incoming linkage from device drivers. Process the packet pkt, of length 1049df8bae1dSRodney W. Grimes * pktlen, which is stored in a contiguous buffer. The packet is parsed 1050df8bae1dSRodney W. Grimes * by each process' filter, and if accepted, stashed into the corresponding 1051df8bae1dSRodney W. Grimes * buffer. 1052df8bae1dSRodney W. Grimes */ 1053df8bae1dSRodney W. Grimes void 10549b44ff22SGarrett Wollman bpf_tap(ifp, pkt, pktlen) 10559b44ff22SGarrett Wollman struct ifnet *ifp; 1056df8bae1dSRodney W. Grimes register u_char *pkt; 1057df8bae1dSRodney W. Grimes register u_int pktlen; 1058df8bae1dSRodney W. Grimes { 1059df8bae1dSRodney W. Grimes struct bpf_if *bp; 1060df8bae1dSRodney W. Grimes register struct bpf_d *d; 1061df8bae1dSRodney W. Grimes register u_int slen; 1062df8bae1dSRodney W. Grimes /* 1063df8bae1dSRodney W. Grimes * Note that the ipl does not have to be raised at this point. 1064df8bae1dSRodney W. Grimes * The only problem that could arise here is that if two different 1065df8bae1dSRodney W. Grimes * interfaces shared any data. This is not the case. 1066df8bae1dSRodney W. Grimes */ 10679b44ff22SGarrett Wollman bp = ifp->if_bpf; 1068df8bae1dSRodney W. Grimes for (d = bp->bif_dlist; d != 0; d = d->bd_next) { 1069df8bae1dSRodney W. Grimes ++d->bd_rcount; 1070df8bae1dSRodney W. Grimes slen = bpf_filter(d->bd_filter, pkt, pktlen, pktlen); 1071df8bae1dSRodney W. Grimes if (slen != 0) 1072df8bae1dSRodney W. Grimes catchpacket(d, pkt, pktlen, slen, bcopy); 1073df8bae1dSRodney W. Grimes } 1074df8bae1dSRodney W. Grimes } 1075df8bae1dSRodney W. Grimes 1076df8bae1dSRodney W. Grimes /* 1077df8bae1dSRodney W. Grimes * Copy data from an mbuf chain into a buffer. This code is derived 1078df8bae1dSRodney W. Grimes * from m_copydata in sys/uipc_mbuf.c. 1079df8bae1dSRodney W. Grimes */ 1080df8bae1dSRodney W. Grimes static void 1081df8bae1dSRodney W. Grimes bpf_mcopy(src_arg, dst_arg, len) 1082df8bae1dSRodney W. Grimes const void *src_arg; 1083df8bae1dSRodney W. Grimes void *dst_arg; 10848bcbc7dfSAlexander Langer register size_t len; 1085df8bae1dSRodney W. Grimes { 1086df8bae1dSRodney W. Grimes register const struct mbuf *m; 1087df8bae1dSRodney W. Grimes register u_int count; 1088df8bae1dSRodney W. Grimes u_char *dst; 1089df8bae1dSRodney W. Grimes 1090df8bae1dSRodney W. Grimes m = src_arg; 1091df8bae1dSRodney W. Grimes dst = dst_arg; 1092df8bae1dSRodney W. Grimes while (len > 0) { 1093df8bae1dSRodney W. Grimes if (m == 0) 1094df8bae1dSRodney W. Grimes panic("bpf_mcopy"); 1095df8bae1dSRodney W. Grimes count = min(m->m_len, len); 10960453d3cbSBruce Evans bcopy(mtod(m, void *), dst, count); 1097df8bae1dSRodney W. Grimes m = m->m_next; 1098df8bae1dSRodney W. Grimes dst += count; 1099df8bae1dSRodney W. Grimes len -= count; 1100df8bae1dSRodney W. Grimes } 1101df8bae1dSRodney W. Grimes } 1102df8bae1dSRodney W. Grimes 1103df8bae1dSRodney W. Grimes /* 1104df8bae1dSRodney W. Grimes * Incoming linkage from device drivers, when packet is in an mbuf chain. 1105df8bae1dSRodney W. Grimes */ 1106df8bae1dSRodney W. Grimes void 11079b44ff22SGarrett Wollman bpf_mtap(ifp, m) 11089b44ff22SGarrett Wollman struct ifnet *ifp; 1109df8bae1dSRodney W. Grimes struct mbuf *m; 1110df8bae1dSRodney W. Grimes { 11119b44ff22SGarrett Wollman struct bpf_if *bp = ifp->if_bpf; 1112df8bae1dSRodney W. Grimes struct bpf_d *d; 1113df8bae1dSRodney W. Grimes u_int pktlen, slen; 1114df8bae1dSRodney W. Grimes struct mbuf *m0; 1115df8bae1dSRodney W. Grimes 1116df8bae1dSRodney W. Grimes pktlen = 0; 1117df8bae1dSRodney W. Grimes for (m0 = m; m0 != 0; m0 = m0->m_next) 1118df8bae1dSRodney W. Grimes pktlen += m0->m_len; 1119df8bae1dSRodney W. Grimes 1120df8bae1dSRodney W. Grimes for (d = bp->bif_dlist; d != 0; d = d->bd_next) { 1121df8bae1dSRodney W. Grimes ++d->bd_rcount; 1122df8bae1dSRodney W. Grimes slen = bpf_filter(d->bd_filter, (u_char *)m, pktlen, 0); 1123df8bae1dSRodney W. Grimes if (slen != 0) 1124df8bae1dSRodney W. Grimes catchpacket(d, (u_char *)m, pktlen, slen, bpf_mcopy); 1125df8bae1dSRodney W. Grimes } 1126df8bae1dSRodney W. Grimes } 1127df8bae1dSRodney W. Grimes 1128df8bae1dSRodney W. Grimes /* 1129df8bae1dSRodney W. Grimes * Move the packet data from interface memory (pkt) into the 1130df8bae1dSRodney W. Grimes * store buffer. Return 1 if it's time to wakeup a listener (buffer full), 1131df8bae1dSRodney W. Grimes * otherwise 0. "copy" is the routine called to do the actual data 1132df8bae1dSRodney W. Grimes * transfer. bcopy is passed in to copy contiguous chunks, while 1133df8bae1dSRodney W. Grimes * bpf_mcopy is passed in to copy mbuf chains. In the latter case, 1134df8bae1dSRodney W. Grimes * pkt is really an mbuf. 1135df8bae1dSRodney W. Grimes */ 1136df8bae1dSRodney W. Grimes static void 1137df8bae1dSRodney W. Grimes catchpacket(d, pkt, pktlen, snaplen, cpfn) 1138df8bae1dSRodney W. Grimes register struct bpf_d *d; 1139df8bae1dSRodney W. Grimes register u_char *pkt; 1140df8bae1dSRodney W. Grimes register u_int pktlen, snaplen; 11418bcbc7dfSAlexander Langer register void (*cpfn) __P((const void *, void *, size_t)); 1142df8bae1dSRodney W. Grimes { 1143df8bae1dSRodney W. Grimes register struct bpf_hdr *hp; 1144df8bae1dSRodney W. Grimes register int totlen, curlen; 1145df8bae1dSRodney W. Grimes register int hdrlen = d->bd_bif->bif_hdrlen; 1146df8bae1dSRodney W. Grimes /* 1147df8bae1dSRodney W. Grimes * Figure out how many bytes to move. If the packet is 1148df8bae1dSRodney W. Grimes * greater or equal to the snapshot length, transfer that 1149df8bae1dSRodney W. Grimes * much. Otherwise, transfer the whole packet (unless 1150df8bae1dSRodney W. Grimes * we hit the buffer size limit). 1151df8bae1dSRodney W. Grimes */ 1152df8bae1dSRodney W. Grimes totlen = hdrlen + min(snaplen, pktlen); 1153df8bae1dSRodney W. Grimes if (totlen > d->bd_bufsize) 1154df8bae1dSRodney W. Grimes totlen = d->bd_bufsize; 1155df8bae1dSRodney W. Grimes 1156df8bae1dSRodney W. Grimes /* 1157df8bae1dSRodney W. Grimes * Round up the end of the previous packet to the next longword. 1158df8bae1dSRodney W. Grimes */ 1159df8bae1dSRodney W. Grimes curlen = BPF_WORDALIGN(d->bd_slen); 1160df8bae1dSRodney W. Grimes if (curlen + totlen > d->bd_bufsize) { 1161df8bae1dSRodney W. Grimes /* 1162df8bae1dSRodney W. Grimes * This packet will overflow the storage buffer. 1163df8bae1dSRodney W. Grimes * Rotate the buffers if we can, then wakeup any 1164df8bae1dSRodney W. Grimes * pending reads. 1165df8bae1dSRodney W. Grimes */ 1166df8bae1dSRodney W. Grimes if (d->bd_fbuf == 0) { 1167df8bae1dSRodney W. Grimes /* 1168df8bae1dSRodney W. Grimes * We haven't completed the previous read yet, 1169df8bae1dSRodney W. Grimes * so drop the packet. 1170df8bae1dSRodney W. Grimes */ 1171df8bae1dSRodney W. Grimes ++d->bd_dcount; 1172df8bae1dSRodney W. Grimes return; 1173df8bae1dSRodney W. Grimes } 1174df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 1175df8bae1dSRodney W. Grimes bpf_wakeup(d); 1176df8bae1dSRodney W. Grimes curlen = 0; 1177df8bae1dSRodney W. Grimes } 1178df8bae1dSRodney W. Grimes else if (d->bd_immediate) 1179df8bae1dSRodney W. Grimes /* 1180df8bae1dSRodney W. Grimes * Immediate mode is set. A packet arrived so any 1181df8bae1dSRodney W. Grimes * reads should be woken up. 1182df8bae1dSRodney W. Grimes */ 1183df8bae1dSRodney W. Grimes bpf_wakeup(d); 1184df8bae1dSRodney W. Grimes 1185df8bae1dSRodney W. Grimes /* 1186df8bae1dSRodney W. Grimes * Append the bpf header. 1187df8bae1dSRodney W. Grimes */ 1188df8bae1dSRodney W. Grimes hp = (struct bpf_hdr *)(d->bd_sbuf + curlen); 1189df8bae1dSRodney W. Grimes #if BSD >= 199103 1190df8bae1dSRodney W. Grimes microtime(&hp->bh_tstamp); 1191df8bae1dSRodney W. Grimes #elif defined(sun) 1192df8bae1dSRodney W. Grimes uniqtime(&hp->bh_tstamp); 1193df8bae1dSRodney W. Grimes #else 1194df8bae1dSRodney W. Grimes hp->bh_tstamp = time; 1195df8bae1dSRodney W. Grimes #endif 1196df8bae1dSRodney W. Grimes hp->bh_datalen = pktlen; 1197df8bae1dSRodney W. Grimes hp->bh_hdrlen = hdrlen; 1198df8bae1dSRodney W. Grimes /* 1199df8bae1dSRodney W. Grimes * Copy the packet data into the store buffer and update its length. 1200df8bae1dSRodney W. Grimes */ 1201df8bae1dSRodney W. Grimes (*cpfn)(pkt, (u_char *)hp + hdrlen, (hp->bh_caplen = totlen - hdrlen)); 1202df8bae1dSRodney W. Grimes d->bd_slen = curlen + totlen; 1203df8bae1dSRodney W. Grimes } 1204df8bae1dSRodney W. Grimes 1205df8bae1dSRodney W. Grimes /* 1206df8bae1dSRodney W. Grimes * Initialize all nonzero fields of a descriptor. 1207df8bae1dSRodney W. Grimes */ 1208df8bae1dSRodney W. Grimes static int 1209df8bae1dSRodney W. Grimes bpf_allocbufs(d) 1210df8bae1dSRodney W. Grimes register struct bpf_d *d; 1211df8bae1dSRodney W. Grimes { 1212df8bae1dSRodney W. Grimes d->bd_fbuf = (caddr_t)malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK); 1213df8bae1dSRodney W. Grimes if (d->bd_fbuf == 0) 1214df8bae1dSRodney W. Grimes return (ENOBUFS); 1215df8bae1dSRodney W. Grimes 1216df8bae1dSRodney W. Grimes d->bd_sbuf = (caddr_t)malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK); 1217df8bae1dSRodney W. Grimes if (d->bd_sbuf == 0) { 1218df8bae1dSRodney W. Grimes free(d->bd_fbuf, M_DEVBUF); 1219df8bae1dSRodney W. Grimes return (ENOBUFS); 1220df8bae1dSRodney W. Grimes } 1221df8bae1dSRodney W. Grimes d->bd_slen = 0; 1222df8bae1dSRodney W. Grimes d->bd_hlen = 0; 1223df8bae1dSRodney W. Grimes return (0); 1224df8bae1dSRodney W. Grimes } 1225df8bae1dSRodney W. Grimes 1226df8bae1dSRodney W. Grimes /* 1227df8bae1dSRodney W. Grimes * Free buffers currently in use by a descriptor. 1228df8bae1dSRodney W. Grimes * Called on close. 1229df8bae1dSRodney W. Grimes */ 1230df8bae1dSRodney W. Grimes static void 1231df8bae1dSRodney W. Grimes bpf_freed(d) 1232df8bae1dSRodney W. Grimes register struct bpf_d *d; 1233df8bae1dSRodney W. Grimes { 1234df8bae1dSRodney W. Grimes /* 1235df8bae1dSRodney W. Grimes * We don't need to lock out interrupts since this descriptor has 1236df8bae1dSRodney W. Grimes * been detached from its interface and it yet hasn't been marked 1237df8bae1dSRodney W. Grimes * free. 1238df8bae1dSRodney W. Grimes */ 1239df8bae1dSRodney W. Grimes if (d->bd_sbuf != 0) { 1240df8bae1dSRodney W. Grimes free(d->bd_sbuf, M_DEVBUF); 1241df8bae1dSRodney W. Grimes if (d->bd_hbuf != 0) 1242df8bae1dSRodney W. Grimes free(d->bd_hbuf, M_DEVBUF); 1243df8bae1dSRodney W. Grimes if (d->bd_fbuf != 0) 1244df8bae1dSRodney W. Grimes free(d->bd_fbuf, M_DEVBUF); 1245df8bae1dSRodney W. Grimes } 1246df8bae1dSRodney W. Grimes if (d->bd_filter) 1247df8bae1dSRodney W. Grimes free((caddr_t)d->bd_filter, M_DEVBUF); 1248df8bae1dSRodney W. Grimes 1249df8bae1dSRodney W. Grimes D_MARKFREE(d); 1250df8bae1dSRodney W. Grimes } 1251df8bae1dSRodney W. Grimes 1252df8bae1dSRodney W. Grimes /* 1253df8bae1dSRodney W. Grimes * Attach an interface to bpf. driverp is a pointer to a (struct bpf_if *) 1254df8bae1dSRodney W. Grimes * in the driver's softc; dlt is the link layer type; hdrlen is the fixed 1255df8bae1dSRodney W. Grimes * size of the link header (variable length headers not yet supported). 1256df8bae1dSRodney W. Grimes */ 1257df8bae1dSRodney W. Grimes void 12589b44ff22SGarrett Wollman bpfattach(ifp, dlt, hdrlen) 1259df8bae1dSRodney W. Grimes struct ifnet *ifp; 1260df8bae1dSRodney W. Grimes u_int dlt, hdrlen; 1261df8bae1dSRodney W. Grimes { 1262df8bae1dSRodney W. Grimes struct bpf_if *bp; 1263df8bae1dSRodney W. Grimes int i; 1264df8bae1dSRodney W. Grimes bp = (struct bpf_if *)malloc(sizeof(*bp), M_DEVBUF, M_DONTWAIT); 1265df8bae1dSRodney W. Grimes if (bp == 0) 1266df8bae1dSRodney W. Grimes panic("bpfattach"); 1267df8bae1dSRodney W. Grimes 1268df8bae1dSRodney W. Grimes bp->bif_dlist = 0; 1269df8bae1dSRodney W. Grimes bp->bif_ifp = ifp; 1270df8bae1dSRodney W. Grimes bp->bif_dlt = dlt; 1271df8bae1dSRodney W. Grimes 1272df8bae1dSRodney W. Grimes bp->bif_next = bpf_iflist; 1273df8bae1dSRodney W. Grimes bpf_iflist = bp; 1274df8bae1dSRodney W. Grimes 12759b44ff22SGarrett Wollman bp->bif_ifp->if_bpf = 0; 1276df8bae1dSRodney W. Grimes 1277df8bae1dSRodney W. Grimes /* 1278df8bae1dSRodney W. Grimes * Compute the length of the bpf header. This is not necessarily 1279df8bae1dSRodney W. Grimes * equal to SIZEOF_BPF_HDR because we want to insert spacing such 1280df8bae1dSRodney W. Grimes * that the network layer header begins on a longword boundary (for 1281df8bae1dSRodney W. Grimes * performance reasons and to alleviate alignment restrictions). 1282df8bae1dSRodney W. Grimes */ 1283df8bae1dSRodney W. Grimes bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen; 1284df8bae1dSRodney W. Grimes 1285df8bae1dSRodney W. Grimes /* 1286df8bae1dSRodney W. Grimes * Mark all the descriptors free if this hasn't been done. 1287df8bae1dSRodney W. Grimes */ 1288ed0af9bcSJulian Elischer if (!bpf_dtab_init) { 1289df8bae1dSRodney W. Grimes for (i = 0; i < NBPFILTER; ++i) 1290df8bae1dSRodney W. Grimes D_MARKFREE(&bpf_dtab[i]); 1291ed0af9bcSJulian Elischer bpf_dtab_init = 1; 1292ed0af9bcSJulian Elischer } 1293df8bae1dSRodney W. Grimes 12942eeab939SGarrett Wollman if (bootverbose) 1295df8bae1dSRodney W. Grimes printf("bpf: %s%d attached\n", ifp->if_name, ifp->if_unit); 1296df8bae1dSRodney W. Grimes } 129753ac6efbSJulian Elischer 1298ccbc58d3SMarc G. Fournier #ifdef DEVFS 129987f6c662SJulian Elischer static void *bpf_devfs_token[NBPFILTER]; 1300ccbc58d3SMarc G. Fournier #endif 130153ac6efbSJulian Elischer 1302e31abedeSBruce Evans static int bpf_devsw_installed; 130353ac6efbSJulian Elischer 1304514ede09SBruce Evans static void bpf_drvinit __P((void *unused)); 1305514ede09SBruce Evans static void 1306514ede09SBruce Evans bpf_drvinit(unused) 1307514ede09SBruce Evans void *unused; 130853ac6efbSJulian Elischer { 130953ac6efbSJulian Elischer dev_t dev; 1310ccbc58d3SMarc G. Fournier #ifdef DEVFS 131187f6c662SJulian Elischer int i; 1312ccbc58d3SMarc G. Fournier #endif 131353ac6efbSJulian Elischer 131453ac6efbSJulian Elischer if( ! bpf_devsw_installed ) { 131553ac6efbSJulian Elischer dev = makedev(CDEV_MAJOR, 0); 131653ac6efbSJulian Elischer cdevsw_add(&dev,&bpf_cdevsw, NULL); 131753ac6efbSJulian Elischer bpf_devsw_installed = 1; 131853ac6efbSJulian Elischer #ifdef DEVFS 1319ccbc58d3SMarc G. Fournier 132087f6c662SJulian Elischer for ( i = 0 ; i < NBPFILTER ; i++ ) { 132187f6c662SJulian Elischer bpf_devfs_token[i] = 1322ccbc58d3SMarc G. Fournier devfs_add_devswf(&bpf_cdevsw, i, DV_CHR, 0, 0, 1323ccbc58d3SMarc G. Fournier 0600, "bpf%d", i); 132453ac6efbSJulian Elischer } 132553ac6efbSJulian Elischer #endif 132653ac6efbSJulian Elischer } 13277198bf47SJulian Elischer } 132853ac6efbSJulian Elischer 132953ac6efbSJulian Elischer SYSINIT(bpfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,bpf_drvinit,NULL) 133053ac6efbSJulian Elischer 1331f8dc4716SMike Smith #else /* !BPFILTER */ 1332f8dc4716SMike Smith /* 1333f8dc4716SMike Smith * NOP stubs to allow bpf-using drivers to load and function. 1334f8dc4716SMike Smith * 1335f8dc4716SMike Smith * A 'better' implementation would allow the core bpf functionality 1336f8dc4716SMike Smith * to be loaded at runtime. 1337f8dc4716SMike Smith */ 1338f8dc4716SMike Smith 1339f8dc4716SMike Smith void 1340f8dc4716SMike Smith bpf_tap(ifp, pkt, pktlen) 1341f8dc4716SMike Smith struct ifnet *ifp; 1342f8dc4716SMike Smith register u_char *pkt; 1343f8dc4716SMike Smith register u_int pktlen; 1344f8dc4716SMike Smith { 1345f8dc4716SMike Smith } 1346f8dc4716SMike Smith 1347f8dc4716SMike Smith void 1348f8dc4716SMike Smith bpf_mtap(ifp, m) 1349f8dc4716SMike Smith struct ifnet *ifp; 1350f8dc4716SMike Smith struct mbuf *m; 1351f8dc4716SMike Smith { 1352f8dc4716SMike Smith } 1353f8dc4716SMike Smith 1354f8dc4716SMike Smith void 1355f8dc4716SMike Smith bpfattach(ifp, dlt, hdrlen) 1356f8dc4716SMike Smith struct ifnet *ifp; 1357f8dc4716SMike Smith u_int dlt, hdrlen; 1358f8dc4716SMike Smith { 1359f8dc4716SMike Smith } 1360f8dc4716SMike Smith 1361f8dc4716SMike Smith u_int 1362f8dc4716SMike Smith bpf_filter(pc, p, wirelen, buflen) 1363f8dc4716SMike Smith register struct bpf_insn *pc; 1364f8dc4716SMike Smith register u_char *p; 1365f8dc4716SMike Smith u_int wirelen; 1366f8dc4716SMike Smith register u_int buflen; 1367f8dc4716SMike Smith { 1368f8dc4716SMike Smith return -1; /* "no filter" behaviour */ 1369f8dc4716SMike Smith } 1370f8dc4716SMike Smith 1371df8bae1dSRodney W. Grimes #endif 1372