xref: /openbsd-src/usr.sbin/dhcrelay6/bpf.c (revision b57001d2402253b2754c7550188932001fb07564)
1*b57001d2Sdlg /*	$OpenBSD: bpf.c,v 1.3 2019/03/18 00:00:59 dlg Exp $ 	*/
29cbab583Srzalamena 
39cbab583Srzalamena /* BPF socket interface code, originally contributed by Archie Cobbs. */
49cbab583Srzalamena 
59cbab583Srzalamena /*
69cbab583Srzalamena  * Copyright (c) 1995, 1996, 1998, 1999
79cbab583Srzalamena  * The Internet Software Consortium.    All rights reserved.
89cbab583Srzalamena  *
99cbab583Srzalamena  * Redistribution and use in source and binary forms, with or without
109cbab583Srzalamena  * modification, are permitted provided that the following conditions
119cbab583Srzalamena  * are met:
129cbab583Srzalamena  *
139cbab583Srzalamena  * 1. Redistributions of source code must retain the above copyright
149cbab583Srzalamena  *    notice, this list of conditions and the following disclaimer.
159cbab583Srzalamena  * 2. Redistributions in binary form must reproduce the above copyright
169cbab583Srzalamena  *    notice, this list of conditions and the following disclaimer in the
179cbab583Srzalamena  *    documentation and/or other materials provided with the distribution.
189cbab583Srzalamena  * 3. Neither the name of The Internet Software Consortium nor the names
199cbab583Srzalamena  *    of its contributors may be used to endorse or promote products derived
209cbab583Srzalamena  *    from this software without specific prior written permission.
219cbab583Srzalamena  *
229cbab583Srzalamena  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
239cbab583Srzalamena  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
249cbab583Srzalamena  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
259cbab583Srzalamena  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
269cbab583Srzalamena  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
279cbab583Srzalamena  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
289cbab583Srzalamena  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
299cbab583Srzalamena  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
309cbab583Srzalamena  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
319cbab583Srzalamena  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
329cbab583Srzalamena  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
339cbab583Srzalamena  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
349cbab583Srzalamena  * SUCH DAMAGE.
359cbab583Srzalamena  *
369cbab583Srzalamena  * This software has been written for the Internet Software Consortium
379cbab583Srzalamena  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
389cbab583Srzalamena  * Enterprises.  To learn more about the Internet Software Consortium,
399cbab583Srzalamena  * see ``http://www.vix.com/isc''.  To learn more about Vixie
409cbab583Srzalamena  * Enterprises, see ``http://www.vix.com''.
419cbab583Srzalamena  */
429cbab583Srzalamena 
439cbab583Srzalamena #include <sys/types.h>
449cbab583Srzalamena #include <sys/ioctl.h>
459cbab583Srzalamena #include <sys/socket.h>
469cbab583Srzalamena 
479cbab583Srzalamena #include <net/bpf.h>
489cbab583Srzalamena #include <net/if.h>
499cbab583Srzalamena 
509cbab583Srzalamena #include <netinet/in.h>
519cbab583Srzalamena #include <netinet/if_ether.h>
529cbab583Srzalamena 
539cbab583Srzalamena #include <errno.h>
549cbab583Srzalamena #include <fcntl.h>
559cbab583Srzalamena #include <stdio.h>
569cbab583Srzalamena #include <stdlib.h>
579cbab583Srzalamena #include <string.h>
589cbab583Srzalamena #include <unistd.h>
599cbab583Srzalamena 
609cbab583Srzalamena #include "dhcp.h"
619cbab583Srzalamena #include "dhcpd.h"
629cbab583Srzalamena #include "log.h"
639cbab583Srzalamena 
649cbab583Srzalamena ssize_t send_packet_layer3(struct interface_info *,
659cbab583Srzalamena     void *, size_t, struct packet_ctx *);
669cbab583Srzalamena 
679cbab583Srzalamena /*
689cbab583Srzalamena  * Called by get_interface_list for each interface that's discovered.
699cbab583Srzalamena  * Opens a packet filter for each interface and adds it to the select
709cbab583Srzalamena  * mask.
719cbab583Srzalamena  */
729cbab583Srzalamena int
if_register_bpf(struct interface_info * info)739cbab583Srzalamena if_register_bpf(struct interface_info *info)
749cbab583Srzalamena {
759cbab583Srzalamena 	int sock;
769cbab583Srzalamena 
779cbab583Srzalamena 	/* Open the BPF device */
787b08a90aSnatano 	if ((sock = open("/dev/bpf", O_RDWR)) == -1)
799cbab583Srzalamena 		fatal("Can't open bpf device");
809cbab583Srzalamena 
819cbab583Srzalamena 	/* Set the BPF device to point at this interface. */
829cbab583Srzalamena 	if (ioctl(sock, BIOCSETIF, &info->ifr) == -1)
839cbab583Srzalamena 		fatal("Can't attach interface %s to bpf device", info->name);
849cbab583Srzalamena 
859cbab583Srzalamena 	return (sock);
869cbab583Srzalamena }
879cbab583Srzalamena 
889cbab583Srzalamena void
if_register_send(struct interface_info * info)899cbab583Srzalamena if_register_send(struct interface_info *info)
909cbab583Srzalamena {
919cbab583Srzalamena 	/*
929cbab583Srzalamena 	 * If we're using the bpf API for sending and receiving, we
939cbab583Srzalamena 	 * don't need to register this interface twice.
949cbab583Srzalamena 	 */
959cbab583Srzalamena 	info->wfdesc = info->rfdesc;
969cbab583Srzalamena }
979cbab583Srzalamena 
989cbab583Srzalamena /* DHCPv6 BPF filters. */
999cbab583Srzalamena 
1009cbab583Srzalamena /*
1019cbab583Srzalamena  * Packet filter program: 'ip6 and udp and dst port DHCP6_SERVER_PORT'
1029cbab583Srzalamena  */
1039cbab583Srzalamena struct bpf_insn dhcp6_bpf_sfilter[] = {
1049cbab583Srzalamena 	/* Make sure this is an IP packet... */
1059cbab583Srzalamena 	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
1069cbab583Srzalamena 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IPV6, 0, 5),
1079cbab583Srzalamena 
1089cbab583Srzalamena 	/* Make sure this is an UDP packet. */
1099cbab583Srzalamena 	BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 20),
1109cbab583Srzalamena 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 3),
1119cbab583Srzalamena 
1129cbab583Srzalamena 	/* Make sure it is the right port. */
1139cbab583Srzalamena 	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 56),
1149cbab583Srzalamena 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP6_SERVER_PORT, 0, 1),
1159cbab583Srzalamena 
1169cbab583Srzalamena 	/* If we passed all the tests, ask for the whole packet. */
1179cbab583Srzalamena 	BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
1189cbab583Srzalamena 
1199cbab583Srzalamena 	/* Otherwise, drop it. */
1209cbab583Srzalamena 	BPF_STMT(BPF_RET + BPF_K, 0),
1219cbab583Srzalamena };
1229cbab583Srzalamena 
1239cbab583Srzalamena int dhcp6_bpf_sfilter_len = sizeof(dhcp6_bpf_sfilter) / sizeof(struct bpf_insn);
1249cbab583Srzalamena 
1259cbab583Srzalamena /*
1269cbab583Srzalamena  * Packet filter program: 'ip6 and udp'
1279cbab583Srzalamena  */
1289cbab583Srzalamena struct bpf_insn dhcp6_bpf_wfilter[] = {
1299cbab583Srzalamena 	/* Make sure this is an IP packet... */
1309cbab583Srzalamena 	BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
1319cbab583Srzalamena 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IPV6, 0, 3),
1329cbab583Srzalamena 
1339cbab583Srzalamena 	/* Make sure this is an UDP packet. */
1349cbab583Srzalamena 	BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 20),
1359cbab583Srzalamena 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 1),
1369cbab583Srzalamena 
1379cbab583Srzalamena 	/* If we passed all the tests, ask for the whole packet. */
1389cbab583Srzalamena 	BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
1399cbab583Srzalamena 
1409cbab583Srzalamena 	/* Otherwise, drop it. */
1419cbab583Srzalamena 	BPF_STMT(BPF_RET + BPF_K, 0),
1429cbab583Srzalamena };
1439cbab583Srzalamena 
1449cbab583Srzalamena int dhcp6_bpf_wfilter_len = sizeof(dhcp6_bpf_wfilter) / sizeof(struct bpf_insn);
1459cbab583Srzalamena 
1469cbab583Srzalamena 
1479cbab583Srzalamena void
if_register_receive(struct interface_info * info)1489cbab583Srzalamena if_register_receive(struct interface_info *info)
1499cbab583Srzalamena {
1509cbab583Srzalamena 	struct bpf_version v;
1519cbab583Srzalamena 	struct bpf_program p;
1529cbab583Srzalamena 	int flag = 1, sz, cmplt = 0;
1539cbab583Srzalamena 
1549cbab583Srzalamena 	/* Open a BPF device and hang it on this interface... */
1559cbab583Srzalamena 	info->rfdesc = if_register_bpf(info);
1569cbab583Srzalamena 
1579cbab583Srzalamena 	/* Make sure the BPF version is in range... */
1589cbab583Srzalamena 	if (ioctl(info->rfdesc, BIOCVERSION, &v) == -1)
1599cbab583Srzalamena 		fatal("Can't get BPF version");
1609cbab583Srzalamena 
1619cbab583Srzalamena 	if (v.bv_major != BPF_MAJOR_VERSION ||
1629cbab583Srzalamena 	    v.bv_minor < BPF_MINOR_VERSION)
1639cbab583Srzalamena 		fatalx("Kernel BPF version out of range - recompile dhcpd!");
1649cbab583Srzalamena 
1659cbab583Srzalamena 	/*
1669cbab583Srzalamena 	 * Set immediate mode so that reads return as soon as a packet
1679cbab583Srzalamena 	 * comes in, rather than waiting for the input buffer to fill
1689cbab583Srzalamena 	 * with packets.
1699cbab583Srzalamena 	 */
1709cbab583Srzalamena 	if (ioctl(info->rfdesc, BIOCIMMEDIATE, &flag) == -1)
1719cbab583Srzalamena 		fatal("Can't set immediate mode on bpf device");
1729cbab583Srzalamena 
1739cbab583Srzalamena 	/* make sure kernel fills in the source ethernet address */
1749cbab583Srzalamena 	if (ioctl(info->rfdesc, BIOCSHDRCMPLT, &cmplt) == -1)
1759cbab583Srzalamena 		fatal("Can't set header complete flag on bpf device");
1769cbab583Srzalamena 
1779cbab583Srzalamena 	/* Get the required BPF buffer length from the kernel. */
1789cbab583Srzalamena 	if (ioctl(info->rfdesc, BIOCGBLEN, &sz) == -1)
1799cbab583Srzalamena 		fatal("Can't get bpf buffer length");
1809cbab583Srzalamena 	info->rbuf_max = sz;
1819cbab583Srzalamena 	info->rbuf = malloc(info->rbuf_max);
1829cbab583Srzalamena 	if (!info->rbuf)
1839cbab583Srzalamena 		fatalx("Can't allocate %lu bytes for bpf input buffer.",
1849cbab583Srzalamena 		    (unsigned long)info->rbuf_max);
1859cbab583Srzalamena 	info->rbuf_offset = 0;
1869cbab583Srzalamena 	info->rbuf_len = 0;
1879cbab583Srzalamena 
1889cbab583Srzalamena 	/* Set up the bpf filter program structure. */
1899cbab583Srzalamena 	p.bf_len = dhcp6_bpf_sfilter_len;
1909cbab583Srzalamena 	p.bf_insns = dhcp6_bpf_sfilter;
1919cbab583Srzalamena 	if (ioctl(info->rfdesc, BIOCSETF, &p) == -1)
1929cbab583Srzalamena 		fatal("Can't install packet filter program");
1939cbab583Srzalamena 
1949cbab583Srzalamena 	/* Set up the bpf write filter program structure. */
1959cbab583Srzalamena 	p.bf_len = dhcp6_bpf_wfilter_len;
1969cbab583Srzalamena 	p.bf_insns = dhcp6_bpf_wfilter;
1979cbab583Srzalamena 	if (ioctl(info->rfdesc, BIOCSETWF, &p) == -1)
1989cbab583Srzalamena 		fatal("Can't install write filter program");
1999cbab583Srzalamena 
2009cbab583Srzalamena 	/* Only get input packets. */
2019cbab583Srzalamena 	flag = BPF_DIRECTION_OUT;
2029cbab583Srzalamena 	if (ioctl(info->rfdesc, BIOCSDIRFILT , &flag) == -1)
2039cbab583Srzalamena 		fatal("Can't set BPF direction capture");
2049cbab583Srzalamena 
2059cbab583Srzalamena 	/* Drop them so they don't go up in the network stack. */
206*b57001d2Sdlg 	flag = BPF_FILDROP_CAPTURE;
2079cbab583Srzalamena 	if (ioctl(info->rfdesc, BIOCSFILDROP, &flag) == -1)
2089cbab583Srzalamena 		fatal("Can't set BPF filter drop");
2099cbab583Srzalamena 
2109cbab583Srzalamena 	/* make sure these settings cannot be changed after dropping privs */
2119cbab583Srzalamena 	if (ioctl(info->rfdesc, BIOCLOCK) == -1)
2129cbab583Srzalamena 		fatal("Failed to lock bpf descriptor");
2139cbab583Srzalamena }
2149cbab583Srzalamena 
2159cbab583Srzalamena ssize_t
send_packet_layer3(struct interface_info * intf,void * raw,size_t len,struct packet_ctx * pc)2169cbab583Srzalamena send_packet_layer3(struct interface_info *intf, void *raw, size_t len,
2179cbab583Srzalamena     struct packet_ctx *pc)
2189cbab583Srzalamena {
2199cbab583Srzalamena 	struct cmsghdr		*cmsg;
2209cbab583Srzalamena 	ssize_t			 sendlen;
2219cbab583Srzalamena 	struct msghdr		 msg;
2229cbab583Srzalamena 	struct in6_pktinfo	*ipi6;
2239cbab583Srzalamena 	struct sockaddr_storage	 ss;
2249cbab583Srzalamena 	struct iovec		 iov[2];
2259cbab583Srzalamena 	uint8_t			 cmsgbuf[
2269cbab583Srzalamena 	    CMSG_SPACE(sizeof(struct in6_pktinfo))
2279cbab583Srzalamena 	];
2289cbab583Srzalamena 
2299cbab583Srzalamena 	log_debug("  sending %ld bytes to %s:%d via %s",
2309cbab583Srzalamena 	    len, v6addr2str(&ss2sin6(&pc->pc_dst)->sin6_addr),
2319cbab583Srzalamena 	    ntohs(ss2sin6(&pc->pc_dst)->sin6_port), intf->name);
2329cbab583Srzalamena 
2339cbab583Srzalamena 	memset(&msg, 0, sizeof(msg));
2349cbab583Srzalamena 	iov[0].iov_base = raw;
2359cbab583Srzalamena 	iov[0].iov_len = len;
2369cbab583Srzalamena 	msg.msg_iov = iov;
2379cbab583Srzalamena 	msg.msg_iovlen = 1;
2389cbab583Srzalamena 
2399cbab583Srzalamena 	ss = pc->pc_dst;
2409cbab583Srzalamena 	ss2sin6(&ss)->sin6_scope_id = intf->index;
2419cbab583Srzalamena 	msg.msg_name = &ss;
2429cbab583Srzalamena 	msg.msg_namelen = ss.ss_len;
2439cbab583Srzalamena 
2449cbab583Srzalamena 	/* If binded to multicast we should select an interface. */
2459cbab583Srzalamena 	if (IN6_IS_ADDR_MULTICAST(&ss2sin6(&ss)->sin6_addr)) {
2469cbab583Srzalamena 		memset(cmsgbuf, 0, sizeof(cmsgbuf));
2479cbab583Srzalamena 		msg.msg_control = cmsgbuf;
2489cbab583Srzalamena 		msg.msg_controllen = sizeof(cmsgbuf);
2499cbab583Srzalamena 
2509cbab583Srzalamena 		/* Use the IPV6_PKTINFO to select the interface. */
2519cbab583Srzalamena 		cmsg = (struct cmsghdr *)CMSG_FIRSTHDR(&msg);
2529cbab583Srzalamena 		cmsg->cmsg_len = CMSG_LEN(sizeof(*ipi6));
2539cbab583Srzalamena 		cmsg->cmsg_level = IPPROTO_IPV6;
2549cbab583Srzalamena 		cmsg->cmsg_type = IPV6_PKTINFO;
2559cbab583Srzalamena 
2569cbab583Srzalamena 		ipi6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
2579cbab583Srzalamena 		ipi6->ipi6_ifindex = intf->index;
2589cbab583Srzalamena 	}
2599cbab583Srzalamena 
2609cbab583Srzalamena 	if ((sendlen = sendmsg(pc->pc_sd, &msg, 0)) == -1) {
2619cbab583Srzalamena 		log_warn("  failed to send message");
2629cbab583Srzalamena 		return -1;
2639cbab583Srzalamena 	}
2649cbab583Srzalamena 	if (sendlen < (ssize_t)len)
2659cbab583Srzalamena 		log_warnx("  sent less bytes than expected (%ld < %ld)",
2669cbab583Srzalamena 		    sendlen, len);
2679cbab583Srzalamena 
2689cbab583Srzalamena 	return sendlen;
2699cbab583Srzalamena }
2709cbab583Srzalamena 
2719cbab583Srzalamena ssize_t
send_packet(struct interface_info * interface,void * raw,size_t len,struct packet_ctx * pc)2729cbab583Srzalamena send_packet(struct interface_info *interface,
2739cbab583Srzalamena     void *raw, size_t len, struct packet_ctx *pc)
2749cbab583Srzalamena {
2759cbab583Srzalamena 	unsigned char buf[256];
2769cbab583Srzalamena 	struct iovec iov[2];
2779cbab583Srzalamena 	int result, bufp = 0;
2789cbab583Srzalamena 
2799cbab583Srzalamena 	if (pc->pc_sd != 0)
2809cbab583Srzalamena 		return send_packet_layer3(interface, raw, len, pc);
2819cbab583Srzalamena 
2829cbab583Srzalamena 	/* Assemble the headers... */
2839cbab583Srzalamena 	assemble_hw_header(buf, &bufp, pc);
2849cbab583Srzalamena 	assemble_udp_ip6_header(buf, &bufp, pc, raw, len);
2859cbab583Srzalamena 
2869cbab583Srzalamena 	/* Fire it off */
2879cbab583Srzalamena 	iov[0].iov_base = (char *)buf;
2889cbab583Srzalamena 	iov[0].iov_len = bufp;
2899cbab583Srzalamena 	iov[1].iov_base = (char *)raw;
2909cbab583Srzalamena 	iov[1].iov_len = len;
2919cbab583Srzalamena 
2929cbab583Srzalamena 	result = writev(interface->wfdesc, iov, 2);
2939cbab583Srzalamena 	if (result == -1)
2949cbab583Srzalamena 		log_warn("send_packet");
2959cbab583Srzalamena 
2969cbab583Srzalamena 	return (result);
2979cbab583Srzalamena }
2989cbab583Srzalamena 
2999cbab583Srzalamena ssize_t
receive_packet(struct interface_info * interface,unsigned char * buf,size_t len,struct packet_ctx * pc)3009cbab583Srzalamena receive_packet(struct interface_info *interface, unsigned char *buf,
3019cbab583Srzalamena     size_t len, struct packet_ctx *pc)
3029cbab583Srzalamena {
3039cbab583Srzalamena 	int length = 0, offset = 0;
3049cbab583Srzalamena 	struct bpf_hdr hdr;
3059cbab583Srzalamena 
3069cbab583Srzalamena 	/*
3079cbab583Srzalamena 	 * All this complexity is because BPF doesn't guarantee that
3089cbab583Srzalamena 	 * only one packet will be returned at a time.  We're getting
3099cbab583Srzalamena 	 * what we deserve, though - this is a terrible abuse of the BPF
3109cbab583Srzalamena 	 * interface.  Sigh.
3119cbab583Srzalamena 	 */
3129cbab583Srzalamena 
3139cbab583Srzalamena 	/* Process packets until we get one we can return or until we've
3149cbab583Srzalamena 	 * done a read and gotten nothing we can return...
3159cbab583Srzalamena 	 */
3169cbab583Srzalamena 	do {
3179cbab583Srzalamena 		/* If the buffer is empty, fill it. */
3189cbab583Srzalamena 		if (interface->rbuf_offset == interface->rbuf_len) {
3199cbab583Srzalamena 			length = read(interface->rfdesc, interface->rbuf,
3209cbab583Srzalamena 			    interface->rbuf_max);
3219cbab583Srzalamena 			if (length <= 0)
3229cbab583Srzalamena 				return (length);
3239cbab583Srzalamena 			interface->rbuf_offset = 0;
3249cbab583Srzalamena 			interface->rbuf_len = length;
3259cbab583Srzalamena 		}
3269cbab583Srzalamena 
3279cbab583Srzalamena 		/*
3289cbab583Srzalamena 		 * If there isn't room for a whole bpf header, something
3299cbab583Srzalamena 		 * went wrong, but we'll ignore it and hope it goes
3309cbab583Srzalamena 		 * away... XXX
3319cbab583Srzalamena 		 */
3329cbab583Srzalamena 		if (interface->rbuf_len - interface->rbuf_offset <
3339cbab583Srzalamena 		    sizeof(hdr)) {
3349cbab583Srzalamena 			interface->rbuf_offset = interface->rbuf_len;
3359cbab583Srzalamena 			continue;
3369cbab583Srzalamena 		}
3379cbab583Srzalamena 
3389cbab583Srzalamena 		/* Copy out a bpf header... */
3399cbab583Srzalamena 		memcpy(&hdr, &interface->rbuf[interface->rbuf_offset],
3409cbab583Srzalamena 		    sizeof(hdr));
3419cbab583Srzalamena 
3429cbab583Srzalamena 		/*
3439cbab583Srzalamena 		 * If the bpf header plus data doesn't fit in what's
3449cbab583Srzalamena 		 * left of the buffer, stick head in sand yet again...
3459cbab583Srzalamena 		 */
3469cbab583Srzalamena 		if (interface->rbuf_offset + hdr.bh_hdrlen + hdr.bh_caplen >
3479cbab583Srzalamena 		    interface->rbuf_len) {
3489cbab583Srzalamena 			interface->rbuf_offset = interface->rbuf_len;
3499cbab583Srzalamena 			continue;
3509cbab583Srzalamena 		}
3519cbab583Srzalamena 
3529cbab583Srzalamena 		/*
3539cbab583Srzalamena 		 * If the captured data wasn't the whole packet, or if
3549cbab583Srzalamena 		 * the packet won't fit in the input buffer, all we can
3559cbab583Srzalamena 		 * do is drop it.
3569cbab583Srzalamena 		 */
3579cbab583Srzalamena 		if (hdr.bh_caplen != hdr.bh_datalen) {
3589cbab583Srzalamena 			interface->rbuf_offset += hdr.bh_hdrlen =
3599cbab583Srzalamena 			    hdr.bh_caplen;
3609cbab583Srzalamena 			continue;
3619cbab583Srzalamena 		}
3629cbab583Srzalamena 
3639cbab583Srzalamena 		/* Skip over the BPF header... */
3649cbab583Srzalamena 		interface->rbuf_offset += hdr.bh_hdrlen;
3659cbab583Srzalamena 
3669cbab583Srzalamena 		/* Decode the physical header... */
3679cbab583Srzalamena 		offset = decode_hw_header(interface->rbuf,
3689cbab583Srzalamena 		    interface->rbuf_offset, pc);
3699cbab583Srzalamena 
3709cbab583Srzalamena 		/*
3719cbab583Srzalamena 		 * If a physical layer checksum failed (dunno of any
3729cbab583Srzalamena 		 * physical layer that supports this, but WTH), skip
3739cbab583Srzalamena 		 * this packet.
3749cbab583Srzalamena 		 */
3759cbab583Srzalamena 		if (offset < 0) {
3769cbab583Srzalamena 			interface->rbuf_offset += hdr.bh_caplen;
3779cbab583Srzalamena 			continue;
3789cbab583Srzalamena 		}
3799cbab583Srzalamena 		interface->rbuf_offset += offset;
3809cbab583Srzalamena 		hdr.bh_caplen -= offset;
3819cbab583Srzalamena 
3829cbab583Srzalamena 		/* Decode the IP and UDP headers... */
3839cbab583Srzalamena 		offset = decode_udp_ip6_header(interface->rbuf,
3849cbab583Srzalamena 		    interface->rbuf_offset, pc, hdr.bh_caplen);
3859cbab583Srzalamena 
3869cbab583Srzalamena 		/* If the IP or UDP checksum was bad, skip the packet... */
3879cbab583Srzalamena 		if (offset < 0) {
3889cbab583Srzalamena 			interface->rbuf_offset += hdr.bh_caplen;
3899cbab583Srzalamena 			continue;
3909cbab583Srzalamena 		}
3919cbab583Srzalamena 		interface->rbuf_offset += offset;
3929cbab583Srzalamena 		hdr.bh_caplen -= offset;
3939cbab583Srzalamena 
3949cbab583Srzalamena 		/*
3959cbab583Srzalamena 		 * If there's not enough room to stash the packet data,
3969cbab583Srzalamena 		 * we have to skip it (this shouldn't happen in real
3979cbab583Srzalamena 		 * life, though).
3989cbab583Srzalamena 		 */
3999cbab583Srzalamena 		if (hdr.bh_caplen > len) {
4009cbab583Srzalamena 			interface->rbuf_offset += hdr.bh_caplen;
4019cbab583Srzalamena 			continue;
4029cbab583Srzalamena 		}
4039cbab583Srzalamena 
4049cbab583Srzalamena 		/* Copy out the data in the packet... */
4059cbab583Srzalamena 		memcpy(buf, interface->rbuf + interface->rbuf_offset,
4069cbab583Srzalamena 		    hdr.bh_caplen);
4079cbab583Srzalamena 		interface->rbuf_offset += hdr.bh_caplen;
4089cbab583Srzalamena 		return (hdr.bh_caplen);
4099cbab583Srzalamena 	} while (!length);
4109cbab583Srzalamena 	return (0);
4119cbab583Srzalamena }
412