xref: /dflybsd-src/contrib/dhcpcd/src/bpf.c (revision 5422d4140b73a6e65966a6f40831066aa79c4714)
18d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */
27827cba2SAaron LI /*
37827cba2SAaron LI  * dhcpcd: BPF arp and bootp filtering
480aa9461SRoy Marples  * Copyright (c) 2006-2023 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 <stddef.h>
497827cba2SAaron LI #include <stdlib.h>
507827cba2SAaron LI #include <string.h>
517827cba2SAaron LI 
527827cba2SAaron LI #include "common.h"
537827cba2SAaron LI #include "arp.h"
547827cba2SAaron LI #include "bpf.h"
557827cba2SAaron LI #include "dhcp.h"
567827cba2SAaron LI #include "if.h"
577827cba2SAaron LI #include "logerr.h"
587827cba2SAaron LI 
597827cba2SAaron LI /* BPF helper macros */
607827cba2SAaron LI #ifdef __linux__
617827cba2SAaron LI #define	BPF_WHOLEPACKET		0x7fffffff /* work around buggy LPF filters */
627827cba2SAaron LI #else
637827cba2SAaron LI #define	BPF_WHOLEPACKET		~0U
647827cba2SAaron LI #endif
657827cba2SAaron LI 
667827cba2SAaron LI /* Macros to update the BPF structure */
677827cba2SAaron LI #define	BPF_SET_STMT(insn, c, v) {				\
687827cba2SAaron LI 	(insn)->code = (c);					\
697827cba2SAaron LI 	(insn)->jt = 0;						\
707827cba2SAaron LI 	(insn)->jf = 0;						\
717827cba2SAaron LI 	(insn)->k = (uint32_t)(v);				\
72a0d9933aSRoy Marples }
737827cba2SAaron LI 
747827cba2SAaron LI #define	BPF_SET_JUMP(insn, c, v, t, f) {			\
757827cba2SAaron LI 	(insn)->code = (c);					\
767827cba2SAaron LI 	(insn)->jt = (t);					\
777827cba2SAaron LI 	(insn)->jf = (f);					\
787827cba2SAaron LI 	(insn)->k = (uint32_t)(v);				\
79a0d9933aSRoy Marples }
807827cba2SAaron LI 
817827cba2SAaron LI size_t
bpf_frame_header_len(const struct interface * ifp)827827cba2SAaron LI bpf_frame_header_len(const struct interface *ifp)
837827cba2SAaron LI {
847827cba2SAaron LI 
85d4fb1e02SRoy Marples 	switch (ifp->hwtype) {
867827cba2SAaron LI 	case ARPHRD_ETHER:
877827cba2SAaron LI 		return sizeof(struct ether_header);
887827cba2SAaron LI 	default:
897827cba2SAaron LI 		return 0;
907827cba2SAaron LI 	}
917827cba2SAaron LI }
927827cba2SAaron LI 
936e63cc1fSRoy Marples void *
bpf_frame_header_src(const struct interface * ifp,void * fh,size_t * len)946e63cc1fSRoy Marples bpf_frame_header_src(const struct interface *ifp, void *fh, size_t *len)
956e63cc1fSRoy Marples {
966e63cc1fSRoy Marples 	uint8_t *f = fh;
976e63cc1fSRoy Marples 
98d4fb1e02SRoy Marples 	switch (ifp->hwtype) {
996e63cc1fSRoy Marples 	case ARPHRD_ETHER:
1006e63cc1fSRoy Marples 		*len = sizeof(((struct ether_header *)0)->ether_shost);
1016e63cc1fSRoy Marples 		return f + offsetof(struct ether_header, ether_shost);
1026e63cc1fSRoy Marples 	default:
1036e63cc1fSRoy Marples 		*len = 0;
1046e63cc1fSRoy Marples 		errno =	ENOTSUP;
1056e63cc1fSRoy Marples 		return NULL;
1066e63cc1fSRoy Marples 	}
1076e63cc1fSRoy Marples }
1086e63cc1fSRoy Marples 
1096e63cc1fSRoy Marples void *
bpf_frame_header_dst(const struct interface * ifp,void * fh,size_t * len)1106e63cc1fSRoy Marples bpf_frame_header_dst(const struct interface *ifp, void *fh, size_t *len)
1116e63cc1fSRoy Marples {
1126e63cc1fSRoy Marples 	uint8_t *f = fh;
1136e63cc1fSRoy Marples 
114d4fb1e02SRoy Marples 	switch (ifp->hwtype) {
1156e63cc1fSRoy Marples 	case ARPHRD_ETHER:
1166e63cc1fSRoy Marples 		*len = sizeof(((struct ether_header *)0)->ether_dhost);
1176e63cc1fSRoy Marples 		return f + offsetof(struct ether_header, ether_dhost);
1186e63cc1fSRoy Marples 	default:
1196e63cc1fSRoy Marples 		*len = 0;
1206e63cc1fSRoy Marples 		errno =	ENOTSUP;
1216e63cc1fSRoy Marples 		return NULL;
1226e63cc1fSRoy Marples 	}
1236e63cc1fSRoy Marples }
1246e63cc1fSRoy Marples 
1258d36e1dfSRoy Marples static const uint8_t etherbcastaddr[] =
1268d36e1dfSRoy Marples     { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1278d36e1dfSRoy Marples 
1288d36e1dfSRoy Marples int
bpf_frame_bcast(const struct interface * ifp,const void * frame)129d4fb1e02SRoy Marples bpf_frame_bcast(const struct interface *ifp, const void *frame)
1308d36e1dfSRoy Marples {
1318d36e1dfSRoy Marples 
132d4fb1e02SRoy Marples 	switch (ifp->hwtype) {
1338d36e1dfSRoy Marples 	case ARPHRD_ETHER:
134d4fb1e02SRoy Marples 		return memcmp((const char *)frame +
1358d36e1dfSRoy Marples 		    offsetof(struct ether_header, ether_dhost),
1368d36e1dfSRoy Marples 		    etherbcastaddr, sizeof(etherbcastaddr));
1378d36e1dfSRoy Marples 	default:
1388d36e1dfSRoy Marples 		return -1;
1398d36e1dfSRoy Marples 	}
1408d36e1dfSRoy Marples }
1418d36e1dfSRoy Marples 
1427827cba2SAaron LI #ifndef __linux__
1437827cba2SAaron LI /* Linux is a special snowflake for opening, attaching and reading BPF.
1447827cba2SAaron LI  * See if-linux.c for the Linux specific BPF functions. */
1457827cba2SAaron LI 
1467827cba2SAaron LI const char *bpf_name = "Berkley Packet Filter";
1477827cba2SAaron LI 
148d4fb1e02SRoy Marples struct bpf *
bpf_open(const struct interface * ifp,int (* filter)(const struct bpf *,const struct in_addr *),const struct in_addr * ia)149d4fb1e02SRoy Marples bpf_open(const struct interface *ifp,
150d4fb1e02SRoy Marples     int (*filter)(const struct bpf *, const struct in_addr *),
151d4fb1e02SRoy Marples     const struct in_addr *ia)
1527827cba2SAaron LI {
153d4fb1e02SRoy Marples 	struct bpf *bpf;
154d4fb1e02SRoy Marples 	struct bpf_version pv = { .bv_major = 0, .bv_minor = 0 };
155d4fb1e02SRoy Marples 	struct ifreq ifr = { .ifr_flags = 0 };
1567827cba2SAaron LI 	int ibuf_len = 0;
15780aa9461SRoy Marples #ifdef O_CLOEXEC
15880aa9461SRoy Marples #define BPF_OPEN_FLAGS O_RDWR | O_NONBLOCK | O_CLOEXEC
15980aa9461SRoy Marples #else
16080aa9461SRoy Marples #define BPF_OPEN_FLAGS O_RDWR | O_NONBLOCK
16180aa9461SRoy Marples #endif
1627827cba2SAaron LI #ifdef BIOCIMMEDIATE
1637827cba2SAaron LI 	unsigned int flags;
1647827cba2SAaron LI #endif
1657827cba2SAaron LI #ifndef O_CLOEXEC
1667827cba2SAaron LI 	int fd_opts;
1677827cba2SAaron LI #endif
1687827cba2SAaron LI 
169d4fb1e02SRoy Marples 	bpf = calloc(1, sizeof(*bpf));
170d4fb1e02SRoy Marples 	if (bpf == NULL)
171d4fb1e02SRoy Marples 		return NULL;
172d4fb1e02SRoy Marples 	bpf->bpf_ifp = ifp;
173d4fb1e02SRoy Marples 
17480aa9461SRoy Marples 	/* /dev/bpf is a cloner on modern kernels */
17580aa9461SRoy Marples 	bpf->bpf_fd = open("/dev/bpf", BPF_OPEN_FLAGS);
17680aa9461SRoy Marples 
17780aa9461SRoy Marples 	/* Support older kernels where /dev/bpf is not a cloner */
17880aa9461SRoy Marples 	if (bpf->bpf_fd == -1) {
1797827cba2SAaron LI 		char device[32];
1807827cba2SAaron LI 		int n = 0;
1817827cba2SAaron LI 
1827827cba2SAaron LI 		do {
1837827cba2SAaron LI 			snprintf(device, sizeof(device), "/dev/bpf%d", n++);
18480aa9461SRoy Marples 			bpf->bpf_fd = open(device, BPF_OPEN_FLAGS);
185d4fb1e02SRoy Marples 		} while (bpf->bpf_fd == -1 && errno == EBUSY);
18680aa9461SRoy Marples 	}
1877827cba2SAaron LI 
188d4fb1e02SRoy Marples 	if (bpf->bpf_fd == -1)
189d4fb1e02SRoy Marples 		goto eexit;
1907827cba2SAaron LI 
1917827cba2SAaron LI #ifndef O_CLOEXEC
192d4fb1e02SRoy Marples 	if ((fd_opts = fcntl(bpf->bpf_fd, F_GETFD)) == -1 ||
193d4fb1e02SRoy Marples 	    fcntl(bpf->bpf_fd, F_SETFD, fd_opts | FD_CLOEXEC) == -1)
194d4fb1e02SRoy Marples 		goto eexit;
1957827cba2SAaron LI #endif
1967827cba2SAaron LI 
197d4fb1e02SRoy Marples 	if (ioctl(bpf->bpf_fd, BIOCVERSION, &pv) == -1)
1987827cba2SAaron LI 		goto eexit;
1997827cba2SAaron LI 	if (pv.bv_major != BPF_MAJOR_VERSION ||
2007827cba2SAaron LI 	    pv.bv_minor < BPF_MINOR_VERSION) {
2017827cba2SAaron LI 		logerrx("BPF version mismatch - recompile");
2027827cba2SAaron LI 		goto eexit;
2037827cba2SAaron LI 	}
2047827cba2SAaron LI 
2057827cba2SAaron LI 	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
206d4fb1e02SRoy Marples 	if (ioctl(bpf->bpf_fd, BIOCSETIF, &ifr) == -1)
2077827cba2SAaron LI 		goto eexit;
2087827cba2SAaron LI 
2097827cba2SAaron LI #ifdef BIOCIMMEDIATE
2107827cba2SAaron LI 	flags = 1;
211d4fb1e02SRoy Marples 	if (ioctl(bpf->bpf_fd, BIOCIMMEDIATE, &flags) == -1)
2127827cba2SAaron LI 		goto eexit;
2137827cba2SAaron LI #endif
2147827cba2SAaron LI 
215d4fb1e02SRoy Marples 	if (filter(bpf, ia) != 0)
216d4fb1e02SRoy Marples 		goto eexit;
217d4fb1e02SRoy Marples 
218d4fb1e02SRoy Marples 	/* Get the required BPF buffer length from the kernel. */
219d4fb1e02SRoy Marples 	if (ioctl(bpf->bpf_fd, BIOCGBLEN, &ibuf_len) == -1)
220d4fb1e02SRoy Marples 		goto eexit;
221d4fb1e02SRoy Marples 	bpf->bpf_size = (size_t)ibuf_len;
222d4fb1e02SRoy Marples 	bpf->bpf_buffer = malloc(bpf->bpf_size);
223d4fb1e02SRoy Marples 	if (bpf->bpf_buffer == NULL)
224d4fb1e02SRoy Marples 		goto eexit;
225d4fb1e02SRoy Marples 	return bpf;
2267827cba2SAaron LI 
2277827cba2SAaron LI eexit:
228d4fb1e02SRoy Marples 	if (bpf->bpf_fd != -1)
229d4fb1e02SRoy Marples 		close(bpf->bpf_fd);
230d4fb1e02SRoy Marples 	free(bpf);
231d4fb1e02SRoy Marples 	return NULL;
2327827cba2SAaron LI }
2337827cba2SAaron LI 
2347827cba2SAaron LI /* BPF requires that we read the entire buffer.
2357827cba2SAaron LI  * So we pass the buffer in the API so we can loop on >1 packet. */
2367827cba2SAaron LI ssize_t
bpf_read(struct bpf * bpf,void * data,size_t len)237d4fb1e02SRoy Marples bpf_read(struct bpf *bpf, void *data, size_t len)
2387827cba2SAaron LI {
2397827cba2SAaron LI 	ssize_t bytes;
2407827cba2SAaron LI 	struct bpf_hdr packet;
2417827cba2SAaron LI 	const char *payload;
2427827cba2SAaron LI 
243d4fb1e02SRoy Marples 	bpf->bpf_flags &= ~BPF_EOF;
2447827cba2SAaron LI 	for (;;) {
245d4fb1e02SRoy Marples 		if (bpf->bpf_len == 0) {
246d4fb1e02SRoy Marples 			bytes = read(bpf->bpf_fd, bpf->bpf_buffer,
247d4fb1e02SRoy Marples 			    bpf->bpf_size);
2487827cba2SAaron LI #if defined(__sun)
2497827cba2SAaron LI 			/* After 2^31 bytes, the kernel offset overflows.
2507827cba2SAaron LI 			 * To work around this bug, lseek 0. */
2517827cba2SAaron LI 			if (bytes == -1 && errno == EINVAL) {
252d4fb1e02SRoy Marples 				lseek(bpf->bpf_fd, 0, SEEK_SET);
2537827cba2SAaron LI 				continue;
2547827cba2SAaron LI 			}
2557827cba2SAaron LI #endif
2567827cba2SAaron LI 			if (bytes == -1 || bytes == 0)
2577827cba2SAaron LI 				return bytes;
258d4fb1e02SRoy Marples 			bpf->bpf_len = (size_t)bytes;
259d4fb1e02SRoy Marples 			bpf->bpf_pos = 0;
2607827cba2SAaron LI 		}
2617827cba2SAaron LI 		bytes = -1;
262d4fb1e02SRoy Marples 		payload = (const char *)bpf->bpf_buffer + bpf->bpf_pos;
263d4fb1e02SRoy Marples 		memcpy(&packet, payload, sizeof(packet));
264d4fb1e02SRoy Marples 		if (bpf->bpf_pos + packet.bh_caplen + packet.bh_hdrlen >
265d4fb1e02SRoy Marples 		    bpf->bpf_len)
2667827cba2SAaron LI 			goto next; /* Packet beyond buffer, drop. */
267d4fb1e02SRoy Marples 		payload += packet.bh_hdrlen;
2686e63cc1fSRoy Marples 		if (packet.bh_caplen > len)
2697827cba2SAaron LI 			bytes = (ssize_t)len;
2706e63cc1fSRoy Marples 		else
2716e63cc1fSRoy Marples 			bytes = (ssize_t)packet.bh_caplen;
272d4fb1e02SRoy Marples 		if (bpf_frame_bcast(bpf->bpf_ifp, payload) == 0)
273d4fb1e02SRoy Marples 			bpf->bpf_flags |= BPF_BCAST;
274d4fb1e02SRoy Marples 		else
275d4fb1e02SRoy Marples 			bpf->bpf_flags &= ~BPF_BCAST;
2767827cba2SAaron LI 		memcpy(data, payload, (size_t)bytes);
2777827cba2SAaron LI next:
278d4fb1e02SRoy Marples 		bpf->bpf_pos += BPF_WORDALIGN(packet.bh_hdrlen +
2797827cba2SAaron LI 		    packet.bh_caplen);
280d4fb1e02SRoy Marples 		if (bpf->bpf_pos >= bpf->bpf_len) {
281d4fb1e02SRoy Marples 			bpf->bpf_len = bpf->bpf_pos = 0;
282d4fb1e02SRoy Marples 			bpf->bpf_flags |= BPF_EOF;
2837827cba2SAaron LI 		}
2847827cba2SAaron LI 		if (bytes != -1)
2857827cba2SAaron LI 			return bytes;
2867827cba2SAaron LI 	}
2877827cba2SAaron LI 
2887827cba2SAaron LI 	/* NOTREACHED */
2897827cba2SAaron LI }
2907827cba2SAaron LI 
2917827cba2SAaron LI int
bpf_attach(int fd,void * filter,unsigned int filter_len)2927827cba2SAaron LI bpf_attach(int fd, void *filter, unsigned int filter_len)
2937827cba2SAaron LI {
294d4fb1e02SRoy Marples 	struct bpf_program pf = { .bf_insns = filter, .bf_len = filter_len };
2957827cba2SAaron LI 
2967827cba2SAaron LI 	/* Install the filter. */
2977827cba2SAaron LI 	return ioctl(fd, BIOCSETF, &pf);
2987827cba2SAaron LI }
299d4fb1e02SRoy Marples 
300d4fb1e02SRoy Marples #ifdef BIOCSETWF
301d4fb1e02SRoy Marples static int
bpf_wattach(int fd,void * filter,unsigned int filter_len)302d4fb1e02SRoy Marples bpf_wattach(int fd, void *filter, unsigned int filter_len)
303d4fb1e02SRoy Marples {
304d4fb1e02SRoy Marples 	struct bpf_program pf = { .bf_insns = filter, .bf_len = filter_len };
305d4fb1e02SRoy Marples 
306d4fb1e02SRoy Marples 	/* Install the filter. */
307d4fb1e02SRoy Marples 	return ioctl(fd, BIOCSETWF, &pf);
308d4fb1e02SRoy Marples }
309d4fb1e02SRoy Marples #endif
3107827cba2SAaron LI #endif
3117827cba2SAaron LI 
3127827cba2SAaron LI #ifndef __sun
3137827cba2SAaron LI /* SunOS is special too - sending via BPF goes nowhere. */
3147827cba2SAaron LI ssize_t
bpf_send(const struct bpf * bpf,uint16_t protocol,const void * data,size_t len)315d4fb1e02SRoy Marples bpf_send(const struct bpf *bpf, uint16_t protocol,
3167827cba2SAaron LI     const void *data, size_t len)
3177827cba2SAaron LI {
3187827cba2SAaron LI 	struct iovec iov[2];
3197827cba2SAaron LI 	struct ether_header eh;
3207827cba2SAaron LI 
321d4fb1e02SRoy Marples 	switch(bpf->bpf_ifp->hwtype) {
3227827cba2SAaron LI 	case ARPHRD_ETHER:
3237827cba2SAaron LI 		memset(&eh.ether_dhost, 0xff, sizeof(eh.ether_dhost));
324d4fb1e02SRoy Marples 		memcpy(&eh.ether_shost, bpf->bpf_ifp->hwaddr,
325d4fb1e02SRoy Marples 		    sizeof(eh.ether_shost));
3267827cba2SAaron LI 		eh.ether_type = htons(protocol);
3277827cba2SAaron LI 		iov[0].iov_base = &eh;
3287827cba2SAaron LI 		iov[0].iov_len = sizeof(eh);
3297827cba2SAaron LI 		break;
3307827cba2SAaron LI 	default:
3317827cba2SAaron LI 		iov[0].iov_base = NULL;
3327827cba2SAaron LI 		iov[0].iov_len = 0;
3337827cba2SAaron LI 		break;
3347827cba2SAaron LI 	}
3357827cba2SAaron LI 	iov[1].iov_base = UNCONST(data);
3367827cba2SAaron LI 	iov[1].iov_len = len;
337d4fb1e02SRoy Marples 	return writev(bpf->bpf_fd, iov, 2);
3387827cba2SAaron LI }
3397827cba2SAaron LI #endif
3407827cba2SAaron LI 
341d4fb1e02SRoy Marples void
bpf_close(struct bpf * bpf)342d4fb1e02SRoy Marples bpf_close(struct bpf *bpf)
3437827cba2SAaron LI {
3447827cba2SAaron LI 
345d4fb1e02SRoy Marples 	close(bpf->bpf_fd);
346d4fb1e02SRoy Marples 	free(bpf->bpf_buffer);
347d4fb1e02SRoy Marples 	free(bpf);
3487827cba2SAaron LI }
3497827cba2SAaron LI 
3507827cba2SAaron LI #ifdef ARP
3518d36e1dfSRoy Marples #define BPF_CMP_HWADDR_LEN	((((HWADDR_LEN / 4) + 2) * 2) + 1)
3527827cba2SAaron LI static unsigned int
bpf_cmp_hwaddr(struct bpf_insn * bpf,size_t bpf_len,size_t off,bool equal,const uint8_t * hwaddr,size_t hwaddr_len)3537827cba2SAaron LI bpf_cmp_hwaddr(struct bpf_insn *bpf, size_t bpf_len, size_t off,
354d4fb1e02SRoy Marples     bool equal, const uint8_t *hwaddr, size_t hwaddr_len)
3557827cba2SAaron LI {
3567827cba2SAaron LI 	struct bpf_insn *bp;
3577827cba2SAaron LI 	size_t maclen, nlft, njmps;
3587827cba2SAaron LI 	uint32_t mac32;
3597827cba2SAaron LI 	uint16_t mac16;
3607827cba2SAaron LI 	uint8_t jt, jf;
3617827cba2SAaron LI 
3627827cba2SAaron LI 	/* Calc the number of jumps */
3637827cba2SAaron LI 	if ((hwaddr_len / 4) >= 128) {
3647827cba2SAaron LI 		errno = EINVAL;
3657827cba2SAaron LI 		return 0;
3667827cba2SAaron LI 	}
3677827cba2SAaron LI 	njmps = (hwaddr_len / 4) * 2; /* 2 instructions per check */
3687827cba2SAaron LI 	/* We jump after the 1st check. */
3697827cba2SAaron LI 	if (njmps)
3707827cba2SAaron LI 		njmps -= 2;
3717827cba2SAaron LI 	nlft = hwaddr_len % 4;
3727827cba2SAaron LI 	if (nlft) {
3737827cba2SAaron LI 		njmps += (nlft / 2) * 2;
3747827cba2SAaron LI 		nlft = nlft % 2;
3757827cba2SAaron LI 		if (nlft)
3767827cba2SAaron LI 			njmps += 2;
3777827cba2SAaron LI 
3787827cba2SAaron LI 	}
3797827cba2SAaron LI 
3807827cba2SAaron LI 	/* Skip to positive finish. */
3817827cba2SAaron LI 	njmps++;
3827827cba2SAaron LI 	if (equal) {
3837827cba2SAaron LI 		jt = (uint8_t)njmps;
3847827cba2SAaron LI 		jf = 0;
3857827cba2SAaron LI 	} else {
3867827cba2SAaron LI 		jt = 0;
3877827cba2SAaron LI 		jf = (uint8_t)njmps;
3887827cba2SAaron LI 	}
3897827cba2SAaron LI 
3907827cba2SAaron LI 	bp = bpf;
3917827cba2SAaron LI 	for (; hwaddr_len > 0;
3927827cba2SAaron LI 	     hwaddr += maclen, hwaddr_len -= maclen, off += maclen)
3937827cba2SAaron LI 	{
3947827cba2SAaron LI 		if (bpf_len < 3) {
3957827cba2SAaron LI 			errno = ENOBUFS;
3967827cba2SAaron LI 			return 0;
3977827cba2SAaron LI 		}
3987827cba2SAaron LI 		bpf_len -= 3;
3997827cba2SAaron LI 
4007827cba2SAaron LI 		if (hwaddr_len >= 4) {
4017827cba2SAaron LI 			maclen = sizeof(mac32);
4027827cba2SAaron LI 			memcpy(&mac32, hwaddr, maclen);
4037827cba2SAaron LI 			BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, off);
4047827cba2SAaron LI 			bp++;
4057827cba2SAaron LI 			BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
4067827cba2SAaron LI 			             htonl(mac32), jt, jf);
4077827cba2SAaron LI 		} else if (hwaddr_len >= 2) {
4087827cba2SAaron LI 			maclen = sizeof(mac16);
4097827cba2SAaron LI 			memcpy(&mac16, hwaddr, maclen);
4107827cba2SAaron LI 			BPF_SET_STMT(bp, BPF_LD + BPF_H + BPF_IND, off);
4117827cba2SAaron LI 			bp++;
4127827cba2SAaron LI 			BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
4137827cba2SAaron LI 			             htons(mac16), jt, jf);
4147827cba2SAaron LI 		} else {
4157827cba2SAaron LI 			maclen = sizeof(*hwaddr);
4167827cba2SAaron LI 			BPF_SET_STMT(bp, BPF_LD + BPF_B + BPF_IND, off);
4177827cba2SAaron LI 			bp++;
4187827cba2SAaron LI 			BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
4197827cba2SAaron LI 			             *hwaddr, jt, jf);
4207827cba2SAaron LI 		}
4217827cba2SAaron LI 		if (jt)
4227827cba2SAaron LI 			jt = (uint8_t)(jt - 2);
4237827cba2SAaron LI 		if (jf)
4247827cba2SAaron LI 			jf = (uint8_t)(jf - 2);
4257827cba2SAaron LI 		bp++;
4267827cba2SAaron LI 	}
4277827cba2SAaron LI 
4287827cba2SAaron LI 	/* Last step is always return failure.
4297827cba2SAaron LI 	 * Next step is a positive finish. */
4307827cba2SAaron LI 	BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
4317827cba2SAaron LI 	bp++;
4327827cba2SAaron LI 
4337827cba2SAaron LI 	return (unsigned int)(bp - bpf);
4347827cba2SAaron LI }
4357827cba2SAaron LI #endif
4367827cba2SAaron LI 
4377827cba2SAaron LI #ifdef ARP
4387827cba2SAaron LI static const struct bpf_insn bpf_arp_ether [] = {
4397827cba2SAaron LI 	/* Check this is an ARP packet. */
4407827cba2SAaron LI 	BPF_STMT(BPF_LD + BPF_H + BPF_ABS,
4417827cba2SAaron LI 	         offsetof(struct ether_header, ether_type)),
4427827cba2SAaron LI 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 1, 0),
4437827cba2SAaron LI 	BPF_STMT(BPF_RET + BPF_K, 0),
4447827cba2SAaron LI 
4457827cba2SAaron LI 	/* Load frame header length into X */
4467827cba2SAaron LI 	BPF_STMT(BPF_LDX + BPF_W + BPF_IMM, sizeof(struct ether_header)),
4477827cba2SAaron LI 
448d4fb1e02SRoy Marples 	/* Make sure the hardware type matches. */
4497827cba2SAaron LI 	BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_hrd)),
4507827cba2SAaron LI 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0),
4517827cba2SAaron LI 	BPF_STMT(BPF_RET + BPF_K, 0),
4527827cba2SAaron LI 
4537827cba2SAaron LI 	/* Make sure the hardware length matches. */
4547827cba2SAaron LI 	BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct arphdr, ar_hln)),
4557827cba2SAaron LI 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K,
4567827cba2SAaron LI 	         sizeof(((struct ether_arp *)0)->arp_sha), 1, 0),
4577827cba2SAaron LI 	BPF_STMT(BPF_RET + BPF_K, 0),
4587827cba2SAaron LI };
4598d36e1dfSRoy Marples #define BPF_ARP_ETHER_LEN	__arraycount(bpf_arp_ether)
4607827cba2SAaron LI 
4617827cba2SAaron LI static const struct bpf_insn bpf_arp_filter [] = {
4627827cba2SAaron LI 	/* Make sure this is for IP. */
4637827cba2SAaron LI 	BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_pro)),
4647827cba2SAaron LI 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0),
4657827cba2SAaron LI 	BPF_STMT(BPF_RET + BPF_K, 0),
4667827cba2SAaron LI 	/* Make sure this is an ARP REQUEST. */
4677827cba2SAaron LI 	BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_op)),
4687827cba2SAaron LI 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0),
4697827cba2SAaron LI 	/* or ARP REPLY. */
4708d36e1dfSRoy Marples 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0),
4717827cba2SAaron LI 	BPF_STMT(BPF_RET + BPF_K, 0),
4727827cba2SAaron LI 	/* Make sure the protocol length matches. */
4737827cba2SAaron LI 	BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct arphdr, ar_pln)),
4747827cba2SAaron LI 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(in_addr_t), 1, 0),
4757827cba2SAaron LI 	BPF_STMT(BPF_RET + BPF_K, 0),
4767827cba2SAaron LI };
4778d36e1dfSRoy Marples #define BPF_ARP_FILTER_LEN	__arraycount(bpf_arp_filter)
4788d36e1dfSRoy Marples 
479d4fb1e02SRoy Marples /* One address is two checks of two statements. */
480d4fb1e02SRoy Marples #define BPF_NADDRS		1
481d4fb1e02SRoy Marples #define BPF_ARP_ADDRS_LEN	5 + ((BPF_NADDRS * 2) * 2)
4828d36e1dfSRoy Marples 
4838d36e1dfSRoy Marples #define BPF_ARP_LEN		BPF_ARP_ETHER_LEN + BPF_ARP_FILTER_LEN + \
4848d36e1dfSRoy Marples 				BPF_CMP_HWADDR_LEN + BPF_ARP_ADDRS_LEN
4857827cba2SAaron LI 
486d4fb1e02SRoy Marples static int
bpf_arp_rw(const struct bpf * bpf,const struct in_addr * ia,bool recv)487d4fb1e02SRoy Marples bpf_arp_rw(const struct bpf *bpf, const struct in_addr *ia, bool recv)
4887827cba2SAaron LI {
489d4fb1e02SRoy Marples 	const struct interface *ifp = bpf->bpf_ifp;
490d4fb1e02SRoy Marples 	struct bpf_insn buf[BPF_ARP_LEN + 1];
4917827cba2SAaron LI 	struct bpf_insn *bp;
4927827cba2SAaron LI 	uint16_t arp_len;
4937827cba2SAaron LI 
494d4fb1e02SRoy Marples 	bp = buf;
4957827cba2SAaron LI 	/* Check frame header. */
496d4fb1e02SRoy Marples 	switch(ifp->hwtype) {
4977827cba2SAaron LI 	case ARPHRD_ETHER:
4987827cba2SAaron LI 		memcpy(bp, bpf_arp_ether, sizeof(bpf_arp_ether));
4998d36e1dfSRoy Marples 		bp += BPF_ARP_ETHER_LEN;
5007827cba2SAaron LI 		arp_len = sizeof(struct ether_header)+sizeof(struct ether_arp);
5017827cba2SAaron LI 		break;
5027827cba2SAaron LI 	default:
5037827cba2SAaron LI 		errno = EINVAL;
5047827cba2SAaron LI 		return -1;
5057827cba2SAaron LI 	}
5067827cba2SAaron LI 
5077827cba2SAaron LI 	/* Copy in the main filter. */
5087827cba2SAaron LI 	memcpy(bp, bpf_arp_filter, sizeof(bpf_arp_filter));
5098d36e1dfSRoy Marples 	bp += BPF_ARP_FILTER_LEN;
5107827cba2SAaron LI 
5117827cba2SAaron LI 	/* Ensure it's not from us. */
5128d36e1dfSRoy Marples 	bp += bpf_cmp_hwaddr(bp, BPF_CMP_HWADDR_LEN, sizeof(struct arphdr),
513d4fb1e02SRoy Marples 	                     !recv, ifp->hwaddr, ifp->hwlen);
5147827cba2SAaron LI 
5157827cba2SAaron LI 	/* Match sender protocol address */
5167827cba2SAaron LI 	BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND,
5177827cba2SAaron LI 	    sizeof(struct arphdr) + ifp->hwlen);
5187827cba2SAaron LI 	bp++;
519d4fb1e02SRoy Marples 	BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, htonl(ia->s_addr), 0, 1);
5207827cba2SAaron LI 	bp++;
5217827cba2SAaron LI 	BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len);
5227827cba2SAaron LI 	bp++;
5237827cba2SAaron LI 
5247827cba2SAaron LI 	/* If we didn't match sender, then we're only interested in
5257827cba2SAaron LI 	 * ARP probes to us, so check the null host sender. */
5267827cba2SAaron LI 	BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, INADDR_ANY, 1, 0);
5277827cba2SAaron LI 	bp++;
5287827cba2SAaron LI 	BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
5297827cba2SAaron LI 	bp++;
5307827cba2SAaron LI 
5317827cba2SAaron LI 	/* Match target protocol address */
532d4fb1e02SRoy Marples 	BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND, (sizeof(struct arphdr) +
533d4fb1e02SRoy Marples 	    (size_t)(ifp->hwlen * 2) + sizeof(in_addr_t)));
5347827cba2SAaron LI 	bp++;
535d4fb1e02SRoy Marples 	BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, htonl(ia->s_addr), 0, 1);
5367827cba2SAaron LI 	bp++;
5377827cba2SAaron LI 	BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len);
5387827cba2SAaron LI 	bp++;
5397827cba2SAaron LI 
540d4fb1e02SRoy Marples 	/* No match, drop it */
5417827cba2SAaron LI 	BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
5427827cba2SAaron LI 	bp++;
5437827cba2SAaron LI 
544d4fb1e02SRoy Marples #ifdef BIOCSETWF
545d4fb1e02SRoy Marples 	if (!recv)
546d4fb1e02SRoy Marples 		return bpf_wattach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
547d4fb1e02SRoy Marples #endif
548d4fb1e02SRoy Marples 
549d4fb1e02SRoy Marples 	return bpf_attach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
550d4fb1e02SRoy Marples }
551d4fb1e02SRoy Marples 
552d4fb1e02SRoy Marples int
bpf_arp(const struct bpf * bpf,const struct in_addr * ia)553d4fb1e02SRoy Marples bpf_arp(const struct bpf *bpf, const struct in_addr *ia)
554d4fb1e02SRoy Marples {
555d4fb1e02SRoy Marples 
556d4fb1e02SRoy Marples #ifdef BIOCSETWF
557d4fb1e02SRoy Marples 	if (bpf_arp_rw(bpf, ia, true) == -1 ||
558d4fb1e02SRoy Marples 	    bpf_arp_rw(bpf, ia, false) == -1 ||
559d4fb1e02SRoy Marples 	    ioctl(bpf->bpf_fd, BIOCLOCK) == -1)
560d4fb1e02SRoy Marples 		return -1;
561d4fb1e02SRoy Marples 	return 0;
562d4fb1e02SRoy Marples #else
563d4fb1e02SRoy Marples 	return bpf_arp_rw(bpf, ia, true);
564d4fb1e02SRoy Marples #endif
5657827cba2SAaron LI }
5667827cba2SAaron LI #endif
5677827cba2SAaron LI 
5688d36e1dfSRoy Marples #ifdef ARPHRD_NONE
5698d36e1dfSRoy Marples static const struct bpf_insn bpf_bootp_none[] = {
5708d36e1dfSRoy Marples };
5718d36e1dfSRoy Marples #define BPF_BOOTP_NONE_LEN	__arraycount(bpf_bootp_none)
5728d36e1dfSRoy Marples #endif
5738d36e1dfSRoy Marples 
5747827cba2SAaron LI static const struct bpf_insn bpf_bootp_ether[] = {
5757827cba2SAaron LI 	/* Make sure this is an IP packet. */
5767827cba2SAaron LI 	BPF_STMT(BPF_LD + BPF_H + BPF_ABS,
5777827cba2SAaron LI 	         offsetof(struct ether_header, ether_type)),
5787827cba2SAaron LI 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0),
5797827cba2SAaron LI 	BPF_STMT(BPF_RET + BPF_K, 0),
5807827cba2SAaron LI 
5811b3b16a2SRoy Marples 	/* Advance to the IP header. */
5821b3b16a2SRoy Marples 	BPF_STMT(BPF_LDX + BPF_K, sizeof(struct ether_header)),
5837827cba2SAaron LI };
5847827cba2SAaron LI #define BPF_BOOTP_ETHER_LEN	__arraycount(bpf_bootp_ether)
5857827cba2SAaron LI 
586d4fb1e02SRoy Marples static const struct bpf_insn bpf_bootp_base[] = {
5878d36e1dfSRoy Marples 	/* Make sure it's an IPv4 packet. */
5887827cba2SAaron LI 	BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0),
5898d36e1dfSRoy Marples 	BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0xf0),
5908d36e1dfSRoy Marples 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x40, 1, 0),
5917827cba2SAaron LI 	BPF_STMT(BPF_RET + BPF_K, 0),
5927827cba2SAaron LI 
5937827cba2SAaron LI 	/* Make sure it's a UDP packet. */
5947827cba2SAaron LI 	BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct ip, ip_p)),
5957827cba2SAaron LI 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0),
5967827cba2SAaron LI 	BPF_STMT(BPF_RET + BPF_K, 0),
5977827cba2SAaron LI 
5987827cba2SAaron LI 	/* Make sure this isn't a fragment. */
5997827cba2SAaron LI 	BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct ip, ip_off)),
6007827cba2SAaron LI 	BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 0, 1),
6017827cba2SAaron LI 	BPF_STMT(BPF_RET + BPF_K, 0),
6027827cba2SAaron LI 
6037827cba2SAaron LI 	/* Advance to the UDP header. */
6041b3b16a2SRoy Marples 	BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0),
6051b3b16a2SRoy Marples 	BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x0f),
6061b3b16a2SRoy Marples 	BPF_STMT(BPF_ALU + BPF_MUL + BPF_K, 4),
6078d36e1dfSRoy Marples 	BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0),
6087827cba2SAaron LI 	BPF_STMT(BPF_MISC + BPF_TAX, 0),
609d4fb1e02SRoy Marples };
610d4fb1e02SRoy Marples #define BPF_BOOTP_BASE_LEN	__arraycount(bpf_bootp_base)
6117827cba2SAaron LI 
612d4fb1e02SRoy Marples static const struct bpf_insn bpf_bootp_read[] = {
613*f3744ac9SRoy Marples 	/* Make sure it's to the right port.
614*f3744ac9SRoy Marples 	 * RFC2131 makes no mention of enforcing a source port. */
615*f3744ac9SRoy Marples 	BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct udphdr, uh_dport)),
616*f3744ac9SRoy Marples 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTPC, 1, 0),
6177827cba2SAaron LI 	BPF_STMT(BPF_RET + BPF_K, 0),
6187827cba2SAaron LI };
619d4fb1e02SRoy Marples #define BPF_BOOTP_READ_LEN	__arraycount(bpf_bootp_read)
6207827cba2SAaron LI 
621d4fb1e02SRoy Marples #ifdef BIOCSETWF
622d4fb1e02SRoy Marples static const struct bpf_insn bpf_bootp_write[] = {
623*f3744ac9SRoy Marples 	/* Make sure it's from and to the right port.
624*f3744ac9SRoy Marples 	 * RFC2131 makes no mention of encforcing a source port,
625*f3744ac9SRoy Marples 	 * but dhcpcd does enforce it for sending. */
626d4fb1e02SRoy Marples 	BPF_STMT(BPF_LD + BPF_W + BPF_IND, 0),
627d4fb1e02SRoy Marples 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (BOOTPC << 16) + BOOTPS, 1, 0),
628d4fb1e02SRoy Marples 	BPF_STMT(BPF_RET + BPF_K, 0),
629d4fb1e02SRoy Marples };
630d4fb1e02SRoy Marples #define BPF_BOOTP_WRITE_LEN	__arraycount(bpf_bootp_write)
631d4fb1e02SRoy Marples #endif
632d4fb1e02SRoy Marples 
6337827cba2SAaron LI #define BPF_BOOTP_CHADDR_LEN	((BOOTP_CHADDR_LEN / 4) * 3)
6347827cba2SAaron LI #define	BPF_BOOTP_XID_LEN	4 /* BOUND check is 4 instructions */
6357827cba2SAaron LI 
636d4fb1e02SRoy Marples #define BPF_BOOTP_LEN		BPF_BOOTP_ETHER_LEN + \
637d4fb1e02SRoy Marples 				BPF_BOOTP_BASE_LEN + BPF_BOOTP_READ_LEN + \
638d4fb1e02SRoy Marples 				BPF_BOOTP_XID_LEN + BPF_BOOTP_CHADDR_LEN + 4
6397827cba2SAaron LI 
640d4fb1e02SRoy Marples static int
bpf_bootp_rw(const struct bpf * bpf,bool read)641d4fb1e02SRoy Marples bpf_bootp_rw(const struct bpf *bpf, bool read)
6427827cba2SAaron LI {
643d4fb1e02SRoy Marples 	struct bpf_insn buf[BPF_BOOTP_LEN + 1];
6447827cba2SAaron LI 	struct bpf_insn *bp;
6457827cba2SAaron LI 
646d4fb1e02SRoy Marples 	bp = buf;
6477827cba2SAaron LI 	/* Check frame header. */
648d4fb1e02SRoy Marples 	switch(bpf->bpf_ifp->hwtype) {
6498d36e1dfSRoy Marples #ifdef ARPHRD_NONE
6508d36e1dfSRoy Marples 	case ARPHRD_NONE:
6518d36e1dfSRoy Marples 		memcpy(bp, bpf_bootp_none, sizeof(bpf_bootp_none));
6528d36e1dfSRoy Marples 		bp += BPF_BOOTP_NONE_LEN;
6538d36e1dfSRoy Marples 		break;
6548d36e1dfSRoy Marples #endif
6557827cba2SAaron LI 	case ARPHRD_ETHER:
6567827cba2SAaron LI 		memcpy(bp, bpf_bootp_ether, sizeof(bpf_bootp_ether));
6577827cba2SAaron LI 		bp += BPF_BOOTP_ETHER_LEN;
6587827cba2SAaron LI 		break;
6597827cba2SAaron LI 	default:
6607827cba2SAaron LI 		errno = EINVAL;
6617827cba2SAaron LI 		return -1;
6627827cba2SAaron LI 	}
6637827cba2SAaron LI 
6647827cba2SAaron LI 	/* Copy in the main filter. */
665d4fb1e02SRoy Marples 	memcpy(bp, bpf_bootp_base, sizeof(bpf_bootp_base));
666d4fb1e02SRoy Marples 	bp += BPF_BOOTP_BASE_LEN;
6677827cba2SAaron LI 
668d4fb1e02SRoy Marples #ifdef BIOCSETWF
669d4fb1e02SRoy Marples 	if (!read) {
670d4fb1e02SRoy Marples 		memcpy(bp, bpf_bootp_write, sizeof(bpf_bootp_write));
671d4fb1e02SRoy Marples 		bp += BPF_BOOTP_WRITE_LEN;
6727827cba2SAaron LI 
6731b3b16a2SRoy Marples 		/* All passed, return the packet. */
6741b3b16a2SRoy Marples 		BPF_SET_STMT(bp, BPF_RET + BPF_K, BPF_WHOLEPACKET);
6757827cba2SAaron LI 		bp++;
6767827cba2SAaron LI 
677d4fb1e02SRoy Marples 		return bpf_wattach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
678d4fb1e02SRoy Marples 	}
679d4fb1e02SRoy Marples #else
680d4fb1e02SRoy Marples 	UNUSED(read);
681d4fb1e02SRoy Marples #endif
682d4fb1e02SRoy Marples 
683d4fb1e02SRoy Marples 	memcpy(bp, bpf_bootp_read, sizeof(bpf_bootp_read));
684d4fb1e02SRoy Marples 	bp += BPF_BOOTP_READ_LEN;
685d4fb1e02SRoy Marples 
686d4fb1e02SRoy Marples 	/* All passed, return the packet. */
687d4fb1e02SRoy Marples 	BPF_SET_STMT(bp, BPF_RET + BPF_K, BPF_WHOLEPACKET);
688d4fb1e02SRoy Marples 	bp++;
689d4fb1e02SRoy Marples 
690d4fb1e02SRoy Marples 	return bpf_attach(bpf->bpf_fd, buf, (unsigned int)(bp - buf));
691d4fb1e02SRoy Marples }
692d4fb1e02SRoy Marples 
693d4fb1e02SRoy Marples int
bpf_bootp(const struct bpf * bpf,__unused const struct in_addr * ia)694d4fb1e02SRoy Marples bpf_bootp(const struct bpf *bpf, __unused const struct in_addr *ia)
695d4fb1e02SRoy Marples {
696d4fb1e02SRoy Marples 
697d4fb1e02SRoy Marples #ifdef BIOCSETWF
698d4fb1e02SRoy Marples 	if (bpf_bootp_rw(bpf, true) == -1 ||
699d4fb1e02SRoy Marples 	    bpf_bootp_rw(bpf, false) == -1 ||
700d4fb1e02SRoy Marples 	    ioctl(bpf->bpf_fd, BIOCLOCK) == -1)
701d4fb1e02SRoy Marples 		return -1;
702d4fb1e02SRoy Marples 	return 0;
703d4fb1e02SRoy Marples #else
7047f8103cdSRoy Marples #ifdef PRIVSEP
7057f8103cdSRoy Marples #if defined(__sun) /* Solaris cannot send via BPF. */
7067f8103cdSRoy Marples #elif defined(BIOCSETF)
7077f8103cdSRoy Marples #warning No BIOCSETWF support - a compromised BPF can be used as a raw socket
7087f8103cdSRoy Marples #else
7097f8103cdSRoy Marples #warning A compromised PF_PACKET socket can be used as a raw socket
7107f8103cdSRoy Marples #endif
7117f8103cdSRoy Marples #endif
712d4fb1e02SRoy Marples 	return bpf_bootp_rw(bpf, true);
713d4fb1e02SRoy Marples #endif
7147827cba2SAaron LI }
715