1c398230bSWarner Losh /*- 2df8bae1dSRodney W. Grimes * Copyright (c) 1990, 1991, 1993 3253a3814SLawrence Stewart * 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" 41fc0a61a4SKonstantin Belousov #include "opt_compat.h" 425bb5f2c9SPeter Wemm #include "opt_netgraph.h" 43df8bae1dSRodney W. Grimes 4495aab9ccSJohn-Mark Gurney #include <sys/types.h> 45df8bae1dSRodney W. Grimes #include <sys/param.h> 46e4b3229aSAlexander V. Chernikov #include <sys/lock.h> 47e4b3229aSAlexander V. Chernikov #include <sys/rwlock.h> 48df8bae1dSRodney W. Grimes #include <sys/systm.h> 49ce7609a4SBruce Evans #include <sys/conf.h> 50e76eee55SPoul-Henning Kamp #include <sys/fcntl.h> 51ebd8672cSBjoern A. Zeeb #include <sys/jail.h> 524d1d4912SBruce Evans #include <sys/malloc.h> 53df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 54df8bae1dSRodney W. Grimes #include <sys/time.h> 55acd3428bSRobert Watson #include <sys/priv.h> 56df8bae1dSRodney W. Grimes #include <sys/proc.h> 570310c19fSBruce Evans #include <sys/signalvar.h> 58528f627fSBruce Evans #include <sys/filio.h> 59528f627fSBruce Evans #include <sys/sockio.h> 60528f627fSBruce Evans #include <sys/ttycom.h> 61e76eee55SPoul-Henning Kamp #include <sys/uio.h> 62df8bae1dSRodney W. Grimes 6395aab9ccSJohn-Mark Gurney #include <sys/event.h> 6495aab9ccSJohn-Mark Gurney #include <sys/file.h> 65243ac7d8SPeter Wemm #include <sys/poll.h> 6695aab9ccSJohn-Mark Gurney #include <sys/proc.h> 67df8bae1dSRodney W. Grimes 68df8bae1dSRodney W. Grimes #include <sys/socket.h> 69df8bae1dSRodney W. Grimes 70fba9235dSBruce Evans #include <net/if.h> 71e4b3229aSAlexander V. Chernikov #define BPF_INTERNAL 72df8bae1dSRodney W. Grimes #include <net/bpf.h> 734d621040SChristian S.J. Peron #include <net/bpf_buffer.h> 74ae275efcSJung-uk Kim #ifdef BPF_JITTER 75ae275efcSJung-uk Kim #include <net/bpf_jitter.h> 76ae275efcSJung-uk Kim #endif 774d621040SChristian S.J. Peron #include <net/bpf_zerocopy.h> 78df8bae1dSRodney W. Grimes #include <net/bpfdesc.h> 79530c0060SRobert Watson #include <net/vnet.h> 80df8bae1dSRodney W. Grimes 81df8bae1dSRodney W. Grimes #include <netinet/in.h> 82df8bae1dSRodney W. Grimes #include <netinet/if_ether.h> 83df8bae1dSRodney W. Grimes #include <sys/kernel.h> 84f708ef1bSPoul-Henning Kamp #include <sys/sysctl.h> 857b778b5eSEivind Eklund 86246b5467SSam Leffler #include <net80211/ieee80211_freebsd.h> 87246b5467SSam Leffler 88aed55708SRobert Watson #include <security/mac/mac_framework.h> 89aed55708SRobert Watson 904d621040SChristian S.J. Peron MALLOC_DEFINE(M_BPF, "BPF", "BPF data"); 9187f6c662SJulian Elischer 925bb5f2c9SPeter Wemm #if defined(DEV_BPF) || defined(NETGRAPH_BPF) 9353ac6efbSJulian Elischer 94df8bae1dSRodney W. Grimes #define PRINET 26 /* interruptible */ 95df8bae1dSRodney W. Grimes 96547d94bdSJung-uk Kim #define SIZEOF_BPF_HDR(type) \ 97547d94bdSJung-uk Kim (offsetof(type, bh_hdrlen) + sizeof(((type *)0)->bh_hdrlen)) 98547d94bdSJung-uk Kim 99fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 100fc0a61a4SKonstantin Belousov #include <sys/mount.h> 101fc0a61a4SKonstantin Belousov #include <compat/freebsd32/freebsd32.h> 102fc0a61a4SKonstantin Belousov #define BPF_ALIGNMENT32 sizeof(int32_t) 103fc0a61a4SKonstantin Belousov #define BPF_WORDALIGN32(x) (((x)+(BPF_ALIGNMENT32-1))&~(BPF_ALIGNMENT32-1)) 104fc0a61a4SKonstantin Belousov 105547d94bdSJung-uk Kim #ifndef BURN_BRIDGES 106fc0a61a4SKonstantin Belousov /* 107fc0a61a4SKonstantin Belousov * 32-bit version of structure prepended to each packet. We use this header 108fc0a61a4SKonstantin Belousov * instead of the standard one for 32-bit streams. We mark the a stream as 109fc0a61a4SKonstantin Belousov * 32-bit the first time we see a 32-bit compat ioctl request. 110fc0a61a4SKonstantin Belousov */ 111fc0a61a4SKonstantin Belousov struct bpf_hdr32 { 112fc0a61a4SKonstantin Belousov struct timeval32 bh_tstamp; /* time stamp */ 113fc0a61a4SKonstantin Belousov uint32_t bh_caplen; /* length of captured portion */ 114fc0a61a4SKonstantin Belousov uint32_t bh_datalen; /* original length of packet */ 115fc0a61a4SKonstantin Belousov uint16_t bh_hdrlen; /* length of bpf header (this struct 116fc0a61a4SKonstantin Belousov plus alignment padding) */ 117fc0a61a4SKonstantin Belousov }; 118253a3814SLawrence Stewart #endif 119fc0a61a4SKonstantin Belousov 120fc0a61a4SKonstantin Belousov struct bpf_program32 { 121fc0a61a4SKonstantin Belousov u_int bf_len; 122fc0a61a4SKonstantin Belousov uint32_t bf_insns; 123fc0a61a4SKonstantin Belousov }; 124fc0a61a4SKonstantin Belousov 125fc0a61a4SKonstantin Belousov struct bpf_dltlist32 { 126fc0a61a4SKonstantin Belousov u_int bfl_len; 127fc0a61a4SKonstantin Belousov u_int bfl_list; 128fc0a61a4SKonstantin Belousov }; 129fc0a61a4SKonstantin Belousov 130fc0a61a4SKonstantin Belousov #define BIOCSETF32 _IOW('B', 103, struct bpf_program32) 131fc0a61a4SKonstantin Belousov #define BIOCSRTIMEOUT32 _IOW('B', 109, struct timeval32) 132fc0a61a4SKonstantin Belousov #define BIOCGRTIMEOUT32 _IOR('B', 110, struct timeval32) 133fc0a61a4SKonstantin Belousov #define BIOCGDLTLIST32 _IOWR('B', 121, struct bpf_dltlist32) 134fc0a61a4SKonstantin Belousov #define BIOCSETWF32 _IOW('B', 123, struct bpf_program32) 135fc0a61a4SKonstantin Belousov #define BIOCSETFNR32 _IOW('B', 130, struct bpf_program32) 136253a3814SLawrence Stewart #endif 137fc0a61a4SKonstantin Belousov 138df8bae1dSRodney W. Grimes /* 139d1a67300SRobert Watson * bpf_iflist is a list of BPF interface structures, each corresponding to a 140d1a67300SRobert Watson * specific DLT. The same network interface might have several BPF interface 141d1a67300SRobert Watson * structures registered by different layers in the stack (i.e., 802.11 142d1a67300SRobert Watson * frames, ethernet frames, etc). 143df8bae1dSRodney W. Grimes */ 1444a3feeaaSRobert Watson static LIST_HEAD(, bpf_if) bpf_iflist; 145e7bb21b3SJonathan Lemon static struct mtx bpf_mtx; /* bpf global lock */ 14669f7644bSChristian S.J. Peron static int bpf_bpfd_cnt; 147df8bae1dSRodney W. Grimes 14819ba8395SChristian S.J. Peron static void bpf_attachd(struct bpf_d *, struct bpf_if *); 14919ba8395SChristian S.J. Peron static void bpf_detachd(struct bpf_d *); 150929ddbbbSAlfred Perlstein static void bpf_freed(struct bpf_d *); 151cb44b6dfSAndrew Thompson static int bpf_movein(struct uio *, int, struct ifnet *, struct mbuf **, 152560a54e1SJung-uk Kim struct sockaddr *, int *, struct bpf_insn *); 153929ddbbbSAlfred Perlstein static int bpf_setif(struct bpf_d *, struct ifreq *); 154929ddbbbSAlfred Perlstein static void bpf_timed_out(void *); 155e7bb21b3SJonathan Lemon static __inline void 156929ddbbbSAlfred Perlstein bpf_wakeup(struct bpf_d *); 1574d621040SChristian S.J. Peron static void catchpacket(struct bpf_d *, u_char *, u_int, u_int, 1584d621040SChristian S.J. Peron void (*)(struct bpf_d *, caddr_t, u_int, void *, u_int), 159547d94bdSJung-uk Kim struct bintime *); 160929ddbbbSAlfred Perlstein static void reset_d(struct bpf_d *); 16193e39f0bSChristian S.J. Peron static int bpf_setf(struct bpf_d *, struct bpf_program *, u_long cmd); 1628eab61f3SSam Leffler static int bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *); 1638eab61f3SSam Leffler static int bpf_setdlt(struct bpf_d *, u_int); 16495aab9ccSJohn-Mark Gurney static void filt_bpfdetach(struct knote *); 16595aab9ccSJohn-Mark Gurney static int filt_bpfread(struct knote *, long); 166a3272e3cSChristian S.J. Peron static void bpf_drvinit(void *); 16769f7644bSChristian S.J. Peron static int bpf_stats_sysctl(SYSCTL_HANDLER_ARGS); 16869f7644bSChristian S.J. Peron 16969f7644bSChristian S.J. Peron SYSCTL_NODE(_net, OID_AUTO, bpf, CTLFLAG_RW, 0, "bpf sysctl"); 17012dc9582SJung-uk Kim int bpf_maxinsns = BPF_MAXINSNS; 17169f7644bSChristian S.J. Peron SYSCTL_INT(_net_bpf, OID_AUTO, maxinsns, CTLFLAG_RW, 17269f7644bSChristian S.J. Peron &bpf_maxinsns, 0, "Maximum bpf program instructions"); 173ffeeb924SChristian S.J. Peron static int bpf_zerocopy_enable = 0; 1744d621040SChristian S.J. Peron SYSCTL_INT(_net_bpf, OID_AUTO, zerocopy_enable, CTLFLAG_RW, 1754d621040SChristian S.J. Peron &bpf_zerocopy_enable, 0, "Enable new zero-copy BPF buffer sessions"); 1766472ac3dSEd Schouten static SYSCTL_NODE(_net_bpf, OID_AUTO, stats, CTLFLAG_MPSAFE | CTLFLAG_RW, 17769f7644bSChristian S.J. Peron bpf_stats_sysctl, "bpf statistics portal"); 178df8bae1dSRodney W. Grimes 179*51ec1eb7SAlexander V. Chernikov static VNET_DEFINE(int, bpf_optimize_writers) = 0; 180*51ec1eb7SAlexander V. Chernikov #define V_bpf_optimize_writers VNET(bpf_optimize_writers) 181*51ec1eb7SAlexander V. Chernikov SYSCTL_VNET_INT(_net_bpf, OID_AUTO, optimize_writers, 182*51ec1eb7SAlexander V. Chernikov CTLFLAG_RW, &VNET_NAME(bpf_optimize_writers), 0, 183*51ec1eb7SAlexander V. Chernikov "Do not send packets until BPF program is set"); 184*51ec1eb7SAlexander V. Chernikov 18587f6c662SJulian Elischer static d_open_t bpfopen; 18687f6c662SJulian Elischer static d_read_t bpfread; 18787f6c662SJulian Elischer static d_write_t bpfwrite; 18887f6c662SJulian Elischer static d_ioctl_t bpfioctl; 189243ac7d8SPeter Wemm static d_poll_t bpfpoll; 19095aab9ccSJohn-Mark Gurney static d_kqfilter_t bpfkqfilter; 19187f6c662SJulian Elischer 1924e2f199eSPoul-Henning Kamp static struct cdevsw bpf_cdevsw = { 193dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 1947ac40f5fSPoul-Henning Kamp .d_open = bpfopen, 1957ac40f5fSPoul-Henning Kamp .d_read = bpfread, 1967ac40f5fSPoul-Henning Kamp .d_write = bpfwrite, 1977ac40f5fSPoul-Henning Kamp .d_ioctl = bpfioctl, 1987ac40f5fSPoul-Henning Kamp .d_poll = bpfpoll, 1997ac40f5fSPoul-Henning Kamp .d_name = "bpf", 20095aab9ccSJohn-Mark Gurney .d_kqfilter = bpfkqfilter, 2014e2f199eSPoul-Henning Kamp }; 20287f6c662SJulian Elischer 203e76d823bSRobert Watson static struct filterops bpfread_filtops = { 204e76d823bSRobert Watson .f_isfd = 1, 205e76d823bSRobert Watson .f_detach = filt_bpfdetach, 206e76d823bSRobert Watson .f_event = filt_bpfread, 207e76d823bSRobert Watson }; 20887f6c662SJulian Elischer 2094d621040SChristian S.J. Peron /* 2104d621040SChristian S.J. Peron * Wrapper functions for various buffering methods. If the set of buffer 2114d621040SChristian S.J. Peron * modes expands, we will probably want to introduce a switch data structure 2124d621040SChristian S.J. Peron * similar to protosw, et. 2134d621040SChristian S.J. Peron */ 2144d621040SChristian S.J. Peron static void 2154d621040SChristian S.J. Peron bpf_append_bytes(struct bpf_d *d, caddr_t buf, u_int offset, void *src, 2164d621040SChristian S.J. Peron u_int len) 2174d621040SChristian S.J. Peron { 2184d621040SChristian S.J. Peron 219e4b3229aSAlexander V. Chernikov BPFD_WLOCK_ASSERT(d); 2204d621040SChristian S.J. Peron 2214d621040SChristian S.J. Peron switch (d->bd_bufmode) { 2224d621040SChristian S.J. Peron case BPF_BUFMODE_BUFFER: 2234d621040SChristian S.J. Peron return (bpf_buffer_append_bytes(d, buf, offset, src, len)); 2244d621040SChristian S.J. Peron 2254d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 2264d621040SChristian S.J. Peron d->bd_zcopy++; 2274d621040SChristian S.J. Peron return (bpf_zerocopy_append_bytes(d, buf, offset, src, len)); 2284d621040SChristian S.J. Peron 2294d621040SChristian S.J. Peron default: 2304d621040SChristian S.J. Peron panic("bpf_buf_append_bytes"); 2314d621040SChristian S.J. Peron } 2324d621040SChristian S.J. Peron } 2334d621040SChristian S.J. Peron 2344d621040SChristian S.J. Peron static void 2354d621040SChristian S.J. Peron bpf_append_mbuf(struct bpf_d *d, caddr_t buf, u_int offset, void *src, 2364d621040SChristian S.J. Peron u_int len) 2374d621040SChristian S.J. Peron { 2384d621040SChristian S.J. Peron 239e4b3229aSAlexander V. Chernikov BPFD_WLOCK_ASSERT(d); 2404d621040SChristian S.J. Peron 2414d621040SChristian S.J. Peron switch (d->bd_bufmode) { 2424d621040SChristian S.J. Peron case BPF_BUFMODE_BUFFER: 2434d621040SChristian S.J. Peron return (bpf_buffer_append_mbuf(d, buf, offset, src, len)); 2444d621040SChristian S.J. Peron 2454d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 2464d621040SChristian S.J. Peron d->bd_zcopy++; 2474d621040SChristian S.J. Peron return (bpf_zerocopy_append_mbuf(d, buf, offset, src, len)); 2484d621040SChristian S.J. Peron 2494d621040SChristian S.J. Peron default: 2504d621040SChristian S.J. Peron panic("bpf_buf_append_mbuf"); 2514d621040SChristian S.J. Peron } 2524d621040SChristian S.J. Peron } 2534d621040SChristian S.J. Peron 2544d621040SChristian S.J. Peron /* 25529f612ecSChristian S.J. Peron * This function gets called when the free buffer is re-assigned. 25629f612ecSChristian S.J. Peron */ 25729f612ecSChristian S.J. Peron static void 25829f612ecSChristian S.J. Peron bpf_buf_reclaimed(struct bpf_d *d) 25929f612ecSChristian S.J. Peron { 26029f612ecSChristian S.J. Peron 261e4b3229aSAlexander V. Chernikov BPFD_WLOCK_ASSERT(d); 26229f612ecSChristian S.J. Peron 26329f612ecSChristian S.J. Peron switch (d->bd_bufmode) { 26429f612ecSChristian S.J. Peron case BPF_BUFMODE_BUFFER: 26529f612ecSChristian S.J. Peron return; 26629f612ecSChristian S.J. Peron 26729f612ecSChristian S.J. Peron case BPF_BUFMODE_ZBUF: 26829f612ecSChristian S.J. Peron bpf_zerocopy_buf_reclaimed(d); 26929f612ecSChristian S.J. Peron return; 27029f612ecSChristian S.J. Peron 27129f612ecSChristian S.J. Peron default: 27229f612ecSChristian S.J. Peron panic("bpf_buf_reclaimed"); 27329f612ecSChristian S.J. Peron } 27429f612ecSChristian S.J. Peron } 27529f612ecSChristian S.J. Peron 27629f612ecSChristian S.J. Peron /* 2774d621040SChristian S.J. Peron * If the buffer mechanism has a way to decide that a held buffer can be made 2784d621040SChristian S.J. Peron * free, then it is exposed via the bpf_canfreebuf() interface. (1) is 2794d621040SChristian S.J. Peron * returned if the buffer can be discarded, (0) is returned if it cannot. 2804d621040SChristian S.J. Peron */ 2814d621040SChristian S.J. Peron static int 2824d621040SChristian S.J. Peron bpf_canfreebuf(struct bpf_d *d) 2834d621040SChristian S.J. Peron { 2844d621040SChristian S.J. Peron 2854d621040SChristian S.J. Peron BPFD_LOCK_ASSERT(d); 2864d621040SChristian S.J. Peron 2874d621040SChristian S.J. Peron switch (d->bd_bufmode) { 2884d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 2894d621040SChristian S.J. Peron return (bpf_zerocopy_canfreebuf(d)); 2904d621040SChristian S.J. Peron } 2914d621040SChristian S.J. Peron return (0); 2924d621040SChristian S.J. Peron } 2934d621040SChristian S.J. Peron 294a7a91e65SRobert Watson /* 295a7a91e65SRobert Watson * Allow the buffer model to indicate that the current store buffer is 296a7a91e65SRobert Watson * immutable, regardless of the appearance of space. Return (1) if the 297a7a91e65SRobert Watson * buffer is writable, and (0) if not. 298a7a91e65SRobert Watson */ 299a7a91e65SRobert Watson static int 300a7a91e65SRobert Watson bpf_canwritebuf(struct bpf_d *d) 301a7a91e65SRobert Watson { 302a7a91e65SRobert Watson BPFD_LOCK_ASSERT(d); 303a7a91e65SRobert Watson 304a7a91e65SRobert Watson switch (d->bd_bufmode) { 305a7a91e65SRobert Watson case BPF_BUFMODE_ZBUF: 306a7a91e65SRobert Watson return (bpf_zerocopy_canwritebuf(d)); 307a7a91e65SRobert Watson } 308a7a91e65SRobert Watson return (1); 309a7a91e65SRobert Watson } 310a7a91e65SRobert Watson 311a7a91e65SRobert Watson /* 312a7a91e65SRobert Watson * Notify buffer model that an attempt to write to the store buffer has 313a7a91e65SRobert Watson * resulted in a dropped packet, in which case the buffer may be considered 314a7a91e65SRobert Watson * full. 315a7a91e65SRobert Watson */ 316a7a91e65SRobert Watson static void 317a7a91e65SRobert Watson bpf_buffull(struct bpf_d *d) 318a7a91e65SRobert Watson { 319a7a91e65SRobert Watson 320e4b3229aSAlexander V. Chernikov BPFD_WLOCK_ASSERT(d); 321a7a91e65SRobert Watson 322a7a91e65SRobert Watson switch (d->bd_bufmode) { 323a7a91e65SRobert Watson case BPF_BUFMODE_ZBUF: 324a7a91e65SRobert Watson bpf_zerocopy_buffull(d); 325a7a91e65SRobert Watson break; 326a7a91e65SRobert Watson } 327a7a91e65SRobert Watson } 328a7a91e65SRobert Watson 329a7a91e65SRobert Watson /* 330a7a91e65SRobert Watson * Notify the buffer model that a buffer has moved into the hold position. 331a7a91e65SRobert Watson */ 3324d621040SChristian S.J. Peron void 3334d621040SChristian S.J. Peron bpf_bufheld(struct bpf_d *d) 3344d621040SChristian S.J. Peron { 3354d621040SChristian S.J. Peron 336e4b3229aSAlexander V. Chernikov BPFD_WLOCK_ASSERT(d); 3374d621040SChristian S.J. Peron 3384d621040SChristian S.J. Peron switch (d->bd_bufmode) { 3394d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 3404d621040SChristian S.J. Peron bpf_zerocopy_bufheld(d); 3414d621040SChristian S.J. Peron break; 3424d621040SChristian S.J. Peron } 3434d621040SChristian S.J. Peron } 3444d621040SChristian S.J. Peron 3454d621040SChristian S.J. Peron static void 3464d621040SChristian S.J. Peron bpf_free(struct bpf_d *d) 3474d621040SChristian S.J. Peron { 3484d621040SChristian S.J. Peron 3494d621040SChristian S.J. Peron switch (d->bd_bufmode) { 3504d621040SChristian S.J. Peron case BPF_BUFMODE_BUFFER: 3514d621040SChristian S.J. Peron return (bpf_buffer_free(d)); 3524d621040SChristian S.J. Peron 3534d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 3544d621040SChristian S.J. Peron return (bpf_zerocopy_free(d)); 3554d621040SChristian S.J. Peron 3564d621040SChristian S.J. Peron default: 3574d621040SChristian S.J. Peron panic("bpf_buf_free"); 3584d621040SChristian S.J. Peron } 3594d621040SChristian S.J. Peron } 3604d621040SChristian S.J. Peron 3614d621040SChristian S.J. Peron static int 3624d621040SChristian S.J. Peron bpf_uiomove(struct bpf_d *d, caddr_t buf, u_int len, struct uio *uio) 3634d621040SChristian S.J. Peron { 3644d621040SChristian S.J. Peron 3654d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_BUFFER) 3664d621040SChristian S.J. Peron return (EOPNOTSUPP); 3674d621040SChristian S.J. Peron return (bpf_buffer_uiomove(d, buf, len, uio)); 3684d621040SChristian S.J. Peron } 3694d621040SChristian S.J. Peron 3704d621040SChristian S.J. Peron static int 3714d621040SChristian S.J. Peron bpf_ioctl_sblen(struct bpf_d *d, u_int *i) 3724d621040SChristian S.J. Peron { 3734d621040SChristian S.J. Peron 3744d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_BUFFER) 3754d621040SChristian S.J. Peron return (EOPNOTSUPP); 3764d621040SChristian S.J. Peron return (bpf_buffer_ioctl_sblen(d, i)); 3774d621040SChristian S.J. Peron } 3784d621040SChristian S.J. Peron 3794d621040SChristian S.J. Peron static int 3804d621040SChristian S.J. Peron bpf_ioctl_getzmax(struct thread *td, struct bpf_d *d, size_t *i) 3814d621040SChristian S.J. Peron { 3824d621040SChristian S.J. Peron 3834d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_ZBUF) 3844d621040SChristian S.J. Peron return (EOPNOTSUPP); 3854d621040SChristian S.J. Peron return (bpf_zerocopy_ioctl_getzmax(td, d, i)); 3864d621040SChristian S.J. Peron } 3874d621040SChristian S.J. Peron 3884d621040SChristian S.J. Peron static int 3894d621040SChristian S.J. Peron bpf_ioctl_rotzbuf(struct thread *td, struct bpf_d *d, struct bpf_zbuf *bz) 3904d621040SChristian S.J. Peron { 3914d621040SChristian S.J. Peron 3924d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_ZBUF) 3934d621040SChristian S.J. Peron return (EOPNOTSUPP); 3944d621040SChristian S.J. Peron return (bpf_zerocopy_ioctl_rotzbuf(td, d, bz)); 3954d621040SChristian S.J. Peron } 3964d621040SChristian S.J. Peron 3974d621040SChristian S.J. Peron static int 3984d621040SChristian S.J. Peron bpf_ioctl_setzbuf(struct thread *td, struct bpf_d *d, struct bpf_zbuf *bz) 3994d621040SChristian S.J. Peron { 4004d621040SChristian S.J. Peron 4014d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_ZBUF) 4024d621040SChristian S.J. Peron return (EOPNOTSUPP); 4034d621040SChristian S.J. Peron return (bpf_zerocopy_ioctl_setzbuf(td, d, bz)); 4044d621040SChristian S.J. Peron } 4054d621040SChristian S.J. Peron 4064d621040SChristian S.J. Peron /* 4074d621040SChristian S.J. Peron * General BPF functions. 4084d621040SChristian S.J. Peron */ 409df8bae1dSRodney W. Grimes static int 410cb44b6dfSAndrew Thompson bpf_movein(struct uio *uio, int linktype, struct ifnet *ifp, struct mbuf **mp, 411560a54e1SJung-uk Kim struct sockaddr *sockp, int *hdrlen, struct bpf_insn *wfilter) 412df8bae1dSRodney W. Grimes { 413246b5467SSam Leffler const struct ieee80211_bpf_params *p; 414cb44b6dfSAndrew Thompson struct ether_header *eh; 415df8bae1dSRodney W. Grimes struct mbuf *m; 416df8bae1dSRodney W. Grimes int error; 417df8bae1dSRodney W. Grimes int len; 418df8bae1dSRodney W. Grimes int hlen; 41993e39f0bSChristian S.J. Peron int slen; 420df8bae1dSRodney W. Grimes 421df8bae1dSRodney W. Grimes /* 422df8bae1dSRodney W. Grimes * Build a sockaddr based on the data link layer type. 423df8bae1dSRodney W. Grimes * We do this at this level because the ethernet header 424df8bae1dSRodney W. Grimes * is copied directly into the data field of the sockaddr. 425df8bae1dSRodney W. Grimes * In the case of SLIP, there is no header and the packet 426df8bae1dSRodney W. Grimes * is forwarded as is. 427df8bae1dSRodney W. Grimes * Also, we are careful to leave room at the front of the mbuf 428df8bae1dSRodney W. Grimes * for the link level header. 429df8bae1dSRodney W. Grimes */ 430df8bae1dSRodney W. Grimes switch (linktype) { 431df8bae1dSRodney W. Grimes 432df8bae1dSRodney W. Grimes case DLT_SLIP: 433df8bae1dSRodney W. Grimes sockp->sa_family = AF_INET; 434df8bae1dSRodney W. Grimes hlen = 0; 435df8bae1dSRodney W. Grimes break; 436df8bae1dSRodney W. Grimes 437df8bae1dSRodney W. Grimes case DLT_EN10MB: 438df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 439df8bae1dSRodney W. Grimes /* XXX Would MAXLINKHDR be better? */ 440797f247bSMatthew N. Dodd hlen = ETHER_HDR_LEN; 441df8bae1dSRodney W. Grimes break; 442df8bae1dSRodney W. Grimes 443df8bae1dSRodney W. Grimes case DLT_FDDI: 444d41f24e7SDavid Greenman sockp->sa_family = AF_IMPLINK; 445d41f24e7SDavid Greenman hlen = 0; 446df8bae1dSRodney W. Grimes break; 447df8bae1dSRodney W. Grimes 44822f05c43SAndrey A. Chernov case DLT_RAW: 449df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 450df8bae1dSRodney W. Grimes hlen = 0; 451df8bae1dSRodney W. Grimes break; 452df8bae1dSRodney W. Grimes 45301399f34SDavid Malone case DLT_NULL: 45401399f34SDavid Malone /* 45501399f34SDavid Malone * null interface types require a 4 byte pseudo header which 45601399f34SDavid Malone * corresponds to the address family of the packet. 45701399f34SDavid Malone */ 45801399f34SDavid Malone sockp->sa_family = AF_UNSPEC; 45901399f34SDavid Malone hlen = 4; 46001399f34SDavid Malone break; 46101399f34SDavid Malone 4624f53e3ccSKenjiro Cho case DLT_ATM_RFC1483: 4634f53e3ccSKenjiro Cho /* 4644f53e3ccSKenjiro Cho * en atm driver requires 4-byte atm pseudo header. 4654f53e3ccSKenjiro Cho * though it isn't standard, vpi:vci needs to be 4664f53e3ccSKenjiro Cho * specified anyway. 4674f53e3ccSKenjiro Cho */ 4684f53e3ccSKenjiro Cho sockp->sa_family = AF_UNSPEC; 4694f53e3ccSKenjiro Cho hlen = 12; /* XXX 4(ATM_PH) + 3(LLC) + 5(SNAP) */ 4704f53e3ccSKenjiro Cho break; 4714f53e3ccSKenjiro Cho 47230fa52a6SBrian Somers case DLT_PPP: 47330fa52a6SBrian Somers sockp->sa_family = AF_UNSPEC; 47430fa52a6SBrian Somers hlen = 4; /* This should match PPP_HDRLEN */ 47530fa52a6SBrian Somers break; 47630fa52a6SBrian Somers 477246b5467SSam Leffler case DLT_IEEE802_11: /* IEEE 802.11 wireless */ 478246b5467SSam Leffler sockp->sa_family = AF_IEEE80211; 479246b5467SSam Leffler hlen = 0; 480246b5467SSam Leffler break; 481246b5467SSam Leffler 482246b5467SSam Leffler case DLT_IEEE802_11_RADIO: /* IEEE 802.11 wireless w/ phy params */ 483246b5467SSam Leffler sockp->sa_family = AF_IEEE80211; 484246b5467SSam Leffler sockp->sa_len = 12; /* XXX != 0 */ 485246b5467SSam Leffler hlen = sizeof(struct ieee80211_bpf_params); 486246b5467SSam Leffler break; 487246b5467SSam Leffler 488df8bae1dSRodney W. Grimes default: 489df8bae1dSRodney W. Grimes return (EIO); 490df8bae1dSRodney W. Grimes } 491df8bae1dSRodney W. Grimes 492df8bae1dSRodney W. Grimes len = uio->uio_resid; 49301399f34SDavid Malone 494cb44b6dfSAndrew Thompson if (len - hlen > ifp->if_mtu) 49501399f34SDavid Malone return (EMSGSIZE); 49601399f34SDavid Malone 497968c88bcSJung-uk Kim if ((unsigned)len > MJUM16BYTES) 498df8bae1dSRodney W. Grimes return (EIO); 499df8bae1dSRodney W. Grimes 500968c88bcSJung-uk Kim if (len <= MHLEN) 501968c88bcSJung-uk Kim MGETHDR(m, M_WAIT, MT_DATA); 502968c88bcSJung-uk Kim else if (len <= MCLBYTES) 503ea26d587SRuslan Ermilov m = m_getcl(M_WAIT, MT_DATA, M_PKTHDR); 504ea26d587SRuslan Ermilov else 505968c88bcSJung-uk Kim m = m_getjcl(M_WAIT, MT_DATA, M_PKTHDR, 506968c88bcSJung-uk Kim #if (MJUMPAGESIZE > MCLBYTES) 507968c88bcSJung-uk Kim len <= MJUMPAGESIZE ? MJUMPAGESIZE : 508968c88bcSJung-uk Kim #endif 509968c88bcSJung-uk Kim (len <= MJUM9BYTES ? MJUM9BYTES : MJUM16BYTES)); 510963e4c2aSGarrett Wollman m->m_pkthdr.len = m->m_len = len; 511963e4c2aSGarrett Wollman m->m_pkthdr.rcvif = NULL; 512df8bae1dSRodney W. Grimes *mp = m; 51324a229f4SSam Leffler 51493e39f0bSChristian S.J. Peron if (m->m_len < hlen) { 51593e39f0bSChristian S.J. Peron error = EPERM; 51693e39f0bSChristian S.J. Peron goto bad; 51793e39f0bSChristian S.J. Peron } 51893e39f0bSChristian S.J. Peron 51993e39f0bSChristian S.J. Peron error = uiomove(mtod(m, u_char *), len, uio); 52093e39f0bSChristian S.J. Peron if (error) 52193e39f0bSChristian S.J. Peron goto bad; 52293e39f0bSChristian S.J. Peron 52393e39f0bSChristian S.J. Peron slen = bpf_filter(wfilter, mtod(m, u_char *), len, len); 52493e39f0bSChristian S.J. Peron if (slen == 0) { 52593e39f0bSChristian S.J. Peron error = EPERM; 52693e39f0bSChristian S.J. Peron goto bad; 52793e39f0bSChristian S.J. Peron } 52893e39f0bSChristian S.J. Peron 529cb44b6dfSAndrew Thompson /* Check for multicast destination */ 530cb44b6dfSAndrew Thompson switch (linktype) { 531cb44b6dfSAndrew Thompson case DLT_EN10MB: 532cb44b6dfSAndrew Thompson eh = mtod(m, struct ether_header *); 533cb44b6dfSAndrew Thompson if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 534cb44b6dfSAndrew Thompson if (bcmp(ifp->if_broadcastaddr, eh->ether_dhost, 535cb44b6dfSAndrew Thompson ETHER_ADDR_LEN) == 0) 536cb44b6dfSAndrew Thompson m->m_flags |= M_BCAST; 537cb44b6dfSAndrew Thompson else 538cb44b6dfSAndrew Thompson m->m_flags |= M_MCAST; 539cb44b6dfSAndrew Thompson } 540cb44b6dfSAndrew Thompson break; 541cb44b6dfSAndrew Thompson } 542cb44b6dfSAndrew Thompson 543df8bae1dSRodney W. Grimes /* 54493e39f0bSChristian S.J. Peron * Make room for link header, and copy it to sockaddr 545df8bae1dSRodney W. Grimes */ 546df8bae1dSRodney W. Grimes if (hlen != 0) { 547246b5467SSam Leffler if (sockp->sa_family == AF_IEEE80211) { 548246b5467SSam Leffler /* 549246b5467SSam Leffler * Collect true length from the parameter header 550246b5467SSam Leffler * NB: sockp is known to be zero'd so if we do a 551246b5467SSam Leffler * short copy unspecified parameters will be 552246b5467SSam Leffler * zero. 553246b5467SSam Leffler * NB: packet may not be aligned after stripping 554246b5467SSam Leffler * bpf params 555246b5467SSam Leffler * XXX check ibp_vers 556246b5467SSam Leffler */ 557246b5467SSam Leffler p = mtod(m, const struct ieee80211_bpf_params *); 558246b5467SSam Leffler hlen = p->ibp_len; 559246b5467SSam Leffler if (hlen > sizeof(sockp->sa_data)) { 560246b5467SSam Leffler error = EINVAL; 561246b5467SSam Leffler goto bad; 562246b5467SSam Leffler } 563246b5467SSam Leffler } 56493e39f0bSChristian S.J. Peron bcopy(m->m_data, sockp->sa_data, hlen); 565df8bae1dSRodney W. Grimes } 566560a54e1SJung-uk Kim *hdrlen = hlen; 56793e39f0bSChristian S.J. Peron 568df8bae1dSRodney W. Grimes return (0); 569df8bae1dSRodney W. Grimes bad: 570df8bae1dSRodney W. Grimes m_freem(m); 571df8bae1dSRodney W. Grimes return (error); 572df8bae1dSRodney W. Grimes } 573df8bae1dSRodney W. Grimes 574df8bae1dSRodney W. Grimes /* 575df8bae1dSRodney W. Grimes * Attach file to the bpf interface, i.e. make d listen on bp. 576df8bae1dSRodney W. Grimes */ 577df8bae1dSRodney W. Grimes static void 57819ba8395SChristian S.J. Peron bpf_attachd(struct bpf_d *d, struct bpf_if *bp) 579df8bae1dSRodney W. Grimes { 580df8bae1dSRodney W. Grimes /* 581*51ec1eb7SAlexander V. Chernikov * Point d at bp, and add d to the interface's list. 582*51ec1eb7SAlexander V. Chernikov * Since there are many applicaiotns using BPF for 583*51ec1eb7SAlexander V. Chernikov * sending raw packets only (dhcpd, cdpd are good examples) 584*51ec1eb7SAlexander V. Chernikov * we can delay adding d to the list of active listeners until 585*51ec1eb7SAlexander V. Chernikov * some filter is configured. 586df8bae1dSRodney W. Grimes */ 587df8bae1dSRodney W. Grimes d->bd_bif = bp; 588*51ec1eb7SAlexander V. Chernikov 589*51ec1eb7SAlexander V. Chernikov BPFIF_WLOCK(bp); 590*51ec1eb7SAlexander V. Chernikov 591*51ec1eb7SAlexander V. Chernikov if (V_bpf_optimize_writers != 0) { 592*51ec1eb7SAlexander V. Chernikov /* Add to writers-only list */ 593*51ec1eb7SAlexander V. Chernikov LIST_INSERT_HEAD(&bp->bif_wlist, d, bd_next); 594*51ec1eb7SAlexander V. Chernikov /* 595*51ec1eb7SAlexander V. Chernikov * We decrement bd_writer on every filter set operation. 596*51ec1eb7SAlexander V. Chernikov * First BIOCSETF is done by pcap_open_live() to set up 597*51ec1eb7SAlexander V. Chernikov * snap length. After that appliation usually sets its own filter 598*51ec1eb7SAlexander V. Chernikov */ 599*51ec1eb7SAlexander V. Chernikov d->bd_writer = 2; 600*51ec1eb7SAlexander V. Chernikov } else 6014a3feeaaSRobert Watson LIST_INSERT_HEAD(&bp->bif_dlist, d, bd_next); 602df8bae1dSRodney W. Grimes 603e4b3229aSAlexander V. Chernikov BPFIF_WUNLOCK(bp); 604b743c310SSam Leffler 605*51ec1eb7SAlexander V. Chernikov BPF_LOCK(); 606*51ec1eb7SAlexander V. Chernikov bpf_bpfd_cnt++; 607*51ec1eb7SAlexander V. Chernikov BPF_UNLOCK(); 608*51ec1eb7SAlexander V. Chernikov 609*51ec1eb7SAlexander V. Chernikov CTR3(KTR_NET, "%s: bpf_attach called by pid %d, adding to %s list", 610*51ec1eb7SAlexander V. Chernikov __func__, d->bd_pid, d->bd_writer ? "writer" : "active"); 611*51ec1eb7SAlexander V. Chernikov 612*51ec1eb7SAlexander V. Chernikov if (V_bpf_optimize_writers == 0) 613*51ec1eb7SAlexander V. Chernikov EVENTHANDLER_INVOKE(bpf_track, bp->bif_ifp, bp->bif_dlt, 1); 614*51ec1eb7SAlexander V. Chernikov } 615*51ec1eb7SAlexander V. Chernikov 616*51ec1eb7SAlexander V. Chernikov /* 617*51ec1eb7SAlexander V. Chernikov * Add d to the list of active bp filters. 618*51ec1eb7SAlexander V. Chernikov * Reuqires bpf_attachd() to be called before 619*51ec1eb7SAlexander V. Chernikov */ 620*51ec1eb7SAlexander V. Chernikov static void 621*51ec1eb7SAlexander V. Chernikov bpf_upgraded(struct bpf_d *d) 622*51ec1eb7SAlexander V. Chernikov { 623*51ec1eb7SAlexander V. Chernikov struct bpf_if *bp; 624*51ec1eb7SAlexander V. Chernikov 625*51ec1eb7SAlexander V. Chernikov bp = d->bd_bif; 626*51ec1eb7SAlexander V. Chernikov 627*51ec1eb7SAlexander V. Chernikov BPFIF_WLOCK(bp); 628*51ec1eb7SAlexander V. Chernikov BPFD_WLOCK(d); 629*51ec1eb7SAlexander V. Chernikov 630*51ec1eb7SAlexander V. Chernikov /* Remove from writers-only list */ 631*51ec1eb7SAlexander V. Chernikov LIST_REMOVE(d, bd_next); 632*51ec1eb7SAlexander V. Chernikov LIST_INSERT_HEAD(&bp->bif_dlist, d, bd_next); 633*51ec1eb7SAlexander V. Chernikov /* Mark d as reader */ 634*51ec1eb7SAlexander V. Chernikov d->bd_writer = 0; 635*51ec1eb7SAlexander V. Chernikov 636*51ec1eb7SAlexander V. Chernikov BPFD_WUNLOCK(d); 637*51ec1eb7SAlexander V. Chernikov BPFIF_WUNLOCK(bp); 638*51ec1eb7SAlexander V. Chernikov 639*51ec1eb7SAlexander V. Chernikov CTR2(KTR_NET, "%s: upgrade required by pid %d", __func__, d->bd_pid); 640*51ec1eb7SAlexander V. Chernikov 6415ce8d970SSam Leffler EVENTHANDLER_INVOKE(bpf_track, bp->bif_ifp, bp->bif_dlt, 1); 642df8bae1dSRodney W. Grimes } 643df8bae1dSRodney W. Grimes 644df8bae1dSRodney W. Grimes /* 645df8bae1dSRodney W. Grimes * Detach a file from its interface. 646df8bae1dSRodney W. Grimes */ 647df8bae1dSRodney W. Grimes static void 64819ba8395SChristian S.J. Peron bpf_detachd(struct bpf_d *d) 649df8bae1dSRodney W. Grimes { 6506e891d64SPoul-Henning Kamp int error; 651df8bae1dSRodney W. Grimes struct bpf_if *bp; 65246448b5aSRobert Watson struct ifnet *ifp; 653df8bae1dSRodney W. Grimes 654*51ec1eb7SAlexander V. Chernikov CTR2(KTR_NET, "%s: detach required by pid %d", __func__, d->bd_pid); 655*51ec1eb7SAlexander V. Chernikov 656e4b3229aSAlexander V. Chernikov BPF_LOCK_ASSERT(); 657e4b3229aSAlexander V. Chernikov 658df8bae1dSRodney W. Grimes bp = d->bd_bif; 659e4b3229aSAlexander V. Chernikov BPFIF_WLOCK(bp); 660e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 66146448b5aSRobert Watson 662*51ec1eb7SAlexander V. Chernikov /* Save bd_writer value */ 663*51ec1eb7SAlexander V. Chernikov error = d->bd_writer; 664*51ec1eb7SAlexander V. Chernikov 66546448b5aSRobert Watson /* 66646448b5aSRobert Watson * Remove d from the interface's descriptor list. 66746448b5aSRobert Watson */ 66846448b5aSRobert Watson LIST_REMOVE(d, bd_next); 66946448b5aSRobert Watson 670e4b3229aSAlexander V. Chernikov ifp = bp->bif_ifp; 671572bde2aSRobert Watson d->bd_bif = NULL; 672e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 673e4b3229aSAlexander V. Chernikov BPFIF_WUNLOCK(bp); 674e4b3229aSAlexander V. Chernikov 675e4b3229aSAlexander V. Chernikov /* We're already protected by global lock. */ 676e4b3229aSAlexander V. Chernikov bpf_bpfd_cnt--; 67746448b5aSRobert Watson 678*51ec1eb7SAlexander V. Chernikov /* Call event handler iff d is attached */ 679*51ec1eb7SAlexander V. Chernikov if (error == 0) 6805ce8d970SSam Leffler EVENTHANDLER_INVOKE(bpf_track, ifp, bp->bif_dlt, 0); 681b743c310SSam Leffler 682df8bae1dSRodney W. Grimes /* 683df8bae1dSRodney W. Grimes * Check if this descriptor had requested promiscuous mode. 684df8bae1dSRodney W. Grimes * If so, turn it off. 685df8bae1dSRodney W. Grimes */ 686df8bae1dSRodney W. Grimes if (d->bd_promisc) { 687df8bae1dSRodney W. Grimes d->bd_promisc = 0; 68897021c24SMarko Zec CURVNET_SET(ifp->if_vnet); 68946448b5aSRobert Watson error = ifpromisc(ifp, 0); 69097021c24SMarko Zec CURVNET_RESTORE(); 6916e891d64SPoul-Henning Kamp if (error != 0 && error != ENXIO) { 692df8bae1dSRodney W. Grimes /* 6936e891d64SPoul-Henning Kamp * ENXIO can happen if a pccard is unplugged 694df8bae1dSRodney W. Grimes * Something is really wrong if we were able to put 695df8bae1dSRodney W. Grimes * the driver into promiscuous mode, but can't 696df8bae1dSRodney W. Grimes * take it out. 697df8bae1dSRodney W. Grimes */ 6988eab61f3SSam Leffler if_printf(bp->bif_ifp, 6998eab61f3SSam Leffler "bpf_detach: ifpromisc failed (%d)\n", error); 7006e891d64SPoul-Henning Kamp } 701df8bae1dSRodney W. Grimes } 702df8bae1dSRodney W. Grimes } 703df8bae1dSRodney W. Grimes 704df8bae1dSRodney W. Grimes /* 705136600feSEd Schouten * Close the descriptor by detaching it from its interface, 706136600feSEd Schouten * deallocating its buffers, and marking it free. 707136600feSEd Schouten */ 708136600feSEd Schouten static void 709136600feSEd Schouten bpf_dtor(void *data) 710136600feSEd Schouten { 711136600feSEd Schouten struct bpf_d *d = data; 712136600feSEd Schouten 713e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 714136600feSEd Schouten if (d->bd_state == BPF_WAITING) 715136600feSEd Schouten callout_stop(&d->bd_callout); 716136600feSEd Schouten d->bd_state = BPF_IDLE; 717e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 718136600feSEd Schouten funsetown(&d->bd_sigio); 719e4b3229aSAlexander V. Chernikov BPF_LOCK(); 720136600feSEd Schouten if (d->bd_bif) 721136600feSEd Schouten bpf_detachd(d); 722e4b3229aSAlexander V. Chernikov BPF_UNLOCK(); 723136600feSEd Schouten #ifdef MAC 724136600feSEd Schouten mac_bpfdesc_destroy(d); 725136600feSEd Schouten #endif /* MAC */ 7266aba400aSAttilio Rao seldrain(&d->bd_sel); 727136600feSEd Schouten knlist_destroy(&d->bd_sel.si_note); 7289fee1bd1SJung-uk Kim callout_drain(&d->bd_callout); 729136600feSEd Schouten bpf_freed(d); 730136600feSEd Schouten free(d, M_BPF); 731136600feSEd Schouten } 732136600feSEd Schouten 733136600feSEd Schouten /* 734df8bae1dSRodney W. Grimes * Open ethernet device. Returns ENXIO for illegal minor device number, 735df8bae1dSRodney W. Grimes * EBUSY if file is open by another process. 736df8bae1dSRodney W. Grimes */ 737df8bae1dSRodney W. Grimes /* ARGSUSED */ 73887f6c662SJulian Elischer static int 73919ba8395SChristian S.J. Peron bpfopen(struct cdev *dev, int flags, int fmt, struct thread *td) 740df8bae1dSRodney W. Grimes { 741e7bb21b3SJonathan Lemon struct bpf_d *d; 742136600feSEd Schouten int error; 743df8bae1dSRodney W. Grimes 7441ede983cSDag-Erling Smørgrav d = malloc(sizeof(*d), M_BPF, M_WAITOK | M_ZERO); 745136600feSEd Schouten error = devfs_set_cdevpriv(d, bpf_dtor); 746136600feSEd Schouten if (error != 0) { 747136600feSEd Schouten free(d, M_BPF); 748136600feSEd Schouten return (error); 749136600feSEd Schouten } 7504d621040SChristian S.J. Peron 7514d621040SChristian S.J. Peron /* 7524d621040SChristian S.J. Peron * For historical reasons, perform a one-time initialization call to 7534d621040SChristian S.J. Peron * the buffer routines, even though we're not yet committed to a 7544d621040SChristian S.J. Peron * particular buffer method. 7554d621040SChristian S.J. Peron */ 7564d621040SChristian S.J. Peron bpf_buffer_init(d); 7574d621040SChristian S.J. Peron d->bd_bufmode = BPF_BUFMODE_BUFFER; 75800a83887SPaul Traina d->bd_sig = SIGIO; 759560a54e1SJung-uk Kim d->bd_direction = BPF_D_INOUT; 760e4b3229aSAlexander V. Chernikov BPF_PID_REFRESH(d, td); 76182f4445dSRobert Watson #ifdef MAC 76230d239bcSRobert Watson mac_bpfdesc_init(d); 76330d239bcSRobert Watson mac_bpfdesc_create(td->td_ucred, d); 76482f4445dSRobert Watson #endif 765e4b3229aSAlexander V. Chernikov rw_init(&d->bd_lock, "bpf cdev lock"); 766e4b3229aSAlexander V. Chernikov callout_init_rw(&d->bd_callout, &d->bd_lock, 0); 767e4b3229aSAlexander V. Chernikov knlist_init_rw_reader(&d->bd_sel.si_note, &d->bd_lock); 768df8bae1dSRodney W. Grimes 769df8bae1dSRodney W. Grimes return (0); 770df8bae1dSRodney W. Grimes } 771df8bae1dSRodney W. Grimes 772df8bae1dSRodney W. Grimes /* 773df8bae1dSRodney W. Grimes * bpfread - read next chunk of packets from buffers 774df8bae1dSRodney W. Grimes */ 77587f6c662SJulian Elischer static int 77619ba8395SChristian S.J. Peron bpfread(struct cdev *dev, struct uio *uio, int ioflag) 777df8bae1dSRodney W. Grimes { 778136600feSEd Schouten struct bpf_d *d; 779df8bae1dSRodney W. Grimes int error; 7808df67d77SJung-uk Kim int non_block; 7818df67d77SJung-uk Kim int timed_out; 782df8bae1dSRodney W. Grimes 783136600feSEd Schouten error = devfs_get_cdevpriv((void **)&d); 784136600feSEd Schouten if (error != 0) 785136600feSEd Schouten return (error); 786136600feSEd Schouten 787df8bae1dSRodney W. Grimes /* 788df8bae1dSRodney W. Grimes * Restrict application to use a buffer the same size as 789df8bae1dSRodney W. Grimes * as kernel buffers. 790df8bae1dSRodney W. Grimes */ 791df8bae1dSRodney W. Grimes if (uio->uio_resid != d->bd_bufsize) 792df8bae1dSRodney W. Grimes return (EINVAL); 793df8bae1dSRodney W. Grimes 7948df67d77SJung-uk Kim non_block = ((ioflag & O_NONBLOCK) != 0); 7958df67d77SJung-uk Kim 796e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 797e4b3229aSAlexander V. Chernikov BPF_PID_REFRESH_CUR(d); 7984d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_BUFFER) { 799e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 8004d621040SChristian S.J. Peron return (EOPNOTSUPP); 8014d621040SChristian S.J. Peron } 80281bda851SJohn Polstra if (d->bd_state == BPF_WAITING) 80381bda851SJohn Polstra callout_stop(&d->bd_callout); 80481bda851SJohn Polstra timed_out = (d->bd_state == BPF_TIMED_OUT); 80581bda851SJohn Polstra d->bd_state = BPF_IDLE; 806df8bae1dSRodney W. Grimes /* 807df8bae1dSRodney W. Grimes * If the hold buffer is empty, then do a timed sleep, which 808df8bae1dSRodney W. Grimes * ends when the timeout expires or when enough packets 809df8bae1dSRodney W. Grimes * have arrived to fill the store buffer. 810df8bae1dSRodney W. Grimes */ 811572bde2aSRobert Watson while (d->bd_hbuf == NULL) { 8128df67d77SJung-uk Kim if (d->bd_slen != 0) { 813df8bae1dSRodney W. Grimes /* 814df8bae1dSRodney W. Grimes * A packet(s) either arrived since the previous 815df8bae1dSRodney W. Grimes * read or arrived while we were asleep. 8168df67d77SJung-uk Kim */ 8178df67d77SJung-uk Kim if (d->bd_immediate || non_block || timed_out) { 8188df67d77SJung-uk Kim /* 8198df67d77SJung-uk Kim * Rotate the buffers and return what's here 8208df67d77SJung-uk Kim * if we are in immediate mode, non-blocking 8218df67d77SJung-uk Kim * flag is set, or this descriptor timed out. 822df8bae1dSRodney W. Grimes */ 823df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 824df8bae1dSRodney W. Grimes break; 825df8bae1dSRodney W. Grimes } 8268df67d77SJung-uk Kim } 827de5d9935SRobert Watson 828de5d9935SRobert Watson /* 829de5d9935SRobert Watson * No data is available, check to see if the bpf device 830de5d9935SRobert Watson * is still pointed at a real interface. If not, return 831de5d9935SRobert Watson * ENXIO so that the userland process knows to rebind 832de5d9935SRobert Watson * it before using it again. 833de5d9935SRobert Watson */ 834de5d9935SRobert Watson if (d->bd_bif == NULL) { 835e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 836de5d9935SRobert Watson return (ENXIO); 837de5d9935SRobert Watson } 838de5d9935SRobert Watson 8398df67d77SJung-uk Kim if (non_block) { 840e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 841fba3cfdeSJohn Polstra return (EWOULDBLOCK); 842fba3cfdeSJohn Polstra } 843e4b3229aSAlexander V. Chernikov error = rw_sleep(d, &d->bd_lock, PRINET|PCATCH, 844e7bb21b3SJonathan Lemon "bpf", d->bd_rtout); 845df8bae1dSRodney W. Grimes if (error == EINTR || error == ERESTART) { 846e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 847df8bae1dSRodney W. Grimes return (error); 848df8bae1dSRodney W. Grimes } 849df8bae1dSRodney W. Grimes if (error == EWOULDBLOCK) { 850df8bae1dSRodney W. Grimes /* 851df8bae1dSRodney W. Grimes * On a timeout, return what's in the buffer, 852df8bae1dSRodney W. Grimes * which may be nothing. If there is something 853df8bae1dSRodney W. Grimes * in the store buffer, we can rotate the buffers. 854df8bae1dSRodney W. Grimes */ 855df8bae1dSRodney W. Grimes if (d->bd_hbuf) 856df8bae1dSRodney W. Grimes /* 857df8bae1dSRodney W. Grimes * We filled up the buffer in between 858df8bae1dSRodney W. Grimes * getting the timeout and arriving 859df8bae1dSRodney W. Grimes * here, so we don't need to rotate. 860df8bae1dSRodney W. Grimes */ 861df8bae1dSRodney W. Grimes break; 862df8bae1dSRodney W. Grimes 863df8bae1dSRodney W. Grimes if (d->bd_slen == 0) { 864e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 865df8bae1dSRodney W. Grimes return (0); 866df8bae1dSRodney W. Grimes } 867df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 868df8bae1dSRodney W. Grimes break; 869df8bae1dSRodney W. Grimes } 870df8bae1dSRodney W. Grimes } 871df8bae1dSRodney W. Grimes /* 872df8bae1dSRodney W. Grimes * At this point, we know we have something in the hold slot. 873df8bae1dSRodney W. Grimes */ 874e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 875df8bae1dSRodney W. Grimes 876df8bae1dSRodney W. Grimes /* 877df8bae1dSRodney W. Grimes * Move data from hold buffer into user space. 878df8bae1dSRodney W. Grimes * We know the entire buffer is transferred since 879df8bae1dSRodney W. Grimes * we checked above that the read buffer is bpf_bufsize bytes. 88031b32e6dSRobert Watson * 88131b32e6dSRobert Watson * XXXRW: More synchronization needed here: what if a second thread 88231b32e6dSRobert Watson * issues a read on the same fd at the same time? Don't want this 88331b32e6dSRobert Watson * getting invalidated. 884df8bae1dSRodney W. Grimes */ 8854d621040SChristian S.J. Peron error = bpf_uiomove(d, d->bd_hbuf, d->bd_hlen, uio); 886df8bae1dSRodney W. Grimes 887e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 888df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 889572bde2aSRobert Watson d->bd_hbuf = NULL; 890df8bae1dSRodney W. Grimes d->bd_hlen = 0; 89129f612ecSChristian S.J. Peron bpf_buf_reclaimed(d); 892e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 893df8bae1dSRodney W. Grimes 894df8bae1dSRodney W. Grimes return (error); 895df8bae1dSRodney W. Grimes } 896df8bae1dSRodney W. Grimes 897df8bae1dSRodney W. Grimes /* 898df8bae1dSRodney W. Grimes * If there are processes sleeping on this descriptor, wake them up. 899df8bae1dSRodney W. Grimes */ 900e7bb21b3SJonathan Lemon static __inline void 90119ba8395SChristian S.J. Peron bpf_wakeup(struct bpf_d *d) 902df8bae1dSRodney W. Grimes { 903a3272e3cSChristian S.J. Peron 904e4b3229aSAlexander V. Chernikov BPFD_WLOCK_ASSERT(d); 90581bda851SJohn Polstra if (d->bd_state == BPF_WAITING) { 90681bda851SJohn Polstra callout_stop(&d->bd_callout); 90781bda851SJohn Polstra d->bd_state = BPF_IDLE; 90881bda851SJohn Polstra } 909521f364bSDag-Erling Smørgrav wakeup(d); 910831d27a9SDon Lewis if (d->bd_async && d->bd_sig && d->bd_sigio) 911f1320723SAlfred Perlstein pgsigio(&d->bd_sigio, d->bd_sig, 0); 91200a83887SPaul Traina 913512824f8SSeigo Tanimura selwakeuppri(&d->bd_sel, PRINET); 914ad3b9257SJohn-Mark Gurney KNOTE_LOCKED(&d->bd_sel.si_note, 0); 915df8bae1dSRodney W. Grimes } 916df8bae1dSRodney W. Grimes 91781bda851SJohn Polstra static void 91819ba8395SChristian S.J. Peron bpf_timed_out(void *arg) 91981bda851SJohn Polstra { 92081bda851SJohn Polstra struct bpf_d *d = (struct bpf_d *)arg; 92181bda851SJohn Polstra 922e4b3229aSAlexander V. Chernikov BPFD_WLOCK_ASSERT(d); 9239fee1bd1SJung-uk Kim 9249fee1bd1SJung-uk Kim if (callout_pending(&d->bd_callout) || !callout_active(&d->bd_callout)) 9259fee1bd1SJung-uk Kim return; 92681bda851SJohn Polstra if (d->bd_state == BPF_WAITING) { 92781bda851SJohn Polstra d->bd_state = BPF_TIMED_OUT; 92881bda851SJohn Polstra if (d->bd_slen != 0) 92981bda851SJohn Polstra bpf_wakeup(d); 93081bda851SJohn Polstra } 93181bda851SJohn Polstra } 93281bda851SJohn Polstra 93387f6c662SJulian Elischer static int 9344d621040SChristian S.J. Peron bpf_ready(struct bpf_d *d) 9354d621040SChristian S.J. Peron { 9364d621040SChristian S.J. Peron 937e4b3229aSAlexander V. Chernikov BPFD_WLOCK_ASSERT(d); 9384d621040SChristian S.J. Peron 9394d621040SChristian S.J. Peron if (!bpf_canfreebuf(d) && d->bd_hlen != 0) 9404d621040SChristian S.J. Peron return (1); 9414d621040SChristian S.J. Peron if ((d->bd_immediate || d->bd_state == BPF_TIMED_OUT) && 9424d621040SChristian S.J. Peron d->bd_slen != 0) 9434d621040SChristian S.J. Peron return (1); 9444d621040SChristian S.J. Peron return (0); 9454d621040SChristian S.J. Peron } 9464d621040SChristian S.J. Peron 9474d621040SChristian S.J. Peron static int 94819ba8395SChristian S.J. Peron bpfwrite(struct cdev *dev, struct uio *uio, int ioflag) 949df8bae1dSRodney W. Grimes { 950136600feSEd Schouten struct bpf_d *d; 951df8bae1dSRodney W. Grimes struct ifnet *ifp; 952560a54e1SJung-uk Kim struct mbuf *m, *mc; 9538240bf1eSRobert Watson struct sockaddr dst; 954560a54e1SJung-uk Kim int error, hlen; 955df8bae1dSRodney W. Grimes 956136600feSEd Schouten error = devfs_get_cdevpriv((void **)&d); 957136600feSEd Schouten if (error != 0) 958136600feSEd Schouten return (error); 959136600feSEd Schouten 960e4b3229aSAlexander V. Chernikov BPF_PID_REFRESH_CUR(d); 9614d621040SChristian S.J. Peron d->bd_wcount++; 9624d621040SChristian S.J. Peron if (d->bd_bif == NULL) { 9634d621040SChristian S.J. Peron d->bd_wdcount++; 964df8bae1dSRodney W. Grimes return (ENXIO); 9654d621040SChristian S.J. Peron } 966df8bae1dSRodney W. Grimes 967df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 968df8bae1dSRodney W. Grimes 9694d621040SChristian S.J. Peron if ((ifp->if_flags & IFF_UP) == 0) { 9704d621040SChristian S.J. Peron d->bd_wdcount++; 9713518d220SSam Leffler return (ENETDOWN); 9724d621040SChristian S.J. Peron } 9733518d220SSam Leffler 9744d621040SChristian S.J. Peron if (uio->uio_resid == 0) { 9754d621040SChristian S.J. Peron d->bd_wdcount++; 976df8bae1dSRodney W. Grimes return (0); 9774d621040SChristian S.J. Peron } 978df8bae1dSRodney W. Grimes 9798240bf1eSRobert Watson bzero(&dst, sizeof(dst)); 980d83e603aSChristian S.J. Peron m = NULL; 981d83e603aSChristian S.J. Peron hlen = 0; 982cb44b6dfSAndrew Thompson error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, ifp, 983560a54e1SJung-uk Kim &m, &dst, &hlen, d->bd_wfilter); 9844d621040SChristian S.J. Peron if (error) { 9854d621040SChristian S.J. Peron d->bd_wdcount++; 986df8bae1dSRodney W. Grimes return (error); 9874d621040SChristian S.J. Peron } 9884d621040SChristian S.J. Peron d->bd_wfcount++; 989114ae644SMike Smith if (d->bd_hdrcmplt) 990114ae644SMike Smith dst.sa_family = pseudo_AF_HDRCMPLT; 991114ae644SMike Smith 992560a54e1SJung-uk Kim if (d->bd_feedback) { 993560a54e1SJung-uk Kim mc = m_dup(m, M_DONTWAIT); 994560a54e1SJung-uk Kim if (mc != NULL) 995560a54e1SJung-uk Kim mc->m_pkthdr.rcvif = ifp; 9968cd892f7SJung-uk Kim /* Set M_PROMISC for outgoing packets to be discarded. */ 9978cd892f7SJung-uk Kim if (d->bd_direction == BPF_D_INOUT) 9988cd892f7SJung-uk Kim m->m_flags |= M_PROMISC; 999560a54e1SJung-uk Kim } else 1000560a54e1SJung-uk Kim mc = NULL; 1001560a54e1SJung-uk Kim 1002560a54e1SJung-uk Kim m->m_pkthdr.len -= hlen; 1003560a54e1SJung-uk Kim m->m_len -= hlen; 1004560a54e1SJung-uk Kim m->m_data += hlen; /* XXX */ 1005560a54e1SJung-uk Kim 100621ca7b57SMarko Zec CURVNET_SET(ifp->if_vnet); 100782f4445dSRobert Watson #ifdef MAC 1008e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 100930d239bcSRobert Watson mac_bpfdesc_create_mbuf(d, m); 1010560a54e1SJung-uk Kim if (mc != NULL) 101130d239bcSRobert Watson mac_bpfdesc_create_mbuf(d, mc); 1012e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 101382f4445dSRobert Watson #endif 1014560a54e1SJung-uk Kim 1015572bde2aSRobert Watson error = (*ifp->if_output)(ifp, m, &dst, NULL); 10164d621040SChristian S.J. Peron if (error) 10174d621040SChristian S.J. Peron d->bd_wdcount++; 1018560a54e1SJung-uk Kim 1019560a54e1SJung-uk Kim if (mc != NULL) { 10200bf686c1SRobert Watson if (error == 0) 1021560a54e1SJung-uk Kim (*ifp->if_input)(ifp, mc); 10220bf686c1SRobert Watson else 1023560a54e1SJung-uk Kim m_freem(mc); 1024560a54e1SJung-uk Kim } 102521ca7b57SMarko Zec CURVNET_RESTORE(); 1026560a54e1SJung-uk Kim 1027df8bae1dSRodney W. Grimes return (error); 1028df8bae1dSRodney W. Grimes } 1029df8bae1dSRodney W. Grimes 1030df8bae1dSRodney W. Grimes /* 1031e82669d9SRobert Watson * Reset a descriptor by flushing its packet buffer and clearing the receive 1032e82669d9SRobert Watson * and drop counts. This is doable for kernel-only buffers, but with 1033e82669d9SRobert Watson * zero-copy buffers, we can't write to (or rotate) buffers that are 1034e82669d9SRobert Watson * currently owned by userspace. It would be nice if we could encapsulate 1035e82669d9SRobert Watson * this logic in the buffer code rather than here. 1036df8bae1dSRodney W. Grimes */ 1037df8bae1dSRodney W. Grimes static void 103819ba8395SChristian S.J. Peron reset_d(struct bpf_d *d) 1039df8bae1dSRodney W. Grimes { 1040e7bb21b3SJonathan Lemon 1041e4b3229aSAlexander V. Chernikov BPFD_WLOCK_ASSERT(d); 1042e82669d9SRobert Watson 1043e82669d9SRobert Watson if ((d->bd_hbuf != NULL) && 1044e82669d9SRobert Watson (d->bd_bufmode != BPF_BUFMODE_ZBUF || bpf_canfreebuf(d))) { 1045df8bae1dSRodney W. Grimes /* Free the hold buffer. */ 1046df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 1047572bde2aSRobert Watson d->bd_hbuf = NULL; 1048e82669d9SRobert Watson d->bd_hlen = 0; 104929f612ecSChristian S.J. Peron bpf_buf_reclaimed(d); 1050df8bae1dSRodney W. Grimes } 1051e82669d9SRobert Watson if (bpf_canwritebuf(d)) 1052df8bae1dSRodney W. Grimes d->bd_slen = 0; 1053df8bae1dSRodney W. Grimes d->bd_rcount = 0; 1054df8bae1dSRodney W. Grimes d->bd_dcount = 0; 105569f7644bSChristian S.J. Peron d->bd_fcount = 0; 10564d621040SChristian S.J. Peron d->bd_wcount = 0; 10574d621040SChristian S.J. Peron d->bd_wfcount = 0; 10584d621040SChristian S.J. Peron d->bd_wdcount = 0; 10594d621040SChristian S.J. Peron d->bd_zcopy = 0; 1060df8bae1dSRodney W. Grimes } 1061df8bae1dSRodney W. Grimes 1062df8bae1dSRodney W. Grimes /* 1063df8bae1dSRodney W. Grimes * FIONREAD Check for read packet available. 1064df8bae1dSRodney W. Grimes * SIOCGIFADDR Get interface address - convenient hook to driver. 1065df8bae1dSRodney W. Grimes * BIOCGBLEN Get buffer len [for read()]. 1066f11c3508SDavid Malone * BIOCSETF Set read filter. 1067f11c3508SDavid Malone * BIOCSETFNR Set read filter without resetting descriptor. 1068f11c3508SDavid Malone * BIOCSETWF Set write filter. 1069df8bae1dSRodney W. Grimes * BIOCFLUSH Flush read packet buffer. 1070df8bae1dSRodney W. Grimes * BIOCPROMISC Put interface into promiscuous mode. 1071df8bae1dSRodney W. Grimes * BIOCGDLT Get link layer type. 1072df8bae1dSRodney W. Grimes * BIOCGETIF Get interface name. 1073df8bae1dSRodney W. Grimes * BIOCSETIF Set interface. 1074df8bae1dSRodney W. Grimes * BIOCSRTIMEOUT Set read timeout. 1075df8bae1dSRodney W. Grimes * BIOCGRTIMEOUT Get read timeout. 1076df8bae1dSRodney W. Grimes * BIOCGSTATS Get packet stats. 1077df8bae1dSRodney W. Grimes * BIOCIMMEDIATE Set immediate mode. 1078df8bae1dSRodney W. Grimes * BIOCVERSION Get filter language version. 1079114ae644SMike Smith * BIOCGHDRCMPLT Get "header already complete" flag 1080114ae644SMike Smith * BIOCSHDRCMPLT Set "header already complete" flag 1081560a54e1SJung-uk Kim * BIOCGDIRECTION Get packet direction flag 1082560a54e1SJung-uk Kim * BIOCSDIRECTION Set packet direction flag 1083547d94bdSJung-uk Kim * BIOCGTSTAMP Get time stamp format and resolution. 1084547d94bdSJung-uk Kim * BIOCSTSTAMP Set time stamp format and resolution. 108593e39f0bSChristian S.J. Peron * BIOCLOCK Set "locked" flag 1086560a54e1SJung-uk Kim * BIOCFEEDBACK Set packet feedback mode. 10874d621040SChristian S.J. Peron * BIOCSETZBUF Set current zero-copy buffer locations. 10884d621040SChristian S.J. Peron * BIOCGETZMAX Get maximum zero-copy buffer size. 10894d621040SChristian S.J. Peron * BIOCROTZBUF Force rotation of zero-copy buffer 10904d621040SChristian S.J. Peron * BIOCSETBUFMODE Set buffer mode. 10914d621040SChristian S.J. Peron * BIOCGETBUFMODE Get current buffer mode. 1092df8bae1dSRodney W. Grimes */ 1093df8bae1dSRodney W. Grimes /* ARGSUSED */ 109487f6c662SJulian Elischer static int 109519ba8395SChristian S.J. Peron bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, 109619ba8395SChristian S.J. Peron struct thread *td) 1097df8bae1dSRodney W. Grimes { 1098136600feSEd Schouten struct bpf_d *d; 1099136600feSEd Schouten int error; 1100136600feSEd Schouten 1101136600feSEd Schouten error = devfs_get_cdevpriv((void **)&d); 1102136600feSEd Schouten if (error != 0) 1103136600feSEd Schouten return (error); 1104df8bae1dSRodney W. Grimes 1105b75a24a0SChristian S.J. Peron /* 1106b75a24a0SChristian S.J. Peron * Refresh PID associated with this descriptor. 1107b75a24a0SChristian S.J. Peron */ 1108e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 1109e4b3229aSAlexander V. Chernikov BPF_PID_REFRESH(d, td); 111081bda851SJohn Polstra if (d->bd_state == BPF_WAITING) 111181bda851SJohn Polstra callout_stop(&d->bd_callout); 111281bda851SJohn Polstra d->bd_state = BPF_IDLE; 1113e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 111481bda851SJohn Polstra 111593e39f0bSChristian S.J. Peron if (d->bd_locked == 1) { 111693e39f0bSChristian S.J. Peron switch (cmd) { 111793e39f0bSChristian S.J. Peron case BIOCGBLEN: 111893e39f0bSChristian S.J. Peron case BIOCFLUSH: 111993e39f0bSChristian S.J. Peron case BIOCGDLT: 112093e39f0bSChristian S.J. Peron case BIOCGDLTLIST: 1121fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1122fc0a61a4SKonstantin Belousov case BIOCGDLTLIST32: 1123fc0a61a4SKonstantin Belousov #endif 112493e39f0bSChristian S.J. Peron case BIOCGETIF: 112593e39f0bSChristian S.J. Peron case BIOCGRTIMEOUT: 11269624d947SJuli Mallett #if defined(COMPAT_FREEBSD32) && !defined(__mips__) 1127fc0a61a4SKonstantin Belousov case BIOCGRTIMEOUT32: 1128fc0a61a4SKonstantin Belousov #endif 112993e39f0bSChristian S.J. Peron case BIOCGSTATS: 113093e39f0bSChristian S.J. Peron case BIOCVERSION: 113193e39f0bSChristian S.J. Peron case BIOCGRSIG: 113293e39f0bSChristian S.J. Peron case BIOCGHDRCMPLT: 1133547d94bdSJung-uk Kim case BIOCSTSTAMP: 1134560a54e1SJung-uk Kim case BIOCFEEDBACK: 113593e39f0bSChristian S.J. Peron case FIONREAD: 113693e39f0bSChristian S.J. Peron case BIOCLOCK: 113793e39f0bSChristian S.J. Peron case BIOCSRTIMEOUT: 11389624d947SJuli Mallett #if defined(COMPAT_FREEBSD32) && !defined(__mips__) 1139fc0a61a4SKonstantin Belousov case BIOCSRTIMEOUT32: 1140fc0a61a4SKonstantin Belousov #endif 114193e39f0bSChristian S.J. Peron case BIOCIMMEDIATE: 114293e39f0bSChristian S.J. Peron case TIOCGPGRP: 11434d621040SChristian S.J. Peron case BIOCROTZBUF: 114493e39f0bSChristian S.J. Peron break; 114593e39f0bSChristian S.J. Peron default: 114693e39f0bSChristian S.J. Peron return (EPERM); 114793e39f0bSChristian S.J. Peron } 114893e39f0bSChristian S.J. Peron } 1149fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1150fc0a61a4SKonstantin Belousov /* 1151fc0a61a4SKonstantin Belousov * If we see a 32-bit compat ioctl, mark the stream as 32-bit so 1152fc0a61a4SKonstantin Belousov * that it will get 32-bit packet headers. 1153fc0a61a4SKonstantin Belousov */ 1154fc0a61a4SKonstantin Belousov switch (cmd) { 1155fc0a61a4SKonstantin Belousov case BIOCSETF32: 1156fc0a61a4SKonstantin Belousov case BIOCSETFNR32: 1157fc0a61a4SKonstantin Belousov case BIOCSETWF32: 1158fc0a61a4SKonstantin Belousov case BIOCGDLTLIST32: 1159fc0a61a4SKonstantin Belousov case BIOCGRTIMEOUT32: 1160fc0a61a4SKonstantin Belousov case BIOCSRTIMEOUT32: 1161fc0a61a4SKonstantin Belousov d->bd_compat32 = 1; 1162fc0a61a4SKonstantin Belousov } 1163fc0a61a4SKonstantin Belousov #endif 1164fc0a61a4SKonstantin Belousov 116597021c24SMarko Zec CURVNET_SET(TD_TO_VNET(td)); 1166df8bae1dSRodney W. Grimes switch (cmd) { 1167df8bae1dSRodney W. Grimes 1168df8bae1dSRodney W. Grimes default: 1169df8bae1dSRodney W. Grimes error = EINVAL; 1170df8bae1dSRodney W. Grimes break; 1171df8bae1dSRodney W. Grimes 1172df8bae1dSRodney W. Grimes /* 1173df8bae1dSRodney W. Grimes * Check for read packet available. 1174df8bae1dSRodney W. Grimes */ 1175df8bae1dSRodney W. Grimes case FIONREAD: 1176df8bae1dSRodney W. Grimes { 1177df8bae1dSRodney W. Grimes int n; 1178df8bae1dSRodney W. Grimes 1179e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 1180df8bae1dSRodney W. Grimes n = d->bd_slen; 1181df8bae1dSRodney W. Grimes if (d->bd_hbuf) 1182df8bae1dSRodney W. Grimes n += d->bd_hlen; 1183e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 1184df8bae1dSRodney W. Grimes 1185df8bae1dSRodney W. Grimes *(int *)addr = n; 1186df8bae1dSRodney W. Grimes break; 1187df8bae1dSRodney W. Grimes } 1188df8bae1dSRodney W. Grimes 1189df8bae1dSRodney W. Grimes case SIOCGIFADDR: 1190df8bae1dSRodney W. Grimes { 1191df8bae1dSRodney W. Grimes struct ifnet *ifp; 1192df8bae1dSRodney W. Grimes 1193572bde2aSRobert Watson if (d->bd_bif == NULL) 1194df8bae1dSRodney W. Grimes error = EINVAL; 1195df8bae1dSRodney W. Grimes else { 1196df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 1197df8bae1dSRodney W. Grimes error = (*ifp->if_ioctl)(ifp, cmd, addr); 1198df8bae1dSRodney W. Grimes } 1199df8bae1dSRodney W. Grimes break; 1200df8bae1dSRodney W. Grimes } 1201df8bae1dSRodney W. Grimes 1202df8bae1dSRodney W. Grimes /* 1203df8bae1dSRodney W. Grimes * Get buffer len [for read()]. 1204df8bae1dSRodney W. Grimes */ 1205df8bae1dSRodney W. Grimes case BIOCGBLEN: 1206df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bufsize; 1207df8bae1dSRodney W. Grimes break; 1208df8bae1dSRodney W. Grimes 1209df8bae1dSRodney W. Grimes /* 1210df8bae1dSRodney W. Grimes * Set buffer length. 1211df8bae1dSRodney W. Grimes */ 1212df8bae1dSRodney W. Grimes case BIOCSBLEN: 12134d621040SChristian S.J. Peron error = bpf_ioctl_sblen(d, (u_int *)addr); 1214df8bae1dSRodney W. Grimes break; 1215df8bae1dSRodney W. Grimes 1216df8bae1dSRodney W. Grimes /* 1217df8bae1dSRodney W. Grimes * Set link layer read filter. 1218df8bae1dSRodney W. Grimes */ 1219df8bae1dSRodney W. Grimes case BIOCSETF: 1220f11c3508SDavid Malone case BIOCSETFNR: 122193e39f0bSChristian S.J. Peron case BIOCSETWF: 1222fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1223fc0a61a4SKonstantin Belousov case BIOCSETF32: 1224fc0a61a4SKonstantin Belousov case BIOCSETFNR32: 1225fc0a61a4SKonstantin Belousov case BIOCSETWF32: 1226fc0a61a4SKonstantin Belousov #endif 122793e39f0bSChristian S.J. Peron error = bpf_setf(d, (struct bpf_program *)addr, cmd); 1228df8bae1dSRodney W. Grimes break; 1229df8bae1dSRodney W. Grimes 1230df8bae1dSRodney W. Grimes /* 1231df8bae1dSRodney W. Grimes * Flush read packet buffer. 1232df8bae1dSRodney W. Grimes */ 1233df8bae1dSRodney W. Grimes case BIOCFLUSH: 1234e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 1235df8bae1dSRodney W. Grimes reset_d(d); 1236e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 1237df8bae1dSRodney W. Grimes break; 1238df8bae1dSRodney W. Grimes 1239df8bae1dSRodney W. Grimes /* 1240df8bae1dSRodney W. Grimes * Put interface into promiscuous mode. 1241df8bae1dSRodney W. Grimes */ 1242df8bae1dSRodney W. Grimes case BIOCPROMISC: 1243572bde2aSRobert Watson if (d->bd_bif == NULL) { 1244df8bae1dSRodney W. Grimes /* 1245df8bae1dSRodney W. Grimes * No interface attached yet. 1246df8bae1dSRodney W. Grimes */ 1247df8bae1dSRodney W. Grimes error = EINVAL; 1248df8bae1dSRodney W. Grimes break; 1249df8bae1dSRodney W. Grimes } 1250df8bae1dSRodney W. Grimes if (d->bd_promisc == 0) { 1251df8bae1dSRodney W. Grimes error = ifpromisc(d->bd_bif->bif_ifp, 1); 1252df8bae1dSRodney W. Grimes if (error == 0) 1253df8bae1dSRodney W. Grimes d->bd_promisc = 1; 1254df8bae1dSRodney W. Grimes } 1255df8bae1dSRodney W. Grimes break; 1256df8bae1dSRodney W. Grimes 1257df8bae1dSRodney W. Grimes /* 12588eab61f3SSam Leffler * Get current data link type. 1259df8bae1dSRodney W. Grimes */ 1260df8bae1dSRodney W. Grimes case BIOCGDLT: 1261572bde2aSRobert Watson if (d->bd_bif == NULL) 1262df8bae1dSRodney W. Grimes error = EINVAL; 1263df8bae1dSRodney W. Grimes else 1264df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bif->bif_dlt; 1265df8bae1dSRodney W. Grimes break; 1266df8bae1dSRodney W. Grimes 1267df8bae1dSRodney W. Grimes /* 12688eab61f3SSam Leffler * Get a list of supported data link types. 12698eab61f3SSam Leffler */ 1270fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1271fc0a61a4SKonstantin Belousov case BIOCGDLTLIST32: 1272fc0a61a4SKonstantin Belousov { 1273fc0a61a4SKonstantin Belousov struct bpf_dltlist32 *list32; 1274fc0a61a4SKonstantin Belousov struct bpf_dltlist dltlist; 1275fc0a61a4SKonstantin Belousov 1276fc0a61a4SKonstantin Belousov list32 = (struct bpf_dltlist32 *)addr; 1277fc0a61a4SKonstantin Belousov dltlist.bfl_len = list32->bfl_len; 1278fc0a61a4SKonstantin Belousov dltlist.bfl_list = PTRIN(list32->bfl_list); 1279fc0a61a4SKonstantin Belousov if (d->bd_bif == NULL) 1280fc0a61a4SKonstantin Belousov error = EINVAL; 1281fc0a61a4SKonstantin Belousov else { 1282fc0a61a4SKonstantin Belousov error = bpf_getdltlist(d, &dltlist); 1283fc0a61a4SKonstantin Belousov if (error == 0) 1284fc0a61a4SKonstantin Belousov list32->bfl_len = dltlist.bfl_len; 1285fc0a61a4SKonstantin Belousov } 1286fc0a61a4SKonstantin Belousov break; 1287fc0a61a4SKonstantin Belousov } 1288fc0a61a4SKonstantin Belousov #endif 1289fc0a61a4SKonstantin Belousov 12908eab61f3SSam Leffler case BIOCGDLTLIST: 1291572bde2aSRobert Watson if (d->bd_bif == NULL) 12928eab61f3SSam Leffler error = EINVAL; 12938eab61f3SSam Leffler else 12948eab61f3SSam Leffler error = bpf_getdltlist(d, (struct bpf_dltlist *)addr); 12958eab61f3SSam Leffler break; 12968eab61f3SSam Leffler 12978eab61f3SSam Leffler /* 12988eab61f3SSam Leffler * Set data link type. 12998eab61f3SSam Leffler */ 13008eab61f3SSam Leffler case BIOCSDLT: 1301572bde2aSRobert Watson if (d->bd_bif == NULL) 13028eab61f3SSam Leffler error = EINVAL; 13038eab61f3SSam Leffler else 13048eab61f3SSam Leffler error = bpf_setdlt(d, *(u_int *)addr); 13058eab61f3SSam Leffler break; 13068eab61f3SSam Leffler 13078eab61f3SSam Leffler /* 13081dd0feaaSArchie Cobbs * Get interface name. 1309df8bae1dSRodney W. Grimes */ 1310df8bae1dSRodney W. Grimes case BIOCGETIF: 1311572bde2aSRobert Watson if (d->bd_bif == NULL) 1312df8bae1dSRodney W. Grimes error = EINVAL; 13131dd0feaaSArchie Cobbs else { 13141dd0feaaSArchie Cobbs struct ifnet *const ifp = d->bd_bif->bif_ifp; 13151dd0feaaSArchie Cobbs struct ifreq *const ifr = (struct ifreq *)addr; 13161dd0feaaSArchie Cobbs 13179bf40edeSBrooks Davis strlcpy(ifr->ifr_name, ifp->if_xname, 13189bf40edeSBrooks Davis sizeof(ifr->ifr_name)); 13191dd0feaaSArchie Cobbs } 1320df8bae1dSRodney W. Grimes break; 1321df8bae1dSRodney W. Grimes 1322df8bae1dSRodney W. Grimes /* 1323df8bae1dSRodney W. Grimes * Set interface. 1324df8bae1dSRodney W. Grimes */ 1325df8bae1dSRodney W. Grimes case BIOCSETIF: 1326df8bae1dSRodney W. Grimes error = bpf_setif(d, (struct ifreq *)addr); 1327df8bae1dSRodney W. Grimes break; 1328df8bae1dSRodney W. Grimes 1329df8bae1dSRodney W. Grimes /* 1330df8bae1dSRodney W. Grimes * Set read timeout. 1331df8bae1dSRodney W. Grimes */ 1332df8bae1dSRodney W. Grimes case BIOCSRTIMEOUT: 13339624d947SJuli Mallett #if defined(COMPAT_FREEBSD32) && !defined(__mips__) 1334fc0a61a4SKonstantin Belousov case BIOCSRTIMEOUT32: 1335fc0a61a4SKonstantin Belousov #endif 1336df8bae1dSRodney W. Grimes { 1337df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 13389624d947SJuli Mallett #if defined(COMPAT_FREEBSD32) && !defined(__mips__) 1339fc0a61a4SKonstantin Belousov struct timeval32 *tv32; 1340fc0a61a4SKonstantin Belousov struct timeval tv64; 1341fc0a61a4SKonstantin Belousov 1342fc0a61a4SKonstantin Belousov if (cmd == BIOCSRTIMEOUT32) { 1343fc0a61a4SKonstantin Belousov tv32 = (struct timeval32 *)addr; 1344fc0a61a4SKonstantin Belousov tv = &tv64; 1345fc0a61a4SKonstantin Belousov tv->tv_sec = tv32->tv_sec; 1346fc0a61a4SKonstantin Belousov tv->tv_usec = tv32->tv_usec; 1347fc0a61a4SKonstantin Belousov } else 1348fc0a61a4SKonstantin Belousov #endif 1349fc0a61a4SKonstantin Belousov tv = (struct timeval *)addr; 1350df8bae1dSRodney W. Grimes 1351bdc2cdc5SAlexander Langer /* 1352bdc2cdc5SAlexander Langer * Subtract 1 tick from tvtohz() since this isn't 1353bdc2cdc5SAlexander Langer * a one-shot timer. 1354bdc2cdc5SAlexander Langer */ 1355bdc2cdc5SAlexander Langer if ((error = itimerfix(tv)) == 0) 1356bdc2cdc5SAlexander Langer d->bd_rtout = tvtohz(tv) - 1; 1357df8bae1dSRodney W. Grimes break; 1358df8bae1dSRodney W. Grimes } 1359df8bae1dSRodney W. Grimes 1360df8bae1dSRodney W. Grimes /* 1361df8bae1dSRodney W. Grimes * Get read timeout. 1362df8bae1dSRodney W. Grimes */ 1363df8bae1dSRodney W. Grimes case BIOCGRTIMEOUT: 13649624d947SJuli Mallett #if defined(COMPAT_FREEBSD32) && !defined(__mips__) 1365fc0a61a4SKonstantin Belousov case BIOCGRTIMEOUT32: 1366fc0a61a4SKonstantin Belousov #endif 1367df8bae1dSRodney W. Grimes { 1368fc0a61a4SKonstantin Belousov struct timeval *tv; 13699624d947SJuli Mallett #if defined(COMPAT_FREEBSD32) && !defined(__mips__) 1370fc0a61a4SKonstantin Belousov struct timeval32 *tv32; 1371fc0a61a4SKonstantin Belousov struct timeval tv64; 1372fc0a61a4SKonstantin Belousov 1373fc0a61a4SKonstantin Belousov if (cmd == BIOCGRTIMEOUT32) 1374fc0a61a4SKonstantin Belousov tv = &tv64; 1375fc0a61a4SKonstantin Belousov else 1376fc0a61a4SKonstantin Belousov #endif 1377fc0a61a4SKonstantin Belousov tv = (struct timeval *)addr; 1378df8bae1dSRodney W. Grimes 1379bdc2cdc5SAlexander Langer tv->tv_sec = d->bd_rtout / hz; 1380bdc2cdc5SAlexander Langer tv->tv_usec = (d->bd_rtout % hz) * tick; 13819624d947SJuli Mallett #if defined(COMPAT_FREEBSD32) && !defined(__mips__) 1382fc0a61a4SKonstantin Belousov if (cmd == BIOCGRTIMEOUT32) { 1383fc0a61a4SKonstantin Belousov tv32 = (struct timeval32 *)addr; 1384fc0a61a4SKonstantin Belousov tv32->tv_sec = tv->tv_sec; 1385fc0a61a4SKonstantin Belousov tv32->tv_usec = tv->tv_usec; 1386fc0a61a4SKonstantin Belousov } 1387fc0a61a4SKonstantin Belousov #endif 1388fc0a61a4SKonstantin Belousov 1389df8bae1dSRodney W. Grimes break; 1390df8bae1dSRodney W. Grimes } 1391df8bae1dSRodney W. Grimes 1392df8bae1dSRodney W. Grimes /* 1393df8bae1dSRodney W. Grimes * Get packet stats. 1394df8bae1dSRodney W. Grimes */ 1395df8bae1dSRodney W. Grimes case BIOCGSTATS: 1396df8bae1dSRodney W. Grimes { 1397df8bae1dSRodney W. Grimes struct bpf_stat *bs = (struct bpf_stat *)addr; 1398df8bae1dSRodney W. Grimes 13994d621040SChristian S.J. Peron /* XXXCSJP overflow */ 1400df8bae1dSRodney W. Grimes bs->bs_recv = d->bd_rcount; 1401df8bae1dSRodney W. Grimes bs->bs_drop = d->bd_dcount; 1402df8bae1dSRodney W. Grimes break; 1403df8bae1dSRodney W. Grimes } 1404df8bae1dSRodney W. Grimes 1405df8bae1dSRodney W. Grimes /* 1406df8bae1dSRodney W. Grimes * Set immediate mode. 1407df8bae1dSRodney W. Grimes */ 1408df8bae1dSRodney W. Grimes case BIOCIMMEDIATE: 1409df8bae1dSRodney W. Grimes d->bd_immediate = *(u_int *)addr; 1410df8bae1dSRodney W. Grimes break; 1411df8bae1dSRodney W. Grimes 1412df8bae1dSRodney W. Grimes case BIOCVERSION: 1413df8bae1dSRodney W. Grimes { 1414df8bae1dSRodney W. Grimes struct bpf_version *bv = (struct bpf_version *)addr; 1415df8bae1dSRodney W. Grimes 1416df8bae1dSRodney W. Grimes bv->bv_major = BPF_MAJOR_VERSION; 1417df8bae1dSRodney W. Grimes bv->bv_minor = BPF_MINOR_VERSION; 1418df8bae1dSRodney W. Grimes break; 1419df8bae1dSRodney W. Grimes } 142000a83887SPaul Traina 1421114ae644SMike Smith /* 1422114ae644SMike Smith * Get "header already complete" flag 1423114ae644SMike Smith */ 1424114ae644SMike Smith case BIOCGHDRCMPLT: 1425114ae644SMike Smith *(u_int *)addr = d->bd_hdrcmplt; 1426114ae644SMike Smith break; 1427114ae644SMike Smith 1428114ae644SMike Smith /* 1429114ae644SMike Smith * Set "header already complete" flag 1430114ae644SMike Smith */ 1431114ae644SMike Smith case BIOCSHDRCMPLT: 1432114ae644SMike Smith d->bd_hdrcmplt = *(u_int *)addr ? 1 : 0; 1433114ae644SMike Smith break; 1434114ae644SMike Smith 14358ed3828cSRobert Watson /* 1436560a54e1SJung-uk Kim * Get packet direction flag 14378ed3828cSRobert Watson */ 1438560a54e1SJung-uk Kim case BIOCGDIRECTION: 1439560a54e1SJung-uk Kim *(u_int *)addr = d->bd_direction; 14408ed3828cSRobert Watson break; 14418ed3828cSRobert Watson 14428ed3828cSRobert Watson /* 1443560a54e1SJung-uk Kim * Set packet direction flag 14448ed3828cSRobert Watson */ 1445560a54e1SJung-uk Kim case BIOCSDIRECTION: 1446560a54e1SJung-uk Kim { 1447560a54e1SJung-uk Kim u_int direction; 1448560a54e1SJung-uk Kim 1449560a54e1SJung-uk Kim direction = *(u_int *)addr; 1450560a54e1SJung-uk Kim switch (direction) { 1451560a54e1SJung-uk Kim case BPF_D_IN: 1452560a54e1SJung-uk Kim case BPF_D_INOUT: 1453560a54e1SJung-uk Kim case BPF_D_OUT: 1454560a54e1SJung-uk Kim d->bd_direction = direction; 1455560a54e1SJung-uk Kim break; 1456560a54e1SJung-uk Kim default: 1457560a54e1SJung-uk Kim error = EINVAL; 1458560a54e1SJung-uk Kim } 1459560a54e1SJung-uk Kim } 1460560a54e1SJung-uk Kim break; 1461560a54e1SJung-uk Kim 1462547d94bdSJung-uk Kim /* 1463d0d7bcdfSJung-uk Kim * Get packet timestamp format and resolution. 1464547d94bdSJung-uk Kim */ 1465547d94bdSJung-uk Kim case BIOCGTSTAMP: 1466547d94bdSJung-uk Kim *(u_int *)addr = d->bd_tstamp; 1467547d94bdSJung-uk Kim break; 1468547d94bdSJung-uk Kim 1469547d94bdSJung-uk Kim /* 1470547d94bdSJung-uk Kim * Set packet timestamp format and resolution. 1471547d94bdSJung-uk Kim */ 1472547d94bdSJung-uk Kim case BIOCSTSTAMP: 1473547d94bdSJung-uk Kim { 1474547d94bdSJung-uk Kim u_int func; 1475547d94bdSJung-uk Kim 1476547d94bdSJung-uk Kim func = *(u_int *)addr; 1477547d94bdSJung-uk Kim if (BPF_T_VALID(func)) 1478547d94bdSJung-uk Kim d->bd_tstamp = func; 1479547d94bdSJung-uk Kim else 1480547d94bdSJung-uk Kim error = EINVAL; 1481547d94bdSJung-uk Kim } 1482547d94bdSJung-uk Kim break; 1483547d94bdSJung-uk Kim 1484560a54e1SJung-uk Kim case BIOCFEEDBACK: 1485560a54e1SJung-uk Kim d->bd_feedback = *(u_int *)addr; 1486560a54e1SJung-uk Kim break; 1487560a54e1SJung-uk Kim 1488560a54e1SJung-uk Kim case BIOCLOCK: 1489560a54e1SJung-uk Kim d->bd_locked = 1; 14908ed3828cSRobert Watson break; 14918ed3828cSRobert Watson 149200a83887SPaul Traina case FIONBIO: /* Non-blocking I/O */ 149300a83887SPaul Traina break; 149400a83887SPaul Traina 149500a83887SPaul Traina case FIOASYNC: /* Send signal on receive packets */ 149600a83887SPaul Traina d->bd_async = *(int *)addr; 149700a83887SPaul Traina break; 149800a83887SPaul Traina 1499831d27a9SDon Lewis case FIOSETOWN: 1500831d27a9SDon Lewis error = fsetown(*(int *)addr, &d->bd_sigio); 150100a83887SPaul Traina break; 150200a83887SPaul Traina 1503831d27a9SDon Lewis case FIOGETOWN: 150491e97a82SDon Lewis *(int *)addr = fgetown(&d->bd_sigio); 1505831d27a9SDon Lewis break; 1506831d27a9SDon Lewis 1507831d27a9SDon Lewis /* This is deprecated, FIOSETOWN should be used instead. */ 1508831d27a9SDon Lewis case TIOCSPGRP: 1509831d27a9SDon Lewis error = fsetown(-(*(int *)addr), &d->bd_sigio); 1510831d27a9SDon Lewis break; 1511831d27a9SDon Lewis 1512831d27a9SDon Lewis /* This is deprecated, FIOGETOWN should be used instead. */ 151300a83887SPaul Traina case TIOCGPGRP: 151491e97a82SDon Lewis *(int *)addr = -fgetown(&d->bd_sigio); 151500a83887SPaul Traina break; 151600a83887SPaul Traina 151700a83887SPaul Traina case BIOCSRSIG: /* Set receive signal */ 151800a83887SPaul Traina { 151900a83887SPaul Traina u_int sig; 152000a83887SPaul Traina 152100a83887SPaul Traina sig = *(u_int *)addr; 152200a83887SPaul Traina 152300a83887SPaul Traina if (sig >= NSIG) 152400a83887SPaul Traina error = EINVAL; 152500a83887SPaul Traina else 152600a83887SPaul Traina d->bd_sig = sig; 152700a83887SPaul Traina break; 152800a83887SPaul Traina } 152900a83887SPaul Traina case BIOCGRSIG: 153000a83887SPaul Traina *(u_int *)addr = d->bd_sig; 153100a83887SPaul Traina break; 15324d621040SChristian S.J. Peron 15334d621040SChristian S.J. Peron case BIOCGETBUFMODE: 15344d621040SChristian S.J. Peron *(u_int *)addr = d->bd_bufmode; 15354d621040SChristian S.J. Peron break; 15364d621040SChristian S.J. Peron 15374d621040SChristian S.J. Peron case BIOCSETBUFMODE: 15384d621040SChristian S.J. Peron /* 15394d621040SChristian S.J. Peron * Allow the buffering mode to be changed as long as we 15404d621040SChristian S.J. Peron * haven't yet committed to a particular mode. Our 15414d621040SChristian S.J. Peron * definition of commitment, for now, is whether or not a 15424d621040SChristian S.J. Peron * buffer has been allocated or an interface attached, since 15434d621040SChristian S.J. Peron * that's the point where things get tricky. 15444d621040SChristian S.J. Peron */ 15454d621040SChristian S.J. Peron switch (*(u_int *)addr) { 15464d621040SChristian S.J. Peron case BPF_BUFMODE_BUFFER: 15474d621040SChristian S.J. Peron break; 15484d621040SChristian S.J. Peron 15494d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 15504d621040SChristian S.J. Peron if (bpf_zerocopy_enable) 15514d621040SChristian S.J. Peron break; 15524d621040SChristian S.J. Peron /* FALLSTHROUGH */ 15534d621040SChristian S.J. Peron 15544d621040SChristian S.J. Peron default: 15551b610a74SBjoern A. Zeeb CURVNET_RESTORE(); 15564d621040SChristian S.J. Peron return (EINVAL); 15574d621040SChristian S.J. Peron } 15584d621040SChristian S.J. Peron 1559e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 15604d621040SChristian S.J. Peron if (d->bd_sbuf != NULL || d->bd_hbuf != NULL || 15614d621040SChristian S.J. Peron d->bd_fbuf != NULL || d->bd_bif != NULL) { 1562e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 15631b610a74SBjoern A. Zeeb CURVNET_RESTORE(); 15644d621040SChristian S.J. Peron return (EBUSY); 15654d621040SChristian S.J. Peron } 15664d621040SChristian S.J. Peron d->bd_bufmode = *(u_int *)addr; 1567e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 15684d621040SChristian S.J. Peron break; 15694d621040SChristian S.J. Peron 15704d621040SChristian S.J. Peron case BIOCGETZMAX: 15711b610a74SBjoern A. Zeeb error = bpf_ioctl_getzmax(td, d, (size_t *)addr); 15721b610a74SBjoern A. Zeeb break; 15734d621040SChristian S.J. Peron 15744d621040SChristian S.J. Peron case BIOCSETZBUF: 15751b610a74SBjoern A. Zeeb error = bpf_ioctl_setzbuf(td, d, (struct bpf_zbuf *)addr); 15761b610a74SBjoern A. Zeeb break; 15774d621040SChristian S.J. Peron 15784d621040SChristian S.J. Peron case BIOCROTZBUF: 15791b610a74SBjoern A. Zeeb error = bpf_ioctl_rotzbuf(td, d, (struct bpf_zbuf *)addr); 15801b610a74SBjoern A. Zeeb break; 1581df8bae1dSRodney W. Grimes } 158297021c24SMarko Zec CURVNET_RESTORE(); 1583df8bae1dSRodney W. Grimes return (error); 1584df8bae1dSRodney W. Grimes } 1585df8bae1dSRodney W. Grimes 1586df8bae1dSRodney W. Grimes /* 1587df8bae1dSRodney W. Grimes * Set d's packet filter program to fp. If this file already has a filter, 1588df8bae1dSRodney W. Grimes * free it and replace it. Returns EINVAL for bogus requests. 1589df8bae1dSRodney W. Grimes */ 1590f708ef1bSPoul-Henning Kamp static int 159119ba8395SChristian S.J. Peron bpf_setf(struct bpf_d *d, struct bpf_program *fp, u_long cmd) 1592df8bae1dSRodney W. Grimes { 1593df8bae1dSRodney W. Grimes struct bpf_insn *fcode, *old; 159493e39f0bSChristian S.J. Peron u_int wfilter, flen, size; 1595293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1596ae275efcSJung-uk Kim bpf_jit_filter *ofunc; 1597ae275efcSJung-uk Kim #endif 1598fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1599fc0a61a4SKonstantin Belousov struct bpf_program32 *fp32; 1600fc0a61a4SKonstantin Belousov struct bpf_program fp_swab; 1601*51ec1eb7SAlexander V. Chernikov int need_upgrade = 0; 1602df8bae1dSRodney W. Grimes 1603fc0a61a4SKonstantin Belousov if (cmd == BIOCSETWF32 || cmd == BIOCSETF32 || cmd == BIOCSETFNR32) { 1604fc0a61a4SKonstantin Belousov fp32 = (struct bpf_program32 *)fp; 1605fc0a61a4SKonstantin Belousov fp_swab.bf_len = fp32->bf_len; 1606fc0a61a4SKonstantin Belousov fp_swab.bf_insns = (struct bpf_insn *)(uintptr_t)fp32->bf_insns; 1607fc0a61a4SKonstantin Belousov fp = &fp_swab; 1608fc0a61a4SKonstantin Belousov if (cmd == BIOCSETWF32) 1609fc0a61a4SKonstantin Belousov cmd = BIOCSETWF; 1610fc0a61a4SKonstantin Belousov } 1611fc0a61a4SKonstantin Belousov #endif 161293e39f0bSChristian S.J. Peron if (cmd == BIOCSETWF) { 161393e39f0bSChristian S.J. Peron old = d->bd_wfilter; 161493e39f0bSChristian S.J. Peron wfilter = 1; 1615293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1616ae275efcSJung-uk Kim ofunc = NULL; 1617ae275efcSJung-uk Kim #endif 161893e39f0bSChristian S.J. Peron } else { 161993e39f0bSChristian S.J. Peron wfilter = 0; 162093e39f0bSChristian S.J. Peron old = d->bd_rfilter; 1621293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1622ae275efcSJung-uk Kim ofunc = d->bd_bfilter; 1623ae275efcSJung-uk Kim #endif 162493e39f0bSChristian S.J. Peron } 1625572bde2aSRobert Watson if (fp->bf_insns == NULL) { 1626df8bae1dSRodney W. Grimes if (fp->bf_len != 0) 1627df8bae1dSRodney W. Grimes return (EINVAL); 1628e4b3229aSAlexander V. Chernikov /* 1629e4b3229aSAlexander V. Chernikov * Protect filter change by interface lock, too. 1630e4b3229aSAlexander V. Chernikov * The same lock order is used by bpf_detachd(). 1631e4b3229aSAlexander V. Chernikov */ 1632e4b3229aSAlexander V. Chernikov BPFIF_WLOCK(d->bd_bif); 1633e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 163493e39f0bSChristian S.J. Peron if (wfilter) 163593e39f0bSChristian S.J. Peron d->bd_wfilter = NULL; 1636ae275efcSJung-uk Kim else { 163793e39f0bSChristian S.J. Peron d->bd_rfilter = NULL; 1638293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1639ae275efcSJung-uk Kim d->bd_bfilter = NULL; 1640ae275efcSJung-uk Kim #endif 1641f11c3508SDavid Malone if (cmd == BIOCSETF) 1642df8bae1dSRodney W. Grimes reset_d(d); 1643f11c3508SDavid Malone } 1644e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 1645e4b3229aSAlexander V. Chernikov BPFIF_WUNLOCK(d->bd_bif); 1646572bde2aSRobert Watson if (old != NULL) 1647bd3a5320SPoul-Henning Kamp free((caddr_t)old, M_BPF); 1648293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1649ae275efcSJung-uk Kim if (ofunc != NULL) 1650ae275efcSJung-uk Kim bpf_destroy_jit_filter(ofunc); 1651ae275efcSJung-uk Kim #endif 1652df8bae1dSRodney W. Grimes return (0); 1653df8bae1dSRodney W. Grimes } 1654df8bae1dSRodney W. Grimes flen = fp->bf_len; 16550eb20604SChristian S.J. Peron if (flen > bpf_maxinsns) 1656df8bae1dSRodney W. Grimes return (EINVAL); 1657df8bae1dSRodney W. Grimes 1658df8bae1dSRodney W. Grimes size = flen * sizeof(*fp->bf_insns); 1659a163d034SWarner Losh fcode = (struct bpf_insn *)malloc(size, M_BPF, M_WAITOK); 1660df8bae1dSRodney W. Grimes if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 && 1661df8bae1dSRodney W. Grimes bpf_validate(fcode, (int)flen)) { 1662e4b3229aSAlexander V. Chernikov /* 1663e4b3229aSAlexander V. Chernikov * Protect filter change by interface lock, too 1664e4b3229aSAlexander V. Chernikov * The same lock order is used by bpf_detachd(). 1665e4b3229aSAlexander V. Chernikov */ 1666e4b3229aSAlexander V. Chernikov BPFIF_WLOCK(d->bd_bif); 1667e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 166893e39f0bSChristian S.J. Peron if (wfilter) 166993e39f0bSChristian S.J. Peron d->bd_wfilter = fcode; 1670ae275efcSJung-uk Kim else { 167193e39f0bSChristian S.J. Peron d->bd_rfilter = fcode; 1672293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1673ae275efcSJung-uk Kim d->bd_bfilter = bpf_jitter(fcode, flen); 1674ae275efcSJung-uk Kim #endif 1675f11c3508SDavid Malone if (cmd == BIOCSETF) 1676df8bae1dSRodney W. Grimes reset_d(d); 1677*51ec1eb7SAlexander V. Chernikov 1678*51ec1eb7SAlexander V. Chernikov /* 1679*51ec1eb7SAlexander V. Chernikov * Do not require upgrade by first BIOCSETF 1680*51ec1eb7SAlexander V. Chernikov * (used to set snaplen) by pcap_open_live() 1681*51ec1eb7SAlexander V. Chernikov */ 1682*51ec1eb7SAlexander V. Chernikov if ((d->bd_writer != 0) && (--d->bd_writer == 0)) 1683*51ec1eb7SAlexander V. Chernikov need_upgrade = 1; 1684*51ec1eb7SAlexander V. Chernikov CTR4(KTR_NET, "%s: filter function set by pid %d, " 1685*51ec1eb7SAlexander V. Chernikov "bd_writer counter %d, need_upgrade %d", 1686*51ec1eb7SAlexander V. Chernikov __func__, d->bd_pid, d->bd_writer, need_upgrade); 1687f11c3508SDavid Malone } 1688e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 1689e4b3229aSAlexander V. Chernikov BPFIF_WUNLOCK(d->bd_bif); 1690572bde2aSRobert Watson if (old != NULL) 1691bd3a5320SPoul-Henning Kamp free((caddr_t)old, M_BPF); 1692293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1693ae275efcSJung-uk Kim if (ofunc != NULL) 1694ae275efcSJung-uk Kim bpf_destroy_jit_filter(ofunc); 1695ae275efcSJung-uk Kim #endif 1696df8bae1dSRodney W. Grimes 1697*51ec1eb7SAlexander V. Chernikov /* Move d to active readers list */ 1698*51ec1eb7SAlexander V. Chernikov if (need_upgrade != 0) 1699*51ec1eb7SAlexander V. Chernikov bpf_upgraded(d); 1700*51ec1eb7SAlexander V. Chernikov 1701df8bae1dSRodney W. Grimes return (0); 1702df8bae1dSRodney W. Grimes } 1703bd3a5320SPoul-Henning Kamp free((caddr_t)fcode, M_BPF); 1704df8bae1dSRodney W. Grimes return (EINVAL); 1705df8bae1dSRodney W. Grimes } 1706df8bae1dSRodney W. Grimes 1707df8bae1dSRodney W. Grimes /* 1708df8bae1dSRodney W. Grimes * Detach a file from its current interface (if attached at all) and attach 1709df8bae1dSRodney W. Grimes * to the interface indicated by the name stored in ifr. 1710df8bae1dSRodney W. Grimes * Return an errno or 0. 1711df8bae1dSRodney W. Grimes */ 1712df8bae1dSRodney W. Grimes static int 171319ba8395SChristian S.J. Peron bpf_setif(struct bpf_d *d, struct ifreq *ifr) 1714df8bae1dSRodney W. Grimes { 1715df8bae1dSRodney W. Grimes struct bpf_if *bp; 17169b44ff22SGarrett Wollman struct ifnet *theywant; 1717df8bae1dSRodney W. Grimes 17189b44ff22SGarrett Wollman theywant = ifunit(ifr->ifr_name); 171916d878ccSChristian S.J. Peron if (theywant == NULL || theywant->if_bpf == NULL) 172016d878ccSChristian S.J. Peron return (ENXIO); 17219b44ff22SGarrett Wollman 172216d878ccSChristian S.J. Peron bp = theywant->if_bpf; 17234d621040SChristian S.J. Peron 1724df8bae1dSRodney W. Grimes /* 17254d621040SChristian S.J. Peron * Behavior here depends on the buffering model. If we're using 17264d621040SChristian S.J. Peron * kernel memory buffers, then we can allocate them here. If we're 17274d621040SChristian S.J. Peron * using zero-copy, then the user process must have registered 17284d621040SChristian S.J. Peron * buffers by the time we get here. If not, return an error. 17294d621040SChristian S.J. Peron * 17304d621040SChristian S.J. Peron * XXXRW: There are locking issues here with multi-threaded use: what 17314d621040SChristian S.J. Peron * if two threads try to set the interface at once? 1732df8bae1dSRodney W. Grimes */ 17334d621040SChristian S.J. Peron switch (d->bd_bufmode) { 17344d621040SChristian S.J. Peron case BPF_BUFMODE_BUFFER: 1735a3594432SRobert Watson if (d->bd_sbuf == NULL) 17364d621040SChristian S.J. Peron bpf_buffer_alloc(d); 17374d621040SChristian S.J. Peron KASSERT(d->bd_sbuf != NULL, ("bpf_setif: bd_sbuf NULL")); 17384d621040SChristian S.J. Peron break; 17394d621040SChristian S.J. Peron 17404d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 17414d621040SChristian S.J. Peron if (d->bd_sbuf == NULL) 17424d621040SChristian S.J. Peron return (EINVAL); 17434d621040SChristian S.J. Peron break; 17444d621040SChristian S.J. Peron 17454d621040SChristian S.J. Peron default: 17464d621040SChristian S.J. Peron panic("bpf_setif: bufmode %d", d->bd_bufmode); 17474d621040SChristian S.J. Peron } 1748df8bae1dSRodney W. Grimes if (bp != d->bd_bif) { 1749df8bae1dSRodney W. Grimes if (d->bd_bif) 1750df8bae1dSRodney W. Grimes /* 1751df8bae1dSRodney W. Grimes * Detach if attached to something else. 1752df8bae1dSRodney W. Grimes */ 1753df8bae1dSRodney W. Grimes bpf_detachd(d); 1754df8bae1dSRodney W. Grimes 1755df8bae1dSRodney W. Grimes bpf_attachd(d, bp); 1756df8bae1dSRodney W. Grimes } 1757e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 1758df8bae1dSRodney W. Grimes reset_d(d); 1759e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 1760df8bae1dSRodney W. Grimes return (0); 1761df8bae1dSRodney W. Grimes } 1762df8bae1dSRodney W. Grimes 1763df8bae1dSRodney W. Grimes /* 1764243ac7d8SPeter Wemm * Support for select() and poll() system calls 1765df8bae1dSRodney W. Grimes * 1766df8bae1dSRodney W. Grimes * Return true iff the specific operation will not block indefinitely. 1767df8bae1dSRodney W. Grimes * Otherwise, return false but make a note that a selwakeup() must be done. 1768df8bae1dSRodney W. Grimes */ 176937c84183SPoul-Henning Kamp static int 177019ba8395SChristian S.J. Peron bpfpoll(struct cdev *dev, int events, struct thread *td) 1771df8bae1dSRodney W. Grimes { 1772e7bb21b3SJonathan Lemon struct bpf_d *d; 17730832fc64SGarance A Drosehn int revents; 1774df8bae1dSRodney W. Grimes 1775136600feSEd Schouten if (devfs_get_cdevpriv((void **)&d) != 0 || d->bd_bif == NULL) 1776136600feSEd Schouten return (events & 1777136600feSEd Schouten (POLLHUP|POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM)); 1778de5d9935SRobert Watson 1779b75a24a0SChristian S.J. Peron /* 1780b75a24a0SChristian S.J. Peron * Refresh PID associated with this descriptor. 1781b75a24a0SChristian S.J. Peron */ 17820832fc64SGarance A Drosehn revents = events & (POLLOUT | POLLWRNORM); 1783e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 1784e4b3229aSAlexander V. Chernikov BPF_PID_REFRESH(d, td); 178575c13541SPoul-Henning Kamp if (events & (POLLIN | POLLRDNORM)) { 178695aab9ccSJohn-Mark Gurney if (bpf_ready(d)) 1787243ac7d8SPeter Wemm revents |= events & (POLLIN | POLLRDNORM); 178881bda851SJohn Polstra else { 1789ed01445dSJohn Baldwin selrecord(td, &d->bd_sel); 179081bda851SJohn Polstra /* Start the read timeout if necessary. */ 179181bda851SJohn Polstra if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) { 179281bda851SJohn Polstra callout_reset(&d->bd_callout, d->bd_rtout, 179381bda851SJohn Polstra bpf_timed_out, d); 179481bda851SJohn Polstra d->bd_state = BPF_WAITING; 179581bda851SJohn Polstra } 179681bda851SJohn Polstra } 179775c13541SPoul-Henning Kamp } 1798e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 1799243ac7d8SPeter Wemm return (revents); 1800df8bae1dSRodney W. Grimes } 1801df8bae1dSRodney W. Grimes 1802df8bae1dSRodney W. Grimes /* 180395aab9ccSJohn-Mark Gurney * Support for kevent() system call. Register EVFILT_READ filters and 180495aab9ccSJohn-Mark Gurney * reject all others. 180595aab9ccSJohn-Mark Gurney */ 180695aab9ccSJohn-Mark Gurney int 180719ba8395SChristian S.J. Peron bpfkqfilter(struct cdev *dev, struct knote *kn) 180895aab9ccSJohn-Mark Gurney { 1809136600feSEd Schouten struct bpf_d *d; 181095aab9ccSJohn-Mark Gurney 1811136600feSEd Schouten if (devfs_get_cdevpriv((void **)&d) != 0 || 1812136600feSEd Schouten kn->kn_filter != EVFILT_READ) 181395aab9ccSJohn-Mark Gurney return (1); 181495aab9ccSJohn-Mark Gurney 1815b75a24a0SChristian S.J. Peron /* 1816b75a24a0SChristian S.J. Peron * Refresh PID associated with this descriptor. 1817b75a24a0SChristian S.J. Peron */ 1818e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 1819e4b3229aSAlexander V. Chernikov BPF_PID_REFRESH_CUR(d); 182095aab9ccSJohn-Mark Gurney kn->kn_fop = &bpfread_filtops; 182195aab9ccSJohn-Mark Gurney kn->kn_hook = d; 18224b19419eSChristian S.J. Peron knlist_add(&d->bd_sel.si_note, kn, 1); 1823e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 182495aab9ccSJohn-Mark Gurney 182595aab9ccSJohn-Mark Gurney return (0); 182695aab9ccSJohn-Mark Gurney } 182795aab9ccSJohn-Mark Gurney 182895aab9ccSJohn-Mark Gurney static void 182919ba8395SChristian S.J. Peron filt_bpfdetach(struct knote *kn) 183095aab9ccSJohn-Mark Gurney { 183195aab9ccSJohn-Mark Gurney struct bpf_d *d = (struct bpf_d *)kn->kn_hook; 183295aab9ccSJohn-Mark Gurney 1833ad3b9257SJohn-Mark Gurney knlist_remove(&d->bd_sel.si_note, kn, 0); 183495aab9ccSJohn-Mark Gurney } 183595aab9ccSJohn-Mark Gurney 183695aab9ccSJohn-Mark Gurney static int 183719ba8395SChristian S.J. Peron filt_bpfread(struct knote *kn, long hint) 183895aab9ccSJohn-Mark Gurney { 183995aab9ccSJohn-Mark Gurney struct bpf_d *d = (struct bpf_d *)kn->kn_hook; 184095aab9ccSJohn-Mark Gurney int ready; 184195aab9ccSJohn-Mark Gurney 1842e4b3229aSAlexander V. Chernikov BPFD_WLOCK_ASSERT(d); 184395aab9ccSJohn-Mark Gurney ready = bpf_ready(d); 184495aab9ccSJohn-Mark Gurney if (ready) { 184595aab9ccSJohn-Mark Gurney kn->kn_data = d->bd_slen; 184695aab9ccSJohn-Mark Gurney if (d->bd_hbuf) 184795aab9ccSJohn-Mark Gurney kn->kn_data += d->bd_hlen; 18485d7af3a1SJung-uk Kim } else if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) { 184995aab9ccSJohn-Mark Gurney callout_reset(&d->bd_callout, d->bd_rtout, 185095aab9ccSJohn-Mark Gurney bpf_timed_out, d); 185195aab9ccSJohn-Mark Gurney d->bd_state = BPF_WAITING; 185295aab9ccSJohn-Mark Gurney } 185395aab9ccSJohn-Mark Gurney 185495aab9ccSJohn-Mark Gurney return (ready); 185595aab9ccSJohn-Mark Gurney } 185695aab9ccSJohn-Mark Gurney 1857253a3814SLawrence Stewart #define BPF_TSTAMP_NONE 0 1858253a3814SLawrence Stewart #define BPF_TSTAMP_FAST 1 1859253a3814SLawrence Stewart #define BPF_TSTAMP_NORMAL 2 1860253a3814SLawrence Stewart #define BPF_TSTAMP_EXTERN 3 1861253a3814SLawrence Stewart 1862253a3814SLawrence Stewart static int 1863253a3814SLawrence Stewart bpf_ts_quality(int tstype) 1864253a3814SLawrence Stewart { 1865253a3814SLawrence Stewart 1866253a3814SLawrence Stewart if (tstype == BPF_T_NONE) 1867253a3814SLawrence Stewart return (BPF_TSTAMP_NONE); 1868253a3814SLawrence Stewart if ((tstype & BPF_T_FAST) != 0) 1869253a3814SLawrence Stewart return (BPF_TSTAMP_FAST); 1870253a3814SLawrence Stewart 1871253a3814SLawrence Stewart return (BPF_TSTAMP_NORMAL); 1872253a3814SLawrence Stewart } 1873253a3814SLawrence Stewart 1874253a3814SLawrence Stewart static int 1875253a3814SLawrence Stewart bpf_gettime(struct bintime *bt, int tstype, struct mbuf *m) 1876253a3814SLawrence Stewart { 1877253a3814SLawrence Stewart struct m_tag *tag; 1878253a3814SLawrence Stewart int quality; 1879253a3814SLawrence Stewart 1880253a3814SLawrence Stewart quality = bpf_ts_quality(tstype); 1881253a3814SLawrence Stewart if (quality == BPF_TSTAMP_NONE) 1882253a3814SLawrence Stewart return (quality); 1883253a3814SLawrence Stewart 1884253a3814SLawrence Stewart if (m != NULL) { 1885253a3814SLawrence Stewart tag = m_tag_locate(m, MTAG_BPF, MTAG_BPF_TIMESTAMP, NULL); 1886253a3814SLawrence Stewart if (tag != NULL) { 1887253a3814SLawrence Stewart *bt = *(struct bintime *)(tag + 1); 1888253a3814SLawrence Stewart return (BPF_TSTAMP_EXTERN); 1889253a3814SLawrence Stewart } 1890253a3814SLawrence Stewart } 1891253a3814SLawrence Stewart if (quality == BPF_TSTAMP_NORMAL) 1892253a3814SLawrence Stewart binuptime(bt); 1893253a3814SLawrence Stewart else 1894253a3814SLawrence Stewart getbinuptime(bt); 1895253a3814SLawrence Stewart 1896253a3814SLawrence Stewart return (quality); 1897253a3814SLawrence Stewart } 1898253a3814SLawrence Stewart 189995aab9ccSJohn-Mark Gurney /* 1900df8bae1dSRodney W. Grimes * Incoming linkage from device drivers. Process the packet pkt, of length 1901df8bae1dSRodney W. Grimes * pktlen, which is stored in a contiguous buffer. The packet is parsed 1902df8bae1dSRodney W. Grimes * by each process' filter, and if accepted, stashed into the corresponding 1903df8bae1dSRodney W. Grimes * buffer. 1904df8bae1dSRodney W. Grimes */ 1905df8bae1dSRodney W. Grimes void 190619ba8395SChristian S.J. Peron bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen) 1907df8bae1dSRodney W. Grimes { 1908547d94bdSJung-uk Kim struct bintime bt; 19098994a245SDag-Erling Smørgrav struct bpf_d *d; 1910a36599ccSJung-uk Kim #ifdef BPF_JITTER 1911a36599ccSJung-uk Kim bpf_jit_filter *bf; 1912a36599ccSJung-uk Kim #endif 1913253a3814SLawrence Stewart u_int slen; 1914253a3814SLawrence Stewart int gottime; 1915e7bb21b3SJonathan Lemon 1916253a3814SLawrence Stewart gottime = BPF_TSTAMP_NONE; 1917e4b3229aSAlexander V. Chernikov 1918e4b3229aSAlexander V. Chernikov BPFIF_RLOCK(bp); 1919e4b3229aSAlexander V. Chernikov 19204a3feeaaSRobert Watson LIST_FOREACH(d, &bp->bif_dlist, bd_next) { 1921e4b3229aSAlexander V. Chernikov /* 1922e4b3229aSAlexander V. Chernikov * We are not using any locks for d here because: 1923e4b3229aSAlexander V. Chernikov * 1) any filter change is protected by interface 1924e4b3229aSAlexander V. Chernikov * write lock 1925e4b3229aSAlexander V. Chernikov * 2) destroying/detaching d is protected by interface 1926e4b3229aSAlexander V. Chernikov * write lock, too 1927e4b3229aSAlexander V. Chernikov */ 1928e4b3229aSAlexander V. Chernikov 1929e4b3229aSAlexander V. Chernikov /* XXX: Do not protect counter for the sake of performance. */ 1930df8bae1dSRodney W. Grimes ++d->bd_rcount; 1931a05cf8c6SChristian S.J. Peron /* 1932a05cf8c6SChristian S.J. Peron * NB: We dont call BPF_CHECK_DIRECTION() here since there is no 1933a05cf8c6SChristian S.J. Peron * way for the caller to indiciate to us whether this packet 1934a05cf8c6SChristian S.J. Peron * is inbound or outbound. In the bpf_mtap() routines, we use 1935a05cf8c6SChristian S.J. Peron * the interface pointers on the mbuf to figure it out. 1936a05cf8c6SChristian S.J. Peron */ 1937ae275efcSJung-uk Kim #ifdef BPF_JITTER 1938a36599ccSJung-uk Kim bf = bpf_jitter_enable != 0 ? d->bd_bfilter : NULL; 1939a36599ccSJung-uk Kim if (bf != NULL) 1940a36599ccSJung-uk Kim slen = (*(bf->func))(pkt, pktlen, pktlen); 1941ae275efcSJung-uk Kim else 1942ae275efcSJung-uk Kim #endif 194393e39f0bSChristian S.J. Peron slen = bpf_filter(d->bd_rfilter, pkt, pktlen, pktlen); 1944ec272d87SRobert Watson if (slen != 0) { 1945e4b3229aSAlexander V. Chernikov /* 1946e4b3229aSAlexander V. Chernikov * Filter matches. Let's to acquire write lock. 1947e4b3229aSAlexander V. Chernikov */ 1948e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 1949e4b3229aSAlexander V. Chernikov 195069f7644bSChristian S.J. Peron d->bd_fcount++; 1951253a3814SLawrence Stewart if (gottime < bpf_ts_quality(d->bd_tstamp)) 1952253a3814SLawrence Stewart gottime = bpf_gettime(&bt, d->bd_tstamp, NULL); 1953ec272d87SRobert Watson #ifdef MAC 195430d239bcSRobert Watson if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) 1955ec272d87SRobert Watson #endif 19564d621040SChristian S.J. Peron catchpacket(d, pkt, pktlen, slen, 1957547d94bdSJung-uk Kim bpf_append_bytes, &bt); 1958e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 1959ec272d87SRobert Watson } 1960df8bae1dSRodney W. Grimes } 1961e4b3229aSAlexander V. Chernikov BPFIF_RUNLOCK(bp); 1962df8bae1dSRodney W. Grimes } 1963df8bae1dSRodney W. Grimes 1964f81a2a49SJung-uk Kim #define BPF_CHECK_DIRECTION(d, r, i) \ 1965f81a2a49SJung-uk Kim (((d)->bd_direction == BPF_D_IN && (r) != (i)) || \ 1966f81a2a49SJung-uk Kim ((d)->bd_direction == BPF_D_OUT && (r) == (i))) 1967560a54e1SJung-uk Kim 1968df8bae1dSRodney W. Grimes /* 1969df8bae1dSRodney W. Grimes * Incoming linkage from device drivers, when packet is in an mbuf chain. 1970e4b3229aSAlexander V. Chernikov * Locking model is explained in bpf_tap(). 1971df8bae1dSRodney W. Grimes */ 1972df8bae1dSRodney W. Grimes void 197319ba8395SChristian S.J. Peron bpf_mtap(struct bpf_if *bp, struct mbuf *m) 1974df8bae1dSRodney W. Grimes { 1975547d94bdSJung-uk Kim struct bintime bt; 1976df8bae1dSRodney W. Grimes struct bpf_d *d; 1977a36599ccSJung-uk Kim #ifdef BPF_JITTER 1978a36599ccSJung-uk Kim bpf_jit_filter *bf; 1979a36599ccSJung-uk Kim #endif 1980253a3814SLawrence Stewart u_int pktlen, slen; 1981253a3814SLawrence Stewart int gottime; 198291433904SDavid Malone 19838cd892f7SJung-uk Kim /* Skip outgoing duplicate packets. */ 19848cd892f7SJung-uk Kim if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { 19858cd892f7SJung-uk Kim m->m_flags &= ~M_PROMISC; 19868cd892f7SJung-uk Kim return; 19878cd892f7SJung-uk Kim } 19888cd892f7SJung-uk Kim 1989f0e2422bSPoul-Henning Kamp pktlen = m_length(m, NULL); 1990253a3814SLawrence Stewart gottime = BPF_TSTAMP_NONE; 1991e4b3229aSAlexander V. Chernikov 1992e4b3229aSAlexander V. Chernikov BPFIF_RLOCK(bp); 1993e4b3229aSAlexander V. Chernikov 19944a3feeaaSRobert Watson LIST_FOREACH(d, &bp->bif_dlist, bd_next) { 1995f81a2a49SJung-uk Kim if (BPF_CHECK_DIRECTION(d, m->m_pkthdr.rcvif, bp->bif_ifp)) 19968ed3828cSRobert Watson continue; 1997df8bae1dSRodney W. Grimes ++d->bd_rcount; 1998ae275efcSJung-uk Kim #ifdef BPF_JITTER 1999a36599ccSJung-uk Kim bf = bpf_jitter_enable != 0 ? d->bd_bfilter : NULL; 2000ae275efcSJung-uk Kim /* XXX We cannot handle multiple mbufs. */ 2001a36599ccSJung-uk Kim if (bf != NULL && m->m_next == NULL) 2002a36599ccSJung-uk Kim slen = (*(bf->func))(mtod(m, u_char *), pktlen, pktlen); 2003ae275efcSJung-uk Kim else 2004ae275efcSJung-uk Kim #endif 200593e39f0bSChristian S.J. Peron slen = bpf_filter(d->bd_rfilter, (u_char *)m, pktlen, 0); 20064ddfb531SChristian S.J. Peron if (slen != 0) { 2007e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 2008e4b3229aSAlexander V. Chernikov 200969f7644bSChristian S.J. Peron d->bd_fcount++; 2010253a3814SLawrence Stewart if (gottime < bpf_ts_quality(d->bd_tstamp)) 2011253a3814SLawrence Stewart gottime = bpf_gettime(&bt, d->bd_tstamp, m); 20120c7fb534SRobert Watson #ifdef MAC 201330d239bcSRobert Watson if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) 20140c7fb534SRobert Watson #endif 20150c7fb534SRobert Watson catchpacket(d, (u_char *)m, pktlen, slen, 2016547d94bdSJung-uk Kim bpf_append_mbuf, &bt); 2017e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 20184ddfb531SChristian S.J. Peron } 2019df8bae1dSRodney W. Grimes } 2020e4b3229aSAlexander V. Chernikov BPFIF_RUNLOCK(bp); 2021df8bae1dSRodney W. Grimes } 2022df8bae1dSRodney W. Grimes 2023df8bae1dSRodney W. Grimes /* 2024437ffe18SSam Leffler * Incoming linkage from device drivers, when packet is in 2025437ffe18SSam Leffler * an mbuf chain and to be prepended by a contiguous header. 2026437ffe18SSam Leffler */ 2027437ffe18SSam Leffler void 202819ba8395SChristian S.J. Peron bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m) 2029437ffe18SSam Leffler { 2030547d94bdSJung-uk Kim struct bintime bt; 2031437ffe18SSam Leffler struct mbuf mb; 2032437ffe18SSam Leffler struct bpf_d *d; 2033253a3814SLawrence Stewart u_int pktlen, slen; 2034253a3814SLawrence Stewart int gottime; 203591433904SDavid Malone 20368cd892f7SJung-uk Kim /* Skip outgoing duplicate packets. */ 20378cd892f7SJung-uk Kim if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { 20388cd892f7SJung-uk Kim m->m_flags &= ~M_PROMISC; 20398cd892f7SJung-uk Kim return; 20408cd892f7SJung-uk Kim } 20418cd892f7SJung-uk Kim 2042437ffe18SSam Leffler pktlen = m_length(m, NULL); 2043437ffe18SSam Leffler /* 2044437ffe18SSam Leffler * Craft on-stack mbuf suitable for passing to bpf_filter. 2045437ffe18SSam Leffler * Note that we cut corners here; we only setup what's 2046437ffe18SSam Leffler * absolutely needed--this mbuf should never go anywhere else. 2047437ffe18SSam Leffler */ 2048437ffe18SSam Leffler mb.m_next = m; 2049437ffe18SSam Leffler mb.m_data = data; 2050437ffe18SSam Leffler mb.m_len = dlen; 2051437ffe18SSam Leffler pktlen += dlen; 2052437ffe18SSam Leffler 2053253a3814SLawrence Stewart gottime = BPF_TSTAMP_NONE; 2054e4b3229aSAlexander V. Chernikov 2055e4b3229aSAlexander V. Chernikov BPFIF_RLOCK(bp); 2056e4b3229aSAlexander V. Chernikov 20574a3feeaaSRobert Watson LIST_FOREACH(d, &bp->bif_dlist, bd_next) { 2058f81a2a49SJung-uk Kim if (BPF_CHECK_DIRECTION(d, m->m_pkthdr.rcvif, bp->bif_ifp)) 2059437ffe18SSam Leffler continue; 2060437ffe18SSam Leffler ++d->bd_rcount; 206193e39f0bSChristian S.J. Peron slen = bpf_filter(d->bd_rfilter, (u_char *)&mb, pktlen, 0); 20624ddfb531SChristian S.J. Peron if (slen != 0) { 2063e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 2064e4b3229aSAlexander V. Chernikov 206569f7644bSChristian S.J. Peron d->bd_fcount++; 2066253a3814SLawrence Stewart if (gottime < bpf_ts_quality(d->bd_tstamp)) 2067253a3814SLawrence Stewart gottime = bpf_gettime(&bt, d->bd_tstamp, m); 2068437ffe18SSam Leffler #ifdef MAC 206930d239bcSRobert Watson if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) 2070437ffe18SSam Leffler #endif 2071437ffe18SSam Leffler catchpacket(d, (u_char *)&mb, pktlen, slen, 2072547d94bdSJung-uk Kim bpf_append_mbuf, &bt); 2073e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 20744ddfb531SChristian S.J. Peron } 2075437ffe18SSam Leffler } 2076e4b3229aSAlexander V. Chernikov BPFIF_RUNLOCK(bp); 2077437ffe18SSam Leffler } 2078437ffe18SSam Leffler 2079560a54e1SJung-uk Kim #undef BPF_CHECK_DIRECTION 2080560a54e1SJung-uk Kim 2081253a3814SLawrence Stewart #undef BPF_TSTAMP_NONE 2082253a3814SLawrence Stewart #undef BPF_TSTAMP_FAST 2083253a3814SLawrence Stewart #undef BPF_TSTAMP_NORMAL 2084253a3814SLawrence Stewart #undef BPF_TSTAMP_EXTERN 2085253a3814SLawrence Stewart 2086547d94bdSJung-uk Kim static int 2087547d94bdSJung-uk Kim bpf_hdrlen(struct bpf_d *d) 2088547d94bdSJung-uk Kim { 2089547d94bdSJung-uk Kim int hdrlen; 2090547d94bdSJung-uk Kim 2091547d94bdSJung-uk Kim hdrlen = d->bd_bif->bif_hdrlen; 2092547d94bdSJung-uk Kim #ifndef BURN_BRIDGES 2093547d94bdSJung-uk Kim if (d->bd_tstamp == BPF_T_NONE || 2094547d94bdSJung-uk Kim BPF_T_FORMAT(d->bd_tstamp) == BPF_T_MICROTIME) 2095547d94bdSJung-uk Kim #ifdef COMPAT_FREEBSD32 2096547d94bdSJung-uk Kim if (d->bd_compat32) 2097547d94bdSJung-uk Kim hdrlen += SIZEOF_BPF_HDR(struct bpf_hdr32); 2098547d94bdSJung-uk Kim else 2099547d94bdSJung-uk Kim #endif 2100547d94bdSJung-uk Kim hdrlen += SIZEOF_BPF_HDR(struct bpf_hdr); 2101547d94bdSJung-uk Kim else 2102547d94bdSJung-uk Kim #endif 2103547d94bdSJung-uk Kim hdrlen += SIZEOF_BPF_HDR(struct bpf_xhdr); 2104547d94bdSJung-uk Kim #ifdef COMPAT_FREEBSD32 2105547d94bdSJung-uk Kim if (d->bd_compat32) 2106547d94bdSJung-uk Kim hdrlen = BPF_WORDALIGN32(hdrlen); 2107547d94bdSJung-uk Kim else 2108547d94bdSJung-uk Kim #endif 2109547d94bdSJung-uk Kim hdrlen = BPF_WORDALIGN(hdrlen); 2110547d94bdSJung-uk Kim 2111547d94bdSJung-uk Kim return (hdrlen - d->bd_bif->bif_hdrlen); 2112547d94bdSJung-uk Kim } 2113547d94bdSJung-uk Kim 2114547d94bdSJung-uk Kim static void 2115547d94bdSJung-uk Kim bpf_bintime2ts(struct bintime *bt, struct bpf_ts *ts, int tstype) 2116547d94bdSJung-uk Kim { 2117253a3814SLawrence Stewart struct bintime bt2; 2118547d94bdSJung-uk Kim struct timeval tsm; 2119547d94bdSJung-uk Kim struct timespec tsn; 2120547d94bdSJung-uk Kim 2121253a3814SLawrence Stewart if ((tstype & BPF_T_MONOTONIC) == 0) { 2122253a3814SLawrence Stewart bt2 = *bt; 2123253a3814SLawrence Stewart bintime_add(&bt2, &boottimebin); 2124253a3814SLawrence Stewart bt = &bt2; 2125253a3814SLawrence Stewart } 2126547d94bdSJung-uk Kim switch (BPF_T_FORMAT(tstype)) { 2127547d94bdSJung-uk Kim case BPF_T_MICROTIME: 2128547d94bdSJung-uk Kim bintime2timeval(bt, &tsm); 2129547d94bdSJung-uk Kim ts->bt_sec = tsm.tv_sec; 2130547d94bdSJung-uk Kim ts->bt_frac = tsm.tv_usec; 2131547d94bdSJung-uk Kim break; 2132547d94bdSJung-uk Kim case BPF_T_NANOTIME: 2133547d94bdSJung-uk Kim bintime2timespec(bt, &tsn); 2134547d94bdSJung-uk Kim ts->bt_sec = tsn.tv_sec; 2135547d94bdSJung-uk Kim ts->bt_frac = tsn.tv_nsec; 2136547d94bdSJung-uk Kim break; 2137547d94bdSJung-uk Kim case BPF_T_BINTIME: 2138547d94bdSJung-uk Kim ts->bt_sec = bt->sec; 2139547d94bdSJung-uk Kim ts->bt_frac = bt->frac; 2140547d94bdSJung-uk Kim break; 2141547d94bdSJung-uk Kim } 2142547d94bdSJung-uk Kim } 2143547d94bdSJung-uk Kim 2144437ffe18SSam Leffler /* 2145df8bae1dSRodney W. Grimes * Move the packet data from interface memory (pkt) into the 21469e610888SDag-Erling Smørgrav * store buffer. "cpfn" is the routine called to do the actual data 2147df8bae1dSRodney W. Grimes * transfer. bcopy is passed in to copy contiguous chunks, while 21484d621040SChristian S.J. Peron * bpf_append_mbuf is passed in to copy mbuf chains. In the latter case, 2149df8bae1dSRodney W. Grimes * pkt is really an mbuf. 2150df8bae1dSRodney W. Grimes */ 2151df8bae1dSRodney W. Grimes static void 215219ba8395SChristian S.J. Peron catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen, 21534d621040SChristian S.J. Peron void (*cpfn)(struct bpf_d *, caddr_t, u_int, void *, u_int), 2154547d94bdSJung-uk Kim struct bintime *bt) 2155df8bae1dSRodney W. Grimes { 2156547d94bdSJung-uk Kim struct bpf_xhdr hdr; 2157547d94bdSJung-uk Kim #ifndef BURN_BRIDGES 2158547d94bdSJung-uk Kim struct bpf_hdr hdr_old; 2159fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 2160547d94bdSJung-uk Kim struct bpf_hdr32 hdr32_old; 2161fc0a61a4SKonstantin Belousov #endif 2162547d94bdSJung-uk Kim #endif 2163547d94bdSJung-uk Kim int caplen, curlen, hdrlen, totlen; 21647819da79SJohn-Mark Gurney int do_wakeup = 0; 2165547d94bdSJung-uk Kim int do_timestamp; 2166547d94bdSJung-uk Kim int tstype; 21679e610888SDag-Erling Smørgrav 2168e4b3229aSAlexander V. Chernikov BPFD_WLOCK_ASSERT(d); 21694d621040SChristian S.J. Peron 21704d621040SChristian S.J. Peron /* 21714d621040SChristian S.J. Peron * Detect whether user space has released a buffer back to us, and if 21724d621040SChristian S.J. Peron * so, move it from being a hold buffer to a free buffer. This may 21734d621040SChristian S.J. Peron * not be the best place to do it (for example, we might only want to 21744d621040SChristian S.J. Peron * run this check if we need the space), but for now it's a reliable 21754d621040SChristian S.J. Peron * spot to do it. 21764d621040SChristian S.J. Peron */ 2177fa0c2b34SRobert Watson if (d->bd_fbuf == NULL && bpf_canfreebuf(d)) { 21784d621040SChristian S.J. Peron d->bd_fbuf = d->bd_hbuf; 21794d621040SChristian S.J. Peron d->bd_hbuf = NULL; 21804d621040SChristian S.J. Peron d->bd_hlen = 0; 218129f612ecSChristian S.J. Peron bpf_buf_reclaimed(d); 21824d621040SChristian S.J. Peron } 21834d621040SChristian S.J. Peron 2184df8bae1dSRodney W. Grimes /* 2185df8bae1dSRodney W. Grimes * Figure out how many bytes to move. If the packet is 2186df8bae1dSRodney W. Grimes * greater or equal to the snapshot length, transfer that 2187df8bae1dSRodney W. Grimes * much. Otherwise, transfer the whole packet (unless 2188df8bae1dSRodney W. Grimes * we hit the buffer size limit). 2189df8bae1dSRodney W. Grimes */ 2190547d94bdSJung-uk Kim hdrlen = bpf_hdrlen(d); 2191df8bae1dSRodney W. Grimes totlen = hdrlen + min(snaplen, pktlen); 2192df8bae1dSRodney W. Grimes if (totlen > d->bd_bufsize) 2193df8bae1dSRodney W. Grimes totlen = d->bd_bufsize; 2194df8bae1dSRodney W. Grimes 2195df8bae1dSRodney W. Grimes /* 2196df8bae1dSRodney W. Grimes * Round up the end of the previous packet to the next longword. 2197a7a91e65SRobert Watson * 2198a7a91e65SRobert Watson * Drop the packet if there's no room and no hope of room 2199a7a91e65SRobert Watson * If the packet would overflow the storage buffer or the storage 2200a7a91e65SRobert Watson * buffer is considered immutable by the buffer model, try to rotate 2201a7a91e65SRobert Watson * the buffer and wakeup pending processes. 2202df8bae1dSRodney W. Grimes */ 2203fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 2204fc0a61a4SKonstantin Belousov if (d->bd_compat32) 2205fc0a61a4SKonstantin Belousov curlen = BPF_WORDALIGN32(d->bd_slen); 2206fc0a61a4SKonstantin Belousov else 2207fc0a61a4SKonstantin Belousov #endif 2208df8bae1dSRodney W. Grimes curlen = BPF_WORDALIGN(d->bd_slen); 2209a7a91e65SRobert Watson if (curlen + totlen > d->bd_bufsize || !bpf_canwritebuf(d)) { 2210572bde2aSRobert Watson if (d->bd_fbuf == NULL) { 2211df8bae1dSRodney W. Grimes /* 2212a7a91e65SRobert Watson * There's no room in the store buffer, and no 2213a7a91e65SRobert Watson * prospect of room, so drop the packet. Notify the 2214a7a91e65SRobert Watson * buffer model. 2215df8bae1dSRodney W. Grimes */ 2216a7a91e65SRobert Watson bpf_buffull(d); 2217df8bae1dSRodney W. Grimes ++d->bd_dcount; 2218df8bae1dSRodney W. Grimes return; 2219df8bae1dSRodney W. Grimes } 2220df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 22217819da79SJohn-Mark Gurney do_wakeup = 1; 2222df8bae1dSRodney W. Grimes curlen = 0; 2223a7a91e65SRobert Watson } else if (d->bd_immediate || d->bd_state == BPF_TIMED_OUT) 2224df8bae1dSRodney W. Grimes /* 22254d621040SChristian S.J. Peron * Immediate mode is set, or the read timeout has already 22264d621040SChristian S.J. Peron * expired during a select call. A packet arrived, so the 22274d621040SChristian S.J. Peron * reader should be woken up. 2228df8bae1dSRodney W. Grimes */ 22297819da79SJohn-Mark Gurney do_wakeup = 1; 2230547d94bdSJung-uk Kim caplen = totlen - hdrlen; 2231547d94bdSJung-uk Kim tstype = d->bd_tstamp; 2232547d94bdSJung-uk Kim do_timestamp = tstype != BPF_T_NONE; 2233547d94bdSJung-uk Kim #ifndef BURN_BRIDGES 2234547d94bdSJung-uk Kim if (tstype == BPF_T_NONE || BPF_T_FORMAT(tstype) == BPF_T_MICROTIME) { 2235547d94bdSJung-uk Kim struct bpf_ts ts; 2236547d94bdSJung-uk Kim if (do_timestamp) 2237547d94bdSJung-uk Kim bpf_bintime2ts(bt, &ts, tstype); 2238fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 2239fc0a61a4SKonstantin Belousov if (d->bd_compat32) { 2240547d94bdSJung-uk Kim bzero(&hdr32_old, sizeof(hdr32_old)); 2241547d94bdSJung-uk Kim if (do_timestamp) { 2242547d94bdSJung-uk Kim hdr32_old.bh_tstamp.tv_sec = ts.bt_sec; 2243547d94bdSJung-uk Kim hdr32_old.bh_tstamp.tv_usec = ts.bt_frac; 2244547d94bdSJung-uk Kim } 2245547d94bdSJung-uk Kim hdr32_old.bh_datalen = pktlen; 2246547d94bdSJung-uk Kim hdr32_old.bh_hdrlen = hdrlen; 2247547d94bdSJung-uk Kim hdr32_old.bh_caplen = caplen; 2248547d94bdSJung-uk Kim bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr32_old, 2249547d94bdSJung-uk Kim sizeof(hdr32_old)); 2250547d94bdSJung-uk Kim goto copy; 2251547d94bdSJung-uk Kim } 2252547d94bdSJung-uk Kim #endif 2253547d94bdSJung-uk Kim bzero(&hdr_old, sizeof(hdr_old)); 2254547d94bdSJung-uk Kim if (do_timestamp) { 2255547d94bdSJung-uk Kim hdr_old.bh_tstamp.tv_sec = ts.bt_sec; 2256547d94bdSJung-uk Kim hdr_old.bh_tstamp.tv_usec = ts.bt_frac; 2257547d94bdSJung-uk Kim } 2258547d94bdSJung-uk Kim hdr_old.bh_datalen = pktlen; 2259547d94bdSJung-uk Kim hdr_old.bh_hdrlen = hdrlen; 2260547d94bdSJung-uk Kim hdr_old.bh_caplen = caplen; 2261547d94bdSJung-uk Kim bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr_old, 2262547d94bdSJung-uk Kim sizeof(hdr_old)); 2263fc0a61a4SKonstantin Belousov goto copy; 2264fc0a61a4SKonstantin Belousov } 2265fc0a61a4SKonstantin Belousov #endif 2266df8bae1dSRodney W. Grimes 2267df8bae1dSRodney W. Grimes /* 22684d621040SChristian S.J. Peron * Append the bpf header. Note we append the actual header size, but 22694d621040SChristian S.J. Peron * move forward the length of the header plus padding. 2270df8bae1dSRodney W. Grimes */ 22714d621040SChristian S.J. Peron bzero(&hdr, sizeof(hdr)); 2272547d94bdSJung-uk Kim if (do_timestamp) 2273547d94bdSJung-uk Kim bpf_bintime2ts(bt, &hdr.bh_tstamp, tstype); 22744d621040SChristian S.J. Peron hdr.bh_datalen = pktlen; 22754d621040SChristian S.J. Peron hdr.bh_hdrlen = hdrlen; 2276547d94bdSJung-uk Kim hdr.bh_caplen = caplen; 22774d621040SChristian S.J. Peron bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr, sizeof(hdr)); 22784d621040SChristian S.J. Peron 2279df8bae1dSRodney W. Grimes /* 2280df8bae1dSRodney W. Grimes * Copy the packet data into the store buffer and update its length. 2281df8bae1dSRodney W. Grimes */ 2282547d94bdSJung-uk Kim #ifndef BURN_BRIDGES 2283fc0a61a4SKonstantin Belousov copy: 2284fc0a61a4SKonstantin Belousov #endif 2285547d94bdSJung-uk Kim (*cpfn)(d, d->bd_sbuf, curlen + hdrlen, pkt, caplen); 2286df8bae1dSRodney W. Grimes d->bd_slen = curlen + totlen; 22877819da79SJohn-Mark Gurney 22887819da79SJohn-Mark Gurney if (do_wakeup) 22897819da79SJohn-Mark Gurney bpf_wakeup(d); 2290df8bae1dSRodney W. Grimes } 2291df8bae1dSRodney W. Grimes 2292df8bae1dSRodney W. Grimes /* 2293df8bae1dSRodney W. Grimes * Free buffers currently in use by a descriptor. 2294df8bae1dSRodney W. Grimes * Called on close. 2295df8bae1dSRodney W. Grimes */ 2296df8bae1dSRodney W. Grimes static void 229719ba8395SChristian S.J. Peron bpf_freed(struct bpf_d *d) 2298df8bae1dSRodney W. Grimes { 22994d621040SChristian S.J. Peron 2300df8bae1dSRodney W. Grimes /* 2301df8bae1dSRodney W. Grimes * We don't need to lock out interrupts since this descriptor has 2302df8bae1dSRodney W. Grimes * been detached from its interface and it yet hasn't been marked 2303df8bae1dSRodney W. Grimes * free. 2304df8bae1dSRodney W. Grimes */ 23054d621040SChristian S.J. Peron bpf_free(d); 230670485847SJung-uk Kim if (d->bd_rfilter != NULL) { 230793e39f0bSChristian S.J. Peron free((caddr_t)d->bd_rfilter, M_BPF); 2308ae275efcSJung-uk Kim #ifdef BPF_JITTER 230970485847SJung-uk Kim if (d->bd_bfilter != NULL) 2310ae275efcSJung-uk Kim bpf_destroy_jit_filter(d->bd_bfilter); 2311ae275efcSJung-uk Kim #endif 2312ae275efcSJung-uk Kim } 231370485847SJung-uk Kim if (d->bd_wfilter != NULL) 231493e39f0bSChristian S.J. Peron free((caddr_t)d->bd_wfilter, M_BPF); 2315e4b3229aSAlexander V. Chernikov rw_destroy(&d->bd_lock); 2316df8bae1dSRodney W. Grimes } 2317df8bae1dSRodney W. Grimes 2318df8bae1dSRodney W. Grimes /* 231924a229f4SSam Leffler * Attach an interface to bpf. dlt is the link layer type; hdrlen is the 232024a229f4SSam Leffler * fixed size of the link header (variable length headers not yet supported). 2321df8bae1dSRodney W. Grimes */ 2322df8bae1dSRodney W. Grimes void 232319ba8395SChristian S.J. Peron bpfattach(struct ifnet *ifp, u_int dlt, u_int hdrlen) 2324df8bae1dSRodney W. Grimes { 232524a229f4SSam Leffler 232624a229f4SSam Leffler bpfattach2(ifp, dlt, hdrlen, &ifp->if_bpf); 232724a229f4SSam Leffler } 232824a229f4SSam Leffler 232924a229f4SSam Leffler /* 233024a229f4SSam Leffler * Attach an interface to bpf. ifp is a pointer to the structure 233124a229f4SSam Leffler * defining the interface to be attached, dlt is the link layer type, 233224a229f4SSam Leffler * and hdrlen is the fixed size of the link header (variable length 233324a229f4SSam Leffler * headers are not yet supporrted). 233424a229f4SSam Leffler */ 233524a229f4SSam Leffler void 233619ba8395SChristian S.J. Peron bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp) 233724a229f4SSam Leffler { 2338df8bae1dSRodney W. Grimes struct bpf_if *bp; 233919ba8395SChristian S.J. Peron 234019ba8395SChristian S.J. Peron bp = malloc(sizeof(*bp), M_BPF, M_NOWAIT | M_ZERO); 2341572bde2aSRobert Watson if (bp == NULL) 2342df8bae1dSRodney W. Grimes panic("bpfattach"); 2343df8bae1dSRodney W. Grimes 23444a3feeaaSRobert Watson LIST_INIT(&bp->bif_dlist); 2345*51ec1eb7SAlexander V. Chernikov LIST_INIT(&bp->bif_wlist); 2346df8bae1dSRodney W. Grimes bp->bif_ifp = ifp; 2347df8bae1dSRodney W. Grimes bp->bif_dlt = dlt; 2348e4b3229aSAlexander V. Chernikov rw_init(&bp->bif_lock, "bpf interface lock"); 234916d878ccSChristian S.J. Peron KASSERT(*driverp == NULL, ("bpfattach2: driverp already initialized")); 235016d878ccSChristian S.J. Peron *driverp = bp; 2351df8bae1dSRodney W. Grimes 2352e4b3229aSAlexander V. Chernikov BPF_LOCK(); 23534a3feeaaSRobert Watson LIST_INSERT_HEAD(&bpf_iflist, bp, bif_next); 2354e4b3229aSAlexander V. Chernikov BPF_UNLOCK(); 2355df8bae1dSRodney W. Grimes 2356547d94bdSJung-uk Kim bp->bif_hdrlen = hdrlen; 2357df8bae1dSRodney W. Grimes 23582eeab939SGarrett Wollman if (bootverbose) 235924a229f4SSam Leffler if_printf(ifp, "bpf attached\n"); 2360df8bae1dSRodney W. Grimes } 236153ac6efbSJulian Elischer 2362de5d9935SRobert Watson /* 2363de5d9935SRobert Watson * Detach bpf from an interface. This involves detaching each descriptor 2364de5d9935SRobert Watson * associated with the interface, and leaving bd_bif NULL. Notify each 2365de5d9935SRobert Watson * descriptor as it's detached so that any sleepers wake up and get 2366de5d9935SRobert Watson * ENXIO. 2367de5d9935SRobert Watson */ 2368de5d9935SRobert Watson void 236919ba8395SChristian S.J. Peron bpfdetach(struct ifnet *ifp) 2370de5d9935SRobert Watson { 23714a3feeaaSRobert Watson struct bpf_if *bp; 2372de5d9935SRobert Watson struct bpf_d *d; 23739a7e6bacSLawrence Stewart #ifdef INVARIANTS 23749a7e6bacSLawrence Stewart int ndetached; 2375de5d9935SRobert Watson 23769a7e6bacSLawrence Stewart ndetached = 0; 23779a7e6bacSLawrence Stewart #endif 23789a7e6bacSLawrence Stewart 23799a7e6bacSLawrence Stewart /* Find all bpf_if struct's which reference ifp and detach them. */ 23809a7e6bacSLawrence Stewart do { 2381e4b3229aSAlexander V. Chernikov BPF_LOCK(); 23824a3feeaaSRobert Watson LIST_FOREACH(bp, &bpf_iflist, bif_next) { 2383de5d9935SRobert Watson if (ifp == bp->bif_ifp) 2384de5d9935SRobert Watson break; 2385de5d9935SRobert Watson } 23869a7e6bacSLawrence Stewart if (bp != NULL) 23874a3feeaaSRobert Watson LIST_REMOVE(bp, bif_next); 2388e4b3229aSAlexander V. Chernikov BPF_UNLOCK(); 2389de5d9935SRobert Watson 23909a7e6bacSLawrence Stewart if (bp != NULL) { 23919a7e6bacSLawrence Stewart #ifdef INVARIANTS 23929a7e6bacSLawrence Stewart ndetached++; 23939a7e6bacSLawrence Stewart #endif 23944a3feeaaSRobert Watson while ((d = LIST_FIRST(&bp->bif_dlist)) != NULL) { 2395e7bb21b3SJonathan Lemon bpf_detachd(d); 2396e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 2397e7bb21b3SJonathan Lemon bpf_wakeup(d); 2398e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 2399e7bb21b3SJonathan Lemon } 2400e4b3229aSAlexander V. Chernikov rw_destroy(&bp->bif_lock); 2401de5d9935SRobert Watson free(bp, M_BPF); 24028eab61f3SSam Leffler } 24039a7e6bacSLawrence Stewart } while (bp != NULL); 24049a7e6bacSLawrence Stewart 24059a7e6bacSLawrence Stewart #ifdef INVARIANTS 24069a7e6bacSLawrence Stewart if (ndetached == 0) 24079a7e6bacSLawrence Stewart printf("bpfdetach: %s was not attached\n", ifp->if_xname); 24089a7e6bacSLawrence Stewart #endif 24099a7e6bacSLawrence Stewart } 2410de5d9935SRobert Watson 24118eab61f3SSam Leffler /* 24128eab61f3SSam Leffler * Get a list of available data link type of the interface. 24138eab61f3SSam Leffler */ 24148eab61f3SSam Leffler static int 241519ba8395SChristian S.J. Peron bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *bfl) 24168eab61f3SSam Leffler { 24178eab61f3SSam Leffler int n, error; 24188eab61f3SSam Leffler struct ifnet *ifp; 24198eab61f3SSam Leffler struct bpf_if *bp; 24208eab61f3SSam Leffler 24218eab61f3SSam Leffler ifp = d->bd_bif->bif_ifp; 24228eab61f3SSam Leffler n = 0; 24238eab61f3SSam Leffler error = 0; 2424e4b3229aSAlexander V. Chernikov BPF_LOCK(); 24254a3feeaaSRobert Watson LIST_FOREACH(bp, &bpf_iflist, bif_next) { 24268eab61f3SSam Leffler if (bp->bif_ifp != ifp) 24278eab61f3SSam Leffler continue; 24288eab61f3SSam Leffler if (bfl->bfl_list != NULL) { 24298eab61f3SSam Leffler if (n >= bfl->bfl_len) { 2430e4b3229aSAlexander V. Chernikov BPF_UNLOCK(); 24318eab61f3SSam Leffler return (ENOMEM); 24328eab61f3SSam Leffler } 24338eab61f3SSam Leffler error = copyout(&bp->bif_dlt, 24348eab61f3SSam Leffler bfl->bfl_list + n, sizeof(u_int)); 24358eab61f3SSam Leffler } 24368eab61f3SSam Leffler n++; 24378eab61f3SSam Leffler } 2438e4b3229aSAlexander V. Chernikov BPF_UNLOCK(); 24398eab61f3SSam Leffler bfl->bfl_len = n; 24408eab61f3SSam Leffler return (error); 24418eab61f3SSam Leffler } 24428eab61f3SSam Leffler 24438eab61f3SSam Leffler /* 24448eab61f3SSam Leffler * Set the data link type of a BPF instance. 24458eab61f3SSam Leffler */ 24468eab61f3SSam Leffler static int 244719ba8395SChristian S.J. Peron bpf_setdlt(struct bpf_d *d, u_int dlt) 24488eab61f3SSam Leffler { 24498eab61f3SSam Leffler int error, opromisc; 24508eab61f3SSam Leffler struct ifnet *ifp; 24518eab61f3SSam Leffler struct bpf_if *bp; 24528eab61f3SSam Leffler 24538eab61f3SSam Leffler if (d->bd_bif->bif_dlt == dlt) 24548eab61f3SSam Leffler return (0); 24558eab61f3SSam Leffler ifp = d->bd_bif->bif_ifp; 2456e4b3229aSAlexander V. Chernikov BPF_LOCK(); 24574a3feeaaSRobert Watson LIST_FOREACH(bp, &bpf_iflist, bif_next) { 24588eab61f3SSam Leffler if (bp->bif_ifp == ifp && bp->bif_dlt == dlt) 24598eab61f3SSam Leffler break; 24608eab61f3SSam Leffler } 2461e4b3229aSAlexander V. Chernikov BPF_UNLOCK(); 24628eab61f3SSam Leffler if (bp != NULL) { 24638eab61f3SSam Leffler opromisc = d->bd_promisc; 24648eab61f3SSam Leffler bpf_detachd(d); 24658eab61f3SSam Leffler bpf_attachd(d, bp); 2466e4b3229aSAlexander V. Chernikov BPFD_WLOCK(d); 24678eab61f3SSam Leffler reset_d(d); 2468e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(d); 24698eab61f3SSam Leffler if (opromisc) { 24708eab61f3SSam Leffler error = ifpromisc(bp->bif_ifp, 1); 24718eab61f3SSam Leffler if (error) 24728eab61f3SSam Leffler if_printf(bp->bif_ifp, 24738eab61f3SSam Leffler "bpf_setdlt: ifpromisc failed (%d)\n", 24748eab61f3SSam Leffler error); 24758eab61f3SSam Leffler else 24768eab61f3SSam Leffler d->bd_promisc = 1; 24778eab61f3SSam Leffler } 24788eab61f3SSam Leffler } 24798eab61f3SSam Leffler return (bp == NULL ? EINVAL : 0); 2480de5d9935SRobert Watson } 2481de5d9935SRobert Watson 24823f54a085SPoul-Henning Kamp static void 248319ba8395SChristian S.J. Peron bpf_drvinit(void *unused) 248453ac6efbSJulian Elischer { 2485136600feSEd Schouten struct cdev *dev; 248653ac6efbSJulian Elischer 24876008862bSJohn Baldwin mtx_init(&bpf_mtx, "bpf global lock", NULL, MTX_DEF); 24884a3feeaaSRobert Watson LIST_INIT(&bpf_iflist); 2489136600feSEd Schouten 2490136600feSEd Schouten dev = make_dev(&bpf_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "bpf"); 2491136600feSEd Schouten /* For compatibility */ 2492136600feSEd Schouten make_dev_alias(dev, "bpf0"); 24937198bf47SJulian Elischer } 249453ac6efbSJulian Elischer 24950e37f3e1SChristian S.J. Peron /* 24960e37f3e1SChristian S.J. Peron * Zero out the various packet counters associated with all of the bpf 24970e37f3e1SChristian S.J. Peron * descriptors. At some point, we will probably want to get a bit more 24980e37f3e1SChristian S.J. Peron * granular and allow the user to specify descriptors to be zeroed. 24990e37f3e1SChristian S.J. Peron */ 25000e37f3e1SChristian S.J. Peron static void 25010e37f3e1SChristian S.J. Peron bpf_zero_counters(void) 25020e37f3e1SChristian S.J. Peron { 25030e37f3e1SChristian S.J. Peron struct bpf_if *bp; 25040e37f3e1SChristian S.J. Peron struct bpf_d *bd; 25050e37f3e1SChristian S.J. Peron 2506e4b3229aSAlexander V. Chernikov BPF_LOCK(); 25070e37f3e1SChristian S.J. Peron LIST_FOREACH(bp, &bpf_iflist, bif_next) { 2508e4b3229aSAlexander V. Chernikov BPFIF_RLOCK(bp); 25090e37f3e1SChristian S.J. Peron LIST_FOREACH(bd, &bp->bif_dlist, bd_next) { 2510e4b3229aSAlexander V. Chernikov BPFD_WLOCK(bd); 25110e37f3e1SChristian S.J. Peron bd->bd_rcount = 0; 25120e37f3e1SChristian S.J. Peron bd->bd_dcount = 0; 25130e37f3e1SChristian S.J. Peron bd->bd_fcount = 0; 25140e37f3e1SChristian S.J. Peron bd->bd_wcount = 0; 25150e37f3e1SChristian S.J. Peron bd->bd_wfcount = 0; 25160e37f3e1SChristian S.J. Peron bd->bd_zcopy = 0; 2517e4b3229aSAlexander V. Chernikov BPFD_WUNLOCK(bd); 25180e37f3e1SChristian S.J. Peron } 2519e4b3229aSAlexander V. Chernikov BPFIF_RUNLOCK(bp); 25200e37f3e1SChristian S.J. Peron } 2521e4b3229aSAlexander V. Chernikov BPF_UNLOCK(); 25220e37f3e1SChristian S.J. Peron } 25230e37f3e1SChristian S.J. Peron 252469f7644bSChristian S.J. Peron static void 252569f7644bSChristian S.J. Peron bpfstats_fill_xbpf(struct xbpf_d *d, struct bpf_d *bd) 252669f7644bSChristian S.J. Peron { 252769f7644bSChristian S.J. Peron 252869f7644bSChristian S.J. Peron bzero(d, sizeof(*d)); 252969f7644bSChristian S.J. Peron BPFD_LOCK_ASSERT(bd); 25304d621040SChristian S.J. Peron d->bd_structsize = sizeof(*d); 253169f7644bSChristian S.J. Peron d->bd_immediate = bd->bd_immediate; 253269f7644bSChristian S.J. Peron d->bd_promisc = bd->bd_promisc; 253369f7644bSChristian S.J. Peron d->bd_hdrcmplt = bd->bd_hdrcmplt; 2534560a54e1SJung-uk Kim d->bd_direction = bd->bd_direction; 2535560a54e1SJung-uk Kim d->bd_feedback = bd->bd_feedback; 253669f7644bSChristian S.J. Peron d->bd_async = bd->bd_async; 253769f7644bSChristian S.J. Peron d->bd_rcount = bd->bd_rcount; 253869f7644bSChristian S.J. Peron d->bd_dcount = bd->bd_dcount; 253969f7644bSChristian S.J. Peron d->bd_fcount = bd->bd_fcount; 254069f7644bSChristian S.J. Peron d->bd_sig = bd->bd_sig; 254169f7644bSChristian S.J. Peron d->bd_slen = bd->bd_slen; 254269f7644bSChristian S.J. Peron d->bd_hlen = bd->bd_hlen; 254369f7644bSChristian S.J. Peron d->bd_bufsize = bd->bd_bufsize; 254469f7644bSChristian S.J. Peron d->bd_pid = bd->bd_pid; 254569f7644bSChristian S.J. Peron strlcpy(d->bd_ifname, 254669f7644bSChristian S.J. Peron bd->bd_bif->bif_ifp->if_xname, IFNAMSIZ); 254793e39f0bSChristian S.J. Peron d->bd_locked = bd->bd_locked; 25484d621040SChristian S.J. Peron d->bd_wcount = bd->bd_wcount; 25494d621040SChristian S.J. Peron d->bd_wdcount = bd->bd_wdcount; 25504d621040SChristian S.J. Peron d->bd_wfcount = bd->bd_wfcount; 25514d621040SChristian S.J. Peron d->bd_zcopy = bd->bd_zcopy; 25524d621040SChristian S.J. Peron d->bd_bufmode = bd->bd_bufmode; 255369f7644bSChristian S.J. Peron } 255469f7644bSChristian S.J. Peron 255569f7644bSChristian S.J. Peron static int 255669f7644bSChristian S.J. Peron bpf_stats_sysctl(SYSCTL_HANDLER_ARGS) 255769f7644bSChristian S.J. Peron { 25580e37f3e1SChristian S.J. Peron struct xbpf_d *xbdbuf, *xbd, zerostats; 2559422a63daSChristian S.J. Peron int index, error; 256069f7644bSChristian S.J. Peron struct bpf_if *bp; 256169f7644bSChristian S.J. Peron struct bpf_d *bd; 256269f7644bSChristian S.J. Peron 256369f7644bSChristian S.J. Peron /* 256469f7644bSChristian S.J. Peron * XXX This is not technically correct. It is possible for non 256569f7644bSChristian S.J. Peron * privileged users to open bpf devices. It would make sense 256669f7644bSChristian S.J. Peron * if the users who opened the devices were able to retrieve 256769f7644bSChristian S.J. Peron * the statistics for them, too. 256869f7644bSChristian S.J. Peron */ 2569acd3428bSRobert Watson error = priv_check(req->td, PRIV_NET_BPF); 257069f7644bSChristian S.J. Peron if (error) 257169f7644bSChristian S.J. Peron return (error); 25720e37f3e1SChristian S.J. Peron /* 25730e37f3e1SChristian S.J. Peron * Check to see if the user is requesting that the counters be 25740e37f3e1SChristian S.J. Peron * zeroed out. Explicitly check that the supplied data is zeroed, 25750e37f3e1SChristian S.J. Peron * as we aren't allowing the user to set the counters currently. 25760e37f3e1SChristian S.J. Peron */ 25770e37f3e1SChristian S.J. Peron if (req->newptr != NULL) { 25780e37f3e1SChristian S.J. Peron if (req->newlen != sizeof(zerostats)) 25790e37f3e1SChristian S.J. Peron return (EINVAL); 25800e37f3e1SChristian S.J. Peron bzero(&zerostats, sizeof(zerostats)); 25810e37f3e1SChristian S.J. Peron xbd = req->newptr; 25820e37f3e1SChristian S.J. Peron if (bcmp(xbd, &zerostats, sizeof(*xbd)) != 0) 25830e37f3e1SChristian S.J. Peron return (EINVAL); 25840e37f3e1SChristian S.J. Peron bpf_zero_counters(); 25850e37f3e1SChristian S.J. Peron return (0); 25860e37f3e1SChristian S.J. Peron } 258769f7644bSChristian S.J. Peron if (req->oldptr == NULL) 2588422a63daSChristian S.J. Peron return (SYSCTL_OUT(req, 0, bpf_bpfd_cnt * sizeof(*xbd))); 258969f7644bSChristian S.J. Peron if (bpf_bpfd_cnt == 0) 259069f7644bSChristian S.J. Peron return (SYSCTL_OUT(req, 0, 0)); 2591422a63daSChristian S.J. Peron xbdbuf = malloc(req->oldlen, M_BPF, M_WAITOK); 2592e4b3229aSAlexander V. Chernikov BPF_LOCK(); 2593422a63daSChristian S.J. Peron if (req->oldlen < (bpf_bpfd_cnt * sizeof(*xbd))) { 2594e4b3229aSAlexander V. Chernikov BPF_UNLOCK(); 2595422a63daSChristian S.J. Peron free(xbdbuf, M_BPF); 2596422a63daSChristian S.J. Peron return (ENOMEM); 2597422a63daSChristian S.J. Peron } 2598422a63daSChristian S.J. Peron index = 0; 259969f7644bSChristian S.J. Peron LIST_FOREACH(bp, &bpf_iflist, bif_next) { 2600e4b3229aSAlexander V. Chernikov BPFIF_RLOCK(bp); 2601*51ec1eb7SAlexander V. Chernikov /* Send writers-only first */ 2602*51ec1eb7SAlexander V. Chernikov LIST_FOREACH(bd, &bp->bif_wlist, bd_next) { 2603*51ec1eb7SAlexander V. Chernikov xbd = &xbdbuf[index++]; 2604*51ec1eb7SAlexander V. Chernikov BPFD_RLOCK(bd); 2605*51ec1eb7SAlexander V. Chernikov bpfstats_fill_xbpf(xbd, bd); 2606*51ec1eb7SAlexander V. Chernikov BPFD_RUNLOCK(bd); 2607*51ec1eb7SAlexander V. Chernikov } 260869f7644bSChristian S.J. Peron LIST_FOREACH(bd, &bp->bif_dlist, bd_next) { 2609422a63daSChristian S.J. Peron xbd = &xbdbuf[index++]; 2610e4b3229aSAlexander V. Chernikov BPFD_RLOCK(bd); 2611422a63daSChristian S.J. Peron bpfstats_fill_xbpf(xbd, bd); 2612e4b3229aSAlexander V. Chernikov BPFD_RUNLOCK(bd); 261369f7644bSChristian S.J. Peron } 2614e4b3229aSAlexander V. Chernikov BPFIF_RUNLOCK(bp); 261569f7644bSChristian S.J. Peron } 2616e4b3229aSAlexander V. Chernikov BPF_UNLOCK(); 2617422a63daSChristian S.J. Peron error = SYSCTL_OUT(req, xbdbuf, index * sizeof(*xbd)); 2618422a63daSChristian S.J. Peron free(xbdbuf, M_BPF); 261969f7644bSChristian S.J. Peron return (error); 262069f7644bSChristian S.J. Peron } 262169f7644bSChristian S.J. Peron 2622237fdd78SRobert Watson SYSINIT(bpfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,bpf_drvinit,NULL); 262353ac6efbSJulian Elischer 26245bb5f2c9SPeter Wemm #else /* !DEV_BPF && !NETGRAPH_BPF */ 2625f8dc4716SMike Smith /* 2626f8dc4716SMike Smith * NOP stubs to allow bpf-using drivers to load and function. 2627f8dc4716SMike Smith * 2628f8dc4716SMike Smith * A 'better' implementation would allow the core bpf functionality 2629f8dc4716SMike Smith * to be loaded at runtime. 2630f8dc4716SMike Smith */ 26317eae78a4SChristian S.J. Peron static struct bpf_if bp_null; 2632f8dc4716SMike Smith 2633f8dc4716SMike Smith void 263419ba8395SChristian S.J. Peron bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen) 2635f8dc4716SMike Smith { 2636f8dc4716SMike Smith } 2637f8dc4716SMike Smith 2638f8dc4716SMike Smith void 263919ba8395SChristian S.J. Peron bpf_mtap(struct bpf_if *bp, struct mbuf *m) 2640f8dc4716SMike Smith { 2641f8dc4716SMike Smith } 2642f8dc4716SMike Smith 2643f8dc4716SMike Smith void 264419ba8395SChristian S.J. Peron bpf_mtap2(struct bpf_if *bp, void *d, u_int l, struct mbuf *m) 2645437ffe18SSam Leffler { 2646437ffe18SSam Leffler } 2647437ffe18SSam Leffler 2648437ffe18SSam Leffler void 264919ba8395SChristian S.J. Peron bpfattach(struct ifnet *ifp, u_int dlt, u_int hdrlen) 2650f8dc4716SMike Smith { 26517eae78a4SChristian S.J. Peron 26527eae78a4SChristian S.J. Peron bpfattach2(ifp, dlt, hdrlen, &ifp->if_bpf); 2653f8dc4716SMike Smith } 2654f8dc4716SMike Smith 2655da626c17SBill Paul void 265619ba8395SChristian S.J. Peron bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp) 26575f7a7923SSam Leffler { 26587eae78a4SChristian S.J. Peron 26597eae78a4SChristian S.J. Peron *driverp = &bp_null; 26605f7a7923SSam Leffler } 26615f7a7923SSam Leffler 26625f7a7923SSam Leffler void 266319ba8395SChristian S.J. Peron bpfdetach(struct ifnet *ifp) 2664da626c17SBill Paul { 2665da626c17SBill Paul } 2666da626c17SBill Paul 2667f8dc4716SMike Smith u_int 266819ba8395SChristian S.J. Peron bpf_filter(const struct bpf_insn *pc, u_char *p, u_int wirelen, u_int buflen) 2669f8dc4716SMike Smith { 2670f8dc4716SMike Smith return -1; /* "no filter" behaviour */ 2671f8dc4716SMike Smith } 2672f8dc4716SMike Smith 26735bb5f2c9SPeter Wemm int 267419ba8395SChristian S.J. Peron bpf_validate(const struct bpf_insn *f, int len) 26755bb5f2c9SPeter Wemm { 26765bb5f2c9SPeter Wemm return 0; /* false */ 26775bb5f2c9SPeter Wemm } 26785bb5f2c9SPeter Wemm 26795bb5f2c9SPeter Wemm #endif /* !DEV_BPF && !NETGRAPH_BPF */ 2680