1c398230bSWarner Losh /*- 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 * 4. Neither the name of the University nor the names of its contributors 19df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 20df8bae1dSRodney W. Grimes * without specific prior written permission. 21df8bae1dSRodney W. Grimes * 22df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32df8bae1dSRodney W. Grimes * SUCH DAMAGE. 33df8bae1dSRodney W. Grimes * 344f252c4dSRuslan Ermilov * @(#)bpf.c 8.4 (Berkeley) 1/9/95 35df8bae1dSRodney W. Grimes * 36c3aac50fSPeter Wemm * $FreeBSD$ 37df8bae1dSRodney W. Grimes */ 38df8bae1dSRodney W. Grimes 395bb5f2c9SPeter Wemm #include "opt_bpf.h" 4082f4445dSRobert Watson #include "opt_mac.h" 415bb5f2c9SPeter Wemm #include "opt_netgraph.h" 42df8bae1dSRodney W. Grimes 4395aab9ccSJohn-Mark Gurney #include <sys/types.h> 44df8bae1dSRodney W. Grimes #include <sys/param.h> 45df8bae1dSRodney W. Grimes #include <sys/systm.h> 46ce7609a4SBruce Evans #include <sys/conf.h> 47e76eee55SPoul-Henning Kamp #include <sys/fcntl.h> 4882f4445dSRobert Watson #include <sys/mac.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> 57e76eee55SPoul-Henning Kamp #include <sys/uio.h> 58df8bae1dSRodney W. Grimes 5995aab9ccSJohn-Mark Gurney #include <sys/event.h> 6095aab9ccSJohn-Mark Gurney #include <sys/file.h> 61243ac7d8SPeter Wemm #include <sys/poll.h> 6295aab9ccSJohn-Mark Gurney #include <sys/proc.h> 63df8bae1dSRodney W. Grimes 64df8bae1dSRodney W. Grimes #include <sys/socket.h> 65df8bae1dSRodney W. Grimes 66fba9235dSBruce Evans #include <net/if.h> 67df8bae1dSRodney W. Grimes #include <net/bpf.h> 68df8bae1dSRodney W. Grimes #include <net/bpfdesc.h> 69df8bae1dSRodney W. Grimes 70df8bae1dSRodney W. Grimes #include <netinet/in.h> 71df8bae1dSRodney W. Grimes #include <netinet/if_ether.h> 72df8bae1dSRodney W. Grimes #include <sys/kernel.h> 73f708ef1bSPoul-Henning Kamp #include <sys/sysctl.h> 747b778b5eSEivind Eklund 75959b7375SPoul-Henning Kamp static MALLOC_DEFINE(M_BPF, "BPF", "BPF data"); 7687f6c662SJulian Elischer 775bb5f2c9SPeter Wemm #if defined(DEV_BPF) || defined(NETGRAPH_BPF) 7853ac6efbSJulian Elischer 79df8bae1dSRodney W. Grimes #define PRINET 26 /* interruptible */ 80df8bae1dSRodney W. Grimes 81df8bae1dSRodney W. Grimes /* 82df8bae1dSRodney W. Grimes * The default read buffer size is patchable. 83df8bae1dSRodney W. Grimes */ 84e7bb21b3SJonathan Lemon static int bpf_bufsize = 4096; 85f708ef1bSPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, bpf_bufsize, CTLFLAG_RW, 86f708ef1bSPoul-Henning Kamp &bpf_bufsize, 0, ""); 87eba2a1aeSPoul-Henning Kamp static int bpf_maxbufsize = BPF_MAXBUFSIZE; 88eba2a1aeSPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, bpf_maxbufsize, CTLFLAG_RW, 89eba2a1aeSPoul-Henning Kamp &bpf_maxbufsize, 0, ""); 90df8bae1dSRodney W. Grimes 91df8bae1dSRodney W. Grimes /* 92d1a67300SRobert Watson * bpf_iflist is a list of BPF interface structures, each corresponding to a 93d1a67300SRobert Watson * specific DLT. The same network interface might have several BPF interface 94d1a67300SRobert Watson * structures registered by different layers in the stack (i.e., 802.11 95d1a67300SRobert Watson * frames, ethernet frames, etc). 96df8bae1dSRodney W. Grimes */ 974a3feeaaSRobert Watson static LIST_HEAD(, bpf_if) bpf_iflist; 98e7bb21b3SJonathan Lemon static struct mtx bpf_mtx; /* bpf global lock */ 99df8bae1dSRodney W. Grimes 100929ddbbbSAlfred Perlstein static int bpf_allocbufs(struct bpf_d *); 101929ddbbbSAlfred Perlstein static void bpf_attachd(struct bpf_d *d, struct bpf_if *bp); 102929ddbbbSAlfred Perlstein static void bpf_detachd(struct bpf_d *d); 103929ddbbbSAlfred Perlstein static void bpf_freed(struct bpf_d *); 104929ddbbbSAlfred Perlstein static void bpf_mcopy(const void *, void *, size_t); 105929ddbbbSAlfred Perlstein static int bpf_movein(struct uio *, int, 106929ddbbbSAlfred Perlstein struct mbuf **, struct sockaddr *, int *); 107929ddbbbSAlfred Perlstein static int bpf_setif(struct bpf_d *, struct ifreq *); 108929ddbbbSAlfred Perlstein static void bpf_timed_out(void *); 109e7bb21b3SJonathan Lemon static __inline void 110929ddbbbSAlfred Perlstein bpf_wakeup(struct bpf_d *); 111929ddbbbSAlfred Perlstein static void catchpacket(struct bpf_d *, u_char *, u_int, 112929ddbbbSAlfred Perlstein u_int, void (*)(const void *, void *, size_t)); 113929ddbbbSAlfred Perlstein static void reset_d(struct bpf_d *); 114929ddbbbSAlfred Perlstein static int bpf_setf(struct bpf_d *, struct bpf_program *); 1158eab61f3SSam Leffler static int bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *); 1168eab61f3SSam Leffler static int bpf_setdlt(struct bpf_d *, u_int); 11795aab9ccSJohn-Mark Gurney static void filt_bpfdetach(struct knote *); 11895aab9ccSJohn-Mark Gurney static int filt_bpfread(struct knote *, long); 119df8bae1dSRodney W. Grimes 12087f6c662SJulian Elischer static d_open_t bpfopen; 12187f6c662SJulian Elischer static d_close_t bpfclose; 12287f6c662SJulian Elischer static d_read_t bpfread; 12387f6c662SJulian Elischer static d_write_t bpfwrite; 12487f6c662SJulian Elischer static d_ioctl_t bpfioctl; 125243ac7d8SPeter Wemm static d_poll_t bpfpoll; 12695aab9ccSJohn-Mark Gurney static d_kqfilter_t bpfkqfilter; 12787f6c662SJulian Elischer 1284e2f199eSPoul-Henning Kamp static struct cdevsw bpf_cdevsw = { 129dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 130dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 1317ac40f5fSPoul-Henning Kamp .d_open = bpfopen, 1327ac40f5fSPoul-Henning Kamp .d_close = bpfclose, 1337ac40f5fSPoul-Henning Kamp .d_read = bpfread, 1347ac40f5fSPoul-Henning Kamp .d_write = bpfwrite, 1357ac40f5fSPoul-Henning Kamp .d_ioctl = bpfioctl, 1367ac40f5fSPoul-Henning Kamp .d_poll = bpfpoll, 1377ac40f5fSPoul-Henning Kamp .d_name = "bpf", 13895aab9ccSJohn-Mark Gurney .d_kqfilter = bpfkqfilter, 1394e2f199eSPoul-Henning Kamp }; 14087f6c662SJulian Elischer 14195aab9ccSJohn-Mark Gurney static struct filterops bpfread_filtops = 14295aab9ccSJohn-Mark Gurney { 1, NULL, filt_bpfdetach, filt_bpfread }; 14387f6c662SJulian Elischer 144df8bae1dSRodney W. Grimes static int 145df8bae1dSRodney W. Grimes bpf_movein(uio, linktype, mp, sockp, datlen) 1468994a245SDag-Erling Smørgrav struct uio *uio; 147df8bae1dSRodney W. Grimes int linktype, *datlen; 1488994a245SDag-Erling Smørgrav struct mbuf **mp; 1498994a245SDag-Erling Smørgrav struct sockaddr *sockp; 150df8bae1dSRodney W. Grimes { 151df8bae1dSRodney W. Grimes struct mbuf *m; 152df8bae1dSRodney W. Grimes int error; 153df8bae1dSRodney W. Grimes int len; 154df8bae1dSRodney W. Grimes int hlen; 155df8bae1dSRodney W. Grimes 156df8bae1dSRodney W. Grimes /* 157df8bae1dSRodney W. Grimes * Build a sockaddr based on the data link layer type. 158df8bae1dSRodney W. Grimes * We do this at this level because the ethernet header 159df8bae1dSRodney W. Grimes * is copied directly into the data field of the sockaddr. 160df8bae1dSRodney W. Grimes * In the case of SLIP, there is no header and the packet 161df8bae1dSRodney W. Grimes * is forwarded as is. 162df8bae1dSRodney W. Grimes * Also, we are careful to leave room at the front of the mbuf 163df8bae1dSRodney W. Grimes * for the link level header. 164df8bae1dSRodney W. Grimes */ 165df8bae1dSRodney W. Grimes switch (linktype) { 166df8bae1dSRodney W. Grimes 167df8bae1dSRodney W. Grimes case DLT_SLIP: 168df8bae1dSRodney W. Grimes sockp->sa_family = AF_INET; 169df8bae1dSRodney W. Grimes hlen = 0; 170df8bae1dSRodney W. Grimes break; 171df8bae1dSRodney W. Grimes 172df8bae1dSRodney W. Grimes case DLT_EN10MB: 173df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 174df8bae1dSRodney W. Grimes /* XXX Would MAXLINKHDR be better? */ 175797f247bSMatthew N. Dodd hlen = ETHER_HDR_LEN; 176df8bae1dSRodney W. Grimes break; 177df8bae1dSRodney W. Grimes 178df8bae1dSRodney W. Grimes case DLT_FDDI: 179d41f24e7SDavid Greenman sockp->sa_family = AF_IMPLINK; 180d41f24e7SDavid Greenman hlen = 0; 181df8bae1dSRodney W. Grimes break; 182df8bae1dSRodney W. Grimes 18322f05c43SAndrey A. Chernov case DLT_RAW: 184df8bae1dSRodney W. Grimes case DLT_NULL: 185df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 186df8bae1dSRodney W. Grimes hlen = 0; 187df8bae1dSRodney W. Grimes break; 188df8bae1dSRodney W. Grimes 1894f53e3ccSKenjiro Cho case DLT_ATM_RFC1483: 1904f53e3ccSKenjiro Cho /* 1914f53e3ccSKenjiro Cho * en atm driver requires 4-byte atm pseudo header. 1924f53e3ccSKenjiro Cho * though it isn't standard, vpi:vci needs to be 1934f53e3ccSKenjiro Cho * specified anyway. 1944f53e3ccSKenjiro Cho */ 1954f53e3ccSKenjiro Cho sockp->sa_family = AF_UNSPEC; 1964f53e3ccSKenjiro Cho hlen = 12; /* XXX 4(ATM_PH) + 3(LLC) + 5(SNAP) */ 1974f53e3ccSKenjiro Cho break; 1984f53e3ccSKenjiro Cho 19930fa52a6SBrian Somers case DLT_PPP: 20030fa52a6SBrian Somers sockp->sa_family = AF_UNSPEC; 20130fa52a6SBrian Somers hlen = 4; /* This should match PPP_HDRLEN */ 20230fa52a6SBrian Somers break; 20330fa52a6SBrian Somers 204df8bae1dSRodney W. Grimes default: 205df8bae1dSRodney W. Grimes return (EIO); 206df8bae1dSRodney W. Grimes } 207df8bae1dSRodney W. Grimes 208df8bae1dSRodney W. Grimes len = uio->uio_resid; 209df8bae1dSRodney W. Grimes *datlen = len - hlen; 210df8bae1dSRodney W. Grimes if ((unsigned)len > MCLBYTES) 211df8bae1dSRodney W. Grimes return (EIO); 212df8bae1dSRodney W. Grimes 213963e4c2aSGarrett Wollman if (len > MHLEN) { 214a163d034SWarner Losh m = m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR); 21524a229f4SSam Leffler } else { 216a163d034SWarner Losh MGETHDR(m, M_TRYWAIT, MT_DATA); 217df8bae1dSRodney W. Grimes } 21824a229f4SSam Leffler if (m == NULL) 21924a229f4SSam Leffler return (ENOBUFS); 220963e4c2aSGarrett Wollman m->m_pkthdr.len = m->m_len = len; 221963e4c2aSGarrett Wollman m->m_pkthdr.rcvif = NULL; 222df8bae1dSRodney W. Grimes *mp = m; 22324a229f4SSam Leffler 224df8bae1dSRodney W. Grimes /* 225df8bae1dSRodney W. Grimes * Make room for link header. 226df8bae1dSRodney W. Grimes */ 227df8bae1dSRodney W. Grimes if (hlen != 0) { 2284f079e2fSGarrett Wollman m->m_pkthdr.len -= hlen; 229df8bae1dSRodney W. Grimes m->m_len -= hlen; 230df8bae1dSRodney W. Grimes #if BSD >= 199103 231df8bae1dSRodney W. Grimes m->m_data += hlen; /* XXX */ 232df8bae1dSRodney W. Grimes #else 233df8bae1dSRodney W. Grimes m->m_off += hlen; 234df8bae1dSRodney W. Grimes #endif 235c9524588SDag-Erling Smørgrav error = uiomove(sockp->sa_data, hlen, uio); 236df8bae1dSRodney W. Grimes if (error) 237df8bae1dSRodney W. Grimes goto bad; 238df8bae1dSRodney W. Grimes } 239c9524588SDag-Erling Smørgrav error = uiomove(mtod(m, void *), len - hlen, uio); 240df8bae1dSRodney W. Grimes if (!error) 241df8bae1dSRodney W. Grimes return (0); 242df8bae1dSRodney W. Grimes bad: 243df8bae1dSRodney W. Grimes m_freem(m); 244df8bae1dSRodney W. Grimes return (error); 245df8bae1dSRodney W. Grimes } 246df8bae1dSRodney W. Grimes 247df8bae1dSRodney W. Grimes /* 248df8bae1dSRodney W. Grimes * Attach file to the bpf interface, i.e. make d listen on bp. 249df8bae1dSRodney W. Grimes */ 250df8bae1dSRodney W. Grimes static void 251df8bae1dSRodney W. Grimes bpf_attachd(d, bp) 252df8bae1dSRodney W. Grimes struct bpf_d *d; 253df8bae1dSRodney W. Grimes struct bpf_if *bp; 254df8bae1dSRodney W. Grimes { 255df8bae1dSRodney W. Grimes /* 256df8bae1dSRodney W. Grimes * Point d at bp, and add d to the interface's list of listeners. 257df8bae1dSRodney W. Grimes * Finally, point the driver's bpf cookie at the interface so 258df8bae1dSRodney W. Grimes * it will divert packets to bpf. 259df8bae1dSRodney W. Grimes */ 260e7bb21b3SJonathan Lemon BPFIF_LOCK(bp); 261df8bae1dSRodney W. Grimes d->bd_bif = bp; 2624a3feeaaSRobert Watson LIST_INSERT_HEAD(&bp->bif_dlist, d, bd_next); 263df8bae1dSRodney W. Grimes 26424a229f4SSam Leffler *bp->bif_driverp = bp; 265e7bb21b3SJonathan Lemon BPFIF_UNLOCK(bp); 266df8bae1dSRodney W. Grimes } 267df8bae1dSRodney W. Grimes 268df8bae1dSRodney W. Grimes /* 269df8bae1dSRodney W. Grimes * Detach a file from its interface. 270df8bae1dSRodney W. Grimes */ 271df8bae1dSRodney W. Grimes static void 272df8bae1dSRodney W. Grimes bpf_detachd(d) 273df8bae1dSRodney W. Grimes struct bpf_d *d; 274df8bae1dSRodney W. Grimes { 2756e891d64SPoul-Henning Kamp int error; 276df8bae1dSRodney W. Grimes struct bpf_if *bp; 27746448b5aSRobert Watson struct ifnet *ifp; 278df8bae1dSRodney W. Grimes 279df8bae1dSRodney W. Grimes bp = d->bd_bif; 28046448b5aSRobert Watson BPFIF_LOCK(bp); 28146448b5aSRobert Watson BPFD_LOCK(d); 28246448b5aSRobert Watson ifp = d->bd_bif->bif_ifp; 28346448b5aSRobert Watson 28446448b5aSRobert Watson /* 28546448b5aSRobert Watson * Remove d from the interface's descriptor list. 28646448b5aSRobert Watson */ 28746448b5aSRobert Watson LIST_REMOVE(d, bd_next); 28846448b5aSRobert Watson 28946448b5aSRobert Watson /* 29046448b5aSRobert Watson * Let the driver know that there are no more listeners. 29146448b5aSRobert Watson */ 29246448b5aSRobert Watson if (LIST_EMPTY(&bp->bif_dlist)) 29346448b5aSRobert Watson *bp->bif_driverp = NULL; 29446448b5aSRobert Watson 295572bde2aSRobert Watson d->bd_bif = NULL; 29646448b5aSRobert Watson BPFD_UNLOCK(d); 29746448b5aSRobert Watson BPFIF_UNLOCK(bp); 29846448b5aSRobert Watson 299df8bae1dSRodney W. Grimes /* 300df8bae1dSRodney W. Grimes * Check if this descriptor had requested promiscuous mode. 301df8bae1dSRodney W. Grimes * If so, turn it off. 302df8bae1dSRodney W. Grimes */ 303df8bae1dSRodney W. Grimes if (d->bd_promisc) { 304df8bae1dSRodney W. Grimes d->bd_promisc = 0; 30546448b5aSRobert Watson error = ifpromisc(ifp, 0); 3066e891d64SPoul-Henning Kamp if (error != 0 && error != ENXIO) { 307df8bae1dSRodney W. Grimes /* 3086e891d64SPoul-Henning Kamp * ENXIO can happen if a pccard is unplugged 309df8bae1dSRodney W. Grimes * Something is really wrong if we were able to put 310df8bae1dSRodney W. Grimes * the driver into promiscuous mode, but can't 311df8bae1dSRodney W. Grimes * take it out. 312df8bae1dSRodney W. Grimes */ 3138eab61f3SSam Leffler if_printf(bp->bif_ifp, 3148eab61f3SSam Leffler "bpf_detach: ifpromisc failed (%d)\n", error); 3156e891d64SPoul-Henning Kamp } 316df8bae1dSRodney W. Grimes } 317df8bae1dSRodney W. Grimes } 318df8bae1dSRodney W. Grimes 319df8bae1dSRodney W. Grimes /* 320df8bae1dSRodney W. Grimes * Open ethernet device. Returns ENXIO for illegal minor device number, 321df8bae1dSRodney W. Grimes * EBUSY if file is open by another process. 322df8bae1dSRodney W. Grimes */ 323df8bae1dSRodney W. Grimes /* ARGSUSED */ 32487f6c662SJulian Elischer static int 325b40ce416SJulian Elischer bpfopen(dev, flags, fmt, td) 32689c9c53dSPoul-Henning Kamp struct cdev *dev; 32760039670SBruce Evans int flags; 32860039670SBruce Evans int fmt; 329b40ce416SJulian Elischer struct thread *td; 330df8bae1dSRodney W. Grimes { 331e7bb21b3SJonathan Lemon struct bpf_d *d; 332df8bae1dSRodney W. Grimes 333e7bb21b3SJonathan Lemon mtx_lock(&bpf_mtx); 334bd3a5320SPoul-Henning Kamp d = dev->si_drv1; 335df8bae1dSRodney W. Grimes /* 336df8bae1dSRodney W. Grimes * Each minor can be opened by only one process. If the requested 337df8bae1dSRodney W. Grimes * minor is in use, return EBUSY. 338df8bae1dSRodney W. Grimes */ 339d17d8184SRobert Watson if (d != NULL) { 340e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 341df8bae1dSRodney W. Grimes return (EBUSY); 342e7bb21b3SJonathan Lemon } 343e7bb21b3SJonathan Lemon dev->si_drv1 = (struct bpf_d *)~0; /* mark device in use */ 344e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 345e7bb21b3SJonathan Lemon 346d1d74c28SJohn Baldwin if ((dev->si_flags & SI_NAMED) == 0) 347b0d17ba6SPoul-Henning Kamp make_dev(&bpf_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 0600, 348b0d17ba6SPoul-Henning Kamp "bpf%d", dev2unit(dev)); 349a163d034SWarner Losh MALLOC(d, struct bpf_d *, sizeof(*d), M_BPF, M_WAITOK | M_ZERO); 350bd3a5320SPoul-Henning Kamp dev->si_drv1 = d; 351df8bae1dSRodney W. Grimes d->bd_bufsize = bpf_bufsize; 35200a83887SPaul Traina d->bd_sig = SIGIO; 3538ed3828cSRobert Watson d->bd_seesent = 1; 35482f4445dSRobert Watson #ifdef MAC 35582f4445dSRobert Watson mac_init_bpfdesc(d); 35682f4445dSRobert Watson mac_create_bpfdesc(td->td_ucred, d); 35782f4445dSRobert Watson #endif 3586008862bSJohn Baldwin mtx_init(&d->bd_mtx, devtoname(dev), "bpf cdev lock", MTX_DEF); 35931199c84SGleb Smirnoff callout_init(&d->bd_callout, NET_CALLOUT_MPSAFE); 360ad3b9257SJohn-Mark Gurney knlist_init(&d->bd_sel.si_note, &d->bd_mtx); 361df8bae1dSRodney W. Grimes 362df8bae1dSRodney W. Grimes return (0); 363df8bae1dSRodney W. Grimes } 364df8bae1dSRodney W. Grimes 365df8bae1dSRodney W. Grimes /* 366df8bae1dSRodney W. Grimes * Close the descriptor by detaching it from its interface, 367df8bae1dSRodney W. Grimes * deallocating its buffers, and marking it free. 368df8bae1dSRodney W. Grimes */ 369df8bae1dSRodney W. Grimes /* ARGSUSED */ 37087f6c662SJulian Elischer static int 371b40ce416SJulian Elischer bpfclose(dev, flags, fmt, td) 37289c9c53dSPoul-Henning Kamp struct cdev *dev; 37360039670SBruce Evans int flags; 37460039670SBruce Evans int fmt; 375b40ce416SJulian Elischer struct thread *td; 376df8bae1dSRodney W. Grimes { 377e7bb21b3SJonathan Lemon struct bpf_d *d = dev->si_drv1; 378df8bae1dSRodney W. Grimes 37981bda851SJohn Polstra BPFD_LOCK(d); 38081bda851SJohn Polstra if (d->bd_state == BPF_WAITING) 38181bda851SJohn Polstra callout_stop(&d->bd_callout); 38281bda851SJohn Polstra d->bd_state = BPF_IDLE; 38381bda851SJohn Polstra BPFD_UNLOCK(d); 384e649887bSAlfred Perlstein funsetown(&d->bd_sigio); 385e7bb21b3SJonathan Lemon mtx_lock(&bpf_mtx); 386df8bae1dSRodney W. Grimes if (d->bd_bif) 387df8bae1dSRodney W. Grimes bpf_detachd(d); 388e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 38982f4445dSRobert Watson #ifdef MAC 39082f4445dSRobert Watson mac_destroy_bpfdesc(d); 39182f4445dSRobert Watson #endif /* MAC */ 392ad3b9257SJohn-Mark Gurney knlist_destroy(&d->bd_sel.si_note); 393df8bae1dSRodney W. Grimes bpf_freed(d); 394d17d8184SRobert Watson dev->si_drv1 = NULL; 395d722be54SLuigi Rizzo free(d, M_BPF); 396df8bae1dSRodney W. Grimes 397df8bae1dSRodney W. Grimes return (0); 398df8bae1dSRodney W. Grimes } 399df8bae1dSRodney W. Grimes 400df8bae1dSRodney W. Grimes 401df8bae1dSRodney W. Grimes /* 402df8bae1dSRodney W. Grimes * Rotate the packet buffers in descriptor d. Move the store buffer 403df8bae1dSRodney W. Grimes * into the hold slot, and the free buffer into the store slot. 404df8bae1dSRodney W. Grimes * Zero the length of the new store buffer. 405df8bae1dSRodney W. Grimes */ 406df8bae1dSRodney W. Grimes #define ROTATE_BUFFERS(d) \ 407df8bae1dSRodney W. Grimes (d)->bd_hbuf = (d)->bd_sbuf; \ 408df8bae1dSRodney W. Grimes (d)->bd_hlen = (d)->bd_slen; \ 409df8bae1dSRodney W. Grimes (d)->bd_sbuf = (d)->bd_fbuf; \ 410df8bae1dSRodney W. Grimes (d)->bd_slen = 0; \ 411d17d8184SRobert Watson (d)->bd_fbuf = NULL; 412df8bae1dSRodney W. Grimes /* 413df8bae1dSRodney W. Grimes * bpfread - read next chunk of packets from buffers 414df8bae1dSRodney W. Grimes */ 41587f6c662SJulian Elischer static int 41660039670SBruce Evans bpfread(dev, uio, ioflag) 41789c9c53dSPoul-Henning Kamp struct cdev *dev; 4188994a245SDag-Erling Smørgrav struct uio *uio; 41960039670SBruce Evans int ioflag; 420df8bae1dSRodney W. Grimes { 421e7bb21b3SJonathan Lemon struct bpf_d *d = dev->si_drv1; 42281bda851SJohn Polstra int timed_out; 423df8bae1dSRodney W. Grimes int error; 424df8bae1dSRodney W. Grimes 425df8bae1dSRodney W. Grimes /* 426df8bae1dSRodney W. Grimes * Restrict application to use a buffer the same size as 427df8bae1dSRodney W. Grimes * as kernel buffers. 428df8bae1dSRodney W. Grimes */ 429df8bae1dSRodney W. Grimes if (uio->uio_resid != d->bd_bufsize) 430df8bae1dSRodney W. Grimes return (EINVAL); 431df8bae1dSRodney W. Grimes 432e7bb21b3SJonathan Lemon BPFD_LOCK(d); 43381bda851SJohn Polstra if (d->bd_state == BPF_WAITING) 43481bda851SJohn Polstra callout_stop(&d->bd_callout); 43581bda851SJohn Polstra timed_out = (d->bd_state == BPF_TIMED_OUT); 43681bda851SJohn Polstra d->bd_state = BPF_IDLE; 437df8bae1dSRodney W. Grimes /* 438df8bae1dSRodney W. Grimes * If the hold buffer is empty, then do a timed sleep, which 439df8bae1dSRodney W. Grimes * ends when the timeout expires or when enough packets 440df8bae1dSRodney W. Grimes * have arrived to fill the store buffer. 441df8bae1dSRodney W. Grimes */ 442572bde2aSRobert Watson while (d->bd_hbuf == NULL) { 44381bda851SJohn Polstra if ((d->bd_immediate || timed_out) && d->bd_slen != 0) { 444df8bae1dSRodney W. Grimes /* 445df8bae1dSRodney W. Grimes * A packet(s) either arrived since the previous 446df8bae1dSRodney W. Grimes * read or arrived while we were asleep. 447df8bae1dSRodney W. Grimes * Rotate the buffers and return what's here. 448df8bae1dSRodney W. Grimes */ 449df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 450df8bae1dSRodney W. Grimes break; 451df8bae1dSRodney W. Grimes } 452de5d9935SRobert Watson 453de5d9935SRobert Watson /* 454de5d9935SRobert Watson * No data is available, check to see if the bpf device 455de5d9935SRobert Watson * is still pointed at a real interface. If not, return 456de5d9935SRobert Watson * ENXIO so that the userland process knows to rebind 457de5d9935SRobert Watson * it before using it again. 458de5d9935SRobert Watson */ 459de5d9935SRobert Watson if (d->bd_bif == NULL) { 460e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 461de5d9935SRobert Watson return (ENXIO); 462de5d9935SRobert Watson } 463de5d9935SRobert Watson 464e76eee55SPoul-Henning Kamp if (ioflag & O_NONBLOCK) { 465e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 466fba3cfdeSJohn Polstra return (EWOULDBLOCK); 467fba3cfdeSJohn Polstra } 468521f364bSDag-Erling Smørgrav error = msleep(d, &d->bd_mtx, PRINET|PCATCH, 469e7bb21b3SJonathan Lemon "bpf", d->bd_rtout); 470df8bae1dSRodney W. Grimes if (error == EINTR || error == ERESTART) { 471e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 472df8bae1dSRodney W. Grimes return (error); 473df8bae1dSRodney W. Grimes } 474df8bae1dSRodney W. Grimes if (error == EWOULDBLOCK) { 475df8bae1dSRodney W. Grimes /* 476df8bae1dSRodney W. Grimes * On a timeout, return what's in the buffer, 477df8bae1dSRodney W. Grimes * which may be nothing. If there is something 478df8bae1dSRodney W. Grimes * in the store buffer, we can rotate the buffers. 479df8bae1dSRodney W. Grimes */ 480df8bae1dSRodney W. Grimes if (d->bd_hbuf) 481df8bae1dSRodney W. Grimes /* 482df8bae1dSRodney W. Grimes * We filled up the buffer in between 483df8bae1dSRodney W. Grimes * getting the timeout and arriving 484df8bae1dSRodney W. Grimes * here, so we don't need to rotate. 485df8bae1dSRodney W. Grimes */ 486df8bae1dSRodney W. Grimes break; 487df8bae1dSRodney W. Grimes 488df8bae1dSRodney W. Grimes if (d->bd_slen == 0) { 489e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 490df8bae1dSRodney W. Grimes return (0); 491df8bae1dSRodney W. Grimes } 492df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 493df8bae1dSRodney W. Grimes break; 494df8bae1dSRodney W. Grimes } 495df8bae1dSRodney W. Grimes } 496df8bae1dSRodney W. Grimes /* 497df8bae1dSRodney W. Grimes * At this point, we know we have something in the hold slot. 498df8bae1dSRodney W. Grimes */ 499e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 500df8bae1dSRodney W. Grimes 501df8bae1dSRodney W. Grimes /* 502df8bae1dSRodney W. Grimes * Move data from hold buffer into user space. 503df8bae1dSRodney W. Grimes * We know the entire buffer is transferred since 504df8bae1dSRodney W. Grimes * we checked above that the read buffer is bpf_bufsize bytes. 505df8bae1dSRodney W. Grimes */ 506e7bb21b3SJonathan Lemon error = uiomove(d->bd_hbuf, d->bd_hlen, uio); 507df8bae1dSRodney W. Grimes 508e7bb21b3SJonathan Lemon BPFD_LOCK(d); 509df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 510572bde2aSRobert Watson d->bd_hbuf = NULL; 511df8bae1dSRodney W. Grimes d->bd_hlen = 0; 512e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 513df8bae1dSRodney W. Grimes 514df8bae1dSRodney W. Grimes return (error); 515df8bae1dSRodney W. Grimes } 516df8bae1dSRodney W. Grimes 517df8bae1dSRodney W. Grimes 518df8bae1dSRodney W. Grimes /* 519df8bae1dSRodney W. Grimes * If there are processes sleeping on this descriptor, wake them up. 520df8bae1dSRodney W. Grimes */ 521e7bb21b3SJonathan Lemon static __inline void 522df8bae1dSRodney W. Grimes bpf_wakeup(d) 5238994a245SDag-Erling Smørgrav struct bpf_d *d; 524df8bae1dSRodney W. Grimes { 52581bda851SJohn Polstra if (d->bd_state == BPF_WAITING) { 52681bda851SJohn Polstra callout_stop(&d->bd_callout); 52781bda851SJohn Polstra d->bd_state = BPF_IDLE; 52881bda851SJohn Polstra } 529521f364bSDag-Erling Smørgrav wakeup(d); 530831d27a9SDon Lewis if (d->bd_async && d->bd_sig && d->bd_sigio) 531f1320723SAlfred Perlstein pgsigio(&d->bd_sigio, d->bd_sig, 0); 53200a83887SPaul Traina 533512824f8SSeigo Tanimura selwakeuppri(&d->bd_sel, PRINET); 534ad3b9257SJohn-Mark Gurney KNOTE_LOCKED(&d->bd_sel.si_note, 0); 535df8bae1dSRodney W. Grimes } 536df8bae1dSRodney W. Grimes 53781bda851SJohn Polstra static void 53881bda851SJohn Polstra bpf_timed_out(arg) 53981bda851SJohn Polstra void *arg; 54081bda851SJohn Polstra { 54181bda851SJohn Polstra struct bpf_d *d = (struct bpf_d *)arg; 54281bda851SJohn Polstra 54381bda851SJohn Polstra BPFD_LOCK(d); 54481bda851SJohn Polstra if (d->bd_state == BPF_WAITING) { 54581bda851SJohn Polstra d->bd_state = BPF_TIMED_OUT; 54681bda851SJohn Polstra if (d->bd_slen != 0) 54781bda851SJohn Polstra bpf_wakeup(d); 54881bda851SJohn Polstra } 54981bda851SJohn Polstra BPFD_UNLOCK(d); 55081bda851SJohn Polstra } 55181bda851SJohn Polstra 55287f6c662SJulian Elischer static int 55360039670SBruce Evans bpfwrite(dev, uio, ioflag) 55489c9c53dSPoul-Henning Kamp struct cdev *dev; 555df8bae1dSRodney W. Grimes struct uio *uio; 55660039670SBruce Evans int ioflag; 557df8bae1dSRodney W. Grimes { 558e7bb21b3SJonathan Lemon struct bpf_d *d = dev->si_drv1; 559df8bae1dSRodney W. Grimes struct ifnet *ifp; 560df8bae1dSRodney W. Grimes struct mbuf *m; 561e7bb21b3SJonathan Lemon int error; 5628240bf1eSRobert Watson struct sockaddr dst; 563df8bae1dSRodney W. Grimes int datlen; 564df8bae1dSRodney W. Grimes 565572bde2aSRobert Watson if (d->bd_bif == NULL) 566df8bae1dSRodney W. Grimes return (ENXIO); 567df8bae1dSRodney W. Grimes 568df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 569df8bae1dSRodney W. Grimes 5703518d220SSam Leffler if ((ifp->if_flags & IFF_UP) == 0) 5713518d220SSam Leffler return (ENETDOWN); 5723518d220SSam Leffler 573df8bae1dSRodney W. Grimes if (uio->uio_resid == 0) 574df8bae1dSRodney W. Grimes return (0); 575df8bae1dSRodney W. Grimes 5768240bf1eSRobert Watson bzero(&dst, sizeof(dst)); 577df8bae1dSRodney W. Grimes error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, &dst, &datlen); 578df8bae1dSRodney W. Grimes if (error) 579df8bae1dSRodney W. Grimes return (error); 580df8bae1dSRodney W. Grimes 58177fc70c1SPawel Jakub Dawidek if (datlen > ifp->if_mtu) { 58277fc70c1SPawel Jakub Dawidek m_freem(m); 583df8bae1dSRodney W. Grimes return (EMSGSIZE); 58477fc70c1SPawel Jakub Dawidek } 585df8bae1dSRodney W. Grimes 586114ae644SMike Smith if (d->bd_hdrcmplt) 587114ae644SMike Smith dst.sa_family = pseudo_AF_HDRCMPLT; 588114ae644SMike Smith 58982f4445dSRobert Watson #ifdef MAC 590f747d2ddSRobert Watson BPFD_LOCK(d); 59182f4445dSRobert Watson mac_create_mbuf_from_bpfdesc(d, m); 592f747d2ddSRobert Watson BPFD_UNLOCK(d); 59382f4445dSRobert Watson #endif 594b8f9429dSRobert Watson NET_LOCK_GIANT(); 595572bde2aSRobert Watson error = (*ifp->if_output)(ifp, m, &dst, NULL); 596b8f9429dSRobert Watson NET_UNLOCK_GIANT(); 597df8bae1dSRodney W. Grimes /* 598df8bae1dSRodney W. Grimes * The driver frees the mbuf. 599df8bae1dSRodney W. Grimes */ 600df8bae1dSRodney W. Grimes return (error); 601df8bae1dSRodney W. Grimes } 602df8bae1dSRodney W. Grimes 603df8bae1dSRodney W. Grimes /* 604df8bae1dSRodney W. Grimes * Reset a descriptor by flushing its packet buffer and clearing the 605e7bb21b3SJonathan Lemon * receive and drop counts. 606df8bae1dSRodney W. Grimes */ 607df8bae1dSRodney W. Grimes static void 608df8bae1dSRodney W. Grimes reset_d(d) 609df8bae1dSRodney W. Grimes struct bpf_d *d; 610df8bae1dSRodney W. Grimes { 611e7bb21b3SJonathan Lemon 612e7bb21b3SJonathan Lemon mtx_assert(&d->bd_mtx, MA_OWNED); 613df8bae1dSRodney W. Grimes if (d->bd_hbuf) { 614df8bae1dSRodney W. Grimes /* Free the hold buffer. */ 615df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 616572bde2aSRobert Watson d->bd_hbuf = NULL; 617df8bae1dSRodney W. Grimes } 618df8bae1dSRodney W. Grimes d->bd_slen = 0; 619df8bae1dSRodney W. Grimes d->bd_hlen = 0; 620df8bae1dSRodney W. Grimes d->bd_rcount = 0; 621df8bae1dSRodney W. Grimes d->bd_dcount = 0; 622df8bae1dSRodney W. Grimes } 623df8bae1dSRodney W. Grimes 624df8bae1dSRodney W. Grimes /* 625df8bae1dSRodney W. Grimes * FIONREAD Check for read packet available. 626df8bae1dSRodney W. Grimes * SIOCGIFADDR Get interface address - convenient hook to driver. 627df8bae1dSRodney W. Grimes * BIOCGBLEN Get buffer len [for read()]. 628df8bae1dSRodney W. Grimes * BIOCSETF Set ethernet read filter. 629df8bae1dSRodney W. Grimes * BIOCFLUSH Flush read packet buffer. 630df8bae1dSRodney W. Grimes * BIOCPROMISC Put interface into promiscuous mode. 631df8bae1dSRodney W. Grimes * BIOCGDLT Get link layer type. 632df8bae1dSRodney W. Grimes * BIOCGETIF Get interface name. 633df8bae1dSRodney W. Grimes * BIOCSETIF Set interface. 634df8bae1dSRodney W. Grimes * BIOCSRTIMEOUT Set read timeout. 635df8bae1dSRodney W. Grimes * BIOCGRTIMEOUT Get read timeout. 636df8bae1dSRodney W. Grimes * BIOCGSTATS Get packet stats. 637df8bae1dSRodney W. Grimes * BIOCIMMEDIATE Set immediate mode. 638df8bae1dSRodney W. Grimes * BIOCVERSION Get filter language version. 639114ae644SMike Smith * BIOCGHDRCMPLT Get "header already complete" flag 640114ae644SMike Smith * BIOCSHDRCMPLT Set "header already complete" flag 6418ed3828cSRobert Watson * BIOCGSEESENT Get "see packets sent" flag 6428ed3828cSRobert Watson * BIOCSSEESENT Set "see packets sent" flag 643df8bae1dSRodney W. Grimes */ 644df8bae1dSRodney W. Grimes /* ARGSUSED */ 64587f6c662SJulian Elischer static int 646b40ce416SJulian Elischer bpfioctl(dev, cmd, addr, flags, td) 64789c9c53dSPoul-Henning Kamp struct cdev *dev; 648ecbb00a2SDoug Rabson u_long cmd; 649df8bae1dSRodney W. Grimes caddr_t addr; 65060039670SBruce Evans int flags; 651b40ce416SJulian Elischer struct thread *td; 652df8bae1dSRodney W. Grimes { 653e7bb21b3SJonathan Lemon struct bpf_d *d = dev->si_drv1; 654e7bb21b3SJonathan Lemon int error = 0; 655df8bae1dSRodney W. Grimes 65681bda851SJohn Polstra BPFD_LOCK(d); 65781bda851SJohn Polstra if (d->bd_state == BPF_WAITING) 65881bda851SJohn Polstra callout_stop(&d->bd_callout); 65981bda851SJohn Polstra d->bd_state = BPF_IDLE; 66081bda851SJohn Polstra BPFD_UNLOCK(d); 66181bda851SJohn Polstra 662df8bae1dSRodney W. Grimes switch (cmd) { 663df8bae1dSRodney W. Grimes 664df8bae1dSRodney W. Grimes default: 665df8bae1dSRodney W. Grimes error = EINVAL; 666df8bae1dSRodney W. Grimes break; 667df8bae1dSRodney W. Grimes 668df8bae1dSRodney W. Grimes /* 669df8bae1dSRodney W. Grimes * Check for read packet available. 670df8bae1dSRodney W. Grimes */ 671df8bae1dSRodney W. Grimes case FIONREAD: 672df8bae1dSRodney W. Grimes { 673df8bae1dSRodney W. Grimes int n; 674df8bae1dSRodney W. Grimes 675e7bb21b3SJonathan Lemon BPFD_LOCK(d); 676df8bae1dSRodney W. Grimes n = d->bd_slen; 677df8bae1dSRodney W. Grimes if (d->bd_hbuf) 678df8bae1dSRodney W. Grimes n += d->bd_hlen; 679e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 680df8bae1dSRodney W. Grimes 681df8bae1dSRodney W. Grimes *(int *)addr = n; 682df8bae1dSRodney W. Grimes break; 683df8bae1dSRodney W. Grimes } 684df8bae1dSRodney W. Grimes 685df8bae1dSRodney W. Grimes case SIOCGIFADDR: 686df8bae1dSRodney W. Grimes { 687df8bae1dSRodney W. Grimes struct ifnet *ifp; 688df8bae1dSRodney W. Grimes 689572bde2aSRobert Watson if (d->bd_bif == NULL) 690df8bae1dSRodney W. Grimes error = EINVAL; 691df8bae1dSRodney W. Grimes else { 692df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 693df8bae1dSRodney W. Grimes error = (*ifp->if_ioctl)(ifp, cmd, addr); 694df8bae1dSRodney W. Grimes } 695df8bae1dSRodney W. Grimes break; 696df8bae1dSRodney W. Grimes } 697df8bae1dSRodney W. Grimes 698df8bae1dSRodney W. Grimes /* 699df8bae1dSRodney W. Grimes * Get buffer len [for read()]. 700df8bae1dSRodney W. Grimes */ 701df8bae1dSRodney W. Grimes case BIOCGBLEN: 702df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bufsize; 703df8bae1dSRodney W. Grimes break; 704df8bae1dSRodney W. Grimes 705df8bae1dSRodney W. Grimes /* 706df8bae1dSRodney W. Grimes * Set buffer length. 707df8bae1dSRodney W. Grimes */ 708df8bae1dSRodney W. Grimes case BIOCSBLEN: 709572bde2aSRobert Watson if (d->bd_bif != NULL) 710df8bae1dSRodney W. Grimes error = EINVAL; 711df8bae1dSRodney W. Grimes else { 7128994a245SDag-Erling Smørgrav u_int size = *(u_int *)addr; 713df8bae1dSRodney W. Grimes 714eba2a1aeSPoul-Henning Kamp if (size > bpf_maxbufsize) 715eba2a1aeSPoul-Henning Kamp *(u_int *)addr = size = bpf_maxbufsize; 716df8bae1dSRodney W. Grimes else if (size < BPF_MINBUFSIZE) 717df8bae1dSRodney W. Grimes *(u_int *)addr = size = BPF_MINBUFSIZE; 718df8bae1dSRodney W. Grimes d->bd_bufsize = size; 719df8bae1dSRodney W. Grimes } 720df8bae1dSRodney W. Grimes break; 721df8bae1dSRodney W. Grimes 722df8bae1dSRodney W. Grimes /* 723df8bae1dSRodney W. Grimes * Set link layer read filter. 724df8bae1dSRodney W. Grimes */ 725df8bae1dSRodney W. Grimes case BIOCSETF: 726df8bae1dSRodney W. Grimes error = bpf_setf(d, (struct bpf_program *)addr); 727df8bae1dSRodney W. Grimes break; 728df8bae1dSRodney W. Grimes 729df8bae1dSRodney W. Grimes /* 730df8bae1dSRodney W. Grimes * Flush read packet buffer. 731df8bae1dSRodney W. Grimes */ 732df8bae1dSRodney W. Grimes case BIOCFLUSH: 733e7bb21b3SJonathan Lemon BPFD_LOCK(d); 734df8bae1dSRodney W. Grimes reset_d(d); 735e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 736df8bae1dSRodney W. Grimes break; 737df8bae1dSRodney W. Grimes 738df8bae1dSRodney W. Grimes /* 739df8bae1dSRodney W. Grimes * Put interface into promiscuous mode. 740df8bae1dSRodney W. Grimes */ 741df8bae1dSRodney W. Grimes case BIOCPROMISC: 742572bde2aSRobert Watson if (d->bd_bif == NULL) { 743df8bae1dSRodney W. Grimes /* 744df8bae1dSRodney W. Grimes * No interface attached yet. 745df8bae1dSRodney W. Grimes */ 746df8bae1dSRodney W. Grimes error = EINVAL; 747df8bae1dSRodney W. Grimes break; 748df8bae1dSRodney W. Grimes } 749df8bae1dSRodney W. Grimes if (d->bd_promisc == 0) { 750e7bb21b3SJonathan Lemon mtx_lock(&Giant); 751df8bae1dSRodney W. Grimes error = ifpromisc(d->bd_bif->bif_ifp, 1); 752e7bb21b3SJonathan Lemon mtx_unlock(&Giant); 753df8bae1dSRodney W. Grimes if (error == 0) 754df8bae1dSRodney W. Grimes d->bd_promisc = 1; 755df8bae1dSRodney W. Grimes } 756df8bae1dSRodney W. Grimes break; 757df8bae1dSRodney W. Grimes 758df8bae1dSRodney W. Grimes /* 7598eab61f3SSam Leffler * Get current data link type. 760df8bae1dSRodney W. Grimes */ 761df8bae1dSRodney W. Grimes case BIOCGDLT: 762572bde2aSRobert Watson if (d->bd_bif == NULL) 763df8bae1dSRodney W. Grimes error = EINVAL; 764df8bae1dSRodney W. Grimes else 765df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bif->bif_dlt; 766df8bae1dSRodney W. Grimes break; 767df8bae1dSRodney W. Grimes 768df8bae1dSRodney W. Grimes /* 7698eab61f3SSam Leffler * Get a list of supported data link types. 7708eab61f3SSam Leffler */ 7718eab61f3SSam Leffler case BIOCGDLTLIST: 772572bde2aSRobert Watson if (d->bd_bif == NULL) 7738eab61f3SSam Leffler error = EINVAL; 7748eab61f3SSam Leffler else 7758eab61f3SSam Leffler error = bpf_getdltlist(d, (struct bpf_dltlist *)addr); 7768eab61f3SSam Leffler break; 7778eab61f3SSam Leffler 7788eab61f3SSam Leffler /* 7798eab61f3SSam Leffler * Set data link type. 7808eab61f3SSam Leffler */ 7818eab61f3SSam Leffler case BIOCSDLT: 782572bde2aSRobert Watson if (d->bd_bif == NULL) 7838eab61f3SSam Leffler error = EINVAL; 7848eab61f3SSam Leffler else 7858eab61f3SSam Leffler error = bpf_setdlt(d, *(u_int *)addr); 7868eab61f3SSam Leffler break; 7878eab61f3SSam Leffler 7888eab61f3SSam Leffler /* 7891dd0feaaSArchie Cobbs * Get interface name. 790df8bae1dSRodney W. Grimes */ 791df8bae1dSRodney W. Grimes case BIOCGETIF: 792572bde2aSRobert Watson if (d->bd_bif == NULL) 793df8bae1dSRodney W. Grimes error = EINVAL; 7941dd0feaaSArchie Cobbs else { 7951dd0feaaSArchie Cobbs struct ifnet *const ifp = d->bd_bif->bif_ifp; 7961dd0feaaSArchie Cobbs struct ifreq *const ifr = (struct ifreq *)addr; 7971dd0feaaSArchie Cobbs 7989bf40edeSBrooks Davis strlcpy(ifr->ifr_name, ifp->if_xname, 7999bf40edeSBrooks Davis sizeof(ifr->ifr_name)); 8001dd0feaaSArchie Cobbs } 801df8bae1dSRodney W. Grimes break; 802df8bae1dSRodney W. Grimes 803df8bae1dSRodney W. Grimes /* 804df8bae1dSRodney W. Grimes * Set interface. 805df8bae1dSRodney W. Grimes */ 806df8bae1dSRodney W. Grimes case BIOCSETIF: 807df8bae1dSRodney W. Grimes error = bpf_setif(d, (struct ifreq *)addr); 808df8bae1dSRodney W. Grimes break; 809df8bae1dSRodney W. Grimes 810df8bae1dSRodney W. Grimes /* 811df8bae1dSRodney W. Grimes * Set read timeout. 812df8bae1dSRodney W. Grimes */ 813df8bae1dSRodney W. Grimes case BIOCSRTIMEOUT: 814df8bae1dSRodney W. Grimes { 815df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 816df8bae1dSRodney W. Grimes 817bdc2cdc5SAlexander Langer /* 818bdc2cdc5SAlexander Langer * Subtract 1 tick from tvtohz() since this isn't 819bdc2cdc5SAlexander Langer * a one-shot timer. 820bdc2cdc5SAlexander Langer */ 821bdc2cdc5SAlexander Langer if ((error = itimerfix(tv)) == 0) 822bdc2cdc5SAlexander Langer d->bd_rtout = tvtohz(tv) - 1; 823df8bae1dSRodney W. Grimes break; 824df8bae1dSRodney W. Grimes } 825df8bae1dSRodney W. Grimes 826df8bae1dSRodney W. Grimes /* 827df8bae1dSRodney W. Grimes * Get read timeout. 828df8bae1dSRodney W. Grimes */ 829df8bae1dSRodney W. Grimes case BIOCGRTIMEOUT: 830df8bae1dSRodney W. Grimes { 831df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 832df8bae1dSRodney W. Grimes 833bdc2cdc5SAlexander Langer tv->tv_sec = d->bd_rtout / hz; 834bdc2cdc5SAlexander Langer tv->tv_usec = (d->bd_rtout % hz) * tick; 835df8bae1dSRodney W. Grimes break; 836df8bae1dSRodney W. Grimes } 837df8bae1dSRodney W. Grimes 838df8bae1dSRodney W. Grimes /* 839df8bae1dSRodney W. Grimes * Get packet stats. 840df8bae1dSRodney W. Grimes */ 841df8bae1dSRodney W. Grimes case BIOCGSTATS: 842df8bae1dSRodney W. Grimes { 843df8bae1dSRodney W. Grimes struct bpf_stat *bs = (struct bpf_stat *)addr; 844df8bae1dSRodney W. Grimes 845df8bae1dSRodney W. Grimes bs->bs_recv = d->bd_rcount; 846df8bae1dSRodney W. Grimes bs->bs_drop = d->bd_dcount; 847df8bae1dSRodney W. Grimes break; 848df8bae1dSRodney W. Grimes } 849df8bae1dSRodney W. Grimes 850df8bae1dSRodney W. Grimes /* 851df8bae1dSRodney W. Grimes * Set immediate mode. 852df8bae1dSRodney W. Grimes */ 853df8bae1dSRodney W. Grimes case BIOCIMMEDIATE: 854df8bae1dSRodney W. Grimes d->bd_immediate = *(u_int *)addr; 855df8bae1dSRodney W. Grimes break; 856df8bae1dSRodney W. Grimes 857df8bae1dSRodney W. Grimes case BIOCVERSION: 858df8bae1dSRodney W. Grimes { 859df8bae1dSRodney W. Grimes struct bpf_version *bv = (struct bpf_version *)addr; 860df8bae1dSRodney W. Grimes 861df8bae1dSRodney W. Grimes bv->bv_major = BPF_MAJOR_VERSION; 862df8bae1dSRodney W. Grimes bv->bv_minor = BPF_MINOR_VERSION; 863df8bae1dSRodney W. Grimes break; 864df8bae1dSRodney W. Grimes } 86500a83887SPaul Traina 866114ae644SMike Smith /* 867114ae644SMike Smith * Get "header already complete" flag 868114ae644SMike Smith */ 869114ae644SMike Smith case BIOCGHDRCMPLT: 870114ae644SMike Smith *(u_int *)addr = d->bd_hdrcmplt; 871114ae644SMike Smith break; 872114ae644SMike Smith 873114ae644SMike Smith /* 874114ae644SMike Smith * Set "header already complete" flag 875114ae644SMike Smith */ 876114ae644SMike Smith case BIOCSHDRCMPLT: 877114ae644SMike Smith d->bd_hdrcmplt = *(u_int *)addr ? 1 : 0; 878114ae644SMike Smith break; 879114ae644SMike Smith 8808ed3828cSRobert Watson /* 8818ed3828cSRobert Watson * Get "see sent packets" flag 8828ed3828cSRobert Watson */ 8838ed3828cSRobert Watson case BIOCGSEESENT: 8848ed3828cSRobert Watson *(u_int *)addr = d->bd_seesent; 8858ed3828cSRobert Watson break; 8868ed3828cSRobert Watson 8878ed3828cSRobert Watson /* 8888ed3828cSRobert Watson * Set "see sent packets" flag 8898ed3828cSRobert Watson */ 8908ed3828cSRobert Watson case BIOCSSEESENT: 8918ed3828cSRobert Watson d->bd_seesent = *(u_int *)addr; 8928ed3828cSRobert Watson break; 8938ed3828cSRobert Watson 89400a83887SPaul Traina case FIONBIO: /* Non-blocking I/O */ 89500a83887SPaul Traina break; 89600a83887SPaul Traina 89700a83887SPaul Traina case FIOASYNC: /* Send signal on receive packets */ 89800a83887SPaul Traina d->bd_async = *(int *)addr; 89900a83887SPaul Traina break; 90000a83887SPaul Traina 901831d27a9SDon Lewis case FIOSETOWN: 902831d27a9SDon Lewis error = fsetown(*(int *)addr, &d->bd_sigio); 90300a83887SPaul Traina break; 90400a83887SPaul Traina 905831d27a9SDon Lewis case FIOGETOWN: 90691e97a82SDon Lewis *(int *)addr = fgetown(&d->bd_sigio); 907831d27a9SDon Lewis break; 908831d27a9SDon Lewis 909831d27a9SDon Lewis /* This is deprecated, FIOSETOWN should be used instead. */ 910831d27a9SDon Lewis case TIOCSPGRP: 911831d27a9SDon Lewis error = fsetown(-(*(int *)addr), &d->bd_sigio); 912831d27a9SDon Lewis break; 913831d27a9SDon Lewis 914831d27a9SDon Lewis /* This is deprecated, FIOGETOWN should be used instead. */ 91500a83887SPaul Traina case TIOCGPGRP: 91691e97a82SDon Lewis *(int *)addr = -fgetown(&d->bd_sigio); 91700a83887SPaul Traina break; 91800a83887SPaul Traina 91900a83887SPaul Traina case BIOCSRSIG: /* Set receive signal */ 92000a83887SPaul Traina { 92100a83887SPaul Traina u_int sig; 92200a83887SPaul Traina 92300a83887SPaul Traina sig = *(u_int *)addr; 92400a83887SPaul Traina 92500a83887SPaul Traina if (sig >= NSIG) 92600a83887SPaul Traina error = EINVAL; 92700a83887SPaul Traina else 92800a83887SPaul Traina d->bd_sig = sig; 92900a83887SPaul Traina break; 93000a83887SPaul Traina } 93100a83887SPaul Traina case BIOCGRSIG: 93200a83887SPaul Traina *(u_int *)addr = d->bd_sig; 93300a83887SPaul Traina break; 934df8bae1dSRodney W. Grimes } 935df8bae1dSRodney W. Grimes return (error); 936df8bae1dSRodney W. Grimes } 937df8bae1dSRodney W. Grimes 938df8bae1dSRodney W. Grimes /* 939df8bae1dSRodney W. Grimes * Set d's packet filter program to fp. If this file already has a filter, 940df8bae1dSRodney W. Grimes * free it and replace it. Returns EINVAL for bogus requests. 941df8bae1dSRodney W. Grimes */ 942f708ef1bSPoul-Henning Kamp static int 943df8bae1dSRodney W. Grimes bpf_setf(d, fp) 944df8bae1dSRodney W. Grimes struct bpf_d *d; 945df8bae1dSRodney W. Grimes struct bpf_program *fp; 946df8bae1dSRodney W. Grimes { 947df8bae1dSRodney W. Grimes struct bpf_insn *fcode, *old; 948df8bae1dSRodney W. Grimes u_int flen, size; 949df8bae1dSRodney W. Grimes 950572bde2aSRobert Watson if (fp->bf_insns == NULL) { 951df8bae1dSRodney W. Grimes if (fp->bf_len != 0) 952df8bae1dSRodney W. Grimes return (EINVAL); 953e7bb21b3SJonathan Lemon BPFD_LOCK(d); 954a8e93fb7SRobert Watson old = d->bd_filter; 955572bde2aSRobert Watson d->bd_filter = NULL; 956df8bae1dSRodney W. Grimes reset_d(d); 957e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 958572bde2aSRobert Watson if (old != NULL) 959bd3a5320SPoul-Henning Kamp free((caddr_t)old, M_BPF); 960df8bae1dSRodney W. Grimes return (0); 961df8bae1dSRodney W. Grimes } 962df8bae1dSRodney W. Grimes flen = fp->bf_len; 963df8bae1dSRodney W. Grimes if (flen > BPF_MAXINSNS) 964df8bae1dSRodney W. Grimes return (EINVAL); 965df8bae1dSRodney W. Grimes 966df8bae1dSRodney W. Grimes size = flen * sizeof(*fp->bf_insns); 967a163d034SWarner Losh fcode = (struct bpf_insn *)malloc(size, M_BPF, M_WAITOK); 968df8bae1dSRodney W. Grimes if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 && 969df8bae1dSRodney W. Grimes bpf_validate(fcode, (int)flen)) { 970e7bb21b3SJonathan Lemon BPFD_LOCK(d); 971a8e93fb7SRobert Watson old = d->bd_filter; 972df8bae1dSRodney W. Grimes d->bd_filter = fcode; 973df8bae1dSRodney W. Grimes reset_d(d); 974e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 975572bde2aSRobert Watson if (old != NULL) 976bd3a5320SPoul-Henning Kamp free((caddr_t)old, M_BPF); 977df8bae1dSRodney W. Grimes 978df8bae1dSRodney W. Grimes return (0); 979df8bae1dSRodney W. Grimes } 980bd3a5320SPoul-Henning Kamp free((caddr_t)fcode, M_BPF); 981df8bae1dSRodney W. Grimes return (EINVAL); 982df8bae1dSRodney W. Grimes } 983df8bae1dSRodney W. Grimes 984df8bae1dSRodney W. Grimes /* 985df8bae1dSRodney W. Grimes * Detach a file from its current interface (if attached at all) and attach 986df8bae1dSRodney W. Grimes * to the interface indicated by the name stored in ifr. 987df8bae1dSRodney W. Grimes * Return an errno or 0. 988df8bae1dSRodney W. Grimes */ 989df8bae1dSRodney W. Grimes static int 990df8bae1dSRodney W. Grimes bpf_setif(d, ifr) 991df8bae1dSRodney W. Grimes struct bpf_d *d; 992df8bae1dSRodney W. Grimes struct ifreq *ifr; 993df8bae1dSRodney W. Grimes { 994df8bae1dSRodney W. Grimes struct bpf_if *bp; 995e7bb21b3SJonathan Lemon int error; 9969b44ff22SGarrett Wollman struct ifnet *theywant; 997df8bae1dSRodney W. Grimes 9989b44ff22SGarrett Wollman theywant = ifunit(ifr->ifr_name); 999572bde2aSRobert Watson if (theywant == NULL) 10009b44ff22SGarrett Wollman return ENXIO; 10019b44ff22SGarrett Wollman 1002df8bae1dSRodney W. Grimes /* 1003df8bae1dSRodney W. Grimes * Look through attached interfaces for the named one. 1004df8bae1dSRodney W. Grimes */ 1005e7bb21b3SJonathan Lemon mtx_lock(&bpf_mtx); 10064a3feeaaSRobert Watson LIST_FOREACH(bp, &bpf_iflist, bif_next) { 1007df8bae1dSRodney W. Grimes struct ifnet *ifp = bp->bif_ifp; 1008df8bae1dSRodney W. Grimes 1009572bde2aSRobert Watson if (ifp == NULL || ifp != theywant) 1010df8bae1dSRodney W. Grimes continue; 101124a229f4SSam Leffler /* skip additional entry */ 101224a229f4SSam Leffler if (bp->bif_driverp != (struct bpf_if **)&ifp->if_bpf) 101324a229f4SSam Leffler continue; 1014e7bb21b3SJonathan Lemon 1015e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 1016df8bae1dSRodney W. Grimes /* 1017df8bae1dSRodney W. Grimes * We found the requested interface. 1018df8bae1dSRodney W. Grimes * Allocate the packet buffers if we need to. 1019df8bae1dSRodney W. Grimes * If we're already attached to requested interface, 1020df8bae1dSRodney W. Grimes * just flush the buffer. 1021df8bae1dSRodney W. Grimes */ 1022572bde2aSRobert Watson if (d->bd_sbuf == NULL) { 1023df8bae1dSRodney W. Grimes error = bpf_allocbufs(d); 1024df8bae1dSRodney W. Grimes if (error != 0) 1025df8bae1dSRodney W. Grimes return (error); 1026df8bae1dSRodney W. Grimes } 1027df8bae1dSRodney W. Grimes if (bp != d->bd_bif) { 1028df8bae1dSRodney W. Grimes if (d->bd_bif) 1029df8bae1dSRodney W. Grimes /* 1030df8bae1dSRodney W. Grimes * Detach if attached to something else. 1031df8bae1dSRodney W. Grimes */ 1032df8bae1dSRodney W. Grimes bpf_detachd(d); 1033df8bae1dSRodney W. Grimes 1034df8bae1dSRodney W. Grimes bpf_attachd(d, bp); 1035df8bae1dSRodney W. Grimes } 1036e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1037df8bae1dSRodney W. Grimes reset_d(d); 1038e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1039df8bae1dSRodney W. Grimes return (0); 1040df8bae1dSRodney W. Grimes } 1041e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 1042df8bae1dSRodney W. Grimes /* Not found. */ 1043df8bae1dSRodney W. Grimes return (ENXIO); 1044df8bae1dSRodney W. Grimes } 1045df8bae1dSRodney W. Grimes 1046df8bae1dSRodney W. Grimes /* 1047243ac7d8SPeter Wemm * Support for select() and poll() system calls 1048df8bae1dSRodney W. Grimes * 1049df8bae1dSRodney W. Grimes * Return true iff the specific operation will not block indefinitely. 1050df8bae1dSRodney W. Grimes * Otherwise, return false but make a note that a selwakeup() must be done. 1051df8bae1dSRodney W. Grimes */ 105237c84183SPoul-Henning Kamp static int 1053b40ce416SJulian Elischer bpfpoll(dev, events, td) 105489c9c53dSPoul-Henning Kamp struct cdev *dev; 1055243ac7d8SPeter Wemm int events; 1056b40ce416SJulian Elischer struct thread *td; 1057df8bae1dSRodney W. Grimes { 1058e7bb21b3SJonathan Lemon struct bpf_d *d; 10590832fc64SGarance A Drosehn int revents; 1060df8bae1dSRodney W. Grimes 1061bd3a5320SPoul-Henning Kamp d = dev->si_drv1; 1062de5d9935SRobert Watson if (d->bd_bif == NULL) 1063de5d9935SRobert Watson return (ENXIO); 1064de5d9935SRobert Watson 10650832fc64SGarance A Drosehn revents = events & (POLLOUT | POLLWRNORM); 1066e7bb21b3SJonathan Lemon BPFD_LOCK(d); 106775c13541SPoul-Henning Kamp if (events & (POLLIN | POLLRDNORM)) { 106895aab9ccSJohn-Mark Gurney if (bpf_ready(d)) 1069243ac7d8SPeter Wemm revents |= events & (POLLIN | POLLRDNORM); 107081bda851SJohn Polstra else { 1071ed01445dSJohn Baldwin selrecord(td, &d->bd_sel); 107281bda851SJohn Polstra /* Start the read timeout if necessary. */ 107381bda851SJohn Polstra if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) { 107481bda851SJohn Polstra callout_reset(&d->bd_callout, d->bd_rtout, 107581bda851SJohn Polstra bpf_timed_out, d); 107681bda851SJohn Polstra d->bd_state = BPF_WAITING; 107781bda851SJohn Polstra } 107881bda851SJohn Polstra } 107975c13541SPoul-Henning Kamp } 1080e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1081243ac7d8SPeter Wemm return (revents); 1082df8bae1dSRodney W. Grimes } 1083df8bae1dSRodney W. Grimes 1084df8bae1dSRodney W. Grimes /* 108595aab9ccSJohn-Mark Gurney * Support for kevent() system call. Register EVFILT_READ filters and 108695aab9ccSJohn-Mark Gurney * reject all others. 108795aab9ccSJohn-Mark Gurney */ 108895aab9ccSJohn-Mark Gurney int 108995aab9ccSJohn-Mark Gurney bpfkqfilter(dev, kn) 109089c9c53dSPoul-Henning Kamp struct cdev *dev; 109195aab9ccSJohn-Mark Gurney struct knote *kn; 109295aab9ccSJohn-Mark Gurney { 109395aab9ccSJohn-Mark Gurney struct bpf_d *d = (struct bpf_d *)dev->si_drv1; 109495aab9ccSJohn-Mark Gurney 109595aab9ccSJohn-Mark Gurney if (kn->kn_filter != EVFILT_READ) 109695aab9ccSJohn-Mark Gurney return (1); 109795aab9ccSJohn-Mark Gurney 109895aab9ccSJohn-Mark Gurney kn->kn_fop = &bpfread_filtops; 109995aab9ccSJohn-Mark Gurney kn->kn_hook = d; 1100ad3b9257SJohn-Mark Gurney knlist_add(&d->bd_sel.si_note, kn, 0); 110195aab9ccSJohn-Mark Gurney 110295aab9ccSJohn-Mark Gurney return (0); 110395aab9ccSJohn-Mark Gurney } 110495aab9ccSJohn-Mark Gurney 110595aab9ccSJohn-Mark Gurney static void 110695aab9ccSJohn-Mark Gurney filt_bpfdetach(kn) 110795aab9ccSJohn-Mark Gurney struct knote *kn; 110895aab9ccSJohn-Mark Gurney { 110995aab9ccSJohn-Mark Gurney struct bpf_d *d = (struct bpf_d *)kn->kn_hook; 111095aab9ccSJohn-Mark Gurney 1111ad3b9257SJohn-Mark Gurney knlist_remove(&d->bd_sel.si_note, kn, 0); 111295aab9ccSJohn-Mark Gurney } 111395aab9ccSJohn-Mark Gurney 111495aab9ccSJohn-Mark Gurney static int 111595aab9ccSJohn-Mark Gurney filt_bpfread(kn, hint) 111695aab9ccSJohn-Mark Gurney struct knote *kn; 111795aab9ccSJohn-Mark Gurney long hint; 111895aab9ccSJohn-Mark Gurney { 111995aab9ccSJohn-Mark Gurney struct bpf_d *d = (struct bpf_d *)kn->kn_hook; 112095aab9ccSJohn-Mark Gurney int ready; 112195aab9ccSJohn-Mark Gurney 112286c9a453SJohn-Mark Gurney BPFD_LOCK_ASSERT(d); 112395aab9ccSJohn-Mark Gurney ready = bpf_ready(d); 112495aab9ccSJohn-Mark Gurney if (ready) { 112595aab9ccSJohn-Mark Gurney kn->kn_data = d->bd_slen; 112695aab9ccSJohn-Mark Gurney if (d->bd_hbuf) 112795aab9ccSJohn-Mark Gurney kn->kn_data += d->bd_hlen; 112895aab9ccSJohn-Mark Gurney } 112995aab9ccSJohn-Mark Gurney else if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) { 113095aab9ccSJohn-Mark Gurney callout_reset(&d->bd_callout, d->bd_rtout, 113195aab9ccSJohn-Mark Gurney bpf_timed_out, d); 113295aab9ccSJohn-Mark Gurney d->bd_state = BPF_WAITING; 113395aab9ccSJohn-Mark Gurney } 113495aab9ccSJohn-Mark Gurney 113595aab9ccSJohn-Mark Gurney return (ready); 113695aab9ccSJohn-Mark Gurney } 113795aab9ccSJohn-Mark Gurney 113895aab9ccSJohn-Mark Gurney /* 1139df8bae1dSRodney W. Grimes * Incoming linkage from device drivers. Process the packet pkt, of length 1140df8bae1dSRodney W. Grimes * pktlen, which is stored in a contiguous buffer. The packet is parsed 1141df8bae1dSRodney W. Grimes * by each process' filter, and if accepted, stashed into the corresponding 1142df8bae1dSRodney W. Grimes * buffer. 1143df8bae1dSRodney W. Grimes */ 1144df8bae1dSRodney W. Grimes void 114524a229f4SSam Leffler bpf_tap(bp, pkt, pktlen) 114624a229f4SSam Leffler struct bpf_if *bp; 11478994a245SDag-Erling Smørgrav u_char *pkt; 11488994a245SDag-Erling Smørgrav u_int pktlen; 1149df8bae1dSRodney W. Grimes { 11508994a245SDag-Erling Smørgrav struct bpf_d *d; 11518994a245SDag-Erling Smørgrav u_int slen; 1152e7bb21b3SJonathan Lemon 115346691dd8SRobert Watson /* 115446691dd8SRobert Watson * Lockless read to avoid cost of locking the interface if there are 115546691dd8SRobert Watson * no descriptors attached. 115646691dd8SRobert Watson */ 11574a3feeaaSRobert Watson if (LIST_EMPTY(&bp->bif_dlist)) 115846691dd8SRobert Watson return; 115946691dd8SRobert Watson 1160e7bb21b3SJonathan Lemon BPFIF_LOCK(bp); 11614a3feeaaSRobert Watson LIST_FOREACH(d, &bp->bif_dlist, bd_next) { 1162e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1163df8bae1dSRodney W. Grimes ++d->bd_rcount; 1164df8bae1dSRodney W. Grimes slen = bpf_filter(d->bd_filter, pkt, pktlen, pktlen); 1165ec272d87SRobert Watson if (slen != 0) { 1166ec272d87SRobert Watson #ifdef MAC 116724a229f4SSam Leffler if (mac_check_bpfdesc_receive(d, bp->bif_ifp) == 0) 1168ec272d87SRobert Watson #endif 1169df8bae1dSRodney W. Grimes catchpacket(d, pkt, pktlen, slen, bcopy); 1170ec272d87SRobert Watson } 1171e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1172df8bae1dSRodney W. Grimes } 1173e7bb21b3SJonathan Lemon BPFIF_UNLOCK(bp); 1174df8bae1dSRodney W. Grimes } 1175df8bae1dSRodney W. Grimes 1176df8bae1dSRodney W. Grimes /* 1177df8bae1dSRodney W. Grimes * Copy data from an mbuf chain into a buffer. This code is derived 1178df8bae1dSRodney W. Grimes * from m_copydata in sys/uipc_mbuf.c. 1179df8bae1dSRodney W. Grimes */ 1180df8bae1dSRodney W. Grimes static void 1181df8bae1dSRodney W. Grimes bpf_mcopy(src_arg, dst_arg, len) 1182df8bae1dSRodney W. Grimes const void *src_arg; 1183df8bae1dSRodney W. Grimes void *dst_arg; 11848994a245SDag-Erling Smørgrav size_t len; 1185df8bae1dSRodney W. Grimes { 11868994a245SDag-Erling Smørgrav const struct mbuf *m; 11878994a245SDag-Erling Smørgrav u_int count; 1188df8bae1dSRodney W. Grimes u_char *dst; 1189df8bae1dSRodney W. Grimes 1190df8bae1dSRodney W. Grimes m = src_arg; 1191df8bae1dSRodney W. Grimes dst = dst_arg; 1192df8bae1dSRodney W. Grimes while (len > 0) { 1193572bde2aSRobert Watson if (m == NULL) 1194df8bae1dSRodney W. Grimes panic("bpf_mcopy"); 1195df8bae1dSRodney W. Grimes count = min(m->m_len, len); 11960453d3cbSBruce Evans bcopy(mtod(m, void *), dst, count); 1197df8bae1dSRodney W. Grimes m = m->m_next; 1198df8bae1dSRodney W. Grimes dst += count; 1199df8bae1dSRodney W. Grimes len -= count; 1200df8bae1dSRodney W. Grimes } 1201df8bae1dSRodney W. Grimes } 1202df8bae1dSRodney W. Grimes 1203df8bae1dSRodney W. Grimes /* 1204df8bae1dSRodney W. Grimes * Incoming linkage from device drivers, when packet is in an mbuf chain. 1205df8bae1dSRodney W. Grimes */ 1206df8bae1dSRodney W. Grimes void 120724a229f4SSam Leffler bpf_mtap(bp, m) 120824a229f4SSam Leffler struct bpf_if *bp; 1209df8bae1dSRodney W. Grimes struct mbuf *m; 1210df8bae1dSRodney W. Grimes { 1211df8bae1dSRodney W. Grimes struct bpf_d *d; 1212df8bae1dSRodney W. Grimes u_int pktlen, slen; 1213df8bae1dSRodney W. Grimes 121446691dd8SRobert Watson /* 121546691dd8SRobert Watson * Lockless read to avoid cost of locking the interface if there are 121646691dd8SRobert Watson * no descriptors attached. 121746691dd8SRobert Watson */ 12184a3feeaaSRobert Watson if (LIST_EMPTY(&bp->bif_dlist)) 121946691dd8SRobert Watson return; 122046691dd8SRobert Watson 1221f0e2422bSPoul-Henning Kamp pktlen = m_length(m, NULL); 12227b831242SPoul-Henning Kamp if (pktlen == m->m_len) { 122324a229f4SSam Leffler bpf_tap(bp, mtod(m, u_char *), pktlen); 12247b831242SPoul-Henning Kamp return; 12257b831242SPoul-Henning Kamp } 1226df8bae1dSRodney W. Grimes 1227e7bb21b3SJonathan Lemon BPFIF_LOCK(bp); 12284a3feeaaSRobert Watson LIST_FOREACH(d, &bp->bif_dlist, bd_next) { 12298ed3828cSRobert Watson if (!d->bd_seesent && (m->m_pkthdr.rcvif == NULL)) 12308ed3828cSRobert Watson continue; 1231e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1232df8bae1dSRodney W. Grimes ++d->bd_rcount; 1233df8bae1dSRodney W. Grimes slen = bpf_filter(d->bd_filter, (u_char *)m, pktlen, 0); 1234df8bae1dSRodney W. Grimes if (slen != 0) 12350c7fb534SRobert Watson #ifdef MAC 123624a229f4SSam Leffler if (mac_check_bpfdesc_receive(d, bp->bif_ifp) == 0) 12370c7fb534SRobert Watson #endif 12380c7fb534SRobert Watson catchpacket(d, (u_char *)m, pktlen, slen, 12390c7fb534SRobert Watson bpf_mcopy); 1240e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1241df8bae1dSRodney W. Grimes } 1242e7bb21b3SJonathan Lemon BPFIF_UNLOCK(bp); 1243df8bae1dSRodney W. Grimes } 1244df8bae1dSRodney W. Grimes 1245df8bae1dSRodney W. Grimes /* 1246437ffe18SSam Leffler * Incoming linkage from device drivers, when packet is in 1247437ffe18SSam Leffler * an mbuf chain and to be prepended by a contiguous header. 1248437ffe18SSam Leffler */ 1249437ffe18SSam Leffler void 1250437ffe18SSam Leffler bpf_mtap2(bp, data, dlen, m) 1251437ffe18SSam Leffler struct bpf_if *bp; 1252437ffe18SSam Leffler void *data; 1253437ffe18SSam Leffler u_int dlen; 1254437ffe18SSam Leffler struct mbuf *m; 1255437ffe18SSam Leffler { 1256437ffe18SSam Leffler struct mbuf mb; 1257437ffe18SSam Leffler struct bpf_d *d; 1258437ffe18SSam Leffler u_int pktlen, slen; 1259437ffe18SSam Leffler 126046691dd8SRobert Watson /* 126146691dd8SRobert Watson * Lockless read to avoid cost of locking the interface if there are 126246691dd8SRobert Watson * no descriptors attached. 126346691dd8SRobert Watson */ 12644a3feeaaSRobert Watson if (LIST_EMPTY(&bp->bif_dlist)) 126546691dd8SRobert Watson return; 126646691dd8SRobert Watson 1267437ffe18SSam Leffler pktlen = m_length(m, NULL); 1268437ffe18SSam Leffler /* 1269437ffe18SSam Leffler * Craft on-stack mbuf suitable for passing to bpf_filter. 1270437ffe18SSam Leffler * Note that we cut corners here; we only setup what's 1271437ffe18SSam Leffler * absolutely needed--this mbuf should never go anywhere else. 1272437ffe18SSam Leffler */ 1273437ffe18SSam Leffler mb.m_next = m; 1274437ffe18SSam Leffler mb.m_data = data; 1275437ffe18SSam Leffler mb.m_len = dlen; 1276437ffe18SSam Leffler pktlen += dlen; 1277437ffe18SSam Leffler 1278437ffe18SSam Leffler BPFIF_LOCK(bp); 12794a3feeaaSRobert Watson LIST_FOREACH(d, &bp->bif_dlist, bd_next) { 1280437ffe18SSam Leffler if (!d->bd_seesent && (m->m_pkthdr.rcvif == NULL)) 1281437ffe18SSam Leffler continue; 1282437ffe18SSam Leffler BPFD_LOCK(d); 1283437ffe18SSam Leffler ++d->bd_rcount; 1284437ffe18SSam Leffler slen = bpf_filter(d->bd_filter, (u_char *)&mb, pktlen, 0); 1285437ffe18SSam Leffler if (slen != 0) 1286437ffe18SSam Leffler #ifdef MAC 1287437ffe18SSam Leffler if (mac_check_bpfdesc_receive(d, bp->bif_ifp) == 0) 1288437ffe18SSam Leffler #endif 1289437ffe18SSam Leffler catchpacket(d, (u_char *)&mb, pktlen, slen, 1290437ffe18SSam Leffler bpf_mcopy); 1291437ffe18SSam Leffler BPFD_UNLOCK(d); 1292437ffe18SSam Leffler } 1293437ffe18SSam Leffler BPFIF_UNLOCK(bp); 1294437ffe18SSam Leffler } 1295437ffe18SSam Leffler 1296437ffe18SSam Leffler /* 1297df8bae1dSRodney W. Grimes * Move the packet data from interface memory (pkt) into the 12989e610888SDag-Erling Smørgrav * store buffer. "cpfn" is the routine called to do the actual data 1299df8bae1dSRodney W. Grimes * transfer. bcopy is passed in to copy contiguous chunks, while 1300df8bae1dSRodney W. Grimes * bpf_mcopy is passed in to copy mbuf chains. In the latter case, 1301df8bae1dSRodney W. Grimes * pkt is really an mbuf. 1302df8bae1dSRodney W. Grimes */ 1303df8bae1dSRodney W. Grimes static void 1304df8bae1dSRodney W. Grimes catchpacket(d, pkt, pktlen, snaplen, cpfn) 13058994a245SDag-Erling Smørgrav struct bpf_d *d; 13068994a245SDag-Erling Smørgrav u_char *pkt; 13078994a245SDag-Erling Smørgrav u_int pktlen, snaplen; 13088994a245SDag-Erling Smørgrav void (*cpfn)(const void *, void *, size_t); 1309df8bae1dSRodney W. Grimes { 13108994a245SDag-Erling Smørgrav struct bpf_hdr *hp; 13118994a245SDag-Erling Smørgrav int totlen, curlen; 13128994a245SDag-Erling Smørgrav int hdrlen = d->bd_bif->bif_hdrlen; 13137819da79SJohn-Mark Gurney int do_wakeup = 0; 13149e610888SDag-Erling Smørgrav 1315df8bae1dSRodney W. Grimes /* 1316df8bae1dSRodney W. Grimes * Figure out how many bytes to move. If the packet is 1317df8bae1dSRodney W. Grimes * greater or equal to the snapshot length, transfer that 1318df8bae1dSRodney W. Grimes * much. Otherwise, transfer the whole packet (unless 1319df8bae1dSRodney W. Grimes * we hit the buffer size limit). 1320df8bae1dSRodney W. Grimes */ 1321df8bae1dSRodney W. Grimes totlen = hdrlen + min(snaplen, pktlen); 1322df8bae1dSRodney W. Grimes if (totlen > d->bd_bufsize) 1323df8bae1dSRodney W. Grimes totlen = d->bd_bufsize; 1324df8bae1dSRodney W. Grimes 1325df8bae1dSRodney W. Grimes /* 1326df8bae1dSRodney W. Grimes * Round up the end of the previous packet to the next longword. 1327df8bae1dSRodney W. Grimes */ 1328df8bae1dSRodney W. Grimes curlen = BPF_WORDALIGN(d->bd_slen); 1329df8bae1dSRodney W. Grimes if (curlen + totlen > d->bd_bufsize) { 1330df8bae1dSRodney W. Grimes /* 1331df8bae1dSRodney W. Grimes * This packet will overflow the storage buffer. 1332df8bae1dSRodney W. Grimes * Rotate the buffers if we can, then wakeup any 1333df8bae1dSRodney W. Grimes * pending reads. 1334df8bae1dSRodney W. Grimes */ 1335572bde2aSRobert Watson if (d->bd_fbuf == NULL) { 1336df8bae1dSRodney W. Grimes /* 1337df8bae1dSRodney W. Grimes * We haven't completed the previous read yet, 1338df8bae1dSRodney W. Grimes * so drop the packet. 1339df8bae1dSRodney W. Grimes */ 1340df8bae1dSRodney W. Grimes ++d->bd_dcount; 1341df8bae1dSRodney W. Grimes return; 1342df8bae1dSRodney W. Grimes } 1343df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 13447819da79SJohn-Mark Gurney do_wakeup = 1; 1345df8bae1dSRodney W. Grimes curlen = 0; 1346df8bae1dSRodney W. Grimes } 134781bda851SJohn Polstra else if (d->bd_immediate || d->bd_state == BPF_TIMED_OUT) 1348df8bae1dSRodney W. Grimes /* 134981bda851SJohn Polstra * Immediate mode is set, or the read timeout has 135081bda851SJohn Polstra * already expired during a select call. A packet 135181bda851SJohn Polstra * arrived, so the reader should be woken up. 1352df8bae1dSRodney W. Grimes */ 13537819da79SJohn-Mark Gurney do_wakeup = 1; 1354df8bae1dSRodney W. Grimes 1355df8bae1dSRodney W. Grimes /* 1356df8bae1dSRodney W. Grimes * Append the bpf header. 1357df8bae1dSRodney W. Grimes */ 1358df8bae1dSRodney W. Grimes hp = (struct bpf_hdr *)(d->bd_sbuf + curlen); 1359df8bae1dSRodney W. Grimes microtime(&hp->bh_tstamp); 1360df8bae1dSRodney W. Grimes hp->bh_datalen = pktlen; 1361df8bae1dSRodney W. Grimes hp->bh_hdrlen = hdrlen; 1362df8bae1dSRodney W. Grimes /* 1363df8bae1dSRodney W. Grimes * Copy the packet data into the store buffer and update its length. 1364df8bae1dSRodney W. Grimes */ 1365df8bae1dSRodney W. Grimes (*cpfn)(pkt, (u_char *)hp + hdrlen, (hp->bh_caplen = totlen - hdrlen)); 1366df8bae1dSRodney W. Grimes d->bd_slen = curlen + totlen; 13677819da79SJohn-Mark Gurney 13687819da79SJohn-Mark Gurney if (do_wakeup) 13697819da79SJohn-Mark Gurney bpf_wakeup(d); 1370df8bae1dSRodney W. Grimes } 1371df8bae1dSRodney W. Grimes 1372df8bae1dSRodney W. Grimes /* 1373df8bae1dSRodney W. Grimes * Initialize all nonzero fields of a descriptor. 1374df8bae1dSRodney W. Grimes */ 1375df8bae1dSRodney W. Grimes static int 1376df8bae1dSRodney W. Grimes bpf_allocbufs(d) 13778994a245SDag-Erling Smørgrav struct bpf_d *d; 1378df8bae1dSRodney W. Grimes { 1379a163d034SWarner Losh d->bd_fbuf = (caddr_t)malloc(d->bd_bufsize, M_BPF, M_WAITOK); 1380572bde2aSRobert Watson if (d->bd_fbuf == NULL) 1381df8bae1dSRodney W. Grimes return (ENOBUFS); 1382df8bae1dSRodney W. Grimes 1383a163d034SWarner Losh d->bd_sbuf = (caddr_t)malloc(d->bd_bufsize, M_BPF, M_WAITOK); 1384572bde2aSRobert Watson if (d->bd_sbuf == NULL) { 1385bd3a5320SPoul-Henning Kamp free(d->bd_fbuf, M_BPF); 1386df8bae1dSRodney W. Grimes return (ENOBUFS); 1387df8bae1dSRodney W. Grimes } 1388df8bae1dSRodney W. Grimes d->bd_slen = 0; 1389df8bae1dSRodney W. Grimes d->bd_hlen = 0; 1390df8bae1dSRodney W. Grimes return (0); 1391df8bae1dSRodney W. Grimes } 1392df8bae1dSRodney W. Grimes 1393df8bae1dSRodney W. Grimes /* 1394df8bae1dSRodney W. Grimes * Free buffers currently in use by a descriptor. 1395df8bae1dSRodney W. Grimes * Called on close. 1396df8bae1dSRodney W. Grimes */ 1397df8bae1dSRodney W. Grimes static void 1398df8bae1dSRodney W. Grimes bpf_freed(d) 13998994a245SDag-Erling Smørgrav struct bpf_d *d; 1400df8bae1dSRodney W. Grimes { 1401df8bae1dSRodney W. Grimes /* 1402df8bae1dSRodney W. Grimes * We don't need to lock out interrupts since this descriptor has 1403df8bae1dSRodney W. Grimes * been detached from its interface and it yet hasn't been marked 1404df8bae1dSRodney W. Grimes * free. 1405df8bae1dSRodney W. Grimes */ 1406572bde2aSRobert Watson if (d->bd_sbuf != NULL) { 1407bd3a5320SPoul-Henning Kamp free(d->bd_sbuf, M_BPF); 1408572bde2aSRobert Watson if (d->bd_hbuf != NULL) 1409bd3a5320SPoul-Henning Kamp free(d->bd_hbuf, M_BPF); 1410572bde2aSRobert Watson if (d->bd_fbuf != NULL) 1411bd3a5320SPoul-Henning Kamp free(d->bd_fbuf, M_BPF); 1412df8bae1dSRodney W. Grimes } 1413df8bae1dSRodney W. Grimes if (d->bd_filter) 1414bd3a5320SPoul-Henning Kamp free((caddr_t)d->bd_filter, M_BPF); 1415e7bb21b3SJonathan Lemon mtx_destroy(&d->bd_mtx); 1416df8bae1dSRodney W. Grimes } 1417df8bae1dSRodney W. Grimes 1418df8bae1dSRodney W. Grimes /* 141924a229f4SSam Leffler * Attach an interface to bpf. dlt is the link layer type; hdrlen is the 142024a229f4SSam Leffler * fixed size of the link header (variable length headers not yet supported). 1421df8bae1dSRodney W. Grimes */ 1422df8bae1dSRodney W. Grimes void 14239b44ff22SGarrett Wollman bpfattach(ifp, dlt, hdrlen) 1424df8bae1dSRodney W. Grimes struct ifnet *ifp; 1425df8bae1dSRodney W. Grimes u_int dlt, hdrlen; 1426df8bae1dSRodney W. Grimes { 142724a229f4SSam Leffler 142824a229f4SSam Leffler bpfattach2(ifp, dlt, hdrlen, &ifp->if_bpf); 142924a229f4SSam Leffler } 143024a229f4SSam Leffler 143124a229f4SSam Leffler /* 143224a229f4SSam Leffler * Attach an interface to bpf. ifp is a pointer to the structure 143324a229f4SSam Leffler * defining the interface to be attached, dlt is the link layer type, 143424a229f4SSam Leffler * and hdrlen is the fixed size of the link header (variable length 143524a229f4SSam Leffler * headers are not yet supporrted). 143624a229f4SSam Leffler */ 143724a229f4SSam Leffler void 143824a229f4SSam Leffler bpfattach2(ifp, dlt, hdrlen, driverp) 143924a229f4SSam Leffler struct ifnet *ifp; 144024a229f4SSam Leffler u_int dlt, hdrlen; 144124a229f4SSam Leffler struct bpf_if **driverp; 144224a229f4SSam Leffler { 1443df8bae1dSRodney W. Grimes struct bpf_if *bp; 14446a40ecceSJohn Baldwin bp = (struct bpf_if *)malloc(sizeof(*bp), M_BPF, M_NOWAIT | M_ZERO); 1445572bde2aSRobert Watson if (bp == NULL) 1446df8bae1dSRodney W. Grimes panic("bpfattach"); 1447df8bae1dSRodney W. Grimes 14484a3feeaaSRobert Watson LIST_INIT(&bp->bif_dlist); 144924a229f4SSam Leffler bp->bif_driverp = driverp; 1450df8bae1dSRodney W. Grimes bp->bif_ifp = ifp; 1451df8bae1dSRodney W. Grimes bp->bif_dlt = dlt; 14526008862bSJohn Baldwin mtx_init(&bp->bif_mtx, "bpf interface lock", NULL, MTX_DEF); 1453df8bae1dSRodney W. Grimes 1454e7bb21b3SJonathan Lemon mtx_lock(&bpf_mtx); 14554a3feeaaSRobert Watson LIST_INSERT_HEAD(&bpf_iflist, bp, bif_next); 1456e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 1457df8bae1dSRodney W. Grimes 1458572bde2aSRobert Watson *bp->bif_driverp = NULL; 1459df8bae1dSRodney W. Grimes 1460df8bae1dSRodney W. Grimes /* 1461df8bae1dSRodney W. Grimes * Compute the length of the bpf header. This is not necessarily 1462df8bae1dSRodney W. Grimes * equal to SIZEOF_BPF_HDR because we want to insert spacing such 1463df8bae1dSRodney W. Grimes * that the network layer header begins on a longword boundary (for 1464df8bae1dSRodney W. Grimes * performance reasons and to alleviate alignment restrictions). 1465df8bae1dSRodney W. Grimes */ 1466df8bae1dSRodney W. Grimes bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen; 1467df8bae1dSRodney W. Grimes 14682eeab939SGarrett Wollman if (bootverbose) 146924a229f4SSam Leffler if_printf(ifp, "bpf attached\n"); 1470df8bae1dSRodney W. Grimes } 147153ac6efbSJulian Elischer 1472de5d9935SRobert Watson /* 1473de5d9935SRobert Watson * Detach bpf from an interface. This involves detaching each descriptor 1474de5d9935SRobert Watson * associated with the interface, and leaving bd_bif NULL. Notify each 1475de5d9935SRobert Watson * descriptor as it's detached so that any sleepers wake up and get 1476de5d9935SRobert Watson * ENXIO. 1477de5d9935SRobert Watson */ 1478de5d9935SRobert Watson void 1479de5d9935SRobert Watson bpfdetach(ifp) 1480de5d9935SRobert Watson struct ifnet *ifp; 1481de5d9935SRobert Watson { 14824a3feeaaSRobert Watson struct bpf_if *bp; 1483de5d9935SRobert Watson struct bpf_d *d; 1484de5d9935SRobert Watson 1485de5d9935SRobert Watson /* Locate BPF interface information */ 14868eab61f3SSam Leffler mtx_lock(&bpf_mtx); 14874a3feeaaSRobert Watson LIST_FOREACH(bp, &bpf_iflist, bif_next) { 1488de5d9935SRobert Watson if (ifp == bp->bif_ifp) 1489de5d9935SRobert Watson break; 1490de5d9935SRobert Watson } 1491de5d9935SRobert Watson 1492de5d9935SRobert Watson /* Interface wasn't attached */ 1493d79bf337SMatthew N. Dodd if ((bp == NULL) || (bp->bif_ifp == NULL)) { 1494e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 14959bf40edeSBrooks Davis printf("bpfdetach: %s was not attached\n", ifp->if_xname); 1496de5d9935SRobert Watson return; 1497de5d9935SRobert Watson } 1498de5d9935SRobert Watson 14994a3feeaaSRobert Watson LIST_REMOVE(bp, bif_next); 15008eab61f3SSam Leffler mtx_unlock(&bpf_mtx); 1501de5d9935SRobert Watson 15024a3feeaaSRobert Watson while ((d = LIST_FIRST(&bp->bif_dlist)) != NULL) { 1503e7bb21b3SJonathan Lemon bpf_detachd(d); 1504e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1505e7bb21b3SJonathan Lemon bpf_wakeup(d); 1506e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1507e7bb21b3SJonathan Lemon } 1508e7bb21b3SJonathan Lemon 1509e7bb21b3SJonathan Lemon mtx_destroy(&bp->bif_mtx); 1510de5d9935SRobert Watson free(bp, M_BPF); 15118eab61f3SSam Leffler } 1512de5d9935SRobert Watson 15138eab61f3SSam Leffler /* 15148eab61f3SSam Leffler * Get a list of available data link type of the interface. 15158eab61f3SSam Leffler */ 15168eab61f3SSam Leffler static int 15178eab61f3SSam Leffler bpf_getdltlist(d, bfl) 15188eab61f3SSam Leffler struct bpf_d *d; 15198eab61f3SSam Leffler struct bpf_dltlist *bfl; 15208eab61f3SSam Leffler { 15218eab61f3SSam Leffler int n, error; 15228eab61f3SSam Leffler struct ifnet *ifp; 15238eab61f3SSam Leffler struct bpf_if *bp; 15248eab61f3SSam Leffler 15258eab61f3SSam Leffler ifp = d->bd_bif->bif_ifp; 15268eab61f3SSam Leffler n = 0; 15278eab61f3SSam Leffler error = 0; 15288eab61f3SSam Leffler mtx_lock(&bpf_mtx); 15294a3feeaaSRobert Watson LIST_FOREACH(bp, &bpf_iflist, bif_next) { 15308eab61f3SSam Leffler if (bp->bif_ifp != ifp) 15318eab61f3SSam Leffler continue; 15328eab61f3SSam Leffler if (bfl->bfl_list != NULL) { 15338eab61f3SSam Leffler if (n >= bfl->bfl_len) { 1534e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 15358eab61f3SSam Leffler return (ENOMEM); 15368eab61f3SSam Leffler } 15378eab61f3SSam Leffler error = copyout(&bp->bif_dlt, 15388eab61f3SSam Leffler bfl->bfl_list + n, sizeof(u_int)); 15398eab61f3SSam Leffler } 15408eab61f3SSam Leffler n++; 15418eab61f3SSam Leffler } 15428eab61f3SSam Leffler mtx_unlock(&bpf_mtx); 15438eab61f3SSam Leffler bfl->bfl_len = n; 15448eab61f3SSam Leffler return (error); 15458eab61f3SSam Leffler } 15468eab61f3SSam Leffler 15478eab61f3SSam Leffler /* 15488eab61f3SSam Leffler * Set the data link type of a BPF instance. 15498eab61f3SSam Leffler */ 15508eab61f3SSam Leffler static int 15518eab61f3SSam Leffler bpf_setdlt(d, dlt) 15528eab61f3SSam Leffler struct bpf_d *d; 15538eab61f3SSam Leffler u_int dlt; 15548eab61f3SSam Leffler { 15558eab61f3SSam Leffler int error, opromisc; 15568eab61f3SSam Leffler struct ifnet *ifp; 15578eab61f3SSam Leffler struct bpf_if *bp; 15588eab61f3SSam Leffler 15598eab61f3SSam Leffler if (d->bd_bif->bif_dlt == dlt) 15608eab61f3SSam Leffler return (0); 15618eab61f3SSam Leffler ifp = d->bd_bif->bif_ifp; 15628eab61f3SSam Leffler mtx_lock(&bpf_mtx); 15634a3feeaaSRobert Watson LIST_FOREACH(bp, &bpf_iflist, bif_next) { 15648eab61f3SSam Leffler if (bp->bif_ifp == ifp && bp->bif_dlt == dlt) 15658eab61f3SSam Leffler break; 15668eab61f3SSam Leffler } 15678eab61f3SSam Leffler mtx_unlock(&bpf_mtx); 15688eab61f3SSam Leffler if (bp != NULL) { 15698eab61f3SSam Leffler opromisc = d->bd_promisc; 15708eab61f3SSam Leffler bpf_detachd(d); 15718eab61f3SSam Leffler bpf_attachd(d, bp); 157293daabddSBrian Feldman BPFD_LOCK(d); 15738eab61f3SSam Leffler reset_d(d); 15748eab61f3SSam Leffler BPFD_UNLOCK(d); 15758eab61f3SSam Leffler if (opromisc) { 15768eab61f3SSam Leffler error = ifpromisc(bp->bif_ifp, 1); 15778eab61f3SSam Leffler if (error) 15788eab61f3SSam Leffler if_printf(bp->bif_ifp, 15798eab61f3SSam Leffler "bpf_setdlt: ifpromisc failed (%d)\n", 15808eab61f3SSam Leffler error); 15818eab61f3SSam Leffler else 15828eab61f3SSam Leffler d->bd_promisc = 1; 15838eab61f3SSam Leffler } 15848eab61f3SSam Leffler } 15858eab61f3SSam Leffler return (bp == NULL ? EINVAL : 0); 1586de5d9935SRobert Watson } 1587de5d9935SRobert Watson 1588929ddbbbSAlfred Perlstein static void bpf_drvinit(void *unused); 1589bd3a5320SPoul-Henning Kamp 159089c9c53dSPoul-Henning Kamp static void bpf_clone(void *arg, char *name, int namelen, struct cdev **dev); 15913f54a085SPoul-Henning Kamp 15923f54a085SPoul-Henning Kamp static void 15933f54a085SPoul-Henning Kamp bpf_clone(arg, name, namelen, dev) 15943f54a085SPoul-Henning Kamp void *arg; 15953f54a085SPoul-Henning Kamp char *name; 15963f54a085SPoul-Henning Kamp int namelen; 159789c9c53dSPoul-Henning Kamp struct cdev **dev; 15983f54a085SPoul-Henning Kamp { 15993f54a085SPoul-Henning Kamp int u; 16003f54a085SPoul-Henning Kamp 1601f3732fd1SPoul-Henning Kamp if (*dev != NULL) 16023f54a085SPoul-Henning Kamp return; 1603db901281SPoul-Henning Kamp if (dev_stdclone(name, NULL, "bpf", &u) != 1) 16043f54a085SPoul-Henning Kamp return; 1605b0d17ba6SPoul-Henning Kamp *dev = make_dev(&bpf_cdevsw, unit2minor(u), UID_ROOT, GID_WHEEL, 0600, 1606b0d17ba6SPoul-Henning Kamp "bpf%d", u); 1607b0d17ba6SPoul-Henning Kamp (*dev)->si_flags |= SI_CHEAPCLONE; 16083f54a085SPoul-Henning Kamp return; 16093f54a085SPoul-Henning Kamp } 16103f54a085SPoul-Henning Kamp 1611514ede09SBruce Evans static void 1612514ede09SBruce Evans bpf_drvinit(unused) 1613514ede09SBruce Evans void *unused; 161453ac6efbSJulian Elischer { 161553ac6efbSJulian Elischer 16166008862bSJohn Baldwin mtx_init(&bpf_mtx, "bpf global lock", NULL, MTX_DEF); 16174a3feeaaSRobert Watson LIST_INIT(&bpf_iflist); 1618db901281SPoul-Henning Kamp EVENTHANDLER_REGISTER(dev_clone, bpf_clone, 0, 1000); 16197198bf47SJulian Elischer } 162053ac6efbSJulian Elischer 1621c9c7976fSPoul-Henning Kamp SYSINIT(bpfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,bpf_drvinit,NULL) 162253ac6efbSJulian Elischer 16235bb5f2c9SPeter Wemm #else /* !DEV_BPF && !NETGRAPH_BPF */ 1624f8dc4716SMike Smith /* 1625f8dc4716SMike Smith * NOP stubs to allow bpf-using drivers to load and function. 1626f8dc4716SMike Smith * 1627f8dc4716SMike Smith * A 'better' implementation would allow the core bpf functionality 1628f8dc4716SMike Smith * to be loaded at runtime. 1629f8dc4716SMike Smith */ 1630f8dc4716SMike Smith 1631f8dc4716SMike Smith void 1632e5562beeSSam Leffler bpf_tap(bp, pkt, pktlen) 1633e5562beeSSam Leffler struct bpf_if *bp; 16348994a245SDag-Erling Smørgrav u_char *pkt; 16358994a245SDag-Erling Smørgrav u_int pktlen; 1636f8dc4716SMike Smith { 1637f8dc4716SMike Smith } 1638f8dc4716SMike Smith 1639f8dc4716SMike Smith void 1640e5562beeSSam Leffler bpf_mtap(bp, m) 1641e5562beeSSam Leffler struct bpf_if *bp; 1642f8dc4716SMike Smith struct mbuf *m; 1643f8dc4716SMike Smith { 1644f8dc4716SMike Smith } 1645f8dc4716SMike Smith 1646f8dc4716SMike Smith void 1647437ffe18SSam Leffler bpf_mtap2(bp, d, l, m) 1648437ffe18SSam Leffler struct bpf_if *bp; 1649c1dae2f0STim J. Robbins void *d; 1650437ffe18SSam Leffler u_int l; 1651437ffe18SSam Leffler struct mbuf *m; 1652437ffe18SSam Leffler { 1653437ffe18SSam Leffler } 1654437ffe18SSam Leffler 1655437ffe18SSam Leffler void 1656f8dc4716SMike Smith bpfattach(ifp, dlt, hdrlen) 1657f8dc4716SMike Smith struct ifnet *ifp; 1658f8dc4716SMike Smith u_int dlt, hdrlen; 1659f8dc4716SMike Smith { 1660f8dc4716SMike Smith } 1661f8dc4716SMike Smith 1662da626c17SBill Paul void 16635f7a7923SSam Leffler bpfattach2(ifp, dlt, hdrlen, driverp) 16645f7a7923SSam Leffler struct ifnet *ifp; 16655f7a7923SSam Leffler u_int dlt, hdrlen; 16665f7a7923SSam Leffler struct bpf_if **driverp; 16675f7a7923SSam Leffler { 16685f7a7923SSam Leffler } 16695f7a7923SSam Leffler 16705f7a7923SSam Leffler void 1671da626c17SBill Paul bpfdetach(ifp) 1672da626c17SBill Paul struct ifnet *ifp; 1673da626c17SBill Paul { 1674da626c17SBill Paul } 1675da626c17SBill Paul 1676f8dc4716SMike Smith u_int 1677f8dc4716SMike Smith bpf_filter(pc, p, wirelen, buflen) 16788994a245SDag-Erling Smørgrav const struct bpf_insn *pc; 16798994a245SDag-Erling Smørgrav u_char *p; 1680f8dc4716SMike Smith u_int wirelen; 16818994a245SDag-Erling Smørgrav u_int buflen; 1682f8dc4716SMike Smith { 1683f8dc4716SMike Smith return -1; /* "no filter" behaviour */ 1684f8dc4716SMike Smith } 1685f8dc4716SMike Smith 16865bb5f2c9SPeter Wemm int 16875bb5f2c9SPeter Wemm bpf_validate(f, len) 16885bb5f2c9SPeter Wemm const struct bpf_insn *f; 16895bb5f2c9SPeter Wemm int len; 16905bb5f2c9SPeter Wemm { 16915bb5f2c9SPeter Wemm return 0; /* false */ 16925bb5f2c9SPeter Wemm } 16935bb5f2c9SPeter Wemm 16945bb5f2c9SPeter Wemm #endif /* !DEV_BPF && !NETGRAPH_BPF */ 1695