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 */ 36df8bae1dSRodney W. Grimes 37c7866007SRobert Watson #include <sys/cdefs.h> 38c7866007SRobert Watson __FBSDID("$FreeBSD$"); 39c7866007SRobert Watson 405bb5f2c9SPeter Wemm #include "opt_bpf.h" 4182f4445dSRobert Watson #include "opt_mac.h" 425bb5f2c9SPeter Wemm #include "opt_netgraph.h" 43df8bae1dSRodney W. Grimes 4495aab9ccSJohn-Mark Gurney #include <sys/types.h> 45df8bae1dSRodney W. Grimes #include <sys/param.h> 46df8bae1dSRodney W. Grimes #include <sys/systm.h> 47ce7609a4SBruce Evans #include <sys/conf.h> 48e76eee55SPoul-Henning Kamp #include <sys/fcntl.h> 494d1d4912SBruce Evans #include <sys/malloc.h> 50df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 51df8bae1dSRodney W. Grimes #include <sys/time.h> 52acd3428bSRobert Watson #include <sys/priv.h> 53df8bae1dSRodney W. Grimes #include <sys/proc.h> 540310c19fSBruce Evans #include <sys/signalvar.h> 55528f627fSBruce Evans #include <sys/filio.h> 56528f627fSBruce Evans #include <sys/sockio.h> 57528f627fSBruce Evans #include <sys/ttycom.h> 58e76eee55SPoul-Henning Kamp #include <sys/uio.h> 59df8bae1dSRodney W. Grimes 6095aab9ccSJohn-Mark Gurney #include <sys/event.h> 6195aab9ccSJohn-Mark Gurney #include <sys/file.h> 62243ac7d8SPeter Wemm #include <sys/poll.h> 6395aab9ccSJohn-Mark Gurney #include <sys/proc.h> 64df8bae1dSRodney W. Grimes 65df8bae1dSRodney W. Grimes #include <sys/socket.h> 66df8bae1dSRodney W. Grimes 67fba9235dSBruce Evans #include <net/if.h> 68df8bae1dSRodney W. Grimes #include <net/bpf.h> 694d621040SChristian S.J. Peron #include <net/bpf_buffer.h> 70ae275efcSJung-uk Kim #ifdef BPF_JITTER 71ae275efcSJung-uk Kim #include <net/bpf_jitter.h> 72ae275efcSJung-uk Kim #endif 734d621040SChristian S.J. Peron #include <net/bpf_zerocopy.h> 74df8bae1dSRodney W. Grimes #include <net/bpfdesc.h> 75df8bae1dSRodney W. Grimes 76df8bae1dSRodney W. Grimes #include <netinet/in.h> 77df8bae1dSRodney W. Grimes #include <netinet/if_ether.h> 78df8bae1dSRodney W. Grimes #include <sys/kernel.h> 79f708ef1bSPoul-Henning Kamp #include <sys/sysctl.h> 807b778b5eSEivind Eklund 81246b5467SSam Leffler #include <net80211/ieee80211_freebsd.h> 82246b5467SSam Leffler 83aed55708SRobert Watson #include <security/mac/mac_framework.h> 84aed55708SRobert Watson 854d621040SChristian S.J. Peron MALLOC_DEFINE(M_BPF, "BPF", "BPF data"); 8687f6c662SJulian Elischer 875bb5f2c9SPeter Wemm #if defined(DEV_BPF) || defined(NETGRAPH_BPF) 8853ac6efbSJulian Elischer 89df8bae1dSRodney W. Grimes #define PRINET 26 /* interruptible */ 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 */ 9969f7644bSChristian S.J. Peron static int bpf_bpfd_cnt; 100df8bae1dSRodney W. Grimes 10119ba8395SChristian S.J. Peron static void bpf_attachd(struct bpf_d *, struct bpf_if *); 10219ba8395SChristian S.J. Peron static void bpf_detachd(struct bpf_d *); 103929ddbbbSAlfred Perlstein static void bpf_freed(struct bpf_d *); 104cb44b6dfSAndrew Thompson static int bpf_movein(struct uio *, int, struct ifnet *, struct mbuf **, 105560a54e1SJung-uk Kim struct sockaddr *, int *, struct bpf_insn *); 106929ddbbbSAlfred Perlstein static int bpf_setif(struct bpf_d *, struct ifreq *); 107929ddbbbSAlfred Perlstein static void bpf_timed_out(void *); 108e7bb21b3SJonathan Lemon static __inline void 109929ddbbbSAlfred Perlstein bpf_wakeup(struct bpf_d *); 1104d621040SChristian S.J. Peron static void catchpacket(struct bpf_d *, u_char *, u_int, u_int, 1114d621040SChristian S.J. Peron void (*)(struct bpf_d *, caddr_t, u_int, void *, u_int), 11291433904SDavid Malone struct timeval *); 113929ddbbbSAlfred Perlstein static void reset_d(struct bpf_d *); 11493e39f0bSChristian S.J. Peron static int bpf_setf(struct bpf_d *, struct bpf_program *, u_long cmd); 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); 119a3272e3cSChristian S.J. Peron static void bpf_drvinit(void *); 1206a113b3dSRobert Watson static void bpf_clone(void *, struct ucred *, char *, int, struct cdev **); 12169f7644bSChristian S.J. Peron static int bpf_stats_sysctl(SYSCTL_HANDLER_ARGS); 12269f7644bSChristian S.J. Peron 12369f7644bSChristian S.J. Peron SYSCTL_NODE(_net, OID_AUTO, bpf, CTLFLAG_RW, 0, "bpf sysctl"); 12469f7644bSChristian S.J. Peron static int bpf_maxinsns = BPF_MAXINSNS; 12569f7644bSChristian S.J. Peron SYSCTL_INT(_net_bpf, OID_AUTO, maxinsns, CTLFLAG_RW, 12669f7644bSChristian S.J. Peron &bpf_maxinsns, 0, "Maximum bpf program instructions"); 1274d621040SChristian S.J. Peron static int bpf_zerocopy_enable = 0; 1284d621040SChristian S.J. Peron SYSCTL_INT(_net_bpf, OID_AUTO, zerocopy_enable, CTLFLAG_RW, 1294d621040SChristian S.J. Peron &bpf_zerocopy_enable, 0, "Enable new zero-copy BPF buffer sessions"); 13069f7644bSChristian S.J. Peron SYSCTL_NODE(_net_bpf, OID_AUTO, stats, CTLFLAG_RW, 13169f7644bSChristian S.J. Peron bpf_stats_sysctl, "bpf statistics portal"); 132df8bae1dSRodney W. Grimes 13387f6c662SJulian Elischer static d_open_t bpfopen; 13487f6c662SJulian Elischer static d_close_t bpfclose; 13587f6c662SJulian Elischer static d_read_t bpfread; 13687f6c662SJulian Elischer static d_write_t bpfwrite; 13787f6c662SJulian Elischer static d_ioctl_t bpfioctl; 138243ac7d8SPeter Wemm static d_poll_t bpfpoll; 13995aab9ccSJohn-Mark Gurney static d_kqfilter_t bpfkqfilter; 14087f6c662SJulian Elischer 1414e2f199eSPoul-Henning Kamp static struct cdevsw bpf_cdevsw = { 142dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 1437ac40f5fSPoul-Henning Kamp .d_open = bpfopen, 1447ac40f5fSPoul-Henning Kamp .d_close = bpfclose, 1457ac40f5fSPoul-Henning Kamp .d_read = bpfread, 1467ac40f5fSPoul-Henning Kamp .d_write = bpfwrite, 1477ac40f5fSPoul-Henning Kamp .d_ioctl = bpfioctl, 1487ac40f5fSPoul-Henning Kamp .d_poll = bpfpoll, 1497ac40f5fSPoul-Henning Kamp .d_name = "bpf", 15095aab9ccSJohn-Mark Gurney .d_kqfilter = bpfkqfilter, 1514e2f199eSPoul-Henning Kamp }; 15287f6c662SJulian Elischer 15395aab9ccSJohn-Mark Gurney static struct filterops bpfread_filtops = 15495aab9ccSJohn-Mark Gurney { 1, NULL, filt_bpfdetach, filt_bpfread }; 15587f6c662SJulian Elischer 1564d621040SChristian S.J. Peron /* 1574d621040SChristian S.J. Peron * Wrapper functions for various buffering methods. If the set of buffer 1584d621040SChristian S.J. Peron * modes expands, we will probably want to introduce a switch data structure 1594d621040SChristian S.J. Peron * similar to protosw, et. 1604d621040SChristian S.J. Peron */ 1614d621040SChristian S.J. Peron static void 1624d621040SChristian S.J. Peron bpf_append_bytes(struct bpf_d *d, caddr_t buf, u_int offset, void *src, 1634d621040SChristian S.J. Peron u_int len) 1644d621040SChristian S.J. Peron { 1654d621040SChristian S.J. Peron 1664d621040SChristian S.J. Peron BPFD_LOCK_ASSERT(d); 1674d621040SChristian S.J. Peron 1684d621040SChristian S.J. Peron switch (d->bd_bufmode) { 1694d621040SChristian S.J. Peron case BPF_BUFMODE_BUFFER: 1704d621040SChristian S.J. Peron return (bpf_buffer_append_bytes(d, buf, offset, src, len)); 1714d621040SChristian S.J. Peron 1724d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 1734d621040SChristian S.J. Peron d->bd_zcopy++; 1744d621040SChristian S.J. Peron return (bpf_zerocopy_append_bytes(d, buf, offset, src, len)); 1754d621040SChristian S.J. Peron 1764d621040SChristian S.J. Peron default: 1774d621040SChristian S.J. Peron panic("bpf_buf_append_bytes"); 1784d621040SChristian S.J. Peron } 1794d621040SChristian S.J. Peron } 1804d621040SChristian S.J. Peron 1814d621040SChristian S.J. Peron static void 1824d621040SChristian S.J. Peron bpf_append_mbuf(struct bpf_d *d, caddr_t buf, u_int offset, void *src, 1834d621040SChristian S.J. Peron u_int len) 1844d621040SChristian S.J. Peron { 1854d621040SChristian S.J. Peron 1864d621040SChristian S.J. Peron BPFD_LOCK_ASSERT(d); 1874d621040SChristian S.J. Peron 1884d621040SChristian S.J. Peron switch (d->bd_bufmode) { 1894d621040SChristian S.J. Peron case BPF_BUFMODE_BUFFER: 1904d621040SChristian S.J. Peron return (bpf_buffer_append_mbuf(d, buf, offset, src, len)); 1914d621040SChristian S.J. Peron 1924d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 1934d621040SChristian S.J. Peron d->bd_zcopy++; 1944d621040SChristian S.J. Peron return (bpf_zerocopy_append_mbuf(d, buf, offset, src, len)); 1954d621040SChristian S.J. Peron 1964d621040SChristian S.J. Peron default: 1974d621040SChristian S.J. Peron panic("bpf_buf_append_mbuf"); 1984d621040SChristian S.J. Peron } 1994d621040SChristian S.J. Peron } 2004d621040SChristian S.J. Peron 2014d621040SChristian S.J. Peron /* 2024d621040SChristian S.J. Peron * If the buffer mechanism has a way to decide that a held buffer can be made 2034d621040SChristian S.J. Peron * free, then it is exposed via the bpf_canfreebuf() interface. (1) is 2044d621040SChristian S.J. Peron * returned if the buffer can be discarded, (0) is returned if it cannot. 2054d621040SChristian S.J. Peron */ 2064d621040SChristian S.J. Peron static int 2074d621040SChristian S.J. Peron bpf_canfreebuf(struct bpf_d *d) 2084d621040SChristian S.J. Peron { 2094d621040SChristian S.J. Peron 2104d621040SChristian S.J. Peron BPFD_LOCK_ASSERT(d); 2114d621040SChristian S.J. Peron 2124d621040SChristian S.J. Peron switch (d->bd_bufmode) { 2134d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 2144d621040SChristian S.J. Peron return (bpf_zerocopy_canfreebuf(d)); 2154d621040SChristian S.J. Peron } 2164d621040SChristian S.J. Peron return (0); 2174d621040SChristian S.J. Peron } 2184d621040SChristian S.J. Peron 219a7a91e65SRobert Watson /* 220a7a91e65SRobert Watson * Allow the buffer model to indicate that the current store buffer is 221a7a91e65SRobert Watson * immutable, regardless of the appearance of space. Return (1) if the 222a7a91e65SRobert Watson * buffer is writable, and (0) if not. 223a7a91e65SRobert Watson */ 224a7a91e65SRobert Watson static int 225a7a91e65SRobert Watson bpf_canwritebuf(struct bpf_d *d) 226a7a91e65SRobert Watson { 227a7a91e65SRobert Watson 228a7a91e65SRobert Watson BPFD_LOCK_ASSERT(d); 229a7a91e65SRobert Watson 230a7a91e65SRobert Watson switch (d->bd_bufmode) { 231a7a91e65SRobert Watson case BPF_BUFMODE_ZBUF: 232a7a91e65SRobert Watson return (bpf_zerocopy_canwritebuf(d)); 233a7a91e65SRobert Watson } 234a7a91e65SRobert Watson return (1); 235a7a91e65SRobert Watson } 236a7a91e65SRobert Watson 237a7a91e65SRobert Watson /* 238a7a91e65SRobert Watson * Notify buffer model that an attempt to write to the store buffer has 239a7a91e65SRobert Watson * resulted in a dropped packet, in which case the buffer may be considered 240a7a91e65SRobert Watson * full. 241a7a91e65SRobert Watson */ 242a7a91e65SRobert Watson static void 243a7a91e65SRobert Watson bpf_buffull(struct bpf_d *d) 244a7a91e65SRobert Watson { 245a7a91e65SRobert Watson 246a7a91e65SRobert Watson BPFD_LOCK_ASSERT(d); 247a7a91e65SRobert Watson 248a7a91e65SRobert Watson switch (d->bd_bufmode) { 249a7a91e65SRobert Watson case BPF_BUFMODE_ZBUF: 250a7a91e65SRobert Watson bpf_zerocopy_buffull(d); 251a7a91e65SRobert Watson break; 252a7a91e65SRobert Watson } 253a7a91e65SRobert Watson } 254a7a91e65SRobert Watson 255a7a91e65SRobert Watson /* 256a7a91e65SRobert Watson * Notify the buffer model that a buffer has moved into the hold position. 257a7a91e65SRobert Watson */ 2584d621040SChristian S.J. Peron void 2594d621040SChristian S.J. Peron bpf_bufheld(struct bpf_d *d) 2604d621040SChristian S.J. Peron { 2614d621040SChristian S.J. Peron 2624d621040SChristian S.J. Peron BPFD_LOCK_ASSERT(d); 2634d621040SChristian S.J. Peron 2644d621040SChristian S.J. Peron switch (d->bd_bufmode) { 2654d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 2664d621040SChristian S.J. Peron bpf_zerocopy_bufheld(d); 2674d621040SChristian S.J. Peron break; 2684d621040SChristian S.J. Peron } 2694d621040SChristian S.J. Peron } 2704d621040SChristian S.J. Peron 2714d621040SChristian S.J. Peron static void 2724d621040SChristian S.J. Peron bpf_free(struct bpf_d *d) 2734d621040SChristian S.J. Peron { 2744d621040SChristian S.J. Peron 2754d621040SChristian S.J. Peron switch (d->bd_bufmode) { 2764d621040SChristian S.J. Peron case BPF_BUFMODE_BUFFER: 2774d621040SChristian S.J. Peron return (bpf_buffer_free(d)); 2784d621040SChristian S.J. Peron 2794d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 2804d621040SChristian S.J. Peron return (bpf_zerocopy_free(d)); 2814d621040SChristian S.J. Peron 2824d621040SChristian S.J. Peron default: 2834d621040SChristian S.J. Peron panic("bpf_buf_free"); 2844d621040SChristian S.J. Peron } 2854d621040SChristian S.J. Peron } 2864d621040SChristian S.J. Peron 2874d621040SChristian S.J. Peron static int 2884d621040SChristian S.J. Peron bpf_uiomove(struct bpf_d *d, caddr_t buf, u_int len, struct uio *uio) 2894d621040SChristian S.J. Peron { 2904d621040SChristian S.J. Peron 2914d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_BUFFER) 2924d621040SChristian S.J. Peron return (EOPNOTSUPP); 2934d621040SChristian S.J. Peron return (bpf_buffer_uiomove(d, buf, len, uio)); 2944d621040SChristian S.J. Peron } 2954d621040SChristian S.J. Peron 2964d621040SChristian S.J. Peron static int 2974d621040SChristian S.J. Peron bpf_ioctl_sblen(struct bpf_d *d, u_int *i) 2984d621040SChristian S.J. Peron { 2994d621040SChristian S.J. Peron 3004d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_BUFFER) 3014d621040SChristian S.J. Peron return (EOPNOTSUPP); 3024d621040SChristian S.J. Peron return (bpf_buffer_ioctl_sblen(d, i)); 3034d621040SChristian S.J. Peron } 3044d621040SChristian S.J. Peron 3054d621040SChristian S.J. Peron static int 3064d621040SChristian S.J. Peron bpf_ioctl_getzmax(struct thread *td, struct bpf_d *d, size_t *i) 3074d621040SChristian S.J. Peron { 3084d621040SChristian S.J. Peron 3094d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_ZBUF) 3104d621040SChristian S.J. Peron return (EOPNOTSUPP); 3114d621040SChristian S.J. Peron return (bpf_zerocopy_ioctl_getzmax(td, d, i)); 3124d621040SChristian S.J. Peron } 3134d621040SChristian S.J. Peron 3144d621040SChristian S.J. Peron static int 3154d621040SChristian S.J. Peron bpf_ioctl_rotzbuf(struct thread *td, struct bpf_d *d, struct bpf_zbuf *bz) 3164d621040SChristian S.J. Peron { 3174d621040SChristian S.J. Peron 3184d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_ZBUF) 3194d621040SChristian S.J. Peron return (EOPNOTSUPP); 3204d621040SChristian S.J. Peron return (bpf_zerocopy_ioctl_rotzbuf(td, d, bz)); 3214d621040SChristian S.J. Peron } 3224d621040SChristian S.J. Peron 3234d621040SChristian S.J. Peron static int 3244d621040SChristian S.J. Peron bpf_ioctl_setzbuf(struct thread *td, struct bpf_d *d, struct bpf_zbuf *bz) 3254d621040SChristian S.J. Peron { 3264d621040SChristian S.J. Peron 3274d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_ZBUF) 3284d621040SChristian S.J. Peron return (EOPNOTSUPP); 3294d621040SChristian S.J. Peron return (bpf_zerocopy_ioctl_setzbuf(td, d, bz)); 3304d621040SChristian S.J. Peron } 3314d621040SChristian S.J. Peron 3324d621040SChristian S.J. Peron /* 3334d621040SChristian S.J. Peron * General BPF functions. 3344d621040SChristian S.J. Peron */ 335df8bae1dSRodney W. Grimes static int 336cb44b6dfSAndrew Thompson bpf_movein(struct uio *uio, int linktype, struct ifnet *ifp, struct mbuf **mp, 337560a54e1SJung-uk Kim struct sockaddr *sockp, int *hdrlen, struct bpf_insn *wfilter) 338df8bae1dSRodney W. Grimes { 339246b5467SSam Leffler const struct ieee80211_bpf_params *p; 340cb44b6dfSAndrew Thompson struct ether_header *eh; 341df8bae1dSRodney W. Grimes struct mbuf *m; 342df8bae1dSRodney W. Grimes int error; 343df8bae1dSRodney W. Grimes int len; 344df8bae1dSRodney W. Grimes int hlen; 34593e39f0bSChristian S.J. Peron int slen; 346df8bae1dSRodney W. Grimes 347df8bae1dSRodney W. Grimes /* 348df8bae1dSRodney W. Grimes * Build a sockaddr based on the data link layer type. 349df8bae1dSRodney W. Grimes * We do this at this level because the ethernet header 350df8bae1dSRodney W. Grimes * is copied directly into the data field of the sockaddr. 351df8bae1dSRodney W. Grimes * In the case of SLIP, there is no header and the packet 352df8bae1dSRodney W. Grimes * is forwarded as is. 353df8bae1dSRodney W. Grimes * Also, we are careful to leave room at the front of the mbuf 354df8bae1dSRodney W. Grimes * for the link level header. 355df8bae1dSRodney W. Grimes */ 356df8bae1dSRodney W. Grimes switch (linktype) { 357df8bae1dSRodney W. Grimes 358df8bae1dSRodney W. Grimes case DLT_SLIP: 359df8bae1dSRodney W. Grimes sockp->sa_family = AF_INET; 360df8bae1dSRodney W. Grimes hlen = 0; 361df8bae1dSRodney W. Grimes break; 362df8bae1dSRodney W. Grimes 363df8bae1dSRodney W. Grimes case DLT_EN10MB: 364df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 365df8bae1dSRodney W. Grimes /* XXX Would MAXLINKHDR be better? */ 366797f247bSMatthew N. Dodd hlen = ETHER_HDR_LEN; 367df8bae1dSRodney W. Grimes break; 368df8bae1dSRodney W. Grimes 369df8bae1dSRodney W. Grimes case DLT_FDDI: 370d41f24e7SDavid Greenman sockp->sa_family = AF_IMPLINK; 371d41f24e7SDavid Greenman hlen = 0; 372df8bae1dSRodney W. Grimes break; 373df8bae1dSRodney W. Grimes 37422f05c43SAndrey A. Chernov case DLT_RAW: 375df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 376df8bae1dSRodney W. Grimes hlen = 0; 377df8bae1dSRodney W. Grimes break; 378df8bae1dSRodney W. Grimes 37901399f34SDavid Malone case DLT_NULL: 38001399f34SDavid Malone /* 38101399f34SDavid Malone * null interface types require a 4 byte pseudo header which 38201399f34SDavid Malone * corresponds to the address family of the packet. 38301399f34SDavid Malone */ 38401399f34SDavid Malone sockp->sa_family = AF_UNSPEC; 38501399f34SDavid Malone hlen = 4; 38601399f34SDavid Malone break; 38701399f34SDavid Malone 3884f53e3ccSKenjiro Cho case DLT_ATM_RFC1483: 3894f53e3ccSKenjiro Cho /* 3904f53e3ccSKenjiro Cho * en atm driver requires 4-byte atm pseudo header. 3914f53e3ccSKenjiro Cho * though it isn't standard, vpi:vci needs to be 3924f53e3ccSKenjiro Cho * specified anyway. 3934f53e3ccSKenjiro Cho */ 3944f53e3ccSKenjiro Cho sockp->sa_family = AF_UNSPEC; 3954f53e3ccSKenjiro Cho hlen = 12; /* XXX 4(ATM_PH) + 3(LLC) + 5(SNAP) */ 3964f53e3ccSKenjiro Cho break; 3974f53e3ccSKenjiro Cho 39830fa52a6SBrian Somers case DLT_PPP: 39930fa52a6SBrian Somers sockp->sa_family = AF_UNSPEC; 40030fa52a6SBrian Somers hlen = 4; /* This should match PPP_HDRLEN */ 40130fa52a6SBrian Somers break; 40230fa52a6SBrian Somers 403246b5467SSam Leffler case DLT_IEEE802_11: /* IEEE 802.11 wireless */ 404246b5467SSam Leffler sockp->sa_family = AF_IEEE80211; 405246b5467SSam Leffler hlen = 0; 406246b5467SSam Leffler break; 407246b5467SSam Leffler 408246b5467SSam Leffler case DLT_IEEE802_11_RADIO: /* IEEE 802.11 wireless w/ phy params */ 409246b5467SSam Leffler sockp->sa_family = AF_IEEE80211; 410246b5467SSam Leffler sockp->sa_len = 12; /* XXX != 0 */ 411246b5467SSam Leffler hlen = sizeof(struct ieee80211_bpf_params); 412246b5467SSam Leffler break; 413246b5467SSam Leffler 414df8bae1dSRodney W. Grimes default: 415df8bae1dSRodney W. Grimes return (EIO); 416df8bae1dSRodney W. Grimes } 417df8bae1dSRodney W. Grimes 418df8bae1dSRodney W. Grimes len = uio->uio_resid; 41901399f34SDavid Malone 420cb44b6dfSAndrew Thompson if (len - hlen > ifp->if_mtu) 42101399f34SDavid Malone return (EMSGSIZE); 42201399f34SDavid Malone 423df8bae1dSRodney W. Grimes if ((unsigned)len > MCLBYTES) 424df8bae1dSRodney W. Grimes return (EIO); 425df8bae1dSRodney W. Grimes 426ea26d587SRuslan Ermilov if (len > MHLEN) 427ea26d587SRuslan Ermilov m = m_getcl(M_WAIT, MT_DATA, M_PKTHDR); 428ea26d587SRuslan Ermilov else 429ea26d587SRuslan Ermilov MGETHDR(m, M_WAIT, MT_DATA); 430963e4c2aSGarrett Wollman m->m_pkthdr.len = m->m_len = len; 431963e4c2aSGarrett Wollman m->m_pkthdr.rcvif = NULL; 432df8bae1dSRodney W. Grimes *mp = m; 43324a229f4SSam Leffler 43493e39f0bSChristian S.J. Peron if (m->m_len < hlen) { 43593e39f0bSChristian S.J. Peron error = EPERM; 43693e39f0bSChristian S.J. Peron goto bad; 43793e39f0bSChristian S.J. Peron } 43893e39f0bSChristian S.J. Peron 43993e39f0bSChristian S.J. Peron error = uiomove(mtod(m, u_char *), len, uio); 44093e39f0bSChristian S.J. Peron if (error) 44193e39f0bSChristian S.J. Peron goto bad; 44293e39f0bSChristian S.J. Peron 44393e39f0bSChristian S.J. Peron slen = bpf_filter(wfilter, mtod(m, u_char *), len, len); 44493e39f0bSChristian S.J. Peron if (slen == 0) { 44593e39f0bSChristian S.J. Peron error = EPERM; 44693e39f0bSChristian S.J. Peron goto bad; 44793e39f0bSChristian S.J. Peron } 44893e39f0bSChristian S.J. Peron 449cb44b6dfSAndrew Thompson /* Check for multicast destination */ 450cb44b6dfSAndrew Thompson switch (linktype) { 451cb44b6dfSAndrew Thompson case DLT_EN10MB: 452cb44b6dfSAndrew Thompson eh = mtod(m, struct ether_header *); 453cb44b6dfSAndrew Thompson if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 454cb44b6dfSAndrew Thompson if (bcmp(ifp->if_broadcastaddr, eh->ether_dhost, 455cb44b6dfSAndrew Thompson ETHER_ADDR_LEN) == 0) 456cb44b6dfSAndrew Thompson m->m_flags |= M_BCAST; 457cb44b6dfSAndrew Thompson else 458cb44b6dfSAndrew Thompson m->m_flags |= M_MCAST; 459cb44b6dfSAndrew Thompson } 460cb44b6dfSAndrew Thompson break; 461cb44b6dfSAndrew Thompson } 462cb44b6dfSAndrew Thompson 463df8bae1dSRodney W. Grimes /* 46493e39f0bSChristian S.J. Peron * Make room for link header, and copy it to sockaddr 465df8bae1dSRodney W. Grimes */ 466df8bae1dSRodney W. Grimes if (hlen != 0) { 467246b5467SSam Leffler if (sockp->sa_family == AF_IEEE80211) { 468246b5467SSam Leffler /* 469246b5467SSam Leffler * Collect true length from the parameter header 470246b5467SSam Leffler * NB: sockp is known to be zero'd so if we do a 471246b5467SSam Leffler * short copy unspecified parameters will be 472246b5467SSam Leffler * zero. 473246b5467SSam Leffler * NB: packet may not be aligned after stripping 474246b5467SSam Leffler * bpf params 475246b5467SSam Leffler * XXX check ibp_vers 476246b5467SSam Leffler */ 477246b5467SSam Leffler p = mtod(m, const struct ieee80211_bpf_params *); 478246b5467SSam Leffler hlen = p->ibp_len; 479246b5467SSam Leffler if (hlen > sizeof(sockp->sa_data)) { 480246b5467SSam Leffler error = EINVAL; 481246b5467SSam Leffler goto bad; 482246b5467SSam Leffler } 483246b5467SSam Leffler } 48493e39f0bSChristian S.J. Peron bcopy(m->m_data, sockp->sa_data, hlen); 485df8bae1dSRodney W. Grimes } 486560a54e1SJung-uk Kim *hdrlen = hlen; 48793e39f0bSChristian S.J. Peron 488df8bae1dSRodney W. Grimes return (0); 489df8bae1dSRodney W. Grimes bad: 490df8bae1dSRodney W. Grimes m_freem(m); 491df8bae1dSRodney W. Grimes return (error); 492df8bae1dSRodney W. Grimes } 493df8bae1dSRodney W. Grimes 494df8bae1dSRodney W. Grimes /* 495df8bae1dSRodney W. Grimes * Attach file to the bpf interface, i.e. make d listen on bp. 496df8bae1dSRodney W. Grimes */ 497df8bae1dSRodney W. Grimes static void 49819ba8395SChristian S.J. Peron bpf_attachd(struct bpf_d *d, struct bpf_if *bp) 499df8bae1dSRodney W. Grimes { 500df8bae1dSRodney W. Grimes /* 501df8bae1dSRodney W. Grimes * Point d at bp, and add d to the interface's list of listeners. 502df8bae1dSRodney W. Grimes * Finally, point the driver's bpf cookie at the interface so 503df8bae1dSRodney W. Grimes * it will divert packets to bpf. 504df8bae1dSRodney W. Grimes */ 505e7bb21b3SJonathan Lemon BPFIF_LOCK(bp); 506df8bae1dSRodney W. Grimes d->bd_bif = bp; 5074a3feeaaSRobert Watson LIST_INSERT_HEAD(&bp->bif_dlist, d, bd_next); 508df8bae1dSRodney W. Grimes 50969f7644bSChristian S.J. Peron bpf_bpfd_cnt++; 510e7bb21b3SJonathan Lemon BPFIF_UNLOCK(bp); 511df8bae1dSRodney W. Grimes } 512df8bae1dSRodney W. Grimes 513df8bae1dSRodney W. Grimes /* 514df8bae1dSRodney W. Grimes * Detach a file from its interface. 515df8bae1dSRodney W. Grimes */ 516df8bae1dSRodney W. Grimes static void 51719ba8395SChristian S.J. Peron bpf_detachd(struct bpf_d *d) 518df8bae1dSRodney W. Grimes { 5196e891d64SPoul-Henning Kamp int error; 520df8bae1dSRodney W. Grimes struct bpf_if *bp; 52146448b5aSRobert Watson struct ifnet *ifp; 522df8bae1dSRodney W. Grimes 523df8bae1dSRodney W. Grimes bp = d->bd_bif; 52446448b5aSRobert Watson BPFIF_LOCK(bp); 52546448b5aSRobert Watson BPFD_LOCK(d); 52646448b5aSRobert Watson ifp = d->bd_bif->bif_ifp; 52746448b5aSRobert Watson 52846448b5aSRobert Watson /* 52946448b5aSRobert Watson * Remove d from the interface's descriptor list. 53046448b5aSRobert Watson */ 53146448b5aSRobert Watson LIST_REMOVE(d, bd_next); 53246448b5aSRobert Watson 53369f7644bSChristian S.J. Peron bpf_bpfd_cnt--; 534572bde2aSRobert Watson d->bd_bif = NULL; 53546448b5aSRobert Watson BPFD_UNLOCK(d); 53646448b5aSRobert Watson BPFIF_UNLOCK(bp); 53746448b5aSRobert Watson 538df8bae1dSRodney W. Grimes /* 539df8bae1dSRodney W. Grimes * Check if this descriptor had requested promiscuous mode. 540df8bae1dSRodney W. Grimes * If so, turn it off. 541df8bae1dSRodney W. Grimes */ 542df8bae1dSRodney W. Grimes if (d->bd_promisc) { 543df8bae1dSRodney W. Grimes d->bd_promisc = 0; 54446448b5aSRobert Watson error = ifpromisc(ifp, 0); 5456e891d64SPoul-Henning Kamp if (error != 0 && error != ENXIO) { 546df8bae1dSRodney W. Grimes /* 5476e891d64SPoul-Henning Kamp * ENXIO can happen if a pccard is unplugged 548df8bae1dSRodney W. Grimes * Something is really wrong if we were able to put 549df8bae1dSRodney W. Grimes * the driver into promiscuous mode, but can't 550df8bae1dSRodney W. Grimes * take it out. 551df8bae1dSRodney W. Grimes */ 5528eab61f3SSam Leffler if_printf(bp->bif_ifp, 5538eab61f3SSam Leffler "bpf_detach: ifpromisc failed (%d)\n", error); 5546e891d64SPoul-Henning Kamp } 555df8bae1dSRodney W. Grimes } 556df8bae1dSRodney W. Grimes } 557df8bae1dSRodney W. Grimes 558df8bae1dSRodney W. Grimes /* 559df8bae1dSRodney W. Grimes * Open ethernet device. Returns ENXIO for illegal minor device number, 560df8bae1dSRodney W. Grimes * EBUSY if file is open by another process. 561df8bae1dSRodney W. Grimes */ 562df8bae1dSRodney W. Grimes /* ARGSUSED */ 56387f6c662SJulian Elischer static int 56419ba8395SChristian S.J. Peron bpfopen(struct cdev *dev, int flags, int fmt, struct thread *td) 565df8bae1dSRodney W. Grimes { 566e7bb21b3SJonathan Lemon struct bpf_d *d; 567df8bae1dSRodney W. Grimes 568e7bb21b3SJonathan Lemon mtx_lock(&bpf_mtx); 569bd3a5320SPoul-Henning Kamp d = dev->si_drv1; 570df8bae1dSRodney W. Grimes /* 571df8bae1dSRodney W. Grimes * Each minor can be opened by only one process. If the requested 572df8bae1dSRodney W. Grimes * minor is in use, return EBUSY. 573df8bae1dSRodney W. Grimes */ 574d17d8184SRobert Watson if (d != NULL) { 575e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 576df8bae1dSRodney W. Grimes return (EBUSY); 577e7bb21b3SJonathan Lemon } 578e7bb21b3SJonathan Lemon dev->si_drv1 = (struct bpf_d *)~0; /* mark device in use */ 579e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 580e7bb21b3SJonathan Lemon 581d1d74c28SJohn Baldwin if ((dev->si_flags & SI_NAMED) == 0) 582b0d17ba6SPoul-Henning Kamp make_dev(&bpf_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 0600, 583b0d17ba6SPoul-Henning Kamp "bpf%d", dev2unit(dev)); 584a163d034SWarner Losh MALLOC(d, struct bpf_d *, sizeof(*d), M_BPF, M_WAITOK | M_ZERO); 585bd3a5320SPoul-Henning Kamp dev->si_drv1 = d; 5864d621040SChristian S.J. Peron 5874d621040SChristian S.J. Peron /* 5884d621040SChristian S.J. Peron * For historical reasons, perform a one-time initialization call to 5894d621040SChristian S.J. Peron * the buffer routines, even though we're not yet committed to a 5904d621040SChristian S.J. Peron * particular buffer method. 5914d621040SChristian S.J. Peron */ 5924d621040SChristian S.J. Peron bpf_buffer_init(d); 5934d621040SChristian S.J. Peron d->bd_bufmode = BPF_BUFMODE_BUFFER; 59400a83887SPaul Traina d->bd_sig = SIGIO; 595560a54e1SJung-uk Kim d->bd_direction = BPF_D_INOUT; 59669f7644bSChristian S.J. Peron d->bd_pid = td->td_proc->p_pid; 59782f4445dSRobert Watson #ifdef MAC 59830d239bcSRobert Watson mac_bpfdesc_init(d); 59930d239bcSRobert Watson mac_bpfdesc_create(td->td_ucred, d); 60082f4445dSRobert Watson #endif 6016008862bSJohn Baldwin mtx_init(&d->bd_mtx, devtoname(dev), "bpf cdev lock", MTX_DEF); 602c6b28997SRobert Watson callout_init(&d->bd_callout, CALLOUT_MPSAFE); 603571dcd15SSuleiman Souhlal knlist_init(&d->bd_sel.si_note, &d->bd_mtx, NULL, NULL, NULL); 604df8bae1dSRodney W. Grimes 605df8bae1dSRodney W. Grimes return (0); 606df8bae1dSRodney W. Grimes } 607df8bae1dSRodney W. Grimes 608df8bae1dSRodney W. Grimes /* 609df8bae1dSRodney W. Grimes * Close the descriptor by detaching it from its interface, 610df8bae1dSRodney W. Grimes * deallocating its buffers, and marking it free. 611df8bae1dSRodney W. Grimes */ 612df8bae1dSRodney W. Grimes /* ARGSUSED */ 61387f6c662SJulian Elischer static int 61419ba8395SChristian S.J. Peron bpfclose(struct cdev *dev, int flags, int fmt, struct thread *td) 615df8bae1dSRodney W. Grimes { 616e7bb21b3SJonathan Lemon struct bpf_d *d = dev->si_drv1; 617df8bae1dSRodney W. Grimes 61881bda851SJohn Polstra BPFD_LOCK(d); 61981bda851SJohn Polstra if (d->bd_state == BPF_WAITING) 62081bda851SJohn Polstra callout_stop(&d->bd_callout); 62181bda851SJohn Polstra d->bd_state = BPF_IDLE; 62281bda851SJohn Polstra BPFD_UNLOCK(d); 623e649887bSAlfred Perlstein funsetown(&d->bd_sigio); 624e7bb21b3SJonathan Lemon mtx_lock(&bpf_mtx); 625df8bae1dSRodney W. Grimes if (d->bd_bif) 626df8bae1dSRodney W. Grimes bpf_detachd(d); 627e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 6284549709fSBrian Feldman selwakeuppri(&d->bd_sel, PRINET); 62982f4445dSRobert Watson #ifdef MAC 63030d239bcSRobert Watson mac_bpfdesc_destroy(d); 63182f4445dSRobert Watson #endif /* MAC */ 632ad3b9257SJohn-Mark Gurney knlist_destroy(&d->bd_sel.si_note); 633df8bae1dSRodney W. Grimes bpf_freed(d); 634d17d8184SRobert Watson dev->si_drv1 = NULL; 635d722be54SLuigi Rizzo free(d, M_BPF); 636df8bae1dSRodney W. Grimes 637df8bae1dSRodney W. Grimes return (0); 638df8bae1dSRodney W. Grimes } 639df8bae1dSRodney W. Grimes 640df8bae1dSRodney W. Grimes /* 641df8bae1dSRodney W. Grimes * bpfread - read next chunk of packets from buffers 642df8bae1dSRodney W. Grimes */ 64387f6c662SJulian Elischer static int 64419ba8395SChristian S.J. Peron bpfread(struct cdev *dev, struct uio *uio, int ioflag) 645df8bae1dSRodney W. Grimes { 646e7bb21b3SJonathan Lemon struct bpf_d *d = dev->si_drv1; 64781bda851SJohn Polstra int timed_out; 648df8bae1dSRodney W. Grimes int error; 649df8bae1dSRodney W. Grimes 650df8bae1dSRodney W. Grimes /* 651df8bae1dSRodney W. Grimes * Restrict application to use a buffer the same size as 652df8bae1dSRodney W. Grimes * as kernel buffers. 653df8bae1dSRodney W. Grimes */ 654df8bae1dSRodney W. Grimes if (uio->uio_resid != d->bd_bufsize) 655df8bae1dSRodney W. Grimes return (EINVAL); 656df8bae1dSRodney W. Grimes 657e7bb21b3SJonathan Lemon BPFD_LOCK(d); 65850ed6e07SChristian S.J. Peron d->bd_pid = curthread->td_proc->p_pid; 6594d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_BUFFER) { 6604d621040SChristian S.J. Peron BPFD_UNLOCK(d); 6614d621040SChristian S.J. Peron return (EOPNOTSUPP); 6624d621040SChristian S.J. Peron } 66381bda851SJohn Polstra if (d->bd_state == BPF_WAITING) 66481bda851SJohn Polstra callout_stop(&d->bd_callout); 66581bda851SJohn Polstra timed_out = (d->bd_state == BPF_TIMED_OUT); 66681bda851SJohn Polstra d->bd_state = BPF_IDLE; 667df8bae1dSRodney W. Grimes /* 668df8bae1dSRodney W. Grimes * If the hold buffer is empty, then do a timed sleep, which 669df8bae1dSRodney W. Grimes * ends when the timeout expires or when enough packets 670df8bae1dSRodney W. Grimes * have arrived to fill the store buffer. 671df8bae1dSRodney W. Grimes */ 672572bde2aSRobert Watson while (d->bd_hbuf == NULL) { 67381bda851SJohn Polstra if ((d->bd_immediate || timed_out) && d->bd_slen != 0) { 674df8bae1dSRodney W. Grimes /* 675df8bae1dSRodney W. Grimes * A packet(s) either arrived since the previous 676df8bae1dSRodney W. Grimes * read or arrived while we were asleep. 677df8bae1dSRodney W. Grimes * Rotate the buffers and return what's here. 678df8bae1dSRodney W. Grimes */ 679df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 680df8bae1dSRodney W. Grimes break; 681df8bae1dSRodney W. Grimes } 682de5d9935SRobert Watson 683de5d9935SRobert Watson /* 684de5d9935SRobert Watson * No data is available, check to see if the bpf device 685de5d9935SRobert Watson * is still pointed at a real interface. If not, return 686de5d9935SRobert Watson * ENXIO so that the userland process knows to rebind 687de5d9935SRobert Watson * it before using it again. 688de5d9935SRobert Watson */ 689de5d9935SRobert Watson if (d->bd_bif == NULL) { 690e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 691de5d9935SRobert Watson return (ENXIO); 692de5d9935SRobert Watson } 693de5d9935SRobert Watson 694e76eee55SPoul-Henning Kamp if (ioflag & O_NONBLOCK) { 695e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 696fba3cfdeSJohn Polstra return (EWOULDBLOCK); 697fba3cfdeSJohn Polstra } 698521f364bSDag-Erling Smørgrav error = msleep(d, &d->bd_mtx, PRINET|PCATCH, 699e7bb21b3SJonathan Lemon "bpf", d->bd_rtout); 700df8bae1dSRodney W. Grimes if (error == EINTR || error == ERESTART) { 701e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 702df8bae1dSRodney W. Grimes return (error); 703df8bae1dSRodney W. Grimes } 704df8bae1dSRodney W. Grimes if (error == EWOULDBLOCK) { 705df8bae1dSRodney W. Grimes /* 706df8bae1dSRodney W. Grimes * On a timeout, return what's in the buffer, 707df8bae1dSRodney W. Grimes * which may be nothing. If there is something 708df8bae1dSRodney W. Grimes * in the store buffer, we can rotate the buffers. 709df8bae1dSRodney W. Grimes */ 710df8bae1dSRodney W. Grimes if (d->bd_hbuf) 711df8bae1dSRodney W. Grimes /* 712df8bae1dSRodney W. Grimes * We filled up the buffer in between 713df8bae1dSRodney W. Grimes * getting the timeout and arriving 714df8bae1dSRodney W. Grimes * here, so we don't need to rotate. 715df8bae1dSRodney W. Grimes */ 716df8bae1dSRodney W. Grimes break; 717df8bae1dSRodney W. Grimes 718df8bae1dSRodney W. Grimes if (d->bd_slen == 0) { 719e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 720df8bae1dSRodney W. Grimes return (0); 721df8bae1dSRodney W. Grimes } 722df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 723df8bae1dSRodney W. Grimes break; 724df8bae1dSRodney W. Grimes } 725df8bae1dSRodney W. Grimes } 726df8bae1dSRodney W. Grimes /* 727df8bae1dSRodney W. Grimes * At this point, we know we have something in the hold slot. 728df8bae1dSRodney W. Grimes */ 729e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 730df8bae1dSRodney W. Grimes 731df8bae1dSRodney W. Grimes /* 732df8bae1dSRodney W. Grimes * Move data from hold buffer into user space. 733df8bae1dSRodney W. Grimes * We know the entire buffer is transferred since 734df8bae1dSRodney W. Grimes * we checked above that the read buffer is bpf_bufsize bytes. 73531b32e6dSRobert Watson * 73631b32e6dSRobert Watson * XXXRW: More synchronization needed here: what if a second thread 73731b32e6dSRobert Watson * issues a read on the same fd at the same time? Don't want this 73831b32e6dSRobert Watson * getting invalidated. 739df8bae1dSRodney W. Grimes */ 7404d621040SChristian S.J. Peron error = bpf_uiomove(d, d->bd_hbuf, d->bd_hlen, uio); 741df8bae1dSRodney W. Grimes 742e7bb21b3SJonathan Lemon BPFD_LOCK(d); 743df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 744572bde2aSRobert Watson d->bd_hbuf = NULL; 745df8bae1dSRodney W. Grimes d->bd_hlen = 0; 746e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 747df8bae1dSRodney W. Grimes 748df8bae1dSRodney W. Grimes return (error); 749df8bae1dSRodney W. Grimes } 750df8bae1dSRodney W. Grimes 751df8bae1dSRodney W. Grimes /* 752df8bae1dSRodney W. Grimes * If there are processes sleeping on this descriptor, wake them up. 753df8bae1dSRodney W. Grimes */ 754e7bb21b3SJonathan Lemon static __inline void 75519ba8395SChristian S.J. Peron bpf_wakeup(struct bpf_d *d) 756df8bae1dSRodney W. Grimes { 757a3272e3cSChristian S.J. Peron 758a3272e3cSChristian S.J. Peron BPFD_LOCK_ASSERT(d); 75981bda851SJohn Polstra if (d->bd_state == BPF_WAITING) { 76081bda851SJohn Polstra callout_stop(&d->bd_callout); 76181bda851SJohn Polstra d->bd_state = BPF_IDLE; 76281bda851SJohn Polstra } 763521f364bSDag-Erling Smørgrav wakeup(d); 764831d27a9SDon Lewis if (d->bd_async && d->bd_sig && d->bd_sigio) 765f1320723SAlfred Perlstein pgsigio(&d->bd_sigio, d->bd_sig, 0); 76600a83887SPaul Traina 767512824f8SSeigo Tanimura selwakeuppri(&d->bd_sel, PRINET); 768ad3b9257SJohn-Mark Gurney KNOTE_LOCKED(&d->bd_sel.si_note, 0); 769df8bae1dSRodney W. Grimes } 770df8bae1dSRodney W. Grimes 77181bda851SJohn Polstra static void 77219ba8395SChristian S.J. Peron bpf_timed_out(void *arg) 77381bda851SJohn Polstra { 77481bda851SJohn Polstra struct bpf_d *d = (struct bpf_d *)arg; 77581bda851SJohn Polstra 77681bda851SJohn Polstra BPFD_LOCK(d); 77781bda851SJohn Polstra if (d->bd_state == BPF_WAITING) { 77881bda851SJohn Polstra d->bd_state = BPF_TIMED_OUT; 77981bda851SJohn Polstra if (d->bd_slen != 0) 78081bda851SJohn Polstra bpf_wakeup(d); 78181bda851SJohn Polstra } 78281bda851SJohn Polstra BPFD_UNLOCK(d); 78381bda851SJohn Polstra } 78481bda851SJohn Polstra 78587f6c662SJulian Elischer static int 7864d621040SChristian S.J. Peron bpf_ready(struct bpf_d *d) 7874d621040SChristian S.J. Peron { 7884d621040SChristian S.J. Peron 7894d621040SChristian S.J. Peron BPFD_LOCK_ASSERT(d); 7904d621040SChristian S.J. Peron 7914d621040SChristian S.J. Peron if (!bpf_canfreebuf(d) && d->bd_hlen != 0) 7924d621040SChristian S.J. Peron return (1); 7934d621040SChristian S.J. Peron if ((d->bd_immediate || d->bd_state == BPF_TIMED_OUT) && 7944d621040SChristian S.J. Peron d->bd_slen != 0) 7954d621040SChristian S.J. Peron return (1); 7964d621040SChristian S.J. Peron return (0); 7974d621040SChristian S.J. Peron } 7984d621040SChristian S.J. Peron 7994d621040SChristian S.J. Peron static int 80019ba8395SChristian S.J. Peron bpfwrite(struct cdev *dev, struct uio *uio, int ioflag) 801df8bae1dSRodney W. Grimes { 802e7bb21b3SJonathan Lemon struct bpf_d *d = dev->si_drv1; 803df8bae1dSRodney W. Grimes struct ifnet *ifp; 804560a54e1SJung-uk Kim struct mbuf *m, *mc; 8058240bf1eSRobert Watson struct sockaddr dst; 806560a54e1SJung-uk Kim int error, hlen; 807df8bae1dSRodney W. Grimes 80850ed6e07SChristian S.J. Peron d->bd_pid = curthread->td_proc->p_pid; 8094d621040SChristian S.J. Peron d->bd_wcount++; 8104d621040SChristian S.J. Peron if (d->bd_bif == NULL) { 8114d621040SChristian S.J. Peron d->bd_wdcount++; 812df8bae1dSRodney W. Grimes return (ENXIO); 8134d621040SChristian S.J. Peron } 814df8bae1dSRodney W. Grimes 815df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 816df8bae1dSRodney W. Grimes 8174d621040SChristian S.J. Peron if ((ifp->if_flags & IFF_UP) == 0) { 8184d621040SChristian S.J. Peron d->bd_wdcount++; 8193518d220SSam Leffler return (ENETDOWN); 8204d621040SChristian S.J. Peron } 8213518d220SSam Leffler 8224d621040SChristian S.J. Peron if (uio->uio_resid == 0) { 8234d621040SChristian S.J. Peron d->bd_wdcount++; 824df8bae1dSRodney W. Grimes return (0); 8254d621040SChristian S.J. Peron } 826df8bae1dSRodney W. Grimes 8278240bf1eSRobert Watson bzero(&dst, sizeof(dst)); 828d83e603aSChristian S.J. Peron m = NULL; 829d83e603aSChristian S.J. Peron hlen = 0; 830cb44b6dfSAndrew Thompson error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, ifp, 831560a54e1SJung-uk Kim &m, &dst, &hlen, d->bd_wfilter); 8324d621040SChristian S.J. Peron if (error) { 8334d621040SChristian S.J. Peron d->bd_wdcount++; 834df8bae1dSRodney W. Grimes return (error); 8354d621040SChristian S.J. Peron } 8364d621040SChristian S.J. Peron d->bd_wfcount++; 837114ae644SMike Smith if (d->bd_hdrcmplt) 838114ae644SMike Smith dst.sa_family = pseudo_AF_HDRCMPLT; 839114ae644SMike Smith 840560a54e1SJung-uk Kim if (d->bd_feedback) { 841560a54e1SJung-uk Kim mc = m_dup(m, M_DONTWAIT); 842560a54e1SJung-uk Kim if (mc != NULL) 843560a54e1SJung-uk Kim mc->m_pkthdr.rcvif = ifp; 8448cd892f7SJung-uk Kim /* Set M_PROMISC for outgoing packets to be discarded. */ 8458cd892f7SJung-uk Kim if (d->bd_direction == BPF_D_INOUT) 8468cd892f7SJung-uk Kim m->m_flags |= M_PROMISC; 847560a54e1SJung-uk Kim } else 848560a54e1SJung-uk Kim mc = NULL; 849560a54e1SJung-uk Kim 850560a54e1SJung-uk Kim m->m_pkthdr.len -= hlen; 851560a54e1SJung-uk Kim m->m_len -= hlen; 852560a54e1SJung-uk Kim m->m_data += hlen; /* XXX */ 853560a54e1SJung-uk Kim 85482f4445dSRobert Watson #ifdef MAC 855f747d2ddSRobert Watson BPFD_LOCK(d); 85630d239bcSRobert Watson mac_bpfdesc_create_mbuf(d, m); 857560a54e1SJung-uk Kim if (mc != NULL) 85830d239bcSRobert Watson mac_bpfdesc_create_mbuf(d, mc); 859f747d2ddSRobert Watson BPFD_UNLOCK(d); 86082f4445dSRobert Watson #endif 861560a54e1SJung-uk Kim 862572bde2aSRobert Watson error = (*ifp->if_output)(ifp, m, &dst, NULL); 8634d621040SChristian S.J. Peron if (error) 8644d621040SChristian S.J. Peron d->bd_wdcount++; 865560a54e1SJung-uk Kim 866560a54e1SJung-uk Kim if (mc != NULL) { 8670bf686c1SRobert Watson if (error == 0) 868560a54e1SJung-uk Kim (*ifp->if_input)(ifp, mc); 8690bf686c1SRobert Watson else 870560a54e1SJung-uk Kim m_freem(mc); 871560a54e1SJung-uk Kim } 872560a54e1SJung-uk Kim 873df8bae1dSRodney W. Grimes return (error); 874df8bae1dSRodney W. Grimes } 875df8bae1dSRodney W. Grimes 876df8bae1dSRodney W. Grimes /* 877df8bae1dSRodney W. Grimes * Reset a descriptor by flushing its packet buffer and clearing the 878e7bb21b3SJonathan Lemon * receive and drop counts. 879df8bae1dSRodney W. Grimes */ 880df8bae1dSRodney W. Grimes static void 88119ba8395SChristian S.J. Peron reset_d(struct bpf_d *d) 882df8bae1dSRodney W. Grimes { 883e7bb21b3SJonathan Lemon 884e7bb21b3SJonathan Lemon mtx_assert(&d->bd_mtx, MA_OWNED); 885df8bae1dSRodney W. Grimes if (d->bd_hbuf) { 886df8bae1dSRodney W. Grimes /* Free the hold buffer. */ 887df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 888572bde2aSRobert Watson d->bd_hbuf = NULL; 889df8bae1dSRodney W. Grimes } 890df8bae1dSRodney W. Grimes d->bd_slen = 0; 891df8bae1dSRodney W. Grimes d->bd_hlen = 0; 892df8bae1dSRodney W. Grimes d->bd_rcount = 0; 893df8bae1dSRodney W. Grimes d->bd_dcount = 0; 89469f7644bSChristian S.J. Peron d->bd_fcount = 0; 8954d621040SChristian S.J. Peron d->bd_wcount = 0; 8964d621040SChristian S.J. Peron d->bd_wfcount = 0; 8974d621040SChristian S.J. Peron d->bd_wdcount = 0; 8984d621040SChristian S.J. Peron d->bd_zcopy = 0; 899df8bae1dSRodney W. Grimes } 900df8bae1dSRodney W. Grimes 901df8bae1dSRodney W. Grimes /* 902df8bae1dSRodney W. Grimes * FIONREAD Check for read packet available. 903df8bae1dSRodney W. Grimes * SIOCGIFADDR Get interface address - convenient hook to driver. 904df8bae1dSRodney W. Grimes * BIOCGBLEN Get buffer len [for read()]. 905df8bae1dSRodney W. Grimes * BIOCSETF Set ethernet read filter. 90693e39f0bSChristian S.J. Peron * BIOCSETWF Set ethernet write filter. 907df8bae1dSRodney W. Grimes * BIOCFLUSH Flush read packet buffer. 908df8bae1dSRodney W. Grimes * BIOCPROMISC Put interface into promiscuous mode. 909df8bae1dSRodney W. Grimes * BIOCGDLT Get link layer type. 910df8bae1dSRodney W. Grimes * BIOCGETIF Get interface name. 911df8bae1dSRodney W. Grimes * BIOCSETIF Set interface. 912df8bae1dSRodney W. Grimes * BIOCSRTIMEOUT Set read timeout. 913df8bae1dSRodney W. Grimes * BIOCGRTIMEOUT Get read timeout. 914df8bae1dSRodney W. Grimes * BIOCGSTATS Get packet stats. 915df8bae1dSRodney W. Grimes * BIOCIMMEDIATE Set immediate mode. 916df8bae1dSRodney W. Grimes * BIOCVERSION Get filter language version. 917114ae644SMike Smith * BIOCGHDRCMPLT Get "header already complete" flag 918114ae644SMike Smith * BIOCSHDRCMPLT Set "header already complete" flag 919560a54e1SJung-uk Kim * BIOCGDIRECTION Get packet direction flag 920560a54e1SJung-uk Kim * BIOCSDIRECTION Set packet direction flag 92193e39f0bSChristian S.J. Peron * BIOCLOCK Set "locked" flag 922560a54e1SJung-uk Kim * BIOCFEEDBACK Set packet feedback mode. 9234d621040SChristian S.J. Peron * BIOCSETZBUF Set current zero-copy buffer locations. 9244d621040SChristian S.J. Peron * BIOCGETZMAX Get maximum zero-copy buffer size. 9254d621040SChristian S.J. Peron * BIOCROTZBUF Force rotation of zero-copy buffer 9264d621040SChristian S.J. Peron * BIOCSETBUFMODE Set buffer mode. 9274d621040SChristian S.J. Peron * BIOCGETBUFMODE Get current buffer mode. 928df8bae1dSRodney W. Grimes */ 929df8bae1dSRodney W. Grimes /* ARGSUSED */ 93087f6c662SJulian Elischer static int 93119ba8395SChristian S.J. Peron bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, 93219ba8395SChristian S.J. Peron struct thread *td) 933df8bae1dSRodney W. Grimes { 934e7bb21b3SJonathan Lemon struct bpf_d *d = dev->si_drv1; 935e7bb21b3SJonathan Lemon int error = 0; 936df8bae1dSRodney W. Grimes 937b75a24a0SChristian S.J. Peron /* 938b75a24a0SChristian S.J. Peron * Refresh PID associated with this descriptor. 939b75a24a0SChristian S.J. Peron */ 94081bda851SJohn Polstra BPFD_LOCK(d); 941cb1d4f92SChristian S.J. Peron d->bd_pid = td->td_proc->p_pid; 94281bda851SJohn Polstra if (d->bd_state == BPF_WAITING) 94381bda851SJohn Polstra callout_stop(&d->bd_callout); 94481bda851SJohn Polstra d->bd_state = BPF_IDLE; 94581bda851SJohn Polstra BPFD_UNLOCK(d); 94681bda851SJohn Polstra 94793e39f0bSChristian S.J. Peron if (d->bd_locked == 1) { 94893e39f0bSChristian S.J. Peron switch (cmd) { 94993e39f0bSChristian S.J. Peron case BIOCGBLEN: 95093e39f0bSChristian S.J. Peron case BIOCFLUSH: 95193e39f0bSChristian S.J. Peron case BIOCGDLT: 95293e39f0bSChristian S.J. Peron case BIOCGDLTLIST: 95393e39f0bSChristian S.J. Peron case BIOCGETIF: 95493e39f0bSChristian S.J. Peron case BIOCGRTIMEOUT: 95593e39f0bSChristian S.J. Peron case BIOCGSTATS: 95693e39f0bSChristian S.J. Peron case BIOCVERSION: 95793e39f0bSChristian S.J. Peron case BIOCGRSIG: 95893e39f0bSChristian S.J. Peron case BIOCGHDRCMPLT: 959560a54e1SJung-uk Kim case BIOCFEEDBACK: 96093e39f0bSChristian S.J. Peron case FIONREAD: 96193e39f0bSChristian S.J. Peron case BIOCLOCK: 96293e39f0bSChristian S.J. Peron case BIOCSRTIMEOUT: 96393e39f0bSChristian S.J. Peron case BIOCIMMEDIATE: 96493e39f0bSChristian S.J. Peron case TIOCGPGRP: 9654d621040SChristian S.J. Peron case BIOCROTZBUF: 96693e39f0bSChristian S.J. Peron break; 96793e39f0bSChristian S.J. Peron default: 96893e39f0bSChristian S.J. Peron return (EPERM); 96993e39f0bSChristian S.J. Peron } 97093e39f0bSChristian S.J. Peron } 971df8bae1dSRodney W. Grimes switch (cmd) { 972df8bae1dSRodney W. Grimes 973df8bae1dSRodney W. Grimes default: 974df8bae1dSRodney W. Grimes error = EINVAL; 975df8bae1dSRodney W. Grimes break; 976df8bae1dSRodney W. Grimes 977df8bae1dSRodney W. Grimes /* 978df8bae1dSRodney W. Grimes * Check for read packet available. 979df8bae1dSRodney W. Grimes */ 980df8bae1dSRodney W. Grimes case FIONREAD: 981df8bae1dSRodney W. Grimes { 982df8bae1dSRodney W. Grimes int n; 983df8bae1dSRodney W. Grimes 984e7bb21b3SJonathan Lemon BPFD_LOCK(d); 985df8bae1dSRodney W. Grimes n = d->bd_slen; 986df8bae1dSRodney W. Grimes if (d->bd_hbuf) 987df8bae1dSRodney W. Grimes n += d->bd_hlen; 988e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 989df8bae1dSRodney W. Grimes 990df8bae1dSRodney W. Grimes *(int *)addr = n; 991df8bae1dSRodney W. Grimes break; 992df8bae1dSRodney W. Grimes } 993df8bae1dSRodney W. Grimes 994df8bae1dSRodney W. Grimes case SIOCGIFADDR: 995df8bae1dSRodney W. Grimes { 996df8bae1dSRodney W. Grimes struct ifnet *ifp; 997df8bae1dSRodney W. Grimes 998572bde2aSRobert Watson if (d->bd_bif == NULL) 999df8bae1dSRodney W. Grimes error = EINVAL; 1000df8bae1dSRodney W. Grimes else { 1001df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 1002df8bae1dSRodney W. Grimes error = (*ifp->if_ioctl)(ifp, cmd, addr); 1003df8bae1dSRodney W. Grimes } 1004df8bae1dSRodney W. Grimes break; 1005df8bae1dSRodney W. Grimes } 1006df8bae1dSRodney W. Grimes 1007df8bae1dSRodney W. Grimes /* 1008df8bae1dSRodney W. Grimes * Get buffer len [for read()]. 1009df8bae1dSRodney W. Grimes */ 1010df8bae1dSRodney W. Grimes case BIOCGBLEN: 1011df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bufsize; 1012df8bae1dSRodney W. Grimes break; 1013df8bae1dSRodney W. Grimes 1014df8bae1dSRodney W. Grimes /* 1015df8bae1dSRodney W. Grimes * Set buffer length. 1016df8bae1dSRodney W. Grimes */ 1017df8bae1dSRodney W. Grimes case BIOCSBLEN: 10184d621040SChristian S.J. Peron error = bpf_ioctl_sblen(d, (u_int *)addr); 1019df8bae1dSRodney W. Grimes break; 1020df8bae1dSRodney W. Grimes 1021df8bae1dSRodney W. Grimes /* 1022df8bae1dSRodney W. Grimes * Set link layer read filter. 1023df8bae1dSRodney W. Grimes */ 1024df8bae1dSRodney W. Grimes case BIOCSETF: 102593e39f0bSChristian S.J. Peron case BIOCSETWF: 102693e39f0bSChristian S.J. Peron error = bpf_setf(d, (struct bpf_program *)addr, cmd); 1027df8bae1dSRodney W. Grimes break; 1028df8bae1dSRodney W. Grimes 1029df8bae1dSRodney W. Grimes /* 1030df8bae1dSRodney W. Grimes * Flush read packet buffer. 1031df8bae1dSRodney W. Grimes */ 1032df8bae1dSRodney W. Grimes case BIOCFLUSH: 1033e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1034df8bae1dSRodney W. Grimes reset_d(d); 1035e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1036df8bae1dSRodney W. Grimes break; 1037df8bae1dSRodney W. Grimes 1038df8bae1dSRodney W. Grimes /* 1039df8bae1dSRodney W. Grimes * Put interface into promiscuous mode. 1040df8bae1dSRodney W. Grimes */ 1041df8bae1dSRodney W. Grimes case BIOCPROMISC: 1042572bde2aSRobert Watson if (d->bd_bif == NULL) { 1043df8bae1dSRodney W. Grimes /* 1044df8bae1dSRodney W. Grimes * No interface attached yet. 1045df8bae1dSRodney W. Grimes */ 1046df8bae1dSRodney W. Grimes error = EINVAL; 1047df8bae1dSRodney W. Grimes break; 1048df8bae1dSRodney W. Grimes } 1049df8bae1dSRodney W. Grimes if (d->bd_promisc == 0) { 1050df8bae1dSRodney W. Grimes error = ifpromisc(d->bd_bif->bif_ifp, 1); 1051df8bae1dSRodney W. Grimes if (error == 0) 1052df8bae1dSRodney W. Grimes d->bd_promisc = 1; 1053df8bae1dSRodney W. Grimes } 1054df8bae1dSRodney W. Grimes break; 1055df8bae1dSRodney W. Grimes 1056df8bae1dSRodney W. Grimes /* 10578eab61f3SSam Leffler * Get current data link type. 1058df8bae1dSRodney W. Grimes */ 1059df8bae1dSRodney W. Grimes case BIOCGDLT: 1060572bde2aSRobert Watson if (d->bd_bif == NULL) 1061df8bae1dSRodney W. Grimes error = EINVAL; 1062df8bae1dSRodney W. Grimes else 1063df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bif->bif_dlt; 1064df8bae1dSRodney W. Grimes break; 1065df8bae1dSRodney W. Grimes 1066df8bae1dSRodney W. Grimes /* 10678eab61f3SSam Leffler * Get a list of supported data link types. 10688eab61f3SSam Leffler */ 10698eab61f3SSam Leffler case BIOCGDLTLIST: 1070572bde2aSRobert Watson if (d->bd_bif == NULL) 10718eab61f3SSam Leffler error = EINVAL; 10728eab61f3SSam Leffler else 10738eab61f3SSam Leffler error = bpf_getdltlist(d, (struct bpf_dltlist *)addr); 10748eab61f3SSam Leffler break; 10758eab61f3SSam Leffler 10768eab61f3SSam Leffler /* 10778eab61f3SSam Leffler * Set data link type. 10788eab61f3SSam Leffler */ 10798eab61f3SSam Leffler case BIOCSDLT: 1080572bde2aSRobert Watson if (d->bd_bif == NULL) 10818eab61f3SSam Leffler error = EINVAL; 10828eab61f3SSam Leffler else 10838eab61f3SSam Leffler error = bpf_setdlt(d, *(u_int *)addr); 10848eab61f3SSam Leffler break; 10858eab61f3SSam Leffler 10868eab61f3SSam Leffler /* 10871dd0feaaSArchie Cobbs * Get interface name. 1088df8bae1dSRodney W. Grimes */ 1089df8bae1dSRodney W. Grimes case BIOCGETIF: 1090572bde2aSRobert Watson if (d->bd_bif == NULL) 1091df8bae1dSRodney W. Grimes error = EINVAL; 10921dd0feaaSArchie Cobbs else { 10931dd0feaaSArchie Cobbs struct ifnet *const ifp = d->bd_bif->bif_ifp; 10941dd0feaaSArchie Cobbs struct ifreq *const ifr = (struct ifreq *)addr; 10951dd0feaaSArchie Cobbs 10969bf40edeSBrooks Davis strlcpy(ifr->ifr_name, ifp->if_xname, 10979bf40edeSBrooks Davis sizeof(ifr->ifr_name)); 10981dd0feaaSArchie Cobbs } 1099df8bae1dSRodney W. Grimes break; 1100df8bae1dSRodney W. Grimes 1101df8bae1dSRodney W. Grimes /* 1102df8bae1dSRodney W. Grimes * Set interface. 1103df8bae1dSRodney W. Grimes */ 1104df8bae1dSRodney W. Grimes case BIOCSETIF: 1105df8bae1dSRodney W. Grimes error = bpf_setif(d, (struct ifreq *)addr); 1106df8bae1dSRodney W. Grimes break; 1107df8bae1dSRodney W. Grimes 1108df8bae1dSRodney W. Grimes /* 1109df8bae1dSRodney W. Grimes * Set read timeout. 1110df8bae1dSRodney W. Grimes */ 1111df8bae1dSRodney W. Grimes case BIOCSRTIMEOUT: 1112df8bae1dSRodney W. Grimes { 1113df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 1114df8bae1dSRodney W. Grimes 1115bdc2cdc5SAlexander Langer /* 1116bdc2cdc5SAlexander Langer * Subtract 1 tick from tvtohz() since this isn't 1117bdc2cdc5SAlexander Langer * a one-shot timer. 1118bdc2cdc5SAlexander Langer */ 1119bdc2cdc5SAlexander Langer if ((error = itimerfix(tv)) == 0) 1120bdc2cdc5SAlexander Langer d->bd_rtout = tvtohz(tv) - 1; 1121df8bae1dSRodney W. Grimes break; 1122df8bae1dSRodney W. Grimes } 1123df8bae1dSRodney W. Grimes 1124df8bae1dSRodney W. Grimes /* 1125df8bae1dSRodney W. Grimes * Get read timeout. 1126df8bae1dSRodney W. Grimes */ 1127df8bae1dSRodney W. Grimes case BIOCGRTIMEOUT: 1128df8bae1dSRodney W. Grimes { 1129df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 1130df8bae1dSRodney W. Grimes 1131bdc2cdc5SAlexander Langer tv->tv_sec = d->bd_rtout / hz; 1132bdc2cdc5SAlexander Langer tv->tv_usec = (d->bd_rtout % hz) * tick; 1133df8bae1dSRodney W. Grimes break; 1134df8bae1dSRodney W. Grimes } 1135df8bae1dSRodney W. Grimes 1136df8bae1dSRodney W. Grimes /* 1137df8bae1dSRodney W. Grimes * Get packet stats. 1138df8bae1dSRodney W. Grimes */ 1139df8bae1dSRodney W. Grimes case BIOCGSTATS: 1140df8bae1dSRodney W. Grimes { 1141df8bae1dSRodney W. Grimes struct bpf_stat *bs = (struct bpf_stat *)addr; 1142df8bae1dSRodney W. Grimes 11434d621040SChristian S.J. Peron /* XXXCSJP overflow */ 1144df8bae1dSRodney W. Grimes bs->bs_recv = d->bd_rcount; 1145df8bae1dSRodney W. Grimes bs->bs_drop = d->bd_dcount; 1146df8bae1dSRodney W. Grimes break; 1147df8bae1dSRodney W. Grimes } 1148df8bae1dSRodney W. Grimes 1149df8bae1dSRodney W. Grimes /* 1150df8bae1dSRodney W. Grimes * Set immediate mode. 1151df8bae1dSRodney W. Grimes */ 1152df8bae1dSRodney W. Grimes case BIOCIMMEDIATE: 1153df8bae1dSRodney W. Grimes d->bd_immediate = *(u_int *)addr; 1154df8bae1dSRodney W. Grimes break; 1155df8bae1dSRodney W. Grimes 1156df8bae1dSRodney W. Grimes case BIOCVERSION: 1157df8bae1dSRodney W. Grimes { 1158df8bae1dSRodney W. Grimes struct bpf_version *bv = (struct bpf_version *)addr; 1159df8bae1dSRodney W. Grimes 1160df8bae1dSRodney W. Grimes bv->bv_major = BPF_MAJOR_VERSION; 1161df8bae1dSRodney W. Grimes bv->bv_minor = BPF_MINOR_VERSION; 1162df8bae1dSRodney W. Grimes break; 1163df8bae1dSRodney W. Grimes } 116400a83887SPaul Traina 1165114ae644SMike Smith /* 1166114ae644SMike Smith * Get "header already complete" flag 1167114ae644SMike Smith */ 1168114ae644SMike Smith case BIOCGHDRCMPLT: 1169114ae644SMike Smith *(u_int *)addr = d->bd_hdrcmplt; 1170114ae644SMike Smith break; 1171114ae644SMike Smith 1172114ae644SMike Smith /* 1173114ae644SMike Smith * Set "header already complete" flag 1174114ae644SMike Smith */ 1175114ae644SMike Smith case BIOCSHDRCMPLT: 1176114ae644SMike Smith d->bd_hdrcmplt = *(u_int *)addr ? 1 : 0; 1177114ae644SMike Smith break; 1178114ae644SMike Smith 11798ed3828cSRobert Watson /* 1180560a54e1SJung-uk Kim * Get packet direction flag 11818ed3828cSRobert Watson */ 1182560a54e1SJung-uk Kim case BIOCGDIRECTION: 1183560a54e1SJung-uk Kim *(u_int *)addr = d->bd_direction; 11848ed3828cSRobert Watson break; 11858ed3828cSRobert Watson 11868ed3828cSRobert Watson /* 1187560a54e1SJung-uk Kim * Set packet direction flag 11888ed3828cSRobert Watson */ 1189560a54e1SJung-uk Kim case BIOCSDIRECTION: 1190560a54e1SJung-uk Kim { 1191560a54e1SJung-uk Kim u_int direction; 1192560a54e1SJung-uk Kim 1193560a54e1SJung-uk Kim direction = *(u_int *)addr; 1194560a54e1SJung-uk Kim switch (direction) { 1195560a54e1SJung-uk Kim case BPF_D_IN: 1196560a54e1SJung-uk Kim case BPF_D_INOUT: 1197560a54e1SJung-uk Kim case BPF_D_OUT: 1198560a54e1SJung-uk Kim d->bd_direction = direction; 1199560a54e1SJung-uk Kim break; 1200560a54e1SJung-uk Kim default: 1201560a54e1SJung-uk Kim error = EINVAL; 1202560a54e1SJung-uk Kim } 1203560a54e1SJung-uk Kim } 1204560a54e1SJung-uk Kim break; 1205560a54e1SJung-uk Kim 1206560a54e1SJung-uk Kim case BIOCFEEDBACK: 1207560a54e1SJung-uk Kim d->bd_feedback = *(u_int *)addr; 1208560a54e1SJung-uk Kim break; 1209560a54e1SJung-uk Kim 1210560a54e1SJung-uk Kim case BIOCLOCK: 1211560a54e1SJung-uk Kim d->bd_locked = 1; 12128ed3828cSRobert Watson break; 12138ed3828cSRobert Watson 121400a83887SPaul Traina case FIONBIO: /* Non-blocking I/O */ 121500a83887SPaul Traina break; 121600a83887SPaul Traina 121700a83887SPaul Traina case FIOASYNC: /* Send signal on receive packets */ 121800a83887SPaul Traina d->bd_async = *(int *)addr; 121900a83887SPaul Traina break; 122000a83887SPaul Traina 1221831d27a9SDon Lewis case FIOSETOWN: 1222831d27a9SDon Lewis error = fsetown(*(int *)addr, &d->bd_sigio); 122300a83887SPaul Traina break; 122400a83887SPaul Traina 1225831d27a9SDon Lewis case FIOGETOWN: 122691e97a82SDon Lewis *(int *)addr = fgetown(&d->bd_sigio); 1227831d27a9SDon Lewis break; 1228831d27a9SDon Lewis 1229831d27a9SDon Lewis /* This is deprecated, FIOSETOWN should be used instead. */ 1230831d27a9SDon Lewis case TIOCSPGRP: 1231831d27a9SDon Lewis error = fsetown(-(*(int *)addr), &d->bd_sigio); 1232831d27a9SDon Lewis break; 1233831d27a9SDon Lewis 1234831d27a9SDon Lewis /* This is deprecated, FIOGETOWN should be used instead. */ 123500a83887SPaul Traina case TIOCGPGRP: 123691e97a82SDon Lewis *(int *)addr = -fgetown(&d->bd_sigio); 123700a83887SPaul Traina break; 123800a83887SPaul Traina 123900a83887SPaul Traina case BIOCSRSIG: /* Set receive signal */ 124000a83887SPaul Traina { 124100a83887SPaul Traina u_int sig; 124200a83887SPaul Traina 124300a83887SPaul Traina sig = *(u_int *)addr; 124400a83887SPaul Traina 124500a83887SPaul Traina if (sig >= NSIG) 124600a83887SPaul Traina error = EINVAL; 124700a83887SPaul Traina else 124800a83887SPaul Traina d->bd_sig = sig; 124900a83887SPaul Traina break; 125000a83887SPaul Traina } 125100a83887SPaul Traina case BIOCGRSIG: 125200a83887SPaul Traina *(u_int *)addr = d->bd_sig; 125300a83887SPaul Traina break; 12544d621040SChristian S.J. Peron 12554d621040SChristian S.J. Peron case BIOCGETBUFMODE: 12564d621040SChristian S.J. Peron *(u_int *)addr = d->bd_bufmode; 12574d621040SChristian S.J. Peron break; 12584d621040SChristian S.J. Peron 12594d621040SChristian S.J. Peron case BIOCSETBUFMODE: 12604d621040SChristian S.J. Peron /* 12614d621040SChristian S.J. Peron * Allow the buffering mode to be changed as long as we 12624d621040SChristian S.J. Peron * haven't yet committed to a particular mode. Our 12634d621040SChristian S.J. Peron * definition of commitment, for now, is whether or not a 12644d621040SChristian S.J. Peron * buffer has been allocated or an interface attached, since 12654d621040SChristian S.J. Peron * that's the point where things get tricky. 12664d621040SChristian S.J. Peron */ 12674d621040SChristian S.J. Peron switch (*(u_int *)addr) { 12684d621040SChristian S.J. Peron case BPF_BUFMODE_BUFFER: 12694d621040SChristian S.J. Peron break; 12704d621040SChristian S.J. Peron 12714d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 12724d621040SChristian S.J. Peron if (bpf_zerocopy_enable) 12734d621040SChristian S.J. Peron break; 12744d621040SChristian S.J. Peron /* FALLSTHROUGH */ 12754d621040SChristian S.J. Peron 12764d621040SChristian S.J. Peron default: 12774d621040SChristian S.J. Peron return (EINVAL); 12784d621040SChristian S.J. Peron } 12794d621040SChristian S.J. Peron 12804d621040SChristian S.J. Peron BPFD_LOCK(d); 12814d621040SChristian S.J. Peron if (d->bd_sbuf != NULL || d->bd_hbuf != NULL || 12824d621040SChristian S.J. Peron d->bd_fbuf != NULL || d->bd_bif != NULL) { 12834d621040SChristian S.J. Peron BPFD_UNLOCK(d); 12844d621040SChristian S.J. Peron return (EBUSY); 12854d621040SChristian S.J. Peron } 12864d621040SChristian S.J. Peron d->bd_bufmode = *(u_int *)addr; 12874d621040SChristian S.J. Peron BPFD_UNLOCK(d); 12884d621040SChristian S.J. Peron break; 12894d621040SChristian S.J. Peron 12904d621040SChristian S.J. Peron case BIOCGETZMAX: 12914d621040SChristian S.J. Peron return (bpf_ioctl_getzmax(td, d, (size_t *)addr)); 12924d621040SChristian S.J. Peron 12934d621040SChristian S.J. Peron case BIOCSETZBUF: 12944d621040SChristian S.J. Peron return (bpf_ioctl_setzbuf(td, d, (struct bpf_zbuf *)addr)); 12954d621040SChristian S.J. Peron 12964d621040SChristian S.J. Peron case BIOCROTZBUF: 12974d621040SChristian S.J. Peron return (bpf_ioctl_rotzbuf(td, d, (struct bpf_zbuf *)addr)); 1298df8bae1dSRodney W. Grimes } 1299df8bae1dSRodney W. Grimes return (error); 1300df8bae1dSRodney W. Grimes } 1301df8bae1dSRodney W. Grimes 1302df8bae1dSRodney W. Grimes /* 1303df8bae1dSRodney W. Grimes * Set d's packet filter program to fp. If this file already has a filter, 1304df8bae1dSRodney W. Grimes * free it and replace it. Returns EINVAL for bogus requests. 1305df8bae1dSRodney W. Grimes */ 1306f708ef1bSPoul-Henning Kamp static int 130719ba8395SChristian S.J. Peron bpf_setf(struct bpf_d *d, struct bpf_program *fp, u_long cmd) 1308df8bae1dSRodney W. Grimes { 1309df8bae1dSRodney W. Grimes struct bpf_insn *fcode, *old; 131093e39f0bSChristian S.J. Peron u_int wfilter, flen, size; 1311293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1312ae275efcSJung-uk Kim bpf_jit_filter *ofunc; 1313ae275efcSJung-uk Kim #endif 1314df8bae1dSRodney W. Grimes 131593e39f0bSChristian S.J. Peron if (cmd == BIOCSETWF) { 131693e39f0bSChristian S.J. Peron old = d->bd_wfilter; 131793e39f0bSChristian S.J. Peron wfilter = 1; 1318293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1319ae275efcSJung-uk Kim ofunc = NULL; 1320ae275efcSJung-uk Kim #endif 132193e39f0bSChristian S.J. Peron } else { 132293e39f0bSChristian S.J. Peron wfilter = 0; 132393e39f0bSChristian S.J. Peron old = d->bd_rfilter; 1324293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1325ae275efcSJung-uk Kim ofunc = d->bd_bfilter; 1326ae275efcSJung-uk Kim #endif 132793e39f0bSChristian S.J. Peron } 1328572bde2aSRobert Watson if (fp->bf_insns == NULL) { 1329df8bae1dSRodney W. Grimes if (fp->bf_len != 0) 1330df8bae1dSRodney W. Grimes return (EINVAL); 1331e7bb21b3SJonathan Lemon BPFD_LOCK(d); 133293e39f0bSChristian S.J. Peron if (wfilter) 133393e39f0bSChristian S.J. Peron d->bd_wfilter = NULL; 1334ae275efcSJung-uk Kim else { 133593e39f0bSChristian S.J. Peron d->bd_rfilter = NULL; 1336293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1337ae275efcSJung-uk Kim d->bd_bfilter = NULL; 1338ae275efcSJung-uk Kim #endif 1339ae275efcSJung-uk Kim } 1340df8bae1dSRodney W. Grimes reset_d(d); 1341e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1342572bde2aSRobert Watson if (old != NULL) 1343bd3a5320SPoul-Henning Kamp free((caddr_t)old, M_BPF); 1344293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1345ae275efcSJung-uk Kim if (ofunc != NULL) 1346ae275efcSJung-uk Kim bpf_destroy_jit_filter(ofunc); 1347ae275efcSJung-uk Kim #endif 1348df8bae1dSRodney W. Grimes return (0); 1349df8bae1dSRodney W. Grimes } 1350df8bae1dSRodney W. Grimes flen = fp->bf_len; 13510eb20604SChristian S.J. Peron if (flen > bpf_maxinsns) 1352df8bae1dSRodney W. Grimes return (EINVAL); 1353df8bae1dSRodney W. Grimes 1354df8bae1dSRodney W. Grimes size = flen * sizeof(*fp->bf_insns); 1355a163d034SWarner Losh fcode = (struct bpf_insn *)malloc(size, M_BPF, M_WAITOK); 1356df8bae1dSRodney W. Grimes if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 && 1357df8bae1dSRodney W. Grimes bpf_validate(fcode, (int)flen)) { 1358e7bb21b3SJonathan Lemon BPFD_LOCK(d); 135993e39f0bSChristian S.J. Peron if (wfilter) 136093e39f0bSChristian S.J. Peron d->bd_wfilter = fcode; 1361ae275efcSJung-uk Kim else { 136293e39f0bSChristian S.J. Peron d->bd_rfilter = fcode; 1363293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1364ae275efcSJung-uk Kim d->bd_bfilter = bpf_jitter(fcode, flen); 1365ae275efcSJung-uk Kim #endif 1366ae275efcSJung-uk Kim } 1367df8bae1dSRodney W. Grimes reset_d(d); 1368e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1369572bde2aSRobert Watson if (old != NULL) 1370bd3a5320SPoul-Henning Kamp free((caddr_t)old, M_BPF); 1371293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1372ae275efcSJung-uk Kim if (ofunc != NULL) 1373ae275efcSJung-uk Kim bpf_destroy_jit_filter(ofunc); 1374ae275efcSJung-uk Kim #endif 1375df8bae1dSRodney W. Grimes 1376df8bae1dSRodney W. Grimes return (0); 1377df8bae1dSRodney W. Grimes } 1378bd3a5320SPoul-Henning Kamp free((caddr_t)fcode, M_BPF); 1379df8bae1dSRodney W. Grimes return (EINVAL); 1380df8bae1dSRodney W. Grimes } 1381df8bae1dSRodney W. Grimes 1382df8bae1dSRodney W. Grimes /* 1383df8bae1dSRodney W. Grimes * Detach a file from its current interface (if attached at all) and attach 1384df8bae1dSRodney W. Grimes * to the interface indicated by the name stored in ifr. 1385df8bae1dSRodney W. Grimes * Return an errno or 0. 1386df8bae1dSRodney W. Grimes */ 1387df8bae1dSRodney W. Grimes static int 138819ba8395SChristian S.J. Peron bpf_setif(struct bpf_d *d, struct ifreq *ifr) 1389df8bae1dSRodney W. Grimes { 1390df8bae1dSRodney W. Grimes struct bpf_if *bp; 13919b44ff22SGarrett Wollman struct ifnet *theywant; 1392df8bae1dSRodney W. Grimes 13939b44ff22SGarrett Wollman theywant = ifunit(ifr->ifr_name); 139416d878ccSChristian S.J. Peron if (theywant == NULL || theywant->if_bpf == NULL) 139516d878ccSChristian S.J. Peron return (ENXIO); 13969b44ff22SGarrett Wollman 139716d878ccSChristian S.J. Peron bp = theywant->if_bpf; 13984d621040SChristian S.J. Peron 1399df8bae1dSRodney W. Grimes /* 14004d621040SChristian S.J. Peron * Behavior here depends on the buffering model. If we're using 14014d621040SChristian S.J. Peron * kernel memory buffers, then we can allocate them here. If we're 14024d621040SChristian S.J. Peron * using zero-copy, then the user process must have registered 14034d621040SChristian S.J. Peron * buffers by the time we get here. If not, return an error. 14044d621040SChristian S.J. Peron * 14054d621040SChristian S.J. Peron * XXXRW: There are locking issues here with multi-threaded use: what 14064d621040SChristian S.J. Peron * if two threads try to set the interface at once? 1407df8bae1dSRodney W. Grimes */ 14084d621040SChristian S.J. Peron switch (d->bd_bufmode) { 14094d621040SChristian S.J. Peron case BPF_BUFMODE_BUFFER: 1410a3594432SRobert Watson if (d->bd_sbuf == NULL) 14114d621040SChristian S.J. Peron bpf_buffer_alloc(d); 14124d621040SChristian S.J. Peron KASSERT(d->bd_sbuf != NULL, ("bpf_setif: bd_sbuf NULL")); 14134d621040SChristian S.J. Peron break; 14144d621040SChristian S.J. Peron 14154d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 14164d621040SChristian S.J. Peron if (d->bd_sbuf == NULL) 14174d621040SChristian S.J. Peron return (EINVAL); 14184d621040SChristian S.J. Peron break; 14194d621040SChristian S.J. Peron 14204d621040SChristian S.J. Peron default: 14214d621040SChristian S.J. Peron panic("bpf_setif: bufmode %d", d->bd_bufmode); 14224d621040SChristian S.J. Peron } 1423df8bae1dSRodney W. Grimes if (bp != d->bd_bif) { 1424df8bae1dSRodney W. Grimes if (d->bd_bif) 1425df8bae1dSRodney W. Grimes /* 1426df8bae1dSRodney W. Grimes * Detach if attached to something else. 1427df8bae1dSRodney W. Grimes */ 1428df8bae1dSRodney W. Grimes bpf_detachd(d); 1429df8bae1dSRodney W. Grimes 1430df8bae1dSRodney W. Grimes bpf_attachd(d, bp); 1431df8bae1dSRodney W. Grimes } 1432e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1433df8bae1dSRodney W. Grimes reset_d(d); 1434e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1435df8bae1dSRodney W. Grimes return (0); 1436df8bae1dSRodney W. Grimes } 1437df8bae1dSRodney W. Grimes 1438df8bae1dSRodney W. Grimes /* 1439243ac7d8SPeter Wemm * Support for select() and poll() system calls 1440df8bae1dSRodney W. Grimes * 1441df8bae1dSRodney W. Grimes * Return true iff the specific operation will not block indefinitely. 1442df8bae1dSRodney W. Grimes * Otherwise, return false but make a note that a selwakeup() must be done. 1443df8bae1dSRodney W. Grimes */ 144437c84183SPoul-Henning Kamp static int 144519ba8395SChristian S.J. Peron bpfpoll(struct cdev *dev, int events, struct thread *td) 1446df8bae1dSRodney W. Grimes { 1447e7bb21b3SJonathan Lemon struct bpf_d *d; 14480832fc64SGarance A Drosehn int revents; 1449df8bae1dSRodney W. Grimes 1450bd3a5320SPoul-Henning Kamp d = dev->si_drv1; 1451de5d9935SRobert Watson if (d->bd_bif == NULL) 1452de5d9935SRobert Watson return (ENXIO); 1453de5d9935SRobert Watson 1454b75a24a0SChristian S.J. Peron /* 1455b75a24a0SChristian S.J. Peron * Refresh PID associated with this descriptor. 1456b75a24a0SChristian S.J. Peron */ 14570832fc64SGarance A Drosehn revents = events & (POLLOUT | POLLWRNORM); 1458e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1459cb1d4f92SChristian S.J. Peron d->bd_pid = td->td_proc->p_pid; 146075c13541SPoul-Henning Kamp if (events & (POLLIN | POLLRDNORM)) { 146195aab9ccSJohn-Mark Gurney if (bpf_ready(d)) 1462243ac7d8SPeter Wemm revents |= events & (POLLIN | POLLRDNORM); 146381bda851SJohn Polstra else { 1464ed01445dSJohn Baldwin selrecord(td, &d->bd_sel); 146581bda851SJohn Polstra /* Start the read timeout if necessary. */ 146681bda851SJohn Polstra if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) { 146781bda851SJohn Polstra callout_reset(&d->bd_callout, d->bd_rtout, 146881bda851SJohn Polstra bpf_timed_out, d); 146981bda851SJohn Polstra d->bd_state = BPF_WAITING; 147081bda851SJohn Polstra } 147181bda851SJohn Polstra } 147275c13541SPoul-Henning Kamp } 1473e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1474243ac7d8SPeter Wemm return (revents); 1475df8bae1dSRodney W. Grimes } 1476df8bae1dSRodney W. Grimes 1477df8bae1dSRodney W. Grimes /* 147895aab9ccSJohn-Mark Gurney * Support for kevent() system call. Register EVFILT_READ filters and 147995aab9ccSJohn-Mark Gurney * reject all others. 148095aab9ccSJohn-Mark Gurney */ 148195aab9ccSJohn-Mark Gurney int 148219ba8395SChristian S.J. Peron bpfkqfilter(struct cdev *dev, struct knote *kn) 148395aab9ccSJohn-Mark Gurney { 148495aab9ccSJohn-Mark Gurney struct bpf_d *d = (struct bpf_d *)dev->si_drv1; 148595aab9ccSJohn-Mark Gurney 148695aab9ccSJohn-Mark Gurney if (kn->kn_filter != EVFILT_READ) 148795aab9ccSJohn-Mark Gurney return (1); 148895aab9ccSJohn-Mark Gurney 1489b75a24a0SChristian S.J. Peron /* 1490b75a24a0SChristian S.J. Peron * Refresh PID associated with this descriptor. 1491b75a24a0SChristian S.J. Peron */ 1492cb1d4f92SChristian S.J. Peron BPFD_LOCK(d); 1493b75a24a0SChristian S.J. Peron d->bd_pid = curthread->td_proc->p_pid; 149495aab9ccSJohn-Mark Gurney kn->kn_fop = &bpfread_filtops; 149595aab9ccSJohn-Mark Gurney kn->kn_hook = d; 14964b19419eSChristian S.J. Peron knlist_add(&d->bd_sel.si_note, kn, 1); 1497cb1d4f92SChristian S.J. Peron BPFD_UNLOCK(d); 149895aab9ccSJohn-Mark Gurney 149995aab9ccSJohn-Mark Gurney return (0); 150095aab9ccSJohn-Mark Gurney } 150195aab9ccSJohn-Mark Gurney 150295aab9ccSJohn-Mark Gurney static void 150319ba8395SChristian S.J. Peron filt_bpfdetach(struct knote *kn) 150495aab9ccSJohn-Mark Gurney { 150595aab9ccSJohn-Mark Gurney struct bpf_d *d = (struct bpf_d *)kn->kn_hook; 150695aab9ccSJohn-Mark Gurney 1507ad3b9257SJohn-Mark Gurney knlist_remove(&d->bd_sel.si_note, kn, 0); 150895aab9ccSJohn-Mark Gurney } 150995aab9ccSJohn-Mark Gurney 151095aab9ccSJohn-Mark Gurney static int 151119ba8395SChristian S.J. Peron filt_bpfread(struct knote *kn, long hint) 151295aab9ccSJohn-Mark Gurney { 151395aab9ccSJohn-Mark Gurney struct bpf_d *d = (struct bpf_d *)kn->kn_hook; 151495aab9ccSJohn-Mark Gurney int ready; 151595aab9ccSJohn-Mark Gurney 151686c9a453SJohn-Mark Gurney BPFD_LOCK_ASSERT(d); 151795aab9ccSJohn-Mark Gurney ready = bpf_ready(d); 151895aab9ccSJohn-Mark Gurney if (ready) { 151995aab9ccSJohn-Mark Gurney kn->kn_data = d->bd_slen; 152095aab9ccSJohn-Mark Gurney if (d->bd_hbuf) 152195aab9ccSJohn-Mark Gurney kn->kn_data += d->bd_hlen; 152295aab9ccSJohn-Mark Gurney } 152395aab9ccSJohn-Mark Gurney else if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) { 152495aab9ccSJohn-Mark Gurney callout_reset(&d->bd_callout, d->bd_rtout, 152595aab9ccSJohn-Mark Gurney bpf_timed_out, d); 152695aab9ccSJohn-Mark Gurney d->bd_state = BPF_WAITING; 152795aab9ccSJohn-Mark Gurney } 152895aab9ccSJohn-Mark Gurney 152995aab9ccSJohn-Mark Gurney return (ready); 153095aab9ccSJohn-Mark Gurney } 153195aab9ccSJohn-Mark Gurney 153295aab9ccSJohn-Mark Gurney /* 1533df8bae1dSRodney W. Grimes * Incoming linkage from device drivers. Process the packet pkt, of length 1534df8bae1dSRodney W. Grimes * pktlen, which is stored in a contiguous buffer. The packet is parsed 1535df8bae1dSRodney W. Grimes * by each process' filter, and if accepted, stashed into the corresponding 1536df8bae1dSRodney W. Grimes * buffer. 1537df8bae1dSRodney W. Grimes */ 1538df8bae1dSRodney W. Grimes void 153919ba8395SChristian S.J. Peron bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen) 1540df8bae1dSRodney W. Grimes { 15418994a245SDag-Erling Smørgrav struct bpf_d *d; 15428994a245SDag-Erling Smørgrav u_int slen; 154391433904SDavid Malone int gottime; 154491433904SDavid Malone struct timeval tv; 1545e7bb21b3SJonathan Lemon 154691433904SDavid Malone gottime = 0; 1547e7bb21b3SJonathan Lemon BPFIF_LOCK(bp); 15484a3feeaaSRobert Watson LIST_FOREACH(d, &bp->bif_dlist, bd_next) { 1549e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1550df8bae1dSRodney W. Grimes ++d->bd_rcount; 1551ae275efcSJung-uk Kim #ifdef BPF_JITTER 1552ae275efcSJung-uk Kim if (bpf_jitter_enable != 0 && d->bd_bfilter != NULL) 1553ae275efcSJung-uk Kim slen = (*(d->bd_bfilter->func))(pkt, pktlen, pktlen); 1554ae275efcSJung-uk Kim else 1555ae275efcSJung-uk Kim #endif 155693e39f0bSChristian S.J. Peron slen = bpf_filter(d->bd_rfilter, pkt, pktlen, pktlen); 1557ec272d87SRobert Watson if (slen != 0) { 155869f7644bSChristian S.J. Peron d->bd_fcount++; 155991433904SDavid Malone if (!gottime) { 156091433904SDavid Malone microtime(&tv); 156191433904SDavid Malone gottime = 1; 156291433904SDavid Malone } 1563ec272d87SRobert Watson #ifdef MAC 156430d239bcSRobert Watson if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) 1565ec272d87SRobert Watson #endif 15664d621040SChristian S.J. Peron catchpacket(d, pkt, pktlen, slen, 15674d621040SChristian S.J. Peron bpf_append_bytes, &tv); 1568ec272d87SRobert Watson } 1569e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1570df8bae1dSRodney W. Grimes } 1571e7bb21b3SJonathan Lemon BPFIF_UNLOCK(bp); 1572df8bae1dSRodney W. Grimes } 1573df8bae1dSRodney W. Grimes 15749a3a0f92SJung-uk Kim #define BPF_CHECK_DIRECTION(d, i) \ 15759a3a0f92SJung-uk Kim (((d)->bd_direction == BPF_D_IN && (i) == NULL) || \ 15769a3a0f92SJung-uk Kim ((d)->bd_direction == BPF_D_OUT && (i) != NULL)) 1577560a54e1SJung-uk Kim 1578df8bae1dSRodney W. Grimes /* 1579df8bae1dSRodney W. Grimes * Incoming linkage from device drivers, when packet is in an mbuf chain. 1580df8bae1dSRodney W. Grimes */ 1581df8bae1dSRodney W. Grimes void 158219ba8395SChristian S.J. Peron bpf_mtap(struct bpf_if *bp, struct mbuf *m) 1583df8bae1dSRodney W. Grimes { 1584df8bae1dSRodney W. Grimes struct bpf_d *d; 1585df8bae1dSRodney W. Grimes u_int pktlen, slen; 158691433904SDavid Malone int gottime; 158791433904SDavid Malone struct timeval tv; 158891433904SDavid Malone 15898cd892f7SJung-uk Kim /* Skip outgoing duplicate packets. */ 15908cd892f7SJung-uk Kim if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { 15918cd892f7SJung-uk Kim m->m_flags &= ~M_PROMISC; 15928cd892f7SJung-uk Kim return; 15938cd892f7SJung-uk Kim } 15948cd892f7SJung-uk Kim 159591433904SDavid Malone gottime = 0; 1596df8bae1dSRodney W. Grimes 1597f0e2422bSPoul-Henning Kamp pktlen = m_length(m, NULL); 1598df8bae1dSRodney W. Grimes 1599e7bb21b3SJonathan Lemon BPFIF_LOCK(bp); 16004a3feeaaSRobert Watson LIST_FOREACH(d, &bp->bif_dlist, bd_next) { 16018cd892f7SJung-uk Kim if (BPF_CHECK_DIRECTION(d, m->m_pkthdr.rcvif)) 16028ed3828cSRobert Watson continue; 1603e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1604df8bae1dSRodney W. Grimes ++d->bd_rcount; 1605ae275efcSJung-uk Kim #ifdef BPF_JITTER 1606ae275efcSJung-uk Kim /* XXX We cannot handle multiple mbufs. */ 1607ae275efcSJung-uk Kim if (bpf_jitter_enable != 0 && d->bd_bfilter != NULL && 1608ae275efcSJung-uk Kim m->m_next == NULL) 1609ae275efcSJung-uk Kim slen = (*(d->bd_bfilter->func))(mtod(m, u_char *), 1610ae275efcSJung-uk Kim pktlen, pktlen); 1611ae275efcSJung-uk Kim else 1612ae275efcSJung-uk Kim #endif 161393e39f0bSChristian S.J. Peron slen = bpf_filter(d->bd_rfilter, (u_char *)m, pktlen, 0); 16144ddfb531SChristian S.J. Peron if (slen != 0) { 161569f7644bSChristian S.J. Peron d->bd_fcount++; 161691433904SDavid Malone if (!gottime) { 161791433904SDavid Malone microtime(&tv); 161891433904SDavid Malone gottime = 1; 161991433904SDavid Malone } 16200c7fb534SRobert Watson #ifdef MAC 162130d239bcSRobert Watson if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) 16220c7fb534SRobert Watson #endif 16230c7fb534SRobert Watson catchpacket(d, (u_char *)m, pktlen, slen, 16244d621040SChristian S.J. Peron bpf_append_mbuf, &tv); 16254ddfb531SChristian S.J. Peron } 1626e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1627df8bae1dSRodney W. Grimes } 1628e7bb21b3SJonathan Lemon BPFIF_UNLOCK(bp); 1629df8bae1dSRodney W. Grimes } 1630df8bae1dSRodney W. Grimes 1631df8bae1dSRodney W. Grimes /* 1632437ffe18SSam Leffler * Incoming linkage from device drivers, when packet is in 1633437ffe18SSam Leffler * an mbuf chain and to be prepended by a contiguous header. 1634437ffe18SSam Leffler */ 1635437ffe18SSam Leffler void 163619ba8395SChristian S.J. Peron bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m) 1637437ffe18SSam Leffler { 1638437ffe18SSam Leffler struct mbuf mb; 1639437ffe18SSam Leffler struct bpf_d *d; 1640437ffe18SSam Leffler u_int pktlen, slen; 164191433904SDavid Malone int gottime; 164291433904SDavid Malone struct timeval tv; 164391433904SDavid Malone 16448cd892f7SJung-uk Kim /* Skip outgoing duplicate packets. */ 16458cd892f7SJung-uk Kim if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { 16468cd892f7SJung-uk Kim m->m_flags &= ~M_PROMISC; 16478cd892f7SJung-uk Kim return; 16488cd892f7SJung-uk Kim } 16498cd892f7SJung-uk Kim 165091433904SDavid Malone gottime = 0; 1651437ffe18SSam Leffler 1652437ffe18SSam Leffler pktlen = m_length(m, NULL); 1653437ffe18SSam Leffler /* 1654437ffe18SSam Leffler * Craft on-stack mbuf suitable for passing to bpf_filter. 1655437ffe18SSam Leffler * Note that we cut corners here; we only setup what's 1656437ffe18SSam Leffler * absolutely needed--this mbuf should never go anywhere else. 1657437ffe18SSam Leffler */ 1658437ffe18SSam Leffler mb.m_next = m; 1659437ffe18SSam Leffler mb.m_data = data; 1660437ffe18SSam Leffler mb.m_len = dlen; 1661437ffe18SSam Leffler pktlen += dlen; 1662437ffe18SSam Leffler 1663437ffe18SSam Leffler BPFIF_LOCK(bp); 16644a3feeaaSRobert Watson LIST_FOREACH(d, &bp->bif_dlist, bd_next) { 16658cd892f7SJung-uk Kim if (BPF_CHECK_DIRECTION(d, m->m_pkthdr.rcvif)) 1666437ffe18SSam Leffler continue; 1667437ffe18SSam Leffler BPFD_LOCK(d); 1668437ffe18SSam Leffler ++d->bd_rcount; 166993e39f0bSChristian S.J. Peron slen = bpf_filter(d->bd_rfilter, (u_char *)&mb, pktlen, 0); 16704ddfb531SChristian S.J. Peron if (slen != 0) { 167169f7644bSChristian S.J. Peron d->bd_fcount++; 167291433904SDavid Malone if (!gottime) { 167391433904SDavid Malone microtime(&tv); 167491433904SDavid Malone gottime = 1; 167591433904SDavid Malone } 1676437ffe18SSam Leffler #ifdef MAC 167730d239bcSRobert Watson if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) 1678437ffe18SSam Leffler #endif 1679437ffe18SSam Leffler catchpacket(d, (u_char *)&mb, pktlen, slen, 16804d621040SChristian S.J. Peron bpf_append_mbuf, &tv); 16814ddfb531SChristian S.J. Peron } 1682437ffe18SSam Leffler BPFD_UNLOCK(d); 1683437ffe18SSam Leffler } 1684437ffe18SSam Leffler BPFIF_UNLOCK(bp); 1685437ffe18SSam Leffler } 1686437ffe18SSam Leffler 1687560a54e1SJung-uk Kim #undef BPF_CHECK_DIRECTION 1688560a54e1SJung-uk Kim 1689437ffe18SSam Leffler /* 1690df8bae1dSRodney W. Grimes * Move the packet data from interface memory (pkt) into the 16919e610888SDag-Erling Smørgrav * store buffer. "cpfn" is the routine called to do the actual data 1692df8bae1dSRodney W. Grimes * transfer. bcopy is passed in to copy contiguous chunks, while 16934d621040SChristian S.J. Peron * bpf_append_mbuf is passed in to copy mbuf chains. In the latter case, 1694df8bae1dSRodney W. Grimes * pkt is really an mbuf. 1695df8bae1dSRodney W. Grimes */ 1696df8bae1dSRodney W. Grimes static void 169719ba8395SChristian S.J. Peron catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen, 16984d621040SChristian S.J. Peron void (*cpfn)(struct bpf_d *, caddr_t, u_int, void *, u_int), 16994d621040SChristian S.J. Peron struct timeval *tv) 1700df8bae1dSRodney W. Grimes { 17014d621040SChristian S.J. Peron struct bpf_hdr hdr; 17028994a245SDag-Erling Smørgrav int totlen, curlen; 17038994a245SDag-Erling Smørgrav int hdrlen = d->bd_bif->bif_hdrlen; 17047819da79SJohn-Mark Gurney int do_wakeup = 0; 17059e610888SDag-Erling Smørgrav 1706a3272e3cSChristian S.J. Peron BPFD_LOCK_ASSERT(d); 17074d621040SChristian S.J. Peron 17084d621040SChristian S.J. Peron /* 17094d621040SChristian S.J. Peron * Detect whether user space has released a buffer back to us, and if 17104d621040SChristian S.J. Peron * so, move it from being a hold buffer to a free buffer. This may 17114d621040SChristian S.J. Peron * not be the best place to do it (for example, we might only want to 17124d621040SChristian S.J. Peron * run this check if we need the space), but for now it's a reliable 17134d621040SChristian S.J. Peron * spot to do it. 17144d621040SChristian S.J. Peron */ 1715fa0c2b34SRobert Watson if (d->bd_fbuf == NULL && bpf_canfreebuf(d)) { 17164d621040SChristian S.J. Peron d->bd_fbuf = d->bd_hbuf; 17174d621040SChristian S.J. Peron d->bd_hbuf = NULL; 17184d621040SChristian S.J. Peron d->bd_hlen = 0; 17194d621040SChristian S.J. Peron } 17204d621040SChristian S.J. Peron 1721df8bae1dSRodney W. Grimes /* 1722df8bae1dSRodney W. Grimes * Figure out how many bytes to move. If the packet is 1723df8bae1dSRodney W. Grimes * greater or equal to the snapshot length, transfer that 1724df8bae1dSRodney W. Grimes * much. Otherwise, transfer the whole packet (unless 1725df8bae1dSRodney W. Grimes * we hit the buffer size limit). 1726df8bae1dSRodney W. Grimes */ 1727df8bae1dSRodney W. Grimes totlen = hdrlen + min(snaplen, pktlen); 1728df8bae1dSRodney W. Grimes if (totlen > d->bd_bufsize) 1729df8bae1dSRodney W. Grimes totlen = d->bd_bufsize; 1730df8bae1dSRodney W. Grimes 1731df8bae1dSRodney W. Grimes /* 1732df8bae1dSRodney W. Grimes * Round up the end of the previous packet to the next longword. 1733a7a91e65SRobert Watson * 1734a7a91e65SRobert Watson * Drop the packet if there's no room and no hope of room 1735a7a91e65SRobert Watson * If the packet would overflow the storage buffer or the storage 1736a7a91e65SRobert Watson * buffer is considered immutable by the buffer model, try to rotate 1737a7a91e65SRobert Watson * the buffer and wakeup pending processes. 1738df8bae1dSRodney W. Grimes */ 1739df8bae1dSRodney W. Grimes curlen = BPF_WORDALIGN(d->bd_slen); 1740a7a91e65SRobert Watson if (curlen + totlen > d->bd_bufsize || !bpf_canwritebuf(d)) { 1741572bde2aSRobert Watson if (d->bd_fbuf == NULL) { 1742df8bae1dSRodney W. Grimes /* 1743a7a91e65SRobert Watson * There's no room in the store buffer, and no 1744a7a91e65SRobert Watson * prospect of room, so drop the packet. Notify the 1745a7a91e65SRobert Watson * buffer model. 1746df8bae1dSRodney W. Grimes */ 1747a7a91e65SRobert Watson bpf_buffull(d); 1748df8bae1dSRodney W. Grimes ++d->bd_dcount; 1749df8bae1dSRodney W. Grimes return; 1750df8bae1dSRodney W. Grimes } 1751df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 17527819da79SJohn-Mark Gurney do_wakeup = 1; 1753df8bae1dSRodney W. Grimes curlen = 0; 1754a7a91e65SRobert Watson } else if (d->bd_immediate || d->bd_state == BPF_TIMED_OUT) 1755df8bae1dSRodney W. Grimes /* 17564d621040SChristian S.J. Peron * Immediate mode is set, or the read timeout has already 17574d621040SChristian S.J. Peron * expired during a select call. A packet arrived, so the 17584d621040SChristian S.J. Peron * reader should be woken up. 1759df8bae1dSRodney W. Grimes */ 17607819da79SJohn-Mark Gurney do_wakeup = 1; 1761df8bae1dSRodney W. Grimes 1762df8bae1dSRodney W. Grimes /* 17634d621040SChristian S.J. Peron * Append the bpf header. Note we append the actual header size, but 17644d621040SChristian S.J. Peron * move forward the length of the header plus padding. 1765df8bae1dSRodney W. Grimes */ 17664d621040SChristian S.J. Peron bzero(&hdr, sizeof(hdr)); 17674d621040SChristian S.J. Peron hdr.bh_tstamp = *tv; 17684d621040SChristian S.J. Peron hdr.bh_datalen = pktlen; 17694d621040SChristian S.J. Peron hdr.bh_hdrlen = hdrlen; 17704d621040SChristian S.J. Peron hdr.bh_caplen = totlen - hdrlen; 17714d621040SChristian S.J. Peron bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr, sizeof(hdr)); 17724d621040SChristian S.J. Peron 1773df8bae1dSRodney W. Grimes /* 1774df8bae1dSRodney W. Grimes * Copy the packet data into the store buffer and update its length. 1775df8bae1dSRodney W. Grimes */ 17764d621040SChristian S.J. Peron (*cpfn)(d, d->bd_sbuf, curlen + hdrlen, pkt, hdr.bh_caplen); 1777df8bae1dSRodney W. Grimes d->bd_slen = curlen + totlen; 17787819da79SJohn-Mark Gurney 17797819da79SJohn-Mark Gurney if (do_wakeup) 17807819da79SJohn-Mark Gurney bpf_wakeup(d); 1781df8bae1dSRodney W. Grimes } 1782df8bae1dSRodney W. Grimes 1783df8bae1dSRodney W. Grimes /* 1784df8bae1dSRodney W. Grimes * Free buffers currently in use by a descriptor. 1785df8bae1dSRodney W. Grimes * Called on close. 1786df8bae1dSRodney W. Grimes */ 1787df8bae1dSRodney W. Grimes static void 178819ba8395SChristian S.J. Peron bpf_freed(struct bpf_d *d) 1789df8bae1dSRodney W. Grimes { 17904d621040SChristian S.J. Peron 1791df8bae1dSRodney W. Grimes /* 1792df8bae1dSRodney W. Grimes * We don't need to lock out interrupts since this descriptor has 1793df8bae1dSRodney W. Grimes * been detached from its interface and it yet hasn't been marked 1794df8bae1dSRodney W. Grimes * free. 1795df8bae1dSRodney W. Grimes */ 17964d621040SChristian S.J. Peron bpf_free(d); 1797ae275efcSJung-uk Kim if (d->bd_rfilter) { 179893e39f0bSChristian S.J. Peron free((caddr_t)d->bd_rfilter, M_BPF); 1799ae275efcSJung-uk Kim #ifdef BPF_JITTER 1800ae275efcSJung-uk Kim bpf_destroy_jit_filter(d->bd_bfilter); 1801ae275efcSJung-uk Kim #endif 1802ae275efcSJung-uk Kim } 180393e39f0bSChristian S.J. Peron if (d->bd_wfilter) 180493e39f0bSChristian S.J. Peron free((caddr_t)d->bd_wfilter, M_BPF); 1805e7bb21b3SJonathan Lemon mtx_destroy(&d->bd_mtx); 1806df8bae1dSRodney W. Grimes } 1807df8bae1dSRodney W. Grimes 1808df8bae1dSRodney W. Grimes /* 180924a229f4SSam Leffler * Attach an interface to bpf. dlt is the link layer type; hdrlen is the 181024a229f4SSam Leffler * fixed size of the link header (variable length headers not yet supported). 1811df8bae1dSRodney W. Grimes */ 1812df8bae1dSRodney W. Grimes void 181319ba8395SChristian S.J. Peron bpfattach(struct ifnet *ifp, u_int dlt, u_int hdrlen) 1814df8bae1dSRodney W. Grimes { 181524a229f4SSam Leffler 181624a229f4SSam Leffler bpfattach2(ifp, dlt, hdrlen, &ifp->if_bpf); 181724a229f4SSam Leffler } 181824a229f4SSam Leffler 181924a229f4SSam Leffler /* 182024a229f4SSam Leffler * Attach an interface to bpf. ifp is a pointer to the structure 182124a229f4SSam Leffler * defining the interface to be attached, dlt is the link layer type, 182224a229f4SSam Leffler * and hdrlen is the fixed size of the link header (variable length 182324a229f4SSam Leffler * headers are not yet supporrted). 182424a229f4SSam Leffler */ 182524a229f4SSam Leffler void 182619ba8395SChristian S.J. Peron bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp) 182724a229f4SSam Leffler { 1828df8bae1dSRodney W. Grimes struct bpf_if *bp; 182919ba8395SChristian S.J. Peron 183019ba8395SChristian S.J. Peron bp = malloc(sizeof(*bp), M_BPF, M_NOWAIT | M_ZERO); 1831572bde2aSRobert Watson if (bp == NULL) 1832df8bae1dSRodney W. Grimes panic("bpfattach"); 1833df8bae1dSRodney W. Grimes 18344a3feeaaSRobert Watson LIST_INIT(&bp->bif_dlist); 1835df8bae1dSRodney W. Grimes bp->bif_ifp = ifp; 1836df8bae1dSRodney W. Grimes bp->bif_dlt = dlt; 18376008862bSJohn Baldwin mtx_init(&bp->bif_mtx, "bpf interface lock", NULL, MTX_DEF); 183816d878ccSChristian S.J. Peron KASSERT(*driverp == NULL, ("bpfattach2: driverp already initialized")); 183916d878ccSChristian S.J. Peron *driverp = bp; 1840df8bae1dSRodney W. Grimes 1841e7bb21b3SJonathan Lemon mtx_lock(&bpf_mtx); 18424a3feeaaSRobert Watson LIST_INSERT_HEAD(&bpf_iflist, bp, bif_next); 1843e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 1844df8bae1dSRodney W. Grimes 1845df8bae1dSRodney W. Grimes /* 1846df8bae1dSRodney W. Grimes * Compute the length of the bpf header. This is not necessarily 1847df8bae1dSRodney W. Grimes * equal to SIZEOF_BPF_HDR because we want to insert spacing such 1848df8bae1dSRodney W. Grimes * that the network layer header begins on a longword boundary (for 1849df8bae1dSRodney W. Grimes * performance reasons and to alleviate alignment restrictions). 1850df8bae1dSRodney W. Grimes */ 1851df8bae1dSRodney W. Grimes bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen; 1852df8bae1dSRodney W. Grimes 18532eeab939SGarrett Wollman if (bootverbose) 185424a229f4SSam Leffler if_printf(ifp, "bpf attached\n"); 1855df8bae1dSRodney W. Grimes } 185653ac6efbSJulian Elischer 1857de5d9935SRobert Watson /* 1858de5d9935SRobert Watson * Detach bpf from an interface. This involves detaching each descriptor 1859de5d9935SRobert Watson * associated with the interface, and leaving bd_bif NULL. Notify each 1860de5d9935SRobert Watson * descriptor as it's detached so that any sleepers wake up and get 1861de5d9935SRobert Watson * ENXIO. 1862de5d9935SRobert Watson */ 1863de5d9935SRobert Watson void 186419ba8395SChristian S.J. Peron bpfdetach(struct ifnet *ifp) 1865de5d9935SRobert Watson { 18664a3feeaaSRobert Watson struct bpf_if *bp; 1867de5d9935SRobert Watson struct bpf_d *d; 1868de5d9935SRobert Watson 1869de5d9935SRobert Watson /* Locate BPF interface information */ 18708eab61f3SSam Leffler mtx_lock(&bpf_mtx); 18714a3feeaaSRobert Watson LIST_FOREACH(bp, &bpf_iflist, bif_next) { 1872de5d9935SRobert Watson if (ifp == bp->bif_ifp) 1873de5d9935SRobert Watson break; 1874de5d9935SRobert Watson } 1875de5d9935SRobert Watson 1876de5d9935SRobert Watson /* Interface wasn't attached */ 1877d79bf337SMatthew N. Dodd if ((bp == NULL) || (bp->bif_ifp == NULL)) { 1878e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 18799bf40edeSBrooks Davis printf("bpfdetach: %s was not attached\n", ifp->if_xname); 1880de5d9935SRobert Watson return; 1881de5d9935SRobert Watson } 1882de5d9935SRobert Watson 18834a3feeaaSRobert Watson LIST_REMOVE(bp, bif_next); 18848eab61f3SSam Leffler mtx_unlock(&bpf_mtx); 1885de5d9935SRobert Watson 18864a3feeaaSRobert Watson while ((d = LIST_FIRST(&bp->bif_dlist)) != NULL) { 1887e7bb21b3SJonathan Lemon bpf_detachd(d); 1888e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1889e7bb21b3SJonathan Lemon bpf_wakeup(d); 1890e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1891e7bb21b3SJonathan Lemon } 1892e7bb21b3SJonathan Lemon 1893e7bb21b3SJonathan Lemon mtx_destroy(&bp->bif_mtx); 1894de5d9935SRobert Watson free(bp, M_BPF); 18958eab61f3SSam Leffler } 1896de5d9935SRobert Watson 18978eab61f3SSam Leffler /* 18988eab61f3SSam Leffler * Get a list of available data link type of the interface. 18998eab61f3SSam Leffler */ 19008eab61f3SSam Leffler static int 190119ba8395SChristian S.J. Peron bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *bfl) 19028eab61f3SSam Leffler { 19038eab61f3SSam Leffler int n, error; 19048eab61f3SSam Leffler struct ifnet *ifp; 19058eab61f3SSam Leffler struct bpf_if *bp; 19068eab61f3SSam Leffler 19078eab61f3SSam Leffler ifp = d->bd_bif->bif_ifp; 19088eab61f3SSam Leffler n = 0; 19098eab61f3SSam Leffler error = 0; 19108eab61f3SSam Leffler mtx_lock(&bpf_mtx); 19114a3feeaaSRobert Watson LIST_FOREACH(bp, &bpf_iflist, bif_next) { 19128eab61f3SSam Leffler if (bp->bif_ifp != ifp) 19138eab61f3SSam Leffler continue; 19148eab61f3SSam Leffler if (bfl->bfl_list != NULL) { 19158eab61f3SSam Leffler if (n >= bfl->bfl_len) { 1916e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 19178eab61f3SSam Leffler return (ENOMEM); 19188eab61f3SSam Leffler } 19198eab61f3SSam Leffler error = copyout(&bp->bif_dlt, 19208eab61f3SSam Leffler bfl->bfl_list + n, sizeof(u_int)); 19218eab61f3SSam Leffler } 19228eab61f3SSam Leffler n++; 19238eab61f3SSam Leffler } 19248eab61f3SSam Leffler mtx_unlock(&bpf_mtx); 19258eab61f3SSam Leffler bfl->bfl_len = n; 19268eab61f3SSam Leffler return (error); 19278eab61f3SSam Leffler } 19288eab61f3SSam Leffler 19298eab61f3SSam Leffler /* 19308eab61f3SSam Leffler * Set the data link type of a BPF instance. 19318eab61f3SSam Leffler */ 19328eab61f3SSam Leffler static int 193319ba8395SChristian S.J. Peron bpf_setdlt(struct bpf_d *d, u_int dlt) 19348eab61f3SSam Leffler { 19358eab61f3SSam Leffler int error, opromisc; 19368eab61f3SSam Leffler struct ifnet *ifp; 19378eab61f3SSam Leffler struct bpf_if *bp; 19388eab61f3SSam Leffler 19398eab61f3SSam Leffler if (d->bd_bif->bif_dlt == dlt) 19408eab61f3SSam Leffler return (0); 19418eab61f3SSam Leffler ifp = d->bd_bif->bif_ifp; 19428eab61f3SSam Leffler mtx_lock(&bpf_mtx); 19434a3feeaaSRobert Watson LIST_FOREACH(bp, &bpf_iflist, bif_next) { 19448eab61f3SSam Leffler if (bp->bif_ifp == ifp && bp->bif_dlt == dlt) 19458eab61f3SSam Leffler break; 19468eab61f3SSam Leffler } 19478eab61f3SSam Leffler mtx_unlock(&bpf_mtx); 19488eab61f3SSam Leffler if (bp != NULL) { 19498eab61f3SSam Leffler opromisc = d->bd_promisc; 19508eab61f3SSam Leffler bpf_detachd(d); 19518eab61f3SSam Leffler bpf_attachd(d, bp); 195293daabddSBrian Feldman BPFD_LOCK(d); 19538eab61f3SSam Leffler reset_d(d); 19548eab61f3SSam Leffler BPFD_UNLOCK(d); 19558eab61f3SSam Leffler if (opromisc) { 19568eab61f3SSam Leffler error = ifpromisc(bp->bif_ifp, 1); 19578eab61f3SSam Leffler if (error) 19588eab61f3SSam Leffler if_printf(bp->bif_ifp, 19598eab61f3SSam Leffler "bpf_setdlt: ifpromisc failed (%d)\n", 19608eab61f3SSam Leffler error); 19618eab61f3SSam Leffler else 19628eab61f3SSam Leffler d->bd_promisc = 1; 19638eab61f3SSam Leffler } 19648eab61f3SSam Leffler } 19658eab61f3SSam Leffler return (bp == NULL ? EINVAL : 0); 1966de5d9935SRobert Watson } 1967de5d9935SRobert Watson 19683f54a085SPoul-Henning Kamp static void 196919ba8395SChristian S.J. Peron bpf_clone(void *arg, struct ucred *cred, char *name, int namelen, 197019ba8395SChristian S.J. Peron struct cdev **dev) 19713f54a085SPoul-Henning Kamp { 19723f54a085SPoul-Henning Kamp int u; 19733f54a085SPoul-Henning Kamp 1974f3732fd1SPoul-Henning Kamp if (*dev != NULL) 19753f54a085SPoul-Henning Kamp return; 1976db901281SPoul-Henning Kamp if (dev_stdclone(name, NULL, "bpf", &u) != 1) 19773f54a085SPoul-Henning Kamp return; 1978b0d17ba6SPoul-Henning Kamp *dev = make_dev(&bpf_cdevsw, unit2minor(u), UID_ROOT, GID_WHEEL, 0600, 1979b0d17ba6SPoul-Henning Kamp "bpf%d", u); 1980f4f6abcbSPoul-Henning Kamp dev_ref(*dev); 1981b0d17ba6SPoul-Henning Kamp (*dev)->si_flags |= SI_CHEAPCLONE; 19823f54a085SPoul-Henning Kamp return; 19833f54a085SPoul-Henning Kamp } 19843f54a085SPoul-Henning Kamp 1985514ede09SBruce Evans static void 198619ba8395SChristian S.J. Peron bpf_drvinit(void *unused) 198753ac6efbSJulian Elischer { 198853ac6efbSJulian Elischer 19896008862bSJohn Baldwin mtx_init(&bpf_mtx, "bpf global lock", NULL, MTX_DEF); 19904a3feeaaSRobert Watson LIST_INIT(&bpf_iflist); 1991db901281SPoul-Henning Kamp EVENTHANDLER_REGISTER(dev_clone, bpf_clone, 0, 1000); 19927198bf47SJulian Elischer } 199353ac6efbSJulian Elischer 199469f7644bSChristian S.J. Peron static void 199569f7644bSChristian S.J. Peron bpfstats_fill_xbpf(struct xbpf_d *d, struct bpf_d *bd) 199669f7644bSChristian S.J. Peron { 199769f7644bSChristian S.J. Peron 199869f7644bSChristian S.J. Peron bzero(d, sizeof(*d)); 199969f7644bSChristian S.J. Peron BPFD_LOCK_ASSERT(bd); 20004d621040SChristian S.J. Peron d->bd_structsize = sizeof(*d); 200169f7644bSChristian S.J. Peron d->bd_immediate = bd->bd_immediate; 200269f7644bSChristian S.J. Peron d->bd_promisc = bd->bd_promisc; 200369f7644bSChristian S.J. Peron d->bd_hdrcmplt = bd->bd_hdrcmplt; 2004560a54e1SJung-uk Kim d->bd_direction = bd->bd_direction; 2005560a54e1SJung-uk Kim d->bd_feedback = bd->bd_feedback; 200669f7644bSChristian S.J. Peron d->bd_async = bd->bd_async; 200769f7644bSChristian S.J. Peron d->bd_rcount = bd->bd_rcount; 200869f7644bSChristian S.J. Peron d->bd_dcount = bd->bd_dcount; 200969f7644bSChristian S.J. Peron d->bd_fcount = bd->bd_fcount; 201069f7644bSChristian S.J. Peron d->bd_sig = bd->bd_sig; 201169f7644bSChristian S.J. Peron d->bd_slen = bd->bd_slen; 201269f7644bSChristian S.J. Peron d->bd_hlen = bd->bd_hlen; 201369f7644bSChristian S.J. Peron d->bd_bufsize = bd->bd_bufsize; 201469f7644bSChristian S.J. Peron d->bd_pid = bd->bd_pid; 201569f7644bSChristian S.J. Peron strlcpy(d->bd_ifname, 201669f7644bSChristian S.J. Peron bd->bd_bif->bif_ifp->if_xname, IFNAMSIZ); 201793e39f0bSChristian S.J. Peron d->bd_locked = bd->bd_locked; 20184d621040SChristian S.J. Peron d->bd_wcount = bd->bd_wcount; 20194d621040SChristian S.J. Peron d->bd_wdcount = bd->bd_wdcount; 20204d621040SChristian S.J. Peron d->bd_wfcount = bd->bd_wfcount; 20214d621040SChristian S.J. Peron d->bd_zcopy = bd->bd_zcopy; 20224d621040SChristian S.J. Peron d->bd_bufmode = bd->bd_bufmode; 202369f7644bSChristian S.J. Peron } 202469f7644bSChristian S.J. Peron 202569f7644bSChristian S.J. Peron static int 202669f7644bSChristian S.J. Peron bpf_stats_sysctl(SYSCTL_HANDLER_ARGS) 202769f7644bSChristian S.J. Peron { 2028422a63daSChristian S.J. Peron struct xbpf_d *xbdbuf, *xbd; 2029422a63daSChristian S.J. Peron int index, error; 203069f7644bSChristian S.J. Peron struct bpf_if *bp; 203169f7644bSChristian S.J. Peron struct bpf_d *bd; 203269f7644bSChristian S.J. Peron 203369f7644bSChristian S.J. Peron /* 203469f7644bSChristian S.J. Peron * XXX This is not technically correct. It is possible for non 203569f7644bSChristian S.J. Peron * privileged users to open bpf devices. It would make sense 203669f7644bSChristian S.J. Peron * if the users who opened the devices were able to retrieve 203769f7644bSChristian S.J. Peron * the statistics for them, too. 203869f7644bSChristian S.J. Peron */ 2039acd3428bSRobert Watson error = priv_check(req->td, PRIV_NET_BPF); 204069f7644bSChristian S.J. Peron if (error) 204169f7644bSChristian S.J. Peron return (error); 204269f7644bSChristian S.J. Peron if (req->oldptr == NULL) 2043422a63daSChristian S.J. Peron return (SYSCTL_OUT(req, 0, bpf_bpfd_cnt * sizeof(*xbd))); 204469f7644bSChristian S.J. Peron if (bpf_bpfd_cnt == 0) 204569f7644bSChristian S.J. Peron return (SYSCTL_OUT(req, 0, 0)); 2046422a63daSChristian S.J. Peron xbdbuf = malloc(req->oldlen, M_BPF, M_WAITOK); 204769f7644bSChristian S.J. Peron mtx_lock(&bpf_mtx); 2048422a63daSChristian S.J. Peron if (req->oldlen < (bpf_bpfd_cnt * sizeof(*xbd))) { 2049422a63daSChristian S.J. Peron mtx_unlock(&bpf_mtx); 2050422a63daSChristian S.J. Peron free(xbdbuf, M_BPF); 2051422a63daSChristian S.J. Peron return (ENOMEM); 2052422a63daSChristian S.J. Peron } 2053422a63daSChristian S.J. Peron index = 0; 205469f7644bSChristian S.J. Peron LIST_FOREACH(bp, &bpf_iflist, bif_next) { 20551fc9e387SChristian S.J. Peron BPFIF_LOCK(bp); 205669f7644bSChristian S.J. Peron LIST_FOREACH(bd, &bp->bif_dlist, bd_next) { 2057422a63daSChristian S.J. Peron xbd = &xbdbuf[index++]; 205869f7644bSChristian S.J. Peron BPFD_LOCK(bd); 2059422a63daSChristian S.J. Peron bpfstats_fill_xbpf(xbd, bd); 206069f7644bSChristian S.J. Peron BPFD_UNLOCK(bd); 206169f7644bSChristian S.J. Peron } 20621fc9e387SChristian S.J. Peron BPFIF_UNLOCK(bp); 206369f7644bSChristian S.J. Peron } 206469f7644bSChristian S.J. Peron mtx_unlock(&bpf_mtx); 2065422a63daSChristian S.J. Peron error = SYSCTL_OUT(req, xbdbuf, index * sizeof(*xbd)); 2066422a63daSChristian S.J. Peron free(xbdbuf, M_BPF); 206769f7644bSChristian S.J. Peron return (error); 206869f7644bSChristian S.J. Peron } 206969f7644bSChristian S.J. Peron 2070237fdd78SRobert Watson SYSINIT(bpfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,bpf_drvinit,NULL); 207153ac6efbSJulian Elischer 20725bb5f2c9SPeter Wemm #else /* !DEV_BPF && !NETGRAPH_BPF */ 2073f8dc4716SMike Smith /* 2074f8dc4716SMike Smith * NOP stubs to allow bpf-using drivers to load and function. 2075f8dc4716SMike Smith * 2076f8dc4716SMike Smith * A 'better' implementation would allow the core bpf functionality 2077f8dc4716SMike Smith * to be loaded at runtime. 2078f8dc4716SMike Smith */ 20797eae78a4SChristian S.J. Peron static struct bpf_if bp_null; 2080f8dc4716SMike Smith 2081f8dc4716SMike Smith void 208219ba8395SChristian S.J. Peron bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen) 2083f8dc4716SMike Smith { 2084f8dc4716SMike Smith } 2085f8dc4716SMike Smith 2086f8dc4716SMike Smith void 208719ba8395SChristian S.J. Peron bpf_mtap(struct bpf_if *bp, struct mbuf *m) 2088f8dc4716SMike Smith { 2089f8dc4716SMike Smith } 2090f8dc4716SMike Smith 2091f8dc4716SMike Smith void 209219ba8395SChristian S.J. Peron bpf_mtap2(struct bpf_if *bp, void *d, u_int l, struct mbuf *m) 2093437ffe18SSam Leffler { 2094437ffe18SSam Leffler } 2095437ffe18SSam Leffler 2096437ffe18SSam Leffler void 209719ba8395SChristian S.J. Peron bpfattach(struct ifnet *ifp, u_int dlt, u_int hdrlen) 2098f8dc4716SMike Smith { 20997eae78a4SChristian S.J. Peron 21007eae78a4SChristian S.J. Peron bpfattach2(ifp, dlt, hdrlen, &ifp->if_bpf); 2101f8dc4716SMike Smith } 2102f8dc4716SMike Smith 2103da626c17SBill Paul void 210419ba8395SChristian S.J. Peron bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp) 21055f7a7923SSam Leffler { 21067eae78a4SChristian S.J. Peron 21077eae78a4SChristian S.J. Peron *driverp = &bp_null; 21085f7a7923SSam Leffler } 21095f7a7923SSam Leffler 21105f7a7923SSam Leffler void 211119ba8395SChristian S.J. Peron bpfdetach(struct ifnet *ifp) 2112da626c17SBill Paul { 2113da626c17SBill Paul } 2114da626c17SBill Paul 2115f8dc4716SMike Smith u_int 211619ba8395SChristian S.J. Peron bpf_filter(const struct bpf_insn *pc, u_char *p, u_int wirelen, u_int buflen) 2117f8dc4716SMike Smith { 2118f8dc4716SMike Smith return -1; /* "no filter" behaviour */ 2119f8dc4716SMike Smith } 2120f8dc4716SMike Smith 21215bb5f2c9SPeter Wemm int 212219ba8395SChristian S.J. Peron bpf_validate(const struct bpf_insn *f, int len) 21235bb5f2c9SPeter Wemm { 21245bb5f2c9SPeter Wemm return 0; /* false */ 21255bb5f2c9SPeter Wemm } 21265bb5f2c9SPeter Wemm 21275bb5f2c9SPeter Wemm #endif /* !DEV_BPF && !NETGRAPH_BPF */ 2128