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