1c398230bSWarner Losh /*- 2df8bae1dSRodney W. Grimes * Copyright (c) 1990, 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * This code is derived from the Stanford/CMU enet packet filter, 6df8bae1dSRodney W. Grimes * (net/enet.c) distributed as part of 4.3BSD, and code contributed 7df8bae1dSRodney W. Grimes * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence 8df8bae1dSRodney W. Grimes * Berkeley Laboratory. 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 19df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 20df8bae1dSRodney W. Grimes * without specific prior written permission. 21df8bae1dSRodney W. Grimes * 22df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32df8bae1dSRodney W. Grimes * SUCH DAMAGE. 33df8bae1dSRodney W. Grimes * 344f252c4dSRuslan Ermilov * @(#)bpf.c 8.4 (Berkeley) 1/9/95 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37c7866007SRobert Watson #include <sys/cdefs.h> 38c7866007SRobert Watson __FBSDID("$FreeBSD$"); 39c7866007SRobert Watson 405bb5f2c9SPeter Wemm #include "opt_bpf.h" 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> 46df8bae1dSRodney W. Grimes #include <sys/systm.h> 47ce7609a4SBruce Evans #include <sys/conf.h> 48e76eee55SPoul-Henning Kamp #include <sys/fcntl.h> 49ebd8672cSBjoern A. Zeeb #include <sys/jail.h> 504d1d4912SBruce Evans #include <sys/malloc.h> 51df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 52df8bae1dSRodney W. Grimes #include <sys/time.h> 53acd3428bSRobert Watson #include <sys/priv.h> 54df8bae1dSRodney W. Grimes #include <sys/proc.h> 550310c19fSBruce Evans #include <sys/signalvar.h> 56528f627fSBruce Evans #include <sys/filio.h> 57528f627fSBruce Evans #include <sys/sockio.h> 58528f627fSBruce Evans #include <sys/ttycom.h> 59e76eee55SPoul-Henning Kamp #include <sys/uio.h> 60df8bae1dSRodney W. Grimes 6195aab9ccSJohn-Mark Gurney #include <sys/event.h> 6295aab9ccSJohn-Mark Gurney #include <sys/file.h> 63243ac7d8SPeter Wemm #include <sys/poll.h> 6495aab9ccSJohn-Mark Gurney #include <sys/proc.h> 65df8bae1dSRodney W. Grimes 66df8bae1dSRodney W. Grimes #include <sys/socket.h> 67df8bae1dSRodney W. Grimes 68fba9235dSBruce Evans #include <net/if.h> 69df8bae1dSRodney W. Grimes #include <net/bpf.h> 704d621040SChristian S.J. Peron #include <net/bpf_buffer.h> 71ae275efcSJung-uk Kim #ifdef BPF_JITTER 72ae275efcSJung-uk Kim #include <net/bpf_jitter.h> 73ae275efcSJung-uk Kim #endif 744d621040SChristian S.J. Peron #include <net/bpf_zerocopy.h> 75df8bae1dSRodney W. Grimes #include <net/bpfdesc.h> 76530c0060SRobert Watson #include <net/vnet.h> 77df8bae1dSRodney W. Grimes 78df8bae1dSRodney W. Grimes #include <netinet/in.h> 79df8bae1dSRodney W. Grimes #include <netinet/if_ether.h> 80df8bae1dSRodney W. Grimes #include <sys/kernel.h> 81f708ef1bSPoul-Henning Kamp #include <sys/sysctl.h> 827b778b5eSEivind Eklund 83246b5467SSam Leffler #include <net80211/ieee80211_freebsd.h> 84246b5467SSam Leffler 85aed55708SRobert Watson #include <security/mac/mac_framework.h> 86aed55708SRobert Watson 874d621040SChristian S.J. Peron MALLOC_DEFINE(M_BPF, "BPF", "BPF data"); 8887f6c662SJulian Elischer 895bb5f2c9SPeter Wemm #if defined(DEV_BPF) || defined(NETGRAPH_BPF) 9053ac6efbSJulian Elischer 91df8bae1dSRodney W. Grimes #define PRINET 26 /* interruptible */ 92df8bae1dSRodney W. Grimes 93*547d94bdSJung-uk Kim #define SIZEOF_BPF_HDR(type) \ 94*547d94bdSJung-uk Kim (offsetof(type, bh_hdrlen) + sizeof(((type *)0)->bh_hdrlen)) 95*547d94bdSJung-uk Kim 96fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 97fc0a61a4SKonstantin Belousov #include <sys/mount.h> 98fc0a61a4SKonstantin Belousov #include <compat/freebsd32/freebsd32.h> 99fc0a61a4SKonstantin Belousov #define BPF_ALIGNMENT32 sizeof(int32_t) 100fc0a61a4SKonstantin Belousov #define BPF_WORDALIGN32(x) (((x)+(BPF_ALIGNMENT32-1))&~(BPF_ALIGNMENT32-1)) 101fc0a61a4SKonstantin Belousov 102*547d94bdSJung-uk Kim #ifndef BURN_BRIDGES 103fc0a61a4SKonstantin Belousov /* 104fc0a61a4SKonstantin Belousov * 32-bit version of structure prepended to each packet. We use this header 105fc0a61a4SKonstantin Belousov * instead of the standard one for 32-bit streams. We mark the a stream as 106fc0a61a4SKonstantin Belousov * 32-bit the first time we see a 32-bit compat ioctl request. 107fc0a61a4SKonstantin Belousov */ 108fc0a61a4SKonstantin Belousov struct bpf_hdr32 { 109fc0a61a4SKonstantin Belousov struct timeval32 bh_tstamp; /* time stamp */ 110fc0a61a4SKonstantin Belousov uint32_t bh_caplen; /* length of captured portion */ 111fc0a61a4SKonstantin Belousov uint32_t bh_datalen; /* original length of packet */ 112fc0a61a4SKonstantin Belousov uint16_t bh_hdrlen; /* length of bpf header (this struct 113fc0a61a4SKonstantin Belousov plus alignment padding) */ 114fc0a61a4SKonstantin Belousov }; 115*547d94bdSJung-uk Kim #endif 116fc0a61a4SKonstantin Belousov 117fc0a61a4SKonstantin Belousov struct bpf_program32 { 118fc0a61a4SKonstantin Belousov u_int bf_len; 119fc0a61a4SKonstantin Belousov uint32_t bf_insns; 120fc0a61a4SKonstantin Belousov }; 121fc0a61a4SKonstantin Belousov 122fc0a61a4SKonstantin Belousov struct bpf_dltlist32 { 123fc0a61a4SKonstantin Belousov u_int bfl_len; 124fc0a61a4SKonstantin Belousov u_int bfl_list; 125fc0a61a4SKonstantin Belousov }; 126fc0a61a4SKonstantin Belousov 127fc0a61a4SKonstantin Belousov #define BIOCSETF32 _IOW('B', 103, struct bpf_program32) 128fc0a61a4SKonstantin Belousov #define BIOCSRTIMEOUT32 _IOW('B', 109, struct timeval32) 129fc0a61a4SKonstantin Belousov #define BIOCGRTIMEOUT32 _IOR('B', 110, struct timeval32) 130fc0a61a4SKonstantin Belousov #define BIOCGDLTLIST32 _IOWR('B', 121, struct bpf_dltlist32) 131fc0a61a4SKonstantin Belousov #define BIOCSETWF32 _IOW('B', 123, struct bpf_program32) 132fc0a61a4SKonstantin Belousov #define BIOCSETFNR32 _IOW('B', 130, struct bpf_program32) 133fc0a61a4SKonstantin Belousov #endif 134fc0a61a4SKonstantin Belousov 135df8bae1dSRodney W. Grimes /* 136d1a67300SRobert Watson * bpf_iflist is a list of BPF interface structures, each corresponding to a 137d1a67300SRobert Watson * specific DLT. The same network interface might have several BPF interface 138d1a67300SRobert Watson * structures registered by different layers in the stack (i.e., 802.11 139d1a67300SRobert Watson * frames, ethernet frames, etc). 140df8bae1dSRodney W. Grimes */ 1414a3feeaaSRobert Watson static LIST_HEAD(, bpf_if) bpf_iflist; 142e7bb21b3SJonathan Lemon static struct mtx bpf_mtx; /* bpf global lock */ 14369f7644bSChristian S.J. Peron static int bpf_bpfd_cnt; 144df8bae1dSRodney W. Grimes 14519ba8395SChristian S.J. Peron static void bpf_attachd(struct bpf_d *, struct bpf_if *); 14619ba8395SChristian S.J. Peron static void bpf_detachd(struct bpf_d *); 147929ddbbbSAlfred Perlstein static void bpf_freed(struct bpf_d *); 148cb44b6dfSAndrew Thompson static int bpf_movein(struct uio *, int, struct ifnet *, struct mbuf **, 149560a54e1SJung-uk Kim struct sockaddr *, int *, struct bpf_insn *); 150929ddbbbSAlfred Perlstein static int bpf_setif(struct bpf_d *, struct ifreq *); 151929ddbbbSAlfred Perlstein static void bpf_timed_out(void *); 152e7bb21b3SJonathan Lemon static __inline void 153929ddbbbSAlfred Perlstein bpf_wakeup(struct bpf_d *); 1544d621040SChristian S.J. Peron static void catchpacket(struct bpf_d *, u_char *, u_int, u_int, 1554d621040SChristian S.J. Peron void (*)(struct bpf_d *, caddr_t, u_int, void *, u_int), 156*547d94bdSJung-uk Kim struct bintime *); 157929ddbbbSAlfred Perlstein static void reset_d(struct bpf_d *); 15893e39f0bSChristian S.J. Peron static int bpf_setf(struct bpf_d *, struct bpf_program *, u_long cmd); 1598eab61f3SSam Leffler static int bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *); 1608eab61f3SSam Leffler static int bpf_setdlt(struct bpf_d *, u_int); 16195aab9ccSJohn-Mark Gurney static void filt_bpfdetach(struct knote *); 16295aab9ccSJohn-Mark Gurney static int filt_bpfread(struct knote *, long); 163a3272e3cSChristian S.J. Peron static void bpf_drvinit(void *); 16469f7644bSChristian S.J. Peron static int bpf_stats_sysctl(SYSCTL_HANDLER_ARGS); 16569f7644bSChristian S.J. Peron 16669f7644bSChristian S.J. Peron SYSCTL_NODE(_net, OID_AUTO, bpf, CTLFLAG_RW, 0, "bpf sysctl"); 16712dc9582SJung-uk Kim int bpf_maxinsns = BPF_MAXINSNS; 16869f7644bSChristian S.J. Peron SYSCTL_INT(_net_bpf, OID_AUTO, maxinsns, CTLFLAG_RW, 16969f7644bSChristian S.J. Peron &bpf_maxinsns, 0, "Maximum bpf program instructions"); 170ffeeb924SChristian S.J. Peron static int bpf_zerocopy_enable = 0; 1714d621040SChristian S.J. Peron SYSCTL_INT(_net_bpf, OID_AUTO, zerocopy_enable, CTLFLAG_RW, 1724d621040SChristian S.J. Peron &bpf_zerocopy_enable, 0, "Enable new zero-copy BPF buffer sessions"); 17392709411SChristian S.J. Peron SYSCTL_NODE(_net_bpf, OID_AUTO, stats, CTLFLAG_MPSAFE | CTLFLAG_RW, 17469f7644bSChristian S.J. Peron bpf_stats_sysctl, "bpf statistics portal"); 175df8bae1dSRodney W. Grimes 17687f6c662SJulian Elischer static d_open_t bpfopen; 17787f6c662SJulian Elischer static d_read_t bpfread; 17887f6c662SJulian Elischer static d_write_t bpfwrite; 17987f6c662SJulian Elischer static d_ioctl_t bpfioctl; 180243ac7d8SPeter Wemm static d_poll_t bpfpoll; 18195aab9ccSJohn-Mark Gurney static d_kqfilter_t bpfkqfilter; 18287f6c662SJulian Elischer 1834e2f199eSPoul-Henning Kamp static struct cdevsw bpf_cdevsw = { 184dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 1857ac40f5fSPoul-Henning Kamp .d_open = bpfopen, 1867ac40f5fSPoul-Henning Kamp .d_read = bpfread, 1877ac40f5fSPoul-Henning Kamp .d_write = bpfwrite, 1887ac40f5fSPoul-Henning Kamp .d_ioctl = bpfioctl, 1897ac40f5fSPoul-Henning Kamp .d_poll = bpfpoll, 1907ac40f5fSPoul-Henning Kamp .d_name = "bpf", 19195aab9ccSJohn-Mark Gurney .d_kqfilter = bpfkqfilter, 1924e2f199eSPoul-Henning Kamp }; 19387f6c662SJulian Elischer 194e76d823bSRobert Watson static struct filterops bpfread_filtops = { 195e76d823bSRobert Watson .f_isfd = 1, 196e76d823bSRobert Watson .f_detach = filt_bpfdetach, 197e76d823bSRobert Watson .f_event = filt_bpfread, 198e76d823bSRobert Watson }; 19987f6c662SJulian Elischer 2004d621040SChristian S.J. Peron /* 2014d621040SChristian S.J. Peron * Wrapper functions for various buffering methods. If the set of buffer 2024d621040SChristian S.J. Peron * modes expands, we will probably want to introduce a switch data structure 2034d621040SChristian S.J. Peron * similar to protosw, et. 2044d621040SChristian S.J. Peron */ 2054d621040SChristian S.J. Peron static void 2064d621040SChristian S.J. Peron bpf_append_bytes(struct bpf_d *d, caddr_t buf, u_int offset, void *src, 2074d621040SChristian S.J. Peron u_int len) 2084d621040SChristian S.J. Peron { 2094d621040SChristian S.J. Peron 2104d621040SChristian S.J. Peron BPFD_LOCK_ASSERT(d); 2114d621040SChristian S.J. Peron 2124d621040SChristian S.J. Peron switch (d->bd_bufmode) { 2134d621040SChristian S.J. Peron case BPF_BUFMODE_BUFFER: 2144d621040SChristian S.J. Peron return (bpf_buffer_append_bytes(d, buf, offset, src, len)); 2154d621040SChristian S.J. Peron 2164d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 2174d621040SChristian S.J. Peron d->bd_zcopy++; 2184d621040SChristian S.J. Peron return (bpf_zerocopy_append_bytes(d, buf, offset, src, len)); 2194d621040SChristian S.J. Peron 2204d621040SChristian S.J. Peron default: 2214d621040SChristian S.J. Peron panic("bpf_buf_append_bytes"); 2224d621040SChristian S.J. Peron } 2234d621040SChristian S.J. Peron } 2244d621040SChristian S.J. Peron 2254d621040SChristian S.J. Peron static void 2264d621040SChristian S.J. Peron bpf_append_mbuf(struct bpf_d *d, caddr_t buf, u_int offset, void *src, 2274d621040SChristian S.J. Peron u_int len) 2284d621040SChristian S.J. Peron { 2294d621040SChristian S.J. Peron 2304d621040SChristian S.J. Peron BPFD_LOCK_ASSERT(d); 2314d621040SChristian S.J. Peron 2324d621040SChristian S.J. Peron switch (d->bd_bufmode) { 2334d621040SChristian S.J. Peron case BPF_BUFMODE_BUFFER: 2344d621040SChristian S.J. Peron return (bpf_buffer_append_mbuf(d, buf, offset, src, len)); 2354d621040SChristian S.J. Peron 2364d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 2374d621040SChristian S.J. Peron d->bd_zcopy++; 2384d621040SChristian S.J. Peron return (bpf_zerocopy_append_mbuf(d, buf, offset, src, len)); 2394d621040SChristian S.J. Peron 2404d621040SChristian S.J. Peron default: 2414d621040SChristian S.J. Peron panic("bpf_buf_append_mbuf"); 2424d621040SChristian S.J. Peron } 2434d621040SChristian S.J. Peron } 2444d621040SChristian S.J. Peron 2454d621040SChristian S.J. Peron /* 24629f612ecSChristian S.J. Peron * This function gets called when the free buffer is re-assigned. 24729f612ecSChristian S.J. Peron */ 24829f612ecSChristian S.J. Peron static void 24929f612ecSChristian S.J. Peron bpf_buf_reclaimed(struct bpf_d *d) 25029f612ecSChristian S.J. Peron { 25129f612ecSChristian S.J. Peron 25229f612ecSChristian S.J. Peron BPFD_LOCK_ASSERT(d); 25329f612ecSChristian S.J. Peron 25429f612ecSChristian S.J. Peron switch (d->bd_bufmode) { 25529f612ecSChristian S.J. Peron case BPF_BUFMODE_BUFFER: 25629f612ecSChristian S.J. Peron return; 25729f612ecSChristian S.J. Peron 25829f612ecSChristian S.J. Peron case BPF_BUFMODE_ZBUF: 25929f612ecSChristian S.J. Peron bpf_zerocopy_buf_reclaimed(d); 26029f612ecSChristian S.J. Peron return; 26129f612ecSChristian S.J. Peron 26229f612ecSChristian S.J. Peron default: 26329f612ecSChristian S.J. Peron panic("bpf_buf_reclaimed"); 26429f612ecSChristian S.J. Peron } 26529f612ecSChristian S.J. Peron } 26629f612ecSChristian S.J. Peron 26729f612ecSChristian S.J. Peron /* 2684d621040SChristian S.J. Peron * If the buffer mechanism has a way to decide that a held buffer can be made 2694d621040SChristian S.J. Peron * free, then it is exposed via the bpf_canfreebuf() interface. (1) is 2704d621040SChristian S.J. Peron * returned if the buffer can be discarded, (0) is returned if it cannot. 2714d621040SChristian S.J. Peron */ 2724d621040SChristian S.J. Peron static int 2734d621040SChristian S.J. Peron bpf_canfreebuf(struct bpf_d *d) 2744d621040SChristian S.J. Peron { 2754d621040SChristian S.J. Peron 2764d621040SChristian S.J. Peron BPFD_LOCK_ASSERT(d); 2774d621040SChristian S.J. Peron 2784d621040SChristian S.J. Peron switch (d->bd_bufmode) { 2794d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 2804d621040SChristian S.J. Peron return (bpf_zerocopy_canfreebuf(d)); 2814d621040SChristian S.J. Peron } 2824d621040SChristian S.J. Peron return (0); 2834d621040SChristian S.J. Peron } 2844d621040SChristian S.J. Peron 285a7a91e65SRobert Watson /* 286a7a91e65SRobert Watson * Allow the buffer model to indicate that the current store buffer is 287a7a91e65SRobert Watson * immutable, regardless of the appearance of space. Return (1) if the 288a7a91e65SRobert Watson * buffer is writable, and (0) if not. 289a7a91e65SRobert Watson */ 290a7a91e65SRobert Watson static int 291a7a91e65SRobert Watson bpf_canwritebuf(struct bpf_d *d) 292a7a91e65SRobert Watson { 293a7a91e65SRobert Watson 294a7a91e65SRobert Watson BPFD_LOCK_ASSERT(d); 295a7a91e65SRobert Watson 296a7a91e65SRobert Watson switch (d->bd_bufmode) { 297a7a91e65SRobert Watson case BPF_BUFMODE_ZBUF: 298a7a91e65SRobert Watson return (bpf_zerocopy_canwritebuf(d)); 299a7a91e65SRobert Watson } 300a7a91e65SRobert Watson return (1); 301a7a91e65SRobert Watson } 302a7a91e65SRobert Watson 303a7a91e65SRobert Watson /* 304a7a91e65SRobert Watson * Notify buffer model that an attempt to write to the store buffer has 305a7a91e65SRobert Watson * resulted in a dropped packet, in which case the buffer may be considered 306a7a91e65SRobert Watson * full. 307a7a91e65SRobert Watson */ 308a7a91e65SRobert Watson static void 309a7a91e65SRobert Watson bpf_buffull(struct bpf_d *d) 310a7a91e65SRobert Watson { 311a7a91e65SRobert Watson 312a7a91e65SRobert Watson BPFD_LOCK_ASSERT(d); 313a7a91e65SRobert Watson 314a7a91e65SRobert Watson switch (d->bd_bufmode) { 315a7a91e65SRobert Watson case BPF_BUFMODE_ZBUF: 316a7a91e65SRobert Watson bpf_zerocopy_buffull(d); 317a7a91e65SRobert Watson break; 318a7a91e65SRobert Watson } 319a7a91e65SRobert Watson } 320a7a91e65SRobert Watson 321a7a91e65SRobert Watson /* 322a7a91e65SRobert Watson * Notify the buffer model that a buffer has moved into the hold position. 323a7a91e65SRobert Watson */ 3244d621040SChristian S.J. Peron void 3254d621040SChristian S.J. Peron bpf_bufheld(struct bpf_d *d) 3264d621040SChristian S.J. Peron { 3274d621040SChristian S.J. Peron 3284d621040SChristian S.J. Peron BPFD_LOCK_ASSERT(d); 3294d621040SChristian S.J. Peron 3304d621040SChristian S.J. Peron switch (d->bd_bufmode) { 3314d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 3324d621040SChristian S.J. Peron bpf_zerocopy_bufheld(d); 3334d621040SChristian S.J. Peron break; 3344d621040SChristian S.J. Peron } 3354d621040SChristian S.J. Peron } 3364d621040SChristian S.J. Peron 3374d621040SChristian S.J. Peron static void 3384d621040SChristian S.J. Peron bpf_free(struct bpf_d *d) 3394d621040SChristian S.J. Peron { 3404d621040SChristian S.J. Peron 3414d621040SChristian S.J. Peron switch (d->bd_bufmode) { 3424d621040SChristian S.J. Peron case BPF_BUFMODE_BUFFER: 3434d621040SChristian S.J. Peron return (bpf_buffer_free(d)); 3444d621040SChristian S.J. Peron 3454d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 3464d621040SChristian S.J. Peron return (bpf_zerocopy_free(d)); 3474d621040SChristian S.J. Peron 3484d621040SChristian S.J. Peron default: 3494d621040SChristian S.J. Peron panic("bpf_buf_free"); 3504d621040SChristian S.J. Peron } 3514d621040SChristian S.J. Peron } 3524d621040SChristian S.J. Peron 3534d621040SChristian S.J. Peron static int 3544d621040SChristian S.J. Peron bpf_uiomove(struct bpf_d *d, caddr_t buf, u_int len, struct uio *uio) 3554d621040SChristian S.J. Peron { 3564d621040SChristian S.J. Peron 3574d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_BUFFER) 3584d621040SChristian S.J. Peron return (EOPNOTSUPP); 3594d621040SChristian S.J. Peron return (bpf_buffer_uiomove(d, buf, len, uio)); 3604d621040SChristian S.J. Peron } 3614d621040SChristian S.J. Peron 3624d621040SChristian S.J. Peron static int 3634d621040SChristian S.J. Peron bpf_ioctl_sblen(struct bpf_d *d, u_int *i) 3644d621040SChristian S.J. Peron { 3654d621040SChristian S.J. Peron 3664d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_BUFFER) 3674d621040SChristian S.J. Peron return (EOPNOTSUPP); 3684d621040SChristian S.J. Peron return (bpf_buffer_ioctl_sblen(d, i)); 3694d621040SChristian S.J. Peron } 3704d621040SChristian S.J. Peron 3714d621040SChristian S.J. Peron static int 3724d621040SChristian S.J. Peron bpf_ioctl_getzmax(struct thread *td, struct bpf_d *d, size_t *i) 3734d621040SChristian S.J. Peron { 3744d621040SChristian S.J. Peron 3754d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_ZBUF) 3764d621040SChristian S.J. Peron return (EOPNOTSUPP); 3774d621040SChristian S.J. Peron return (bpf_zerocopy_ioctl_getzmax(td, d, i)); 3784d621040SChristian S.J. Peron } 3794d621040SChristian S.J. Peron 3804d621040SChristian S.J. Peron static int 3814d621040SChristian S.J. Peron bpf_ioctl_rotzbuf(struct thread *td, struct bpf_d *d, struct bpf_zbuf *bz) 3824d621040SChristian S.J. Peron { 3834d621040SChristian S.J. Peron 3844d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_ZBUF) 3854d621040SChristian S.J. Peron return (EOPNOTSUPP); 3864d621040SChristian S.J. Peron return (bpf_zerocopy_ioctl_rotzbuf(td, d, bz)); 3874d621040SChristian S.J. Peron } 3884d621040SChristian S.J. Peron 3894d621040SChristian S.J. Peron static int 3904d621040SChristian S.J. Peron bpf_ioctl_setzbuf(struct thread *td, struct bpf_d *d, struct bpf_zbuf *bz) 3914d621040SChristian S.J. Peron { 3924d621040SChristian S.J. Peron 3934d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_ZBUF) 3944d621040SChristian S.J. Peron return (EOPNOTSUPP); 3954d621040SChristian S.J. Peron return (bpf_zerocopy_ioctl_setzbuf(td, d, bz)); 3964d621040SChristian S.J. Peron } 3974d621040SChristian S.J. Peron 3984d621040SChristian S.J. Peron /* 3994d621040SChristian S.J. Peron * General BPF functions. 4004d621040SChristian S.J. Peron */ 401df8bae1dSRodney W. Grimes static int 402cb44b6dfSAndrew Thompson bpf_movein(struct uio *uio, int linktype, struct ifnet *ifp, struct mbuf **mp, 403560a54e1SJung-uk Kim struct sockaddr *sockp, int *hdrlen, struct bpf_insn *wfilter) 404df8bae1dSRodney W. Grimes { 405246b5467SSam Leffler const struct ieee80211_bpf_params *p; 406cb44b6dfSAndrew Thompson struct ether_header *eh; 407df8bae1dSRodney W. Grimes struct mbuf *m; 408df8bae1dSRodney W. Grimes int error; 409df8bae1dSRodney W. Grimes int len; 410df8bae1dSRodney W. Grimes int hlen; 41193e39f0bSChristian S.J. Peron int slen; 412df8bae1dSRodney W. Grimes 413df8bae1dSRodney W. Grimes /* 414df8bae1dSRodney W. Grimes * Build a sockaddr based on the data link layer type. 415df8bae1dSRodney W. Grimes * We do this at this level because the ethernet header 416df8bae1dSRodney W. Grimes * is copied directly into the data field of the sockaddr. 417df8bae1dSRodney W. Grimes * In the case of SLIP, there is no header and the packet 418df8bae1dSRodney W. Grimes * is forwarded as is. 419df8bae1dSRodney W. Grimes * Also, we are careful to leave room at the front of the mbuf 420df8bae1dSRodney W. Grimes * for the link level header. 421df8bae1dSRodney W. Grimes */ 422df8bae1dSRodney W. Grimes switch (linktype) { 423df8bae1dSRodney W. Grimes 424df8bae1dSRodney W. Grimes case DLT_SLIP: 425df8bae1dSRodney W. Grimes sockp->sa_family = AF_INET; 426df8bae1dSRodney W. Grimes hlen = 0; 427df8bae1dSRodney W. Grimes break; 428df8bae1dSRodney W. Grimes 429df8bae1dSRodney W. Grimes case DLT_EN10MB: 430df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 431df8bae1dSRodney W. Grimes /* XXX Would MAXLINKHDR be better? */ 432797f247bSMatthew N. Dodd hlen = ETHER_HDR_LEN; 433df8bae1dSRodney W. Grimes break; 434df8bae1dSRodney W. Grimes 435df8bae1dSRodney W. Grimes case DLT_FDDI: 436d41f24e7SDavid Greenman sockp->sa_family = AF_IMPLINK; 437d41f24e7SDavid Greenman hlen = 0; 438df8bae1dSRodney W. Grimes break; 439df8bae1dSRodney W. Grimes 44022f05c43SAndrey A. Chernov case DLT_RAW: 441df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 442df8bae1dSRodney W. Grimes hlen = 0; 443df8bae1dSRodney W. Grimes break; 444df8bae1dSRodney W. Grimes 44501399f34SDavid Malone case DLT_NULL: 44601399f34SDavid Malone /* 44701399f34SDavid Malone * null interface types require a 4 byte pseudo header which 44801399f34SDavid Malone * corresponds to the address family of the packet. 44901399f34SDavid Malone */ 45001399f34SDavid Malone sockp->sa_family = AF_UNSPEC; 45101399f34SDavid Malone hlen = 4; 45201399f34SDavid Malone break; 45301399f34SDavid Malone 4544f53e3ccSKenjiro Cho case DLT_ATM_RFC1483: 4554f53e3ccSKenjiro Cho /* 4564f53e3ccSKenjiro Cho * en atm driver requires 4-byte atm pseudo header. 4574f53e3ccSKenjiro Cho * though it isn't standard, vpi:vci needs to be 4584f53e3ccSKenjiro Cho * specified anyway. 4594f53e3ccSKenjiro Cho */ 4604f53e3ccSKenjiro Cho sockp->sa_family = AF_UNSPEC; 4614f53e3ccSKenjiro Cho hlen = 12; /* XXX 4(ATM_PH) + 3(LLC) + 5(SNAP) */ 4624f53e3ccSKenjiro Cho break; 4634f53e3ccSKenjiro Cho 46430fa52a6SBrian Somers case DLT_PPP: 46530fa52a6SBrian Somers sockp->sa_family = AF_UNSPEC; 46630fa52a6SBrian Somers hlen = 4; /* This should match PPP_HDRLEN */ 46730fa52a6SBrian Somers break; 46830fa52a6SBrian Somers 469246b5467SSam Leffler case DLT_IEEE802_11: /* IEEE 802.11 wireless */ 470246b5467SSam Leffler sockp->sa_family = AF_IEEE80211; 471246b5467SSam Leffler hlen = 0; 472246b5467SSam Leffler break; 473246b5467SSam Leffler 474246b5467SSam Leffler case DLT_IEEE802_11_RADIO: /* IEEE 802.11 wireless w/ phy params */ 475246b5467SSam Leffler sockp->sa_family = AF_IEEE80211; 476246b5467SSam Leffler sockp->sa_len = 12; /* XXX != 0 */ 477246b5467SSam Leffler hlen = sizeof(struct ieee80211_bpf_params); 478246b5467SSam Leffler break; 479246b5467SSam Leffler 480df8bae1dSRodney W. Grimes default: 481df8bae1dSRodney W. Grimes return (EIO); 482df8bae1dSRodney W. Grimes } 483df8bae1dSRodney W. Grimes 484df8bae1dSRodney W. Grimes len = uio->uio_resid; 48501399f34SDavid Malone 486cb44b6dfSAndrew Thompson if (len - hlen > ifp->if_mtu) 48701399f34SDavid Malone return (EMSGSIZE); 48801399f34SDavid Malone 489968c88bcSJung-uk Kim if ((unsigned)len > MJUM16BYTES) 490df8bae1dSRodney W. Grimes return (EIO); 491df8bae1dSRodney W. Grimes 492968c88bcSJung-uk Kim if (len <= MHLEN) 493968c88bcSJung-uk Kim MGETHDR(m, M_WAIT, MT_DATA); 494968c88bcSJung-uk Kim else if (len <= MCLBYTES) 495ea26d587SRuslan Ermilov m = m_getcl(M_WAIT, MT_DATA, M_PKTHDR); 496ea26d587SRuslan Ermilov else 497968c88bcSJung-uk Kim m = m_getjcl(M_WAIT, MT_DATA, M_PKTHDR, 498968c88bcSJung-uk Kim #if (MJUMPAGESIZE > MCLBYTES) 499968c88bcSJung-uk Kim len <= MJUMPAGESIZE ? MJUMPAGESIZE : 500968c88bcSJung-uk Kim #endif 501968c88bcSJung-uk Kim (len <= MJUM9BYTES ? MJUM9BYTES : MJUM16BYTES)); 502963e4c2aSGarrett Wollman m->m_pkthdr.len = m->m_len = len; 503963e4c2aSGarrett Wollman m->m_pkthdr.rcvif = NULL; 504df8bae1dSRodney W. Grimes *mp = m; 50524a229f4SSam Leffler 50693e39f0bSChristian S.J. Peron if (m->m_len < hlen) { 50793e39f0bSChristian S.J. Peron error = EPERM; 50893e39f0bSChristian S.J. Peron goto bad; 50993e39f0bSChristian S.J. Peron } 51093e39f0bSChristian S.J. Peron 51193e39f0bSChristian S.J. Peron error = uiomove(mtod(m, u_char *), len, uio); 51293e39f0bSChristian S.J. Peron if (error) 51393e39f0bSChristian S.J. Peron goto bad; 51493e39f0bSChristian S.J. Peron 51593e39f0bSChristian S.J. Peron slen = bpf_filter(wfilter, mtod(m, u_char *), len, len); 51693e39f0bSChristian S.J. Peron if (slen == 0) { 51793e39f0bSChristian S.J. Peron error = EPERM; 51893e39f0bSChristian S.J. Peron goto bad; 51993e39f0bSChristian S.J. Peron } 52093e39f0bSChristian S.J. Peron 521cb44b6dfSAndrew Thompson /* Check for multicast destination */ 522cb44b6dfSAndrew Thompson switch (linktype) { 523cb44b6dfSAndrew Thompson case DLT_EN10MB: 524cb44b6dfSAndrew Thompson eh = mtod(m, struct ether_header *); 525cb44b6dfSAndrew Thompson if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 526cb44b6dfSAndrew Thompson if (bcmp(ifp->if_broadcastaddr, eh->ether_dhost, 527cb44b6dfSAndrew Thompson ETHER_ADDR_LEN) == 0) 528cb44b6dfSAndrew Thompson m->m_flags |= M_BCAST; 529cb44b6dfSAndrew Thompson else 530cb44b6dfSAndrew Thompson m->m_flags |= M_MCAST; 531cb44b6dfSAndrew Thompson } 532cb44b6dfSAndrew Thompson break; 533cb44b6dfSAndrew Thompson } 534cb44b6dfSAndrew Thompson 535df8bae1dSRodney W. Grimes /* 53693e39f0bSChristian S.J. Peron * Make room for link header, and copy it to sockaddr 537df8bae1dSRodney W. Grimes */ 538df8bae1dSRodney W. Grimes if (hlen != 0) { 539246b5467SSam Leffler if (sockp->sa_family == AF_IEEE80211) { 540246b5467SSam Leffler /* 541246b5467SSam Leffler * Collect true length from the parameter header 542246b5467SSam Leffler * NB: sockp is known to be zero'd so if we do a 543246b5467SSam Leffler * short copy unspecified parameters will be 544246b5467SSam Leffler * zero. 545246b5467SSam Leffler * NB: packet may not be aligned after stripping 546246b5467SSam Leffler * bpf params 547246b5467SSam Leffler * XXX check ibp_vers 548246b5467SSam Leffler */ 549246b5467SSam Leffler p = mtod(m, const struct ieee80211_bpf_params *); 550246b5467SSam Leffler hlen = p->ibp_len; 551246b5467SSam Leffler if (hlen > sizeof(sockp->sa_data)) { 552246b5467SSam Leffler error = EINVAL; 553246b5467SSam Leffler goto bad; 554246b5467SSam Leffler } 555246b5467SSam Leffler } 55693e39f0bSChristian S.J. Peron bcopy(m->m_data, sockp->sa_data, hlen); 557df8bae1dSRodney W. Grimes } 558560a54e1SJung-uk Kim *hdrlen = hlen; 55993e39f0bSChristian S.J. Peron 560df8bae1dSRodney W. Grimes return (0); 561df8bae1dSRodney W. Grimes bad: 562df8bae1dSRodney W. Grimes m_freem(m); 563df8bae1dSRodney W. Grimes return (error); 564df8bae1dSRodney W. Grimes } 565df8bae1dSRodney W. Grimes 566df8bae1dSRodney W. Grimes /* 567df8bae1dSRodney W. Grimes * Attach file to the bpf interface, i.e. make d listen on bp. 568df8bae1dSRodney W. Grimes */ 569df8bae1dSRodney W. Grimes static void 57019ba8395SChristian S.J. Peron bpf_attachd(struct bpf_d *d, struct bpf_if *bp) 571df8bae1dSRodney W. Grimes { 572df8bae1dSRodney W. Grimes /* 573df8bae1dSRodney W. Grimes * Point d at bp, and add d to the interface's list of listeners. 574df8bae1dSRodney W. Grimes * Finally, point the driver's bpf cookie at the interface so 575df8bae1dSRodney W. Grimes * it will divert packets to bpf. 576df8bae1dSRodney W. Grimes */ 577e7bb21b3SJonathan Lemon BPFIF_LOCK(bp); 578df8bae1dSRodney W. Grimes d->bd_bif = bp; 5794a3feeaaSRobert Watson LIST_INSERT_HEAD(&bp->bif_dlist, d, bd_next); 580df8bae1dSRodney W. Grimes 58169f7644bSChristian S.J. Peron bpf_bpfd_cnt++; 582e7bb21b3SJonathan Lemon BPFIF_UNLOCK(bp); 583b743c310SSam Leffler 5845ce8d970SSam Leffler EVENTHANDLER_INVOKE(bpf_track, bp->bif_ifp, bp->bif_dlt, 1); 585df8bae1dSRodney W. Grimes } 586df8bae1dSRodney W. Grimes 587df8bae1dSRodney W. Grimes /* 588df8bae1dSRodney W. Grimes * Detach a file from its interface. 589df8bae1dSRodney W. Grimes */ 590df8bae1dSRodney W. Grimes static void 59119ba8395SChristian S.J. Peron bpf_detachd(struct bpf_d *d) 592df8bae1dSRodney W. Grimes { 5936e891d64SPoul-Henning Kamp int error; 594df8bae1dSRodney W. Grimes struct bpf_if *bp; 59546448b5aSRobert Watson struct ifnet *ifp; 596df8bae1dSRodney W. Grimes 597df8bae1dSRodney W. Grimes bp = d->bd_bif; 59846448b5aSRobert Watson BPFIF_LOCK(bp); 59946448b5aSRobert Watson BPFD_LOCK(d); 60046448b5aSRobert Watson ifp = d->bd_bif->bif_ifp; 60146448b5aSRobert Watson 60246448b5aSRobert Watson /* 60346448b5aSRobert Watson * Remove d from the interface's descriptor list. 60446448b5aSRobert Watson */ 60546448b5aSRobert Watson LIST_REMOVE(d, bd_next); 60646448b5aSRobert Watson 60769f7644bSChristian S.J. Peron bpf_bpfd_cnt--; 608572bde2aSRobert Watson d->bd_bif = NULL; 60946448b5aSRobert Watson BPFD_UNLOCK(d); 61046448b5aSRobert Watson BPFIF_UNLOCK(bp); 61146448b5aSRobert Watson 6125ce8d970SSam Leffler EVENTHANDLER_INVOKE(bpf_track, ifp, bp->bif_dlt, 0); 613b743c310SSam Leffler 614df8bae1dSRodney W. Grimes /* 615df8bae1dSRodney W. Grimes * Check if this descriptor had requested promiscuous mode. 616df8bae1dSRodney W. Grimes * If so, turn it off. 617df8bae1dSRodney W. Grimes */ 618df8bae1dSRodney W. Grimes if (d->bd_promisc) { 619df8bae1dSRodney W. Grimes d->bd_promisc = 0; 62097021c24SMarko Zec CURVNET_SET(ifp->if_vnet); 62146448b5aSRobert Watson error = ifpromisc(ifp, 0); 62297021c24SMarko Zec CURVNET_RESTORE(); 6236e891d64SPoul-Henning Kamp if (error != 0 && error != ENXIO) { 624df8bae1dSRodney W. Grimes /* 6256e891d64SPoul-Henning Kamp * ENXIO can happen if a pccard is unplugged 626df8bae1dSRodney W. Grimes * Something is really wrong if we were able to put 627df8bae1dSRodney W. Grimes * the driver into promiscuous mode, but can't 628df8bae1dSRodney W. Grimes * take it out. 629df8bae1dSRodney W. Grimes */ 6308eab61f3SSam Leffler if_printf(bp->bif_ifp, 6318eab61f3SSam Leffler "bpf_detach: ifpromisc failed (%d)\n", error); 6326e891d64SPoul-Henning Kamp } 633df8bae1dSRodney W. Grimes } 634df8bae1dSRodney W. Grimes } 635df8bae1dSRodney W. Grimes 636df8bae1dSRodney W. Grimes /* 637136600feSEd Schouten * Close the descriptor by detaching it from its interface, 638136600feSEd Schouten * deallocating its buffers, and marking it free. 639136600feSEd Schouten */ 640136600feSEd Schouten static void 641136600feSEd Schouten bpf_dtor(void *data) 642136600feSEd Schouten { 643136600feSEd Schouten struct bpf_d *d = data; 644136600feSEd Schouten 645136600feSEd Schouten BPFD_LOCK(d); 646136600feSEd Schouten if (d->bd_state == BPF_WAITING) 647136600feSEd Schouten callout_stop(&d->bd_callout); 648136600feSEd Schouten d->bd_state = BPF_IDLE; 649136600feSEd Schouten BPFD_UNLOCK(d); 650136600feSEd Schouten funsetown(&d->bd_sigio); 651136600feSEd Schouten mtx_lock(&bpf_mtx); 652136600feSEd Schouten if (d->bd_bif) 653136600feSEd Schouten bpf_detachd(d); 654136600feSEd Schouten mtx_unlock(&bpf_mtx); 655136600feSEd Schouten selwakeuppri(&d->bd_sel, PRINET); 656136600feSEd Schouten #ifdef MAC 657136600feSEd Schouten mac_bpfdesc_destroy(d); 658136600feSEd Schouten #endif /* MAC */ 659136600feSEd Schouten knlist_destroy(&d->bd_sel.si_note); 6609fee1bd1SJung-uk Kim callout_drain(&d->bd_callout); 661136600feSEd Schouten bpf_freed(d); 662136600feSEd Schouten free(d, M_BPF); 663136600feSEd Schouten } 664136600feSEd Schouten 665136600feSEd Schouten /* 666df8bae1dSRodney W. Grimes * Open ethernet device. Returns ENXIO for illegal minor device number, 667df8bae1dSRodney W. Grimes * EBUSY if file is open by another process. 668df8bae1dSRodney W. Grimes */ 669df8bae1dSRodney W. Grimes /* ARGSUSED */ 67087f6c662SJulian Elischer static int 67119ba8395SChristian S.J. Peron bpfopen(struct cdev *dev, int flags, int fmt, struct thread *td) 672df8bae1dSRodney W. Grimes { 673e7bb21b3SJonathan Lemon struct bpf_d *d; 674136600feSEd Schouten int error; 675df8bae1dSRodney W. Grimes 6761ede983cSDag-Erling Smørgrav d = malloc(sizeof(*d), M_BPF, M_WAITOK | M_ZERO); 677136600feSEd Schouten error = devfs_set_cdevpriv(d, bpf_dtor); 678136600feSEd Schouten if (error != 0) { 679136600feSEd Schouten free(d, M_BPF); 680136600feSEd Schouten return (error); 681136600feSEd Schouten } 6824d621040SChristian S.J. Peron 6834d621040SChristian S.J. Peron /* 6844d621040SChristian S.J. Peron * For historical reasons, perform a one-time initialization call to 6854d621040SChristian S.J. Peron * the buffer routines, even though we're not yet committed to a 6864d621040SChristian S.J. Peron * particular buffer method. 6874d621040SChristian S.J. Peron */ 6884d621040SChristian S.J. Peron bpf_buffer_init(d); 6894d621040SChristian S.J. Peron d->bd_bufmode = BPF_BUFMODE_BUFFER; 69000a83887SPaul Traina d->bd_sig = SIGIO; 691560a54e1SJung-uk Kim d->bd_direction = BPF_D_INOUT; 69269f7644bSChristian S.J. Peron d->bd_pid = td->td_proc->p_pid; 69382f4445dSRobert Watson #ifdef MAC 69430d239bcSRobert Watson mac_bpfdesc_init(d); 69530d239bcSRobert Watson mac_bpfdesc_create(td->td_ucred, d); 69682f4445dSRobert Watson #endif 6976008862bSJohn Baldwin mtx_init(&d->bd_mtx, devtoname(dev), "bpf cdev lock", MTX_DEF); 6989fee1bd1SJung-uk Kim callout_init_mtx(&d->bd_callout, &d->bd_mtx, 0); 699d8b0556cSKonstantin Belousov knlist_init_mtx(&d->bd_sel.si_note, &d->bd_mtx); 700df8bae1dSRodney W. Grimes 701df8bae1dSRodney W. Grimes return (0); 702df8bae1dSRodney W. Grimes } 703df8bae1dSRodney W. Grimes 704df8bae1dSRodney W. Grimes /* 705df8bae1dSRodney W. Grimes * bpfread - read next chunk of packets from buffers 706df8bae1dSRodney W. Grimes */ 70787f6c662SJulian Elischer static int 70819ba8395SChristian S.J. Peron bpfread(struct cdev *dev, struct uio *uio, int ioflag) 709df8bae1dSRodney W. Grimes { 710136600feSEd Schouten struct bpf_d *d; 711df8bae1dSRodney W. Grimes int error; 7128df67d77SJung-uk Kim int non_block; 7138df67d77SJung-uk Kim int timed_out; 714df8bae1dSRodney W. Grimes 715136600feSEd Schouten error = devfs_get_cdevpriv((void **)&d); 716136600feSEd Schouten if (error != 0) 717136600feSEd Schouten return (error); 718136600feSEd Schouten 719df8bae1dSRodney W. Grimes /* 720df8bae1dSRodney W. Grimes * Restrict application to use a buffer the same size as 721df8bae1dSRodney W. Grimes * as kernel buffers. 722df8bae1dSRodney W. Grimes */ 723df8bae1dSRodney W. Grimes if (uio->uio_resid != d->bd_bufsize) 724df8bae1dSRodney W. Grimes return (EINVAL); 725df8bae1dSRodney W. Grimes 7268df67d77SJung-uk Kim non_block = ((ioflag & O_NONBLOCK) != 0); 7278df67d77SJung-uk Kim 728e7bb21b3SJonathan Lemon BPFD_LOCK(d); 72950ed6e07SChristian S.J. Peron d->bd_pid = curthread->td_proc->p_pid; 7304d621040SChristian S.J. Peron if (d->bd_bufmode != BPF_BUFMODE_BUFFER) { 7314d621040SChristian S.J. Peron BPFD_UNLOCK(d); 7324d621040SChristian S.J. Peron return (EOPNOTSUPP); 7334d621040SChristian S.J. Peron } 73481bda851SJohn Polstra if (d->bd_state == BPF_WAITING) 73581bda851SJohn Polstra callout_stop(&d->bd_callout); 73681bda851SJohn Polstra timed_out = (d->bd_state == BPF_TIMED_OUT); 73781bda851SJohn Polstra d->bd_state = BPF_IDLE; 738df8bae1dSRodney W. Grimes /* 739df8bae1dSRodney W. Grimes * If the hold buffer is empty, then do a timed sleep, which 740df8bae1dSRodney W. Grimes * ends when the timeout expires or when enough packets 741df8bae1dSRodney W. Grimes * have arrived to fill the store buffer. 742df8bae1dSRodney W. Grimes */ 743572bde2aSRobert Watson while (d->bd_hbuf == NULL) { 7448df67d77SJung-uk Kim if (d->bd_slen != 0) { 745df8bae1dSRodney W. Grimes /* 746df8bae1dSRodney W. Grimes * A packet(s) either arrived since the previous 747df8bae1dSRodney W. Grimes * read or arrived while we were asleep. 7488df67d77SJung-uk Kim */ 7498df67d77SJung-uk Kim if (d->bd_immediate || non_block || timed_out) { 7508df67d77SJung-uk Kim /* 7518df67d77SJung-uk Kim * Rotate the buffers and return what's here 7528df67d77SJung-uk Kim * if we are in immediate mode, non-blocking 7538df67d77SJung-uk Kim * flag is set, or this descriptor timed out. 754df8bae1dSRodney W. Grimes */ 755df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 756df8bae1dSRodney W. Grimes break; 757df8bae1dSRodney W. Grimes } 7588df67d77SJung-uk Kim } 759de5d9935SRobert Watson 760de5d9935SRobert Watson /* 761de5d9935SRobert Watson * No data is available, check to see if the bpf device 762de5d9935SRobert Watson * is still pointed at a real interface. If not, return 763de5d9935SRobert Watson * ENXIO so that the userland process knows to rebind 764de5d9935SRobert Watson * it before using it again. 765de5d9935SRobert Watson */ 766de5d9935SRobert Watson if (d->bd_bif == NULL) { 767e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 768de5d9935SRobert Watson return (ENXIO); 769de5d9935SRobert Watson } 770de5d9935SRobert Watson 7718df67d77SJung-uk Kim if (non_block) { 772e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 773fba3cfdeSJohn Polstra return (EWOULDBLOCK); 774fba3cfdeSJohn Polstra } 775521f364bSDag-Erling Smørgrav error = msleep(d, &d->bd_mtx, PRINET|PCATCH, 776e7bb21b3SJonathan Lemon "bpf", d->bd_rtout); 777df8bae1dSRodney W. Grimes if (error == EINTR || error == ERESTART) { 778e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 779df8bae1dSRodney W. Grimes return (error); 780df8bae1dSRodney W. Grimes } 781df8bae1dSRodney W. Grimes if (error == EWOULDBLOCK) { 782df8bae1dSRodney W. Grimes /* 783df8bae1dSRodney W. Grimes * On a timeout, return what's in the buffer, 784df8bae1dSRodney W. Grimes * which may be nothing. If there is something 785df8bae1dSRodney W. Grimes * in the store buffer, we can rotate the buffers. 786df8bae1dSRodney W. Grimes */ 787df8bae1dSRodney W. Grimes if (d->bd_hbuf) 788df8bae1dSRodney W. Grimes /* 789df8bae1dSRodney W. Grimes * We filled up the buffer in between 790df8bae1dSRodney W. Grimes * getting the timeout and arriving 791df8bae1dSRodney W. Grimes * here, so we don't need to rotate. 792df8bae1dSRodney W. Grimes */ 793df8bae1dSRodney W. Grimes break; 794df8bae1dSRodney W. Grimes 795df8bae1dSRodney W. Grimes if (d->bd_slen == 0) { 796e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 797df8bae1dSRodney W. Grimes return (0); 798df8bae1dSRodney W. Grimes } 799df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 800df8bae1dSRodney W. Grimes break; 801df8bae1dSRodney W. Grimes } 802df8bae1dSRodney W. Grimes } 803df8bae1dSRodney W. Grimes /* 804df8bae1dSRodney W. Grimes * At this point, we know we have something in the hold slot. 805df8bae1dSRodney W. Grimes */ 806e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 807df8bae1dSRodney W. Grimes 808df8bae1dSRodney W. Grimes /* 809df8bae1dSRodney W. Grimes * Move data from hold buffer into user space. 810df8bae1dSRodney W. Grimes * We know the entire buffer is transferred since 811df8bae1dSRodney W. Grimes * we checked above that the read buffer is bpf_bufsize bytes. 81231b32e6dSRobert Watson * 81331b32e6dSRobert Watson * XXXRW: More synchronization needed here: what if a second thread 81431b32e6dSRobert Watson * issues a read on the same fd at the same time? Don't want this 81531b32e6dSRobert Watson * getting invalidated. 816df8bae1dSRodney W. Grimes */ 8174d621040SChristian S.J. Peron error = bpf_uiomove(d, d->bd_hbuf, d->bd_hlen, uio); 818df8bae1dSRodney W. Grimes 819e7bb21b3SJonathan Lemon BPFD_LOCK(d); 820df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 821572bde2aSRobert Watson d->bd_hbuf = NULL; 822df8bae1dSRodney W. Grimes d->bd_hlen = 0; 82329f612ecSChristian S.J. Peron bpf_buf_reclaimed(d); 824e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 825df8bae1dSRodney W. Grimes 826df8bae1dSRodney W. Grimes return (error); 827df8bae1dSRodney W. Grimes } 828df8bae1dSRodney W. Grimes 829df8bae1dSRodney W. Grimes /* 830df8bae1dSRodney W. Grimes * If there are processes sleeping on this descriptor, wake them up. 831df8bae1dSRodney W. Grimes */ 832e7bb21b3SJonathan Lemon static __inline void 83319ba8395SChristian S.J. Peron bpf_wakeup(struct bpf_d *d) 834df8bae1dSRodney W. Grimes { 835a3272e3cSChristian S.J. Peron 836a3272e3cSChristian S.J. Peron BPFD_LOCK_ASSERT(d); 83781bda851SJohn Polstra if (d->bd_state == BPF_WAITING) { 83881bda851SJohn Polstra callout_stop(&d->bd_callout); 83981bda851SJohn Polstra d->bd_state = BPF_IDLE; 84081bda851SJohn Polstra } 841521f364bSDag-Erling Smørgrav wakeup(d); 842831d27a9SDon Lewis if (d->bd_async && d->bd_sig && d->bd_sigio) 843f1320723SAlfred Perlstein pgsigio(&d->bd_sigio, d->bd_sig, 0); 84400a83887SPaul Traina 845512824f8SSeigo Tanimura selwakeuppri(&d->bd_sel, PRINET); 846ad3b9257SJohn-Mark Gurney KNOTE_LOCKED(&d->bd_sel.si_note, 0); 847df8bae1dSRodney W. Grimes } 848df8bae1dSRodney W. Grimes 84981bda851SJohn Polstra static void 85019ba8395SChristian S.J. Peron bpf_timed_out(void *arg) 85181bda851SJohn Polstra { 85281bda851SJohn Polstra struct bpf_d *d = (struct bpf_d *)arg; 85381bda851SJohn Polstra 8549fee1bd1SJung-uk Kim BPFD_LOCK_ASSERT(d); 8559fee1bd1SJung-uk Kim 8569fee1bd1SJung-uk Kim if (callout_pending(&d->bd_callout) || !callout_active(&d->bd_callout)) 8579fee1bd1SJung-uk Kim return; 85881bda851SJohn Polstra if (d->bd_state == BPF_WAITING) { 85981bda851SJohn Polstra d->bd_state = BPF_TIMED_OUT; 86081bda851SJohn Polstra if (d->bd_slen != 0) 86181bda851SJohn Polstra bpf_wakeup(d); 86281bda851SJohn Polstra } 86381bda851SJohn Polstra } 86481bda851SJohn Polstra 86587f6c662SJulian Elischer static int 8664d621040SChristian S.J. Peron bpf_ready(struct bpf_d *d) 8674d621040SChristian S.J. Peron { 8684d621040SChristian S.J. Peron 8694d621040SChristian S.J. Peron BPFD_LOCK_ASSERT(d); 8704d621040SChristian S.J. Peron 8714d621040SChristian S.J. Peron if (!bpf_canfreebuf(d) && d->bd_hlen != 0) 8724d621040SChristian S.J. Peron return (1); 8734d621040SChristian S.J. Peron if ((d->bd_immediate || d->bd_state == BPF_TIMED_OUT) && 8744d621040SChristian S.J. Peron d->bd_slen != 0) 8754d621040SChristian S.J. Peron return (1); 8764d621040SChristian S.J. Peron return (0); 8774d621040SChristian S.J. Peron } 8784d621040SChristian S.J. Peron 8794d621040SChristian S.J. Peron static int 88019ba8395SChristian S.J. Peron bpfwrite(struct cdev *dev, struct uio *uio, int ioflag) 881df8bae1dSRodney W. Grimes { 882136600feSEd Schouten struct bpf_d *d; 883df8bae1dSRodney W. Grimes struct ifnet *ifp; 884560a54e1SJung-uk Kim struct mbuf *m, *mc; 8858240bf1eSRobert Watson struct sockaddr dst; 886560a54e1SJung-uk Kim int error, hlen; 887df8bae1dSRodney W. Grimes 888136600feSEd Schouten error = devfs_get_cdevpriv((void **)&d); 889136600feSEd Schouten if (error != 0) 890136600feSEd Schouten return (error); 891136600feSEd Schouten 89250ed6e07SChristian S.J. Peron d->bd_pid = curthread->td_proc->p_pid; 8934d621040SChristian S.J. Peron d->bd_wcount++; 8944d621040SChristian S.J. Peron if (d->bd_bif == NULL) { 8954d621040SChristian S.J. Peron d->bd_wdcount++; 896df8bae1dSRodney W. Grimes return (ENXIO); 8974d621040SChristian S.J. Peron } 898df8bae1dSRodney W. Grimes 899df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 900df8bae1dSRodney W. Grimes 9014d621040SChristian S.J. Peron if ((ifp->if_flags & IFF_UP) == 0) { 9024d621040SChristian S.J. Peron d->bd_wdcount++; 9033518d220SSam Leffler return (ENETDOWN); 9044d621040SChristian S.J. Peron } 9053518d220SSam Leffler 9064d621040SChristian S.J. Peron if (uio->uio_resid == 0) { 9074d621040SChristian S.J. Peron d->bd_wdcount++; 908df8bae1dSRodney W. Grimes return (0); 9094d621040SChristian S.J. Peron } 910df8bae1dSRodney W. Grimes 9118240bf1eSRobert Watson bzero(&dst, sizeof(dst)); 912d83e603aSChristian S.J. Peron m = NULL; 913d83e603aSChristian S.J. Peron hlen = 0; 914cb44b6dfSAndrew Thompson error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, ifp, 915560a54e1SJung-uk Kim &m, &dst, &hlen, d->bd_wfilter); 9164d621040SChristian S.J. Peron if (error) { 9174d621040SChristian S.J. Peron d->bd_wdcount++; 918df8bae1dSRodney W. Grimes return (error); 9194d621040SChristian S.J. Peron } 9204d621040SChristian S.J. Peron d->bd_wfcount++; 921114ae644SMike Smith if (d->bd_hdrcmplt) 922114ae644SMike Smith dst.sa_family = pseudo_AF_HDRCMPLT; 923114ae644SMike Smith 924560a54e1SJung-uk Kim if (d->bd_feedback) { 925560a54e1SJung-uk Kim mc = m_dup(m, M_DONTWAIT); 926560a54e1SJung-uk Kim if (mc != NULL) 927560a54e1SJung-uk Kim mc->m_pkthdr.rcvif = ifp; 9288cd892f7SJung-uk Kim /* Set M_PROMISC for outgoing packets to be discarded. */ 9298cd892f7SJung-uk Kim if (d->bd_direction == BPF_D_INOUT) 9308cd892f7SJung-uk Kim m->m_flags |= M_PROMISC; 931560a54e1SJung-uk Kim } else 932560a54e1SJung-uk Kim mc = NULL; 933560a54e1SJung-uk Kim 934560a54e1SJung-uk Kim m->m_pkthdr.len -= hlen; 935560a54e1SJung-uk Kim m->m_len -= hlen; 936560a54e1SJung-uk Kim m->m_data += hlen; /* XXX */ 937560a54e1SJung-uk Kim 93821ca7b57SMarko Zec CURVNET_SET(ifp->if_vnet); 93982f4445dSRobert Watson #ifdef MAC 940f747d2ddSRobert Watson BPFD_LOCK(d); 94130d239bcSRobert Watson mac_bpfdesc_create_mbuf(d, m); 942560a54e1SJung-uk Kim if (mc != NULL) 94330d239bcSRobert Watson mac_bpfdesc_create_mbuf(d, mc); 944f747d2ddSRobert Watson BPFD_UNLOCK(d); 94582f4445dSRobert Watson #endif 946560a54e1SJung-uk Kim 947572bde2aSRobert Watson error = (*ifp->if_output)(ifp, m, &dst, NULL); 9484d621040SChristian S.J. Peron if (error) 9494d621040SChristian S.J. Peron d->bd_wdcount++; 950560a54e1SJung-uk Kim 951560a54e1SJung-uk Kim if (mc != NULL) { 9520bf686c1SRobert Watson if (error == 0) 953560a54e1SJung-uk Kim (*ifp->if_input)(ifp, mc); 9540bf686c1SRobert Watson else 955560a54e1SJung-uk Kim m_freem(mc); 956560a54e1SJung-uk Kim } 95721ca7b57SMarko Zec CURVNET_RESTORE(); 958560a54e1SJung-uk Kim 959df8bae1dSRodney W. Grimes return (error); 960df8bae1dSRodney W. Grimes } 961df8bae1dSRodney W. Grimes 962df8bae1dSRodney W. Grimes /* 963e82669d9SRobert Watson * Reset a descriptor by flushing its packet buffer and clearing the receive 964e82669d9SRobert Watson * and drop counts. This is doable for kernel-only buffers, but with 965e82669d9SRobert Watson * zero-copy buffers, we can't write to (or rotate) buffers that are 966e82669d9SRobert Watson * currently owned by userspace. It would be nice if we could encapsulate 967e82669d9SRobert Watson * this logic in the buffer code rather than here. 968df8bae1dSRodney W. Grimes */ 969df8bae1dSRodney W. Grimes static void 97019ba8395SChristian S.J. Peron reset_d(struct bpf_d *d) 971df8bae1dSRodney W. Grimes { 972e7bb21b3SJonathan Lemon 973e7bb21b3SJonathan Lemon mtx_assert(&d->bd_mtx, MA_OWNED); 974e82669d9SRobert Watson 975e82669d9SRobert Watson if ((d->bd_hbuf != NULL) && 976e82669d9SRobert Watson (d->bd_bufmode != BPF_BUFMODE_ZBUF || bpf_canfreebuf(d))) { 977df8bae1dSRodney W. Grimes /* Free the hold buffer. */ 978df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 979572bde2aSRobert Watson d->bd_hbuf = NULL; 980e82669d9SRobert Watson d->bd_hlen = 0; 98129f612ecSChristian S.J. Peron bpf_buf_reclaimed(d); 982df8bae1dSRodney W. Grimes } 983e82669d9SRobert Watson if (bpf_canwritebuf(d)) 984df8bae1dSRodney W. Grimes d->bd_slen = 0; 985df8bae1dSRodney W. Grimes d->bd_rcount = 0; 986df8bae1dSRodney W. Grimes d->bd_dcount = 0; 98769f7644bSChristian S.J. Peron d->bd_fcount = 0; 9884d621040SChristian S.J. Peron d->bd_wcount = 0; 9894d621040SChristian S.J. Peron d->bd_wfcount = 0; 9904d621040SChristian S.J. Peron d->bd_wdcount = 0; 9914d621040SChristian S.J. Peron d->bd_zcopy = 0; 992df8bae1dSRodney W. Grimes } 993df8bae1dSRodney W. Grimes 994df8bae1dSRodney W. Grimes /* 995df8bae1dSRodney W. Grimes * FIONREAD Check for read packet available. 996df8bae1dSRodney W. Grimes * SIOCGIFADDR Get interface address - convenient hook to driver. 997df8bae1dSRodney W. Grimes * BIOCGBLEN Get buffer len [for read()]. 998f11c3508SDavid Malone * BIOCSETF Set read filter. 999f11c3508SDavid Malone * BIOCSETFNR Set read filter without resetting descriptor. 1000f11c3508SDavid Malone * BIOCSETWF Set write filter. 1001df8bae1dSRodney W. Grimes * BIOCFLUSH Flush read packet buffer. 1002df8bae1dSRodney W. Grimes * BIOCPROMISC Put interface into promiscuous mode. 1003df8bae1dSRodney W. Grimes * BIOCGDLT Get link layer type. 1004df8bae1dSRodney W. Grimes * BIOCGETIF Get interface name. 1005df8bae1dSRodney W. Grimes * BIOCSETIF Set interface. 1006df8bae1dSRodney W. Grimes * BIOCSRTIMEOUT Set read timeout. 1007df8bae1dSRodney W. Grimes * BIOCGRTIMEOUT Get read timeout. 1008df8bae1dSRodney W. Grimes * BIOCGSTATS Get packet stats. 1009df8bae1dSRodney W. Grimes * BIOCIMMEDIATE Set immediate mode. 1010df8bae1dSRodney W. Grimes * BIOCVERSION Get filter language version. 1011114ae644SMike Smith * BIOCGHDRCMPLT Get "header already complete" flag 1012114ae644SMike Smith * BIOCSHDRCMPLT Set "header already complete" flag 1013560a54e1SJung-uk Kim * BIOCGDIRECTION Get packet direction flag 1014560a54e1SJung-uk Kim * BIOCSDIRECTION Set packet direction flag 1015*547d94bdSJung-uk Kim * BIOCGTSTAMP Get time stamp format and resolution. 1016*547d94bdSJung-uk Kim * BIOCSTSTAMP Set time stamp format and resolution. 101793e39f0bSChristian S.J. Peron * BIOCLOCK Set "locked" flag 1018560a54e1SJung-uk Kim * BIOCFEEDBACK Set packet feedback mode. 10194d621040SChristian S.J. Peron * BIOCSETZBUF Set current zero-copy buffer locations. 10204d621040SChristian S.J. Peron * BIOCGETZMAX Get maximum zero-copy buffer size. 10214d621040SChristian S.J. Peron * BIOCROTZBUF Force rotation of zero-copy buffer 10224d621040SChristian S.J. Peron * BIOCSETBUFMODE Set buffer mode. 10234d621040SChristian S.J. Peron * BIOCGETBUFMODE Get current buffer mode. 1024df8bae1dSRodney W. Grimes */ 1025df8bae1dSRodney W. Grimes /* ARGSUSED */ 102687f6c662SJulian Elischer static int 102719ba8395SChristian S.J. Peron bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, 102819ba8395SChristian S.J. Peron struct thread *td) 1029df8bae1dSRodney W. Grimes { 1030136600feSEd Schouten struct bpf_d *d; 1031136600feSEd Schouten int error; 1032136600feSEd Schouten 1033136600feSEd Schouten error = devfs_get_cdevpriv((void **)&d); 1034136600feSEd Schouten if (error != 0) 1035136600feSEd Schouten return (error); 1036df8bae1dSRodney W. Grimes 1037b75a24a0SChristian S.J. Peron /* 1038b75a24a0SChristian S.J. Peron * Refresh PID associated with this descriptor. 1039b75a24a0SChristian S.J. Peron */ 104081bda851SJohn Polstra BPFD_LOCK(d); 1041cb1d4f92SChristian S.J. Peron d->bd_pid = td->td_proc->p_pid; 104281bda851SJohn Polstra if (d->bd_state == BPF_WAITING) 104381bda851SJohn Polstra callout_stop(&d->bd_callout); 104481bda851SJohn Polstra d->bd_state = BPF_IDLE; 104581bda851SJohn Polstra BPFD_UNLOCK(d); 104681bda851SJohn Polstra 104793e39f0bSChristian S.J. Peron if (d->bd_locked == 1) { 104893e39f0bSChristian S.J. Peron switch (cmd) { 104993e39f0bSChristian S.J. Peron case BIOCGBLEN: 105093e39f0bSChristian S.J. Peron case BIOCFLUSH: 105193e39f0bSChristian S.J. Peron case BIOCGDLT: 105293e39f0bSChristian S.J. Peron case BIOCGDLTLIST: 1053fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1054fc0a61a4SKonstantin Belousov case BIOCGDLTLIST32: 1055fc0a61a4SKonstantin Belousov #endif 105693e39f0bSChristian S.J. Peron case BIOCGETIF: 105793e39f0bSChristian S.J. Peron case BIOCGRTIMEOUT: 1058fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1059fc0a61a4SKonstantin Belousov case BIOCGRTIMEOUT32: 1060fc0a61a4SKonstantin Belousov #endif 106193e39f0bSChristian S.J. Peron case BIOCGSTATS: 106293e39f0bSChristian S.J. Peron case BIOCVERSION: 106393e39f0bSChristian S.J. Peron case BIOCGRSIG: 106493e39f0bSChristian S.J. Peron case BIOCGHDRCMPLT: 1065*547d94bdSJung-uk Kim case BIOCSTSTAMP: 1066560a54e1SJung-uk Kim case BIOCFEEDBACK: 106793e39f0bSChristian S.J. Peron case FIONREAD: 106893e39f0bSChristian S.J. Peron case BIOCLOCK: 106993e39f0bSChristian S.J. Peron case BIOCSRTIMEOUT: 1070fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1071fc0a61a4SKonstantin Belousov case BIOCSRTIMEOUT32: 1072fc0a61a4SKonstantin Belousov #endif 107393e39f0bSChristian S.J. Peron case BIOCIMMEDIATE: 107493e39f0bSChristian S.J. Peron case TIOCGPGRP: 10754d621040SChristian S.J. Peron case BIOCROTZBUF: 107693e39f0bSChristian S.J. Peron break; 107793e39f0bSChristian S.J. Peron default: 107893e39f0bSChristian S.J. Peron return (EPERM); 107993e39f0bSChristian S.J. Peron } 108093e39f0bSChristian S.J. Peron } 1081fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1082fc0a61a4SKonstantin Belousov /* 1083fc0a61a4SKonstantin Belousov * If we see a 32-bit compat ioctl, mark the stream as 32-bit so 1084fc0a61a4SKonstantin Belousov * that it will get 32-bit packet headers. 1085fc0a61a4SKonstantin Belousov */ 1086fc0a61a4SKonstantin Belousov switch (cmd) { 1087fc0a61a4SKonstantin Belousov case BIOCSETF32: 1088fc0a61a4SKonstantin Belousov case BIOCSETFNR32: 1089fc0a61a4SKonstantin Belousov case BIOCSETWF32: 1090fc0a61a4SKonstantin Belousov case BIOCGDLTLIST32: 1091fc0a61a4SKonstantin Belousov case BIOCGRTIMEOUT32: 1092fc0a61a4SKonstantin Belousov case BIOCSRTIMEOUT32: 1093fc0a61a4SKonstantin Belousov d->bd_compat32 = 1; 1094fc0a61a4SKonstantin Belousov } 1095fc0a61a4SKonstantin Belousov #endif 1096fc0a61a4SKonstantin Belousov 109797021c24SMarko Zec CURVNET_SET(TD_TO_VNET(td)); 1098df8bae1dSRodney W. Grimes switch (cmd) { 1099df8bae1dSRodney W. Grimes 1100df8bae1dSRodney W. Grimes default: 1101df8bae1dSRodney W. Grimes error = EINVAL; 1102df8bae1dSRodney W. Grimes break; 1103df8bae1dSRodney W. Grimes 1104df8bae1dSRodney W. Grimes /* 1105df8bae1dSRodney W. Grimes * Check for read packet available. 1106df8bae1dSRodney W. Grimes */ 1107df8bae1dSRodney W. Grimes case FIONREAD: 1108df8bae1dSRodney W. Grimes { 1109df8bae1dSRodney W. Grimes int n; 1110df8bae1dSRodney W. Grimes 1111e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1112df8bae1dSRodney W. Grimes n = d->bd_slen; 1113df8bae1dSRodney W. Grimes if (d->bd_hbuf) 1114df8bae1dSRodney W. Grimes n += d->bd_hlen; 1115e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1116df8bae1dSRodney W. Grimes 1117df8bae1dSRodney W. Grimes *(int *)addr = n; 1118df8bae1dSRodney W. Grimes break; 1119df8bae1dSRodney W. Grimes } 1120df8bae1dSRodney W. Grimes 1121df8bae1dSRodney W. Grimes case SIOCGIFADDR: 1122df8bae1dSRodney W. Grimes { 1123df8bae1dSRodney W. Grimes struct ifnet *ifp; 1124df8bae1dSRodney W. Grimes 1125572bde2aSRobert Watson if (d->bd_bif == NULL) 1126df8bae1dSRodney W. Grimes error = EINVAL; 1127df8bae1dSRodney W. Grimes else { 1128df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 1129df8bae1dSRodney W. Grimes error = (*ifp->if_ioctl)(ifp, cmd, addr); 1130df8bae1dSRodney W. Grimes } 1131df8bae1dSRodney W. Grimes break; 1132df8bae1dSRodney W. Grimes } 1133df8bae1dSRodney W. Grimes 1134df8bae1dSRodney W. Grimes /* 1135df8bae1dSRodney W. Grimes * Get buffer len [for read()]. 1136df8bae1dSRodney W. Grimes */ 1137df8bae1dSRodney W. Grimes case BIOCGBLEN: 1138df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bufsize; 1139df8bae1dSRodney W. Grimes break; 1140df8bae1dSRodney W. Grimes 1141df8bae1dSRodney W. Grimes /* 1142df8bae1dSRodney W. Grimes * Set buffer length. 1143df8bae1dSRodney W. Grimes */ 1144df8bae1dSRodney W. Grimes case BIOCSBLEN: 11454d621040SChristian S.J. Peron error = bpf_ioctl_sblen(d, (u_int *)addr); 1146df8bae1dSRodney W. Grimes break; 1147df8bae1dSRodney W. Grimes 1148df8bae1dSRodney W. Grimes /* 1149df8bae1dSRodney W. Grimes * Set link layer read filter. 1150df8bae1dSRodney W. Grimes */ 1151df8bae1dSRodney W. Grimes case BIOCSETF: 1152f11c3508SDavid Malone case BIOCSETFNR: 115393e39f0bSChristian S.J. Peron case BIOCSETWF: 1154fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1155fc0a61a4SKonstantin Belousov case BIOCSETF32: 1156fc0a61a4SKonstantin Belousov case BIOCSETFNR32: 1157fc0a61a4SKonstantin Belousov case BIOCSETWF32: 1158fc0a61a4SKonstantin Belousov #endif 115993e39f0bSChristian S.J. Peron error = bpf_setf(d, (struct bpf_program *)addr, cmd); 1160df8bae1dSRodney W. Grimes break; 1161df8bae1dSRodney W. Grimes 1162df8bae1dSRodney W. Grimes /* 1163df8bae1dSRodney W. Grimes * Flush read packet buffer. 1164df8bae1dSRodney W. Grimes */ 1165df8bae1dSRodney W. Grimes case BIOCFLUSH: 1166e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1167df8bae1dSRodney W. Grimes reset_d(d); 1168e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1169df8bae1dSRodney W. Grimes break; 1170df8bae1dSRodney W. Grimes 1171df8bae1dSRodney W. Grimes /* 1172df8bae1dSRodney W. Grimes * Put interface into promiscuous mode. 1173df8bae1dSRodney W. Grimes */ 1174df8bae1dSRodney W. Grimes case BIOCPROMISC: 1175572bde2aSRobert Watson if (d->bd_bif == NULL) { 1176df8bae1dSRodney W. Grimes /* 1177df8bae1dSRodney W. Grimes * No interface attached yet. 1178df8bae1dSRodney W. Grimes */ 1179df8bae1dSRodney W. Grimes error = EINVAL; 1180df8bae1dSRodney W. Grimes break; 1181df8bae1dSRodney W. Grimes } 1182df8bae1dSRodney W. Grimes if (d->bd_promisc == 0) { 1183df8bae1dSRodney W. Grimes error = ifpromisc(d->bd_bif->bif_ifp, 1); 1184df8bae1dSRodney W. Grimes if (error == 0) 1185df8bae1dSRodney W. Grimes d->bd_promisc = 1; 1186df8bae1dSRodney W. Grimes } 1187df8bae1dSRodney W. Grimes break; 1188df8bae1dSRodney W. Grimes 1189df8bae1dSRodney W. Grimes /* 11908eab61f3SSam Leffler * Get current data link type. 1191df8bae1dSRodney W. Grimes */ 1192df8bae1dSRodney W. Grimes case BIOCGDLT: 1193572bde2aSRobert Watson if (d->bd_bif == NULL) 1194df8bae1dSRodney W. Grimes error = EINVAL; 1195df8bae1dSRodney W. Grimes else 1196df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bif->bif_dlt; 1197df8bae1dSRodney W. Grimes break; 1198df8bae1dSRodney W. Grimes 1199df8bae1dSRodney W. Grimes /* 12008eab61f3SSam Leffler * Get a list of supported data link types. 12018eab61f3SSam Leffler */ 1202fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1203fc0a61a4SKonstantin Belousov case BIOCGDLTLIST32: 1204fc0a61a4SKonstantin Belousov { 1205fc0a61a4SKonstantin Belousov struct bpf_dltlist32 *list32; 1206fc0a61a4SKonstantin Belousov struct bpf_dltlist dltlist; 1207fc0a61a4SKonstantin Belousov 1208fc0a61a4SKonstantin Belousov list32 = (struct bpf_dltlist32 *)addr; 1209fc0a61a4SKonstantin Belousov dltlist.bfl_len = list32->bfl_len; 1210fc0a61a4SKonstantin Belousov dltlist.bfl_list = PTRIN(list32->bfl_list); 1211fc0a61a4SKonstantin Belousov if (d->bd_bif == NULL) 1212fc0a61a4SKonstantin Belousov error = EINVAL; 1213fc0a61a4SKonstantin Belousov else { 1214fc0a61a4SKonstantin Belousov error = bpf_getdltlist(d, &dltlist); 1215fc0a61a4SKonstantin Belousov if (error == 0) 1216fc0a61a4SKonstantin Belousov list32->bfl_len = dltlist.bfl_len; 1217fc0a61a4SKonstantin Belousov } 1218fc0a61a4SKonstantin Belousov break; 1219fc0a61a4SKonstantin Belousov } 1220fc0a61a4SKonstantin Belousov #endif 1221fc0a61a4SKonstantin Belousov 12228eab61f3SSam Leffler case BIOCGDLTLIST: 1223572bde2aSRobert Watson if (d->bd_bif == NULL) 12248eab61f3SSam Leffler error = EINVAL; 12258eab61f3SSam Leffler else 12268eab61f3SSam Leffler error = bpf_getdltlist(d, (struct bpf_dltlist *)addr); 12278eab61f3SSam Leffler break; 12288eab61f3SSam Leffler 12298eab61f3SSam Leffler /* 12308eab61f3SSam Leffler * Set data link type. 12318eab61f3SSam Leffler */ 12328eab61f3SSam Leffler case BIOCSDLT: 1233572bde2aSRobert Watson if (d->bd_bif == NULL) 12348eab61f3SSam Leffler error = EINVAL; 12358eab61f3SSam Leffler else 12368eab61f3SSam Leffler error = bpf_setdlt(d, *(u_int *)addr); 12378eab61f3SSam Leffler break; 12388eab61f3SSam Leffler 12398eab61f3SSam Leffler /* 12401dd0feaaSArchie Cobbs * Get interface name. 1241df8bae1dSRodney W. Grimes */ 1242df8bae1dSRodney W. Grimes case BIOCGETIF: 1243572bde2aSRobert Watson if (d->bd_bif == NULL) 1244df8bae1dSRodney W. Grimes error = EINVAL; 12451dd0feaaSArchie Cobbs else { 12461dd0feaaSArchie Cobbs struct ifnet *const ifp = d->bd_bif->bif_ifp; 12471dd0feaaSArchie Cobbs struct ifreq *const ifr = (struct ifreq *)addr; 12481dd0feaaSArchie Cobbs 12499bf40edeSBrooks Davis strlcpy(ifr->ifr_name, ifp->if_xname, 12509bf40edeSBrooks Davis sizeof(ifr->ifr_name)); 12511dd0feaaSArchie Cobbs } 1252df8bae1dSRodney W. Grimes break; 1253df8bae1dSRodney W. Grimes 1254df8bae1dSRodney W. Grimes /* 1255df8bae1dSRodney W. Grimes * Set interface. 1256df8bae1dSRodney W. Grimes */ 1257df8bae1dSRodney W. Grimes case BIOCSETIF: 1258df8bae1dSRodney W. Grimes error = bpf_setif(d, (struct ifreq *)addr); 1259df8bae1dSRodney W. Grimes break; 1260df8bae1dSRodney W. Grimes 1261df8bae1dSRodney W. Grimes /* 1262df8bae1dSRodney W. Grimes * Set read timeout. 1263df8bae1dSRodney W. Grimes */ 1264df8bae1dSRodney W. Grimes case BIOCSRTIMEOUT: 1265fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1266fc0a61a4SKonstantin Belousov case BIOCSRTIMEOUT32: 1267fc0a61a4SKonstantin Belousov #endif 1268df8bae1dSRodney W. Grimes { 1269df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 1270fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1271fc0a61a4SKonstantin Belousov struct timeval32 *tv32; 1272fc0a61a4SKonstantin Belousov struct timeval tv64; 1273fc0a61a4SKonstantin Belousov 1274fc0a61a4SKonstantin Belousov if (cmd == BIOCSRTIMEOUT32) { 1275fc0a61a4SKonstantin Belousov tv32 = (struct timeval32 *)addr; 1276fc0a61a4SKonstantin Belousov tv = &tv64; 1277fc0a61a4SKonstantin Belousov tv->tv_sec = tv32->tv_sec; 1278fc0a61a4SKonstantin Belousov tv->tv_usec = tv32->tv_usec; 1279fc0a61a4SKonstantin Belousov } else 1280fc0a61a4SKonstantin Belousov #endif 1281fc0a61a4SKonstantin Belousov tv = (struct timeval *)addr; 1282df8bae1dSRodney W. Grimes 1283bdc2cdc5SAlexander Langer /* 1284bdc2cdc5SAlexander Langer * Subtract 1 tick from tvtohz() since this isn't 1285bdc2cdc5SAlexander Langer * a one-shot timer. 1286bdc2cdc5SAlexander Langer */ 1287bdc2cdc5SAlexander Langer if ((error = itimerfix(tv)) == 0) 1288bdc2cdc5SAlexander Langer d->bd_rtout = tvtohz(tv) - 1; 1289df8bae1dSRodney W. Grimes break; 1290df8bae1dSRodney W. Grimes } 1291df8bae1dSRodney W. Grimes 1292df8bae1dSRodney W. Grimes /* 1293df8bae1dSRodney W. Grimes * Get read timeout. 1294df8bae1dSRodney W. Grimes */ 1295df8bae1dSRodney W. Grimes case BIOCGRTIMEOUT: 1296fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1297fc0a61a4SKonstantin Belousov case BIOCGRTIMEOUT32: 1298fc0a61a4SKonstantin Belousov #endif 1299df8bae1dSRodney W. Grimes { 1300fc0a61a4SKonstantin Belousov struct timeval *tv; 1301fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1302fc0a61a4SKonstantin Belousov struct timeval32 *tv32; 1303fc0a61a4SKonstantin Belousov struct timeval tv64; 1304fc0a61a4SKonstantin Belousov 1305fc0a61a4SKonstantin Belousov if (cmd == BIOCGRTIMEOUT32) 1306fc0a61a4SKonstantin Belousov tv = &tv64; 1307fc0a61a4SKonstantin Belousov else 1308fc0a61a4SKonstantin Belousov #endif 1309fc0a61a4SKonstantin Belousov tv = (struct timeval *)addr; 1310df8bae1dSRodney W. Grimes 1311bdc2cdc5SAlexander Langer tv->tv_sec = d->bd_rtout / hz; 1312bdc2cdc5SAlexander Langer tv->tv_usec = (d->bd_rtout % hz) * tick; 1313fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1314fc0a61a4SKonstantin Belousov if (cmd == BIOCGRTIMEOUT32) { 1315fc0a61a4SKonstantin Belousov tv32 = (struct timeval32 *)addr; 1316fc0a61a4SKonstantin Belousov tv32->tv_sec = tv->tv_sec; 1317fc0a61a4SKonstantin Belousov tv32->tv_usec = tv->tv_usec; 1318fc0a61a4SKonstantin Belousov } 1319fc0a61a4SKonstantin Belousov #endif 1320fc0a61a4SKonstantin Belousov 1321df8bae1dSRodney W. Grimes break; 1322df8bae1dSRodney W. Grimes } 1323df8bae1dSRodney W. Grimes 1324df8bae1dSRodney W. Grimes /* 1325df8bae1dSRodney W. Grimes * Get packet stats. 1326df8bae1dSRodney W. Grimes */ 1327df8bae1dSRodney W. Grimes case BIOCGSTATS: 1328df8bae1dSRodney W. Grimes { 1329df8bae1dSRodney W. Grimes struct bpf_stat *bs = (struct bpf_stat *)addr; 1330df8bae1dSRodney W. Grimes 13314d621040SChristian S.J. Peron /* XXXCSJP overflow */ 1332df8bae1dSRodney W. Grimes bs->bs_recv = d->bd_rcount; 1333df8bae1dSRodney W. Grimes bs->bs_drop = d->bd_dcount; 1334df8bae1dSRodney W. Grimes break; 1335df8bae1dSRodney W. Grimes } 1336df8bae1dSRodney W. Grimes 1337df8bae1dSRodney W. Grimes /* 1338df8bae1dSRodney W. Grimes * Set immediate mode. 1339df8bae1dSRodney W. Grimes */ 1340df8bae1dSRodney W. Grimes case BIOCIMMEDIATE: 1341df8bae1dSRodney W. Grimes d->bd_immediate = *(u_int *)addr; 1342df8bae1dSRodney W. Grimes break; 1343df8bae1dSRodney W. Grimes 1344df8bae1dSRodney W. Grimes case BIOCVERSION: 1345df8bae1dSRodney W. Grimes { 1346df8bae1dSRodney W. Grimes struct bpf_version *bv = (struct bpf_version *)addr; 1347df8bae1dSRodney W. Grimes 1348df8bae1dSRodney W. Grimes bv->bv_major = BPF_MAJOR_VERSION; 1349df8bae1dSRodney W. Grimes bv->bv_minor = BPF_MINOR_VERSION; 1350df8bae1dSRodney W. Grimes break; 1351df8bae1dSRodney W. Grimes } 135200a83887SPaul Traina 1353114ae644SMike Smith /* 1354114ae644SMike Smith * Get "header already complete" flag 1355114ae644SMike Smith */ 1356114ae644SMike Smith case BIOCGHDRCMPLT: 1357114ae644SMike Smith *(u_int *)addr = d->bd_hdrcmplt; 1358114ae644SMike Smith break; 1359114ae644SMike Smith 1360114ae644SMike Smith /* 1361114ae644SMike Smith * Set "header already complete" flag 1362114ae644SMike Smith */ 1363114ae644SMike Smith case BIOCSHDRCMPLT: 1364114ae644SMike Smith d->bd_hdrcmplt = *(u_int *)addr ? 1 : 0; 1365114ae644SMike Smith break; 1366114ae644SMike Smith 13678ed3828cSRobert Watson /* 1368560a54e1SJung-uk Kim * Get packet direction flag 13698ed3828cSRobert Watson */ 1370560a54e1SJung-uk Kim case BIOCGDIRECTION: 1371560a54e1SJung-uk Kim *(u_int *)addr = d->bd_direction; 13728ed3828cSRobert Watson break; 13738ed3828cSRobert Watson 13748ed3828cSRobert Watson /* 1375560a54e1SJung-uk Kim * Set packet direction flag 13768ed3828cSRobert Watson */ 1377560a54e1SJung-uk Kim case BIOCSDIRECTION: 1378560a54e1SJung-uk Kim { 1379560a54e1SJung-uk Kim u_int direction; 1380560a54e1SJung-uk Kim 1381560a54e1SJung-uk Kim direction = *(u_int *)addr; 1382560a54e1SJung-uk Kim switch (direction) { 1383560a54e1SJung-uk Kim case BPF_D_IN: 1384560a54e1SJung-uk Kim case BPF_D_INOUT: 1385560a54e1SJung-uk Kim case BPF_D_OUT: 1386560a54e1SJung-uk Kim d->bd_direction = direction; 1387560a54e1SJung-uk Kim break; 1388560a54e1SJung-uk Kim default: 1389560a54e1SJung-uk Kim error = EINVAL; 1390560a54e1SJung-uk Kim } 1391560a54e1SJung-uk Kim } 1392560a54e1SJung-uk Kim break; 1393560a54e1SJung-uk Kim 1394*547d94bdSJung-uk Kim /* 1395*547d94bdSJung-uk Kim * Set packet timestamp format and resolution. 1396*547d94bdSJung-uk Kim */ 1397*547d94bdSJung-uk Kim case BIOCGTSTAMP: 1398*547d94bdSJung-uk Kim *(u_int *)addr = d->bd_tstamp; 1399*547d94bdSJung-uk Kim break; 1400*547d94bdSJung-uk Kim 1401*547d94bdSJung-uk Kim /* 1402*547d94bdSJung-uk Kim * Set packet timestamp format and resolution. 1403*547d94bdSJung-uk Kim */ 1404*547d94bdSJung-uk Kim case BIOCSTSTAMP: 1405*547d94bdSJung-uk Kim { 1406*547d94bdSJung-uk Kim u_int func; 1407*547d94bdSJung-uk Kim 1408*547d94bdSJung-uk Kim func = *(u_int *)addr; 1409*547d94bdSJung-uk Kim if (BPF_T_VALID(func)) 1410*547d94bdSJung-uk Kim d->bd_tstamp = func; 1411*547d94bdSJung-uk Kim else 1412*547d94bdSJung-uk Kim error = EINVAL; 1413*547d94bdSJung-uk Kim } 1414*547d94bdSJung-uk Kim break; 1415*547d94bdSJung-uk Kim 1416560a54e1SJung-uk Kim case BIOCFEEDBACK: 1417560a54e1SJung-uk Kim d->bd_feedback = *(u_int *)addr; 1418560a54e1SJung-uk Kim break; 1419560a54e1SJung-uk Kim 1420560a54e1SJung-uk Kim case BIOCLOCK: 1421560a54e1SJung-uk Kim d->bd_locked = 1; 14228ed3828cSRobert Watson break; 14238ed3828cSRobert Watson 142400a83887SPaul Traina case FIONBIO: /* Non-blocking I/O */ 142500a83887SPaul Traina break; 142600a83887SPaul Traina 142700a83887SPaul Traina case FIOASYNC: /* Send signal on receive packets */ 142800a83887SPaul Traina d->bd_async = *(int *)addr; 142900a83887SPaul Traina break; 143000a83887SPaul Traina 1431831d27a9SDon Lewis case FIOSETOWN: 1432831d27a9SDon Lewis error = fsetown(*(int *)addr, &d->bd_sigio); 143300a83887SPaul Traina break; 143400a83887SPaul Traina 1435831d27a9SDon Lewis case FIOGETOWN: 143691e97a82SDon Lewis *(int *)addr = fgetown(&d->bd_sigio); 1437831d27a9SDon Lewis break; 1438831d27a9SDon Lewis 1439831d27a9SDon Lewis /* This is deprecated, FIOSETOWN should be used instead. */ 1440831d27a9SDon Lewis case TIOCSPGRP: 1441831d27a9SDon Lewis error = fsetown(-(*(int *)addr), &d->bd_sigio); 1442831d27a9SDon Lewis break; 1443831d27a9SDon Lewis 1444831d27a9SDon Lewis /* This is deprecated, FIOGETOWN should be used instead. */ 144500a83887SPaul Traina case TIOCGPGRP: 144691e97a82SDon Lewis *(int *)addr = -fgetown(&d->bd_sigio); 144700a83887SPaul Traina break; 144800a83887SPaul Traina 144900a83887SPaul Traina case BIOCSRSIG: /* Set receive signal */ 145000a83887SPaul Traina { 145100a83887SPaul Traina u_int sig; 145200a83887SPaul Traina 145300a83887SPaul Traina sig = *(u_int *)addr; 145400a83887SPaul Traina 145500a83887SPaul Traina if (sig >= NSIG) 145600a83887SPaul Traina error = EINVAL; 145700a83887SPaul Traina else 145800a83887SPaul Traina d->bd_sig = sig; 145900a83887SPaul Traina break; 146000a83887SPaul Traina } 146100a83887SPaul Traina case BIOCGRSIG: 146200a83887SPaul Traina *(u_int *)addr = d->bd_sig; 146300a83887SPaul Traina break; 14644d621040SChristian S.J. Peron 14654d621040SChristian S.J. Peron case BIOCGETBUFMODE: 14664d621040SChristian S.J. Peron *(u_int *)addr = d->bd_bufmode; 14674d621040SChristian S.J. Peron break; 14684d621040SChristian S.J. Peron 14694d621040SChristian S.J. Peron case BIOCSETBUFMODE: 14704d621040SChristian S.J. Peron /* 14714d621040SChristian S.J. Peron * Allow the buffering mode to be changed as long as we 14724d621040SChristian S.J. Peron * haven't yet committed to a particular mode. Our 14734d621040SChristian S.J. Peron * definition of commitment, for now, is whether or not a 14744d621040SChristian S.J. Peron * buffer has been allocated or an interface attached, since 14754d621040SChristian S.J. Peron * that's the point where things get tricky. 14764d621040SChristian S.J. Peron */ 14774d621040SChristian S.J. Peron switch (*(u_int *)addr) { 14784d621040SChristian S.J. Peron case BPF_BUFMODE_BUFFER: 14794d621040SChristian S.J. Peron break; 14804d621040SChristian S.J. Peron 14814d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 14824d621040SChristian S.J. Peron if (bpf_zerocopy_enable) 14834d621040SChristian S.J. Peron break; 14844d621040SChristian S.J. Peron /* FALLSTHROUGH */ 14854d621040SChristian S.J. Peron 14864d621040SChristian S.J. Peron default: 14871b610a74SBjoern A. Zeeb CURVNET_RESTORE(); 14884d621040SChristian S.J. Peron return (EINVAL); 14894d621040SChristian S.J. Peron } 14904d621040SChristian S.J. Peron 14914d621040SChristian S.J. Peron BPFD_LOCK(d); 14924d621040SChristian S.J. Peron if (d->bd_sbuf != NULL || d->bd_hbuf != NULL || 14934d621040SChristian S.J. Peron d->bd_fbuf != NULL || d->bd_bif != NULL) { 14944d621040SChristian S.J. Peron BPFD_UNLOCK(d); 14951b610a74SBjoern A. Zeeb CURVNET_RESTORE(); 14964d621040SChristian S.J. Peron return (EBUSY); 14974d621040SChristian S.J. Peron } 14984d621040SChristian S.J. Peron d->bd_bufmode = *(u_int *)addr; 14994d621040SChristian S.J. Peron BPFD_UNLOCK(d); 15004d621040SChristian S.J. Peron break; 15014d621040SChristian S.J. Peron 15024d621040SChristian S.J. Peron case BIOCGETZMAX: 15031b610a74SBjoern A. Zeeb error = bpf_ioctl_getzmax(td, d, (size_t *)addr); 15041b610a74SBjoern A. Zeeb break; 15054d621040SChristian S.J. Peron 15064d621040SChristian S.J. Peron case BIOCSETZBUF: 15071b610a74SBjoern A. Zeeb error = bpf_ioctl_setzbuf(td, d, (struct bpf_zbuf *)addr); 15081b610a74SBjoern A. Zeeb break; 15094d621040SChristian S.J. Peron 15104d621040SChristian S.J. Peron case BIOCROTZBUF: 15111b610a74SBjoern A. Zeeb error = bpf_ioctl_rotzbuf(td, d, (struct bpf_zbuf *)addr); 15121b610a74SBjoern A. Zeeb break; 1513df8bae1dSRodney W. Grimes } 151497021c24SMarko Zec CURVNET_RESTORE(); 1515df8bae1dSRodney W. Grimes return (error); 1516df8bae1dSRodney W. Grimes } 1517df8bae1dSRodney W. Grimes 1518df8bae1dSRodney W. Grimes /* 1519df8bae1dSRodney W. Grimes * Set d's packet filter program to fp. If this file already has a filter, 1520df8bae1dSRodney W. Grimes * free it and replace it. Returns EINVAL for bogus requests. 1521df8bae1dSRodney W. Grimes */ 1522f708ef1bSPoul-Henning Kamp static int 152319ba8395SChristian S.J. Peron bpf_setf(struct bpf_d *d, struct bpf_program *fp, u_long cmd) 1524df8bae1dSRodney W. Grimes { 1525df8bae1dSRodney W. Grimes struct bpf_insn *fcode, *old; 152693e39f0bSChristian S.J. Peron u_int wfilter, flen, size; 1527293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1528ae275efcSJung-uk Kim bpf_jit_filter *ofunc; 1529ae275efcSJung-uk Kim #endif 1530fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 1531fc0a61a4SKonstantin Belousov struct bpf_program32 *fp32; 1532fc0a61a4SKonstantin Belousov struct bpf_program fp_swab; 1533df8bae1dSRodney W. Grimes 1534fc0a61a4SKonstantin Belousov if (cmd == BIOCSETWF32 || cmd == BIOCSETF32 || cmd == BIOCSETFNR32) { 1535fc0a61a4SKonstantin Belousov fp32 = (struct bpf_program32 *)fp; 1536fc0a61a4SKonstantin Belousov fp_swab.bf_len = fp32->bf_len; 1537fc0a61a4SKonstantin Belousov fp_swab.bf_insns = (struct bpf_insn *)(uintptr_t)fp32->bf_insns; 1538fc0a61a4SKonstantin Belousov fp = &fp_swab; 1539fc0a61a4SKonstantin Belousov if (cmd == BIOCSETWF32) 1540fc0a61a4SKonstantin Belousov cmd = BIOCSETWF; 1541fc0a61a4SKonstantin Belousov } 1542fc0a61a4SKonstantin Belousov #endif 154393e39f0bSChristian S.J. Peron if (cmd == BIOCSETWF) { 154493e39f0bSChristian S.J. Peron old = d->bd_wfilter; 154593e39f0bSChristian S.J. Peron wfilter = 1; 1546293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1547ae275efcSJung-uk Kim ofunc = NULL; 1548ae275efcSJung-uk Kim #endif 154993e39f0bSChristian S.J. Peron } else { 155093e39f0bSChristian S.J. Peron wfilter = 0; 155193e39f0bSChristian S.J. Peron old = d->bd_rfilter; 1552293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1553ae275efcSJung-uk Kim ofunc = d->bd_bfilter; 1554ae275efcSJung-uk Kim #endif 155593e39f0bSChristian S.J. Peron } 1556572bde2aSRobert Watson if (fp->bf_insns == NULL) { 1557df8bae1dSRodney W. Grimes if (fp->bf_len != 0) 1558df8bae1dSRodney W. Grimes return (EINVAL); 1559e7bb21b3SJonathan Lemon BPFD_LOCK(d); 156093e39f0bSChristian S.J. Peron if (wfilter) 156193e39f0bSChristian S.J. Peron d->bd_wfilter = NULL; 1562ae275efcSJung-uk Kim else { 156393e39f0bSChristian S.J. Peron d->bd_rfilter = NULL; 1564293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1565ae275efcSJung-uk Kim d->bd_bfilter = NULL; 1566ae275efcSJung-uk Kim #endif 1567f11c3508SDavid Malone if (cmd == BIOCSETF) 1568df8bae1dSRodney W. Grimes reset_d(d); 1569f11c3508SDavid Malone } 1570e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1571572bde2aSRobert Watson if (old != NULL) 1572bd3a5320SPoul-Henning Kamp free((caddr_t)old, M_BPF); 1573293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1574ae275efcSJung-uk Kim if (ofunc != NULL) 1575ae275efcSJung-uk Kim bpf_destroy_jit_filter(ofunc); 1576ae275efcSJung-uk Kim #endif 1577df8bae1dSRodney W. Grimes return (0); 1578df8bae1dSRodney W. Grimes } 1579df8bae1dSRodney W. Grimes flen = fp->bf_len; 15800eb20604SChristian S.J. Peron if (flen > bpf_maxinsns) 1581df8bae1dSRodney W. Grimes return (EINVAL); 1582df8bae1dSRodney W. Grimes 1583df8bae1dSRodney W. Grimes size = flen * sizeof(*fp->bf_insns); 1584a163d034SWarner Losh fcode = (struct bpf_insn *)malloc(size, M_BPF, M_WAITOK); 1585df8bae1dSRodney W. Grimes if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 && 1586df8bae1dSRodney W. Grimes bpf_validate(fcode, (int)flen)) { 1587e7bb21b3SJonathan Lemon BPFD_LOCK(d); 158893e39f0bSChristian S.J. Peron if (wfilter) 158993e39f0bSChristian S.J. Peron d->bd_wfilter = fcode; 1590ae275efcSJung-uk Kim else { 159193e39f0bSChristian S.J. Peron d->bd_rfilter = fcode; 1592293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1593ae275efcSJung-uk Kim d->bd_bfilter = bpf_jitter(fcode, flen); 1594ae275efcSJung-uk Kim #endif 1595f11c3508SDavid Malone if (cmd == BIOCSETF) 1596df8bae1dSRodney W. Grimes reset_d(d); 1597f11c3508SDavid Malone } 1598e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1599572bde2aSRobert Watson if (old != NULL) 1600bd3a5320SPoul-Henning Kamp free((caddr_t)old, M_BPF); 1601293c06a1SRuslan Ermilov #ifdef BPF_JITTER 1602ae275efcSJung-uk Kim if (ofunc != NULL) 1603ae275efcSJung-uk Kim bpf_destroy_jit_filter(ofunc); 1604ae275efcSJung-uk Kim #endif 1605df8bae1dSRodney W. Grimes 1606df8bae1dSRodney W. Grimes return (0); 1607df8bae1dSRodney W. Grimes } 1608bd3a5320SPoul-Henning Kamp free((caddr_t)fcode, M_BPF); 1609df8bae1dSRodney W. Grimes return (EINVAL); 1610df8bae1dSRodney W. Grimes } 1611df8bae1dSRodney W. Grimes 1612df8bae1dSRodney W. Grimes /* 1613df8bae1dSRodney W. Grimes * Detach a file from its current interface (if attached at all) and attach 1614df8bae1dSRodney W. Grimes * to the interface indicated by the name stored in ifr. 1615df8bae1dSRodney W. Grimes * Return an errno or 0. 1616df8bae1dSRodney W. Grimes */ 1617df8bae1dSRodney W. Grimes static int 161819ba8395SChristian S.J. Peron bpf_setif(struct bpf_d *d, struct ifreq *ifr) 1619df8bae1dSRodney W. Grimes { 1620df8bae1dSRodney W. Grimes struct bpf_if *bp; 16219b44ff22SGarrett Wollman struct ifnet *theywant; 1622df8bae1dSRodney W. Grimes 16239b44ff22SGarrett Wollman theywant = ifunit(ifr->ifr_name); 162416d878ccSChristian S.J. Peron if (theywant == NULL || theywant->if_bpf == NULL) 162516d878ccSChristian S.J. Peron return (ENXIO); 16269b44ff22SGarrett Wollman 162716d878ccSChristian S.J. Peron bp = theywant->if_bpf; 16284d621040SChristian S.J. Peron 1629df8bae1dSRodney W. Grimes /* 16304d621040SChristian S.J. Peron * Behavior here depends on the buffering model. If we're using 16314d621040SChristian S.J. Peron * kernel memory buffers, then we can allocate them here. If we're 16324d621040SChristian S.J. Peron * using zero-copy, then the user process must have registered 16334d621040SChristian S.J. Peron * buffers by the time we get here. If not, return an error. 16344d621040SChristian S.J. Peron * 16354d621040SChristian S.J. Peron * XXXRW: There are locking issues here with multi-threaded use: what 16364d621040SChristian S.J. Peron * if two threads try to set the interface at once? 1637df8bae1dSRodney W. Grimes */ 16384d621040SChristian S.J. Peron switch (d->bd_bufmode) { 16394d621040SChristian S.J. Peron case BPF_BUFMODE_BUFFER: 1640a3594432SRobert Watson if (d->bd_sbuf == NULL) 16414d621040SChristian S.J. Peron bpf_buffer_alloc(d); 16424d621040SChristian S.J. Peron KASSERT(d->bd_sbuf != NULL, ("bpf_setif: bd_sbuf NULL")); 16434d621040SChristian S.J. Peron break; 16444d621040SChristian S.J. Peron 16454d621040SChristian S.J. Peron case BPF_BUFMODE_ZBUF: 16464d621040SChristian S.J. Peron if (d->bd_sbuf == NULL) 16474d621040SChristian S.J. Peron return (EINVAL); 16484d621040SChristian S.J. Peron break; 16494d621040SChristian S.J. Peron 16504d621040SChristian S.J. Peron default: 16514d621040SChristian S.J. Peron panic("bpf_setif: bufmode %d", d->bd_bufmode); 16524d621040SChristian S.J. Peron } 1653df8bae1dSRodney W. Grimes if (bp != d->bd_bif) { 1654df8bae1dSRodney W. Grimes if (d->bd_bif) 1655df8bae1dSRodney W. Grimes /* 1656df8bae1dSRodney W. Grimes * Detach if attached to something else. 1657df8bae1dSRodney W. Grimes */ 1658df8bae1dSRodney W. Grimes bpf_detachd(d); 1659df8bae1dSRodney W. Grimes 1660df8bae1dSRodney W. Grimes bpf_attachd(d, bp); 1661df8bae1dSRodney W. Grimes } 1662e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1663df8bae1dSRodney W. Grimes reset_d(d); 1664e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1665df8bae1dSRodney W. Grimes return (0); 1666df8bae1dSRodney W. Grimes } 1667df8bae1dSRodney W. Grimes 1668df8bae1dSRodney W. Grimes /* 1669243ac7d8SPeter Wemm * Support for select() and poll() system calls 1670df8bae1dSRodney W. Grimes * 1671df8bae1dSRodney W. Grimes * Return true iff the specific operation will not block indefinitely. 1672df8bae1dSRodney W. Grimes * Otherwise, return false but make a note that a selwakeup() must be done. 1673df8bae1dSRodney W. Grimes */ 167437c84183SPoul-Henning Kamp static int 167519ba8395SChristian S.J. Peron bpfpoll(struct cdev *dev, int events, struct thread *td) 1676df8bae1dSRodney W. Grimes { 1677e7bb21b3SJonathan Lemon struct bpf_d *d; 16780832fc64SGarance A Drosehn int revents; 1679df8bae1dSRodney W. Grimes 1680136600feSEd Schouten if (devfs_get_cdevpriv((void **)&d) != 0 || d->bd_bif == NULL) 1681136600feSEd Schouten return (events & 1682136600feSEd Schouten (POLLHUP|POLLIN|POLLRDNORM|POLLOUT|POLLWRNORM)); 1683de5d9935SRobert Watson 1684b75a24a0SChristian S.J. Peron /* 1685b75a24a0SChristian S.J. Peron * Refresh PID associated with this descriptor. 1686b75a24a0SChristian S.J. Peron */ 16870832fc64SGarance A Drosehn revents = events & (POLLOUT | POLLWRNORM); 1688e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1689cb1d4f92SChristian S.J. Peron d->bd_pid = td->td_proc->p_pid; 169075c13541SPoul-Henning Kamp if (events & (POLLIN | POLLRDNORM)) { 169195aab9ccSJohn-Mark Gurney if (bpf_ready(d)) 1692243ac7d8SPeter Wemm revents |= events & (POLLIN | POLLRDNORM); 169381bda851SJohn Polstra else { 1694ed01445dSJohn Baldwin selrecord(td, &d->bd_sel); 169581bda851SJohn Polstra /* Start the read timeout if necessary. */ 169681bda851SJohn Polstra if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) { 169781bda851SJohn Polstra callout_reset(&d->bd_callout, d->bd_rtout, 169881bda851SJohn Polstra bpf_timed_out, d); 169981bda851SJohn Polstra d->bd_state = BPF_WAITING; 170081bda851SJohn Polstra } 170181bda851SJohn Polstra } 170275c13541SPoul-Henning Kamp } 1703e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1704243ac7d8SPeter Wemm return (revents); 1705df8bae1dSRodney W. Grimes } 1706df8bae1dSRodney W. Grimes 1707df8bae1dSRodney W. Grimes /* 170895aab9ccSJohn-Mark Gurney * Support for kevent() system call. Register EVFILT_READ filters and 170995aab9ccSJohn-Mark Gurney * reject all others. 171095aab9ccSJohn-Mark Gurney */ 171195aab9ccSJohn-Mark Gurney int 171219ba8395SChristian S.J. Peron bpfkqfilter(struct cdev *dev, struct knote *kn) 171395aab9ccSJohn-Mark Gurney { 1714136600feSEd Schouten struct bpf_d *d; 171595aab9ccSJohn-Mark Gurney 1716136600feSEd Schouten if (devfs_get_cdevpriv((void **)&d) != 0 || 1717136600feSEd Schouten kn->kn_filter != EVFILT_READ) 171895aab9ccSJohn-Mark Gurney return (1); 171995aab9ccSJohn-Mark Gurney 1720b75a24a0SChristian S.J. Peron /* 1721b75a24a0SChristian S.J. Peron * Refresh PID associated with this descriptor. 1722b75a24a0SChristian S.J. Peron */ 1723cb1d4f92SChristian S.J. Peron BPFD_LOCK(d); 1724b75a24a0SChristian S.J. Peron d->bd_pid = curthread->td_proc->p_pid; 172595aab9ccSJohn-Mark Gurney kn->kn_fop = &bpfread_filtops; 172695aab9ccSJohn-Mark Gurney kn->kn_hook = d; 17274b19419eSChristian S.J. Peron knlist_add(&d->bd_sel.si_note, kn, 1); 1728cb1d4f92SChristian S.J. Peron BPFD_UNLOCK(d); 172995aab9ccSJohn-Mark Gurney 173095aab9ccSJohn-Mark Gurney return (0); 173195aab9ccSJohn-Mark Gurney } 173295aab9ccSJohn-Mark Gurney 173395aab9ccSJohn-Mark Gurney static void 173419ba8395SChristian S.J. Peron filt_bpfdetach(struct knote *kn) 173595aab9ccSJohn-Mark Gurney { 173695aab9ccSJohn-Mark Gurney struct bpf_d *d = (struct bpf_d *)kn->kn_hook; 173795aab9ccSJohn-Mark Gurney 1738ad3b9257SJohn-Mark Gurney knlist_remove(&d->bd_sel.si_note, kn, 0); 173995aab9ccSJohn-Mark Gurney } 174095aab9ccSJohn-Mark Gurney 174195aab9ccSJohn-Mark Gurney static int 174219ba8395SChristian S.J. Peron filt_bpfread(struct knote *kn, long hint) 174395aab9ccSJohn-Mark Gurney { 174495aab9ccSJohn-Mark Gurney struct bpf_d *d = (struct bpf_d *)kn->kn_hook; 174595aab9ccSJohn-Mark Gurney int ready; 174695aab9ccSJohn-Mark Gurney 174786c9a453SJohn-Mark Gurney BPFD_LOCK_ASSERT(d); 174895aab9ccSJohn-Mark Gurney ready = bpf_ready(d); 174995aab9ccSJohn-Mark Gurney if (ready) { 175095aab9ccSJohn-Mark Gurney kn->kn_data = d->bd_slen; 175195aab9ccSJohn-Mark Gurney if (d->bd_hbuf) 175295aab9ccSJohn-Mark Gurney kn->kn_data += d->bd_hlen; 17535d7af3a1SJung-uk Kim } else if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) { 175495aab9ccSJohn-Mark Gurney callout_reset(&d->bd_callout, d->bd_rtout, 175595aab9ccSJohn-Mark Gurney bpf_timed_out, d); 175695aab9ccSJohn-Mark Gurney d->bd_state = BPF_WAITING; 175795aab9ccSJohn-Mark Gurney } 175895aab9ccSJohn-Mark Gurney 175995aab9ccSJohn-Mark Gurney return (ready); 176095aab9ccSJohn-Mark Gurney } 176195aab9ccSJohn-Mark Gurney 1762*547d94bdSJung-uk Kim #define BPF_TSTAMP_NONE 0 1763*547d94bdSJung-uk Kim #define BPF_TSTAMP_FAST 1 1764*547d94bdSJung-uk Kim #define BPF_TSTAMP_NORMAL 2 1765*547d94bdSJung-uk Kim #define BPF_TSTAMP_EXTERN 3 1766*547d94bdSJung-uk Kim 1767*547d94bdSJung-uk Kim static int 1768*547d94bdSJung-uk Kim bpf_ts_quality(int tstype) 1769*547d94bdSJung-uk Kim { 1770*547d94bdSJung-uk Kim 1771*547d94bdSJung-uk Kim if (tstype == BPF_T_NONE) 1772*547d94bdSJung-uk Kim return (BPF_TSTAMP_NONE); 1773*547d94bdSJung-uk Kim if ((tstype & BPF_T_FAST) != 0) 1774*547d94bdSJung-uk Kim return (BPF_TSTAMP_FAST); 1775*547d94bdSJung-uk Kim 1776*547d94bdSJung-uk Kim return (BPF_TSTAMP_NORMAL); 1777*547d94bdSJung-uk Kim } 1778*547d94bdSJung-uk Kim 1779*547d94bdSJung-uk Kim static int 1780*547d94bdSJung-uk Kim bpf_gettime(struct bintime *bt, int tstype, struct mbuf *m) 1781*547d94bdSJung-uk Kim { 1782*547d94bdSJung-uk Kim struct m_tag *tag; 1783*547d94bdSJung-uk Kim int quality; 1784*547d94bdSJung-uk Kim 1785*547d94bdSJung-uk Kim quality = bpf_ts_quality(tstype); 1786*547d94bdSJung-uk Kim if (quality == BPF_TSTAMP_NONE) 1787*547d94bdSJung-uk Kim return (quality); 1788*547d94bdSJung-uk Kim 1789*547d94bdSJung-uk Kim if (m != NULL) { 1790*547d94bdSJung-uk Kim tag = m_tag_locate(m, MTAG_BPF, MTAG_BPF_TIMESTAMP, NULL); 1791*547d94bdSJung-uk Kim if (tag != NULL) { 1792*547d94bdSJung-uk Kim *bt = *(struct bintime *)(tag + 1); 1793*547d94bdSJung-uk Kim return (BPF_TSTAMP_EXTERN); 1794*547d94bdSJung-uk Kim } 1795*547d94bdSJung-uk Kim } 1796*547d94bdSJung-uk Kim if (quality == BPF_TSTAMP_NORMAL) 1797*547d94bdSJung-uk Kim binuptime(bt); 1798*547d94bdSJung-uk Kim else 1799*547d94bdSJung-uk Kim getbinuptime(bt); 1800*547d94bdSJung-uk Kim 1801*547d94bdSJung-uk Kim return (quality); 1802*547d94bdSJung-uk Kim } 1803*547d94bdSJung-uk Kim 180495aab9ccSJohn-Mark Gurney /* 1805df8bae1dSRodney W. Grimes * Incoming linkage from device drivers. Process the packet pkt, of length 1806df8bae1dSRodney W. Grimes * pktlen, which is stored in a contiguous buffer. The packet is parsed 1807df8bae1dSRodney W. Grimes * by each process' filter, and if accepted, stashed into the corresponding 1808df8bae1dSRodney W. Grimes * buffer. 1809df8bae1dSRodney W. Grimes */ 1810df8bae1dSRodney W. Grimes void 181119ba8395SChristian S.J. Peron bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen) 1812df8bae1dSRodney W. Grimes { 1813*547d94bdSJung-uk Kim struct bintime bt; 18148994a245SDag-Erling Smørgrav struct bpf_d *d; 1815a36599ccSJung-uk Kim #ifdef BPF_JITTER 1816a36599ccSJung-uk Kim bpf_jit_filter *bf; 1817a36599ccSJung-uk Kim #endif 18188994a245SDag-Erling Smørgrav u_int slen; 181991433904SDavid Malone int gottime; 1820e7bb21b3SJonathan Lemon 1821*547d94bdSJung-uk Kim gottime = BPF_TSTAMP_NONE; 1822e7bb21b3SJonathan Lemon BPFIF_LOCK(bp); 18234a3feeaaSRobert Watson LIST_FOREACH(d, &bp->bif_dlist, bd_next) { 1824e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1825df8bae1dSRodney W. Grimes ++d->bd_rcount; 1826a05cf8c6SChristian S.J. Peron /* 1827a05cf8c6SChristian S.J. Peron * NB: We dont call BPF_CHECK_DIRECTION() here since there is no 1828a05cf8c6SChristian S.J. Peron * way for the caller to indiciate to us whether this packet 1829a05cf8c6SChristian S.J. Peron * is inbound or outbound. In the bpf_mtap() routines, we use 1830a05cf8c6SChristian S.J. Peron * the interface pointers on the mbuf to figure it out. 1831a05cf8c6SChristian S.J. Peron */ 1832ae275efcSJung-uk Kim #ifdef BPF_JITTER 1833a36599ccSJung-uk Kim bf = bpf_jitter_enable != 0 ? d->bd_bfilter : NULL; 1834a36599ccSJung-uk Kim if (bf != NULL) 1835a36599ccSJung-uk Kim slen = (*(bf->func))(pkt, pktlen, pktlen); 1836ae275efcSJung-uk Kim else 1837ae275efcSJung-uk Kim #endif 183893e39f0bSChristian S.J. Peron slen = bpf_filter(d->bd_rfilter, pkt, pktlen, pktlen); 1839ec272d87SRobert Watson if (slen != 0) { 184069f7644bSChristian S.J. Peron d->bd_fcount++; 1841*547d94bdSJung-uk Kim if (gottime < bpf_ts_quality(d->bd_tstamp)) 1842*547d94bdSJung-uk Kim gottime = bpf_gettime(&bt, d->bd_tstamp, NULL); 1843ec272d87SRobert Watson #ifdef MAC 184430d239bcSRobert Watson if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) 1845ec272d87SRobert Watson #endif 18464d621040SChristian S.J. Peron catchpacket(d, pkt, pktlen, slen, 1847*547d94bdSJung-uk Kim bpf_append_bytes, &bt); 1848ec272d87SRobert Watson } 1849e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1850df8bae1dSRodney W. Grimes } 1851e7bb21b3SJonathan Lemon BPFIF_UNLOCK(bp); 1852df8bae1dSRodney W. Grimes } 1853df8bae1dSRodney W. Grimes 1854f81a2a49SJung-uk Kim #define BPF_CHECK_DIRECTION(d, r, i) \ 1855f81a2a49SJung-uk Kim (((d)->bd_direction == BPF_D_IN && (r) != (i)) || \ 1856f81a2a49SJung-uk Kim ((d)->bd_direction == BPF_D_OUT && (r) == (i))) 1857560a54e1SJung-uk Kim 1858df8bae1dSRodney W. Grimes /* 1859df8bae1dSRodney W. Grimes * Incoming linkage from device drivers, when packet is in an mbuf chain. 1860df8bae1dSRodney W. Grimes */ 1861df8bae1dSRodney W. Grimes void 186219ba8395SChristian S.J. Peron bpf_mtap(struct bpf_if *bp, struct mbuf *m) 1863df8bae1dSRodney W. Grimes { 1864*547d94bdSJung-uk Kim struct bintime bt; 1865df8bae1dSRodney W. Grimes struct bpf_d *d; 1866a36599ccSJung-uk Kim #ifdef BPF_JITTER 1867a36599ccSJung-uk Kim bpf_jit_filter *bf; 1868a36599ccSJung-uk Kim #endif 1869df8bae1dSRodney W. Grimes u_int pktlen, slen; 187091433904SDavid Malone int gottime; 187191433904SDavid Malone 18728cd892f7SJung-uk Kim /* Skip outgoing duplicate packets. */ 18738cd892f7SJung-uk Kim if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { 18748cd892f7SJung-uk Kim m->m_flags &= ~M_PROMISC; 18758cd892f7SJung-uk Kim return; 18768cd892f7SJung-uk Kim } 18778cd892f7SJung-uk Kim 1878f0e2422bSPoul-Henning Kamp pktlen = m_length(m, NULL); 1879df8bae1dSRodney W. Grimes 1880*547d94bdSJung-uk Kim gottime = BPF_TSTAMP_NONE; 1881e7bb21b3SJonathan Lemon BPFIF_LOCK(bp); 18824a3feeaaSRobert Watson LIST_FOREACH(d, &bp->bif_dlist, bd_next) { 1883f81a2a49SJung-uk Kim if (BPF_CHECK_DIRECTION(d, m->m_pkthdr.rcvif, bp->bif_ifp)) 18848ed3828cSRobert Watson continue; 1885e7bb21b3SJonathan Lemon BPFD_LOCK(d); 1886df8bae1dSRodney W. Grimes ++d->bd_rcount; 1887ae275efcSJung-uk Kim #ifdef BPF_JITTER 1888a36599ccSJung-uk Kim bf = bpf_jitter_enable != 0 ? d->bd_bfilter : NULL; 1889ae275efcSJung-uk Kim /* XXX We cannot handle multiple mbufs. */ 1890a36599ccSJung-uk Kim if (bf != NULL && m->m_next == NULL) 1891a36599ccSJung-uk Kim slen = (*(bf->func))(mtod(m, u_char *), pktlen, pktlen); 1892ae275efcSJung-uk Kim else 1893ae275efcSJung-uk Kim #endif 189493e39f0bSChristian S.J. Peron slen = bpf_filter(d->bd_rfilter, (u_char *)m, pktlen, 0); 18954ddfb531SChristian S.J. Peron if (slen != 0) { 189669f7644bSChristian S.J. Peron d->bd_fcount++; 1897*547d94bdSJung-uk Kim if (gottime < bpf_ts_quality(d->bd_tstamp)) 1898*547d94bdSJung-uk Kim gottime = bpf_gettime(&bt, d->bd_tstamp, m); 18990c7fb534SRobert Watson #ifdef MAC 190030d239bcSRobert Watson if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) 19010c7fb534SRobert Watson #endif 19020c7fb534SRobert Watson catchpacket(d, (u_char *)m, pktlen, slen, 1903*547d94bdSJung-uk Kim bpf_append_mbuf, &bt); 19044ddfb531SChristian S.J. Peron } 1905e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 1906df8bae1dSRodney W. Grimes } 1907e7bb21b3SJonathan Lemon BPFIF_UNLOCK(bp); 1908df8bae1dSRodney W. Grimes } 1909df8bae1dSRodney W. Grimes 1910df8bae1dSRodney W. Grimes /* 1911437ffe18SSam Leffler * Incoming linkage from device drivers, when packet is in 1912437ffe18SSam Leffler * an mbuf chain and to be prepended by a contiguous header. 1913437ffe18SSam Leffler */ 1914437ffe18SSam Leffler void 191519ba8395SChristian S.J. Peron bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m) 1916437ffe18SSam Leffler { 1917*547d94bdSJung-uk Kim struct bintime bt; 1918437ffe18SSam Leffler struct mbuf mb; 1919437ffe18SSam Leffler struct bpf_d *d; 1920437ffe18SSam Leffler u_int pktlen, slen; 192191433904SDavid Malone int gottime; 192291433904SDavid Malone 19238cd892f7SJung-uk Kim /* Skip outgoing duplicate packets. */ 19248cd892f7SJung-uk Kim if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { 19258cd892f7SJung-uk Kim m->m_flags &= ~M_PROMISC; 19268cd892f7SJung-uk Kim return; 19278cd892f7SJung-uk Kim } 19288cd892f7SJung-uk Kim 1929437ffe18SSam Leffler pktlen = m_length(m, NULL); 1930437ffe18SSam Leffler /* 1931437ffe18SSam Leffler * Craft on-stack mbuf suitable for passing to bpf_filter. 1932437ffe18SSam Leffler * Note that we cut corners here; we only setup what's 1933437ffe18SSam Leffler * absolutely needed--this mbuf should never go anywhere else. 1934437ffe18SSam Leffler */ 1935437ffe18SSam Leffler mb.m_next = m; 1936437ffe18SSam Leffler mb.m_data = data; 1937437ffe18SSam Leffler mb.m_len = dlen; 1938437ffe18SSam Leffler pktlen += dlen; 1939437ffe18SSam Leffler 1940*547d94bdSJung-uk Kim gottime = BPF_TSTAMP_NONE; 1941437ffe18SSam Leffler BPFIF_LOCK(bp); 19424a3feeaaSRobert Watson LIST_FOREACH(d, &bp->bif_dlist, bd_next) { 1943f81a2a49SJung-uk Kim if (BPF_CHECK_DIRECTION(d, m->m_pkthdr.rcvif, bp->bif_ifp)) 1944437ffe18SSam Leffler continue; 1945437ffe18SSam Leffler BPFD_LOCK(d); 1946437ffe18SSam Leffler ++d->bd_rcount; 194793e39f0bSChristian S.J. Peron slen = bpf_filter(d->bd_rfilter, (u_char *)&mb, pktlen, 0); 19484ddfb531SChristian S.J. Peron if (slen != 0) { 194969f7644bSChristian S.J. Peron d->bd_fcount++; 1950*547d94bdSJung-uk Kim if (gottime < bpf_ts_quality(d->bd_tstamp)) 1951*547d94bdSJung-uk Kim gottime = bpf_gettime(&bt, d->bd_tstamp, m); 1952437ffe18SSam Leffler #ifdef MAC 195330d239bcSRobert Watson if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) 1954437ffe18SSam Leffler #endif 1955437ffe18SSam Leffler catchpacket(d, (u_char *)&mb, pktlen, slen, 1956*547d94bdSJung-uk Kim bpf_append_mbuf, &bt); 19574ddfb531SChristian S.J. Peron } 1958437ffe18SSam Leffler BPFD_UNLOCK(d); 1959437ffe18SSam Leffler } 1960437ffe18SSam Leffler BPFIF_UNLOCK(bp); 1961437ffe18SSam Leffler } 1962437ffe18SSam Leffler 1963560a54e1SJung-uk Kim #undef BPF_CHECK_DIRECTION 1964560a54e1SJung-uk Kim 1965*547d94bdSJung-uk Kim #undef BPF_TSTAMP_NONE 1966*547d94bdSJung-uk Kim #undef BPF_TSTAMP_FAST 1967*547d94bdSJung-uk Kim #undef BPF_TSTAMP_NORMAL 1968*547d94bdSJung-uk Kim #undef BPF_TSTAMP_EXTERN 1969*547d94bdSJung-uk Kim 1970*547d94bdSJung-uk Kim static int 1971*547d94bdSJung-uk Kim bpf_hdrlen(struct bpf_d *d) 1972*547d94bdSJung-uk Kim { 1973*547d94bdSJung-uk Kim int hdrlen; 1974*547d94bdSJung-uk Kim 1975*547d94bdSJung-uk Kim hdrlen = d->bd_bif->bif_hdrlen; 1976*547d94bdSJung-uk Kim #ifndef BURN_BRIDGES 1977*547d94bdSJung-uk Kim if (d->bd_tstamp == BPF_T_NONE || 1978*547d94bdSJung-uk Kim BPF_T_FORMAT(d->bd_tstamp) == BPF_T_MICROTIME) 1979*547d94bdSJung-uk Kim #ifdef COMPAT_FREEBSD32 1980*547d94bdSJung-uk Kim if (d->bd_compat32) 1981*547d94bdSJung-uk Kim hdrlen += SIZEOF_BPF_HDR(struct bpf_hdr32); 1982*547d94bdSJung-uk Kim else 1983*547d94bdSJung-uk Kim #endif 1984*547d94bdSJung-uk Kim hdrlen += SIZEOF_BPF_HDR(struct bpf_hdr); 1985*547d94bdSJung-uk Kim else 1986*547d94bdSJung-uk Kim #endif 1987*547d94bdSJung-uk Kim hdrlen += SIZEOF_BPF_HDR(struct bpf_xhdr); 1988*547d94bdSJung-uk Kim #ifdef COMPAT_FREEBSD32 1989*547d94bdSJung-uk Kim if (d->bd_compat32) 1990*547d94bdSJung-uk Kim hdrlen = BPF_WORDALIGN32(hdrlen); 1991*547d94bdSJung-uk Kim else 1992*547d94bdSJung-uk Kim #endif 1993*547d94bdSJung-uk Kim hdrlen = BPF_WORDALIGN(hdrlen); 1994*547d94bdSJung-uk Kim 1995*547d94bdSJung-uk Kim return (hdrlen - d->bd_bif->bif_hdrlen); 1996*547d94bdSJung-uk Kim } 1997*547d94bdSJung-uk Kim 1998*547d94bdSJung-uk Kim static void 1999*547d94bdSJung-uk Kim bpf_bintime2ts(struct bintime *bt, struct bpf_ts *ts, int tstype) 2000*547d94bdSJung-uk Kim { 2001*547d94bdSJung-uk Kim struct bintime bt2; 2002*547d94bdSJung-uk Kim struct timeval tsm; 2003*547d94bdSJung-uk Kim struct timespec tsn; 2004*547d94bdSJung-uk Kim 2005*547d94bdSJung-uk Kim if ((tstype & BPF_T_MONOTONIC) == 0) { 2006*547d94bdSJung-uk Kim bt2 = *bt; 2007*547d94bdSJung-uk Kim bintime_add(&bt2, &boottimebin); 2008*547d94bdSJung-uk Kim bt = &bt2; 2009*547d94bdSJung-uk Kim } 2010*547d94bdSJung-uk Kim switch (BPF_T_FORMAT(tstype)) { 2011*547d94bdSJung-uk Kim case BPF_T_MICROTIME: 2012*547d94bdSJung-uk Kim bintime2timeval(bt, &tsm); 2013*547d94bdSJung-uk Kim ts->bt_sec = tsm.tv_sec; 2014*547d94bdSJung-uk Kim ts->bt_frac = tsm.tv_usec; 2015*547d94bdSJung-uk Kim break; 2016*547d94bdSJung-uk Kim case BPF_T_NANOTIME: 2017*547d94bdSJung-uk Kim bintime2timespec(bt, &tsn); 2018*547d94bdSJung-uk Kim ts->bt_sec = tsn.tv_sec; 2019*547d94bdSJung-uk Kim ts->bt_frac = tsn.tv_nsec; 2020*547d94bdSJung-uk Kim break; 2021*547d94bdSJung-uk Kim case BPF_T_BINTIME: 2022*547d94bdSJung-uk Kim ts->bt_sec = bt->sec; 2023*547d94bdSJung-uk Kim ts->bt_frac = bt->frac; 2024*547d94bdSJung-uk Kim break; 2025*547d94bdSJung-uk Kim } 2026*547d94bdSJung-uk Kim } 2027*547d94bdSJung-uk Kim 2028437ffe18SSam Leffler /* 2029df8bae1dSRodney W. Grimes * Move the packet data from interface memory (pkt) into the 20309e610888SDag-Erling Smørgrav * store buffer. "cpfn" is the routine called to do the actual data 2031df8bae1dSRodney W. Grimes * transfer. bcopy is passed in to copy contiguous chunks, while 20324d621040SChristian S.J. Peron * bpf_append_mbuf is passed in to copy mbuf chains. In the latter case, 2033df8bae1dSRodney W. Grimes * pkt is really an mbuf. 2034df8bae1dSRodney W. Grimes */ 2035df8bae1dSRodney W. Grimes static void 203619ba8395SChristian S.J. Peron catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen, 20374d621040SChristian S.J. Peron void (*cpfn)(struct bpf_d *, caddr_t, u_int, void *, u_int), 2038*547d94bdSJung-uk Kim struct bintime *bt) 2039df8bae1dSRodney W. Grimes { 2040*547d94bdSJung-uk Kim struct bpf_xhdr hdr; 2041*547d94bdSJung-uk Kim #ifndef BURN_BRIDGES 2042*547d94bdSJung-uk Kim struct bpf_hdr hdr_old; 2043fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 2044*547d94bdSJung-uk Kim struct bpf_hdr32 hdr32_old; 2045fc0a61a4SKonstantin Belousov #endif 2046*547d94bdSJung-uk Kim #endif 2047*547d94bdSJung-uk Kim int caplen, curlen, hdrlen, totlen; 20487819da79SJohn-Mark Gurney int do_wakeup = 0; 2049*547d94bdSJung-uk Kim int do_timestamp; 2050*547d94bdSJung-uk Kim int tstype; 20519e610888SDag-Erling Smørgrav 2052a3272e3cSChristian S.J. Peron BPFD_LOCK_ASSERT(d); 20534d621040SChristian S.J. Peron 20544d621040SChristian S.J. Peron /* 20554d621040SChristian S.J. Peron * Detect whether user space has released a buffer back to us, and if 20564d621040SChristian S.J. Peron * so, move it from being a hold buffer to a free buffer. This may 20574d621040SChristian S.J. Peron * not be the best place to do it (for example, we might only want to 20584d621040SChristian S.J. Peron * run this check if we need the space), but for now it's a reliable 20594d621040SChristian S.J. Peron * spot to do it. 20604d621040SChristian S.J. Peron */ 2061fa0c2b34SRobert Watson if (d->bd_fbuf == NULL && bpf_canfreebuf(d)) { 20624d621040SChristian S.J. Peron d->bd_fbuf = d->bd_hbuf; 20634d621040SChristian S.J. Peron d->bd_hbuf = NULL; 20644d621040SChristian S.J. Peron d->bd_hlen = 0; 206529f612ecSChristian S.J. Peron bpf_buf_reclaimed(d); 20664d621040SChristian S.J. Peron } 20674d621040SChristian S.J. Peron 2068df8bae1dSRodney W. Grimes /* 2069df8bae1dSRodney W. Grimes * Figure out how many bytes to move. If the packet is 2070df8bae1dSRodney W. Grimes * greater or equal to the snapshot length, transfer that 2071df8bae1dSRodney W. Grimes * much. Otherwise, transfer the whole packet (unless 2072df8bae1dSRodney W. Grimes * we hit the buffer size limit). 2073df8bae1dSRodney W. Grimes */ 2074*547d94bdSJung-uk Kim hdrlen = bpf_hdrlen(d); 2075df8bae1dSRodney W. Grimes totlen = hdrlen + min(snaplen, pktlen); 2076df8bae1dSRodney W. Grimes if (totlen > d->bd_bufsize) 2077df8bae1dSRodney W. Grimes totlen = d->bd_bufsize; 2078df8bae1dSRodney W. Grimes 2079df8bae1dSRodney W. Grimes /* 2080df8bae1dSRodney W. Grimes * Round up the end of the previous packet to the next longword. 2081a7a91e65SRobert Watson * 2082a7a91e65SRobert Watson * Drop the packet if there's no room and no hope of room 2083a7a91e65SRobert Watson * If the packet would overflow the storage buffer or the storage 2084a7a91e65SRobert Watson * buffer is considered immutable by the buffer model, try to rotate 2085a7a91e65SRobert Watson * the buffer and wakeup pending processes. 2086df8bae1dSRodney W. Grimes */ 2087fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 2088fc0a61a4SKonstantin Belousov if (d->bd_compat32) 2089fc0a61a4SKonstantin Belousov curlen = BPF_WORDALIGN32(d->bd_slen); 2090fc0a61a4SKonstantin Belousov else 2091fc0a61a4SKonstantin Belousov #endif 2092df8bae1dSRodney W. Grimes curlen = BPF_WORDALIGN(d->bd_slen); 2093a7a91e65SRobert Watson if (curlen + totlen > d->bd_bufsize || !bpf_canwritebuf(d)) { 2094572bde2aSRobert Watson if (d->bd_fbuf == NULL) { 2095df8bae1dSRodney W. Grimes /* 2096a7a91e65SRobert Watson * There's no room in the store buffer, and no 2097a7a91e65SRobert Watson * prospect of room, so drop the packet. Notify the 2098a7a91e65SRobert Watson * buffer model. 2099df8bae1dSRodney W. Grimes */ 2100a7a91e65SRobert Watson bpf_buffull(d); 2101df8bae1dSRodney W. Grimes ++d->bd_dcount; 2102df8bae1dSRodney W. Grimes return; 2103df8bae1dSRodney W. Grimes } 2104df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 21057819da79SJohn-Mark Gurney do_wakeup = 1; 2106df8bae1dSRodney W. Grimes curlen = 0; 2107a7a91e65SRobert Watson } else if (d->bd_immediate || d->bd_state == BPF_TIMED_OUT) 2108df8bae1dSRodney W. Grimes /* 21094d621040SChristian S.J. Peron * Immediate mode is set, or the read timeout has already 21104d621040SChristian S.J. Peron * expired during a select call. A packet arrived, so the 21114d621040SChristian S.J. Peron * reader should be woken up. 2112df8bae1dSRodney W. Grimes */ 21137819da79SJohn-Mark Gurney do_wakeup = 1; 2114*547d94bdSJung-uk Kim caplen = totlen - hdrlen; 2115*547d94bdSJung-uk Kim tstype = d->bd_tstamp; 2116*547d94bdSJung-uk Kim do_timestamp = tstype != BPF_T_NONE; 2117*547d94bdSJung-uk Kim #ifndef BURN_BRIDGES 2118*547d94bdSJung-uk Kim if (tstype == BPF_T_NONE || BPF_T_FORMAT(tstype) == BPF_T_MICROTIME) { 2119*547d94bdSJung-uk Kim struct bpf_ts ts; 2120*547d94bdSJung-uk Kim if (do_timestamp) 2121*547d94bdSJung-uk Kim bpf_bintime2ts(bt, &ts, tstype); 2122fc0a61a4SKonstantin Belousov #ifdef COMPAT_FREEBSD32 2123fc0a61a4SKonstantin Belousov if (d->bd_compat32) { 2124*547d94bdSJung-uk Kim bzero(&hdr32_old, sizeof(hdr32_old)); 2125*547d94bdSJung-uk Kim if (do_timestamp) { 2126*547d94bdSJung-uk Kim hdr32_old.bh_tstamp.tv_sec = ts.bt_sec; 2127*547d94bdSJung-uk Kim hdr32_old.bh_tstamp.tv_usec = ts.bt_frac; 2128*547d94bdSJung-uk Kim } 2129*547d94bdSJung-uk Kim hdr32_old.bh_datalen = pktlen; 2130*547d94bdSJung-uk Kim hdr32_old.bh_hdrlen = hdrlen; 2131*547d94bdSJung-uk Kim hdr32_old.bh_caplen = caplen; 2132*547d94bdSJung-uk Kim bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr32_old, 2133*547d94bdSJung-uk Kim sizeof(hdr32_old)); 2134*547d94bdSJung-uk Kim goto copy; 2135*547d94bdSJung-uk Kim } 2136*547d94bdSJung-uk Kim #endif 2137*547d94bdSJung-uk Kim bzero(&hdr_old, sizeof(hdr_old)); 2138*547d94bdSJung-uk Kim if (do_timestamp) { 2139*547d94bdSJung-uk Kim hdr_old.bh_tstamp.tv_sec = ts.bt_sec; 2140*547d94bdSJung-uk Kim hdr_old.bh_tstamp.tv_usec = ts.bt_frac; 2141*547d94bdSJung-uk Kim } 2142*547d94bdSJung-uk Kim hdr_old.bh_datalen = pktlen; 2143*547d94bdSJung-uk Kim hdr_old.bh_hdrlen = hdrlen; 2144*547d94bdSJung-uk Kim hdr_old.bh_caplen = caplen; 2145*547d94bdSJung-uk Kim bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr_old, 2146*547d94bdSJung-uk Kim sizeof(hdr_old)); 2147fc0a61a4SKonstantin Belousov goto copy; 2148fc0a61a4SKonstantin Belousov } 2149fc0a61a4SKonstantin Belousov #endif 2150df8bae1dSRodney W. Grimes 2151df8bae1dSRodney W. Grimes /* 21524d621040SChristian S.J. Peron * Append the bpf header. Note we append the actual header size, but 21534d621040SChristian S.J. Peron * move forward the length of the header plus padding. 2154df8bae1dSRodney W. Grimes */ 21554d621040SChristian S.J. Peron bzero(&hdr, sizeof(hdr)); 2156*547d94bdSJung-uk Kim if (do_timestamp) 2157*547d94bdSJung-uk Kim bpf_bintime2ts(bt, &hdr.bh_tstamp, tstype); 21584d621040SChristian S.J. Peron hdr.bh_datalen = pktlen; 21594d621040SChristian S.J. Peron hdr.bh_hdrlen = hdrlen; 2160*547d94bdSJung-uk Kim hdr.bh_caplen = caplen; 21614d621040SChristian S.J. Peron bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr, sizeof(hdr)); 21624d621040SChristian S.J. Peron 2163df8bae1dSRodney W. Grimes /* 2164df8bae1dSRodney W. Grimes * Copy the packet data into the store buffer and update its length. 2165df8bae1dSRodney W. Grimes */ 2166*547d94bdSJung-uk Kim #ifndef BURN_BRIDGES 2167fc0a61a4SKonstantin Belousov copy: 2168fc0a61a4SKonstantin Belousov #endif 2169*547d94bdSJung-uk Kim (*cpfn)(d, d->bd_sbuf, curlen + hdrlen, pkt, caplen); 2170df8bae1dSRodney W. Grimes d->bd_slen = curlen + totlen; 21717819da79SJohn-Mark Gurney 21727819da79SJohn-Mark Gurney if (do_wakeup) 21737819da79SJohn-Mark Gurney bpf_wakeup(d); 2174df8bae1dSRodney W. Grimes } 2175df8bae1dSRodney W. Grimes 2176df8bae1dSRodney W. Grimes /* 2177df8bae1dSRodney W. Grimes * Free buffers currently in use by a descriptor. 2178df8bae1dSRodney W. Grimes * Called on close. 2179df8bae1dSRodney W. Grimes */ 2180df8bae1dSRodney W. Grimes static void 218119ba8395SChristian S.J. Peron bpf_freed(struct bpf_d *d) 2182df8bae1dSRodney W. Grimes { 21834d621040SChristian S.J. Peron 2184df8bae1dSRodney W. Grimes /* 2185df8bae1dSRodney W. Grimes * We don't need to lock out interrupts since this descriptor has 2186df8bae1dSRodney W. Grimes * been detached from its interface and it yet hasn't been marked 2187df8bae1dSRodney W. Grimes * free. 2188df8bae1dSRodney W. Grimes */ 21894d621040SChristian S.J. Peron bpf_free(d); 219070485847SJung-uk Kim if (d->bd_rfilter != NULL) { 219193e39f0bSChristian S.J. Peron free((caddr_t)d->bd_rfilter, M_BPF); 2192ae275efcSJung-uk Kim #ifdef BPF_JITTER 219370485847SJung-uk Kim if (d->bd_bfilter != NULL) 2194ae275efcSJung-uk Kim bpf_destroy_jit_filter(d->bd_bfilter); 2195ae275efcSJung-uk Kim #endif 2196ae275efcSJung-uk Kim } 219770485847SJung-uk Kim if (d->bd_wfilter != NULL) 219893e39f0bSChristian S.J. Peron free((caddr_t)d->bd_wfilter, M_BPF); 2199e7bb21b3SJonathan Lemon mtx_destroy(&d->bd_mtx); 2200df8bae1dSRodney W. Grimes } 2201df8bae1dSRodney W. Grimes 2202df8bae1dSRodney W. Grimes /* 220324a229f4SSam Leffler * Attach an interface to bpf. dlt is the link layer type; hdrlen is the 220424a229f4SSam Leffler * fixed size of the link header (variable length headers not yet supported). 2205df8bae1dSRodney W. Grimes */ 2206df8bae1dSRodney W. Grimes void 220719ba8395SChristian S.J. Peron bpfattach(struct ifnet *ifp, u_int dlt, u_int hdrlen) 2208df8bae1dSRodney W. Grimes { 220924a229f4SSam Leffler 221024a229f4SSam Leffler bpfattach2(ifp, dlt, hdrlen, &ifp->if_bpf); 221124a229f4SSam Leffler } 221224a229f4SSam Leffler 221324a229f4SSam Leffler /* 221424a229f4SSam Leffler * Attach an interface to bpf. ifp is a pointer to the structure 221524a229f4SSam Leffler * defining the interface to be attached, dlt is the link layer type, 221624a229f4SSam Leffler * and hdrlen is the fixed size of the link header (variable length 221724a229f4SSam Leffler * headers are not yet supporrted). 221824a229f4SSam Leffler */ 221924a229f4SSam Leffler void 222019ba8395SChristian S.J. Peron bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp) 222124a229f4SSam Leffler { 2222df8bae1dSRodney W. Grimes struct bpf_if *bp; 222319ba8395SChristian S.J. Peron 222419ba8395SChristian S.J. Peron bp = malloc(sizeof(*bp), M_BPF, M_NOWAIT | M_ZERO); 2225572bde2aSRobert Watson if (bp == NULL) 2226df8bae1dSRodney W. Grimes panic("bpfattach"); 2227df8bae1dSRodney W. Grimes 22284a3feeaaSRobert Watson LIST_INIT(&bp->bif_dlist); 2229df8bae1dSRodney W. Grimes bp->bif_ifp = ifp; 2230df8bae1dSRodney W. Grimes bp->bif_dlt = dlt; 22316008862bSJohn Baldwin mtx_init(&bp->bif_mtx, "bpf interface lock", NULL, MTX_DEF); 223216d878ccSChristian S.J. Peron KASSERT(*driverp == NULL, ("bpfattach2: driverp already initialized")); 223316d878ccSChristian S.J. Peron *driverp = bp; 2234df8bae1dSRodney W. Grimes 2235e7bb21b3SJonathan Lemon mtx_lock(&bpf_mtx); 22364a3feeaaSRobert Watson LIST_INSERT_HEAD(&bpf_iflist, bp, bif_next); 2237e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 2238df8bae1dSRodney W. Grimes 2239*547d94bdSJung-uk Kim bp->bif_hdrlen = hdrlen; 2240df8bae1dSRodney W. Grimes 22412eeab939SGarrett Wollman if (bootverbose) 224224a229f4SSam Leffler if_printf(ifp, "bpf attached\n"); 2243df8bae1dSRodney W. Grimes } 224453ac6efbSJulian Elischer 2245de5d9935SRobert Watson /* 2246de5d9935SRobert Watson * Detach bpf from an interface. This involves detaching each descriptor 2247de5d9935SRobert Watson * associated with the interface, and leaving bd_bif NULL. Notify each 2248de5d9935SRobert Watson * descriptor as it's detached so that any sleepers wake up and get 2249de5d9935SRobert Watson * ENXIO. 2250de5d9935SRobert Watson */ 2251de5d9935SRobert Watson void 225219ba8395SChristian S.J. Peron bpfdetach(struct ifnet *ifp) 2253de5d9935SRobert Watson { 22544a3feeaaSRobert Watson struct bpf_if *bp; 2255de5d9935SRobert Watson struct bpf_d *d; 2256de5d9935SRobert Watson 2257de5d9935SRobert Watson /* Locate BPF interface information */ 22588eab61f3SSam Leffler mtx_lock(&bpf_mtx); 22594a3feeaaSRobert Watson LIST_FOREACH(bp, &bpf_iflist, bif_next) { 2260de5d9935SRobert Watson if (ifp == bp->bif_ifp) 2261de5d9935SRobert Watson break; 2262de5d9935SRobert Watson } 2263de5d9935SRobert Watson 2264de5d9935SRobert Watson /* Interface wasn't attached */ 2265d79bf337SMatthew N. Dodd if ((bp == NULL) || (bp->bif_ifp == NULL)) { 2266e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 22679bf40edeSBrooks Davis printf("bpfdetach: %s was not attached\n", ifp->if_xname); 2268de5d9935SRobert Watson return; 2269de5d9935SRobert Watson } 2270de5d9935SRobert Watson 22714a3feeaaSRobert Watson LIST_REMOVE(bp, bif_next); 22728eab61f3SSam Leffler mtx_unlock(&bpf_mtx); 2273de5d9935SRobert Watson 22744a3feeaaSRobert Watson while ((d = LIST_FIRST(&bp->bif_dlist)) != NULL) { 2275e7bb21b3SJonathan Lemon bpf_detachd(d); 2276e7bb21b3SJonathan Lemon BPFD_LOCK(d); 2277e7bb21b3SJonathan Lemon bpf_wakeup(d); 2278e7bb21b3SJonathan Lemon BPFD_UNLOCK(d); 2279e7bb21b3SJonathan Lemon } 2280e7bb21b3SJonathan Lemon 2281e7bb21b3SJonathan Lemon mtx_destroy(&bp->bif_mtx); 2282de5d9935SRobert Watson free(bp, M_BPF); 22838eab61f3SSam Leffler } 2284de5d9935SRobert Watson 22858eab61f3SSam Leffler /* 22868eab61f3SSam Leffler * Get a list of available data link type of the interface. 22878eab61f3SSam Leffler */ 22888eab61f3SSam Leffler static int 228919ba8395SChristian S.J. Peron bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *bfl) 22908eab61f3SSam Leffler { 22918eab61f3SSam Leffler int n, error; 22928eab61f3SSam Leffler struct ifnet *ifp; 22938eab61f3SSam Leffler struct bpf_if *bp; 22948eab61f3SSam Leffler 22958eab61f3SSam Leffler ifp = d->bd_bif->bif_ifp; 22968eab61f3SSam Leffler n = 0; 22978eab61f3SSam Leffler error = 0; 22988eab61f3SSam Leffler mtx_lock(&bpf_mtx); 22994a3feeaaSRobert Watson LIST_FOREACH(bp, &bpf_iflist, bif_next) { 23008eab61f3SSam Leffler if (bp->bif_ifp != ifp) 23018eab61f3SSam Leffler continue; 23028eab61f3SSam Leffler if (bfl->bfl_list != NULL) { 23038eab61f3SSam Leffler if (n >= bfl->bfl_len) { 2304e7bb21b3SJonathan Lemon mtx_unlock(&bpf_mtx); 23058eab61f3SSam Leffler return (ENOMEM); 23068eab61f3SSam Leffler } 23078eab61f3SSam Leffler error = copyout(&bp->bif_dlt, 23088eab61f3SSam Leffler bfl->bfl_list + n, sizeof(u_int)); 23098eab61f3SSam Leffler } 23108eab61f3SSam Leffler n++; 23118eab61f3SSam Leffler } 23128eab61f3SSam Leffler mtx_unlock(&bpf_mtx); 23138eab61f3SSam Leffler bfl->bfl_len = n; 23148eab61f3SSam Leffler return (error); 23158eab61f3SSam Leffler } 23168eab61f3SSam Leffler 23178eab61f3SSam Leffler /* 23188eab61f3SSam Leffler * Set the data link type of a BPF instance. 23198eab61f3SSam Leffler */ 23208eab61f3SSam Leffler static int 232119ba8395SChristian S.J. Peron bpf_setdlt(struct bpf_d *d, u_int dlt) 23228eab61f3SSam Leffler { 23238eab61f3SSam Leffler int error, opromisc; 23248eab61f3SSam Leffler struct ifnet *ifp; 23258eab61f3SSam Leffler struct bpf_if *bp; 23268eab61f3SSam Leffler 23278eab61f3SSam Leffler if (d->bd_bif->bif_dlt == dlt) 23288eab61f3SSam Leffler return (0); 23298eab61f3SSam Leffler ifp = d->bd_bif->bif_ifp; 23308eab61f3SSam Leffler mtx_lock(&bpf_mtx); 23314a3feeaaSRobert Watson LIST_FOREACH(bp, &bpf_iflist, bif_next) { 23328eab61f3SSam Leffler if (bp->bif_ifp == ifp && bp->bif_dlt == dlt) 23338eab61f3SSam Leffler break; 23348eab61f3SSam Leffler } 23358eab61f3SSam Leffler mtx_unlock(&bpf_mtx); 23368eab61f3SSam Leffler if (bp != NULL) { 23378eab61f3SSam Leffler opromisc = d->bd_promisc; 23388eab61f3SSam Leffler bpf_detachd(d); 23398eab61f3SSam Leffler bpf_attachd(d, bp); 234093daabddSBrian Feldman BPFD_LOCK(d); 23418eab61f3SSam Leffler reset_d(d); 23428eab61f3SSam Leffler BPFD_UNLOCK(d); 23438eab61f3SSam Leffler if (opromisc) { 23448eab61f3SSam Leffler error = ifpromisc(bp->bif_ifp, 1); 23458eab61f3SSam Leffler if (error) 23468eab61f3SSam Leffler if_printf(bp->bif_ifp, 23478eab61f3SSam Leffler "bpf_setdlt: ifpromisc failed (%d)\n", 23488eab61f3SSam Leffler error); 23498eab61f3SSam Leffler else 23508eab61f3SSam Leffler d->bd_promisc = 1; 23518eab61f3SSam Leffler } 23528eab61f3SSam Leffler } 23538eab61f3SSam Leffler return (bp == NULL ? EINVAL : 0); 2354de5d9935SRobert Watson } 2355de5d9935SRobert Watson 23563f54a085SPoul-Henning Kamp static void 235719ba8395SChristian S.J. Peron bpf_drvinit(void *unused) 235853ac6efbSJulian Elischer { 2359136600feSEd Schouten struct cdev *dev; 236053ac6efbSJulian Elischer 23616008862bSJohn Baldwin mtx_init(&bpf_mtx, "bpf global lock", NULL, MTX_DEF); 23624a3feeaaSRobert Watson LIST_INIT(&bpf_iflist); 2363136600feSEd Schouten 2364136600feSEd Schouten dev = make_dev(&bpf_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "bpf"); 2365136600feSEd Schouten /* For compatibility */ 2366136600feSEd Schouten make_dev_alias(dev, "bpf0"); 23677198bf47SJulian Elischer } 236853ac6efbSJulian Elischer 23690e37f3e1SChristian S.J. Peron /* 23700e37f3e1SChristian S.J. Peron * Zero out the various packet counters associated with all of the bpf 23710e37f3e1SChristian S.J. Peron * descriptors. At some point, we will probably want to get a bit more 23720e37f3e1SChristian S.J. Peron * granular and allow the user to specify descriptors to be zeroed. 23730e37f3e1SChristian S.J. Peron */ 23740e37f3e1SChristian S.J. Peron static void 23750e37f3e1SChristian S.J. Peron bpf_zero_counters(void) 23760e37f3e1SChristian S.J. Peron { 23770e37f3e1SChristian S.J. Peron struct bpf_if *bp; 23780e37f3e1SChristian S.J. Peron struct bpf_d *bd; 23790e37f3e1SChristian S.J. Peron 23800e37f3e1SChristian S.J. Peron mtx_lock(&bpf_mtx); 23810e37f3e1SChristian S.J. Peron LIST_FOREACH(bp, &bpf_iflist, bif_next) { 23820e37f3e1SChristian S.J. Peron BPFIF_LOCK(bp); 23830e37f3e1SChristian S.J. Peron LIST_FOREACH(bd, &bp->bif_dlist, bd_next) { 23840e37f3e1SChristian S.J. Peron BPFD_LOCK(bd); 23850e37f3e1SChristian S.J. Peron bd->bd_rcount = 0; 23860e37f3e1SChristian S.J. Peron bd->bd_dcount = 0; 23870e37f3e1SChristian S.J. Peron bd->bd_fcount = 0; 23880e37f3e1SChristian S.J. Peron bd->bd_wcount = 0; 23890e37f3e1SChristian S.J. Peron bd->bd_wfcount = 0; 23900e37f3e1SChristian S.J. Peron bd->bd_zcopy = 0; 23910e37f3e1SChristian S.J. Peron BPFD_UNLOCK(bd); 23920e37f3e1SChristian S.J. Peron } 23930e37f3e1SChristian S.J. Peron BPFIF_UNLOCK(bp); 23940e37f3e1SChristian S.J. Peron } 23950e37f3e1SChristian S.J. Peron mtx_unlock(&bpf_mtx); 23960e37f3e1SChristian S.J. Peron } 23970e37f3e1SChristian S.J. Peron 239869f7644bSChristian S.J. Peron static void 239969f7644bSChristian S.J. Peron bpfstats_fill_xbpf(struct xbpf_d *d, struct bpf_d *bd) 240069f7644bSChristian S.J. Peron { 240169f7644bSChristian S.J. Peron 240269f7644bSChristian S.J. Peron bzero(d, sizeof(*d)); 240369f7644bSChristian S.J. Peron BPFD_LOCK_ASSERT(bd); 24044d621040SChristian S.J. Peron d->bd_structsize = sizeof(*d); 240569f7644bSChristian S.J. Peron d->bd_immediate = bd->bd_immediate; 240669f7644bSChristian S.J. Peron d->bd_promisc = bd->bd_promisc; 240769f7644bSChristian S.J. Peron d->bd_hdrcmplt = bd->bd_hdrcmplt; 2408560a54e1SJung-uk Kim d->bd_direction = bd->bd_direction; 2409560a54e1SJung-uk Kim d->bd_feedback = bd->bd_feedback; 241069f7644bSChristian S.J. Peron d->bd_async = bd->bd_async; 241169f7644bSChristian S.J. Peron d->bd_rcount = bd->bd_rcount; 241269f7644bSChristian S.J. Peron d->bd_dcount = bd->bd_dcount; 241369f7644bSChristian S.J. Peron d->bd_fcount = bd->bd_fcount; 241469f7644bSChristian S.J. Peron d->bd_sig = bd->bd_sig; 241569f7644bSChristian S.J. Peron d->bd_slen = bd->bd_slen; 241669f7644bSChristian S.J. Peron d->bd_hlen = bd->bd_hlen; 241769f7644bSChristian S.J. Peron d->bd_bufsize = bd->bd_bufsize; 241869f7644bSChristian S.J. Peron d->bd_pid = bd->bd_pid; 241969f7644bSChristian S.J. Peron strlcpy(d->bd_ifname, 242069f7644bSChristian S.J. Peron bd->bd_bif->bif_ifp->if_xname, IFNAMSIZ); 242193e39f0bSChristian S.J. Peron d->bd_locked = bd->bd_locked; 24224d621040SChristian S.J. Peron d->bd_wcount = bd->bd_wcount; 24234d621040SChristian S.J. Peron d->bd_wdcount = bd->bd_wdcount; 24244d621040SChristian S.J. Peron d->bd_wfcount = bd->bd_wfcount; 24254d621040SChristian S.J. Peron d->bd_zcopy = bd->bd_zcopy; 24264d621040SChristian S.J. Peron d->bd_bufmode = bd->bd_bufmode; 242769f7644bSChristian S.J. Peron } 242869f7644bSChristian S.J. Peron 242969f7644bSChristian S.J. Peron static int 243069f7644bSChristian S.J. Peron bpf_stats_sysctl(SYSCTL_HANDLER_ARGS) 243169f7644bSChristian S.J. Peron { 24320e37f3e1SChristian S.J. Peron struct xbpf_d *xbdbuf, *xbd, zerostats; 2433422a63daSChristian S.J. Peron int index, error; 243469f7644bSChristian S.J. Peron struct bpf_if *bp; 243569f7644bSChristian S.J. Peron struct bpf_d *bd; 243669f7644bSChristian S.J. Peron 243769f7644bSChristian S.J. Peron /* 243869f7644bSChristian S.J. Peron * XXX This is not technically correct. It is possible for non 243969f7644bSChristian S.J. Peron * privileged users to open bpf devices. It would make sense 244069f7644bSChristian S.J. Peron * if the users who opened the devices were able to retrieve 244169f7644bSChristian S.J. Peron * the statistics for them, too. 244269f7644bSChristian S.J. Peron */ 2443acd3428bSRobert Watson error = priv_check(req->td, PRIV_NET_BPF); 244469f7644bSChristian S.J. Peron if (error) 244569f7644bSChristian S.J. Peron return (error); 24460e37f3e1SChristian S.J. Peron /* 24470e37f3e1SChristian S.J. Peron * Check to see if the user is requesting that the counters be 24480e37f3e1SChristian S.J. Peron * zeroed out. Explicitly check that the supplied data is zeroed, 24490e37f3e1SChristian S.J. Peron * as we aren't allowing the user to set the counters currently. 24500e37f3e1SChristian S.J. Peron */ 24510e37f3e1SChristian S.J. Peron if (req->newptr != NULL) { 24520e37f3e1SChristian S.J. Peron if (req->newlen != sizeof(zerostats)) 24530e37f3e1SChristian S.J. Peron return (EINVAL); 24540e37f3e1SChristian S.J. Peron bzero(&zerostats, sizeof(zerostats)); 24550e37f3e1SChristian S.J. Peron xbd = req->newptr; 24560e37f3e1SChristian S.J. Peron if (bcmp(xbd, &zerostats, sizeof(*xbd)) != 0) 24570e37f3e1SChristian S.J. Peron return (EINVAL); 24580e37f3e1SChristian S.J. Peron bpf_zero_counters(); 24590e37f3e1SChristian S.J. Peron return (0); 24600e37f3e1SChristian S.J. Peron } 246169f7644bSChristian S.J. Peron if (req->oldptr == NULL) 2462422a63daSChristian S.J. Peron return (SYSCTL_OUT(req, 0, bpf_bpfd_cnt * sizeof(*xbd))); 246369f7644bSChristian S.J. Peron if (bpf_bpfd_cnt == 0) 246469f7644bSChristian S.J. Peron return (SYSCTL_OUT(req, 0, 0)); 2465422a63daSChristian S.J. Peron xbdbuf = malloc(req->oldlen, M_BPF, M_WAITOK); 246669f7644bSChristian S.J. Peron mtx_lock(&bpf_mtx); 2467422a63daSChristian S.J. Peron if (req->oldlen < (bpf_bpfd_cnt * sizeof(*xbd))) { 2468422a63daSChristian S.J. Peron mtx_unlock(&bpf_mtx); 2469422a63daSChristian S.J. Peron free(xbdbuf, M_BPF); 2470422a63daSChristian S.J. Peron return (ENOMEM); 2471422a63daSChristian S.J. Peron } 2472422a63daSChristian S.J. Peron index = 0; 247369f7644bSChristian S.J. Peron LIST_FOREACH(bp, &bpf_iflist, bif_next) { 24741fc9e387SChristian S.J. Peron BPFIF_LOCK(bp); 247569f7644bSChristian S.J. Peron LIST_FOREACH(bd, &bp->bif_dlist, bd_next) { 2476422a63daSChristian S.J. Peron xbd = &xbdbuf[index++]; 247769f7644bSChristian S.J. Peron BPFD_LOCK(bd); 2478422a63daSChristian S.J. Peron bpfstats_fill_xbpf(xbd, bd); 247969f7644bSChristian S.J. Peron BPFD_UNLOCK(bd); 248069f7644bSChristian S.J. Peron } 24811fc9e387SChristian S.J. Peron BPFIF_UNLOCK(bp); 248269f7644bSChristian S.J. Peron } 248369f7644bSChristian S.J. Peron mtx_unlock(&bpf_mtx); 2484422a63daSChristian S.J. Peron error = SYSCTL_OUT(req, xbdbuf, index * sizeof(*xbd)); 2485422a63daSChristian S.J. Peron free(xbdbuf, M_BPF); 248669f7644bSChristian S.J. Peron return (error); 248769f7644bSChristian S.J. Peron } 248869f7644bSChristian S.J. Peron 2489237fdd78SRobert Watson SYSINIT(bpfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,bpf_drvinit,NULL); 249053ac6efbSJulian Elischer 24915bb5f2c9SPeter Wemm #else /* !DEV_BPF && !NETGRAPH_BPF */ 2492f8dc4716SMike Smith /* 2493f8dc4716SMike Smith * NOP stubs to allow bpf-using drivers to load and function. 2494f8dc4716SMike Smith * 2495f8dc4716SMike Smith * A 'better' implementation would allow the core bpf functionality 2496f8dc4716SMike Smith * to be loaded at runtime. 2497f8dc4716SMike Smith */ 24987eae78a4SChristian S.J. Peron static struct bpf_if bp_null; 2499f8dc4716SMike Smith 2500f8dc4716SMike Smith void 250119ba8395SChristian S.J. Peron bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen) 2502f8dc4716SMike Smith { 2503f8dc4716SMike Smith } 2504f8dc4716SMike Smith 2505f8dc4716SMike Smith void 250619ba8395SChristian S.J. Peron bpf_mtap(struct bpf_if *bp, struct mbuf *m) 2507f8dc4716SMike Smith { 2508f8dc4716SMike Smith } 2509f8dc4716SMike Smith 2510f8dc4716SMike Smith void 251119ba8395SChristian S.J. Peron bpf_mtap2(struct bpf_if *bp, void *d, u_int l, struct mbuf *m) 2512437ffe18SSam Leffler { 2513437ffe18SSam Leffler } 2514437ffe18SSam Leffler 2515437ffe18SSam Leffler void 251619ba8395SChristian S.J. Peron bpfattach(struct ifnet *ifp, u_int dlt, u_int hdrlen) 2517f8dc4716SMike Smith { 25187eae78a4SChristian S.J. Peron 25197eae78a4SChristian S.J. Peron bpfattach2(ifp, dlt, hdrlen, &ifp->if_bpf); 2520f8dc4716SMike Smith } 2521f8dc4716SMike Smith 2522da626c17SBill Paul void 252319ba8395SChristian S.J. Peron bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp) 25245f7a7923SSam Leffler { 25257eae78a4SChristian S.J. Peron 25267eae78a4SChristian S.J. Peron *driverp = &bp_null; 25275f7a7923SSam Leffler } 25285f7a7923SSam Leffler 25295f7a7923SSam Leffler void 253019ba8395SChristian S.J. Peron bpfdetach(struct ifnet *ifp) 2531da626c17SBill Paul { 2532da626c17SBill Paul } 2533da626c17SBill Paul 2534f8dc4716SMike Smith u_int 253519ba8395SChristian S.J. Peron bpf_filter(const struct bpf_insn *pc, u_char *p, u_int wirelen, u_int buflen) 2536f8dc4716SMike Smith { 2537f8dc4716SMike Smith return -1; /* "no filter" behaviour */ 2538f8dc4716SMike Smith } 2539f8dc4716SMike Smith 25405bb5f2c9SPeter Wemm int 254119ba8395SChristian S.J. Peron bpf_validate(const struct bpf_insn *f, int len) 25425bb5f2c9SPeter Wemm { 25435bb5f2c9SPeter Wemm return 0; /* false */ 25445bb5f2c9SPeter Wemm } 25455bb5f2c9SPeter Wemm 25465bb5f2c9SPeter Wemm #endif /* !DEV_BPF && !NETGRAPH_BPF */ 2547