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 * 384f252c4dSRuslan Ermilov * @(#)bpf.c 8.4 (Berkeley) 1/9/95 39df8bae1dSRodney W. Grimes * 40c3aac50fSPeter Wemm * $FreeBSD$ 41df8bae1dSRodney W. Grimes */ 42df8bae1dSRodney W. Grimes 435bb5f2c9SPeter Wemm #include "opt_bpf.h" 445bb5f2c9SPeter Wemm #include "opt_netgraph.h" 45df8bae1dSRodney W. Grimes 46df8bae1dSRodney W. Grimes #include <sys/param.h> 47df8bae1dSRodney W. Grimes #include <sys/systm.h> 48ce7609a4SBruce Evans #include <sys/conf.h> 494d1d4912SBruce Evans #include <sys/malloc.h> 50df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 51df8bae1dSRodney W. Grimes #include <sys/time.h> 52df8bae1dSRodney W. Grimes #include <sys/proc.h> 530310c19fSBruce Evans #include <sys/signalvar.h> 54528f627fSBruce Evans #include <sys/filio.h> 55528f627fSBruce Evans #include <sys/sockio.h> 56528f627fSBruce Evans #include <sys/ttycom.h> 57831d27a9SDon Lewis #include <sys/filedesc.h> 58df8bae1dSRodney W. Grimes 59243ac7d8SPeter Wemm #include <sys/poll.h> 60df8bae1dSRodney W. Grimes 61df8bae1dSRodney W. Grimes #include <sys/socket.h> 62fba9235dSBruce Evans #include <sys/vnode.h> 63df8bae1dSRodney W. Grimes 64fba9235dSBruce Evans #include <net/if.h> 65df8bae1dSRodney W. Grimes #include <net/bpf.h> 66df8bae1dSRodney W. Grimes #include <net/bpfdesc.h> 67df8bae1dSRodney W. Grimes 68df8bae1dSRodney W. Grimes #include <netinet/in.h> 69df8bae1dSRodney W. Grimes #include <netinet/if_ether.h> 70df8bae1dSRodney W. Grimes #include <sys/kernel.h> 71f708ef1bSPoul-Henning Kamp #include <sys/sysctl.h> 727b778b5eSEivind Eklund 73959b7375SPoul-Henning Kamp static MALLOC_DEFINE(M_BPF, "BPF", "BPF data"); 7487f6c662SJulian Elischer 755bb5f2c9SPeter Wemm #if defined(DEV_BPF) || defined(NETGRAPH_BPF) 7653ac6efbSJulian Elischer 77df8bae1dSRodney W. Grimes #define PRINET 26 /* interruptible */ 78df8bae1dSRodney W. Grimes 79df8bae1dSRodney W. Grimes /* 80df8bae1dSRodney W. Grimes * The default read buffer size is patchable. 81df8bae1dSRodney W. Grimes */ 82e7bb21b3SJonathan Lemon static int bpf_bufsize = 4096; 83f708ef1bSPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, bpf_bufsize, CTLFLAG_RW, 84f708ef1bSPoul-Henning Kamp &bpf_bufsize, 0, ""); 85eba2a1aeSPoul-Henning Kamp static int bpf_maxbufsize = BPF_MAXBUFSIZE; 86eba2a1aeSPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, bpf_maxbufsize, CTLFLAG_RW, 87eba2a1aeSPoul-Henning Kamp &bpf_maxbufsize, 0, ""); 88df8bae1dSRodney W. Grimes 89df8bae1dSRodney W. Grimes /* 90df8bae1dSRodney W. Grimes * bpf_iflist is the list of interfaces; each corresponds to an ifnet 91df8bae1dSRodney W. Grimes */ 92f708ef1bSPoul-Henning Kamp static struct bpf_if *bpf_iflist; 93e7bb21b3SJonathan Lemon static struct mtx bpf_mtx; /* bpf global lock */ 94df8bae1dSRodney W. Grimes 95df8bae1dSRodney W. Grimes static int bpf_allocbufs __P((struct bpf_d *)); 96ce7609a4SBruce Evans static void bpf_attachd __P((struct bpf_d *d, struct bpf_if *bp)); 97ce7609a4SBruce Evans static void bpf_detachd __P((struct bpf_d *d)); 98df8bae1dSRodney W. Grimes static void bpf_freed __P((struct bpf_d *)); 998bcbc7dfSAlexander Langer static void bpf_mcopy __P((const void *, void *, size_t)); 100df8bae1dSRodney W. Grimes static int bpf_movein __P((struct uio *, int, 101df8bae1dSRodney W. Grimes struct mbuf **, struct sockaddr *, int *)); 102df8bae1dSRodney W. Grimes static int bpf_setif __P((struct bpf_d *, struct ifreq *)); 10381bda851SJohn Polstra static void bpf_timed_out __P((void *)); 104e7bb21b3SJonathan Lemon static __inline void 105df8bae1dSRodney W. Grimes bpf_wakeup __P((struct bpf_d *)); 106df8bae1dSRodney W. Grimes static void catchpacket __P((struct bpf_d *, u_char *, u_int, 1078bcbc7dfSAlexander Langer u_int, void (*)(const void *, void *, size_t))); 108df8bae1dSRodney W. Grimes static void reset_d __P((struct bpf_d *)); 109f708ef1bSPoul-Henning Kamp static int bpf_setf __P((struct bpf_d *, struct bpf_program *)); 110df8bae1dSRodney W. Grimes 11187f6c662SJulian Elischer static d_open_t bpfopen; 11287f6c662SJulian Elischer static d_close_t bpfclose; 11387f6c662SJulian Elischer static d_read_t bpfread; 11487f6c662SJulian Elischer static d_write_t bpfwrite; 11587f6c662SJulian Elischer static d_ioctl_t bpfioctl; 116243ac7d8SPeter Wemm static d_poll_t bpfpoll; 11787f6c662SJulian Elischer 11887f6c662SJulian Elischer #define CDEV_MAJOR 23 1194e2f199eSPoul-Henning Kamp static struct cdevsw bpf_cdevsw = { 1204e2f199eSPoul-Henning Kamp /* open */ bpfopen, 1214e2f199eSPoul-Henning Kamp /* close */ bpfclose, 1224e2f199eSPoul-Henning Kamp /* read */ bpfread, 1234e2f199eSPoul-Henning Kamp /* write */ bpfwrite, 1244e2f199eSPoul-Henning Kamp /* ioctl */ bpfioctl, 1254e2f199eSPoul-Henning Kamp /* poll */ bpfpoll, 1264e2f199eSPoul-Henning Kamp /* mmap */ nommap, 1274e2f199eSPoul-Henning Kamp /* strategy */ nostrategy, 1284e2f199eSPoul-Henning Kamp /* name */ "bpf", 1294e2f199eSPoul-Henning Kamp /* maj */ CDEV_MAJOR, 1304e2f199eSPoul-Henning Kamp /* dump */ nodump, 1314e2f199eSPoul-Henning Kamp /* psize */ nopsize, 1324e2f199eSPoul-Henning Kamp /* flags */ 0, 1334e2f199eSPoul-Henning Kamp }; 13487f6c662SJulian Elischer 13587f6c662SJulian Elischer 136df8bae1dSRodney W. Grimes static int 137df8bae1dSRodney W. Grimes bpf_movein(uio, linktype, mp, sockp, datlen) 138df8bae1dSRodney W. Grimes register struct uio *uio; 139df8bae1dSRodney W. Grimes int linktype, *datlen; 140df8bae1dSRodney W. Grimes register struct mbuf **mp; 141df8bae1dSRodney W. Grimes register struct sockaddr *sockp; 142df8bae1dSRodney W. Grimes { 143df8bae1dSRodney W. Grimes struct mbuf *m; 144df8bae1dSRodney W. Grimes int error; 145df8bae1dSRodney W. Grimes int len; 146df8bae1dSRodney W. Grimes int hlen; 147df8bae1dSRodney W. Grimes 148df8bae1dSRodney W. Grimes /* 149df8bae1dSRodney W. Grimes * Build a sockaddr based on the data link layer type. 150df8bae1dSRodney W. Grimes * We do this at this level because the ethernet header 151df8bae1dSRodney W. Grimes * is copied directly into the data field of the sockaddr. 152df8bae1dSRodney W. Grimes * In the case of SLIP, there is no header and the packet 153df8bae1dSRodney W. Grimes * is forwarded as is. 154df8bae1dSRodney W. Grimes * Also, we are careful to leave room at the front of the mbuf 155df8bae1dSRodney W. Grimes * for the link level header. 156df8bae1dSRodney W. Grimes */ 157df8bae1dSRodney W. Grimes switch (linktype) { 158df8bae1dSRodney W. Grimes 159df8bae1dSRodney W. Grimes case DLT_SLIP: 160df8bae1dSRodney W. Grimes sockp->sa_family = AF_INET; 161df8bae1dSRodney W. Grimes hlen = 0; 162df8bae1dSRodney W. Grimes break; 163df8bae1dSRodney W. Grimes 164df8bae1dSRodney W. Grimes case DLT_EN10MB: 165df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 166df8bae1dSRodney W. Grimes /* XXX Would MAXLINKHDR be better? */ 167df8bae1dSRodney W. Grimes hlen = sizeof(struct ether_header); 168df8bae1dSRodney W. Grimes break; 169df8bae1dSRodney W. Grimes 170df8bae1dSRodney W. Grimes case DLT_FDDI: 171d41f24e7SDavid Greenman sockp->sa_family = AF_IMPLINK; 172d41f24e7SDavid Greenman hlen = 0; 173df8bae1dSRodney W. Grimes break; 174df8bae1dSRodney W. Grimes 17522f05c43SAndrey A. Chernov case DLT_RAW: 176df8bae1dSRodney W. Grimes case DLT_NULL: 177df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 178df8bae1dSRodney W. Grimes hlen = 0; 179df8bae1dSRodney W. Grimes break; 180df8bae1dSRodney W. Grimes 1814f53e3ccSKenjiro Cho case DLT_ATM_RFC1483: 1824f53e3ccSKenjiro Cho /* 1834f53e3ccSKenjiro Cho * en atm driver requires 4-byte atm pseudo header. 1844f53e3ccSKenjiro Cho * though it isn't standard, vpi:vci needs to be 1854f53e3ccSKenjiro Cho * specified anyway. 1864f53e3ccSKenjiro Cho */ 1874f53e3ccSKenjiro Cho sockp->sa_family = AF_UNSPEC; 1884f53e3ccSKenjiro Cho hlen = 12; /* XXX 4(ATM_PH) + 3(LLC) + 5(SNAP) */ 1894f53e3ccSKenjiro Cho break; 1904f53e3ccSKenjiro Cho 19130fa52a6SBrian Somers case DLT_PPP: 19230fa52a6SBrian Somers sockp->sa_family = AF_UNSPEC; 19330fa52a6SBrian Somers hlen = 4; /* This should match PPP_HDRLEN */ 19430fa52a6SBrian Somers break; 19530fa52a6SBrian Somers 196df8bae1dSRodney W. Grimes default: 197df8bae1dSRodney W. Grimes return (EIO); 198df8bae1dSRodney W. Grimes } 199df8bae1dSRodney W. Grimes 200df8bae1dSRodney W. Grimes len = uio->uio_resid; 201df8bae1dSRodney W. Grimes *datlen = len - hlen; 202df8bae1dSRodney W. Grimes if ((unsigned)len > MCLBYTES) 203df8bae1dSRodney W. Grimes return (EIO); 204df8bae1dSRodney W. Grimes 2052a0c503eSBosko Milekic MGETHDR(m, M_TRYWAIT, MT_DATA); 206df8bae1dSRodney W. Grimes if (m == 0) 207df8bae1dSRodney W. Grimes return (ENOBUFS); 208963e4c2aSGarrett Wollman if (len > MHLEN) { 2092a0c503eSBosko Milekic MCLGET(m, M_TRYWAIT); 210df8bae1dSRodney W. Grimes if ((m->m_flags & M_EXT) == 0) { 211df8bae1dSRodney W. Grimes error = ENOBUFS; 212df8bae1dSRodney W. Grimes goto bad; 213df8bae1dSRodney W. Grimes } 214df8bae1dSRodney W. Grimes } 215963e4c2aSGarrett Wollman m->m_pkthdr.len = m->m_len = len; 216963e4c2aSGarrett Wollman m->m_pkthdr.rcvif = NULL; 217df8bae1dSRodney W. Grimes *mp = m; 218df8bae1dSRodney W. Grimes /* 219df8bae1dSRodney W. Grimes * Make room for link header. 220df8bae1dSRodney W. Grimes */ 221df8bae1dSRodney W. Grimes if (hlen != 0) { 2224f079e2fSGarrett Wollman m->m_pkthdr.len -= hlen; 223df8bae1dSRodney W. Grimes m->m_len -= hlen; 224df8bae1dSRodney W. Grimes #if BSD >= 199103 225df8bae1dSRodney W. Grimes m->m_data += hlen; /* XXX */ 226df8bae1dSRodney W. Grimes #else 227df8bae1dSRodney W. Grimes m->m_off += hlen; 228df8bae1dSRodney W. Grimes #endif 229e7bb21b3SJonathan Lemon error = uiomove((caddr_t)sockp->sa_data, hlen, uio); 230df8bae1dSRodney W. Grimes if (error) 231df8bae1dSRodney W. Grimes goto bad; 232df8bae1dSRodney W. Grimes } 233e7bb21b3SJonathan Lemon error = uiomove(mtod(m, caddr_t), len - hlen, uio); 234df8bae1dSRodney W. Grimes if (!error) 235df8bae1dSRodney W. Grimes return (0); 236df8bae1dSRodney W. Grimes bad: 237df8bae1dSRodney W. Grimes m_freem(m); 238df8bae1dSRodney W. Grimes return (error); 239df8bae1dSRodney W. Grimes } 240df8bae1dSRodney W. Grimes 241df8bae1dSRodney W. Grimes /* 242df8bae1dSRodney W. Grimes * Attach file to the bpf interface, i.e. make d listen on bp. 243df8bae1dSRodney W. Grimes */ 244df8bae1dSRodney W. Grimes static void 245df8bae1dSRodney W. Grimes bpf_attachd(d, bp) 246df8bae1dSRodney W. Grimes struct bpf_d *d; 247df8bae1dSRodney W. Grimes struct bpf_if *bp; 248df8bae1dSRodney W. Grimes { 249df8bae1dSRodney W. Grimes /* 250df8bae1dSRodney W. Grimes * Point d at bp, and add d to the interface's list of listeners. 251df8bae1dSRodney W. Grimes * Finally, point the driver's bpf cookie at the interface so 252df8bae1dSRodney W. Grimes * it will divert packets to bpf. 253df8bae1dSRodney W. Grimes */ 254e7bb21b3SJonathan Lemon BPFIF_LOCK(bp); 255df8bae1dSRodney W. Grimes d->bd_bif = bp; 256df8bae1dSRodney W. Grimes d->bd_next = bp->bif_dlist; 257df8bae1dSRodney W. Grimes bp->bif_dlist = d; 258df8bae1dSRodney W. Grimes 2599b44ff22SGarrett Wollman bp->bif_ifp->if_bpf = bp; 260e7bb21b3SJonathan Lemon BPFIF_UNLOCK(bp); 261df8bae1dSRodney W. Grimes } 262df8bae1dSRodney W. Grimes 263df8bae1dSRodney W. Grimes /* 264df8bae1dSRodney W. Grimes * Detach a file from its interface. 265df8bae1dSRodney W. Grimes */ 266df8bae1dSRodney W. Grimes static void 267df8bae1dSRodney W. Grimes bpf_detachd(d) 268df8bae1dSRodney W. Grimes struct bpf_d *d; 269df8bae1dSRodney W. Grimes { 2706e891d64SPoul-Henning Kamp int error; 271df8bae1dSRodney W. Grimes struct bpf_d **p; 272df8bae1dSRodney W. Grimes struct bpf_if *bp; 273df8bae1dSRodney W. Grimes 274df8bae1dSRodney W. Grimes bp = d->bd_bif; 275df8bae1dSRodney W. Grimes /* 276df8bae1dSRodney W. Grimes * Check if this descriptor had requested promiscuous mode. 277df8bae1dSRodney W. Grimes * If so, turn it off. 278df8bae1dSRodney W. Grimes */ 279df8bae1dSRodney W. Grimes if (d->bd_promisc) { 280df8bae1dSRodney W. Grimes d->bd_promisc = 0; 2816e891d64SPoul-Henning Kamp error = ifpromisc(bp->bif_ifp, 0); 2826e891d64SPoul-Henning Kamp if (error != 0 && error != ENXIO) { 283df8bae1dSRodney W. Grimes /* 2846e891d64SPoul-Henning Kamp * ENXIO can happen if a pccard is unplugged 285df8bae1dSRodney W. Grimes * Something is really wrong if we were able to put 286df8bae1dSRodney W. Grimes * the driver into promiscuous mode, but can't 287df8bae1dSRodney W. Grimes * take it out. 288df8bae1dSRodney W. Grimes */ 2896e891d64SPoul-Henning Kamp printf("%s%d: ifpromisc failed %d\n", 2906e891d64SPoul-Henning Kamp bp->bif_ifp->if_name, bp->bif_ifp->if_unit, error); 2916e891d64SPoul-Henning Kamp } 292df8bae1dSRodney W. Grimes } 293df8bae1dSRodney W. Grimes /* Remove d from the interface's descriptor list. */ 294e7bb21b3SJonathan Lemon BPFIF_LOCK(bp); 295df8bae1dSRodney W. Grimes p = &bp->bif_dlist; 296df8bae1dSRodney W. Grimes while (*p != d) { 297df8bae1dSRodney W. Grimes p = &(*p)->bd_next; 298df8bae1dSRodney W. Grimes if (*p == 0) 299df8bae1dSRodney W. Grimes panic("bpf_detachd: descriptor not in list"); 300df8bae1dSRodney W. Grimes } 301df8bae1dSRodney W. Grimes *p = (*p)->bd_next; 302df8bae1dSRodney W. Grimes if (bp->bif_dlist == 0) 303df8bae1dSRodney W. Grimes /* 304df8bae1dSRodney W. Grimes * Let the driver know that there are no more listeners. 305df8bae1dSRodney W. Grimes */ 3069b44ff22SGarrett Wollman d->bd_bif->bif_ifp->if_bpf = 0; 307e7bb21b3SJonathan Lemon BPFIF_UNLOCK(bp); 308df8bae1dSRodney W. Grimes d->bd_bif = 0; 309df8bae1dSRodney W. Grimes } 310df8bae1dSRodney W. Grimes 311df8bae1dSRodney W. Grimes /* 312df8bae1dSRodney W. Grimes * Open ethernet device. Returns ENXIO for illegal minor device number, 313df8bae1dSRodney W. Grimes * EBUSY if file is open by another process. 314df8bae1dSRodney W. Grimes */ 315df8bae1dSRodney W. Grimes /* ARGSUSED */ 31687f6c662SJulian Elischer static int 317b40ce416SJulian Elischer bpfopen(dev, flags, fmt, td) 318df8bae1dSRodney W. Grimes dev_t dev; 31960039670SBruce Evans int flags; 32060039670SBruce Evans int fmt; 321b40ce416SJulian Elischer struct thread *td; 322df8bae1dSRodney W. Grimes { 323e7bb21b3SJonathan Lemon struct bpf_d *d; 324df8bae1dSRodney W. Grimes 325e7bb21b3SJonathan Lemon mtx_lock(&bpf_mtx); 326bd3a5320SPoul-Henning Kamp d = dev->si_drv1; 327df8bae1dSRodney W. Grimes /* 328df8bae1dSRodney W. Grimes * Each minor can be opened by only one process. If the requested 329df8bae1dSRodney W. Grimes * minor is in use, return EBUSY. 330df8bae1dSRodney W. Grimes */ 331e7bb21b3SJonathan Lemon if (d) { 332e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 333df8bae1dSRodney W. Grimes return (EBUSY); 334e7bb21b3SJonathan Lemon } 335e7bb21b3SJonathan Lemon dev->si_drv1 = (struct bpf_d *)~0; /* mark device in use */ 336e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 337e7bb21b3SJonathan Lemon 338d1d74c28SJohn Baldwin if ((dev->si_flags & SI_NAMED) == 0) 339b0d17ba6SPoul-Henning Kamp make_dev(&bpf_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 0600, 340b0d17ba6SPoul-Henning Kamp "bpf%d", dev2unit(dev)); 3417cc0979fSDavid Malone MALLOC(d, struct bpf_d *, sizeof(*d), M_BPF, M_WAITOK | M_ZERO); 342bd3a5320SPoul-Henning Kamp dev->si_drv1 = d; 343df8bae1dSRodney W. Grimes d->bd_bufsize = bpf_bufsize; 34400a83887SPaul Traina d->bd_sig = SIGIO; 3458ed3828cSRobert Watson d->bd_seesent = 1; 346e7bb21b3SJonathan Lemon mtx_init(&d->bd_mtx, devtoname(dev), MTX_DEF); 34781bda851SJohn Polstra callout_init(&d->bd_callout, 1); 348df8bae1dSRodney W. Grimes 349df8bae1dSRodney W. Grimes return (0); 350df8bae1dSRodney W. Grimes } 351df8bae1dSRodney W. Grimes 352df8bae1dSRodney W. Grimes /* 353df8bae1dSRodney W. Grimes * Close the descriptor by detaching it from its interface, 354df8bae1dSRodney W. Grimes * deallocating its buffers, and marking it free. 355df8bae1dSRodney W. Grimes */ 356df8bae1dSRodney W. Grimes /* ARGSUSED */ 35787f6c662SJulian Elischer static int 358b40ce416SJulian Elischer bpfclose(dev, flags, fmt, td) 359df8bae1dSRodney W. Grimes dev_t dev; 36060039670SBruce Evans int flags; 36160039670SBruce Evans int fmt; 362b40ce416SJulian Elischer struct thread *td; 363df8bae1dSRodney W. Grimes { 364e7bb21b3SJonathan Lemon struct bpf_d *d = dev->si_drv1; 365df8bae1dSRodney W. Grimes 36681bda851SJohn Polstra BPFD_LOCK(d); 36781bda851SJohn Polstra if (d->bd_state == BPF_WAITING) 36881bda851SJohn Polstra callout_stop(&d->bd_callout); 36981bda851SJohn Polstra d->bd_state = BPF_IDLE; 37081bda851SJohn Polstra BPFD_UNLOCK(d); 371831d27a9SDon Lewis funsetown(d->bd_sigio); 372e7bb21b3SJonathan Lemon mtx_lock(&bpf_mtx); 373df8bae1dSRodney W. Grimes if (d->bd_bif) 374df8bae1dSRodney W. Grimes bpf_detachd(d); 375e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 376df8bae1dSRodney W. Grimes bpf_freed(d); 377bd3a5320SPoul-Henning Kamp dev->si_drv1 = 0; 378bd3a5320SPoul-Henning Kamp FREE(d, M_BPF); 379df8bae1dSRodney W. Grimes 380df8bae1dSRodney W. Grimes return (0); 381df8bae1dSRodney W. Grimes } 382df8bae1dSRodney W. Grimes 383df8bae1dSRodney W. Grimes 384df8bae1dSRodney W. Grimes /* 385df8bae1dSRodney W. Grimes * Rotate the packet buffers in descriptor d. Move the store buffer 386df8bae1dSRodney W. Grimes * into the hold slot, and the free buffer into the store slot. 387df8bae1dSRodney W. Grimes * Zero the length of the new store buffer. 388df8bae1dSRodney W. Grimes */ 389df8bae1dSRodney W. Grimes #define ROTATE_BUFFERS(d) \ 390df8bae1dSRodney W. Grimes (d)->bd_hbuf = (d)->bd_sbuf; \ 391df8bae1dSRodney W. Grimes (d)->bd_hlen = (d)->bd_slen; \ 392df8bae1dSRodney W. Grimes (d)->bd_sbuf = (d)->bd_fbuf; \ 393df8bae1dSRodney W. Grimes (d)->bd_slen = 0; \ 394df8bae1dSRodney W. Grimes (d)->bd_fbuf = 0; 395df8bae1dSRodney W. Grimes /* 396df8bae1dSRodney W. Grimes * bpfread - read next chunk of packets from buffers 397df8bae1dSRodney W. Grimes */ 39887f6c662SJulian Elischer static int 39960039670SBruce Evans bpfread(dev, uio, ioflag) 400df8bae1dSRodney W. Grimes dev_t dev; 401df8bae1dSRodney W. Grimes register struct uio *uio; 40260039670SBruce Evans int ioflag; 403df8bae1dSRodney W. Grimes { 404e7bb21b3SJonathan Lemon struct bpf_d *d = dev->si_drv1; 40581bda851SJohn Polstra int timed_out; 406df8bae1dSRodney W. Grimes int error; 407df8bae1dSRodney W. Grimes 408df8bae1dSRodney W. Grimes /* 409df8bae1dSRodney W. Grimes * Restrict application to use a buffer the same size as 410df8bae1dSRodney W. Grimes * as kernel buffers. 411df8bae1dSRodney W. Grimes */ 412df8bae1dSRodney W. Grimes if (uio->uio_resid != d->bd_bufsize) 413df8bae1dSRodney W. Grimes return (EINVAL); 414df8bae1dSRodney W. Grimes 415e7bb21b3SJonathan Lemon BPFD_LOCK(d); 41681bda851SJohn Polstra if (d->bd_state == BPF_WAITING) 41781bda851SJohn Polstra callout_stop(&d->bd_callout); 41881bda851SJohn Polstra timed_out = (d->bd_state == BPF_TIMED_OUT); 41981bda851SJohn Polstra d->bd_state = BPF_IDLE; 420df8bae1dSRodney W. Grimes /* 421df8bae1dSRodney W. Grimes * If the hold buffer is empty, then do a timed sleep, which 422df8bae1dSRodney W. Grimes * ends when the timeout expires or when enough packets 423df8bae1dSRodney W. Grimes * have arrived to fill the store buffer. 424df8bae1dSRodney W. Grimes */ 425df8bae1dSRodney W. Grimes while (d->bd_hbuf == 0) { 42681bda851SJohn Polstra if ((d->bd_immediate || timed_out) && d->bd_slen != 0) { 427df8bae1dSRodney W. Grimes /* 428df8bae1dSRodney W. Grimes * A packet(s) either arrived since the previous 429df8bae1dSRodney W. Grimes * read or arrived while we were asleep. 430df8bae1dSRodney W. Grimes * Rotate the buffers and return what's here. 431df8bae1dSRodney W. Grimes */ 432df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 433df8bae1dSRodney W. Grimes break; 434df8bae1dSRodney W. Grimes } 435de5d9935SRobert Watson 436de5d9935SRobert Watson /* 437de5d9935SRobert Watson * No data is available, check to see if the bpf device 438de5d9935SRobert Watson * is still pointed at a real interface. If not, return 439de5d9935SRobert Watson * ENXIO so that the userland process knows to rebind 440de5d9935SRobert Watson * it before using it again. 441de5d9935SRobert Watson */ 442de5d9935SRobert Watson if (d->bd_bif == NULL) { 443e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 444de5d9935SRobert Watson return (ENXIO); 445de5d9935SRobert Watson } 446de5d9935SRobert Watson 447fba3cfdeSJohn Polstra if (ioflag & IO_NDELAY) { 448e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 449fba3cfdeSJohn Polstra return (EWOULDBLOCK); 450fba3cfdeSJohn Polstra } 451e7bb21b3SJonathan Lemon error = msleep((caddr_t)d, &d->bd_mtx, PRINET|PCATCH, 452e7bb21b3SJonathan Lemon "bpf", d->bd_rtout); 453df8bae1dSRodney W. Grimes if (error == EINTR || error == ERESTART) { 454e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 455df8bae1dSRodney W. Grimes return (error); 456df8bae1dSRodney W. Grimes } 457df8bae1dSRodney W. Grimes if (error == EWOULDBLOCK) { 458df8bae1dSRodney W. Grimes /* 459df8bae1dSRodney W. Grimes * On a timeout, return what's in the buffer, 460df8bae1dSRodney W. Grimes * which may be nothing. If there is something 461df8bae1dSRodney W. Grimes * in the store buffer, we can rotate the buffers. 462df8bae1dSRodney W. Grimes */ 463df8bae1dSRodney W. Grimes if (d->bd_hbuf) 464df8bae1dSRodney W. Grimes /* 465df8bae1dSRodney W. Grimes * We filled up the buffer in between 466df8bae1dSRodney W. Grimes * getting the timeout and arriving 467df8bae1dSRodney W. Grimes * here, so we don't need to rotate. 468df8bae1dSRodney W. Grimes */ 469df8bae1dSRodney W. Grimes break; 470df8bae1dSRodney W. Grimes 471df8bae1dSRodney W. Grimes if (d->bd_slen == 0) { 472e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 473df8bae1dSRodney W. Grimes return (0); 474df8bae1dSRodney W. Grimes } 475df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 476df8bae1dSRodney W. Grimes break; 477df8bae1dSRodney W. Grimes } 478df8bae1dSRodney W. Grimes } 479df8bae1dSRodney W. Grimes /* 480df8bae1dSRodney W. Grimes * At this point, we know we have something in the hold slot. 481df8bae1dSRodney W. Grimes */ 482e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 483df8bae1dSRodney W. Grimes 484df8bae1dSRodney W. Grimes /* 485df8bae1dSRodney W. Grimes * Move data from hold buffer into user space. 486df8bae1dSRodney W. Grimes * We know the entire buffer is transferred since 487df8bae1dSRodney W. Grimes * we checked above that the read buffer is bpf_bufsize bytes. 488df8bae1dSRodney W. Grimes */ 489e7bb21b3SJonathan Lemon error = uiomove(d->bd_hbuf, d->bd_hlen, uio); 490df8bae1dSRodney W. Grimes 491e7bb21b3SJonathan Lemon BPFD_LOCK(d); 492df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 493df8bae1dSRodney W. Grimes d->bd_hbuf = 0; 494df8bae1dSRodney W. Grimes d->bd_hlen = 0; 495e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 496df8bae1dSRodney W. Grimes 497df8bae1dSRodney W. Grimes return (error); 498df8bae1dSRodney W. Grimes } 499df8bae1dSRodney W. Grimes 500df8bae1dSRodney W. Grimes 501df8bae1dSRodney W. Grimes /* 502df8bae1dSRodney W. Grimes * If there are processes sleeping on this descriptor, wake them up. 503df8bae1dSRodney W. Grimes */ 504e7bb21b3SJonathan Lemon static __inline void 505df8bae1dSRodney W. Grimes bpf_wakeup(d) 506df8bae1dSRodney W. Grimes register struct bpf_d *d; 507df8bae1dSRodney W. Grimes { 50881bda851SJohn Polstra if (d->bd_state == BPF_WAITING) { 50981bda851SJohn Polstra callout_stop(&d->bd_callout); 51081bda851SJohn Polstra d->bd_state = BPF_IDLE; 51181bda851SJohn Polstra } 512df8bae1dSRodney W. Grimes wakeup((caddr_t)d); 513831d27a9SDon Lewis if (d->bd_async && d->bd_sig && d->bd_sigio) 514831d27a9SDon Lewis pgsigio(d->bd_sigio, d->bd_sig, 0); 51500a83887SPaul Traina 516df8bae1dSRodney W. Grimes selwakeup(&d->bd_sel); 517df8bae1dSRodney W. Grimes /* XXX */ 518df8bae1dSRodney W. Grimes d->bd_sel.si_pid = 0; 519df8bae1dSRodney W. Grimes } 520df8bae1dSRodney W. Grimes 52181bda851SJohn Polstra static void 52281bda851SJohn Polstra bpf_timed_out(arg) 52381bda851SJohn Polstra void *arg; 52481bda851SJohn Polstra { 52581bda851SJohn Polstra struct bpf_d *d = (struct bpf_d *)arg; 52681bda851SJohn Polstra 52781bda851SJohn Polstra BPFD_LOCK(d); 52881bda851SJohn Polstra if (d->bd_state == BPF_WAITING) { 52981bda851SJohn Polstra d->bd_state = BPF_TIMED_OUT; 53081bda851SJohn Polstra if (d->bd_slen != 0) 53181bda851SJohn Polstra bpf_wakeup(d); 53281bda851SJohn Polstra } 53381bda851SJohn Polstra BPFD_UNLOCK(d); 53481bda851SJohn Polstra } 53581bda851SJohn Polstra 53687f6c662SJulian Elischer static int 53760039670SBruce Evans bpfwrite(dev, uio, ioflag) 538df8bae1dSRodney W. Grimes dev_t dev; 539df8bae1dSRodney W. Grimes struct uio *uio; 54060039670SBruce Evans int ioflag; 541df8bae1dSRodney W. Grimes { 542e7bb21b3SJonathan Lemon struct bpf_d *d = dev->si_drv1; 543df8bae1dSRodney W. Grimes struct ifnet *ifp; 544df8bae1dSRodney W. Grimes struct mbuf *m; 545e7bb21b3SJonathan Lemon int error; 546df8bae1dSRodney W. Grimes static struct sockaddr dst; 547df8bae1dSRodney W. Grimes int datlen; 548df8bae1dSRodney W. Grimes 549df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 550df8bae1dSRodney W. Grimes return (ENXIO); 551df8bae1dSRodney W. Grimes 552df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 553df8bae1dSRodney W. Grimes 554df8bae1dSRodney W. Grimes if (uio->uio_resid == 0) 555df8bae1dSRodney W. Grimes return (0); 556df8bae1dSRodney W. Grimes 557df8bae1dSRodney W. Grimes error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, &dst, &datlen); 558df8bae1dSRodney W. Grimes if (error) 559df8bae1dSRodney W. Grimes return (error); 560df8bae1dSRodney W. Grimes 561df8bae1dSRodney W. Grimes if (datlen > ifp->if_mtu) 562df8bae1dSRodney W. Grimes return (EMSGSIZE); 563df8bae1dSRodney W. Grimes 564114ae644SMike Smith if (d->bd_hdrcmplt) 565114ae644SMike Smith dst.sa_family = pseudo_AF_HDRCMPLT; 566114ae644SMike Smith 567e7bb21b3SJonathan Lemon mtx_lock(&Giant); 568df8bae1dSRodney W. Grimes error = (*ifp->if_output)(ifp, m, &dst, (struct rtentry *)0); 569e7bb21b3SJonathan Lemon mtx_unlock(&Giant); 570df8bae1dSRodney W. Grimes /* 571df8bae1dSRodney W. Grimes * The driver frees the mbuf. 572df8bae1dSRodney W. Grimes */ 573df8bae1dSRodney W. Grimes return (error); 574df8bae1dSRodney W. Grimes } 575df8bae1dSRodney W. Grimes 576df8bae1dSRodney W. Grimes /* 577df8bae1dSRodney W. Grimes * Reset a descriptor by flushing its packet buffer and clearing the 578e7bb21b3SJonathan Lemon * receive and drop counts. 579df8bae1dSRodney W. Grimes */ 580df8bae1dSRodney W. Grimes static void 581df8bae1dSRodney W. Grimes reset_d(d) 582df8bae1dSRodney W. Grimes struct bpf_d *d; 583df8bae1dSRodney W. Grimes { 584e7bb21b3SJonathan Lemon 585e7bb21b3SJonathan Lemon mtx_assert(&d->bd_mtx, MA_OWNED); 586df8bae1dSRodney W. Grimes if (d->bd_hbuf) { 587df8bae1dSRodney W. Grimes /* Free the hold buffer. */ 588df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 589df8bae1dSRodney W. Grimes d->bd_hbuf = 0; 590df8bae1dSRodney W. Grimes } 591df8bae1dSRodney W. Grimes d->bd_slen = 0; 592df8bae1dSRodney W. Grimes d->bd_hlen = 0; 593df8bae1dSRodney W. Grimes d->bd_rcount = 0; 594df8bae1dSRodney W. Grimes d->bd_dcount = 0; 595df8bae1dSRodney W. Grimes } 596df8bae1dSRodney W. Grimes 597df8bae1dSRodney W. Grimes /* 598df8bae1dSRodney W. Grimes * FIONREAD Check for read packet available. 599df8bae1dSRodney W. Grimes * SIOCGIFADDR Get interface address - convenient hook to driver. 600df8bae1dSRodney W. Grimes * BIOCGBLEN Get buffer len [for read()]. 601df8bae1dSRodney W. Grimes * BIOCSETF Set ethernet read filter. 602df8bae1dSRodney W. Grimes * BIOCFLUSH Flush read packet buffer. 603df8bae1dSRodney W. Grimes * BIOCPROMISC Put interface into promiscuous mode. 604df8bae1dSRodney W. Grimes * BIOCGDLT Get link layer type. 605df8bae1dSRodney W. Grimes * BIOCGETIF Get interface name. 606df8bae1dSRodney W. Grimes * BIOCSETIF Set interface. 607df8bae1dSRodney W. Grimes * BIOCSRTIMEOUT Set read timeout. 608df8bae1dSRodney W. Grimes * BIOCGRTIMEOUT Get read timeout. 609df8bae1dSRodney W. Grimes * BIOCGSTATS Get packet stats. 610df8bae1dSRodney W. Grimes * BIOCIMMEDIATE Set immediate mode. 611df8bae1dSRodney W. Grimes * BIOCVERSION Get filter language version. 612114ae644SMike Smith * BIOCGHDRCMPLT Get "header already complete" flag 613114ae644SMike Smith * BIOCSHDRCMPLT Set "header already complete" flag 6148ed3828cSRobert Watson * BIOCGSEESENT Get "see packets sent" flag 6158ed3828cSRobert Watson * BIOCSSEESENT Set "see packets sent" flag 616df8bae1dSRodney W. Grimes */ 617df8bae1dSRodney W. Grimes /* ARGSUSED */ 61887f6c662SJulian Elischer static int 619b40ce416SJulian Elischer bpfioctl(dev, cmd, addr, flags, td) 620df8bae1dSRodney W. Grimes dev_t dev; 621ecbb00a2SDoug Rabson u_long cmd; 622df8bae1dSRodney W. Grimes caddr_t addr; 62360039670SBruce Evans int flags; 624b40ce416SJulian Elischer struct thread *td; 625df8bae1dSRodney W. Grimes { 626e7bb21b3SJonathan Lemon struct bpf_d *d = dev->si_drv1; 627e7bb21b3SJonathan Lemon int error = 0; 628df8bae1dSRodney W. Grimes 62981bda851SJohn Polstra BPFD_LOCK(d); 63081bda851SJohn Polstra if (d->bd_state == BPF_WAITING) 63181bda851SJohn Polstra callout_stop(&d->bd_callout); 63281bda851SJohn Polstra d->bd_state = BPF_IDLE; 63381bda851SJohn Polstra BPFD_UNLOCK(d); 63481bda851SJohn Polstra 635df8bae1dSRodney W. Grimes switch (cmd) { 636df8bae1dSRodney W. Grimes 637df8bae1dSRodney W. Grimes default: 638df8bae1dSRodney W. Grimes error = EINVAL; 639df8bae1dSRodney W. Grimes break; 640df8bae1dSRodney W. Grimes 641df8bae1dSRodney W. Grimes /* 642df8bae1dSRodney W. Grimes * Check for read packet available. 643df8bae1dSRodney W. Grimes */ 644df8bae1dSRodney W. Grimes case FIONREAD: 645df8bae1dSRodney W. Grimes { 646df8bae1dSRodney W. Grimes int n; 647df8bae1dSRodney W. Grimes 648e7bb21b3SJonathan Lemon BPFD_LOCK(d); 649df8bae1dSRodney W. Grimes n = d->bd_slen; 650df8bae1dSRodney W. Grimes if (d->bd_hbuf) 651df8bae1dSRodney W. Grimes n += d->bd_hlen; 652e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 653df8bae1dSRodney W. Grimes 654df8bae1dSRodney W. Grimes *(int *)addr = n; 655df8bae1dSRodney W. Grimes break; 656df8bae1dSRodney W. Grimes } 657df8bae1dSRodney W. Grimes 658df8bae1dSRodney W. Grimes case SIOCGIFADDR: 659df8bae1dSRodney W. Grimes { 660df8bae1dSRodney W. Grimes struct ifnet *ifp; 661df8bae1dSRodney W. Grimes 662df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 663df8bae1dSRodney W. Grimes error = EINVAL; 664df8bae1dSRodney W. Grimes else { 665df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 666df8bae1dSRodney W. Grimes error = (*ifp->if_ioctl)(ifp, cmd, addr); 667df8bae1dSRodney W. Grimes } 668df8bae1dSRodney W. Grimes break; 669df8bae1dSRodney W. Grimes } 670df8bae1dSRodney W. Grimes 671df8bae1dSRodney W. Grimes /* 672df8bae1dSRodney W. Grimes * Get buffer len [for read()]. 673df8bae1dSRodney W. Grimes */ 674df8bae1dSRodney W. Grimes case BIOCGBLEN: 675df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bufsize; 676df8bae1dSRodney W. Grimes break; 677df8bae1dSRodney W. Grimes 678df8bae1dSRodney W. Grimes /* 679df8bae1dSRodney W. Grimes * Set buffer length. 680df8bae1dSRodney W. Grimes */ 681df8bae1dSRodney W. Grimes case BIOCSBLEN: 682df8bae1dSRodney W. Grimes if (d->bd_bif != 0) 683df8bae1dSRodney W. Grimes error = EINVAL; 684df8bae1dSRodney W. Grimes else { 685df8bae1dSRodney W. Grimes register u_int size = *(u_int *)addr; 686df8bae1dSRodney W. Grimes 687eba2a1aeSPoul-Henning Kamp if (size > bpf_maxbufsize) 688eba2a1aeSPoul-Henning Kamp *(u_int *)addr = size = bpf_maxbufsize; 689df8bae1dSRodney W. Grimes else if (size < BPF_MINBUFSIZE) 690df8bae1dSRodney W. Grimes *(u_int *)addr = size = BPF_MINBUFSIZE; 691df8bae1dSRodney W. Grimes d->bd_bufsize = size; 692df8bae1dSRodney W. Grimes } 693df8bae1dSRodney W. Grimes break; 694df8bae1dSRodney W. Grimes 695df8bae1dSRodney W. Grimes /* 696df8bae1dSRodney W. Grimes * Set link layer read filter. 697df8bae1dSRodney W. Grimes */ 698df8bae1dSRodney W. Grimes case BIOCSETF: 699df8bae1dSRodney W. Grimes error = bpf_setf(d, (struct bpf_program *)addr); 700df8bae1dSRodney W. Grimes break; 701df8bae1dSRodney W. Grimes 702df8bae1dSRodney W. Grimes /* 703df8bae1dSRodney W. Grimes * Flush read packet buffer. 704df8bae1dSRodney W. Grimes */ 705df8bae1dSRodney W. Grimes case BIOCFLUSH: 706e7bb21b3SJonathan Lemon BPFD_LOCK(d); 707df8bae1dSRodney W. Grimes reset_d(d); 708e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 709df8bae1dSRodney W. Grimes break; 710df8bae1dSRodney W. Grimes 711df8bae1dSRodney W. Grimes /* 712df8bae1dSRodney W. Grimes * Put interface into promiscuous mode. 713df8bae1dSRodney W. Grimes */ 714df8bae1dSRodney W. Grimes case BIOCPROMISC: 715df8bae1dSRodney W. Grimes if (d->bd_bif == 0) { 716df8bae1dSRodney W. Grimes /* 717df8bae1dSRodney W. Grimes * No interface attached yet. 718df8bae1dSRodney W. Grimes */ 719df8bae1dSRodney W. Grimes error = EINVAL; 720df8bae1dSRodney W. Grimes break; 721df8bae1dSRodney W. Grimes } 722df8bae1dSRodney W. Grimes if (d->bd_promisc == 0) { 723e7bb21b3SJonathan Lemon mtx_lock(&Giant); 724df8bae1dSRodney W. Grimes error = ifpromisc(d->bd_bif->bif_ifp, 1); 725e7bb21b3SJonathan Lemon mtx_unlock(&Giant); 726df8bae1dSRodney W. Grimes if (error == 0) 727df8bae1dSRodney W. Grimes d->bd_promisc = 1; 728df8bae1dSRodney W. Grimes } 729df8bae1dSRodney W. Grimes break; 730df8bae1dSRodney W. Grimes 731df8bae1dSRodney W. Grimes /* 732df8bae1dSRodney W. Grimes * Get device parameters. 733df8bae1dSRodney W. Grimes */ 734df8bae1dSRodney W. Grimes case BIOCGDLT: 735df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 736df8bae1dSRodney W. Grimes error = EINVAL; 737df8bae1dSRodney W. Grimes else 738df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bif->bif_dlt; 739df8bae1dSRodney W. Grimes break; 740df8bae1dSRodney W. Grimes 741df8bae1dSRodney W. Grimes /* 7421dd0feaaSArchie Cobbs * Get interface name. 743df8bae1dSRodney W. Grimes */ 744df8bae1dSRodney W. Grimes case BIOCGETIF: 745df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 746df8bae1dSRodney W. Grimes error = EINVAL; 7471dd0feaaSArchie Cobbs else { 7481dd0feaaSArchie Cobbs struct ifnet *const ifp = d->bd_bif->bif_ifp; 7491dd0feaaSArchie Cobbs struct ifreq *const ifr = (struct ifreq *)addr; 7501dd0feaaSArchie Cobbs 7511dd0feaaSArchie Cobbs snprintf(ifr->ifr_name, sizeof(ifr->ifr_name), 7521dd0feaaSArchie Cobbs "%s%d", ifp->if_name, ifp->if_unit); 7531dd0feaaSArchie Cobbs } 754df8bae1dSRodney W. Grimes break; 755df8bae1dSRodney W. Grimes 756df8bae1dSRodney W. Grimes /* 757df8bae1dSRodney W. Grimes * Set interface. 758df8bae1dSRodney W. Grimes */ 759df8bae1dSRodney W. Grimes case BIOCSETIF: 760df8bae1dSRodney W. Grimes error = bpf_setif(d, (struct ifreq *)addr); 761df8bae1dSRodney W. Grimes break; 762df8bae1dSRodney W. Grimes 763df8bae1dSRodney W. Grimes /* 764df8bae1dSRodney W. Grimes * Set read timeout. 765df8bae1dSRodney W. Grimes */ 766df8bae1dSRodney W. Grimes case BIOCSRTIMEOUT: 767df8bae1dSRodney W. Grimes { 768df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 769df8bae1dSRodney W. Grimes 770bdc2cdc5SAlexander Langer /* 771bdc2cdc5SAlexander Langer * Subtract 1 tick from tvtohz() since this isn't 772bdc2cdc5SAlexander Langer * a one-shot timer. 773bdc2cdc5SAlexander Langer */ 774bdc2cdc5SAlexander Langer if ((error = itimerfix(tv)) == 0) 775bdc2cdc5SAlexander Langer d->bd_rtout = tvtohz(tv) - 1; 776df8bae1dSRodney W. Grimes break; 777df8bae1dSRodney W. Grimes } 778df8bae1dSRodney W. Grimes 779df8bae1dSRodney W. Grimes /* 780df8bae1dSRodney W. Grimes * Get read timeout. 781df8bae1dSRodney W. Grimes */ 782df8bae1dSRodney W. Grimes case BIOCGRTIMEOUT: 783df8bae1dSRodney W. Grimes { 784df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 785df8bae1dSRodney W. Grimes 786bdc2cdc5SAlexander Langer tv->tv_sec = d->bd_rtout / hz; 787bdc2cdc5SAlexander Langer tv->tv_usec = (d->bd_rtout % hz) * tick; 788df8bae1dSRodney W. Grimes break; 789df8bae1dSRodney W. Grimes } 790df8bae1dSRodney W. Grimes 791df8bae1dSRodney W. Grimes /* 792df8bae1dSRodney W. Grimes * Get packet stats. 793df8bae1dSRodney W. Grimes */ 794df8bae1dSRodney W. Grimes case BIOCGSTATS: 795df8bae1dSRodney W. Grimes { 796df8bae1dSRodney W. Grimes struct bpf_stat *bs = (struct bpf_stat *)addr; 797df8bae1dSRodney W. Grimes 798df8bae1dSRodney W. Grimes bs->bs_recv = d->bd_rcount; 799df8bae1dSRodney W. Grimes bs->bs_drop = d->bd_dcount; 800df8bae1dSRodney W. Grimes break; 801df8bae1dSRodney W. Grimes } 802df8bae1dSRodney W. Grimes 803df8bae1dSRodney W. Grimes /* 804df8bae1dSRodney W. Grimes * Set immediate mode. 805df8bae1dSRodney W. Grimes */ 806df8bae1dSRodney W. Grimes case BIOCIMMEDIATE: 807df8bae1dSRodney W. Grimes d->bd_immediate = *(u_int *)addr; 808df8bae1dSRodney W. Grimes break; 809df8bae1dSRodney W. Grimes 810df8bae1dSRodney W. Grimes case BIOCVERSION: 811df8bae1dSRodney W. Grimes { 812df8bae1dSRodney W. Grimes struct bpf_version *bv = (struct bpf_version *)addr; 813df8bae1dSRodney W. Grimes 814df8bae1dSRodney W. Grimes bv->bv_major = BPF_MAJOR_VERSION; 815df8bae1dSRodney W. Grimes bv->bv_minor = BPF_MINOR_VERSION; 816df8bae1dSRodney W. Grimes break; 817df8bae1dSRodney W. Grimes } 81800a83887SPaul Traina 819114ae644SMike Smith /* 820114ae644SMike Smith * Get "header already complete" flag 821114ae644SMike Smith */ 822114ae644SMike Smith case BIOCGHDRCMPLT: 823114ae644SMike Smith *(u_int *)addr = d->bd_hdrcmplt; 824114ae644SMike Smith break; 825114ae644SMike Smith 826114ae644SMike Smith /* 827114ae644SMike Smith * Set "header already complete" flag 828114ae644SMike Smith */ 829114ae644SMike Smith case BIOCSHDRCMPLT: 830114ae644SMike Smith d->bd_hdrcmplt = *(u_int *)addr ? 1 : 0; 831114ae644SMike Smith break; 832114ae644SMike Smith 8338ed3828cSRobert Watson /* 8348ed3828cSRobert Watson * Get "see sent packets" flag 8358ed3828cSRobert Watson */ 8368ed3828cSRobert Watson case BIOCGSEESENT: 8378ed3828cSRobert Watson *(u_int *)addr = d->bd_seesent; 8388ed3828cSRobert Watson break; 8398ed3828cSRobert Watson 8408ed3828cSRobert Watson /* 8418ed3828cSRobert Watson * Set "see sent packets" flag 8428ed3828cSRobert Watson */ 8438ed3828cSRobert Watson case BIOCSSEESENT: 8448ed3828cSRobert Watson d->bd_seesent = *(u_int *)addr; 8458ed3828cSRobert Watson break; 8468ed3828cSRobert Watson 84700a83887SPaul Traina case FIONBIO: /* Non-blocking I/O */ 84800a83887SPaul Traina break; 84900a83887SPaul Traina 85000a83887SPaul Traina case FIOASYNC: /* Send signal on receive packets */ 85100a83887SPaul Traina d->bd_async = *(int *)addr; 85200a83887SPaul Traina break; 85300a83887SPaul Traina 854831d27a9SDon Lewis case FIOSETOWN: 855831d27a9SDon Lewis error = fsetown(*(int *)addr, &d->bd_sigio); 85600a83887SPaul Traina break; 85700a83887SPaul Traina 858831d27a9SDon Lewis case FIOGETOWN: 859831d27a9SDon Lewis *(int *)addr = fgetown(d->bd_sigio); 860831d27a9SDon Lewis break; 861831d27a9SDon Lewis 862831d27a9SDon Lewis /* This is deprecated, FIOSETOWN should be used instead. */ 863831d27a9SDon Lewis case TIOCSPGRP: 864831d27a9SDon Lewis error = fsetown(-(*(int *)addr), &d->bd_sigio); 865831d27a9SDon Lewis break; 866831d27a9SDon Lewis 867831d27a9SDon Lewis /* This is deprecated, FIOGETOWN should be used instead. */ 86800a83887SPaul Traina case TIOCGPGRP: 869831d27a9SDon Lewis *(int *)addr = -fgetown(d->bd_sigio); 87000a83887SPaul Traina break; 87100a83887SPaul Traina 87200a83887SPaul Traina case BIOCSRSIG: /* Set receive signal */ 87300a83887SPaul Traina { 87400a83887SPaul Traina u_int sig; 87500a83887SPaul Traina 87600a83887SPaul Traina sig = *(u_int *)addr; 87700a83887SPaul Traina 87800a83887SPaul Traina if (sig >= NSIG) 87900a83887SPaul Traina error = EINVAL; 88000a83887SPaul Traina else 88100a83887SPaul Traina d->bd_sig = sig; 88200a83887SPaul Traina break; 88300a83887SPaul Traina } 88400a83887SPaul Traina case BIOCGRSIG: 88500a83887SPaul Traina *(u_int *)addr = d->bd_sig; 88600a83887SPaul Traina break; 887df8bae1dSRodney W. Grimes } 888df8bae1dSRodney W. Grimes return (error); 889df8bae1dSRodney W. Grimes } 890df8bae1dSRodney W. Grimes 891df8bae1dSRodney W. Grimes /* 892df8bae1dSRodney W. Grimes * Set d's packet filter program to fp. If this file already has a filter, 893df8bae1dSRodney W. Grimes * free it and replace it. Returns EINVAL for bogus requests. 894df8bae1dSRodney W. Grimes */ 895f708ef1bSPoul-Henning Kamp static int 896df8bae1dSRodney W. Grimes bpf_setf(d, fp) 897df8bae1dSRodney W. Grimes struct bpf_d *d; 898df8bae1dSRodney W. Grimes struct bpf_program *fp; 899df8bae1dSRodney W. Grimes { 900df8bae1dSRodney W. Grimes struct bpf_insn *fcode, *old; 901df8bae1dSRodney W. Grimes u_int flen, size; 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); 907e7bb21b3SJonathan Lemon BPFD_LOCK(d); 908df8bae1dSRodney W. Grimes d->bd_filter = 0; 909df8bae1dSRodney W. Grimes reset_d(d); 910e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 911df8bae1dSRodney W. Grimes if (old != 0) 912bd3a5320SPoul-Henning Kamp free((caddr_t)old, M_BPF); 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); 920bd3a5320SPoul-Henning Kamp fcode = (struct bpf_insn *)malloc(size, M_BPF, 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)) { 923e7bb21b3SJonathan Lemon BPFD_LOCK(d); 924df8bae1dSRodney W. Grimes d->bd_filter = fcode; 925df8bae1dSRodney W. Grimes reset_d(d); 926e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 927df8bae1dSRodney W. Grimes if (old != 0) 928bd3a5320SPoul-Henning Kamp free((caddr_t)old, M_BPF); 929df8bae1dSRodney W. Grimes 930df8bae1dSRodney W. Grimes return (0); 931df8bae1dSRodney W. Grimes } 932bd3a5320SPoul-Henning Kamp free((caddr_t)fcode, M_BPF); 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; 947e7bb21b3SJonathan Lemon int 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 */ 957e7bb21b3SJonathan Lemon mtx_lock(&bpf_mtx); 958df8bae1dSRodney W. Grimes for (bp = bpf_iflist; bp != 0; bp = bp->bif_next) { 959df8bae1dSRodney W. Grimes struct ifnet *ifp = bp->bif_ifp; 960df8bae1dSRodney W. Grimes 9619b44ff22SGarrett Wollman if (ifp == 0 || ifp != theywant) 962df8bae1dSRodney W. Grimes continue; 963e7bb21b3SJonathan Lemon 964e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 965df8bae1dSRodney W. Grimes /* 966df8bae1dSRodney W. Grimes * We found the requested interface. 967df8bae1dSRodney W. Grimes * If it's not up, return an error. 968df8bae1dSRodney W. Grimes * Allocate the packet buffers if we need to. 969df8bae1dSRodney W. Grimes * If we're already attached to requested interface, 970df8bae1dSRodney W. Grimes * just flush the buffer. 971df8bae1dSRodney W. Grimes */ 972df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_UP) == 0) 973df8bae1dSRodney W. Grimes return (ENETDOWN); 974df8bae1dSRodney W. Grimes 975df8bae1dSRodney W. Grimes if (d->bd_sbuf == 0) { 976df8bae1dSRodney W. Grimes error = bpf_allocbufs(d); 977df8bae1dSRodney W. Grimes if (error != 0) 978df8bae1dSRodney W. Grimes return (error); 979df8bae1dSRodney W. Grimes } 980df8bae1dSRodney W. Grimes if (bp != d->bd_bif) { 981df8bae1dSRodney W. Grimes if (d->bd_bif) 982df8bae1dSRodney W. Grimes /* 983df8bae1dSRodney W. Grimes * Detach if attached to something else. 984df8bae1dSRodney W. Grimes */ 985df8bae1dSRodney W. Grimes bpf_detachd(d); 986df8bae1dSRodney W. Grimes 987df8bae1dSRodney W. Grimes bpf_attachd(d, bp); 988df8bae1dSRodney W. Grimes } 989e7bb21b3SJonathan Lemon BPFD_LOCK(d); 990df8bae1dSRodney W. Grimes reset_d(d); 991e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 992df8bae1dSRodney W. Grimes return (0); 993df8bae1dSRodney W. Grimes } 994e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 995df8bae1dSRodney W. Grimes /* Not found. */ 996df8bae1dSRodney W. Grimes return (ENXIO); 997df8bae1dSRodney W. Grimes } 998df8bae1dSRodney W. Grimes 999df8bae1dSRodney W. Grimes /* 1000243ac7d8SPeter Wemm * Support for select() and poll() system calls 1001df8bae1dSRodney W. Grimes * 1002df8bae1dSRodney W. Grimes * Return true iff the specific operation will not block indefinitely. 1003df8bae1dSRodney W. Grimes * Otherwise, return false but make a note that a selwakeup() must be done. 1004df8bae1dSRodney W. Grimes */ 1005df8bae1dSRodney W. Grimes int 1006b40ce416SJulian Elischer bpfpoll(dev, events, td) 1007df8bae1dSRodney W. Grimes register dev_t dev; 1008243ac7d8SPeter Wemm int events; 1009b40ce416SJulian Elischer struct thread *td; 1010df8bae1dSRodney W. Grimes { 1011e7bb21b3SJonathan Lemon struct bpf_d *d; 10120832fc64SGarance A Drosehn int revents; 1013df8bae1dSRodney W. Grimes 1014bd3a5320SPoul-Henning Kamp d = dev->si_drv1; 1015de5d9935SRobert Watson if (d->bd_bif == NULL) 1016de5d9935SRobert Watson return (ENXIO); 1017de5d9935SRobert Watson 10180832fc64SGarance A Drosehn revents = events & (POLLOUT | POLLWRNORM); 1019e7bb21b3SJonathan Lemon BPFD_LOCK(d); 102075c13541SPoul-Henning Kamp if (events & (POLLIN | POLLRDNORM)) { 10210832fc64SGarance A Drosehn /* 10220832fc64SGarance A Drosehn * An imitation of the FIONREAD ioctl code. 10230832fc64SGarance A Drosehn * XXX not quite. An exact imitation: 10240832fc64SGarance A Drosehn * if (d->b_slen != 0 || 10250832fc64SGarance A Drosehn * (d->bd_hbuf != NULL && d->bd_hlen != 0) 10260832fc64SGarance A Drosehn */ 102781bda851SJohn Polstra if (d->bd_hlen != 0 || 102881bda851SJohn Polstra ((d->bd_immediate || d->bd_state == BPF_TIMED_OUT) && 102981bda851SJohn Polstra d->bd_slen != 0)) 1030243ac7d8SPeter Wemm revents |= events & (POLLIN | POLLRDNORM); 103181bda851SJohn Polstra else { 1032ed01445dSJohn Baldwin selrecord(td, &d->bd_sel); 103381bda851SJohn Polstra /* Start the read timeout if necessary. */ 103481bda851SJohn Polstra if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) { 103581bda851SJohn Polstra callout_reset(&d->bd_callout, d->bd_rtout, 103681bda851SJohn Polstra bpf_timed_out, d); 103781bda851SJohn Polstra d->bd_state = BPF_WAITING; 103881bda851SJohn Polstra } 103981bda851SJohn Polstra } 104075c13541SPoul-Henning Kamp } 1041e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1042243ac7d8SPeter Wemm return (revents); 1043df8bae1dSRodney W. Grimes } 1044df8bae1dSRodney W. Grimes 1045df8bae1dSRodney W. Grimes /* 1046df8bae1dSRodney W. Grimes * Incoming linkage from device drivers. Process the packet pkt, of length 1047df8bae1dSRodney W. Grimes * pktlen, which is stored in a contiguous buffer. The packet is parsed 1048df8bae1dSRodney W. Grimes * by each process' filter, and if accepted, stashed into the corresponding 1049df8bae1dSRodney W. Grimes * buffer. 1050df8bae1dSRodney W. Grimes */ 1051df8bae1dSRodney W. Grimes void 10529b44ff22SGarrett Wollman bpf_tap(ifp, pkt, pktlen) 10539b44ff22SGarrett Wollman struct ifnet *ifp; 1054df8bae1dSRodney W. Grimes register u_char *pkt; 1055df8bae1dSRodney W. Grimes register u_int pktlen; 1056df8bae1dSRodney W. Grimes { 1057df8bae1dSRodney W. Grimes struct bpf_if *bp; 1058df8bae1dSRodney W. Grimes register struct bpf_d *d; 1059df8bae1dSRodney W. Grimes register u_int slen; 1060e7bb21b3SJonathan Lemon 10619b44ff22SGarrett Wollman bp = ifp->if_bpf; 1062e7bb21b3SJonathan Lemon BPFIF_LOCK(bp); 1063df8bae1dSRodney W. Grimes for (d = bp->bif_dlist; d != 0; d = d->bd_next) { 1064e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1065df8bae1dSRodney W. Grimes ++d->bd_rcount; 1066df8bae1dSRodney W. Grimes slen = bpf_filter(d->bd_filter, pkt, pktlen, pktlen); 1067df8bae1dSRodney W. Grimes if (slen != 0) 1068df8bae1dSRodney W. Grimes catchpacket(d, pkt, pktlen, slen, bcopy); 1069e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1070df8bae1dSRodney W. Grimes } 1071e7bb21b3SJonathan Lemon BPFIF_UNLOCK(bp); 1072df8bae1dSRodney W. Grimes } 1073df8bae1dSRodney W. Grimes 1074df8bae1dSRodney W. Grimes /* 1075df8bae1dSRodney W. Grimes * Copy data from an mbuf chain into a buffer. This code is derived 1076df8bae1dSRodney W. Grimes * from m_copydata in sys/uipc_mbuf.c. 1077df8bae1dSRodney W. Grimes */ 1078df8bae1dSRodney W. Grimes static void 1079df8bae1dSRodney W. Grimes bpf_mcopy(src_arg, dst_arg, len) 1080df8bae1dSRodney W. Grimes const void *src_arg; 1081df8bae1dSRodney W. Grimes void *dst_arg; 10828bcbc7dfSAlexander Langer register size_t len; 1083df8bae1dSRodney W. Grimes { 1084df8bae1dSRodney W. Grimes register const struct mbuf *m; 1085df8bae1dSRodney W. Grimes register u_int count; 1086df8bae1dSRodney W. Grimes u_char *dst; 1087df8bae1dSRodney W. Grimes 1088df8bae1dSRodney W. Grimes m = src_arg; 1089df8bae1dSRodney W. Grimes dst = dst_arg; 1090df8bae1dSRodney W. Grimes while (len > 0) { 1091df8bae1dSRodney W. Grimes if (m == 0) 1092df8bae1dSRodney W. Grimes panic("bpf_mcopy"); 1093df8bae1dSRodney W. Grimes count = min(m->m_len, len); 10940453d3cbSBruce Evans bcopy(mtod(m, void *), dst, count); 1095df8bae1dSRodney W. Grimes m = m->m_next; 1096df8bae1dSRodney W. Grimes dst += count; 1097df8bae1dSRodney W. Grimes len -= count; 1098df8bae1dSRodney W. Grimes } 1099df8bae1dSRodney W. Grimes } 1100df8bae1dSRodney W. Grimes 1101df8bae1dSRodney W. Grimes /* 1102df8bae1dSRodney W. Grimes * Incoming linkage from device drivers, when packet is in an mbuf chain. 1103df8bae1dSRodney W. Grimes */ 1104df8bae1dSRodney W. Grimes void 11059b44ff22SGarrett Wollman bpf_mtap(ifp, m) 11069b44ff22SGarrett Wollman struct ifnet *ifp; 1107df8bae1dSRodney W. Grimes struct mbuf *m; 1108df8bae1dSRodney W. Grimes { 11099b44ff22SGarrett Wollman struct bpf_if *bp = ifp->if_bpf; 1110df8bae1dSRodney W. Grimes struct bpf_d *d; 1111df8bae1dSRodney W. Grimes u_int pktlen, slen; 1112df8bae1dSRodney W. Grimes struct mbuf *m0; 1113df8bae1dSRodney W. Grimes 1114df8bae1dSRodney W. Grimes pktlen = 0; 1115df8bae1dSRodney W. Grimes for (m0 = m; m0 != 0; m0 = m0->m_next) 1116df8bae1dSRodney W. Grimes pktlen += m0->m_len; 1117df8bae1dSRodney W. Grimes 1118e7bb21b3SJonathan Lemon BPFIF_LOCK(bp); 1119df8bae1dSRodney W. Grimes for (d = bp->bif_dlist; d != 0; d = d->bd_next) { 11208ed3828cSRobert Watson if (!d->bd_seesent && (m->m_pkthdr.rcvif == NULL)) 11218ed3828cSRobert Watson continue; 1122e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1123df8bae1dSRodney W. Grimes ++d->bd_rcount; 1124df8bae1dSRodney W. Grimes slen = bpf_filter(d->bd_filter, (u_char *)m, pktlen, 0); 1125df8bae1dSRodney W. Grimes if (slen != 0) 1126df8bae1dSRodney W. Grimes catchpacket(d, (u_char *)m, pktlen, slen, bpf_mcopy); 1127e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1128df8bae1dSRodney W. Grimes } 1129e7bb21b3SJonathan Lemon BPFIF_UNLOCK(bp); 1130df8bae1dSRodney W. Grimes } 1131df8bae1dSRodney W. Grimes 1132df8bae1dSRodney W. Grimes /* 1133df8bae1dSRodney W. Grimes * Move the packet data from interface memory (pkt) into the 1134df8bae1dSRodney W. Grimes * store buffer. Return 1 if it's time to wakeup a listener (buffer full), 1135df8bae1dSRodney W. Grimes * otherwise 0. "copy" is the routine called to do the actual data 1136df8bae1dSRodney W. Grimes * transfer. bcopy is passed in to copy contiguous chunks, while 1137df8bae1dSRodney W. Grimes * bpf_mcopy is passed in to copy mbuf chains. In the latter case, 1138df8bae1dSRodney W. Grimes * pkt is really an mbuf. 1139df8bae1dSRodney W. Grimes */ 1140df8bae1dSRodney W. Grimes static void 1141df8bae1dSRodney W. Grimes catchpacket(d, pkt, pktlen, snaplen, cpfn) 1142df8bae1dSRodney W. Grimes register struct bpf_d *d; 1143df8bae1dSRodney W. Grimes register u_char *pkt; 1144df8bae1dSRodney W. Grimes register u_int pktlen, snaplen; 11458bcbc7dfSAlexander Langer register void (*cpfn) __P((const void *, void *, size_t)); 1146df8bae1dSRodney W. Grimes { 1147df8bae1dSRodney W. Grimes register struct bpf_hdr *hp; 1148df8bae1dSRodney W. Grimes register int totlen, curlen; 1149df8bae1dSRodney W. Grimes register int hdrlen = d->bd_bif->bif_hdrlen; 1150df8bae1dSRodney W. Grimes /* 1151df8bae1dSRodney W. Grimes * Figure out how many bytes to move. If the packet is 1152df8bae1dSRodney W. Grimes * greater or equal to the snapshot length, transfer that 1153df8bae1dSRodney W. Grimes * much. Otherwise, transfer the whole packet (unless 1154df8bae1dSRodney W. Grimes * we hit the buffer size limit). 1155df8bae1dSRodney W. Grimes */ 1156df8bae1dSRodney W. Grimes totlen = hdrlen + min(snaplen, pktlen); 1157df8bae1dSRodney W. Grimes if (totlen > d->bd_bufsize) 1158df8bae1dSRodney W. Grimes totlen = d->bd_bufsize; 1159df8bae1dSRodney W. Grimes 1160df8bae1dSRodney W. Grimes /* 1161df8bae1dSRodney W. Grimes * Round up the end of the previous packet to the next longword. 1162df8bae1dSRodney W. Grimes */ 1163df8bae1dSRodney W. Grimes curlen = BPF_WORDALIGN(d->bd_slen); 1164df8bae1dSRodney W. Grimes if (curlen + totlen > d->bd_bufsize) { 1165df8bae1dSRodney W. Grimes /* 1166df8bae1dSRodney W. Grimes * This packet will overflow the storage buffer. 1167df8bae1dSRodney W. Grimes * Rotate the buffers if we can, then wakeup any 1168df8bae1dSRodney W. Grimes * pending reads. 1169df8bae1dSRodney W. Grimes */ 1170df8bae1dSRodney W. Grimes if (d->bd_fbuf == 0) { 1171df8bae1dSRodney W. Grimes /* 1172df8bae1dSRodney W. Grimes * We haven't completed the previous read yet, 1173df8bae1dSRodney W. Grimes * so drop the packet. 1174df8bae1dSRodney W. Grimes */ 1175df8bae1dSRodney W. Grimes ++d->bd_dcount; 1176df8bae1dSRodney W. Grimes return; 1177df8bae1dSRodney W. Grimes } 1178df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 1179df8bae1dSRodney W. Grimes bpf_wakeup(d); 1180df8bae1dSRodney W. Grimes curlen = 0; 1181df8bae1dSRodney W. Grimes } 118281bda851SJohn Polstra else if (d->bd_immediate || d->bd_state == BPF_TIMED_OUT) 1183df8bae1dSRodney W. Grimes /* 118481bda851SJohn Polstra * Immediate mode is set, or the read timeout has 118581bda851SJohn Polstra * already expired during a select call. A packet 118681bda851SJohn Polstra * arrived, so the reader should be woken up. 1187df8bae1dSRodney W. Grimes */ 1188df8bae1dSRodney W. Grimes bpf_wakeup(d); 1189df8bae1dSRodney W. Grimes 1190df8bae1dSRodney W. Grimes /* 1191df8bae1dSRodney W. Grimes * Append the bpf header. 1192df8bae1dSRodney W. Grimes */ 1193df8bae1dSRodney W. Grimes hp = (struct bpf_hdr *)(d->bd_sbuf + curlen); 1194df8bae1dSRodney W. Grimes microtime(&hp->bh_tstamp); 1195df8bae1dSRodney W. Grimes hp->bh_datalen = pktlen; 1196df8bae1dSRodney W. Grimes hp->bh_hdrlen = hdrlen; 1197df8bae1dSRodney W. Grimes /* 1198df8bae1dSRodney W. Grimes * Copy the packet data into the store buffer and update its length. 1199df8bae1dSRodney W. Grimes */ 1200df8bae1dSRodney W. Grimes (*cpfn)(pkt, (u_char *)hp + hdrlen, (hp->bh_caplen = totlen - hdrlen)); 1201df8bae1dSRodney W. Grimes d->bd_slen = curlen + totlen; 1202df8bae1dSRodney W. Grimes } 1203df8bae1dSRodney W. Grimes 1204df8bae1dSRodney W. Grimes /* 1205df8bae1dSRodney W. Grimes * Initialize all nonzero fields of a descriptor. 1206df8bae1dSRodney W. Grimes */ 1207df8bae1dSRodney W. Grimes static int 1208df8bae1dSRodney W. Grimes bpf_allocbufs(d) 1209df8bae1dSRodney W. Grimes register struct bpf_d *d; 1210df8bae1dSRodney W. Grimes { 1211bd3a5320SPoul-Henning Kamp d->bd_fbuf = (caddr_t)malloc(d->bd_bufsize, M_BPF, M_WAITOK); 1212df8bae1dSRodney W. Grimes if (d->bd_fbuf == 0) 1213df8bae1dSRodney W. Grimes return (ENOBUFS); 1214df8bae1dSRodney W. Grimes 1215bd3a5320SPoul-Henning Kamp d->bd_sbuf = (caddr_t)malloc(d->bd_bufsize, M_BPF, M_WAITOK); 1216df8bae1dSRodney W. Grimes if (d->bd_sbuf == 0) { 1217bd3a5320SPoul-Henning Kamp free(d->bd_fbuf, M_BPF); 1218df8bae1dSRodney W. Grimes return (ENOBUFS); 1219df8bae1dSRodney W. Grimes } 1220df8bae1dSRodney W. Grimes d->bd_slen = 0; 1221df8bae1dSRodney W. Grimes d->bd_hlen = 0; 1222df8bae1dSRodney W. Grimes return (0); 1223df8bae1dSRodney W. Grimes } 1224df8bae1dSRodney W. Grimes 1225df8bae1dSRodney W. Grimes /* 1226df8bae1dSRodney W. Grimes * Free buffers currently in use by a descriptor. 1227df8bae1dSRodney W. Grimes * Called on close. 1228df8bae1dSRodney W. Grimes */ 1229df8bae1dSRodney W. Grimes static void 1230df8bae1dSRodney W. Grimes bpf_freed(d) 1231df8bae1dSRodney W. Grimes register struct bpf_d *d; 1232df8bae1dSRodney W. Grimes { 1233df8bae1dSRodney W. Grimes /* 1234df8bae1dSRodney W. Grimes * We don't need to lock out interrupts since this descriptor has 1235df8bae1dSRodney W. Grimes * been detached from its interface and it yet hasn't been marked 1236df8bae1dSRodney W. Grimes * free. 1237df8bae1dSRodney W. Grimes */ 1238df8bae1dSRodney W. Grimes if (d->bd_sbuf != 0) { 1239bd3a5320SPoul-Henning Kamp free(d->bd_sbuf, M_BPF); 1240df8bae1dSRodney W. Grimes if (d->bd_hbuf != 0) 1241bd3a5320SPoul-Henning Kamp free(d->bd_hbuf, M_BPF); 1242df8bae1dSRodney W. Grimes if (d->bd_fbuf != 0) 1243bd3a5320SPoul-Henning Kamp free(d->bd_fbuf, M_BPF); 1244df8bae1dSRodney W. Grimes } 1245df8bae1dSRodney W. Grimes if (d->bd_filter) 1246bd3a5320SPoul-Henning Kamp free((caddr_t)d->bd_filter, M_BPF); 1247e7bb21b3SJonathan Lemon mtx_destroy(&d->bd_mtx); 1248df8bae1dSRodney W. Grimes } 1249df8bae1dSRodney W. Grimes 1250df8bae1dSRodney W. Grimes /* 125198ec4706SDima Dorfman * Attach an interface to bpf. ifp is a pointer to the structure 125298ec4706SDima Dorfman * defining the interface to be attached, dlt is the link layer type, 125398ec4706SDima Dorfman * and hdrlen is the fixed size of the link header (variable length 125498ec4706SDima Dorfman * headers are not yet supporrted). 1255df8bae1dSRodney W. Grimes */ 1256df8bae1dSRodney W. Grimes void 12579b44ff22SGarrett Wollman bpfattach(ifp, dlt, hdrlen) 1258df8bae1dSRodney W. Grimes struct ifnet *ifp; 1259df8bae1dSRodney W. Grimes u_int dlt, hdrlen; 1260df8bae1dSRodney W. Grimes { 1261df8bae1dSRodney W. Grimes struct bpf_if *bp; 12626a40ecceSJohn Baldwin bp = (struct bpf_if *)malloc(sizeof(*bp), M_BPF, M_NOWAIT | M_ZERO); 1263df8bae1dSRodney W. Grimes if (bp == 0) 1264df8bae1dSRodney W. Grimes panic("bpfattach"); 1265df8bae1dSRodney W. Grimes 1266df8bae1dSRodney W. Grimes bp->bif_ifp = ifp; 1267df8bae1dSRodney W. Grimes bp->bif_dlt = dlt; 1268e7bb21b3SJonathan Lemon mtx_init(&bp->bif_mtx, "bpf interface lock", MTX_DEF); 1269df8bae1dSRodney W. Grimes 1270e7bb21b3SJonathan Lemon mtx_lock(&bpf_mtx); 1271df8bae1dSRodney W. Grimes bp->bif_next = bpf_iflist; 1272df8bae1dSRodney W. Grimes bpf_iflist = bp; 1273e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 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 12852eeab939SGarrett Wollman if (bootverbose) 1286df8bae1dSRodney W. Grimes printf("bpf: %s%d attached\n", ifp->if_name, ifp->if_unit); 1287df8bae1dSRodney W. Grimes } 128853ac6efbSJulian Elischer 1289de5d9935SRobert Watson /* 1290de5d9935SRobert Watson * Detach bpf from an interface. This involves detaching each descriptor 1291de5d9935SRobert Watson * associated with the interface, and leaving bd_bif NULL. Notify each 1292de5d9935SRobert Watson * descriptor as it's detached so that any sleepers wake up and get 1293de5d9935SRobert Watson * ENXIO. 1294de5d9935SRobert Watson */ 1295de5d9935SRobert Watson void 1296de5d9935SRobert Watson bpfdetach(ifp) 1297de5d9935SRobert Watson struct ifnet *ifp; 1298de5d9935SRobert Watson { 1299de5d9935SRobert Watson struct bpf_if *bp, *bp_prev; 1300de5d9935SRobert Watson struct bpf_d *d; 1301de5d9935SRobert Watson 1302e7bb21b3SJonathan Lemon mtx_lock(&bpf_mtx); 1303de5d9935SRobert Watson 1304de5d9935SRobert Watson /* Locate BPF interface information */ 1305de5d9935SRobert Watson bp_prev = NULL; 1306de5d9935SRobert Watson for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) { 1307de5d9935SRobert Watson if (ifp == bp->bif_ifp) 1308de5d9935SRobert Watson break; 1309de5d9935SRobert Watson bp_prev = bp; 1310de5d9935SRobert Watson } 1311de5d9935SRobert Watson 1312de5d9935SRobert Watson /* Interface wasn't attached */ 1313de5d9935SRobert Watson if (bp->bif_ifp == NULL) { 1314e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 1315de5d9935SRobert Watson printf("bpfdetach: %s%d was not attached\n", ifp->if_name, 1316de5d9935SRobert Watson ifp->if_unit); 1317de5d9935SRobert Watson return; 1318de5d9935SRobert Watson } 1319de5d9935SRobert Watson 1320de5d9935SRobert Watson if (bp_prev) { 1321de5d9935SRobert Watson bp_prev->bif_next = bp->bif_next; 1322de5d9935SRobert Watson } else { 1323de5d9935SRobert Watson bpf_iflist = bp->bif_next; 1324de5d9935SRobert Watson } 1325de5d9935SRobert Watson 1326e7bb21b3SJonathan Lemon while ((d = bp->bif_dlist) != NULL) { 1327e7bb21b3SJonathan Lemon bpf_detachd(d); 1328e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1329e7bb21b3SJonathan Lemon bpf_wakeup(d); 1330e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1331e7bb21b3SJonathan Lemon } 1332e7bb21b3SJonathan Lemon 1333e7bb21b3SJonathan Lemon mtx_destroy(&bp->bif_mtx); 1334de5d9935SRobert Watson free(bp, M_BPF); 1335de5d9935SRobert Watson 1336e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 1337de5d9935SRobert Watson } 1338de5d9935SRobert Watson 1339514ede09SBruce Evans static void bpf_drvinit __P((void *unused)); 1340bd3a5320SPoul-Henning Kamp 13413f54a085SPoul-Henning Kamp static void bpf_clone __P((void *arg, char *name, int namelen, dev_t *dev)); 13423f54a085SPoul-Henning Kamp 13433f54a085SPoul-Henning Kamp static void 13443f54a085SPoul-Henning Kamp bpf_clone(arg, name, namelen, dev) 13453f54a085SPoul-Henning Kamp void *arg; 13463f54a085SPoul-Henning Kamp char *name; 13473f54a085SPoul-Henning Kamp int namelen; 13483f54a085SPoul-Henning Kamp dev_t *dev; 13493f54a085SPoul-Henning Kamp { 13503f54a085SPoul-Henning Kamp int u; 13513f54a085SPoul-Henning Kamp 13523f54a085SPoul-Henning Kamp if (*dev != NODEV) 13533f54a085SPoul-Henning Kamp return; 1354db901281SPoul-Henning Kamp if (dev_stdclone(name, NULL, "bpf", &u) != 1) 13553f54a085SPoul-Henning Kamp return; 1356b0d17ba6SPoul-Henning Kamp *dev = make_dev(&bpf_cdevsw, unit2minor(u), UID_ROOT, GID_WHEEL, 0600, 1357b0d17ba6SPoul-Henning Kamp "bpf%d", u); 1358b0d17ba6SPoul-Henning Kamp (*dev)->si_flags |= SI_CHEAPCLONE; 13593f54a085SPoul-Henning Kamp return; 13603f54a085SPoul-Henning Kamp } 13613f54a085SPoul-Henning Kamp 1362514ede09SBruce Evans static void 1363514ede09SBruce Evans bpf_drvinit(unused) 1364514ede09SBruce Evans void *unused; 136553ac6efbSJulian Elischer { 136653ac6efbSJulian Elischer 1367e7bb21b3SJonathan Lemon mtx_init(&bpf_mtx, "bpf global lock", MTX_DEF); 1368db901281SPoul-Henning Kamp EVENTHANDLER_REGISTER(dev_clone, bpf_clone, 0, 1000); 13692447bec8SPoul-Henning Kamp cdevsw_add(&bpf_cdevsw); 13707198bf47SJulian Elischer } 137153ac6efbSJulian Elischer 137253ac6efbSJulian Elischer SYSINIT(bpfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,bpf_drvinit,NULL) 137353ac6efbSJulian Elischer 13745bb5f2c9SPeter Wemm #else /* !DEV_BPF && !NETGRAPH_BPF */ 1375f8dc4716SMike Smith /* 1376f8dc4716SMike Smith * NOP stubs to allow bpf-using drivers to load and function. 1377f8dc4716SMike Smith * 1378f8dc4716SMike Smith * A 'better' implementation would allow the core bpf functionality 1379f8dc4716SMike Smith * to be loaded at runtime. 1380f8dc4716SMike Smith */ 1381f8dc4716SMike Smith 1382f8dc4716SMike Smith void 1383f8dc4716SMike Smith bpf_tap(ifp, pkt, pktlen) 1384f8dc4716SMike Smith struct ifnet *ifp; 1385f8dc4716SMike Smith register u_char *pkt; 1386f8dc4716SMike Smith register u_int pktlen; 1387f8dc4716SMike Smith { 1388f8dc4716SMike Smith } 1389f8dc4716SMike Smith 1390f8dc4716SMike Smith void 1391f8dc4716SMike Smith bpf_mtap(ifp, m) 1392f8dc4716SMike Smith struct ifnet *ifp; 1393f8dc4716SMike Smith struct mbuf *m; 1394f8dc4716SMike Smith { 1395f8dc4716SMike Smith } 1396f8dc4716SMike Smith 1397f8dc4716SMike Smith void 1398f8dc4716SMike Smith bpfattach(ifp, dlt, hdrlen) 1399f8dc4716SMike Smith struct ifnet *ifp; 1400f8dc4716SMike Smith u_int dlt, hdrlen; 1401f8dc4716SMike Smith { 1402f8dc4716SMike Smith } 1403f8dc4716SMike Smith 1404da626c17SBill Paul void 1405da626c17SBill Paul bpfdetach(ifp) 1406da626c17SBill Paul struct ifnet *ifp; 1407da626c17SBill Paul { 1408da626c17SBill Paul } 1409da626c17SBill Paul 1410f8dc4716SMike Smith u_int 1411f8dc4716SMike Smith bpf_filter(pc, p, wirelen, buflen) 14121f8ffa4bSJulian Elischer register const struct bpf_insn *pc; 1413f8dc4716SMike Smith register u_char *p; 1414f8dc4716SMike Smith u_int wirelen; 1415f8dc4716SMike Smith register u_int buflen; 1416f8dc4716SMike Smith { 1417f8dc4716SMike Smith return -1; /* "no filter" behaviour */ 1418f8dc4716SMike Smith } 1419f8dc4716SMike Smith 14205bb5f2c9SPeter Wemm int 14215bb5f2c9SPeter Wemm bpf_validate(f, len) 14225bb5f2c9SPeter Wemm const struct bpf_insn *f; 14235bb5f2c9SPeter Wemm int len; 14245bb5f2c9SPeter Wemm { 14255bb5f2c9SPeter Wemm return 0; /* false */ 14265bb5f2c9SPeter Wemm } 14275bb5f2c9SPeter Wemm 14285bb5f2c9SPeter Wemm #endif /* !DEV_BPF && !NETGRAPH_BPF */ 1429