xref: /dflybsd-src/contrib/dhcpcd/src/bpf.c (revision 8d36e1df80df39bec701fcb39b0b7982e1b94e77)
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