1*8d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */ 27827cba2SAaron LI /* 37827cba2SAaron LI * dhcpcd: BPF arp and bootp filtering 4*8d36e1dfSRoy Marples * Copyright (c) 2006-2019 Roy Marples <roy@marples.name> 57827cba2SAaron LI * All rights reserved 67827cba2SAaron LI 77827cba2SAaron LI * Redistribution and use in source and binary forms, with or without 87827cba2SAaron LI * modification, are permitted provided that the following conditions 97827cba2SAaron LI * are met: 107827cba2SAaron LI * 1. Redistributions of source code must retain the above copyright 117827cba2SAaron LI * notice, this list of conditions and the following disclaimer. 127827cba2SAaron LI * 2. Redistributions in binary form must reproduce the above copyright 137827cba2SAaron LI * notice, this list of conditions and the following disclaimer in the 147827cba2SAaron LI * documentation and/or other materials provided with the distribution. 157827cba2SAaron LI * 167827cba2SAaron LI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 177827cba2SAaron LI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 187827cba2SAaron LI * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 197827cba2SAaron LI * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 207827cba2SAaron LI * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 217827cba2SAaron LI * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 227827cba2SAaron LI * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 237827cba2SAaron LI * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 247827cba2SAaron LI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 257827cba2SAaron LI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 267827cba2SAaron LI * SUCH DAMAGE. 277827cba2SAaron LI */ 287827cba2SAaron LI 297827cba2SAaron LI #include <sys/ioctl.h> 307827cba2SAaron LI #include <sys/socket.h> 317827cba2SAaron LI 327827cba2SAaron LI #include <arpa/inet.h> 337827cba2SAaron LI 347827cba2SAaron LI #include <net/if.h> 357827cba2SAaron LI #include <netinet/in.h> 367827cba2SAaron LI #include <netinet/if_ether.h> 377827cba2SAaron LI 387827cba2SAaron LI #ifdef __linux__ 397827cba2SAaron LI /* Special BPF snowflake. */ 407827cba2SAaron LI #include <linux/filter.h> 417827cba2SAaron LI #define bpf_insn sock_filter 427827cba2SAaron LI #else 437827cba2SAaron LI #include <net/bpf.h> 447827cba2SAaron LI #endif 457827cba2SAaron LI 467827cba2SAaron LI #include <errno.h> 477827cba2SAaron LI #include <fcntl.h> 487827cba2SAaron LI #include <paths.h> 497827cba2SAaron LI #include <stddef.h> 507827cba2SAaron LI #include <stdlib.h> 517827cba2SAaron LI #include <string.h> 527827cba2SAaron LI 537827cba2SAaron LI #include "common.h" 547827cba2SAaron LI #include "arp.h" 557827cba2SAaron LI #include "bpf.h" 567827cba2SAaron LI #include "dhcp.h" 577827cba2SAaron LI #include "if.h" 587827cba2SAaron LI #include "logerr.h" 597827cba2SAaron LI 607827cba2SAaron LI #define ARP_ADDRS_MAX 3 617827cba2SAaron LI 627827cba2SAaron LI /* BPF helper macros */ 637827cba2SAaron LI #ifdef __linux__ 647827cba2SAaron LI #define BPF_WHOLEPACKET 0x7fffffff /* work around buggy LPF filters */ 657827cba2SAaron LI #else 667827cba2SAaron LI #define BPF_WHOLEPACKET ~0U 677827cba2SAaron LI #endif 687827cba2SAaron LI 697827cba2SAaron LI /* Macros to update the BPF structure */ 707827cba2SAaron LI #define BPF_SET_STMT(insn, c, v) { \ 717827cba2SAaron LI (insn)->code = (c); \ 727827cba2SAaron LI (insn)->jt = 0; \ 737827cba2SAaron LI (insn)->jf = 0; \ 747827cba2SAaron LI (insn)->k = (uint32_t)(v); \ 757827cba2SAaron LI }; 767827cba2SAaron LI 777827cba2SAaron LI #define BPF_SET_JUMP(insn, c, v, t, f) { \ 787827cba2SAaron LI (insn)->code = (c); \ 797827cba2SAaron LI (insn)->jt = (t); \ 807827cba2SAaron LI (insn)->jf = (f); \ 817827cba2SAaron LI (insn)->k = (uint32_t)(v); \ 827827cba2SAaron LI }; 837827cba2SAaron LI 847827cba2SAaron LI size_t 857827cba2SAaron LI bpf_frame_header_len(const struct interface *ifp) 867827cba2SAaron LI { 877827cba2SAaron LI 887827cba2SAaron LI switch (ifp->family) { 897827cba2SAaron LI case ARPHRD_ETHER: 907827cba2SAaron LI return sizeof(struct ether_header); 917827cba2SAaron LI default: 927827cba2SAaron LI return 0; 937827cba2SAaron LI } 947827cba2SAaron LI } 957827cba2SAaron LI 96*8d36e1dfSRoy Marples static const uint8_t etherbcastaddr[] = 97*8d36e1dfSRoy Marples { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 98*8d36e1dfSRoy Marples 99*8d36e1dfSRoy Marples int 100*8d36e1dfSRoy Marples bpf_frame_bcast(const struct interface *ifp, const char *frame) 101*8d36e1dfSRoy Marples { 102*8d36e1dfSRoy Marples 103*8d36e1dfSRoy Marples switch (ifp->family) { 104*8d36e1dfSRoy Marples case ARPHRD_ETHER: 105*8d36e1dfSRoy Marples return memcmp(frame + 106*8d36e1dfSRoy Marples offsetof(struct ether_header, ether_dhost), 107*8d36e1dfSRoy Marples etherbcastaddr, sizeof(etherbcastaddr)); 108*8d36e1dfSRoy Marples default: 109*8d36e1dfSRoy Marples return -1; 110*8d36e1dfSRoy Marples } 111*8d36e1dfSRoy Marples } 112*8d36e1dfSRoy Marples 1137827cba2SAaron LI #ifndef __linux__ 1147827cba2SAaron LI /* Linux is a special snowflake for opening, attaching and reading BPF. 1157827cba2SAaron LI * See if-linux.c for the Linux specific BPF functions. */ 1167827cba2SAaron LI 1177827cba2SAaron LI const char *bpf_name = "Berkley Packet Filter"; 1187827cba2SAaron LI 1197827cba2SAaron LI int 1207827cba2SAaron LI bpf_open(struct interface *ifp, int (*filter)(struct interface *, int)) 1217827cba2SAaron LI { 1227827cba2SAaron LI struct ipv4_state *state; 1237827cba2SAaron LI int fd = -1; 1247827cba2SAaron LI struct ifreq ifr; 1257827cba2SAaron LI int ibuf_len = 0; 1267827cba2SAaron LI size_t buf_len; 1277827cba2SAaron LI struct bpf_version pv; 1287827cba2SAaron LI #ifdef BIOCIMMEDIATE 1297827cba2SAaron LI unsigned int flags; 1307827cba2SAaron LI #endif 1317827cba2SAaron LI #ifndef O_CLOEXEC 1327827cba2SAaron LI int fd_opts; 1337827cba2SAaron LI #endif 1347827cba2SAaron LI 1357827cba2SAaron LI #ifdef _PATH_BPF 1367827cba2SAaron LI fd = open(_PATH_BPF, O_RDWR | O_NONBLOCK 1377827cba2SAaron LI #ifdef O_CLOEXEC 1387827cba2SAaron LI | O_CLOEXEC 1397827cba2SAaron LI #endif 1407827cba2SAaron LI ); 1417827cba2SAaron LI #else 1427827cba2SAaron LI char device[32]; 1437827cba2SAaron LI int n = 0; 1447827cba2SAaron LI 1457827cba2SAaron LI do { 1467827cba2SAaron LI snprintf(device, sizeof(device), "/dev/bpf%d", n++); 1477827cba2SAaron LI fd = open(device, O_RDWR | O_NONBLOCK 1487827cba2SAaron LI #ifdef O_CLOEXEC 1497827cba2SAaron LI | O_CLOEXEC 1507827cba2SAaron LI #endif 1517827cba2SAaron LI ); 1527827cba2SAaron LI } while (fd == -1 && errno == EBUSY); 1537827cba2SAaron LI #endif 1547827cba2SAaron LI 1557827cba2SAaron LI if (fd == -1) 1567827cba2SAaron LI return -1; 1577827cba2SAaron LI 1587827cba2SAaron LI #ifndef O_CLOEXEC 1597827cba2SAaron LI if ((fd_opts = fcntl(fd, F_GETFD)) == -1 || 1607827cba2SAaron LI fcntl(fd, F_SETFD, fd_opts | FD_CLOEXEC) == -1) { 1617827cba2SAaron LI close(fd); 1627827cba2SAaron LI return -1; 1637827cba2SAaron LI } 1647827cba2SAaron LI #endif 1657827cba2SAaron LI 1667827cba2SAaron LI memset(&pv, 0, sizeof(pv)); 1677827cba2SAaron LI if (ioctl(fd, BIOCVERSION, &pv) == -1) 1687827cba2SAaron LI goto eexit; 1697827cba2SAaron LI if (pv.bv_major != BPF_MAJOR_VERSION || 1707827cba2SAaron LI pv.bv_minor < BPF_MINOR_VERSION) { 1717827cba2SAaron LI logerrx("BPF version mismatch - recompile"); 1727827cba2SAaron LI goto eexit; 1737827cba2SAaron LI } 1747827cba2SAaron LI 1757827cba2SAaron LI if (filter(ifp, fd) != 0) 1767827cba2SAaron LI goto eexit; 1777827cba2SAaron LI 1787827cba2SAaron LI memset(&ifr, 0, sizeof(ifr)); 1797827cba2SAaron LI strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 1807827cba2SAaron LI if (ioctl(fd, BIOCSETIF, &ifr) == -1) 1817827cba2SAaron LI goto eexit; 1827827cba2SAaron LI 1837827cba2SAaron LI /* Get the required BPF buffer length from the kernel. */ 1847827cba2SAaron LI if (ioctl(fd, BIOCGBLEN, &ibuf_len) == -1) 1857827cba2SAaron LI goto eexit; 1867827cba2SAaron LI buf_len = (size_t)ibuf_len; 1877827cba2SAaron LI state = ipv4_getstate(ifp); 1887827cba2SAaron LI if (state == NULL) 1897827cba2SAaron LI goto eexit; 1907827cba2SAaron LI if (state->buffer_size != buf_len) { 1917827cba2SAaron LI void *nb; 1927827cba2SAaron LI 1937827cba2SAaron LI if ((nb = realloc(state->buffer, buf_len)) == NULL) 1947827cba2SAaron LI goto eexit; 1957827cba2SAaron LI state->buffer = nb; 1967827cba2SAaron LI state->buffer_size = buf_len; 1977827cba2SAaron LI } 1987827cba2SAaron LI 1997827cba2SAaron LI #ifdef BIOCIMMEDIATE 2007827cba2SAaron LI flags = 1; 2017827cba2SAaron LI if (ioctl(fd, BIOCIMMEDIATE, &flags) == -1) 2027827cba2SAaron LI goto eexit; 2037827cba2SAaron LI #endif 2047827cba2SAaron LI 2057827cba2SAaron LI return fd; 2067827cba2SAaron LI 2077827cba2SAaron LI eexit: 2087827cba2SAaron LI close(fd); 2097827cba2SAaron LI return -1; 2107827cba2SAaron LI } 2117827cba2SAaron LI 2127827cba2SAaron LI /* BPF requires that we read the entire buffer. 2137827cba2SAaron LI * So we pass the buffer in the API so we can loop on >1 packet. */ 2147827cba2SAaron LI ssize_t 2157827cba2SAaron LI bpf_read(struct interface *ifp, int fd, void *data, size_t len, 2167827cba2SAaron LI unsigned int *flags) 2177827cba2SAaron LI { 2187827cba2SAaron LI ssize_t fl = (ssize_t)bpf_frame_header_len(ifp); 2197827cba2SAaron LI ssize_t bytes; 2207827cba2SAaron LI struct ipv4_state *state = IPV4_STATE(ifp); 2217827cba2SAaron LI 2227827cba2SAaron LI struct bpf_hdr packet; 2237827cba2SAaron LI const char *payload; 2247827cba2SAaron LI 2257827cba2SAaron LI *flags &= ~BPF_EOF; 2267827cba2SAaron LI for (;;) { 2277827cba2SAaron LI if (state->buffer_len == 0) { 2287827cba2SAaron LI bytes = read(fd, state->buffer, state->buffer_size); 2297827cba2SAaron LI #if defined(__sun) 2307827cba2SAaron LI /* After 2^31 bytes, the kernel offset overflows. 2317827cba2SAaron LI * To work around this bug, lseek 0. */ 2327827cba2SAaron LI if (bytes == -1 && errno == EINVAL) { 2337827cba2SAaron LI lseek(fd, 0, SEEK_SET); 2347827cba2SAaron LI continue; 2357827cba2SAaron LI } 2367827cba2SAaron LI #endif 2377827cba2SAaron LI if (bytes == -1 || bytes == 0) 2387827cba2SAaron LI return bytes; 2397827cba2SAaron LI state->buffer_len = (size_t)bytes; 2407827cba2SAaron LI state->buffer_pos = 0; 2417827cba2SAaron LI } 2427827cba2SAaron LI bytes = -1; 2437827cba2SAaron LI memcpy(&packet, state->buffer + state->buffer_pos, 2447827cba2SAaron LI sizeof(packet)); 2457827cba2SAaron LI if (state->buffer_pos + packet.bh_caplen + packet.bh_hdrlen > 2467827cba2SAaron LI state->buffer_len) 2477827cba2SAaron LI goto next; /* Packet beyond buffer, drop. */ 248*8d36e1dfSRoy Marples payload = state->buffer + state->buffer_pos + packet.bh_hdrlen; 249*8d36e1dfSRoy Marples if (bpf_frame_bcast(ifp, payload) == 0) 250*8d36e1dfSRoy Marples *flags |= BPF_BCAST; 251*8d36e1dfSRoy Marples else 252*8d36e1dfSRoy Marples *flags &= ~BPF_BCAST; 253*8d36e1dfSRoy Marples payload += fl; 2547827cba2SAaron LI bytes = (ssize_t)packet.bh_caplen - fl; 2557827cba2SAaron LI if ((size_t)bytes > len) 2567827cba2SAaron LI bytes = (ssize_t)len; 2577827cba2SAaron LI memcpy(data, payload, (size_t)bytes); 2587827cba2SAaron LI next: 2597827cba2SAaron LI state->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen + 2607827cba2SAaron LI packet.bh_caplen); 2617827cba2SAaron LI if (state->buffer_pos >= state->buffer_len) { 2627827cba2SAaron LI state->buffer_len = state->buffer_pos = 0; 2637827cba2SAaron LI *flags |= BPF_EOF; 2647827cba2SAaron LI } 2657827cba2SAaron LI if (bytes != -1) 2667827cba2SAaron LI return bytes; 2677827cba2SAaron LI } 2687827cba2SAaron LI 2697827cba2SAaron LI /* NOTREACHED */ 2707827cba2SAaron LI } 2717827cba2SAaron LI 2727827cba2SAaron LI int 2737827cba2SAaron LI bpf_attach(int fd, void *filter, unsigned int filter_len) 2747827cba2SAaron LI { 2757827cba2SAaron LI struct bpf_program pf; 2767827cba2SAaron LI 2777827cba2SAaron LI /* Install the filter. */ 2787827cba2SAaron LI memset(&pf, 0, sizeof(pf)); 2797827cba2SAaron LI pf.bf_insns = filter; 2807827cba2SAaron LI pf.bf_len = filter_len; 2817827cba2SAaron LI return ioctl(fd, BIOCSETF, &pf); 2827827cba2SAaron LI } 2837827cba2SAaron LI #endif 2847827cba2SAaron LI 2857827cba2SAaron LI #ifndef __sun 2867827cba2SAaron LI /* SunOS is special too - sending via BPF goes nowhere. */ 2877827cba2SAaron LI ssize_t 2887827cba2SAaron LI bpf_send(const struct interface *ifp, int fd, uint16_t protocol, 2897827cba2SAaron LI const void *data, size_t len) 2907827cba2SAaron LI { 2917827cba2SAaron LI struct iovec iov[2]; 2927827cba2SAaron LI struct ether_header eh; 2937827cba2SAaron LI 2947827cba2SAaron LI switch(ifp->family) { 2957827cba2SAaron LI case ARPHRD_ETHER: 2967827cba2SAaron LI memset(&eh.ether_dhost, 0xff, sizeof(eh.ether_dhost)); 2977827cba2SAaron LI memcpy(&eh.ether_shost, ifp->hwaddr, sizeof(eh.ether_shost)); 2987827cba2SAaron LI eh.ether_type = htons(protocol); 2997827cba2SAaron LI iov[0].iov_base = &eh; 3007827cba2SAaron LI iov[0].iov_len = sizeof(eh); 3017827cba2SAaron LI break; 3027827cba2SAaron LI default: 3037827cba2SAaron LI iov[0].iov_base = NULL; 3047827cba2SAaron LI iov[0].iov_len = 0; 3057827cba2SAaron LI break; 3067827cba2SAaron LI } 3077827cba2SAaron LI iov[1].iov_base = UNCONST(data); 3087827cba2SAaron LI iov[1].iov_len = len; 3097827cba2SAaron LI return writev(fd, iov, 2); 3107827cba2SAaron LI } 3117827cba2SAaron LI #endif 3127827cba2SAaron LI 3137827cba2SAaron LI int 3147827cba2SAaron LI bpf_close(struct interface *ifp, int fd) 3157827cba2SAaron LI { 3167827cba2SAaron LI struct ipv4_state *state = IPV4_STATE(ifp); 3177827cba2SAaron LI 3187827cba2SAaron LI /* Rewind the buffer on closing. */ 3197827cba2SAaron LI state->buffer_len = state->buffer_pos = 0; 3207827cba2SAaron LI return close(fd); 3217827cba2SAaron LI } 3227827cba2SAaron LI 3237827cba2SAaron LI /* Normally this is needed by bootp. 3247827cba2SAaron LI * Once that uses this again, the ARP guard here can be removed. */ 3257827cba2SAaron LI #ifdef ARP 326*8d36e1dfSRoy Marples #define BPF_CMP_HWADDR_LEN ((((HWADDR_LEN / 4) + 2) * 2) + 1) 3277827cba2SAaron LI static unsigned int 3287827cba2SAaron LI bpf_cmp_hwaddr(struct bpf_insn *bpf, size_t bpf_len, size_t off, 3297827cba2SAaron LI bool equal, uint8_t *hwaddr, size_t hwaddr_len) 3307827cba2SAaron LI { 3317827cba2SAaron LI struct bpf_insn *bp; 3327827cba2SAaron LI size_t maclen, nlft, njmps; 3337827cba2SAaron LI uint32_t mac32; 3347827cba2SAaron LI uint16_t mac16; 3357827cba2SAaron LI uint8_t jt, jf; 3367827cba2SAaron LI 3377827cba2SAaron LI /* Calc the number of jumps */ 3387827cba2SAaron LI if ((hwaddr_len / 4) >= 128) { 3397827cba2SAaron LI errno = EINVAL; 3407827cba2SAaron LI return 0; 3417827cba2SAaron LI } 3427827cba2SAaron LI njmps = (hwaddr_len / 4) * 2; /* 2 instructions per check */ 3437827cba2SAaron LI /* We jump after the 1st check. */ 3447827cba2SAaron LI if (njmps) 3457827cba2SAaron LI njmps -= 2; 3467827cba2SAaron LI nlft = hwaddr_len % 4; 3477827cba2SAaron LI if (nlft) { 3487827cba2SAaron LI njmps += (nlft / 2) * 2; 3497827cba2SAaron LI nlft = nlft % 2; 3507827cba2SAaron LI if (nlft) 3517827cba2SAaron LI njmps += 2; 3527827cba2SAaron LI 3537827cba2SAaron LI } 3547827cba2SAaron LI 3557827cba2SAaron LI /* Skip to positive finish. */ 3567827cba2SAaron LI njmps++; 3577827cba2SAaron LI if (equal) { 3587827cba2SAaron LI jt = (uint8_t)njmps; 3597827cba2SAaron LI jf = 0; 3607827cba2SAaron LI } else { 3617827cba2SAaron LI jt = 0; 3627827cba2SAaron LI jf = (uint8_t)njmps; 3637827cba2SAaron LI } 3647827cba2SAaron LI 3657827cba2SAaron LI bp = bpf; 3667827cba2SAaron LI for (; hwaddr_len > 0; 3677827cba2SAaron LI hwaddr += maclen, hwaddr_len -= maclen, off += maclen) 3687827cba2SAaron LI { 3697827cba2SAaron LI if (bpf_len < 3) { 3707827cba2SAaron LI errno = ENOBUFS; 3717827cba2SAaron LI return 0; 3727827cba2SAaron LI } 3737827cba2SAaron LI bpf_len -= 3; 3747827cba2SAaron LI 3757827cba2SAaron LI if (hwaddr_len >= 4) { 3767827cba2SAaron LI maclen = sizeof(mac32); 3777827cba2SAaron LI memcpy(&mac32, hwaddr, maclen); 3787827cba2SAaron LI BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, off); 3797827cba2SAaron LI bp++; 3807827cba2SAaron LI BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, 3817827cba2SAaron LI htonl(mac32), jt, jf); 3827827cba2SAaron LI } else if (hwaddr_len >= 2) { 3837827cba2SAaron LI maclen = sizeof(mac16); 3847827cba2SAaron LI memcpy(&mac16, hwaddr, maclen); 3857827cba2SAaron LI BPF_SET_STMT(bp, BPF_LD + BPF_H + BPF_IND, off); 3867827cba2SAaron LI bp++; 3877827cba2SAaron LI BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, 3887827cba2SAaron LI htons(mac16), jt, jf); 3897827cba2SAaron LI } else { 3907827cba2SAaron LI maclen = sizeof(*hwaddr); 3917827cba2SAaron LI BPF_SET_STMT(bp, BPF_LD + BPF_B + BPF_IND, off); 3927827cba2SAaron LI bp++; 3937827cba2SAaron LI BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, 3947827cba2SAaron LI *hwaddr, jt, jf); 3957827cba2SAaron LI } 3967827cba2SAaron LI if (jt) 3977827cba2SAaron LI jt = (uint8_t)(jt - 2); 3987827cba2SAaron LI if (jf) 3997827cba2SAaron LI jf = (uint8_t)(jf - 2); 4007827cba2SAaron LI bp++; 4017827cba2SAaron LI } 4027827cba2SAaron LI 4037827cba2SAaron LI /* Last step is always return failure. 4047827cba2SAaron LI * Next step is a positive finish. */ 4057827cba2SAaron LI BPF_SET_STMT(bp, BPF_RET + BPF_K, 0); 4067827cba2SAaron LI bp++; 4077827cba2SAaron LI 4087827cba2SAaron LI return (unsigned int)(bp - bpf); 4097827cba2SAaron LI } 4107827cba2SAaron LI #endif 4117827cba2SAaron LI 4127827cba2SAaron LI #ifdef ARP 4137827cba2SAaron LI 4147827cba2SAaron LI static const struct bpf_insn bpf_arp_ether [] = { 4157827cba2SAaron LI /* Ensure packet is at least correct size. */ 4167827cba2SAaron LI BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), 4177827cba2SAaron LI BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), 4187827cba2SAaron LI BPF_STMT(BPF_RET + BPF_K, 0), 4197827cba2SAaron LI 4207827cba2SAaron LI /* Check this is an ARP packet. */ 4217827cba2SAaron LI BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 4227827cba2SAaron LI offsetof(struct ether_header, ether_type)), 4237827cba2SAaron LI BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 1, 0), 4247827cba2SAaron LI BPF_STMT(BPF_RET + BPF_K, 0), 4257827cba2SAaron LI 4267827cba2SAaron LI /* Load frame header length into X */ 4277827cba2SAaron LI BPF_STMT(BPF_LDX + BPF_W + BPF_IMM, sizeof(struct ether_header)), 4287827cba2SAaron LI 4297827cba2SAaron LI /* Make sure the hardware family matches. */ 4307827cba2SAaron LI BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_hrd)), 4317827cba2SAaron LI BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), 4327827cba2SAaron LI BPF_STMT(BPF_RET + BPF_K, 0), 4337827cba2SAaron LI 4347827cba2SAaron LI /* Make sure the hardware length matches. */ 4357827cba2SAaron LI BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct arphdr, ar_hln)), 4367827cba2SAaron LI BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 4377827cba2SAaron LI sizeof(((struct ether_arp *)0)->arp_sha), 1, 0), 4387827cba2SAaron LI BPF_STMT(BPF_RET + BPF_K, 0), 4397827cba2SAaron LI }; 440*8d36e1dfSRoy Marples #define BPF_ARP_ETHER_LEN __arraycount(bpf_arp_ether) 4417827cba2SAaron LI 4427827cba2SAaron LI static const struct bpf_insn bpf_arp_filter [] = { 4437827cba2SAaron LI /* Make sure this is for IP. */ 4447827cba2SAaron LI BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_pro)), 4457827cba2SAaron LI BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), 4467827cba2SAaron LI BPF_STMT(BPF_RET + BPF_K, 0), 4477827cba2SAaron LI /* Make sure this is an ARP REQUEST. */ 4487827cba2SAaron LI BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_op)), 4497827cba2SAaron LI BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0), 4507827cba2SAaron LI /* or ARP REPLY. */ 451*8d36e1dfSRoy Marples BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0), 4527827cba2SAaron LI BPF_STMT(BPF_RET + BPF_K, 0), 4537827cba2SAaron LI /* Make sure the protocol length matches. */ 4547827cba2SAaron LI BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct arphdr, ar_pln)), 4557827cba2SAaron LI BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(in_addr_t), 1, 0), 4567827cba2SAaron LI BPF_STMT(BPF_RET + BPF_K, 0), 4577827cba2SAaron LI }; 458*8d36e1dfSRoy Marples #define BPF_ARP_FILTER_LEN __arraycount(bpf_arp_filter) 459*8d36e1dfSRoy Marples 460*8d36e1dfSRoy Marples #define BPF_ARP_ADDRS_LEN 1 + (ARP_ADDRS_MAX * 2) + 3 + \ 461*8d36e1dfSRoy Marples (ARP_ADDRS_MAX * 2) + 1 462*8d36e1dfSRoy Marples 463*8d36e1dfSRoy Marples #define BPF_ARP_LEN BPF_ARP_ETHER_LEN + BPF_ARP_FILTER_LEN + \ 464*8d36e1dfSRoy Marples BPF_CMP_HWADDR_LEN + BPF_ARP_ADDRS_LEN 4657827cba2SAaron LI 4667827cba2SAaron LI int 4677827cba2SAaron LI bpf_arp(struct interface *ifp, int fd) 4687827cba2SAaron LI { 469*8d36e1dfSRoy Marples struct bpf_insn bpf[BPF_ARP_LEN]; 4707827cba2SAaron LI struct bpf_insn *bp; 4717827cba2SAaron LI struct iarp_state *state; 4727827cba2SAaron LI uint16_t arp_len; 4737827cba2SAaron LI 4747827cba2SAaron LI if (fd == -1) 4757827cba2SAaron LI return 0; 4767827cba2SAaron LI 4777827cba2SAaron LI bp = bpf; 4787827cba2SAaron LI /* Check frame header. */ 4797827cba2SAaron LI switch(ifp->family) { 4807827cba2SAaron LI case ARPHRD_ETHER: 4817827cba2SAaron LI memcpy(bp, bpf_arp_ether, sizeof(bpf_arp_ether)); 482*8d36e1dfSRoy Marples bp += BPF_ARP_ETHER_LEN; 4837827cba2SAaron LI arp_len = sizeof(struct ether_header)+sizeof(struct ether_arp); 4847827cba2SAaron LI break; 4857827cba2SAaron LI default: 4867827cba2SAaron LI errno = EINVAL; 4877827cba2SAaron LI return -1; 4887827cba2SAaron LI } 4897827cba2SAaron LI 4907827cba2SAaron LI /* Copy in the main filter. */ 4917827cba2SAaron LI memcpy(bp, bpf_arp_filter, sizeof(bpf_arp_filter)); 492*8d36e1dfSRoy Marples bp += BPF_ARP_FILTER_LEN; 4937827cba2SAaron LI 4947827cba2SAaron LI /* Ensure it's not from us. */ 495*8d36e1dfSRoy Marples bp += bpf_cmp_hwaddr(bp, BPF_CMP_HWADDR_LEN, sizeof(struct arphdr), 4967827cba2SAaron LI false, ifp->hwaddr, ifp->hwlen); 4977827cba2SAaron LI 4987827cba2SAaron LI state = ARP_STATE(ifp); 4997827cba2SAaron LI if (TAILQ_FIRST(&state->arp_states)) { 5007827cba2SAaron LI struct arp_state *astate; 5017827cba2SAaron LI size_t naddrs; 5027827cba2SAaron LI 5037827cba2SAaron LI /* Match sender protocol address */ 5047827cba2SAaron LI BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, 5057827cba2SAaron LI sizeof(struct arphdr) + ifp->hwlen); 5067827cba2SAaron LI bp++; 5077827cba2SAaron LI naddrs = 0; 5087827cba2SAaron LI TAILQ_FOREACH(astate, &state->arp_states, next) { 5097827cba2SAaron LI if (++naddrs > ARP_ADDRS_MAX) { 5107827cba2SAaron LI errno = ENOBUFS; 5117827cba2SAaron LI logerr(__func__); 5127827cba2SAaron LI break; 5137827cba2SAaron LI } 5147827cba2SAaron LI BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, 5157827cba2SAaron LI htonl(astate->addr.s_addr), 0, 1); 5167827cba2SAaron LI bp++; 5177827cba2SAaron LI BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len); 5187827cba2SAaron LI bp++; 5197827cba2SAaron LI } 5207827cba2SAaron LI 5217827cba2SAaron LI /* If we didn't match sender, then we're only interested in 5227827cba2SAaron LI * ARP probes to us, so check the null host sender. */ 5237827cba2SAaron LI BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, INADDR_ANY, 1, 0); 5247827cba2SAaron LI bp++; 5257827cba2SAaron LI BPF_SET_STMT(bp, BPF_RET + BPF_K, 0); 5267827cba2SAaron LI bp++; 5277827cba2SAaron LI 5287827cba2SAaron LI /* Match target protocol address */ 5297827cba2SAaron LI BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, 5307827cba2SAaron LI (sizeof(struct arphdr) 5317827cba2SAaron LI + (size_t)(ifp->hwlen * 2) + sizeof(in_addr_t))); 5327827cba2SAaron LI bp++; 5337827cba2SAaron LI naddrs = 0; 5347827cba2SAaron LI TAILQ_FOREACH(astate, &state->arp_states, next) { 5357827cba2SAaron LI if (++naddrs > ARP_ADDRS_MAX) { 5367827cba2SAaron LI /* Already logged error above. */ 5377827cba2SAaron LI break; 5387827cba2SAaron LI } 5397827cba2SAaron LI BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, 5407827cba2SAaron LI htonl(astate->addr.s_addr), 0, 1); 5417827cba2SAaron LI bp++; 5427827cba2SAaron LI BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len); 5437827cba2SAaron LI bp++; 5447827cba2SAaron LI } 5457827cba2SAaron LI 5467827cba2SAaron LI /* Return nothing, no protocol address match. */ 5477827cba2SAaron LI BPF_SET_STMT(bp, BPF_RET + BPF_K, 0); 5487827cba2SAaron LI bp++; 5497827cba2SAaron LI } 5507827cba2SAaron LI 5517827cba2SAaron LI return bpf_attach(fd, bpf, (unsigned int)(bp - bpf)); 5527827cba2SAaron LI } 5537827cba2SAaron LI #endif 5547827cba2SAaron LI 555*8d36e1dfSRoy Marples #define BPF_M_FHLEN 0 556*8d36e1dfSRoy Marples #define BPF_M_IPHLEN 1 557*8d36e1dfSRoy Marples #define BPF_M_IPLEN 2 558*8d36e1dfSRoy Marples #define BPF_M_UDP 3 559*8d36e1dfSRoy Marples #define BPF_M_UDPLEN 4 560*8d36e1dfSRoy Marples 561*8d36e1dfSRoy Marples #ifdef ARPHRD_NONE 562*8d36e1dfSRoy Marples static const struct bpf_insn bpf_bootp_none[] = { 563*8d36e1dfSRoy Marples /* Set the frame header length to zero. */ 564*8d36e1dfSRoy Marples BPF_STMT(BPF_LD + BPF_IMM, 0), 565*8d36e1dfSRoy Marples BPF_STMT(BPF_ST, BPF_M_FHLEN), 566*8d36e1dfSRoy Marples }; 567*8d36e1dfSRoy Marples #define BPF_BOOTP_NONE_LEN __arraycount(bpf_bootp_none) 568*8d36e1dfSRoy Marples #endif 569*8d36e1dfSRoy Marples 5707827cba2SAaron LI static const struct bpf_insn bpf_bootp_ether[] = { 5717827cba2SAaron LI /* Make sure this is an IP packet. */ 5727827cba2SAaron LI BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 5737827cba2SAaron LI offsetof(struct ether_header, ether_type)), 5747827cba2SAaron LI BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), 5757827cba2SAaron LI BPF_STMT(BPF_RET + BPF_K, 0), 5767827cba2SAaron LI 5777827cba2SAaron LI /* Load frame header length into X. */ 5787827cba2SAaron LI BPF_STMT(BPF_LDX + BPF_W + BPF_IMM, sizeof(struct ether_header)), 579*8d36e1dfSRoy Marples /* Copy frame header length to memory */ 580*8d36e1dfSRoy Marples BPF_STMT(BPF_STX, BPF_M_FHLEN), 5817827cba2SAaron LI }; 5827827cba2SAaron LI #define BPF_BOOTP_ETHER_LEN __arraycount(bpf_bootp_ether) 5837827cba2SAaron LI 5847827cba2SAaron LI static const struct bpf_insn bpf_bootp_filter[] = { 585*8d36e1dfSRoy Marples /* Make sure it's an IPv4 packet. */ 5867827cba2SAaron LI BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0), 587*8d36e1dfSRoy Marples BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0xf0), 588*8d36e1dfSRoy Marples BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x40, 1, 0), 5897827cba2SAaron LI BPF_STMT(BPF_RET + BPF_K, 0), 5907827cba2SAaron LI 591*8d36e1dfSRoy Marples /* Ensure IP header length is big enough and 592*8d36e1dfSRoy Marples * store the IP header length in memory. */ 593*8d36e1dfSRoy Marples BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0), 594*8d36e1dfSRoy Marples BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x0f), 595*8d36e1dfSRoy Marples BPF_STMT(BPF_ALU + BPF_MUL + BPF_K, 4), 596*8d36e1dfSRoy Marples BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ip), 1, 0), 597*8d36e1dfSRoy Marples BPF_STMT(BPF_RET + BPF_K, 0), 598*8d36e1dfSRoy Marples BPF_STMT(BPF_ST, BPF_M_IPHLEN), 599*8d36e1dfSRoy Marples 6007827cba2SAaron LI /* Make sure it's a UDP packet. */ 6017827cba2SAaron LI BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct ip, ip_p)), 6027827cba2SAaron LI BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0), 6037827cba2SAaron LI BPF_STMT(BPF_RET + BPF_K, 0), 6047827cba2SAaron LI 6057827cba2SAaron LI /* Make sure this isn't a fragment. */ 6067827cba2SAaron LI BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct ip, ip_off)), 6077827cba2SAaron LI BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 0, 1), 6087827cba2SAaron LI BPF_STMT(BPF_RET + BPF_K, 0), 6097827cba2SAaron LI 610*8d36e1dfSRoy Marples /* Store IP length. */ 6117827cba2SAaron LI BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct ip, ip_len)), 612*8d36e1dfSRoy Marples BPF_STMT(BPF_ST, BPF_M_IPLEN), 6137827cba2SAaron LI 6147827cba2SAaron LI /* Advance to the UDP header. */ 615*8d36e1dfSRoy Marples BPF_STMT(BPF_LD + BPF_MEM, BPF_M_IPHLEN), 616*8d36e1dfSRoy Marples BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0), 6177827cba2SAaron LI BPF_STMT(BPF_MISC + BPF_TAX, 0), 6187827cba2SAaron LI 619*8d36e1dfSRoy Marples /* Store UDP location */ 620*8d36e1dfSRoy Marples BPF_STMT(BPF_STX, BPF_M_UDP), 6217827cba2SAaron LI 6227827cba2SAaron LI /* Make sure it's from and to the right port. */ 6237827cba2SAaron LI BPF_STMT(BPF_LD + BPF_W + BPF_IND, 0), 6247827cba2SAaron LI BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (BOOTPS << 16) + BOOTPC, 1, 0), 6257827cba2SAaron LI BPF_STMT(BPF_RET + BPF_K, 0), 6267827cba2SAaron LI 627*8d36e1dfSRoy Marples /* Store UDP length. */ 6287827cba2SAaron LI BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct udphdr, uh_ulen)), 629*8d36e1dfSRoy Marples BPF_STMT(BPF_ST, BPF_M_UDPLEN), 630*8d36e1dfSRoy Marples 631*8d36e1dfSRoy Marples /* Ensure that UDP length + IP header length == IP length */ 632*8d36e1dfSRoy Marples /* Copy IP header length to X. */ 633*8d36e1dfSRoy Marples BPF_STMT(BPF_LDX + BPF_MEM, BPF_M_IPHLEN), 634*8d36e1dfSRoy Marples /* Add UDP length (A) to IP header length (X). */ 635*8d36e1dfSRoy Marples BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0), 636*8d36e1dfSRoy Marples /* Store result in X. */ 6377827cba2SAaron LI BPF_STMT(BPF_MISC + BPF_TAX, 0), 638*8d36e1dfSRoy Marples /* Copy IP length to A. */ 639*8d36e1dfSRoy Marples BPF_STMT(BPF_LD + BPF_MEM, BPF_M_IPLEN), 640*8d36e1dfSRoy Marples /* Ensure X == A. */ 6417827cba2SAaron LI BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), 6427827cba2SAaron LI BPF_STMT(BPF_RET + BPF_K, 0), 6437827cba2SAaron LI 644*8d36e1dfSRoy Marples /* Advance to the BOOTP packet. */ 645*8d36e1dfSRoy Marples BPF_STMT(BPF_LD + BPF_MEM, BPF_M_UDP), 6467827cba2SAaron LI BPF_STMT(BPF_ALU + BPF_ADD + BPF_K, sizeof(struct udphdr)), 6477827cba2SAaron LI BPF_STMT(BPF_MISC + BPF_TAX, 0), 6487827cba2SAaron LI 6497827cba2SAaron LI /* Make sure it's BOOTREPLY. */ 6507827cba2SAaron LI BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct bootp, op)), 6517827cba2SAaron LI BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTREPLY, 1, 0), 6527827cba2SAaron LI BPF_STMT(BPF_RET + BPF_K, 0), 6537827cba2SAaron LI }; 6547827cba2SAaron LI 6557827cba2SAaron LI #define BPF_BOOTP_FILTER_LEN __arraycount(bpf_bootp_filter) 6567827cba2SAaron LI #define BPF_BOOTP_CHADDR_LEN ((BOOTP_CHADDR_LEN / 4) * 3) 6577827cba2SAaron LI #define BPF_BOOTP_XID_LEN 4 /* BOUND check is 4 instructions */ 6587827cba2SAaron LI 6597827cba2SAaron LI #define BPF_BOOTP_LEN BPF_BOOTP_ETHER_LEN + BPF_BOOTP_FILTER_LEN \ 6607827cba2SAaron LI + BPF_BOOTP_XID_LEN + BPF_BOOTP_CHADDR_LEN + 4 6617827cba2SAaron LI 6627827cba2SAaron LI int 6637827cba2SAaron LI bpf_bootp(struct interface *ifp, int fd) 6647827cba2SAaron LI { 6657827cba2SAaron LI #if 0 6667827cba2SAaron LI const struct dhcp_state *state = D_CSTATE(ifp); 6677827cba2SAaron LI #endif 6687827cba2SAaron LI struct bpf_insn bpf[BPF_BOOTP_LEN]; 6697827cba2SAaron LI struct bpf_insn *bp; 6707827cba2SAaron LI 6717827cba2SAaron LI if (fd == -1) 6727827cba2SAaron LI return 0; 6737827cba2SAaron LI 6747827cba2SAaron LI bp = bpf; 6757827cba2SAaron LI /* Check frame header. */ 6767827cba2SAaron LI switch(ifp->family) { 677*8d36e1dfSRoy Marples #ifdef ARPHRD_NONE 678*8d36e1dfSRoy Marples case ARPHRD_NONE: 679*8d36e1dfSRoy Marples memcpy(bp, bpf_bootp_none, sizeof(bpf_bootp_none)); 680*8d36e1dfSRoy Marples bp += BPF_BOOTP_NONE_LEN; 681*8d36e1dfSRoy Marples break; 682*8d36e1dfSRoy Marples #endif 6837827cba2SAaron LI case ARPHRD_ETHER: 6847827cba2SAaron LI memcpy(bp, bpf_bootp_ether, sizeof(bpf_bootp_ether)); 6857827cba2SAaron LI bp += BPF_BOOTP_ETHER_LEN; 6867827cba2SAaron LI break; 6877827cba2SAaron LI default: 6887827cba2SAaron LI errno = EINVAL; 6897827cba2SAaron LI return -1; 6907827cba2SAaron LI } 6917827cba2SAaron LI 6927827cba2SAaron LI /* Copy in the main filter. */ 6937827cba2SAaron LI memcpy(bp, bpf_bootp_filter, sizeof(bpf_bootp_filter)); 6947827cba2SAaron LI bp += BPF_BOOTP_FILTER_LEN; 6957827cba2SAaron LI 6967827cba2SAaron LI /* These checks won't work when same IP exists on other interfaces. */ 6977827cba2SAaron LI #if 0 6987827cba2SAaron LI if (ifp->hwlen <= sizeof(((struct bootp *)0)->chaddr)) 6997827cba2SAaron LI bp += bpf_cmp_hwaddr(bp, BPF_BOOTP_CHADDR_LEN, 7007827cba2SAaron LI offsetof(struct bootp, chaddr), 7017827cba2SAaron LI true, ifp->hwaddr, ifp->hwlen); 7027827cba2SAaron LI 7037827cba2SAaron LI /* Make sure the BOOTP packet is for us. */ 7047827cba2SAaron LI if (state->state == DHS_BOUND) { 7057827cba2SAaron LI /* If bound, we only expect FORCERENEW messages 7067827cba2SAaron LI * and they need to be unicast to us. 7077827cba2SAaron LI * Move back to the IP header in M0 and check dst. */ 7087827cba2SAaron LI BPF_SET_STMT(bp, BPF_LDX + BPF_W + BPF_MEM, 0); 7097827cba2SAaron LI bp++; 7107827cba2SAaron LI BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, 7117827cba2SAaron LI offsetof(struct ip, ip_dst)); 7127827cba2SAaron LI bp++; 7137827cba2SAaron LI BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, 7147827cba2SAaron LI htonl(state->lease.addr.s_addr), 1, 0); 7157827cba2SAaron LI bp++; 7167827cba2SAaron LI BPF_SET_STMT(bp, BPF_RET + BPF_K, 0); 7177827cba2SAaron LI bp++; 7187827cba2SAaron LI } else { 7197827cba2SAaron LI /* As we're not bound, we need to check xid to ensure 7207827cba2SAaron LI * it's a reply to our transaction. */ 7217827cba2SAaron LI BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, 7227827cba2SAaron LI offsetof(struct bootp, xid)); 7237827cba2SAaron LI bp++; 7247827cba2SAaron LI BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, 7257827cba2SAaron LI state->xid, 1, 0); 7267827cba2SAaron LI bp++; 7277827cba2SAaron LI BPF_SET_STMT(bp, BPF_RET + BPF_K, 0); 7287827cba2SAaron LI bp++; 7297827cba2SAaron LI } 7307827cba2SAaron LI #endif 7317827cba2SAaron LI 732*8d36e1dfSRoy Marples /* All passed, return the packet - frame length + ip length */ 733*8d36e1dfSRoy Marples BPF_SET_STMT(bp, BPF_LD + BPF_MEM, BPF_M_FHLEN); 7347827cba2SAaron LI bp++; 735*8d36e1dfSRoy Marples BPF_SET_STMT(bp, BPF_LDX + BPF_MEM, BPF_M_IPLEN); 7367827cba2SAaron LI bp++; 7377827cba2SAaron LI BPF_SET_STMT(bp, BPF_ALU + BPF_ADD + BPF_X, 0); 7387827cba2SAaron LI bp++; 7397827cba2SAaron LI BPF_SET_STMT(bp, BPF_RET + BPF_A, 0); 7407827cba2SAaron LI bp++; 7417827cba2SAaron LI 7427827cba2SAaron LI return bpf_attach(fd, bpf, (unsigned int)(bp - bpf)); 7437827cba2SAaron LI } 744