xref: /minix/minix/tests/test94.c (revision 3ba6090f)
1*3ba6090fSDavid van Moolenbroek /* Tests for BPF devices (LWIP) - by D.C. van Moolenbroek */
2*3ba6090fSDavid van Moolenbroek /* This test needs to be run as root: opening BPF devices is root-only. */
3*3ba6090fSDavid van Moolenbroek /*
4*3ba6090fSDavid van Moolenbroek  * We do not attempt to test the BPF filter code here.  Such a test is better
5*3ba6090fSDavid van Moolenbroek  * done through standardized tests and with direct use of the filter code.
6*3ba6090fSDavid van Moolenbroek  * The current BPF filter implementation has been run through the FreeBSD
7*3ba6090fSDavid van Moolenbroek  * BPF filter regression tests (from their tools/regression/bpf/bpf_filter), of
8*3ba6090fSDavid van Moolenbroek  * which only the last test (0084 - "Check very long BPF program") failed due
9*3ba6090fSDavid van Moolenbroek  * to our lower and strictly enforced BPF_MAXINSNS value.  Future modifications
10*3ba6090fSDavid van Moolenbroek  * of the BPF filter code should be tested against at least that test set.
11*3ba6090fSDavid van Moolenbroek  */
12*3ba6090fSDavid van Moolenbroek #include <stdlib.h>
13*3ba6090fSDavid van Moolenbroek #include <string.h>
14*3ba6090fSDavid van Moolenbroek #include <signal.h>
15*3ba6090fSDavid van Moolenbroek #include <sys/ioctl.h>
16*3ba6090fSDavid van Moolenbroek #include <sys/socket.h>
17*3ba6090fSDavid van Moolenbroek #include <sys/sysctl.h>
18*3ba6090fSDavid van Moolenbroek #include <sys/wait.h>
19*3ba6090fSDavid van Moolenbroek #include <net/bpf.h>
20*3ba6090fSDavid van Moolenbroek #include <net/bpfdesc.h>
21*3ba6090fSDavid van Moolenbroek #include <net/if.h>
22*3ba6090fSDavid van Moolenbroek #include <net/if_types.h>
23*3ba6090fSDavid van Moolenbroek #include <net/if_ether.h>
24*3ba6090fSDavid van Moolenbroek #include <net/if_dl.h>
25*3ba6090fSDavid van Moolenbroek #include <netinet/in.h>
26*3ba6090fSDavid van Moolenbroek #include <netinet/ip.h>
27*3ba6090fSDavid van Moolenbroek #include <netinet/ip6.h>
28*3ba6090fSDavid van Moolenbroek #include <netinet/udp.h>
29*3ba6090fSDavid van Moolenbroek #include <ifaddrs.h>
30*3ba6090fSDavid van Moolenbroek #include <unistd.h>
31*3ba6090fSDavid van Moolenbroek #include <fcntl.h>
32*3ba6090fSDavid van Moolenbroek #include <limits.h>
33*3ba6090fSDavid van Moolenbroek #include <paths.h>
34*3ba6090fSDavid van Moolenbroek #include <pwd.h>
35*3ba6090fSDavid van Moolenbroek 
36*3ba6090fSDavid van Moolenbroek #include "common.h"
37*3ba6090fSDavid van Moolenbroek 
38*3ba6090fSDavid van Moolenbroek #define ITERATIONS	2
39*3ba6090fSDavid van Moolenbroek 
40*3ba6090fSDavid van Moolenbroek #define LOOPBACK_IFNAME	"lo0"
41*3ba6090fSDavid van Moolenbroek 
42*3ba6090fSDavid van Moolenbroek #define TEST_PORT_A	12345
43*3ba6090fSDavid van Moolenbroek #define TEST_PORT_B	12346
44*3ba6090fSDavid van Moolenbroek 
45*3ba6090fSDavid van Moolenbroek #define SLEEP_TIME	250000	/* (us) - increases may require code changes */
46*3ba6090fSDavid van Moolenbroek 
47*3ba6090fSDavid van Moolenbroek #define NONROOT_USER	"bin"	/* name of any unprivileged user */
48*3ba6090fSDavid van Moolenbroek 
49*3ba6090fSDavid van Moolenbroek #ifdef NO_INET6
50*3ba6090fSDavid van Moolenbroek const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
51*3ba6090fSDavid van Moolenbroek #endif /* NO_INET6 */
52*3ba6090fSDavid van Moolenbroek 
53*3ba6090fSDavid van Moolenbroek static unsigned int got_signal;
54*3ba6090fSDavid van Moolenbroek 
55*3ba6090fSDavid van Moolenbroek /*
56*3ba6090fSDavid van Moolenbroek  * Signal handler.
57*3ba6090fSDavid van Moolenbroek  */
58*3ba6090fSDavid van Moolenbroek static void
test94_signal(int sig)59*3ba6090fSDavid van Moolenbroek test94_signal(int sig)
60*3ba6090fSDavid van Moolenbroek {
61*3ba6090fSDavid van Moolenbroek 
62*3ba6090fSDavid van Moolenbroek 	if (sig != SIGUSR1) e(0);
63*3ba6090fSDavid van Moolenbroek 
64*3ba6090fSDavid van Moolenbroek 	got_signal++;
65*3ba6090fSDavid van Moolenbroek }
66*3ba6090fSDavid van Moolenbroek 
67*3ba6090fSDavid van Moolenbroek /*
68*3ba6090fSDavid van Moolenbroek  * Send UDP packets on the given socket 'fd' so as to fill up a BPF store
69*3ba6090fSDavid van Moolenbroek  * buffer of size 'size' exactly.  The provided buffer 'buf' may be used for
70*3ba6090fSDavid van Moolenbroek  * packet generation and is at least of 'size' bytes.  Return the number of
71*3ba6090fSDavid van Moolenbroek  * packets sent.
72*3ba6090fSDavid van Moolenbroek  */
73*3ba6090fSDavid van Moolenbroek static uint32_t
test94_fill_exact(int fd,uint8_t * buf,size_t size,uint32_t seq)74*3ba6090fSDavid van Moolenbroek test94_fill_exact(int fd, uint8_t * buf, size_t size, uint32_t seq)
75*3ba6090fSDavid van Moolenbroek {
76*3ba6090fSDavid van Moolenbroek 	size_t hdrlen, len;
77*3ba6090fSDavid van Moolenbroek 
78*3ba6090fSDavid van Moolenbroek 	hdrlen = BPF_WORDALIGN(sizeof(struct bpf_hdr)) + sizeof(struct ip) +
79*3ba6090fSDavid van Moolenbroek 	    sizeof(struct udphdr) + sizeof(seq);
80*3ba6090fSDavid van Moolenbroek 
81*3ba6090fSDavid van Moolenbroek 	for (len = 16; len <= hdrlen; len <<= 1);
82*3ba6090fSDavid van Moolenbroek 	if (len > size) e(0);
83*3ba6090fSDavid van Moolenbroek 
84*3ba6090fSDavid van Moolenbroek 	hdrlen = BPF_WORDALIGN(hdrlen - sizeof(seq));
85*3ba6090fSDavid van Moolenbroek 
86*3ba6090fSDavid van Moolenbroek 	for (; size > 0; seq++) {
87*3ba6090fSDavid van Moolenbroek 		memset(buf, 'Y', len - hdrlen);
88*3ba6090fSDavid van Moolenbroek 		if (len - hdrlen > sizeof(seq))
89*3ba6090fSDavid van Moolenbroek 			buf[sizeof(seq)] = 'X';
90*3ba6090fSDavid van Moolenbroek 		buf[len - hdrlen - 1] = 'Z';
91*3ba6090fSDavid van Moolenbroek 		memcpy(buf, &seq, sizeof(seq));
92*3ba6090fSDavid van Moolenbroek 
93*3ba6090fSDavid van Moolenbroek 		if (write(fd, buf, len - hdrlen) != len - hdrlen) e(0);
94*3ba6090fSDavid van Moolenbroek 
95*3ba6090fSDavid van Moolenbroek 		size -= len;
96*3ba6090fSDavid van Moolenbroek 	}
97*3ba6090fSDavid van Moolenbroek 
98*3ba6090fSDavid van Moolenbroek 	return seq;
99*3ba6090fSDavid van Moolenbroek }
100*3ba6090fSDavid van Moolenbroek 
101*3ba6090fSDavid van Moolenbroek /*
102*3ba6090fSDavid van Moolenbroek  * Send UDP packets on the given socket 'fd' so as to fill up at least a BPF
103*3ba6090fSDavid van Moolenbroek  * store buffer of size 'size', with at least one more packet being sent.  The
104*3ba6090fSDavid van Moolenbroek  * provided buffer 'buf' may be used for packet generation and is at least of
105*3ba6090fSDavid van Moolenbroek  * 'size' bytes.
106*3ba6090fSDavid van Moolenbroek  */
107*3ba6090fSDavid van Moolenbroek static void
test94_fill_random(int fd,uint8_t * buf,size_t size)108*3ba6090fSDavid van Moolenbroek test94_fill_random(int fd, uint8_t * buf, size_t size)
109*3ba6090fSDavid van Moolenbroek {
110*3ba6090fSDavid van Moolenbroek 	size_t hdrlen, len;
111*3ba6090fSDavid van Moolenbroek 	ssize_t left;
112*3ba6090fSDavid van Moolenbroek 	uint32_t seq;
113*3ba6090fSDavid van Moolenbroek 
114*3ba6090fSDavid van Moolenbroek 	hdrlen = BPF_WORDALIGN(BPF_WORDALIGN(sizeof(struct bpf_hdr)) +
115*3ba6090fSDavid van Moolenbroek 	    sizeof(struct ip) + sizeof(struct udphdr));
116*3ba6090fSDavid van Moolenbroek 
117*3ba6090fSDavid van Moolenbroek 	/* Even if we fill the buffer exactly, we send one more packet. */
118*3ba6090fSDavid van Moolenbroek 	for (left = (ssize_t)size, seq = 1; left >= 0; seq++) {
119*3ba6090fSDavid van Moolenbroek 		len = hdrlen + sizeof(seq) + lrand48() % (size / 10);
120*3ba6090fSDavid van Moolenbroek 
121*3ba6090fSDavid van Moolenbroek 		memset(buf, 'Y', len - hdrlen);
122*3ba6090fSDavid van Moolenbroek 		if (len - hdrlen > sizeof(seq))
123*3ba6090fSDavid van Moolenbroek 			buf[sizeof(seq)] = 'X';
124*3ba6090fSDavid van Moolenbroek 		buf[len - hdrlen - 1] = 'Z';
125*3ba6090fSDavid van Moolenbroek 		memcpy(buf, &seq, sizeof(seq));
126*3ba6090fSDavid van Moolenbroek 
127*3ba6090fSDavid van Moolenbroek 		if (write(fd, buf, len - hdrlen) != len - hdrlen) e(0);
128*3ba6090fSDavid van Moolenbroek 
129*3ba6090fSDavid van Moolenbroek 		left -= BPF_WORDALIGN(len);
130*3ba6090fSDavid van Moolenbroek 	}
131*3ba6090fSDavid van Moolenbroek }
132*3ba6090fSDavid van Moolenbroek 
133*3ba6090fSDavid van Moolenbroek /*
134*3ba6090fSDavid van Moolenbroek  * Send a UDP packet with a specific size of 'size' bytes and sequence number
135*3ba6090fSDavid van Moolenbroek  * 'seq' on socket 'fd', using 'buf' as scratch buffer.
136*3ba6090fSDavid van Moolenbroek  */
137*3ba6090fSDavid van Moolenbroek static void
test94_add_specific(int fd,uint8_t * buf,size_t size,uint32_t seq)138*3ba6090fSDavid van Moolenbroek test94_add_specific(int fd, uint8_t * buf, size_t size, uint32_t seq)
139*3ba6090fSDavid van Moolenbroek {
140*3ba6090fSDavid van Moolenbroek 
141*3ba6090fSDavid van Moolenbroek 	size += sizeof(seq);
142*3ba6090fSDavid van Moolenbroek 
143*3ba6090fSDavid van Moolenbroek 	memset(buf, 'Y', size);
144*3ba6090fSDavid van Moolenbroek 	if (size > sizeof(seq))
145*3ba6090fSDavid van Moolenbroek 		buf[sizeof(seq)] = 'X';
146*3ba6090fSDavid van Moolenbroek 	buf[size - 1] = 'Z';
147*3ba6090fSDavid van Moolenbroek 	memcpy(buf, &seq, sizeof(seq));
148*3ba6090fSDavid van Moolenbroek 
149*3ba6090fSDavid van Moolenbroek 	if (write(fd, buf, size) != size) e(0);
150*3ba6090fSDavid van Moolenbroek }
151*3ba6090fSDavid van Moolenbroek 
152*3ba6090fSDavid van Moolenbroek /*
153*3ba6090fSDavid van Moolenbroek  * Send a randomly sized, relatively small UDP packet on the given socket 'fd',
154*3ba6090fSDavid van Moolenbroek  * using sequence number 'seq'.  The buffer 'buf' may be used as scratch buffer
155*3ba6090fSDavid van Moolenbroek  * which is at most 'size' bytes--the same size as the total BPF buffer.
156*3ba6090fSDavid van Moolenbroek  */
157*3ba6090fSDavid van Moolenbroek static void
test94_add_random(int fd,uint8_t * buf,size_t size,uint32_t seq)158*3ba6090fSDavid van Moolenbroek test94_add_random(int fd, uint8_t * buf, size_t size, uint32_t seq)
159*3ba6090fSDavid van Moolenbroek {
160*3ba6090fSDavid van Moolenbroek 
161*3ba6090fSDavid van Moolenbroek 	test94_add_specific(fd, buf, lrand48() % (size / 10), seq);
162*3ba6090fSDavid van Moolenbroek }
163*3ba6090fSDavid van Moolenbroek 
164*3ba6090fSDavid van Moolenbroek /*
165*3ba6090fSDavid van Moolenbroek  * Check whether the packet in 'buf' of 'caplen' captured bytes out of
166*3ba6090fSDavid van Moolenbroek  * 'datalen' data bytes is one we sent.  If so, return an offset to the packet
167*3ba6090fSDavid van Moolenbroek  * data.  If not, return a negative value.
168*3ba6090fSDavid van Moolenbroek  */
169*3ba6090fSDavid van Moolenbroek static ssize_t
test94_check_pkt(uint8_t * buf,ssize_t caplen,ssize_t datalen)170*3ba6090fSDavid van Moolenbroek test94_check_pkt(uint8_t * buf, ssize_t caplen, ssize_t datalen)
171*3ba6090fSDavid van Moolenbroek {
172*3ba6090fSDavid van Moolenbroek 	struct ip ip;
173*3ba6090fSDavid van Moolenbroek 	struct udphdr uh;
174*3ba6090fSDavid van Moolenbroek 
175*3ba6090fSDavid van Moolenbroek 	if (caplen < sizeof(ip))
176*3ba6090fSDavid van Moolenbroek 		return -1;
177*3ba6090fSDavid van Moolenbroek 
178*3ba6090fSDavid van Moolenbroek 	memcpy(&ip, buf, sizeof(ip));
179*3ba6090fSDavid van Moolenbroek 
180*3ba6090fSDavid van Moolenbroek 	if (ip.ip_v != IPVERSION)
181*3ba6090fSDavid van Moolenbroek 		return -1;
182*3ba6090fSDavid van Moolenbroek 	if (ip.ip_hl != sizeof(ip) >> 2)
183*3ba6090fSDavid van Moolenbroek 		return -1;
184*3ba6090fSDavid van Moolenbroek 	if (ip.ip_p != IPPROTO_UDP)
185*3ba6090fSDavid van Moolenbroek 		return -1;
186*3ba6090fSDavid van Moolenbroek 
187*3ba6090fSDavid van Moolenbroek 	if (caplen - sizeof(ip) < sizeof(uh))
188*3ba6090fSDavid van Moolenbroek 		return -1;
189*3ba6090fSDavid van Moolenbroek 
190*3ba6090fSDavid van Moolenbroek 	memcpy(&uh, buf + sizeof(ip), sizeof(uh));
191*3ba6090fSDavid van Moolenbroek 
192*3ba6090fSDavid van Moolenbroek 	if (uh.uh_sport != htons(TEST_PORT_A))
193*3ba6090fSDavid van Moolenbroek 		return -1;
194*3ba6090fSDavid van Moolenbroek 	if (uh.uh_dport != htons(TEST_PORT_B))
195*3ba6090fSDavid van Moolenbroek 		return -1;
196*3ba6090fSDavid van Moolenbroek 
197*3ba6090fSDavid van Moolenbroek 	if (datalen - sizeof(ip) != ntohs(uh.uh_ulen)) e(0);
198*3ba6090fSDavid van Moolenbroek 
199*3ba6090fSDavid van Moolenbroek 	return sizeof(ip) + sizeof(uh);
200*3ba6090fSDavid van Moolenbroek }
201*3ba6090fSDavid van Moolenbroek 
202*3ba6090fSDavid van Moolenbroek /*
203*3ba6090fSDavid van Moolenbroek  * Check whether the capture in 'buf' of 'len' bytes looks like a valid set of
204*3ba6090fSDavid van Moolenbroek  * captured packets.  The valid packets start from sequence number 'seq'; the
205*3ba6090fSDavid van Moolenbroek  * next expected sequence number is returned.  If 'filtered' is set, there
206*3ba6090fSDavid van Moolenbroek  * should be no other packets in the capture; otherwise, other packets are
207*3ba6090fSDavid van Moolenbroek  * ignored.
208*3ba6090fSDavid van Moolenbroek  */
209*3ba6090fSDavid van Moolenbroek static uint32_t
test94_check(uint8_t * buf,ssize_t len,uint32_t seq,int filtered,uint32_t * caplen,uint32_t * datalen)210*3ba6090fSDavid van Moolenbroek test94_check(uint8_t * buf, ssize_t len, uint32_t seq, int filtered,
211*3ba6090fSDavid van Moolenbroek 	uint32_t * caplen, uint32_t * datalen)
212*3ba6090fSDavid van Moolenbroek {
213*3ba6090fSDavid van Moolenbroek 	struct bpf_hdr bh;
214*3ba6090fSDavid van Moolenbroek 	ssize_t off;
215*3ba6090fSDavid van Moolenbroek 	uint32_t nseq;
216*3ba6090fSDavid van Moolenbroek 
217*3ba6090fSDavid van Moolenbroek 	while (len > 0) {
218*3ba6090fSDavid van Moolenbroek 		/*
219*3ba6090fSDavid van Moolenbroek 		 * We rely on the assumption that the last packet in the buffer
220*3ba6090fSDavid van Moolenbroek 		 * is padded to alignment as well; if not, this check fails.
221*3ba6090fSDavid van Moolenbroek 		 */
222*3ba6090fSDavid van Moolenbroek 		if (len < BPF_WORDALIGN(sizeof(bh))) e(0);
223*3ba6090fSDavid van Moolenbroek 
224*3ba6090fSDavid van Moolenbroek 		memcpy(&bh, buf, sizeof(bh));
225*3ba6090fSDavid van Moolenbroek 
226*3ba6090fSDavid van Moolenbroek 		/*
227*3ba6090fSDavid van Moolenbroek 		 * The timestamp fields should be filled in.  The tests that
228*3ba6090fSDavid van Moolenbroek 		 * use this function do not set a capture length below the
229*3ba6090fSDavid van Moolenbroek 		 * packet length.  The header must be exactly as large as we
230*3ba6090fSDavid van Moolenbroek 		 * expect: no small-size tricks (as NetBSD uses) and no
231*3ba6090fSDavid van Moolenbroek 		 * unexpected extra padding.
232*3ba6090fSDavid van Moolenbroek 		 */
233*3ba6090fSDavid van Moolenbroek 		if (bh.bh_tstamp.tv_sec == 0 && bh.bh_tstamp.tv_usec == 0)
234*3ba6090fSDavid van Moolenbroek 		     e(0);
235*3ba6090fSDavid van Moolenbroek 		if (caplen != NULL) {
236*3ba6090fSDavid van Moolenbroek 			if (bh.bh_caplen != *caplen) e(0);
237*3ba6090fSDavid van Moolenbroek 			if (bh.bh_datalen != *datalen) e(0);
238*3ba6090fSDavid van Moolenbroek 
239*3ba6090fSDavid van Moolenbroek 			caplen++;
240*3ba6090fSDavid van Moolenbroek 			datalen++;
241*3ba6090fSDavid van Moolenbroek 		} else
242*3ba6090fSDavid van Moolenbroek 			if (bh.bh_datalen != bh.bh_caplen) e(0);
243*3ba6090fSDavid van Moolenbroek 		if (bh.bh_hdrlen != BPF_WORDALIGN(sizeof(bh))) e(0);
244*3ba6090fSDavid van Moolenbroek 
245*3ba6090fSDavid van Moolenbroek 		if (bh.bh_hdrlen + BPF_WORDALIGN(bh.bh_caplen) > len) e(0);
246*3ba6090fSDavid van Moolenbroek 
247*3ba6090fSDavid van Moolenbroek 		buf += bh.bh_hdrlen;
248*3ba6090fSDavid van Moolenbroek 		len -= bh.bh_hdrlen;
249*3ba6090fSDavid van Moolenbroek 
250*3ba6090fSDavid van Moolenbroek 		if ((off = test94_check_pkt(buf, bh.bh_caplen,
251*3ba6090fSDavid van Moolenbroek 		    bh.bh_datalen)) < 0) {
252*3ba6090fSDavid van Moolenbroek 			if (filtered) e(0);
253*3ba6090fSDavid van Moolenbroek 
254*3ba6090fSDavid van Moolenbroek 			buf += BPF_WORDALIGN(bh.bh_caplen);
255*3ba6090fSDavid van Moolenbroek 			len -= BPF_WORDALIGN(bh.bh_caplen);
256*3ba6090fSDavid van Moolenbroek 
257*3ba6090fSDavid van Moolenbroek 			continue;
258*3ba6090fSDavid van Moolenbroek 		}
259*3ba6090fSDavid van Moolenbroek 
260*3ba6090fSDavid van Moolenbroek 		if (bh.bh_caplen < off + sizeof(seq)) e(0);
261*3ba6090fSDavid van Moolenbroek 
262*3ba6090fSDavid van Moolenbroek 		memcpy(&nseq, &buf[off], sizeof(nseq));
263*3ba6090fSDavid van Moolenbroek 
264*3ba6090fSDavid van Moolenbroek 		if (nseq != seq++) e(0);
265*3ba6090fSDavid van Moolenbroek 
266*3ba6090fSDavid van Moolenbroek 		off += sizeof(seq);
267*3ba6090fSDavid van Moolenbroek 		if (off < bh.bh_caplen) {
268*3ba6090fSDavid van Moolenbroek 			/* If there is just one byte, it is 'Z'. */
269*3ba6090fSDavid van Moolenbroek 			if (off < bh.bh_caplen && off < bh.bh_datalen - 1) {
270*3ba6090fSDavid van Moolenbroek 				if (buf[off] != 'X') e(0);
271*3ba6090fSDavid van Moolenbroek 
272*3ba6090fSDavid van Moolenbroek 				for (off++; off < bh.bh_caplen &&
273*3ba6090fSDavid van Moolenbroek 				    off < bh.bh_datalen - 1; off++)
274*3ba6090fSDavid van Moolenbroek 					if (buf[off] != 'Y') e(0);
275*3ba6090fSDavid van Moolenbroek 			}
276*3ba6090fSDavid van Moolenbroek 			if (off < bh.bh_caplen && off == bh.bh_datalen - 1 &&
277*3ba6090fSDavid van Moolenbroek 			    buf[off] != 'Z') e(0);
278*3ba6090fSDavid van Moolenbroek 		}
279*3ba6090fSDavid van Moolenbroek 
280*3ba6090fSDavid van Moolenbroek 		buf += BPF_WORDALIGN(bh.bh_caplen);
281*3ba6090fSDavid van Moolenbroek 		len -= BPF_WORDALIGN(bh.bh_caplen);
282*3ba6090fSDavid van Moolenbroek 	}
283*3ba6090fSDavid van Moolenbroek 
284*3ba6090fSDavid van Moolenbroek 	return seq;
285*3ba6090fSDavid van Moolenbroek }
286*3ba6090fSDavid van Moolenbroek 
287*3ba6090fSDavid van Moolenbroek /*
288*3ba6090fSDavid van Moolenbroek  * Filter program to ensure that the given (datalink-headerless) packet is an
289*3ba6090fSDavid van Moolenbroek  * IPv4 UDP packet from port 12345 to port 12346.  Important: the 'k' value of
290*3ba6090fSDavid van Moolenbroek  * the last instruction must be the accepted packet size, and is modified by
291*3ba6090fSDavid van Moolenbroek  * some of the tests further down!
292*3ba6090fSDavid van Moolenbroek  */
293*3ba6090fSDavid van Moolenbroek static struct bpf_insn test94_filter[] = {
294*3ba6090fSDavid van Moolenbroek 	{ BPF_LD+BPF_B+BPF_ABS, 0, 0, 0 },	/* is this an IPv4 header? */
295*3ba6090fSDavid van Moolenbroek 	{ BPF_ALU+BPF_RSH+BPF_K, 0, 0, 4 },
296*3ba6090fSDavid van Moolenbroek 	{ BPF_JMP+BPF_JEQ+BPF_K, 0, 7, 4 },
297*3ba6090fSDavid van Moolenbroek 	{ BPF_LD+BPF_B+BPF_ABS, 0, 0, 9 },	/* is this a UDP packet? */
298*3ba6090fSDavid van Moolenbroek 	{ BPF_JMP+BPF_JEQ+BPF_K, 0, 5, IPPROTO_UDP },
299*3ba6090fSDavid van Moolenbroek 	{ BPF_LDX+BPF_B+BPF_MSH, 0, 0, 0 },
300*3ba6090fSDavid van Moolenbroek 	{ BPF_LD+BPF_H+BPF_IND, 0, 0, 0 },	/* source port 12345? */
301*3ba6090fSDavid van Moolenbroek 	{ BPF_JMP+BPF_JEQ+BPF_K, 0, 2, TEST_PORT_A },
302*3ba6090fSDavid van Moolenbroek 	{ BPF_LD+BPF_H+BPF_IND, 0, 0, 2 },	/* destination port 12346? */
303*3ba6090fSDavid van Moolenbroek 	{ BPF_JMP+BPF_JEQ+BPF_K, 1, 0, TEST_PORT_B },
304*3ba6090fSDavid van Moolenbroek 	{ BPF_RET+BPF_K, 0, 0, 0 },		/* reject the packet */
305*3ba6090fSDavid van Moolenbroek 	{ BPF_RET+BPF_K, 0, 0, (uint32_t)-1 },	/* accept the (whole) packet */
306*3ba6090fSDavid van Moolenbroek };
307*3ba6090fSDavid van Moolenbroek 
308*3ba6090fSDavid van Moolenbroek /*
309*3ba6090fSDavid van Moolenbroek  * Set up a BPF device, a pair of sockets of which traffic will be captured on
310*3ba6090fSDavid van Moolenbroek  * the BPF device, a buffer for capturing packets, and optionally a filter.
311*3ba6090fSDavid van Moolenbroek  * If the given size is non-zero, use that as buffer size.  Return the BPF
312*3ba6090fSDavid van Moolenbroek  * device's actual buffer size, which is also the size of 'buf'.
313*3ba6090fSDavid van Moolenbroek  */
314*3ba6090fSDavid van Moolenbroek static size_t
test94_setup(int * fd,int * fd2,int * fd3,uint8_t ** buf,unsigned int size,int set_filter)315*3ba6090fSDavid van Moolenbroek test94_setup(int * fd, int * fd2, int * fd3, uint8_t ** buf, unsigned int size,
316*3ba6090fSDavid van Moolenbroek 	int set_filter)
317*3ba6090fSDavid van Moolenbroek {
318*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in sinA, sinB;
319*3ba6090fSDavid van Moolenbroek 	struct ifreq ifr;
320*3ba6090fSDavid van Moolenbroek 	struct bpf_program bf;
321*3ba6090fSDavid van Moolenbroek 	unsigned int dlt;
322*3ba6090fSDavid van Moolenbroek 
323*3ba6090fSDavid van Moolenbroek 	if ((*fd = open(_PATH_BPF, O_RDWR)) < 0) e(0);
324*3ba6090fSDavid van Moolenbroek 
325*3ba6090fSDavid van Moolenbroek 	if (size != 0 && ioctl(*fd, BIOCSBLEN, &size) != 0) e(0);
326*3ba6090fSDavid van Moolenbroek 
327*3ba6090fSDavid van Moolenbroek 	if (ioctl(*fd, BIOCGBLEN, &size) != 0) e(0);
328*3ba6090fSDavid van Moolenbroek 	if (size < 1024 || size > BPF_MAXBUFSIZE) e(0);
329*3ba6090fSDavid van Moolenbroek 
330*3ba6090fSDavid van Moolenbroek 	if ((*buf = malloc(size)) == NULL) e(0);
331*3ba6090fSDavid van Moolenbroek 
332*3ba6090fSDavid van Moolenbroek 	if (set_filter) {
333*3ba6090fSDavid van Moolenbroek 		/*
334*3ba6090fSDavid van Moolenbroek 		 * Install a filter to improve predictability for the tests.
335*3ba6090fSDavid van Moolenbroek 		 */
336*3ba6090fSDavid van Moolenbroek 		memset(&bf, 0, sizeof(bf));
337*3ba6090fSDavid van Moolenbroek 		bf.bf_len = __arraycount(test94_filter);
338*3ba6090fSDavid van Moolenbroek 		bf.bf_insns = test94_filter;
339*3ba6090fSDavid van Moolenbroek 		if (ioctl(*fd, BIOCSETF, &bf) != 0) e(0);
340*3ba6090fSDavid van Moolenbroek 	}
341*3ba6090fSDavid van Moolenbroek 
342*3ba6090fSDavid van Moolenbroek 	/* Bind to the loopback device. */
343*3ba6090fSDavid van Moolenbroek 	memset(&ifr, 0, sizeof(ifr));
344*3ba6090fSDavid van Moolenbroek 	strlcpy(ifr.ifr_name, LOOPBACK_IFNAME, sizeof(ifr.ifr_name));
345*3ba6090fSDavid van Moolenbroek 	if (ioctl(*fd, BIOCSETIF, &ifr) != 0) e(0);
346*3ba6090fSDavid van Moolenbroek 
347*3ba6090fSDavid van Moolenbroek 	/*
348*3ba6090fSDavid van Moolenbroek 	 * If the loopback device's data link type is not DLT_RAW, our filter
349*3ba6090fSDavid van Moolenbroek 	 * and size calculations will not work.
350*3ba6090fSDavid van Moolenbroek 	 */
351*3ba6090fSDavid van Moolenbroek 	if (ioctl(*fd, BIOCGDLT, &dlt) != 0) e(0);
352*3ba6090fSDavid van Moolenbroek 	if (dlt != DLT_RAW) e(0);
353*3ba6090fSDavid van Moolenbroek 
354*3ba6090fSDavid van Moolenbroek 	/* We use UDP traffic for our test packets. */
355*3ba6090fSDavid van Moolenbroek 	if ((*fd2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) e(0);
356*3ba6090fSDavid van Moolenbroek 
357*3ba6090fSDavid van Moolenbroek 	memset(&sinA, 0, sizeof(sinA));
358*3ba6090fSDavid van Moolenbroek 	sinA.sin_family = AF_INET;
359*3ba6090fSDavid van Moolenbroek 	sinA.sin_port = htons(TEST_PORT_A);
360*3ba6090fSDavid van Moolenbroek 	sinA.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
361*3ba6090fSDavid van Moolenbroek 	if (bind(*fd2, (struct sockaddr *)&sinA, sizeof(sinA)) != 0) e(0);
362*3ba6090fSDavid van Moolenbroek 
363*3ba6090fSDavid van Moolenbroek 	memcpy(&sinB, &sinA, sizeof(sinB));
364*3ba6090fSDavid van Moolenbroek 	sinB.sin_port = htons(TEST_PORT_B);
365*3ba6090fSDavid van Moolenbroek 	if (connect(*fd2, (struct sockaddr *)&sinB, sizeof(sinB)) != 0) e(0);
366*3ba6090fSDavid van Moolenbroek 
367*3ba6090fSDavid van Moolenbroek 	if ((*fd3 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) e(0);
368*3ba6090fSDavid van Moolenbroek 
369*3ba6090fSDavid van Moolenbroek 	if (bind(*fd3, (struct sockaddr *)&sinB, sizeof(sinB)) != 0) e(0);
370*3ba6090fSDavid van Moolenbroek 
371*3ba6090fSDavid van Moolenbroek 	if (connect(*fd3, (struct sockaddr *)&sinA, sizeof(sinA)) != 0) e(0);
372*3ba6090fSDavid van Moolenbroek 
373*3ba6090fSDavid van Moolenbroek 	return size;
374*3ba6090fSDavid van Moolenbroek }
375*3ba6090fSDavid van Moolenbroek 
376*3ba6090fSDavid van Moolenbroek /*
377*3ba6090fSDavid van Moolenbroek  * Clean up resources allocated by test94_setup().
378*3ba6090fSDavid van Moolenbroek  */
379*3ba6090fSDavid van Moolenbroek static void
test94_cleanup(int fd,int fd2,int fd3,uint8_t * buf)380*3ba6090fSDavid van Moolenbroek test94_cleanup(int fd, int fd2, int fd3, uint8_t * buf)
381*3ba6090fSDavid van Moolenbroek {
382*3ba6090fSDavid van Moolenbroek 
383*3ba6090fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
384*3ba6090fSDavid van Moolenbroek 
385*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
386*3ba6090fSDavid van Moolenbroek 
387*3ba6090fSDavid van Moolenbroek 	free(buf);
388*3ba6090fSDavid van Moolenbroek 
389*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
390*3ba6090fSDavid van Moolenbroek }
391*3ba6090fSDavid van Moolenbroek 
392*3ba6090fSDavid van Moolenbroek /*
393*3ba6090fSDavid van Moolenbroek  * Test reading packets from a BPF device, using regular mode.
394*3ba6090fSDavid van Moolenbroek  */
395*3ba6090fSDavid van Moolenbroek static void
test94a(void)396*3ba6090fSDavid van Moolenbroek test94a(void)
397*3ba6090fSDavid van Moolenbroek {
398*3ba6090fSDavid van Moolenbroek 	struct bpf_program bf;
399*3ba6090fSDavid van Moolenbroek 	struct timeval tv;
400*3ba6090fSDavid van Moolenbroek 	fd_set fds;
401*3ba6090fSDavid van Moolenbroek 	uint8_t *buf;
402*3ba6090fSDavid van Moolenbroek 	pid_t pid;
403*3ba6090fSDavid van Moolenbroek 	size_t size;
404*3ba6090fSDavid van Moolenbroek 	ssize_t len;
405*3ba6090fSDavid van Moolenbroek 	uint32_t seq;
406*3ba6090fSDavid van Moolenbroek 	int fd, fd2, fd3, status, bytes, fl;
407*3ba6090fSDavid van Moolenbroek 
408*3ba6090fSDavid van Moolenbroek 	subtest = 1;
409*3ba6090fSDavid van Moolenbroek 
410*3ba6090fSDavid van Moolenbroek 	size = test94_setup(&fd, &fd2, &fd3, &buf, 0 /*size*/,
411*3ba6090fSDavid van Moolenbroek 	    0 /*set_filter*/);
412*3ba6090fSDavid van Moolenbroek 
413*3ba6090fSDavid van Moolenbroek 	/*
414*3ba6090fSDavid van Moolenbroek 	 * Test that a filled-up store buffer will be returned to a pending
415*3ba6090fSDavid van Moolenbroek 	 * read call.  Perform this first test without a filter, to ensure that
416*3ba6090fSDavid van Moolenbroek 	 * the default behavior is to accept all packets.  The side effect is
417*3ba6090fSDavid van Moolenbroek 	 * that we may receive other loopback traffic as part of our capture.
418*3ba6090fSDavid van Moolenbroek 	 */
419*3ba6090fSDavid van Moolenbroek 	pid = fork();
420*3ba6090fSDavid van Moolenbroek 	switch (pid) {
421*3ba6090fSDavid van Moolenbroek 	case 0:
422*3ba6090fSDavid van Moolenbroek 		errct = 0;
423*3ba6090fSDavid van Moolenbroek 
424*3ba6090fSDavid van Moolenbroek 		usleep(SLEEP_TIME);
425*3ba6090fSDavid van Moolenbroek 
426*3ba6090fSDavid van Moolenbroek 		test94_fill_random(fd2, buf, size);
427*3ba6090fSDavid van Moolenbroek 
428*3ba6090fSDavid van Moolenbroek 		exit(errct);
429*3ba6090fSDavid van Moolenbroek 	case -1:
430*3ba6090fSDavid van Moolenbroek 		e(0);
431*3ba6090fSDavid van Moolenbroek 
432*3ba6090fSDavid van Moolenbroek 		break;
433*3ba6090fSDavid van Moolenbroek 	default:
434*3ba6090fSDavid van Moolenbroek 		break;
435*3ba6090fSDavid van Moolenbroek 	}
436*3ba6090fSDavid van Moolenbroek 
437*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
438*3ba6090fSDavid van Moolenbroek 
439*3ba6090fSDavid van Moolenbroek 	if (len < size * 3/4) e(0);
440*3ba6090fSDavid van Moolenbroek 	if (len > size) e(0);
441*3ba6090fSDavid van Moolenbroek 	test94_check(buf, len, 1 /*seq*/, 0 /*filtered*/, NULL /*caplen*/,
442*3ba6090fSDavid van Moolenbroek 	    NULL /*datalen*/);
443*3ba6090fSDavid van Moolenbroek 
444*3ba6090fSDavid van Moolenbroek 	if (wait(&status) != pid) e(0);
445*3ba6090fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
446*3ba6090fSDavid van Moolenbroek 
447*3ba6090fSDavid van Moolenbroek 	/* Only the exact buffer size may be used in read calls. */
448*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, size - 1) != -1) e(0);
449*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
450*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, size + 1) != -1) e(0);
451*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
452*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, sizeof(struct bpf_hdr)) != -1) e(0);
453*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
454*3ba6090fSDavid van Moolenbroek 
455*3ba6090fSDavid van Moolenbroek 	/*
456*3ba6090fSDavid van Moolenbroek 	 * Install a filter to improve predictability for the remaining tests.
457*3ba6090fSDavid van Moolenbroek 	 */
458*3ba6090fSDavid van Moolenbroek 	memset(&bf, 0, sizeof(bf));
459*3ba6090fSDavid van Moolenbroek 	bf.bf_len = __arraycount(test94_filter);
460*3ba6090fSDavid van Moolenbroek 	bf.bf_insns = test94_filter;
461*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSETF, &bf) != 0) e(0);
462*3ba6090fSDavid van Moolenbroek 
463*3ba6090fSDavid van Moolenbroek 	/*
464*3ba6090fSDavid van Moolenbroek 	 * Next we want to test that an already filled-up buffer will be
465*3ba6090fSDavid van Moolenbroek 	 * returned to a read call immediately.  We take the opportunity to
466*3ba6090fSDavid van Moolenbroek 	 * test that filling the buffer will also wake up a blocked select
467*3ba6090fSDavid van Moolenbroek 	 * call.  In addition, we test ioctl(FIONREAD).
468*3ba6090fSDavid van Moolenbroek 	 */
469*3ba6090fSDavid van Moolenbroek 	tv.tv_sec = 0;
470*3ba6090fSDavid van Moolenbroek 	tv.tv_usec = 0;
471*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&fds);
472*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &fds);
473*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, &tv) != 0) e(0);
474*3ba6090fSDavid van Moolenbroek 	if (FD_ISSET(fd, &fds)) e(0);
475*3ba6090fSDavid van Moolenbroek 
476*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, FIONREAD, &bytes) != 0) e(0);
477*3ba6090fSDavid van Moolenbroek 	if (bytes != 0) e(0);
478*3ba6090fSDavid van Moolenbroek 
479*3ba6090fSDavid van Moolenbroek 	pid = fork();
480*3ba6090fSDavid van Moolenbroek 	switch (pid) {
481*3ba6090fSDavid van Moolenbroek 	case 0:
482*3ba6090fSDavid van Moolenbroek 		errct = 0;
483*3ba6090fSDavid van Moolenbroek 
484*3ba6090fSDavid van Moolenbroek 		usleep(SLEEP_TIME);
485*3ba6090fSDavid van Moolenbroek 
486*3ba6090fSDavid van Moolenbroek 		test94_fill_random(fd2, buf, size);
487*3ba6090fSDavid van Moolenbroek 
488*3ba6090fSDavid van Moolenbroek 		exit(errct);
489*3ba6090fSDavid van Moolenbroek 	case -1:
490*3ba6090fSDavid van Moolenbroek 		e(0);
491*3ba6090fSDavid van Moolenbroek 
492*3ba6090fSDavid van Moolenbroek 		break;
493*3ba6090fSDavid van Moolenbroek 	default:
494*3ba6090fSDavid van Moolenbroek 		break;
495*3ba6090fSDavid van Moolenbroek 	}
496*3ba6090fSDavid van Moolenbroek 
497*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&fds);
498*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &fds);
499*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, NULL) != 1) e(0);
500*3ba6090fSDavid van Moolenbroek 	if (!FD_ISSET(fd, &fds)) e(0);
501*3ba6090fSDavid van Moolenbroek 
502*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, FIONREAD, &bytes) != 0) e(0);
503*3ba6090fSDavid van Moolenbroek 
504*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, NULL) != 1) e(0);
505*3ba6090fSDavid van Moolenbroek 	if (!FD_ISSET(fd, &fds)) e(0);
506*3ba6090fSDavid van Moolenbroek 
507*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
508*3ba6090fSDavid van Moolenbroek 
509*3ba6090fSDavid van Moolenbroek 	if (len < size * 3/4) e(0);
510*3ba6090fSDavid van Moolenbroek 	if (len > size) e(0);
511*3ba6090fSDavid van Moolenbroek 	seq = test94_check(buf, len, 1 /*seq*/, 1 /*filtered*/,
512*3ba6090fSDavid van Moolenbroek 	    NULL /*caplen*/, NULL /*datalen*/);
513*3ba6090fSDavid van Moolenbroek 
514*3ba6090fSDavid van Moolenbroek 	if (len != bytes) e(0);
515*3ba6090fSDavid van Moolenbroek 
516*3ba6090fSDavid van Moolenbroek 	if (wait(&status) != pid) e(0);
517*3ba6090fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
518*3ba6090fSDavid van Moolenbroek 
519*3ba6090fSDavid van Moolenbroek 	/* There is one more packet in the store buffer at this point. */
520*3ba6090fSDavid van Moolenbroek 	tv.tv_sec = 0;
521*3ba6090fSDavid van Moolenbroek 	tv.tv_usec = 0;
522*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&fds);
523*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &fds);
524*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, &tv) != 0) e(0);
525*3ba6090fSDavid van Moolenbroek 	if (FD_ISSET(fd, &fds)) e(0);
526*3ba6090fSDavid van Moolenbroek 
527*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, FIONREAD, &bytes) != 0) e(0);
528*3ba6090fSDavid van Moolenbroek 	if (bytes != 0) e(0);
529*3ba6090fSDavid van Moolenbroek 
530*3ba6090fSDavid van Moolenbroek 	/*
531*3ba6090fSDavid van Moolenbroek 	 * Next, we test whether read timeouts work, first checking that a
532*3ba6090fSDavid van Moolenbroek 	 * timed-out read call returns any packets currently in the buffer.
533*3ba6090fSDavid van Moolenbroek 	 * We use sleep and a signal as a crude way to test that the call was
534*3ba6090fSDavid van Moolenbroek 	 * actually blocked until the timeout occurred.
535*3ba6090fSDavid van Moolenbroek 	 */
536*3ba6090fSDavid van Moolenbroek 	got_signal = 0;
537*3ba6090fSDavid van Moolenbroek 
538*3ba6090fSDavid van Moolenbroek 	pid = fork();
539*3ba6090fSDavid van Moolenbroek 	switch (pid) {
540*3ba6090fSDavid van Moolenbroek 	case 0:
541*3ba6090fSDavid van Moolenbroek 		errct = 0;
542*3ba6090fSDavid van Moolenbroek 
543*3ba6090fSDavid van Moolenbroek 		signal(SIGUSR1, test94_signal);
544*3ba6090fSDavid van Moolenbroek 
545*3ba6090fSDavid van Moolenbroek 		usleep(SLEEP_TIME);
546*3ba6090fSDavid van Moolenbroek 
547*3ba6090fSDavid van Moolenbroek 		test94_add_random(fd2, buf, size, seq + 1);
548*3ba6090fSDavid van Moolenbroek 
549*3ba6090fSDavid van Moolenbroek 		usleep(SLEEP_TIME);
550*3ba6090fSDavid van Moolenbroek 
551*3ba6090fSDavid van Moolenbroek 		if (got_signal != 0) e(0);
552*3ba6090fSDavid van Moolenbroek 		pause();
553*3ba6090fSDavid van Moolenbroek 		if (got_signal != 1) e(0);
554*3ba6090fSDavid van Moolenbroek 
555*3ba6090fSDavid van Moolenbroek 		exit(errct);
556*3ba6090fSDavid van Moolenbroek 	case -1:
557*3ba6090fSDavid van Moolenbroek 		e(0);
558*3ba6090fSDavid van Moolenbroek 
559*3ba6090fSDavid van Moolenbroek 		break;
560*3ba6090fSDavid van Moolenbroek 	default:
561*3ba6090fSDavid van Moolenbroek 		break;
562*3ba6090fSDavid van Moolenbroek 	}
563*3ba6090fSDavid van Moolenbroek 
564*3ba6090fSDavid van Moolenbroek 	tv.tv_sec = 0;
565*3ba6090fSDavid van Moolenbroek 	tv.tv_usec = SLEEP_TIME * 3;
566*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSRTIMEOUT, &tv) != 0) e(0);
567*3ba6090fSDavid van Moolenbroek 
568*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
569*3ba6090fSDavid van Moolenbroek 	if (len <= 0) e(0);
570*3ba6090fSDavid van Moolenbroek 	if (len >= size * 3/4) e(0);	/* two packets < 3/4 of the size */
571*3ba6090fSDavid van Moolenbroek 	if (test94_check(buf, len, seq, 1 /*filtered*/, NULL /*caplen*/,
572*3ba6090fSDavid van Moolenbroek 	    NULL /*datalen*/) != seq + 2) e(0);
573*3ba6090fSDavid van Moolenbroek 
574*3ba6090fSDavid van Moolenbroek 	if (kill(pid, SIGUSR1) != 0) e(0);
575*3ba6090fSDavid van Moolenbroek 
576*3ba6090fSDavid van Moolenbroek 	if (wait(&status) != pid) e(0);
577*3ba6090fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
578*3ba6090fSDavid van Moolenbroek 
579*3ba6090fSDavid van Moolenbroek 	/*
580*3ba6090fSDavid van Moolenbroek 	 * Next, see if a timed-out read will all buffers empty yields EAGAIN.
581*3ba6090fSDavid van Moolenbroek 	 */
582*3ba6090fSDavid van Moolenbroek 	tv.tv_sec = 0;
583*3ba6090fSDavid van Moolenbroek 	tv.tv_usec = SLEEP_TIME;
584*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSRTIMEOUT, &tv) != 0) e(0);
585*3ba6090fSDavid van Moolenbroek 
586*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, size) != -1) e(0);
587*3ba6090fSDavid van Moolenbroek 	if (errno != EAGAIN) e(0);
588*3ba6090fSDavid van Moolenbroek 
589*3ba6090fSDavid van Moolenbroek 	/*
590*3ba6090fSDavid van Moolenbroek 	 * Verify that resetting the timeout to zero makes the call block
591*3ba6090fSDavid van Moolenbroek 	 * forever (for short test values of "forever" anyway), because
592*3ba6090fSDavid van Moolenbroek 	 * otherwise this may create a false illusion of correctness in the
593*3ba6090fSDavid van Moolenbroek 	 * next test, for non-blocking calls.  As a side effect, this tests
594*3ba6090fSDavid van Moolenbroek 	 * read call signal interruption, and ensures no partial results are
595*3ba6090fSDavid van Moolenbroek 	 * returned in that case.
596*3ba6090fSDavid van Moolenbroek 	 */
597*3ba6090fSDavid van Moolenbroek 	tv.tv_sec = 0;
598*3ba6090fSDavid van Moolenbroek 	tv.tv_usec = 0;
599*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSRTIMEOUT, &tv) != 0) e(0);
600*3ba6090fSDavid van Moolenbroek 
601*3ba6090fSDavid van Moolenbroek 	pid = fork();
602*3ba6090fSDavid van Moolenbroek 	switch (pid) {
603*3ba6090fSDavid van Moolenbroek 	case 0:
604*3ba6090fSDavid van Moolenbroek 		errct = 0;
605*3ba6090fSDavid van Moolenbroek 
606*3ba6090fSDavid van Moolenbroek 		signal(SIGUSR1, test94_signal);
607*3ba6090fSDavid van Moolenbroek 
608*3ba6090fSDavid van Moolenbroek 		if (read(fd, buf, size) != -1) e(0);
609*3ba6090fSDavid van Moolenbroek 		if (errno != EINTR) e(0);
610*3ba6090fSDavid van Moolenbroek 
611*3ba6090fSDavid van Moolenbroek 		if (got_signal != 1) e(0);
612*3ba6090fSDavid van Moolenbroek 
613*3ba6090fSDavid van Moolenbroek 		exit(errct);
614*3ba6090fSDavid van Moolenbroek 	case -1:
615*3ba6090fSDavid van Moolenbroek 		e(0);
616*3ba6090fSDavid van Moolenbroek 
617*3ba6090fSDavid van Moolenbroek 		break;
618*3ba6090fSDavid van Moolenbroek 	default:
619*3ba6090fSDavid van Moolenbroek 		break;
620*3ba6090fSDavid van Moolenbroek 	}
621*3ba6090fSDavid van Moolenbroek 
622*3ba6090fSDavid van Moolenbroek 	usleep(SLEEP_TIME * 2);
623*3ba6090fSDavid van Moolenbroek 
624*3ba6090fSDavid van Moolenbroek 	if (kill(pid, SIGUSR1) != 0) e(0);
625*3ba6090fSDavid van Moolenbroek 
626*3ba6090fSDavid van Moolenbroek 	if (wait(&status) != pid) e(0);
627*3ba6090fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
628*3ba6090fSDavid van Moolenbroek 
629*3ba6090fSDavid van Moolenbroek 	/*
630*3ba6090fSDavid van Moolenbroek 	 * Repeat the same test with a non-full, non-empty buffer, to ensure
631*3ba6090fSDavid van Moolenbroek 	 * that interrupted reads do not return partial results.
632*3ba6090fSDavid van Moolenbroek 	 */
633*3ba6090fSDavid van Moolenbroek 	pid = fork();
634*3ba6090fSDavid van Moolenbroek 	switch (pid) {
635*3ba6090fSDavid van Moolenbroek 	case 0:
636*3ba6090fSDavid van Moolenbroek 		errct = 0;
637*3ba6090fSDavid van Moolenbroek 
638*3ba6090fSDavid van Moolenbroek 		signal(SIGUSR1, test94_signal);
639*3ba6090fSDavid van Moolenbroek 
640*3ba6090fSDavid van Moolenbroek 		if (read(fd, buf, size) != -1) e(0);
641*3ba6090fSDavid van Moolenbroek 		if (errno != EINTR) e(0);
642*3ba6090fSDavid van Moolenbroek 
643*3ba6090fSDavid van Moolenbroek 		if (got_signal != 1) e(0);
644*3ba6090fSDavid van Moolenbroek 
645*3ba6090fSDavid van Moolenbroek 		exit(errct);
646*3ba6090fSDavid van Moolenbroek 	case -1:
647*3ba6090fSDavid van Moolenbroek 		e(0);
648*3ba6090fSDavid van Moolenbroek 
649*3ba6090fSDavid van Moolenbroek 		break;
650*3ba6090fSDavid van Moolenbroek 	default:
651*3ba6090fSDavid van Moolenbroek 		break;
652*3ba6090fSDavid van Moolenbroek 	}
653*3ba6090fSDavid van Moolenbroek 
654*3ba6090fSDavid van Moolenbroek 	usleep(SLEEP_TIME);
655*3ba6090fSDavid van Moolenbroek 
656*3ba6090fSDavid van Moolenbroek 	test94_add_random(fd2, buf, size, 2);
657*3ba6090fSDavid van Moolenbroek 
658*3ba6090fSDavid van Moolenbroek 	usleep(SLEEP_TIME);
659*3ba6090fSDavid van Moolenbroek 
660*3ba6090fSDavid van Moolenbroek 	if (kill(pid, SIGUSR1) != 0) e(0);
661*3ba6090fSDavid van Moolenbroek 
662*3ba6090fSDavid van Moolenbroek 	if (wait(&status) != pid) e(0);
663*3ba6090fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
664*3ba6090fSDavid van Moolenbroek 
665*3ba6090fSDavid van Moolenbroek 	/*
666*3ba6090fSDavid van Moolenbroek 	 * Test non-blocking reads with empty, full, and non-empty buffers.
667*3ba6090fSDavid van Moolenbroek 	 * Against common sense, the last case should return whatever is in
668*3ba6090fSDavid van Moolenbroek 	 * the buffer rather than EAGAIN, like immediate-mode reads would.
669*3ba6090fSDavid van Moolenbroek 	 */
670*3ba6090fSDavid van Moolenbroek 	if ((fl = fcntl(fd, F_GETFL)) == -1) e(0);
671*3ba6090fSDavid van Moolenbroek 	if (fcntl(fd, F_SETFL, fl | O_NONBLOCK) != 0) e(0);
672*3ba6090fSDavid van Moolenbroek 
673*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
674*3ba6090fSDavid van Moolenbroek 	if (len <= 0) e(0);
675*3ba6090fSDavid van Moolenbroek 	if (len >= size * 3/4) e(0);	/* one packet < 3/4 of the size */
676*3ba6090fSDavid van Moolenbroek 	seq = test94_check(buf, len, 2 /*seq*/, 1 /*filtered*/,
677*3ba6090fSDavid van Moolenbroek 	    NULL /*caplen*/, NULL /*datalen*/);
678*3ba6090fSDavid van Moolenbroek 
679*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, size) != -1) e(0);
680*3ba6090fSDavid van Moolenbroek 	if (errno != EAGAIN) e(0);
681*3ba6090fSDavid van Moolenbroek 
682*3ba6090fSDavid van Moolenbroek 	test94_fill_random(fd2, buf, size);
683*3ba6090fSDavid van Moolenbroek 
684*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
685*3ba6090fSDavid van Moolenbroek 	if (len < size * 3/4) e(0);
686*3ba6090fSDavid van Moolenbroek 	if (len > size) e(0);
687*3ba6090fSDavid van Moolenbroek 	seq = test94_check(buf, len, 1 /*seq*/, 1 /*filtered*/,
688*3ba6090fSDavid van Moolenbroek 	    NULL /*caplen*/, NULL /*datalen*/);
689*3ba6090fSDavid van Moolenbroek 
690*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
691*3ba6090fSDavid van Moolenbroek 
692*3ba6090fSDavid van Moolenbroek 	if (len <= 0) e(0);
693*3ba6090fSDavid van Moolenbroek 	if (len >= size * 3/4) e(0);	/* one packet < 3/4 of the size */
694*3ba6090fSDavid van Moolenbroek 	if (test94_check(buf, len, seq, 1 /*filtered*/, NULL /*caplen*/,
695*3ba6090fSDavid van Moolenbroek 	    NULL /*datalen*/) != seq + 1) e(0);
696*3ba6090fSDavid van Moolenbroek 
697*3ba6090fSDavid van Moolenbroek 	if (fcntl(fd, F_SETFL, fl) != 0) e(0);
698*3ba6090fSDavid van Moolenbroek 
699*3ba6090fSDavid van Moolenbroek 	/*
700*3ba6090fSDavid van Moolenbroek 	 * Test two remaining aspects of select(2): single-packet arrivals do
701*3ba6090fSDavid van Moolenbroek 	 * not cause a wake-up, and the read timer has no effect.  The latter
702*3ba6090fSDavid van Moolenbroek 	 * is a deliberate implementation choice where we diverge from NetBSD,
703*3ba6090fSDavid van Moolenbroek 	 * because it requires keeping state in a way that violates the
704*3ba6090fSDavid van Moolenbroek 	 * principle of system call independence.
705*3ba6090fSDavid van Moolenbroek 	 */
706*3ba6090fSDavid van Moolenbroek 	tv.tv_sec = 0;
707*3ba6090fSDavid van Moolenbroek 	tv.tv_usec = SLEEP_TIME * 2;
708*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSRTIMEOUT, &tv) != 0) e(0);
709*3ba6090fSDavid van Moolenbroek 
710*3ba6090fSDavid van Moolenbroek 	pid = fork();
711*3ba6090fSDavid van Moolenbroek 	switch (pid) {
712*3ba6090fSDavid van Moolenbroek 	case 0:
713*3ba6090fSDavid van Moolenbroek 		errct = 0;
714*3ba6090fSDavid van Moolenbroek 
715*3ba6090fSDavid van Moolenbroek 		usleep(SLEEP_TIME);
716*3ba6090fSDavid van Moolenbroek 
717*3ba6090fSDavid van Moolenbroek 		test94_add_random(fd2, buf, size, 1);
718*3ba6090fSDavid van Moolenbroek 
719*3ba6090fSDavid van Moolenbroek 		exit(errct);
720*3ba6090fSDavid van Moolenbroek 	case -1:
721*3ba6090fSDavid van Moolenbroek 		e(0);
722*3ba6090fSDavid van Moolenbroek 
723*3ba6090fSDavid van Moolenbroek 		break;
724*3ba6090fSDavid van Moolenbroek 	default:
725*3ba6090fSDavid van Moolenbroek 		break;
726*3ba6090fSDavid van Moolenbroek 	}
727*3ba6090fSDavid van Moolenbroek 
728*3ba6090fSDavid van Moolenbroek 	tv.tv_sec = 1;
729*3ba6090fSDavid van Moolenbroek 	tv.tv_usec = 0;
730*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&fds);
731*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &fds);
732*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, &tv) != 0) e(0);
733*3ba6090fSDavid van Moolenbroek 
734*3ba6090fSDavid van Moolenbroek 	if (wait(&status) != pid) e(0);
735*3ba6090fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
736*3ba6090fSDavid van Moolenbroek 
737*3ba6090fSDavid van Moolenbroek 	test94_cleanup(fd, fd2, fd3, buf);
738*3ba6090fSDavid van Moolenbroek }
739*3ba6090fSDavid van Moolenbroek 
740*3ba6090fSDavid van Moolenbroek /*
741*3ba6090fSDavid van Moolenbroek  * Test reading packets from a BPF device, using immediate mode.
742*3ba6090fSDavid van Moolenbroek  */
743*3ba6090fSDavid van Moolenbroek static void
test94b(void)744*3ba6090fSDavid van Moolenbroek test94b(void)
745*3ba6090fSDavid van Moolenbroek {
746*3ba6090fSDavid van Moolenbroek 	struct timeval tv;
747*3ba6090fSDavid van Moolenbroek 	fd_set fds;
748*3ba6090fSDavid van Moolenbroek 	uint8_t *buf;
749*3ba6090fSDavid van Moolenbroek 	unsigned int val;
750*3ba6090fSDavid van Moolenbroek 	size_t size;
751*3ba6090fSDavid van Moolenbroek 	ssize_t len;
752*3ba6090fSDavid van Moolenbroek 	uint32_t seq;
753*3ba6090fSDavid van Moolenbroek 	pid_t pid;
754*3ba6090fSDavid van Moolenbroek 	int fd, fd2, fd3, bytes, status, fl;
755*3ba6090fSDavid van Moolenbroek 
756*3ba6090fSDavid van Moolenbroek 	subtest = 2;
757*3ba6090fSDavid van Moolenbroek 
758*3ba6090fSDavid van Moolenbroek 	size = test94_setup(&fd, &fd2, &fd3, &buf, 0 /*size*/,
759*3ba6090fSDavid van Moolenbroek 	    1 /*set_filter*/);
760*3ba6090fSDavid van Moolenbroek 
761*3ba6090fSDavid van Moolenbroek 	val = 1;
762*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCIMMEDIATE, &val) != 0) e(0);
763*3ba6090fSDavid van Moolenbroek 
764*3ba6090fSDavid van Moolenbroek 	tv.tv_sec = 0;
765*3ba6090fSDavid van Moolenbroek 	tv.tv_usec = 0;
766*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&fds);
767*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &fds);
768*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, &tv) != 0) e(0);
769*3ba6090fSDavid van Moolenbroek 
770*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, FIONREAD, &bytes) != 0) e(0);
771*3ba6090fSDavid van Moolenbroek 	if (bytes != 0) e(0);
772*3ba6090fSDavid van Moolenbroek 
773*3ba6090fSDavid van Moolenbroek 	/*
774*3ba6090fSDavid van Moolenbroek 	 * Ensure that if the hold buffer is full, an immediate-mode read
775*3ba6090fSDavid van Moolenbroek 	 * returns the content of the hold buffer, even if the store buffer is
776*3ba6090fSDavid van Moolenbroek 	 * not empty.
777*3ba6090fSDavid van Moolenbroek 	 */
778*3ba6090fSDavid van Moolenbroek 	test94_fill_random(fd2, buf, size);
779*3ba6090fSDavid van Moolenbroek 
780*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&fds);
781*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &fds);
782*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, &tv) != 1) e(0);
783*3ba6090fSDavid van Moolenbroek 	if (!FD_ISSET(fd, &fds)) e(0);
784*3ba6090fSDavid van Moolenbroek 
785*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, FIONREAD, &bytes) != 0) e(0);
786*3ba6090fSDavid van Moolenbroek 
787*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
788*3ba6090fSDavid van Moolenbroek 	if (len < size * 3/4) e(0);
789*3ba6090fSDavid van Moolenbroek 	if (len > size) e(0);
790*3ba6090fSDavid van Moolenbroek 	seq = test94_check(buf, len, 1 /*seq*/, 1 /*filtered*/,
791*3ba6090fSDavid van Moolenbroek 	    NULL /*caplen*/, NULL /*datalen*/);
792*3ba6090fSDavid van Moolenbroek 
793*3ba6090fSDavid van Moolenbroek 	if (len != bytes) e(0);
794*3ba6090fSDavid van Moolenbroek 
795*3ba6090fSDavid van Moolenbroek 	/*
796*3ba6090fSDavid van Moolenbroek 	 * There is one packet left in the buffer.  In immediate mode, this
797*3ba6090fSDavid van Moolenbroek 	 * packet should be returned immediately.
798*3ba6090fSDavid van Moolenbroek 	 */
799*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&fds);
800*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &fds);
801*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, &tv) != 1) e(0);
802*3ba6090fSDavid van Moolenbroek 	if (!FD_ISSET(fd, &fds)) e(0);
803*3ba6090fSDavid van Moolenbroek 
804*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, FIONREAD, &bytes) != 0) e(0);
805*3ba6090fSDavid van Moolenbroek 
806*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
807*3ba6090fSDavid van Moolenbroek 	if (len <= 0) e(0);
808*3ba6090fSDavid van Moolenbroek 	if (len >= size * 3/4) e(0);	/* one packet < 3/4 of the size */
809*3ba6090fSDavid van Moolenbroek 	if (test94_check(buf, len, seq, 1 /*filtered*/, NULL /*caplen*/,
810*3ba6090fSDavid van Moolenbroek 	    NULL /*datalen*/) != seq + 1) e(0);
811*3ba6090fSDavid van Moolenbroek 
812*3ba6090fSDavid van Moolenbroek 	if (len != bytes) e(0);
813*3ba6090fSDavid van Moolenbroek 
814*3ba6090fSDavid van Moolenbroek 	/* The buffer is now empty again. */
815*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&fds);
816*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &fds);
817*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, &tv) != 0) e(0);
818*3ba6090fSDavid van Moolenbroek 
819*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, FIONREAD, &bytes) != 0) e(0);
820*3ba6090fSDavid van Moolenbroek 	if (bytes != 0) e(0);
821*3ba6090fSDavid van Moolenbroek 
822*3ba6090fSDavid van Moolenbroek 	/*
823*3ba6090fSDavid van Moolenbroek 	 * Immediate-mode reads may return multiple packets from the store
824*3ba6090fSDavid van Moolenbroek 	 * buffer.
825*3ba6090fSDavid van Moolenbroek 	 */
826*3ba6090fSDavid van Moolenbroek 	test94_add_random(fd2, buf, size, seq + 1);
827*3ba6090fSDavid van Moolenbroek 	test94_add_random(fd2, buf, size, seq + 2);
828*3ba6090fSDavid van Moolenbroek 
829*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&fds);
830*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &fds);
831*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, &tv) != 1) e(0);
832*3ba6090fSDavid van Moolenbroek 	if (!FD_ISSET(fd, &fds)) e(0);
833*3ba6090fSDavid van Moolenbroek 
834*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, FIONREAD, &bytes) != 0) e(0);
835*3ba6090fSDavid van Moolenbroek 
836*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
837*3ba6090fSDavid van Moolenbroek 	if (len <= 0) e(0);
838*3ba6090fSDavid van Moolenbroek 	if (len >= size * 3/4) e(0);	/* two packets < 3/4 of the size */
839*3ba6090fSDavid van Moolenbroek 	if (test94_check(buf, len, seq + 1, 1 /*filtered*/, NULL /*caplen*/,
840*3ba6090fSDavid van Moolenbroek 	    NULL /*datalen*/) != seq + 3) e(0);
841*3ba6090fSDavid van Moolenbroek 
842*3ba6090fSDavid van Moolenbroek 	if (len != bytes) e(0);
843*3ba6090fSDavid van Moolenbroek 
844*3ba6090fSDavid van Moolenbroek 	/*
845*3ba6090fSDavid van Moolenbroek 	 * Now test waking up suspended calls, read(2) first.
846*3ba6090fSDavid van Moolenbroek 	 */
847*3ba6090fSDavid van Moolenbroek 	pid = fork();
848*3ba6090fSDavid van Moolenbroek 	switch (pid) {
849*3ba6090fSDavid van Moolenbroek 	case 0:
850*3ba6090fSDavid van Moolenbroek 		errct = 0;
851*3ba6090fSDavid van Moolenbroek 
852*3ba6090fSDavid van Moolenbroek 		usleep(SLEEP_TIME);
853*3ba6090fSDavid van Moolenbroek 
854*3ba6090fSDavid van Moolenbroek 		test94_add_random(fd2, buf, size, seq + 3);
855*3ba6090fSDavid van Moolenbroek 
856*3ba6090fSDavid van Moolenbroek 		exit(errct);
857*3ba6090fSDavid van Moolenbroek 	case -1:
858*3ba6090fSDavid van Moolenbroek 		e(0);
859*3ba6090fSDavid van Moolenbroek 
860*3ba6090fSDavid van Moolenbroek 		break;
861*3ba6090fSDavid van Moolenbroek 	default:
862*3ba6090fSDavid van Moolenbroek 		break;
863*3ba6090fSDavid van Moolenbroek 	}
864*3ba6090fSDavid van Moolenbroek 
865*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
866*3ba6090fSDavid van Moolenbroek 	if (len <= 0) e(0);
867*3ba6090fSDavid van Moolenbroek 	if (len >= size * 3/4) e(0);	/* one packet < 3/4 of the size */
868*3ba6090fSDavid van Moolenbroek 	if (test94_check(buf, len, seq + 3, 1 /*filtered*/, NULL /*caplen*/,
869*3ba6090fSDavid van Moolenbroek 	    NULL /*datalen*/) != seq + 4) e(0);
870*3ba6090fSDavid van Moolenbroek 
871*3ba6090fSDavid van Moolenbroek 	if (wait(&status) != pid) e(0);
872*3ba6090fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
873*3ba6090fSDavid van Moolenbroek 
874*3ba6090fSDavid van Moolenbroek 	/*
875*3ba6090fSDavid van Moolenbroek 	 * Then select(2).
876*3ba6090fSDavid van Moolenbroek 	 */
877*3ba6090fSDavid van Moolenbroek 	pid = fork();
878*3ba6090fSDavid van Moolenbroek 	switch (pid) {
879*3ba6090fSDavid van Moolenbroek 	case 0:
880*3ba6090fSDavid van Moolenbroek 		errct = 0;
881*3ba6090fSDavid van Moolenbroek 
882*3ba6090fSDavid van Moolenbroek 		usleep(SLEEP_TIME);
883*3ba6090fSDavid van Moolenbroek 
884*3ba6090fSDavid van Moolenbroek 		test94_add_random(fd2, buf, size, seq + 4);
885*3ba6090fSDavid van Moolenbroek 
886*3ba6090fSDavid van Moolenbroek 		exit(errct);
887*3ba6090fSDavid van Moolenbroek 	case -1:
888*3ba6090fSDavid van Moolenbroek 		e(0);
889*3ba6090fSDavid van Moolenbroek 
890*3ba6090fSDavid van Moolenbroek 		break;
891*3ba6090fSDavid van Moolenbroek 	default:
892*3ba6090fSDavid van Moolenbroek 		break;
893*3ba6090fSDavid van Moolenbroek 	}
894*3ba6090fSDavid van Moolenbroek 
895*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&fds);
896*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &fds);
897*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, NULL) != 1) e(0);
898*3ba6090fSDavid van Moolenbroek 	if (!FD_ISSET(fd, &fds)) e(0);
899*3ba6090fSDavid van Moolenbroek 
900*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, FIONREAD, &bytes) != 0) e(0);
901*3ba6090fSDavid van Moolenbroek 
902*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, NULL) != 1) e(0);
903*3ba6090fSDavid van Moolenbroek 	if (!FD_ISSET(fd, &fds)) e(0);
904*3ba6090fSDavid van Moolenbroek 
905*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
906*3ba6090fSDavid van Moolenbroek 	if (len <= 0) e(0);
907*3ba6090fSDavid van Moolenbroek 	if (len >= size * 3/4) e(0);	/* one packet < 3/4 of the size */
908*3ba6090fSDavid van Moolenbroek 	if (test94_check(buf, len, seq + 4, 1 /*filtered*/, NULL /*caplen*/,
909*3ba6090fSDavid van Moolenbroek 	    NULL /*datalen*/) != seq + 5) e(0);
910*3ba6090fSDavid van Moolenbroek 
911*3ba6090fSDavid van Moolenbroek 	if (len != bytes) e(0);
912*3ba6090fSDavid van Moolenbroek 
913*3ba6090fSDavid van Moolenbroek 	if (wait(&status) != pid) e(0);
914*3ba6090fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
915*3ba6090fSDavid van Moolenbroek 
916*3ba6090fSDavid van Moolenbroek 	/*
917*3ba6090fSDavid van Moolenbroek 	 * Non-blocking reads should behave just as with regular mode.
918*3ba6090fSDavid van Moolenbroek 	 */
919*3ba6090fSDavid van Moolenbroek 	if ((fl = fcntl(fd, F_GETFL)) == -1) e(0);
920*3ba6090fSDavid van Moolenbroek 	if (fcntl(fd, F_SETFL, fl | O_NONBLOCK) != 0) e(0);
921*3ba6090fSDavid van Moolenbroek 
922*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, size) != -1) e(0);
923*3ba6090fSDavid van Moolenbroek 	if (errno != EAGAIN) e(0);
924*3ba6090fSDavid van Moolenbroek 
925*3ba6090fSDavid van Moolenbroek 	test94_fill_random(fd2, buf, size);
926*3ba6090fSDavid van Moolenbroek 
927*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
928*3ba6090fSDavid van Moolenbroek 	if (len < size * 3/4) e(0);
929*3ba6090fSDavid van Moolenbroek 	if (len > size) e(0);
930*3ba6090fSDavid van Moolenbroek 	seq = test94_check(buf, len, 1 /*seq*/, 1 /*filtered*/,
931*3ba6090fSDavid van Moolenbroek 	    NULL /*caplen*/, NULL /*datalen*/);
932*3ba6090fSDavid van Moolenbroek 
933*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
934*3ba6090fSDavid van Moolenbroek 	if (len <= 0) e(0);
935*3ba6090fSDavid van Moolenbroek 	if (len >= size * 3/4) e(0);	/* one packet < 3/4 of the size */
936*3ba6090fSDavid van Moolenbroek 	if (test94_check(buf, len, seq, 1 /*filtered*/, NULL /*caplen*/,
937*3ba6090fSDavid van Moolenbroek 	    NULL /*datalen*/) != seq + 1) e(0);
938*3ba6090fSDavid van Moolenbroek 
939*3ba6090fSDavid van Moolenbroek 	if (fcntl(fd, F_SETFL, fl) != 0) e(0);
940*3ba6090fSDavid van Moolenbroek 
941*3ba6090fSDavid van Moolenbroek 	/*
942*3ba6090fSDavid van Moolenbroek 	 * Timeouts should work with immediate mode.
943*3ba6090fSDavid van Moolenbroek 	 */
944*3ba6090fSDavid van Moolenbroek 	tv.tv_sec = 0;
945*3ba6090fSDavid van Moolenbroek 	tv.tv_usec = SLEEP_TIME;
946*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSRTIMEOUT, &tv) != 0) e(0);
947*3ba6090fSDavid van Moolenbroek 
948*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, size) != -1) e(0);
949*3ba6090fSDavid van Moolenbroek 	if (errno != EAGAIN) e(0);
950*3ba6090fSDavid van Moolenbroek 
951*3ba6090fSDavid van Moolenbroek 	test94_cleanup(fd, fd2, fd3, buf);
952*3ba6090fSDavid van Moolenbroek }
953*3ba6090fSDavid van Moolenbroek 
954*3ba6090fSDavid van Moolenbroek /*
955*3ba6090fSDavid van Moolenbroek  * Test reading packets from a BPF device, with an exactly filled buffer.  The
956*3ba6090fSDavid van Moolenbroek  * idea is that normally the store buffer is considered "full" if the next
957*3ba6090fSDavid van Moolenbroek  * packet does not fit in it, but if no more bytes are left in it, it can be
958*3ba6090fSDavid van Moolenbroek  * rotated immediately.  This is a practically useless edge case, but we
959*3ba6090fSDavid van Moolenbroek  * support it, so we might as well test it.  Also, some of the code for this
960*3ba6090fSDavid van Moolenbroek  * case is shared with other rare cases that we cannot test here (interfaces
961*3ba6090fSDavid van Moolenbroek  * disappearing, to be specific), and exactly filling up the buffers does test
962*3ba6090fSDavid van Moolenbroek  * some other bounds checks so all that might make this worth it anyway.  While
963*3ba6090fSDavid van Moolenbroek  * we are exercising full control over our buffers, also check statistics.
964*3ba6090fSDavid van Moolenbroek  */
965*3ba6090fSDavid van Moolenbroek static void
test94c(void)966*3ba6090fSDavid van Moolenbroek test94c(void)
967*3ba6090fSDavid van Moolenbroek {
968*3ba6090fSDavid van Moolenbroek 	struct bpf_stat bs;
969*3ba6090fSDavid van Moolenbroek 	fd_set fds;
970*3ba6090fSDavid van Moolenbroek 	uint8_t *buf;
971*3ba6090fSDavid van Moolenbroek 	size_t size;
972*3ba6090fSDavid van Moolenbroek 	pid_t pid;
973*3ba6090fSDavid van Moolenbroek 	uint32_t count, seq;
974*3ba6090fSDavid van Moolenbroek 	int fd, fd2, fd3, bytes, status, fl;
975*3ba6090fSDavid van Moolenbroek 
976*3ba6090fSDavid van Moolenbroek 	subtest = 3;
977*3ba6090fSDavid van Moolenbroek 
978*3ba6090fSDavid van Moolenbroek 	size = test94_setup(&fd, &fd2, &fd3, &buf, 0 /*size*/,
979*3ba6090fSDavid van Moolenbroek 	    1 /*set_filter*/);
980*3ba6090fSDavid van Moolenbroek 
981*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCGSTATS, &bs) != 0) e(0);
982*3ba6090fSDavid van Moolenbroek 	if (bs.bs_capt != 0) e(0);
983*3ba6090fSDavid van Moolenbroek 	if (bs.bs_drop != 0) e(0);
984*3ba6090fSDavid van Moolenbroek 
985*3ba6090fSDavid van Moolenbroek 	/*
986*3ba6090fSDavid van Moolenbroek 	 * Test read, select, and ioctl(FIONREAD) on an exactly filled buffer.
987*3ba6090fSDavid van Moolenbroek 	 */
988*3ba6090fSDavid van Moolenbroek 	count = test94_fill_exact(fd2, buf, size, 0);
989*3ba6090fSDavid van Moolenbroek 
990*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCGSTATS, &bs) != 0) e(0);
991*3ba6090fSDavid van Moolenbroek 	if (bs.bs_capt != count) e(0);
992*3ba6090fSDavid van Moolenbroek 	if (bs.bs_recv < bs.bs_capt) e(0); /* may be more */
993*3ba6090fSDavid van Moolenbroek 	if (bs.bs_drop != 0) e(0);
994*3ba6090fSDavid van Moolenbroek 
995*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, FIONREAD, &bytes) != 0) e(0);
996*3ba6090fSDavid van Moolenbroek 	if (bytes != size) e(0);
997*3ba6090fSDavid van Moolenbroek 
998*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&fds);
999*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &fds);
1000*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, NULL) != 1) e(0);
1001*3ba6090fSDavid van Moolenbroek 	if (!FD_ISSET(fd, &fds)) e(0);
1002*3ba6090fSDavid van Moolenbroek 
1003*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, size) != size) e(0);
1004*3ba6090fSDavid van Moolenbroek 	test94_check(buf, size, 0 /*seq*/, 1 /*filtered*/, NULL /*caplen*/,
1005*3ba6090fSDavid van Moolenbroek 	    NULL /*datalen*/);
1006*3ba6090fSDavid van Moolenbroek 
1007*3ba6090fSDavid van Moolenbroek 	/*
1008*3ba6090fSDavid van Moolenbroek 	 * If the store buffer is full, the buffers should be swapped after
1009*3ba6090fSDavid van Moolenbroek 	 * emptying the hold buffer.
1010*3ba6090fSDavid van Moolenbroek 	 */
1011*3ba6090fSDavid van Moolenbroek 	seq = test94_fill_exact(fd2, buf, size, 1);
1012*3ba6090fSDavid van Moolenbroek 	test94_fill_exact(fd2, buf, size, seq);
1013*3ba6090fSDavid van Moolenbroek 
1014*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCGSTATS, &bs) != 0) e(0);
1015*3ba6090fSDavid van Moolenbroek 	if (bs.bs_capt != count * 3) e(0);
1016*3ba6090fSDavid van Moolenbroek 	if (bs.bs_recv < bs.bs_capt) e(0); /* may be more */
1017*3ba6090fSDavid van Moolenbroek 	if (bs.bs_drop != 0) e(0);
1018*3ba6090fSDavid van Moolenbroek 
1019*3ba6090fSDavid van Moolenbroek 	test94_add_random(fd2, buf, size, 0); /* this one will get dropped */
1020*3ba6090fSDavid van Moolenbroek 
1021*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCGSTATS, &bs) != 0) e(0);
1022*3ba6090fSDavid van Moolenbroek 	if (bs.bs_capt != count * 3 + 1) e(0);
1023*3ba6090fSDavid van Moolenbroek 	if (bs.bs_recv < bs.bs_capt) e(0); /* may be more */
1024*3ba6090fSDavid van Moolenbroek 	if (bs.bs_drop != 1) e(0);
1025*3ba6090fSDavid van Moolenbroek 
1026*3ba6090fSDavid van Moolenbroek 	test94_add_random(fd2, buf, size, 0); /* this one will get dropped */
1027*3ba6090fSDavid van Moolenbroek 
1028*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCGSTATS, &bs) != 0) e(0);
1029*3ba6090fSDavid van Moolenbroek 	if (bs.bs_capt != count * 3 + 2) e(0);
1030*3ba6090fSDavid van Moolenbroek 	if (bs.bs_recv < bs.bs_capt) e(0); /* may be more */
1031*3ba6090fSDavid van Moolenbroek 	if (bs.bs_drop != 2) e(0);
1032*3ba6090fSDavid van Moolenbroek 
1033*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, FIONREAD, &bytes) != 0) e(0);
1034*3ba6090fSDavid van Moolenbroek 	if (bytes != size) e(0);
1035*3ba6090fSDavid van Moolenbroek 
1036*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, size) != size) e(0);
1037*3ba6090fSDavid van Moolenbroek 	if (test94_check(buf, size, 1 /*seq*/, 1 /*filtered*/, NULL /*caplen*/,
1038*3ba6090fSDavid van Moolenbroek 	    NULL /*datalen*/) != seq) e(0);
1039*3ba6090fSDavid van Moolenbroek 
1040*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, size) != size) e(0);
1041*3ba6090fSDavid van Moolenbroek 	if (test94_check(buf, size, seq, 1 /*filtered*/, NULL /*caplen*/,
1042*3ba6090fSDavid van Moolenbroek 	    NULL /*datalen*/) != count * 2 + 1) e(0);
1043*3ba6090fSDavid van Moolenbroek 
1044*3ba6090fSDavid van Moolenbroek 	/*
1045*3ba6090fSDavid van Moolenbroek 	 * See if an exactly filled buffer resumes reads...
1046*3ba6090fSDavid van Moolenbroek 	 */
1047*3ba6090fSDavid van Moolenbroek 	pid = fork();
1048*3ba6090fSDavid van Moolenbroek 	switch (pid) {
1049*3ba6090fSDavid van Moolenbroek 	case 0:
1050*3ba6090fSDavid van Moolenbroek 		errct = 0;
1051*3ba6090fSDavid van Moolenbroek 
1052*3ba6090fSDavid van Moolenbroek 		usleep(SLEEP_TIME);
1053*3ba6090fSDavid van Moolenbroek 
1054*3ba6090fSDavid van Moolenbroek 		test94_fill_exact(fd2, buf, size, 1);
1055*3ba6090fSDavid van Moolenbroek 
1056*3ba6090fSDavid van Moolenbroek 		exit(errct);
1057*3ba6090fSDavid van Moolenbroek 	case -1:
1058*3ba6090fSDavid van Moolenbroek 		e(0);
1059*3ba6090fSDavid van Moolenbroek 
1060*3ba6090fSDavid van Moolenbroek 		break;
1061*3ba6090fSDavid van Moolenbroek 	default:
1062*3ba6090fSDavid van Moolenbroek 		break;
1063*3ba6090fSDavid van Moolenbroek 	}
1064*3ba6090fSDavid van Moolenbroek 
1065*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, size) != size) e(0);
1066*3ba6090fSDavid van Moolenbroek 	test94_check(buf, size, 1 /*seq*/, 1 /*filtered*/, NULL /*caplen*/,
1067*3ba6090fSDavid van Moolenbroek 	    NULL /*datalen*/);
1068*3ba6090fSDavid van Moolenbroek 
1069*3ba6090fSDavid van Moolenbroek 	if (wait(&status) != pid) e(0);
1070*3ba6090fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
1071*3ba6090fSDavid van Moolenbroek 
1072*3ba6090fSDavid van Moolenbroek 	/*
1073*3ba6090fSDavid van Moolenbroek 	 * ...and selects.
1074*3ba6090fSDavid van Moolenbroek 	 */
1075*3ba6090fSDavid van Moolenbroek 	pid = fork();
1076*3ba6090fSDavid van Moolenbroek 	switch (pid) {
1077*3ba6090fSDavid van Moolenbroek 	case 0:
1078*3ba6090fSDavid van Moolenbroek 		errct = 0;
1079*3ba6090fSDavid van Moolenbroek 
1080*3ba6090fSDavid van Moolenbroek 		usleep(SLEEP_TIME);
1081*3ba6090fSDavid van Moolenbroek 
1082*3ba6090fSDavid van Moolenbroek 		test94_fill_exact(fd2, buf, size, seq);
1083*3ba6090fSDavid van Moolenbroek 
1084*3ba6090fSDavid van Moolenbroek 		exit(errct);
1085*3ba6090fSDavid van Moolenbroek 	case -1:
1086*3ba6090fSDavid van Moolenbroek 		e(0);
1087*3ba6090fSDavid van Moolenbroek 
1088*3ba6090fSDavid van Moolenbroek 		break;
1089*3ba6090fSDavid van Moolenbroek 	default:
1090*3ba6090fSDavid van Moolenbroek 		break;
1091*3ba6090fSDavid van Moolenbroek 	}
1092*3ba6090fSDavid van Moolenbroek 
1093*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&fds);
1094*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &fds);
1095*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, NULL) != 1) e(0);
1096*3ba6090fSDavid van Moolenbroek 	if (!FD_ISSET(fd, &fds)) e(0);
1097*3ba6090fSDavid van Moolenbroek 
1098*3ba6090fSDavid van Moolenbroek 	if ((fl = fcntl(fd, F_GETFL)) == -1) e(0);
1099*3ba6090fSDavid van Moolenbroek 	if (fcntl(fd, F_SETFL, fl | O_NONBLOCK) != 0) e(0);
1100*3ba6090fSDavid van Moolenbroek 
1101*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, size) != size) e(0);
1102*3ba6090fSDavid van Moolenbroek 	test94_check(buf, size, seq, 1 /*filtered*/, NULL /*caplen*/,
1103*3ba6090fSDavid van Moolenbroek 	    NULL /*datalen*/);
1104*3ba6090fSDavid van Moolenbroek 
1105*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, size) != -1) e(0);
1106*3ba6090fSDavid van Moolenbroek 	if (errno != EAGAIN) e(0);
1107*3ba6090fSDavid van Moolenbroek 
1108*3ba6090fSDavid van Moolenbroek 	if (wait(&status) != pid) e(0);
1109*3ba6090fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
1110*3ba6090fSDavid van Moolenbroek 
1111*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCGSTATS, &bs) != 0) e(0);
1112*3ba6090fSDavid van Moolenbroek 	if (bs.bs_capt != count * 5 + 2) e(0);
1113*3ba6090fSDavid van Moolenbroek 	if (bs.bs_recv < bs.bs_capt) e(0); /* may be more */
1114*3ba6090fSDavid van Moolenbroek 	if (bs.bs_drop != 2) e(0);
1115*3ba6090fSDavid van Moolenbroek 
1116*3ba6090fSDavid van Moolenbroek 	test94_cleanup(fd, fd2, fd3, buf);
1117*3ba6090fSDavid van Moolenbroek }
1118*3ba6090fSDavid van Moolenbroek 
1119*3ba6090fSDavid van Moolenbroek /*
1120*3ba6090fSDavid van Moolenbroek  * Test receipt of large packets on BPF devices.  Large packets should be
1121*3ba6090fSDavid van Moolenbroek  * truncated to the size of the buffer, but unless the filter specifies a
1122*3ba6090fSDavid van Moolenbroek  * smaller capture size, no more than that.
1123*3ba6090fSDavid van Moolenbroek  */
1124*3ba6090fSDavid van Moolenbroek static void
test94d(void)1125*3ba6090fSDavid van Moolenbroek test94d(void)
1126*3ba6090fSDavid van Moolenbroek {
1127*3ba6090fSDavid van Moolenbroek 	struct bpf_hdr bh;
1128*3ba6090fSDavid van Moolenbroek 	uint8_t *buf, *buf2;
1129*3ba6090fSDavid van Moolenbroek 	size_t size;
1130*3ba6090fSDavid van Moolenbroek 	ssize_t len;
1131*3ba6090fSDavid van Moolenbroek 	int fd, fd2, fd3, datalen;
1132*3ba6090fSDavid van Moolenbroek 
1133*3ba6090fSDavid van Moolenbroek 	subtest = 4;
1134*3ba6090fSDavid van Moolenbroek 
1135*3ba6090fSDavid van Moolenbroek 	/*
1136*3ba6090fSDavid van Moolenbroek 	 * Specify a size smaller than the largest packet we can send on the
1137*3ba6090fSDavid van Moolenbroek 	 * loopback device.  The size we specify here is currently the default
1138*3ba6090fSDavid van Moolenbroek 	 * size already anyway, but that might change in the future.
1139*3ba6090fSDavid van Moolenbroek 	 */
1140*3ba6090fSDavid van Moolenbroek 	size = test94_setup(&fd, &fd2, &fd3, &buf, 32768 /*size*/,
1141*3ba6090fSDavid van Moolenbroek 	    1 /*set_filter*/);
1142*3ba6090fSDavid van Moolenbroek 	if (size != 32768) e(0);
1143*3ba6090fSDavid van Moolenbroek 
1144*3ba6090fSDavid van Moolenbroek 	datalen = 65000;
1145*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, SOL_SOCKET, SO_SNDBUF, &datalen,
1146*3ba6090fSDavid van Moolenbroek 	    sizeof(datalen)) != 0) e(0);
1147*3ba6090fSDavid van Moolenbroek 
1148*3ba6090fSDavid van Moolenbroek 	if ((buf2 = malloc(datalen)) == NULL) e(0);
1149*3ba6090fSDavid van Moolenbroek 
1150*3ba6090fSDavid van Moolenbroek 	memset(buf2, 'Y', datalen);
1151*3ba6090fSDavid van Moolenbroek 	buf2[0] = 'X';
1152*3ba6090fSDavid van Moolenbroek 	buf2[size - sizeof(struct udphdr) - sizeof(struct ip) -
1153*3ba6090fSDavid van Moolenbroek 	    BPF_WORDALIGN(sizeof(bh)) - 1] = 'Z';
1154*3ba6090fSDavid van Moolenbroek 
1155*3ba6090fSDavid van Moolenbroek 	if (write(fd2, buf2, datalen) != datalen) e(0);
1156*3ba6090fSDavid van Moolenbroek 
1157*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, size) != size) e(0);
1158*3ba6090fSDavid van Moolenbroek 
1159*3ba6090fSDavid van Moolenbroek 	memcpy(&bh, buf, sizeof(bh));
1160*3ba6090fSDavid van Moolenbroek 
1161*3ba6090fSDavid van Moolenbroek 	if (bh.bh_hdrlen != BPF_WORDALIGN(sizeof(bh))) e(0);
1162*3ba6090fSDavid van Moolenbroek 	if (bh.bh_caplen != size - BPF_WORDALIGN(sizeof(bh))) e(0);
1163*3ba6090fSDavid van Moolenbroek 	if (bh.bh_datalen !=
1164*3ba6090fSDavid van Moolenbroek 	    sizeof(struct ip) + sizeof(struct udphdr) + datalen) e(0);
1165*3ba6090fSDavid van Moolenbroek 
1166*3ba6090fSDavid van Moolenbroek 	if (buf[BPF_WORDALIGN(sizeof(bh)) + sizeof(struct ip) +
1167*3ba6090fSDavid van Moolenbroek 	    sizeof(struct udphdr)] != 'X') e(0);
1168*3ba6090fSDavid van Moolenbroek 	if (buf[size - 2] != 'Y') e(0);
1169*3ba6090fSDavid van Moolenbroek 	if (buf[size - 1] != 'Z') e(0);
1170*3ba6090fSDavid van Moolenbroek 
1171*3ba6090fSDavid van Moolenbroek 	/*
1172*3ba6090fSDavid van Moolenbroek 	 * Add a smaller packet in between, to ensure that 1) the large packet
1173*3ba6090fSDavid van Moolenbroek 	 * is not split across buffers, and 2) the packet is truncated to the
1174*3ba6090fSDavid van Moolenbroek 	 * size of the buffer, not the available part of the buffer.  Note how
1175*3ba6090fSDavid van Moolenbroek 	 * forced rotation and our exact-fill policy preclude us from having to
1176*3ba6090fSDavid van Moolenbroek 	 * use immediate mode for any of this.
1177*3ba6090fSDavid van Moolenbroek 	 */
1178*3ba6090fSDavid van Moolenbroek 	test94_add_random(fd2, buf, size, 1 /*seq*/);
1179*3ba6090fSDavid van Moolenbroek 
1180*3ba6090fSDavid van Moolenbroek 	if (write(fd2, buf2, datalen) != datalen) e(0);
1181*3ba6090fSDavid van Moolenbroek 
1182*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
1183*3ba6090fSDavid van Moolenbroek 	if (len <= 0) e(0);
1184*3ba6090fSDavid van Moolenbroek 	if (len >= size * 3/4) e(0);	/* one packet < 3/4 of the size */
1185*3ba6090fSDavid van Moolenbroek 	if (test94_check(buf, len, 1 /*seq*/, 1 /*filtered*/, NULL /*caplen*/,
1186*3ba6090fSDavid van Moolenbroek 	    NULL /*datalen*/) != 2) e(0);
1187*3ba6090fSDavid van Moolenbroek 
1188*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, size) != size) e(0);
1189*3ba6090fSDavid van Moolenbroek 
1190*3ba6090fSDavid van Moolenbroek 	memcpy(&bh, buf, sizeof(bh));
1191*3ba6090fSDavid van Moolenbroek 
1192*3ba6090fSDavid van Moolenbroek 	if (bh.bh_hdrlen != BPF_WORDALIGN(sizeof(bh))) e(0);
1193*3ba6090fSDavid van Moolenbroek 	if (bh.bh_caplen != size - BPF_WORDALIGN(sizeof(bh))) e(0);
1194*3ba6090fSDavid van Moolenbroek 	if (bh.bh_datalen !=
1195*3ba6090fSDavid van Moolenbroek 	    sizeof(struct ip) + sizeof(struct udphdr) + datalen) e(0);
1196*3ba6090fSDavid van Moolenbroek 
1197*3ba6090fSDavid van Moolenbroek 	if (buf[BPF_WORDALIGN(sizeof(bh)) + sizeof(struct ip) +
1198*3ba6090fSDavid van Moolenbroek 	    sizeof(struct udphdr)] != 'X') e(0);
1199*3ba6090fSDavid van Moolenbroek 	if (buf[size - 2] != 'Y') e(0);
1200*3ba6090fSDavid van Moolenbroek 	if (buf[size - 1] != 'Z') e(0);
1201*3ba6090fSDavid van Moolenbroek 
1202*3ba6090fSDavid van Moolenbroek 	free(buf2);
1203*3ba6090fSDavid van Moolenbroek 
1204*3ba6090fSDavid van Moolenbroek 	test94_cleanup(fd, fd2, fd3, buf);
1205*3ba6090fSDavid van Moolenbroek }
1206*3ba6090fSDavid van Moolenbroek 
1207*3ba6090fSDavid van Moolenbroek /*
1208*3ba6090fSDavid van Moolenbroek  * Test whether our filter is active through two-way communication and a
1209*3ba6090fSDavid van Moolenbroek  * subsequent check on the BPF statistics.  We do not actually look through the
1210*3ba6090fSDavid van Moolenbroek  * captured packets, because who knows what else is active on the loopback
1211*3ba6090fSDavid van Moolenbroek  * device (e.g., X11) and the extra code specifically to extract our packets in
1212*3ba6090fSDavid van Moolenbroek  * the other direction is simply not worth it.
1213*3ba6090fSDavid van Moolenbroek  */
1214*3ba6090fSDavid van Moolenbroek static void
test94_comm(int fd,int fd2,int fd3,int filtered)1215*3ba6090fSDavid van Moolenbroek test94_comm(int fd, int fd2, int fd3, int filtered)
1216*3ba6090fSDavid van Moolenbroek {
1217*3ba6090fSDavid van Moolenbroek 	struct bpf_stat bs;
1218*3ba6090fSDavid van Moolenbroek 	char c;
1219*3ba6090fSDavid van Moolenbroek 
1220*3ba6090fSDavid van Moolenbroek 	if (write(fd2, "A", 1) != 1) e(0);
1221*3ba6090fSDavid van Moolenbroek 
1222*3ba6090fSDavid van Moolenbroek 	if (read(fd3, &c, 1) != 1) e(0);
1223*3ba6090fSDavid van Moolenbroek 	if (c != 'A') e(0);
1224*3ba6090fSDavid van Moolenbroek 
1225*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCGSTATS, &bs) != 0) e(0);
1226*3ba6090fSDavid van Moolenbroek 	if (bs.bs_recv == 0) e(0);
1227*3ba6090fSDavid van Moolenbroek 	if (bs.bs_capt == 0) e(0);
1228*3ba6090fSDavid van Moolenbroek 
1229*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCFLUSH) != 0) e(0);
1230*3ba6090fSDavid van Moolenbroek 
1231*3ba6090fSDavid van Moolenbroek 	if (write(fd3, "B", 1) != 1) e(0);
1232*3ba6090fSDavid van Moolenbroek 
1233*3ba6090fSDavid van Moolenbroek 	if (read(fd2, &c, 1) != 1) e(0);
1234*3ba6090fSDavid van Moolenbroek 	if (c != 'B') e(0);
1235*3ba6090fSDavid van Moolenbroek 
1236*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCGSTATS, &bs) != 0) e(0);
1237*3ba6090fSDavid van Moolenbroek 	if (bs.bs_recv == 0) e(0);
1238*3ba6090fSDavid van Moolenbroek 
1239*3ba6090fSDavid van Moolenbroek 	if (filtered) {
1240*3ba6090fSDavid van Moolenbroek 		if (bs.bs_capt != 0) e(0);
1241*3ba6090fSDavid van Moolenbroek 		if (bs.bs_drop != 0) e(0);
1242*3ba6090fSDavid van Moolenbroek 	} else
1243*3ba6090fSDavid van Moolenbroek 		if (bs.bs_capt == 0) e(0);
1244*3ba6090fSDavid van Moolenbroek 
1245*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCFLUSH) != 0) e(0);
1246*3ba6090fSDavid van Moolenbroek }
1247*3ba6090fSDavid van Moolenbroek 
1248*3ba6090fSDavid van Moolenbroek /*
1249*3ba6090fSDavid van Moolenbroek  * Test filter installation and mechanics.
1250*3ba6090fSDavid van Moolenbroek  */
1251*3ba6090fSDavid van Moolenbroek static void
test94e(void)1252*3ba6090fSDavid van Moolenbroek test94e(void)
1253*3ba6090fSDavid van Moolenbroek {
1254*3ba6090fSDavid van Moolenbroek 	struct bpf_program bf;
1255*3ba6090fSDavid van Moolenbroek 	struct bpf_stat bs;
1256*3ba6090fSDavid van Moolenbroek 	struct bpf_hdr bh;
1257*3ba6090fSDavid van Moolenbroek 	uint8_t *buf;
1258*3ba6090fSDavid van Moolenbroek 	size_t size, len, plen, alen, off;
1259*3ba6090fSDavid van Moolenbroek 	uint32_t seq, caplen[4], datalen[4];
1260*3ba6090fSDavid van Moolenbroek 	int i, fd, fd2, fd3, val;
1261*3ba6090fSDavid van Moolenbroek 
1262*3ba6090fSDavid van Moolenbroek 	subtest = 5;
1263*3ba6090fSDavid van Moolenbroek 
1264*3ba6090fSDavid van Moolenbroek 	/*
1265*3ba6090fSDavid van Moolenbroek 	 * We have already tested installing a filter both before and after
1266*3ba6090fSDavid van Moolenbroek 	 * attaching to an interface by now, so we do not repeat that here.
1267*3ba6090fSDavid van Moolenbroek 	 */
1268*3ba6090fSDavid van Moolenbroek 	size = test94_setup(&fd, &fd2, &fd3, &buf, 0 /*size*/,
1269*3ba6090fSDavid van Moolenbroek 	    0 /*set_filter*/);
1270*3ba6090fSDavid van Moolenbroek 
1271*3ba6090fSDavid van Moolenbroek 	val = 1;
1272*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCIMMEDIATE, &val) != 0) e(0);
1273*3ba6090fSDavid van Moolenbroek 
1274*3ba6090fSDavid van Moolenbroek 	/*
1275*3ba6090fSDavid van Moolenbroek 	 * A filter that is too large is rejected.  Unfortunately, due to
1276*3ba6090fSDavid van Moolenbroek 	 * necessary IOCTL rewriting, this tests libc, not the service.
1277*3ba6090fSDavid van Moolenbroek 	 */
1278*3ba6090fSDavid van Moolenbroek 	memset(&bf, 0, sizeof(bf));
1279*3ba6090fSDavid van Moolenbroek 	bf.bf_len = BPF_MAXINSNS + 1;
1280*3ba6090fSDavid van Moolenbroek 	bf.bf_insns = NULL;
1281*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSETF, &bf) != -1) e(0);
1282*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
1283*3ba6090fSDavid van Moolenbroek 
1284*3ba6090fSDavid van Moolenbroek 	/*
1285*3ba6090fSDavid van Moolenbroek 	 * An invalid filter is rejected.  In this test case, the truncated
1286*3ba6090fSDavid van Moolenbroek 	 * filter has a jump target beyond the end of the filter program.
1287*3ba6090fSDavid van Moolenbroek 	 */
1288*3ba6090fSDavid van Moolenbroek 	memset(&bf, 0, sizeof(bf));
1289*3ba6090fSDavid van Moolenbroek 	bf.bf_len = __arraycount(test94_filter) - 1;
1290*3ba6090fSDavid van Moolenbroek 	bf.bf_insns = test94_filter;
1291*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSETF, &bf) != -1) e(0);
1292*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
1293*3ba6090fSDavid van Moolenbroek 
1294*3ba6090fSDavid van Moolenbroek 	test94_comm(fd, fd2, fd3, 0 /*filtered*/);
1295*3ba6090fSDavid van Moolenbroek 
1296*3ba6090fSDavid van Moolenbroek 	bf.bf_len++;
1297*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSETF, &bf) != 0) e(0);
1298*3ba6090fSDavid van Moolenbroek 
1299*3ba6090fSDavid van Moolenbroek 	test94_comm(fd, fd2, fd3, 1 /*filtered*/);
1300*3ba6090fSDavid van Moolenbroek 
1301*3ba6090fSDavid van Moolenbroek 	/*
1302*3ba6090fSDavid van Moolenbroek 	 * Installing a zero-length filter clears the current filter, if any.
1303*3ba6090fSDavid van Moolenbroek 	 */
1304*3ba6090fSDavid van Moolenbroek 	memset(&bf, 0, sizeof(bf));
1305*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSETF, &bf) != 0) e(0);
1306*3ba6090fSDavid van Moolenbroek 
1307*3ba6090fSDavid van Moolenbroek 	test94_comm(fd, fd2, fd3, 0 /*filtered*/);
1308*3ba6090fSDavid van Moolenbroek 
1309*3ba6090fSDavid van Moolenbroek 	/* Test this twice to trip over unconditional filter deallocation. */
1310*3ba6090fSDavid van Moolenbroek 	memset(&bf, 0, sizeof(bf));
1311*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSETF, &bf) != 0) e(0);
1312*3ba6090fSDavid van Moolenbroek 
1313*3ba6090fSDavid van Moolenbroek 	test94_comm(fd, fd2, fd3, 0 /*filtered*/);
1314*3ba6090fSDavid van Moolenbroek 
1315*3ba6090fSDavid van Moolenbroek 	/*
1316*3ba6090fSDavid van Moolenbroek 	 * Test both aligned and unaligned capture sizes.  For each, test
1317*3ba6090fSDavid van Moolenbroek 	 * sizes larger than, equal to, and smaller than the capture size.
1318*3ba6090fSDavid van Moolenbroek 	 * In both cases, aggregate the packets into a single buffer and only
1319*3ba6090fSDavid van Moolenbroek 	 * then go through them, to see whether alignment was done correctly.
1320*3ba6090fSDavid van Moolenbroek 	 * We cannot do everything in one go as BIOCSETF implies a BIOCFLUSH.
1321*3ba6090fSDavid van Moolenbroek 	 */
1322*3ba6090fSDavid van Moolenbroek 	plen = sizeof(struct ip) + sizeof(struct udphdr) + sizeof(seq);
1323*3ba6090fSDavid van Moolenbroek 	if (BPF_WORDALIGN(plen) != plen) e(0);
1324*3ba6090fSDavid van Moolenbroek 	alen = BPF_WORDALIGN(plen + 1);
1325*3ba6090fSDavid van Moolenbroek 	if (alen - 2 <= plen + 1) e(0);
1326*3ba6090fSDavid van Moolenbroek 
1327*3ba6090fSDavid van Moolenbroek 	/* First the aligned cases. */
1328*3ba6090fSDavid van Moolenbroek 	test94_filter[__arraycount(test94_filter) - 1].k = alen;
1329*3ba6090fSDavid van Moolenbroek 
1330*3ba6090fSDavid van Moolenbroek 	memset(&bf, 0, sizeof(bf));
1331*3ba6090fSDavid van Moolenbroek 	bf.bf_len = __arraycount(test94_filter);
1332*3ba6090fSDavid van Moolenbroek 	bf.bf_insns = test94_filter;
1333*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSETF, &bf) != 0) e(0);
1334*3ba6090fSDavid van Moolenbroek 
1335*3ba6090fSDavid van Moolenbroek 	test94_comm(fd, fd2, fd3, 1 /*filtered*/);
1336*3ba6090fSDavid van Moolenbroek 
1337*3ba6090fSDavid van Moolenbroek 	test94_add_specific(fd2, buf, alen + 1 - plen, 1);
1338*3ba6090fSDavid van Moolenbroek 	caplen[0] = alen;
1339*3ba6090fSDavid van Moolenbroek 	datalen[0] = alen + 1;
1340*3ba6090fSDavid van Moolenbroek 
1341*3ba6090fSDavid van Moolenbroek 	test94_add_specific(fd2, buf, alen - plen, 2);
1342*3ba6090fSDavid van Moolenbroek 	caplen[1] = alen;
1343*3ba6090fSDavid van Moolenbroek 	datalen[1] = alen;
1344*3ba6090fSDavid van Moolenbroek 
1345*3ba6090fSDavid van Moolenbroek 	test94_add_specific(fd2, buf, alen + 3 - plen, 3);
1346*3ba6090fSDavid van Moolenbroek 	caplen[2] = alen;
1347*3ba6090fSDavid van Moolenbroek 	datalen[2] = alen + 3;
1348*3ba6090fSDavid van Moolenbroek 
1349*3ba6090fSDavid van Moolenbroek 	test94_add_specific(fd2, buf, alen - 1 - plen, 4);
1350*3ba6090fSDavid van Moolenbroek 	caplen[3] = alen - 1;
1351*3ba6090fSDavid van Moolenbroek 	datalen[3] = alen - 1;
1352*3ba6090fSDavid van Moolenbroek 
1353*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, size);
1354*3ba6090fSDavid van Moolenbroek 
1355*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
1356*3ba6090fSDavid van Moolenbroek 
1357*3ba6090fSDavid van Moolenbroek 	if (test94_check(buf, len, 1 /*seq*/, 1 /*filtered*/, caplen,
1358*3ba6090fSDavid van Moolenbroek 	    datalen) != 5) e(0);
1359*3ba6090fSDavid van Moolenbroek 
1360*3ba6090fSDavid van Moolenbroek 	/* Then the unaligned cases. */
1361*3ba6090fSDavid van Moolenbroek 	test94_filter[__arraycount(test94_filter) - 1].k = alen + 1;
1362*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSETF, &bf) != 0) e(0);
1363*3ba6090fSDavid van Moolenbroek 
1364*3ba6090fSDavid van Moolenbroek 	test94_add_specific(fd2, buf, alen + 2 - plen, 5);
1365*3ba6090fSDavid van Moolenbroek 	caplen[0] = alen + 1;
1366*3ba6090fSDavid van Moolenbroek 	datalen[0] = alen + 2;
1367*3ba6090fSDavid van Moolenbroek 
1368*3ba6090fSDavid van Moolenbroek 	test94_add_specific(fd2, buf, alen + 1 - plen, 6);
1369*3ba6090fSDavid van Moolenbroek 	caplen[1] = alen + 1;
1370*3ba6090fSDavid van Moolenbroek 	datalen[1] = alen + 1;
1371*3ba6090fSDavid van Moolenbroek 
1372*3ba6090fSDavid van Moolenbroek 	test94_add_specific(fd2, buf, alen + 9 - plen, 7);
1373*3ba6090fSDavid van Moolenbroek 	caplen[2] = alen + 1;
1374*3ba6090fSDavid van Moolenbroek 	datalen[2] = alen + 9;
1375*3ba6090fSDavid van Moolenbroek 
1376*3ba6090fSDavid van Moolenbroek 	test94_add_specific(fd2, buf, alen - plen, 8);
1377*3ba6090fSDavid van Moolenbroek 	caplen[3] = alen;
1378*3ba6090fSDavid van Moolenbroek 	datalen[3] = alen;
1379*3ba6090fSDavid van Moolenbroek 
1380*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, size);
1381*3ba6090fSDavid van Moolenbroek 
1382*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
1383*3ba6090fSDavid van Moolenbroek 
1384*3ba6090fSDavid van Moolenbroek 	if (test94_check(buf, len, 5 /*seq*/, 1 /*filtered*/, caplen,
1385*3ba6090fSDavid van Moolenbroek 	    datalen) != 9) e(0);
1386*3ba6090fSDavid van Moolenbroek 
1387*3ba6090fSDavid van Moolenbroek 	/*
1388*3ba6090fSDavid van Moolenbroek 	 * Check that capturing only one byte from packets is possible.  Not
1389*3ba6090fSDavid van Moolenbroek 	 * that that would be particularly useful.
1390*3ba6090fSDavid van Moolenbroek 	 */
1391*3ba6090fSDavid van Moolenbroek 	test94_filter[__arraycount(test94_filter) - 1].k = 1;
1392*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSETF, &bf) != 0) e(0);
1393*3ba6090fSDavid van Moolenbroek 
1394*3ba6090fSDavid van Moolenbroek 	test94_add_random(fd2, buf, size, 9);
1395*3ba6090fSDavid van Moolenbroek 	test94_add_random(fd2, buf, size, 10);
1396*3ba6090fSDavid van Moolenbroek 	test94_add_random(fd2, buf, size, 11);
1397*3ba6090fSDavid van Moolenbroek 
1398*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, size);
1399*3ba6090fSDavid van Moolenbroek 
1400*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
1401*3ba6090fSDavid van Moolenbroek 	if (len <= 0) e(0);
1402*3ba6090fSDavid van Moolenbroek 
1403*3ba6090fSDavid van Moolenbroek 	off = 0;
1404*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < 3; i++) {
1405*3ba6090fSDavid van Moolenbroek 		if (len - off < sizeof(bh)) e(0);
1406*3ba6090fSDavid van Moolenbroek 		memcpy(&bh, &buf[off], sizeof(bh));
1407*3ba6090fSDavid van Moolenbroek 
1408*3ba6090fSDavid van Moolenbroek 		if (bh.bh_tstamp.tv_sec == 0 && bh.bh_tstamp.tv_usec == 0)
1409*3ba6090fSDavid van Moolenbroek 			e(0);
1410*3ba6090fSDavid van Moolenbroek 		if (bh.bh_caplen != 1) e(0);
1411*3ba6090fSDavid van Moolenbroek 		if (bh.bh_datalen < plen) e(0);
1412*3ba6090fSDavid van Moolenbroek 		if (bh.bh_hdrlen != BPF_WORDALIGN(sizeof(bh))) e(0);
1413*3ba6090fSDavid van Moolenbroek 
1414*3ba6090fSDavid van Moolenbroek 		off += bh.bh_hdrlen;
1415*3ba6090fSDavid van Moolenbroek 
1416*3ba6090fSDavid van Moolenbroek 		if (buf[off] != 0x45) e(0);
1417*3ba6090fSDavid van Moolenbroek 
1418*3ba6090fSDavid van Moolenbroek 		off += BPF_WORDALIGN(bh.bh_caplen);
1419*3ba6090fSDavid van Moolenbroek 	}
1420*3ba6090fSDavid van Moolenbroek 	if (off != len) e(0);
1421*3ba6090fSDavid van Moolenbroek 
1422*3ba6090fSDavid van Moolenbroek 	/*
1423*3ba6090fSDavid van Moolenbroek 	 * Finally, a zero capture size should result in rejected packets only.
1424*3ba6090fSDavid van Moolenbroek 	 */
1425*3ba6090fSDavid van Moolenbroek 	test94_filter[__arraycount(test94_filter) - 1].k = 0;
1426*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSETF, &bf) != 0) e(0);
1427*3ba6090fSDavid van Moolenbroek 
1428*3ba6090fSDavid van Moolenbroek 	test94_add_random(fd2, buf, size, 12);
1429*3ba6090fSDavid van Moolenbroek 	test94_add_random(fd2, buf, size, 13);
1430*3ba6090fSDavid van Moolenbroek 	test94_add_random(fd2, buf, size, 14);
1431*3ba6090fSDavid van Moolenbroek 
1432*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCGSTATS, &bs) != 0) e(0);
1433*3ba6090fSDavid van Moolenbroek 	if (bs.bs_recv < 3) e(0);
1434*3ba6090fSDavid van Moolenbroek 	if (bs.bs_capt != 0) e(0);
1435*3ba6090fSDavid van Moolenbroek 	if (bs.bs_drop != 0) e(0);
1436*3ba6090fSDavid van Moolenbroek 
1437*3ba6090fSDavid van Moolenbroek 	/* Restore the capture limit of the filter to its original state. */
1438*3ba6090fSDavid van Moolenbroek 	test94_filter[__arraycount(test94_filter) - 1].k = (uint32_t)-1;
1439*3ba6090fSDavid van Moolenbroek 
1440*3ba6090fSDavid van Moolenbroek 	test94_cleanup(fd, fd2, fd3, buf);
1441*3ba6090fSDavid van Moolenbroek }
1442*3ba6090fSDavid van Moolenbroek 
1443*3ba6090fSDavid van Moolenbroek /*
1444*3ba6090fSDavid van Moolenbroek  * Compute an IP checksum.
1445*3ba6090fSDavid van Moolenbroek  */
1446*3ba6090fSDavid van Moolenbroek static uint16_t
test94_cksum(uint8_t * buf,size_t len)1447*3ba6090fSDavid van Moolenbroek test94_cksum(uint8_t * buf, size_t len)
1448*3ba6090fSDavid van Moolenbroek {
1449*3ba6090fSDavid van Moolenbroek 	uint32_t sum, word;
1450*3ba6090fSDavid van Moolenbroek 
1451*3ba6090fSDavid van Moolenbroek 	/* This is a really dumb implementation but *shrug*. */
1452*3ba6090fSDavid van Moolenbroek 	for (sum = 0; len > 0; sum += word) {
1453*3ba6090fSDavid van Moolenbroek 		if (len > 1) {
1454*3ba6090fSDavid van Moolenbroek 			word = buf[0] << 8 | buf[1];
1455*3ba6090fSDavid van Moolenbroek 			buf += 2;
1456*3ba6090fSDavid van Moolenbroek 			len -= 2;
1457*3ba6090fSDavid van Moolenbroek 		} else {
1458*3ba6090fSDavid van Moolenbroek 			word = buf[0] << 8;
1459*3ba6090fSDavid van Moolenbroek 			len--;
1460*3ba6090fSDavid van Moolenbroek 		}
1461*3ba6090fSDavid van Moolenbroek 	}
1462*3ba6090fSDavid van Moolenbroek 
1463*3ba6090fSDavid van Moolenbroek 	while (sum > UINT16_MAX)
1464*3ba6090fSDavid van Moolenbroek 		sum = (sum & UINT16_MAX) + (sum >> 16);
1465*3ba6090fSDavid van Moolenbroek 
1466*3ba6090fSDavid van Moolenbroek 	return ~(uint16_t)sum;
1467*3ba6090fSDavid van Moolenbroek }
1468*3ba6090fSDavid van Moolenbroek 
1469*3ba6090fSDavid van Moolenbroek /*
1470*3ba6090fSDavid van Moolenbroek  * Set up UDP headers for a packet.  The packet uses IPv4 unless 'v6' is set,
1471*3ba6090fSDavid van Moolenbroek  * in which case IPv6 is used.  The given buffer must be large enough to
1472*3ba6090fSDavid van Moolenbroek  * contain the headers and the (to be appended) data.  The function returns the
1473*3ba6090fSDavid van Moolenbroek  * offset into the buffer to the data portion of the packet.
1474*3ba6090fSDavid van Moolenbroek  */
1475*3ba6090fSDavid van Moolenbroek static size_t
test94_make_pkt(uint8_t * buf,size_t len,int v6)1476*3ba6090fSDavid van Moolenbroek test94_make_pkt(uint8_t * buf, size_t len, int v6)
1477*3ba6090fSDavid van Moolenbroek {
1478*3ba6090fSDavid van Moolenbroek 	struct ip ip;
1479*3ba6090fSDavid van Moolenbroek 	struct ip6_hdr ip6;
1480*3ba6090fSDavid van Moolenbroek 	struct udphdr uh;
1481*3ba6090fSDavid van Moolenbroek 	size_t off;
1482*3ba6090fSDavid van Moolenbroek 
1483*3ba6090fSDavid van Moolenbroek 	if (!v6) {
1484*3ba6090fSDavid van Moolenbroek 		memset(&ip, 0, sizeof(ip));
1485*3ba6090fSDavid van Moolenbroek 		ip.ip_v = IPVERSION;
1486*3ba6090fSDavid van Moolenbroek 		ip.ip_hl = sizeof(ip) >> 2;
1487*3ba6090fSDavid van Moolenbroek 		ip.ip_len = htons(sizeof(ip) + sizeof(uh) + len);
1488*3ba6090fSDavid van Moolenbroek 		ip.ip_ttl = 255;
1489*3ba6090fSDavid van Moolenbroek 		ip.ip_p = IPPROTO_UDP;
1490*3ba6090fSDavid van Moolenbroek 		ip.ip_sum = 0;
1491*3ba6090fSDavid van Moolenbroek 		ip.ip_src.s_addr = htonl(INADDR_LOOPBACK);
1492*3ba6090fSDavid van Moolenbroek 		ip.ip_dst.s_addr = htonl(INADDR_LOOPBACK);
1493*3ba6090fSDavid van Moolenbroek 
1494*3ba6090fSDavid van Moolenbroek 		memcpy(buf, &ip, sizeof(ip));
1495*3ba6090fSDavid van Moolenbroek 		ip.ip_sum = htons(test94_cksum(buf, sizeof(ip)));
1496*3ba6090fSDavid van Moolenbroek 		memcpy(buf, &ip, sizeof(ip));
1497*3ba6090fSDavid van Moolenbroek 		if (test94_cksum(buf, sizeof(ip)) != 0) e(0);
1498*3ba6090fSDavid van Moolenbroek 
1499*3ba6090fSDavid van Moolenbroek 		off = sizeof(ip);
1500*3ba6090fSDavid van Moolenbroek 	} else {
1501*3ba6090fSDavid van Moolenbroek 		memset(&ip6, 0, sizeof(ip6));
1502*3ba6090fSDavid van Moolenbroek 		ip6.ip6_vfc = IPV6_VERSION;
1503*3ba6090fSDavid van Moolenbroek 		ip6.ip6_plen = htons(sizeof(uh) + len);
1504*3ba6090fSDavid van Moolenbroek 		ip6.ip6_nxt = IPPROTO_UDP;
1505*3ba6090fSDavid van Moolenbroek 		ip6.ip6_hlim = 255;
1506*3ba6090fSDavid van Moolenbroek 		memcpy(&ip6.ip6_src, &in6addr_loopback, sizeof(ip6.ip6_src));
1507*3ba6090fSDavid van Moolenbroek 		memcpy(&ip6.ip6_dst, &in6addr_loopback, sizeof(ip6.ip6_dst));
1508*3ba6090fSDavid van Moolenbroek 
1509*3ba6090fSDavid van Moolenbroek 		memcpy(buf, &ip6, sizeof(ip6));
1510*3ba6090fSDavid van Moolenbroek 
1511*3ba6090fSDavid van Moolenbroek 		off = sizeof(ip6);
1512*3ba6090fSDavid van Moolenbroek 	}
1513*3ba6090fSDavid van Moolenbroek 
1514*3ba6090fSDavid van Moolenbroek 	memset(&uh, 0, sizeof(uh));
1515*3ba6090fSDavid van Moolenbroek 	uh.uh_sport = htons(TEST_PORT_A);
1516*3ba6090fSDavid van Moolenbroek 	uh.uh_dport = htons(TEST_PORT_B);
1517*3ba6090fSDavid van Moolenbroek 	uh.uh_ulen = htons(sizeof(uh) + len);
1518*3ba6090fSDavid van Moolenbroek 	uh.uh_sum = 0; /* lazy but we also don't have the data yet */
1519*3ba6090fSDavid van Moolenbroek 
1520*3ba6090fSDavid van Moolenbroek 	memcpy(buf + off, &uh, sizeof(uh));
1521*3ba6090fSDavid van Moolenbroek 
1522*3ba6090fSDavid van Moolenbroek 	return off + sizeof(uh);
1523*3ba6090fSDavid van Moolenbroek }
1524*3ba6090fSDavid van Moolenbroek 
1525*3ba6090fSDavid van Moolenbroek /*
1526*3ba6090fSDavid van Moolenbroek  * Test sending packets by writing to a BPF device.
1527*3ba6090fSDavid van Moolenbroek  */
1528*3ba6090fSDavid van Moolenbroek static void
test94f(void)1529*3ba6090fSDavid van Moolenbroek test94f(void)
1530*3ba6090fSDavid van Moolenbroek {
1531*3ba6090fSDavid van Moolenbroek 	struct bpf_stat bs;
1532*3ba6090fSDavid van Moolenbroek 	struct ifreq ifr;
1533*3ba6090fSDavid van Moolenbroek 	fd_set fds;
1534*3ba6090fSDavid van Moolenbroek 	uint8_t *buf;
1535*3ba6090fSDavid van Moolenbroek 	size_t off;
1536*3ba6090fSDavid van Moolenbroek 	unsigned int i, uval, mtu;
1537*3ba6090fSDavid van Moolenbroek 	int fd, fd2, fd3;
1538*3ba6090fSDavid van Moolenbroek 
1539*3ba6090fSDavid van Moolenbroek 	subtest = 6;
1540*3ba6090fSDavid van Moolenbroek 
1541*3ba6090fSDavid van Moolenbroek 	(void)test94_setup(&fd, &fd2, &fd3, &buf, 0 /*size*/,
1542*3ba6090fSDavid van Moolenbroek 	    1 /*set_filter*/);
1543*3ba6090fSDavid van Moolenbroek 
1544*3ba6090fSDavid van Moolenbroek 	/*
1545*3ba6090fSDavid van Moolenbroek 	 * Select queries should always indicate that the device is writable.
1546*3ba6090fSDavid van Moolenbroek 	 */
1547*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&fds);
1548*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &fds);
1549*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, NULL, &fds, NULL, NULL) != 1) e(0);
1550*3ba6090fSDavid van Moolenbroek 	if (!FD_ISSET(fd, &fds)) e(0);
1551*3ba6090fSDavid van Moolenbroek 
1552*3ba6090fSDavid van Moolenbroek 	/*
1553*3ba6090fSDavid van Moolenbroek 	 * Test packet size limits.  For loopback devices, the maximum data
1554*3ba6090fSDavid van Moolenbroek 	 * link layer level maximum transmission unit should be 65535-4 =
1555*3ba6090fSDavid van Moolenbroek 	 * 65531 bytes.  Obtain the actual value anyway; it might have changed.
1556*3ba6090fSDavid van Moolenbroek 	 */
1557*3ba6090fSDavid van Moolenbroek 	memset(&ifr, 0, sizeof(ifr));
1558*3ba6090fSDavid van Moolenbroek 	strlcpy(ifr.ifr_name, LOOPBACK_IFNAME, sizeof(ifr.ifr_name));
1559*3ba6090fSDavid van Moolenbroek 
1560*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd2, SIOCGIFMTU, &ifr) != 0) e(0);
1561*3ba6090fSDavid van Moolenbroek 	mtu = ifr.ifr_mtu;
1562*3ba6090fSDavid van Moolenbroek 
1563*3ba6090fSDavid van Moolenbroek 	if ((buf = realloc(buf, UINT16_MAX + 1)) == NULL) e(0);
1564*3ba6090fSDavid van Moolenbroek 
1565*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, UINT16_MAX + 1);
1566*3ba6090fSDavid van Moolenbroek 
1567*3ba6090fSDavid van Moolenbroek 	for (i = UINT16_MAX + 1; i > mtu; i--) {
1568*3ba6090fSDavid van Moolenbroek 		if (write(fd, buf, i) != -1) e(0);
1569*3ba6090fSDavid van Moolenbroek 		if (errno != EMSGSIZE) e(0);
1570*3ba6090fSDavid van Moolenbroek 	}
1571*3ba6090fSDavid van Moolenbroek 
1572*3ba6090fSDavid van Moolenbroek 	/* This packet will be discarded as completely crap.  That's fine. */
1573*3ba6090fSDavid van Moolenbroek 	if (write(fd, buf, mtu) != mtu) e(0);
1574*3ba6090fSDavid van Moolenbroek 
1575*3ba6090fSDavid van Moolenbroek 	/*
1576*3ba6090fSDavid van Moolenbroek 	 * Zero-sized writes are accepted but do not do anything.
1577*3ba6090fSDavid van Moolenbroek 	 */
1578*3ba6090fSDavid van Moolenbroek 	if (write(fd, buf, 0) != 0) e(0);
1579*3ba6090fSDavid van Moolenbroek 
1580*3ba6090fSDavid van Moolenbroek 	/*
1581*3ba6090fSDavid van Moolenbroek 	 * Send an actual packet, and see if it arrives.
1582*3ba6090fSDavid van Moolenbroek 	 */
1583*3ba6090fSDavid van Moolenbroek 	off = test94_make_pkt(buf, 6, 0 /*v6*/);
1584*3ba6090fSDavid van Moolenbroek 	memcpy(buf + off, "Hello!", 6);
1585*3ba6090fSDavid van Moolenbroek 
1586*3ba6090fSDavid van Moolenbroek 	if (write(fd, buf, off + 6) != off + 6) e(0);
1587*3ba6090fSDavid van Moolenbroek 
1588*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, mtu);
1589*3ba6090fSDavid van Moolenbroek 	if (read(fd3, buf, mtu) != 6) e(0);
1590*3ba6090fSDavid van Moolenbroek 	if (memcmp(buf, "Hello!", 6) != 0) e(0);
1591*3ba6090fSDavid van Moolenbroek 
1592*3ba6090fSDavid van Moolenbroek 	/*
1593*3ba6090fSDavid van Moolenbroek 	 * Enable feedback mode to test that the packet now arrives twice.
1594*3ba6090fSDavid van Moolenbroek 	 * Send a somewhat larger packet to test that data copy-in handles
1595*3ba6090fSDavid van Moolenbroek 	 * offsets correctly.
1596*3ba6090fSDavid van Moolenbroek 	 */
1597*3ba6090fSDavid van Moolenbroek 	uval = 1;
1598*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSFEEDBACK, &uval) != 0) e(0);
1599*3ba6090fSDavid van Moolenbroek 
1600*3ba6090fSDavid van Moolenbroek 	off = test94_make_pkt(buf, 12345, 0 /*v6*/);
1601*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < 12345; i++)
1602*3ba6090fSDavid van Moolenbroek 		buf[off + i] = 1 + (i % 251); /* the largest prime < 255 */
1603*3ba6090fSDavid van Moolenbroek 
1604*3ba6090fSDavid van Moolenbroek 	if (write(fd, buf, off + 12345) != off + 12345) e(0);
1605*3ba6090fSDavid van Moolenbroek 
1606*3ba6090fSDavid van Moolenbroek 	/* We need a default UDP SO_RCVBUF >= 12345 * 2 for this. */
1607*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, UINT16_MAX);
1608*3ba6090fSDavid van Moolenbroek 	if (recv(fd3, buf, UINT16_MAX, 0) != 12345) e(0);
1609*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < 12345; i++)
1610*3ba6090fSDavid van Moolenbroek 		if (buf[i] != 1 + (i % 251)) e(0);
1611*3ba6090fSDavid van Moolenbroek 
1612*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, UINT16_MAX);
1613*3ba6090fSDavid van Moolenbroek 	if (recv(fd3, buf, UINT16_MAX, MSG_DONTWAIT) != 12345) e(0);
1614*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < 12345; i++)
1615*3ba6090fSDavid van Moolenbroek 		if (buf[i] != 1 + (i % 251)) e(0);
1616*3ba6090fSDavid van Moolenbroek 
1617*3ba6090fSDavid van Moolenbroek 	if (recv(fd3, buf, UINT16_MAX, MSG_DONTWAIT) != -1) e(0);
1618*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
1619*3ba6090fSDavid van Moolenbroek 
1620*3ba6090fSDavid van Moolenbroek 	/*
1621*3ba6090fSDavid van Moolenbroek 	 * The two valid packets we sent will have been captured by our BPF
1622*3ba6090fSDavid van Moolenbroek 	 * device as well, because SEESENT is enabled by default and also
1623*3ba6090fSDavid van Moolenbroek 	 * applies to packets written to a BPF device.  The reason for that is
1624*3ba6090fSDavid van Moolenbroek 	 * that it allows tcpdump(8) to see what DHCP clients are sending, for
1625*3ba6090fSDavid van Moolenbroek 	 * example.  The packets we sent are accepted by the installed filter.
1626*3ba6090fSDavid van Moolenbroek 	 */
1627*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCGSTATS, &bs) != 0) e(0);
1628*3ba6090fSDavid van Moolenbroek 	if (bs.bs_capt != 2) e(0);
1629*3ba6090fSDavid van Moolenbroek 
1630*3ba6090fSDavid van Moolenbroek 	/* Now that we've written data, test select once more. */
1631*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&fds);
1632*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &fds);
1633*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, NULL, &fds, NULL, NULL) != 1) e(0);
1634*3ba6090fSDavid van Moolenbroek 	if (!FD_ISSET(fd, &fds)) e(0);
1635*3ba6090fSDavid van Moolenbroek 
1636*3ba6090fSDavid van Moolenbroek 	test94_cleanup(fd, fd2, fd3, buf);
1637*3ba6090fSDavid van Moolenbroek }
1638*3ba6090fSDavid van Moolenbroek 
1639*3ba6090fSDavid van Moolenbroek /*
1640*3ba6090fSDavid van Moolenbroek  * Test read, write, and select operations on unconfigured devices.
1641*3ba6090fSDavid van Moolenbroek  */
1642*3ba6090fSDavid van Moolenbroek static void
test94g(void)1643*3ba6090fSDavid van Moolenbroek test94g(void)
1644*3ba6090fSDavid van Moolenbroek {
1645*3ba6090fSDavid van Moolenbroek 	fd_set rfds, wfds;
1646*3ba6090fSDavid van Moolenbroek 	uint8_t *buf;
1647*3ba6090fSDavid van Moolenbroek 	unsigned int size;
1648*3ba6090fSDavid van Moolenbroek 	int fd;
1649*3ba6090fSDavid van Moolenbroek 
1650*3ba6090fSDavid van Moolenbroek 	subtest = 7;
1651*3ba6090fSDavid van Moolenbroek 
1652*3ba6090fSDavid van Moolenbroek 	if ((fd = open(_PATH_BPF, O_RDWR)) < 0) e(0);
1653*3ba6090fSDavid van Moolenbroek 
1654*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCGBLEN, &size) != 0) e(0);
1655*3ba6090fSDavid van Moolenbroek 	if (size < 1024 || size > BPF_MAXBUFSIZE) e(0);
1656*3ba6090fSDavid van Moolenbroek 
1657*3ba6090fSDavid van Moolenbroek 	if ((buf = malloc(size)) == NULL) e(0);
1658*3ba6090fSDavid van Moolenbroek 
1659*3ba6090fSDavid van Moolenbroek 	if (read(fd, buf, size) != -1) e(0);
1660*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
1661*3ba6090fSDavid van Moolenbroek 
1662*3ba6090fSDavid van Moolenbroek 	if (write(fd, buf, size) != -1) e(0);
1663*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
1664*3ba6090fSDavid van Moolenbroek 
1665*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&rfds);
1666*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &rfds);
1667*3ba6090fSDavid van Moolenbroek 	FD_ZERO(&wfds);
1668*3ba6090fSDavid van Moolenbroek 	FD_SET(fd, &wfds);
1669*3ba6090fSDavid van Moolenbroek 
1670*3ba6090fSDavid van Moolenbroek 	if (select(fd + 1, &rfds, &wfds, NULL, NULL) != 2) e(0);
1671*3ba6090fSDavid van Moolenbroek 
1672*3ba6090fSDavid van Moolenbroek 	if (!FD_ISSET(fd, &rfds)) e(0);
1673*3ba6090fSDavid van Moolenbroek 	if (!FD_ISSET(fd, &wfds)) e(0);
1674*3ba6090fSDavid van Moolenbroek 
1675*3ba6090fSDavid van Moolenbroek 	free(buf);
1676*3ba6090fSDavid van Moolenbroek 
1677*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1678*3ba6090fSDavid van Moolenbroek }
1679*3ba6090fSDavid van Moolenbroek 
1680*3ba6090fSDavid van Moolenbroek /*
1681*3ba6090fSDavid van Moolenbroek  * Test various IOCTL calls.  Several of these tests are rather superficial,
1682*3ba6090fSDavid van Moolenbroek  * because we would need a real interface, rather than the loopback device, to
1683*3ba6090fSDavid van Moolenbroek  * test their functionality properly.  Also note that we skip various checks
1684*3ba6090fSDavid van Moolenbroek  * performed as part of the earlier subtests.
1685*3ba6090fSDavid van Moolenbroek  */
1686*3ba6090fSDavid van Moolenbroek static void
test94h(void)1687*3ba6090fSDavid van Moolenbroek test94h(void)
1688*3ba6090fSDavid van Moolenbroek {
1689*3ba6090fSDavid van Moolenbroek 	struct bpf_stat bs;
1690*3ba6090fSDavid van Moolenbroek 	struct bpf_version bv;
1691*3ba6090fSDavid van Moolenbroek 	struct bpf_dltlist bfl;
1692*3ba6090fSDavid van Moolenbroek 	struct ifreq ifr;
1693*3ba6090fSDavid van Moolenbroek 	struct timeval tv;
1694*3ba6090fSDavid van Moolenbroek 	uint8_t *buf;
1695*3ba6090fSDavid van Moolenbroek 	size_t size;
1696*3ba6090fSDavid van Moolenbroek 	unsigned int uval, list[2];
1697*3ba6090fSDavid van Moolenbroek 	int cfd, ufd, fd2, fd3, val;
1698*3ba6090fSDavid van Moolenbroek 
1699*3ba6090fSDavid van Moolenbroek 	subtest = 8;
1700*3ba6090fSDavid van Moolenbroek 
1701*3ba6090fSDavid van Moolenbroek 	/*
1702*3ba6090fSDavid van Moolenbroek 	 * Many IOCTLs work only on configured or only on unconfigured BPF
1703*3ba6090fSDavid van Moolenbroek 	 * devices, so for convenience we create a file descriptor for each.
1704*3ba6090fSDavid van Moolenbroek 	 */
1705*3ba6090fSDavid van Moolenbroek 	size = test94_setup(&cfd, &fd2, &fd3, &buf, 0 /*size*/,
1706*3ba6090fSDavid van Moolenbroek 	    1 /*set_filter*/);
1707*3ba6090fSDavid van Moolenbroek 
1708*3ba6090fSDavid van Moolenbroek 	if ((ufd = open(_PATH_BPF, O_RDWR)) < 0) e(0);
1709*3ba6090fSDavid van Moolenbroek 
1710*3ba6090fSDavid van Moolenbroek 	/*
1711*3ba6090fSDavid van Moolenbroek 	 * The BIOCSBLEN value is silently corrected to fall within a valid
1712*3ba6090fSDavid van Moolenbroek 	 * range, and BIOCGBLEN can be used to obtain the corrected value.  We
1713*3ba6090fSDavid van Moolenbroek 	 * do not know the valid range, so we use fairly extreme test values.
1714*3ba6090fSDavid van Moolenbroek 	 */
1715*3ba6090fSDavid van Moolenbroek 	uval = 1;
1716*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSBLEN, &uval) != 0) e(0);
1717*3ba6090fSDavid van Moolenbroek 
1718*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGBLEN, &uval) != 0) e(0);
1719*3ba6090fSDavid van Moolenbroek 	if (uval < sizeof(struct bpf_hdr) || uval > BPF_MAXBUFSIZE) e(0);
1720*3ba6090fSDavid van Moolenbroek 
1721*3ba6090fSDavid van Moolenbroek 	uval = (unsigned int)-1;
1722*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSBLEN, &uval) != 0) e(0);
1723*3ba6090fSDavid van Moolenbroek 
1724*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGBLEN, &uval) != 0) e(0);
1725*3ba6090fSDavid van Moolenbroek 	if (uval < sizeof(struct bpf_hdr) || uval > BPF_MAXBUFSIZE) e(0);
1726*3ba6090fSDavid van Moolenbroek 
1727*3ba6090fSDavid van Moolenbroek 	uval = 0;
1728*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSBLEN, &uval) != 0) e(0);
1729*3ba6090fSDavid van Moolenbroek 
1730*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGBLEN, &uval) != 0) e(0);
1731*3ba6090fSDavid van Moolenbroek 	if (uval < sizeof(struct bpf_hdr) || uval > BPF_MAXBUFSIZE) e(0);
1732*3ba6090fSDavid van Moolenbroek 
1733*3ba6090fSDavid van Moolenbroek 	uval = 1024; /* ..a value that should be acceptable but small */
1734*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSBLEN, &uval) != 0) e(0);
1735*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGBLEN, &uval) != 0) e(0);
1736*3ba6090fSDavid van Moolenbroek 	if (uval != 1024) e(0);
1737*3ba6090fSDavid van Moolenbroek 
1738*3ba6090fSDavid van Moolenbroek 	/*
1739*3ba6090fSDavid van Moolenbroek 	 * For configured devices, it is not possible to adjust the buffer size
1740*3ba6090fSDavid van Moolenbroek 	 * but it is possible to obtain its size.
1741*3ba6090fSDavid van Moolenbroek 	 */
1742*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCSBLEN, &uval) != -1) e(0);
1743*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
1744*3ba6090fSDavid van Moolenbroek 
1745*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCGBLEN, &uval) != 0) e(0);
1746*3ba6090fSDavid van Moolenbroek 	if (uval != size) e(0);
1747*3ba6090fSDavid van Moolenbroek 
1748*3ba6090fSDavid van Moolenbroek 	/*
1749*3ba6090fSDavid van Moolenbroek 	 * BIOCFLUSH resets both buffer contents and statistics.
1750*3ba6090fSDavid van Moolenbroek 	 */
1751*3ba6090fSDavid van Moolenbroek 	uval = 1;
1752*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCIMMEDIATE, &uval) != 0) e(0);
1753*3ba6090fSDavid van Moolenbroek 
1754*3ba6090fSDavid van Moolenbroek 	test94_fill_exact(fd2, buf, size, 1 /*seq*/);
1755*3ba6090fSDavid van Moolenbroek 	test94_fill_exact(fd2, buf, size, 1 /*seq*/);
1756*3ba6090fSDavid van Moolenbroek 	test94_fill_exact(fd2, buf, size, 1 /*seq*/);
1757*3ba6090fSDavid van Moolenbroek 
1758*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCGSTATS, &bs) != 0) e(0);
1759*3ba6090fSDavid van Moolenbroek 	if (bs.bs_recv == 0) e(0);
1760*3ba6090fSDavid van Moolenbroek 	if (bs.bs_drop == 0) e(0);
1761*3ba6090fSDavid van Moolenbroek 	if (bs.bs_capt == 0) e(0);
1762*3ba6090fSDavid van Moolenbroek 
1763*3ba6090fSDavid van Moolenbroek 	/* Do make sure that statistics are not cleared on retrieval.. */
1764*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCGSTATS, &bs) != 0) e(0);
1765*3ba6090fSDavid van Moolenbroek 	if (bs.bs_recv == 0) e(0);
1766*3ba6090fSDavid van Moolenbroek 	if (bs.bs_drop == 0) e(0);
1767*3ba6090fSDavid van Moolenbroek 	if (bs.bs_capt == 0) e(0);
1768*3ba6090fSDavid van Moolenbroek 
1769*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, FIONREAD, &val) != 0) e(0);
1770*3ba6090fSDavid van Moolenbroek 	if (val == 0) e(0);
1771*3ba6090fSDavid van Moolenbroek 
1772*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCFLUSH) != 0) e(0);
1773*3ba6090fSDavid van Moolenbroek 
1774*3ba6090fSDavid van Moolenbroek 	/* There is a race condition for bs_recv here, so we cannot test it. */
1775*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCGSTATS, &bs) != 0) e(0);
1776*3ba6090fSDavid van Moolenbroek 	if (bs.bs_drop != 0) e(0);
1777*3ba6090fSDavid van Moolenbroek 	if (bs.bs_capt != 0) e(0);
1778*3ba6090fSDavid van Moolenbroek 
1779*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, FIONREAD, &val) != 0) e(0);
1780*3ba6090fSDavid van Moolenbroek 	if (val != 0) e(0);
1781*3ba6090fSDavid van Moolenbroek 
1782*3ba6090fSDavid van Moolenbroek 	/*
1783*3ba6090fSDavid van Moolenbroek 	 * Although practically useless, BIOCFLUSH works on unconfigured
1784*3ba6090fSDavid van Moolenbroek 	 * devices.  So does BIOCGSTATS.
1785*3ba6090fSDavid van Moolenbroek 	 */
1786*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCFLUSH) != 0) e(0);
1787*3ba6090fSDavid van Moolenbroek 
1788*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGSTATS, &bs) != 0) e(0);
1789*3ba6090fSDavid van Moolenbroek 	if (bs.bs_recv != 0) e(0);
1790*3ba6090fSDavid van Moolenbroek 	if (bs.bs_drop != 0) e(0);
1791*3ba6090fSDavid van Moolenbroek 	if (bs.bs_capt != 0) e(0);
1792*3ba6090fSDavid van Moolenbroek 
1793*3ba6090fSDavid van Moolenbroek 	/*
1794*3ba6090fSDavid van Moolenbroek 	 * BIOCPROMISC works on configured devices only.  On loopback devices
1795*3ba6090fSDavid van Moolenbroek 	 * it has no observable effect though.
1796*3ba6090fSDavid van Moolenbroek 	 */
1797*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCPROMISC) != -1) e(0);
1798*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
1799*3ba6090fSDavid van Moolenbroek 
1800*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCPROMISC) != 0) e(0);
1801*3ba6090fSDavid van Moolenbroek 
1802*3ba6090fSDavid van Moolenbroek 	/*
1803*3ba6090fSDavid van Moolenbroek 	 * BIOCGDLT does not work on unconfigured devices.
1804*3ba6090fSDavid van Moolenbroek 	 */
1805*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGDLT, &uval) != -1) e(0);
1806*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
1807*3ba6090fSDavid van Moolenbroek 
1808*3ba6090fSDavid van Moolenbroek 	/*
1809*3ba6090fSDavid van Moolenbroek 	 * BIOCGETIF works only on configured devices, where it returns the
1810*3ba6090fSDavid van Moolenbroek 	 * associated device name.
1811*3ba6090fSDavid van Moolenbroek 	 */
1812*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGETIF, &ifr) != -1) e(0);
1813*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
1814*3ba6090fSDavid van Moolenbroek 
1815*3ba6090fSDavid van Moolenbroek 	memset(&ifr, 'X', sizeof(ifr));
1816*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCGETIF, &ifr) != 0) e(0);
1817*3ba6090fSDavid van Moolenbroek 	if (strcmp(ifr.ifr_name, LOOPBACK_IFNAME) != 0) e(0);
1818*3ba6090fSDavid van Moolenbroek 
1819*3ba6090fSDavid van Moolenbroek 	/*
1820*3ba6090fSDavid van Moolenbroek 	 * BIOCSETIF works only on unconfigured devices, and accepts only valid
1821*3ba6090fSDavid van Moolenbroek 	 * valid interface names.  The name is forced to be null terminated.
1822*3ba6090fSDavid van Moolenbroek 	 */
1823*3ba6090fSDavid van Moolenbroek 	memset(&ifr, 0, sizeof(ifr));
1824*3ba6090fSDavid van Moolenbroek 	strlcpy(ifr.ifr_name, LOOPBACK_IFNAME, sizeof(ifr.ifr_name));
1825*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCSETIF, &ifr) != -1) e(0);
1826*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
1827*3ba6090fSDavid van Moolenbroek 
1828*3ba6090fSDavid van Moolenbroek 	memset(&ifr, 0, sizeof(ifr));
1829*3ba6090fSDavid van Moolenbroek 	memset(ifr.ifr_name, 'x', sizeof(ifr.ifr_name));
1830*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSETIF, &ifr) != -1) e(0);
1831*3ba6090fSDavid van Moolenbroek 	if (errno != ENXIO) e(0);
1832*3ba6090fSDavid van Moolenbroek 
1833*3ba6090fSDavid van Moolenbroek 	/* Anyone that has ten loopback devices is simply insane. */
1834*3ba6090fSDavid van Moolenbroek 	memset(&ifr, 0, sizeof(ifr));
1835*3ba6090fSDavid van Moolenbroek 	strlcpy(ifr.ifr_name, LOOPBACK_IFNAME, sizeof(ifr.ifr_name));
1836*3ba6090fSDavid van Moolenbroek 	ifr.ifr_name[strlen(ifr.ifr_name) - 1] += 9;
1837*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSETIF, &ifr) != -1) e(0);
1838*3ba6090fSDavid van Moolenbroek 	if (errno != ENXIO) e(0);
1839*3ba6090fSDavid van Moolenbroek 
1840*3ba6090fSDavid van Moolenbroek 	/*
1841*3ba6090fSDavid van Moolenbroek 	 * It is possible to turn BIOCIMMEDIATE on and off.  We already enabled
1842*3ba6090fSDavid van Moolenbroek 	 * it a bit higher up.  Note that our implementation does not support
1843*3ba6090fSDavid van Moolenbroek 	 * toggling the setting while a read call is no progress, and toggling
1844*3ba6090fSDavid van Moolenbroek 	 * the setting will have no effect while a select call is in progress;
1845*3ba6090fSDavid van Moolenbroek 	 * similar restrictions apply to effectively all relevant settings.
1846*3ba6090fSDavid van Moolenbroek 	 * Either way we do not test that here either.
1847*3ba6090fSDavid van Moolenbroek 	 */
1848*3ba6090fSDavid van Moolenbroek 	test94_add_random(fd2, buf, size, 1 /*seq*/);
1849*3ba6090fSDavid van Moolenbroek 
1850*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, FIONREAD, &val) != 0) e(0);
1851*3ba6090fSDavid van Moolenbroek 	if (val == 0) e(0);
1852*3ba6090fSDavid van Moolenbroek 
1853*3ba6090fSDavid van Moolenbroek 	uval = 0;
1854*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCIMMEDIATE, &uval) != 0) e(0);
1855*3ba6090fSDavid van Moolenbroek 
1856*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, FIONREAD, &val) != 0) e(0);
1857*3ba6090fSDavid van Moolenbroek 	if (val != 0) e(0);
1858*3ba6090fSDavid van Moolenbroek 
1859*3ba6090fSDavid van Moolenbroek 	uval = 1;
1860*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCIMMEDIATE, &uval) != 0) e(0);
1861*3ba6090fSDavid van Moolenbroek 
1862*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, FIONREAD, &val) != 0) e(0);
1863*3ba6090fSDavid van Moolenbroek 	if (val == 0) e(0);
1864*3ba6090fSDavid van Moolenbroek 
1865*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCFLUSH) != 0) e(0);
1866*3ba6090fSDavid van Moolenbroek 
1867*3ba6090fSDavid van Moolenbroek 	/*
1868*3ba6090fSDavid van Moolenbroek 	 * BIOCIMMEDIATE also works on unconfigured devices.
1869*3ba6090fSDavid van Moolenbroek 	 */
1870*3ba6090fSDavid van Moolenbroek 	uval = 1;
1871*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCIMMEDIATE, &uval) != 0) e(0);
1872*3ba6090fSDavid van Moolenbroek 
1873*3ba6090fSDavid van Moolenbroek 	uval = 0;
1874*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCIMMEDIATE, &uval) != 0) e(0);
1875*3ba6090fSDavid van Moolenbroek 
1876*3ba6090fSDavid van Moolenbroek 	/*
1877*3ba6090fSDavid van Moolenbroek 	 * BIOCVERSION should return the current BPF interface version.
1878*3ba6090fSDavid van Moolenbroek 	 */
1879*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCVERSION, &bv) != 0) e(0);
1880*3ba6090fSDavid van Moolenbroek 	if (bv.bv_major != BPF_MAJOR_VERSION) e(0);
1881*3ba6090fSDavid van Moolenbroek 	if (bv.bv_minor != BPF_MINOR_VERSION) e(0);
1882*3ba6090fSDavid van Moolenbroek 
1883*3ba6090fSDavid van Moolenbroek 	/*
1884*3ba6090fSDavid van Moolenbroek 	 * BIOCSHDRCMPLT makes sense only for devices with data link headers,
1885*3ba6090fSDavid van Moolenbroek 	 * which rules out loopback devices.  Check the default and test
1886*3ba6090fSDavid van Moolenbroek 	 * toggling it, and stop there.
1887*3ba6090fSDavid van Moolenbroek 	 */
1888*3ba6090fSDavid van Moolenbroek 	/* The default value is off. */
1889*3ba6090fSDavid van Moolenbroek 	uval = 1;
1890*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGHDRCMPLT, &uval) != 0) e(0);
1891*3ba6090fSDavid van Moolenbroek 	if (uval != 0) e(0);
1892*3ba6090fSDavid van Moolenbroek 
1893*3ba6090fSDavid van Moolenbroek 	uval = 2;
1894*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSHDRCMPLT, &uval) != 0) e(0);
1895*3ba6090fSDavid van Moolenbroek 
1896*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGHDRCMPLT, &uval) != 0) e(0);
1897*3ba6090fSDavid van Moolenbroek 	if (uval != 1) e(0);
1898*3ba6090fSDavid van Moolenbroek 
1899*3ba6090fSDavid van Moolenbroek 	uval = 0;
1900*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSHDRCMPLT, &uval) != 0) e(0);
1901*3ba6090fSDavid van Moolenbroek 
1902*3ba6090fSDavid van Moolenbroek 	uval = 1;
1903*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGHDRCMPLT, &uval) != 0) e(0);
1904*3ba6090fSDavid van Moolenbroek 	if (uval != 0) e(0);
1905*3ba6090fSDavid van Moolenbroek 
1906*3ba6090fSDavid van Moolenbroek 	/*
1907*3ba6090fSDavid van Moolenbroek 	 * BIOCSDLT works on configured devices.  For loopback devices, it can
1908*3ba6090fSDavid van Moolenbroek 	 * only set the data link type to its current value, which on MINIX3
1909*3ba6090fSDavid van Moolenbroek 	 * for loopback devices is DLT_RAW (i.e., no headers at all).
1910*3ba6090fSDavid van Moolenbroek 	 */
1911*3ba6090fSDavid van Moolenbroek 	uval = DLT_RAW;
1912*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSDLT, &uval) != -1) e(0);
1913*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
1914*3ba6090fSDavid van Moolenbroek 
1915*3ba6090fSDavid van Moolenbroek 	uval = DLT_RAW;
1916*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCSDLT, &uval) != 0) e(0);
1917*3ba6090fSDavid van Moolenbroek 
1918*3ba6090fSDavid van Moolenbroek 	uval = DLT_NULL;
1919*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCSDLT, &uval) != -1) e(0);
1920*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
1921*3ba6090fSDavid van Moolenbroek 
1922*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCGDLT, &uval) != 0) e(0);
1923*3ba6090fSDavid van Moolenbroek 	if (uval != DLT_RAW) e(0);
1924*3ba6090fSDavid van Moolenbroek 
1925*3ba6090fSDavid van Moolenbroek 	/*
1926*3ba6090fSDavid van Moolenbroek 	 * BIOCGDLTLIST works on configured devices only, and may be used to
1927*3ba6090fSDavid van Moolenbroek 	 * both query the size of the list and obtain the list.  On MINIX3,
1928*3ba6090fSDavid van Moolenbroek 	 * loopback devices will only ever return DLT_RAW.  Unfortunately,
1929*3ba6090fSDavid van Moolenbroek 	 * much of the handling for this IOCTL is in libc for us, which is also
1930*3ba6090fSDavid van Moolenbroek 	 * why we do not test bad pointers and stuff like that.
1931*3ba6090fSDavid van Moolenbroek 	 */
1932*3ba6090fSDavid van Moolenbroek 	memset(&bfl, 0, sizeof(bfl));
1933*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGDLTLIST, &bfl) != -1) e(0);
1934*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
1935*3ba6090fSDavid van Moolenbroek 
1936*3ba6090fSDavid van Moolenbroek 	memset(&bfl, 0, sizeof(bfl));
1937*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCGDLTLIST, &bfl) != 0) e(0);
1938*3ba6090fSDavid van Moolenbroek 	if (bfl.bfl_len != 1) e(0);
1939*3ba6090fSDavid van Moolenbroek 	if (bfl.bfl_list != NULL) e(0);
1940*3ba6090fSDavid van Moolenbroek 
1941*3ba6090fSDavid van Moolenbroek 	memset(&bfl, 0, sizeof(bfl));
1942*3ba6090fSDavid van Moolenbroek 	bfl.bfl_len = 2;	/* should be ignored */
1943*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCGDLTLIST, &bfl) != 0) e(0);
1944*3ba6090fSDavid van Moolenbroek 	if (bfl.bfl_len != 1) e(0);
1945*3ba6090fSDavid van Moolenbroek 	if (bfl.bfl_list != NULL) e(0);
1946*3ba6090fSDavid van Moolenbroek 
1947*3ba6090fSDavid van Moolenbroek 	memset(&bfl, 0, sizeof(bfl));
1948*3ba6090fSDavid van Moolenbroek 	memset(list, 0, sizeof(list));
1949*3ba6090fSDavid van Moolenbroek 	bfl.bfl_list = list;
1950*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCGDLTLIST, &bfl) != -1) e(0);
1951*3ba6090fSDavid van Moolenbroek 	if (errno != ENOMEM) e(0);
1952*3ba6090fSDavid van Moolenbroek 	if (list[0] != 0) e(0);
1953*3ba6090fSDavid van Moolenbroek 
1954*3ba6090fSDavid van Moolenbroek 	memset(&bfl, 0, sizeof(bfl));
1955*3ba6090fSDavid van Moolenbroek 	bfl.bfl_len = 1;
1956*3ba6090fSDavid van Moolenbroek 	bfl.bfl_list = list;
1957*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCGDLTLIST, &bfl) != 0) e(0);
1958*3ba6090fSDavid van Moolenbroek 	if (bfl.bfl_len != 1) e(0);
1959*3ba6090fSDavid van Moolenbroek 	if (bfl.bfl_list != list) e(0);
1960*3ba6090fSDavid van Moolenbroek 	if (list[0] != DLT_RAW) e(0);
1961*3ba6090fSDavid van Moolenbroek 	if (list[1] != 0) e(0);
1962*3ba6090fSDavid van Moolenbroek 
1963*3ba6090fSDavid van Moolenbroek 	memset(&bfl, 0, sizeof(bfl));
1964*3ba6090fSDavid van Moolenbroek 	memset(list, 0, sizeof(list));
1965*3ba6090fSDavid van Moolenbroek 	bfl.bfl_len = 2;
1966*3ba6090fSDavid van Moolenbroek 	bfl.bfl_list = list;
1967*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCGDLTLIST, &bfl) != 0) e(0);
1968*3ba6090fSDavid van Moolenbroek 	if (bfl.bfl_len != 1) e(0);
1969*3ba6090fSDavid van Moolenbroek 	if (bfl.bfl_list != list) e(0);
1970*3ba6090fSDavid van Moolenbroek 	if (list[0] != DLT_RAW) e(0);
1971*3ba6090fSDavid van Moolenbroek 	if (list[1] != 0) e(0);
1972*3ba6090fSDavid van Moolenbroek 
1973*3ba6090fSDavid van Moolenbroek 	/*
1974*3ba6090fSDavid van Moolenbroek 	 * For loopback devices, BIOCSSEESENT is a bit weird: packets are
1975*3ba6090fSDavid van Moolenbroek 	 * captured on output to get a complete view of loopback traffic, and
1976*3ba6090fSDavid van Moolenbroek 	 * not also on input because that would then duplicate the traffic.  As
1977*3ba6090fSDavid van Moolenbroek 	 * a result, turning off BIOCSSEESENT for a loopback device means that
1978*3ba6090fSDavid van Moolenbroek 	 * no packets will be captured at all anymore.  First test the default
1979*3ba6090fSDavid van Moolenbroek 	 * and toggling on the unconfigured device, then reproduce the above on
1980*3ba6090fSDavid van Moolenbroek 	 * the configured device.
1981*3ba6090fSDavid van Moolenbroek 	 */
1982*3ba6090fSDavid van Moolenbroek 	/* The default value is on. */
1983*3ba6090fSDavid van Moolenbroek 	uval = 0;
1984*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGSEESENT, &uval) != 0) e(0);
1985*3ba6090fSDavid van Moolenbroek 	if (uval != 1) e(0);
1986*3ba6090fSDavid van Moolenbroek 
1987*3ba6090fSDavid van Moolenbroek 	uval = 0;
1988*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSSEESENT, &uval) != 0) e(0);
1989*3ba6090fSDavid van Moolenbroek 
1990*3ba6090fSDavid van Moolenbroek 	uval = 1;
1991*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGSEESENT, &uval) != 0) e(0);
1992*3ba6090fSDavid van Moolenbroek 	if (uval != 0) e(0);
1993*3ba6090fSDavid van Moolenbroek 
1994*3ba6090fSDavid van Moolenbroek 	uval = 2;
1995*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSSEESENT, &uval) != 0) e(0);
1996*3ba6090fSDavid van Moolenbroek 
1997*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGSEESENT, &uval) != 0) e(0);
1998*3ba6090fSDavid van Moolenbroek 	if (uval != 1) e(0);
1999*3ba6090fSDavid van Moolenbroek 
2000*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCGSEESENT, &uval) != 0) e(0);
2001*3ba6090fSDavid van Moolenbroek 	if (uval != 1) e(0);
2002*3ba6090fSDavid van Moolenbroek 
2003*3ba6090fSDavid van Moolenbroek 	uval = 0;
2004*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCSSEESENT, &uval) != 0) e(0);
2005*3ba6090fSDavid van Moolenbroek 
2006*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCFLUSH) != 0) e(0);
2007*3ba6090fSDavid van Moolenbroek 
2008*3ba6090fSDavid van Moolenbroek 	test94_add_random(fd2, buf, size, 1 /*seq*/);
2009*3ba6090fSDavid van Moolenbroek 
2010*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCGSTATS, &bs) != 0) e(0);
2011*3ba6090fSDavid van Moolenbroek 	if (bs.bs_recv != 0) e(0);
2012*3ba6090fSDavid van Moolenbroek 
2013*3ba6090fSDavid van Moolenbroek 	uval = 1;
2014*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCSSEESENT, &uval) != 0) e(0);
2015*3ba6090fSDavid van Moolenbroek 
2016*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCFLUSH) != 0) e(0);
2017*3ba6090fSDavid van Moolenbroek 
2018*3ba6090fSDavid van Moolenbroek 	test94_add_random(fd2, buf, size, 1 /*seq*/);
2019*3ba6090fSDavid van Moolenbroek 
2020*3ba6090fSDavid van Moolenbroek 	if (ioctl(cfd, BIOCGSTATS, &bs) != 0) e(0);
2021*3ba6090fSDavid van Moolenbroek 	if (bs.bs_recv == 0) e(0);
2022*3ba6090fSDavid van Moolenbroek 
2023*3ba6090fSDavid van Moolenbroek 	/*
2024*3ba6090fSDavid van Moolenbroek 	 * The BIOCSRTIMEOUT values are rounded up to clock granularity.
2025*3ba6090fSDavid van Moolenbroek 	 * Invalid timeout values are rejected.
2026*3ba6090fSDavid van Moolenbroek 	 */
2027*3ba6090fSDavid van Moolenbroek 	/* The default value is zero. */
2028*3ba6090fSDavid van Moolenbroek 	tv.tv_sec = 99;
2029*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGRTIMEOUT, &tv) != 0) e(0);
2030*3ba6090fSDavid van Moolenbroek 	if (tv.tv_sec != 0) e(0);
2031*3ba6090fSDavid van Moolenbroek 	if (tv.tv_usec != 0) e(0);
2032*3ba6090fSDavid van Moolenbroek 
2033*3ba6090fSDavid van Moolenbroek 	tv.tv_usec = 1000000;
2034*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSRTIMEOUT, &tv) != -1) e(0);
2035*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
2036*3ba6090fSDavid van Moolenbroek 
2037*3ba6090fSDavid van Moolenbroek 	tv.tv_usec = -1;
2038*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSRTIMEOUT, &tv) != -1) e(0);
2039*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
2040*3ba6090fSDavid van Moolenbroek 
2041*3ba6090fSDavid van Moolenbroek 	tv.tv_sec = -1;
2042*3ba6090fSDavid van Moolenbroek 	tv.tv_usec = 0;
2043*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSRTIMEOUT, &tv) != -1) e(0);
2044*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
2045*3ba6090fSDavid van Moolenbroek 
2046*3ba6090fSDavid van Moolenbroek 	tv.tv_sec = INT_MAX;
2047*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSRTIMEOUT, &tv) != -1) e(0);
2048*3ba6090fSDavid van Moolenbroek 	if (errno != EDOM) e(0);
2049*3ba6090fSDavid van Moolenbroek 
2050*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGRTIMEOUT, &tv) != 0) e(0);
2051*3ba6090fSDavid van Moolenbroek 	if (tv.tv_sec != 0) e(0);
2052*3ba6090fSDavid van Moolenbroek 	if (tv.tv_usec != 0) e(0);
2053*3ba6090fSDavid van Moolenbroek 
2054*3ba6090fSDavid van Moolenbroek 	tv.tv_sec = 123;
2055*3ba6090fSDavid van Moolenbroek 	tv.tv_usec = 1;
2056*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSRTIMEOUT, &tv) != 0) e(0);
2057*3ba6090fSDavid van Moolenbroek 
2058*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGRTIMEOUT, &tv) != 0) e(0);
2059*3ba6090fSDavid van Moolenbroek 	if (tv.tv_sec != 123) e(0);
2060*3ba6090fSDavid van Moolenbroek 	if (tv.tv_usec == 0) e(0); /* rounding should be up */
2061*3ba6090fSDavid van Moolenbroek 
2062*3ba6090fSDavid van Moolenbroek 	tv.tv_sec = 0;
2063*3ba6090fSDavid van Moolenbroek 	tv.tv_usec = 0;
2064*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSRTIMEOUT, &tv) != 0) e(0);
2065*3ba6090fSDavid van Moolenbroek 
2066*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGRTIMEOUT, &tv) != 0) e(0);
2067*3ba6090fSDavid van Moolenbroek 	if (tv.tv_sec != 0) e(0);
2068*3ba6090fSDavid van Moolenbroek 	if (tv.tv_usec != 0) e(0);
2069*3ba6090fSDavid van Moolenbroek 
2070*3ba6090fSDavid van Moolenbroek 	/*
2071*3ba6090fSDavid van Moolenbroek 	 * BIOCSFEEDBACK is another weird setting for which we only test
2072*3ba6090fSDavid van Moolenbroek 	 * default and toggling here.
2073*3ba6090fSDavid van Moolenbroek 	 */
2074*3ba6090fSDavid van Moolenbroek 	/* The default value is off. */
2075*3ba6090fSDavid van Moolenbroek 	uval = 1;
2076*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGFEEDBACK, &uval) != 0) e(0);
2077*3ba6090fSDavid van Moolenbroek 	if (uval != 0) e(0);
2078*3ba6090fSDavid van Moolenbroek 
2079*3ba6090fSDavid van Moolenbroek 	uval = 2;
2080*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSFEEDBACK, &uval) != 0) e(0);
2081*3ba6090fSDavid van Moolenbroek 
2082*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGFEEDBACK, &uval) != 0) e(0);
2083*3ba6090fSDavid van Moolenbroek 	if (uval != 1) e(0);
2084*3ba6090fSDavid van Moolenbroek 
2085*3ba6090fSDavid van Moolenbroek 	uval = 0;
2086*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCSFEEDBACK, &uval) != 0) e(0);
2087*3ba6090fSDavid van Moolenbroek 
2088*3ba6090fSDavid van Moolenbroek 	uval = 1;
2089*3ba6090fSDavid van Moolenbroek 	if (ioctl(ufd, BIOCGFEEDBACK, &uval) != 0) e(0);
2090*3ba6090fSDavid van Moolenbroek 	if (uval != 0) e(0);
2091*3ba6090fSDavid van Moolenbroek 
2092*3ba6090fSDavid van Moolenbroek 	/* Clean up. */
2093*3ba6090fSDavid van Moolenbroek 	if (close(ufd) != 0) e(0);
2094*3ba6090fSDavid van Moolenbroek 
2095*3ba6090fSDavid van Moolenbroek 	test94_cleanup(cfd, fd2, fd3, buf);
2096*3ba6090fSDavid van Moolenbroek }
2097*3ba6090fSDavid van Moolenbroek 
2098*3ba6090fSDavid van Moolenbroek /* IPv6 version of our filter. */
2099*3ba6090fSDavid van Moolenbroek static struct bpf_insn test94_filter6[] = {
2100*3ba6090fSDavid van Moolenbroek 	{ BPF_LD+BPF_B+BPF_ABS, 0, 0, 0 },	/* is this an IPv6 header? */
2101*3ba6090fSDavid van Moolenbroek 	{ BPF_ALU+BPF_RSH+BPF_K, 0, 0, 4 },
2102*3ba6090fSDavid van Moolenbroek 	{ BPF_JMP+BPF_JEQ+BPF_K, 0, 6, 6 },
2103*3ba6090fSDavid van Moolenbroek 	{ BPF_LD+BPF_B+BPF_ABS, 0, 0, 6 },	/* is this a UDP packet? */
2104*3ba6090fSDavid van Moolenbroek 	{ BPF_JMP+BPF_JEQ+BPF_K, 0, 4, IPPROTO_UDP },
2105*3ba6090fSDavid van Moolenbroek 	{ BPF_LD+BPF_H+BPF_ABS, 0, 0, 40 },	/* source port 12345? */
2106*3ba6090fSDavid van Moolenbroek 	{ BPF_JMP+BPF_JEQ+BPF_K, 0, 2, TEST_PORT_A },
2107*3ba6090fSDavid van Moolenbroek 	{ BPF_LD+BPF_H+BPF_ABS, 0, 0, 42 },	/* destination port 12346? */
2108*3ba6090fSDavid van Moolenbroek 	{ BPF_JMP+BPF_JEQ+BPF_K, 1, 0, TEST_PORT_B },
2109*3ba6090fSDavid van Moolenbroek 	{ BPF_RET+BPF_K, 0, 0, 0 },		/* reject the packet */
2110*3ba6090fSDavid van Moolenbroek 	{ BPF_RET+BPF_K, 0, 0, (uint32_t)-1 },	/* accept the (whole) packet */
2111*3ba6090fSDavid van Moolenbroek };
2112*3ba6090fSDavid van Moolenbroek 
2113*3ba6090fSDavid van Moolenbroek /*
2114*3ba6090fSDavid van Moolenbroek  * Test receipt of IPv6 packets, because it was getting a bit messy to
2115*3ba6090fSDavid van Moolenbroek  * integrate that into the previous subtests.  We just want to make sure that
2116*3ba6090fSDavid van Moolenbroek  * IPv6 packets are properly filtered and captured at all.  The rest of the
2117*3ba6090fSDavid van Moolenbroek  * code is entirely version agnostic anyway.
2118*3ba6090fSDavid van Moolenbroek  */
2119*3ba6090fSDavid van Moolenbroek static void
test94i(void)2120*3ba6090fSDavid van Moolenbroek test94i(void)
2121*3ba6090fSDavid van Moolenbroek {
2122*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in6 sin6A, sin6B;
2123*3ba6090fSDavid van Moolenbroek 	struct bpf_program bf;
2124*3ba6090fSDavid van Moolenbroek 	struct bpf_stat bs;
2125*3ba6090fSDavid van Moolenbroek 	struct bpf_hdr bh;
2126*3ba6090fSDavid van Moolenbroek 	struct ifreq ifr;
2127*3ba6090fSDavid van Moolenbroek 	struct ip6_hdr ip6;
2128*3ba6090fSDavid van Moolenbroek 	struct udphdr uh;
2129*3ba6090fSDavid van Moolenbroek 	uint8_t *buf, c;
2130*3ba6090fSDavid van Moolenbroek 	socklen_t socklen;
2131*3ba6090fSDavid van Moolenbroek 	ssize_t len;
2132*3ba6090fSDavid van Moolenbroek 	size_t off;
2133*3ba6090fSDavid van Moolenbroek 	unsigned int uval, size, dlt;
2134*3ba6090fSDavid van Moolenbroek 	int fd, fd2, fd3;
2135*3ba6090fSDavid van Moolenbroek 
2136*3ba6090fSDavid van Moolenbroek 	subtest = 9;
2137*3ba6090fSDavid van Moolenbroek 
2138*3ba6090fSDavid van Moolenbroek 	if ((fd = open(_PATH_BPF, O_RDWR)) < 0) e(0);
2139*3ba6090fSDavid van Moolenbroek 
2140*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCGBLEN, &size) != 0) e(0);
2141*3ba6090fSDavid van Moolenbroek 	if (size < 1024 || size > BPF_MAXBUFSIZE) e(0);
2142*3ba6090fSDavid van Moolenbroek 
2143*3ba6090fSDavid van Moolenbroek 	if ((buf = malloc(size)) == NULL) e(0);
2144*3ba6090fSDavid van Moolenbroek 
2145*3ba6090fSDavid van Moolenbroek 	/* Install the filter. */
2146*3ba6090fSDavid van Moolenbroek 	memset(&bf, 0, sizeof(bf));
2147*3ba6090fSDavid van Moolenbroek 	bf.bf_len = __arraycount(test94_filter6);
2148*3ba6090fSDavid van Moolenbroek 	bf.bf_insns = test94_filter6;
2149*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSETF, &bf) != 0) e(0);
2150*3ba6090fSDavid van Moolenbroek 
2151*3ba6090fSDavid van Moolenbroek 	uval = 1;
2152*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCIMMEDIATE, &uval) != 0) e(0);
2153*3ba6090fSDavid van Moolenbroek 
2154*3ba6090fSDavid van Moolenbroek 	/* Bind to the loopback device. */
2155*3ba6090fSDavid van Moolenbroek 	memset(&ifr, 0, sizeof(ifr));
2156*3ba6090fSDavid van Moolenbroek 	strlcpy(ifr.ifr_name, LOOPBACK_IFNAME, sizeof(ifr.ifr_name));
2157*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSETIF, &ifr) != 0) e(0);
2158*3ba6090fSDavid van Moolenbroek 
2159*3ba6090fSDavid van Moolenbroek 	/*
2160*3ba6090fSDavid van Moolenbroek 	 * If the loopback device's data link type is not DLT_RAW, our filter
2161*3ba6090fSDavid van Moolenbroek 	 * and size calculations will not work.
2162*3ba6090fSDavid van Moolenbroek 	 */
2163*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCGDLT, &dlt) != 0) e(0);
2164*3ba6090fSDavid van Moolenbroek 	if (dlt != DLT_RAW) e(0);
2165*3ba6090fSDavid van Moolenbroek 
2166*3ba6090fSDavid van Moolenbroek 	/* We use UDP traffic for our test packets. */
2167*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) e(0);
2168*3ba6090fSDavid van Moolenbroek 
2169*3ba6090fSDavid van Moolenbroek 	memset(&sin6A, 0, sizeof(sin6A));
2170*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_family = AF_INET6;
2171*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_port = htons(TEST_PORT_A);
2172*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6A.sin6_addr, &in6addr_loopback, sizeof(sin6A.sin6_addr));
2173*3ba6090fSDavid van Moolenbroek 	if (bind(fd2, (struct sockaddr *)&sin6A, sizeof(sin6A)) != 0) e(0);
2174*3ba6090fSDavid van Moolenbroek 
2175*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6B, &sin6A, sizeof(sin6B));
2176*3ba6090fSDavid van Moolenbroek 	sin6B.sin6_port = htons(TEST_PORT_B);
2177*3ba6090fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sin6B, sizeof(sin6B)) != 0) e(0);
2178*3ba6090fSDavid van Moolenbroek 
2179*3ba6090fSDavid van Moolenbroek 	if ((fd3 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) e(0);
2180*3ba6090fSDavid van Moolenbroek 
2181*3ba6090fSDavid van Moolenbroek 	if (bind(fd3, (struct sockaddr *)&sin6B, sizeof(sin6B)) != 0) e(0);
2182*3ba6090fSDavid van Moolenbroek 
2183*3ba6090fSDavid van Moolenbroek 	if (connect(fd3, (struct sockaddr *)&sin6A, sizeof(sin6A)) != 0) e(0);
2184*3ba6090fSDavid van Moolenbroek 
2185*3ba6090fSDavid van Moolenbroek 	if (write(fd2, "A", 1) != 1) e(0);
2186*3ba6090fSDavid van Moolenbroek 
2187*3ba6090fSDavid van Moolenbroek 	if (read(fd3, &c, 1) != 1) e(0);
2188*3ba6090fSDavid van Moolenbroek 	if (c != 'A') e(0);
2189*3ba6090fSDavid van Moolenbroek 
2190*3ba6090fSDavid van Moolenbroek 	if (write(fd3, "B", 1) != 1) e(0);
2191*3ba6090fSDavid van Moolenbroek 
2192*3ba6090fSDavid van Moolenbroek 	if (read(fd2, &c, 1) != 1) e(0);
2193*3ba6090fSDavid van Moolenbroek 	if (c != 'B') e(0);
2194*3ba6090fSDavid van Moolenbroek 
2195*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCGSTATS, &bs) != 0) e(0);
2196*3ba6090fSDavid van Moolenbroek 	if (bs.bs_recv < 2) e(0);
2197*3ba6090fSDavid van Moolenbroek 	if (bs.bs_capt != 1) e(0);
2198*3ba6090fSDavid van Moolenbroek 	if (bs.bs_drop != 0) e(0);
2199*3ba6090fSDavid van Moolenbroek 
2200*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, size);
2201*3ba6090fSDavid van Moolenbroek 
2202*3ba6090fSDavid van Moolenbroek 	len = read(fd, buf, size);
2203*3ba6090fSDavid van Moolenbroek 
2204*3ba6090fSDavid van Moolenbroek 	if (len != BPF_WORDALIGN(sizeof(bh)) +
2205*3ba6090fSDavid van Moolenbroek 	    BPF_WORDALIGN(sizeof(ip6) + sizeof(uh) + 1)) e(0);
2206*3ba6090fSDavid van Moolenbroek 
2207*3ba6090fSDavid van Moolenbroek 	memcpy(&bh, buf, sizeof(bh));
2208*3ba6090fSDavid van Moolenbroek 
2209*3ba6090fSDavid van Moolenbroek 	if (bh.bh_tstamp.tv_sec == 0 && bh.bh_tstamp.tv_usec == 0) e(0);
2210*3ba6090fSDavid van Moolenbroek 	if (bh.bh_caplen != sizeof(ip6) + sizeof(uh) + 1) e(0);
2211*3ba6090fSDavid van Moolenbroek 	if (bh.bh_datalen != bh.bh_caplen) e(0);
2212*3ba6090fSDavid van Moolenbroek 	if (bh.bh_hdrlen != BPF_WORDALIGN(sizeof(bh))) e(0);
2213*3ba6090fSDavid van Moolenbroek 
2214*3ba6090fSDavid van Moolenbroek 	if (buf[bh.bh_hdrlen + sizeof(ip6) + sizeof(uh)] != 'A') e(0);
2215*3ba6090fSDavid van Moolenbroek 
2216*3ba6090fSDavid van Moolenbroek 	/*
2217*3ba6090fSDavid van Moolenbroek 	 * Finally, do a quick test to see if we can send IPv6 packets by
2218*3ba6090fSDavid van Moolenbroek 	 * writing to the BPF device.  We rely on such packets being generated
2219*3ba6090fSDavid van Moolenbroek 	 * properly in a later test.
2220*3ba6090fSDavid van Moolenbroek 	 */
2221*3ba6090fSDavid van Moolenbroek 	off = test94_make_pkt(buf, 6, 1 /*v6*/);
2222*3ba6090fSDavid van Moolenbroek 	memcpy(buf + off, "Hello!", 6);
2223*3ba6090fSDavid van Moolenbroek 
2224*3ba6090fSDavid van Moolenbroek 	if (write(fd, buf, off + 6) != off + 6) e(0);
2225*3ba6090fSDavid van Moolenbroek 
2226*3ba6090fSDavid van Moolenbroek 	socklen = sizeof(sin6A);
2227*3ba6090fSDavid van Moolenbroek 	if (recvfrom(fd3, buf, size, 0, (struct sockaddr *)&sin6A,
2228*3ba6090fSDavid van Moolenbroek 	    &socklen) != 6) e(0);
2229*3ba6090fSDavid van Moolenbroek 
2230*3ba6090fSDavid van Moolenbroek 	if (memcmp(buf, "Hello!", 6) != 0) e(0);
2231*3ba6090fSDavid van Moolenbroek 	if (socklen != sizeof(sin6A)) e(0);
2232*3ba6090fSDavid van Moolenbroek 	if (sin6A.sin6_family != AF_INET6) e(0);
2233*3ba6090fSDavid van Moolenbroek 	if (sin6A.sin6_port != htons(TEST_PORT_A)) e(0);
2234*3ba6090fSDavid van Moolenbroek 	if (memcmp(&sin6A.sin6_addr, &in6addr_loopback,
2235*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A.sin6_addr)) != 0) e(0);
2236*3ba6090fSDavid van Moolenbroek 
2237*3ba6090fSDavid van Moolenbroek 	free(buf);
2238*3ba6090fSDavid van Moolenbroek 
2239*3ba6090fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
2240*3ba6090fSDavid van Moolenbroek 
2241*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
2242*3ba6090fSDavid van Moolenbroek 
2243*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
2244*3ba6090fSDavid van Moolenbroek }
2245*3ba6090fSDavid van Moolenbroek 
2246*3ba6090fSDavid van Moolenbroek /*
2247*3ba6090fSDavid van Moolenbroek  * Test the BPF sysctl(7) interface at a basic level.
2248*3ba6090fSDavid van Moolenbroek  */
2249*3ba6090fSDavid van Moolenbroek static void
test94j(void)2250*3ba6090fSDavid van Moolenbroek test94j(void)
2251*3ba6090fSDavid van Moolenbroek {
2252*3ba6090fSDavid van Moolenbroek 	struct bpf_stat bs1, bs2;
2253*3ba6090fSDavid van Moolenbroek 	struct bpf_d_ext *bde;
2254*3ba6090fSDavid van Moolenbroek 	uint8_t *buf;
2255*3ba6090fSDavid van Moolenbroek 	unsigned int slot, count, uval;
2256*3ba6090fSDavid van Moolenbroek 	size_t len, oldlen, size, bdesize;
2257*3ba6090fSDavid van Moolenbroek 	int fd, fd2, fd3, val, mib[5], smib[3], found;
2258*3ba6090fSDavid van Moolenbroek 
2259*3ba6090fSDavid van Moolenbroek 	subtest = 10;
2260*3ba6090fSDavid van Moolenbroek 
2261*3ba6090fSDavid van Moolenbroek 	/*
2262*3ba6090fSDavid van Moolenbroek 	 * Obtain the maximum buffer size.  The value must be sane.
2263*3ba6090fSDavid van Moolenbroek 	 */
2264*3ba6090fSDavid van Moolenbroek 	memset(mib, 0, sizeof(mib));
2265*3ba6090fSDavid van Moolenbroek 	len = __arraycount(mib);
2266*3ba6090fSDavid van Moolenbroek 	if (sysctlnametomib("net.bpf.maxbufsize", mib, &len) != 0) e(0);
2267*3ba6090fSDavid van Moolenbroek 	if (len != 3) e(0);
2268*3ba6090fSDavid van Moolenbroek 
2269*3ba6090fSDavid van Moolenbroek 	oldlen = sizeof(val);
2270*3ba6090fSDavid van Moolenbroek 	if (sysctl(mib, len, &val, &oldlen, NULL, 0) != 0) e(0);
2271*3ba6090fSDavid van Moolenbroek 	if (oldlen != sizeof(val)) e(0);
2272*3ba6090fSDavid van Moolenbroek 
2273*3ba6090fSDavid van Moolenbroek 	if (val < 1024 || val > INT_MAX / 2) e(0);
2274*3ba6090fSDavid van Moolenbroek 
2275*3ba6090fSDavid van Moolenbroek 	/*
2276*3ba6090fSDavid van Moolenbroek 	 * Attempt to set the maximum buffer size.  This is not (yet) supported
2277*3ba6090fSDavid van Moolenbroek 	 * so for now we want to make sure that it really does not work.
2278*3ba6090fSDavid van Moolenbroek 	 */
2279*3ba6090fSDavid van Moolenbroek 	if (sysctl(mib, len, NULL, NULL, &val, sizeof(val)) != -1) e(0);
2280*3ba6090fSDavid van Moolenbroek 	if (errno != EPERM) e(0);
2281*3ba6090fSDavid van Moolenbroek 
2282*3ba6090fSDavid van Moolenbroek 	/*
2283*3ba6090fSDavid van Moolenbroek 	 * Obtain global statistics.  We check the actual statistics later on.
2284*3ba6090fSDavid van Moolenbroek 	 */
2285*3ba6090fSDavid van Moolenbroek 	memset(smib, 0, sizeof(smib));
2286*3ba6090fSDavid van Moolenbroek 	len = __arraycount(smib);
2287*3ba6090fSDavid van Moolenbroek 	if (sysctlnametomib("net.bpf.stats", smib, &len) != 0) e(0);
2288*3ba6090fSDavid van Moolenbroek 	if (len != 3) e(0);
2289*3ba6090fSDavid van Moolenbroek 
2290*3ba6090fSDavid van Moolenbroek 	oldlen = sizeof(bs1);
2291*3ba6090fSDavid van Moolenbroek 	if (sysctl(smib, len, &bs1, &oldlen, NULL, 0) != 0) e(0);
2292*3ba6090fSDavid van Moolenbroek 	if (oldlen != sizeof(bs1)) e(0);
2293*3ba6090fSDavid van Moolenbroek 
2294*3ba6090fSDavid van Moolenbroek 	/*
2295*3ba6090fSDavid van Moolenbroek 	 * Set up a BPF descriptor, and retrieve the list of BPF peers.  We
2296*3ba6090fSDavid van Moolenbroek 	 * should be able to find our BPF peer.
2297*3ba6090fSDavid van Moolenbroek 	 */
2298*3ba6090fSDavid van Moolenbroek 	memset(mib, 0, sizeof(mib));
2299*3ba6090fSDavid van Moolenbroek 	len = __arraycount(mib);
2300*3ba6090fSDavid van Moolenbroek 	if (sysctlnametomib("net.bpf.peers", mib, &len) != 0) e(0);
2301*3ba6090fSDavid van Moolenbroek 	if (len != 3) e(0);
2302*3ba6090fSDavid van Moolenbroek 	mib[len++] = sizeof(*bde);	/* size of each element */
2303*3ba6090fSDavid van Moolenbroek 	mib[len++] = INT_MAX;		/* limit on elements to return */
2304*3ba6090fSDavid van Moolenbroek 
2305*3ba6090fSDavid van Moolenbroek 	size = test94_setup(&fd, &fd2, &fd3, &buf, 0 /*size*/,
2306*3ba6090fSDavid van Moolenbroek 	    1 /*set_filter*/);
2307*3ba6090fSDavid van Moolenbroek 
2308*3ba6090fSDavid van Moolenbroek 	/* Generate some traffic to bump the statistics. */
2309*3ba6090fSDavid van Moolenbroek 	count = test94_fill_exact(fd2, buf, size, 0);
2310*3ba6090fSDavid van Moolenbroek 	test94_fill_exact(fd2, buf, size, 0);
2311*3ba6090fSDavid van Moolenbroek 	test94_fill_exact(fd2, buf, size, 0);
2312*3ba6090fSDavid van Moolenbroek 
2313*3ba6090fSDavid van Moolenbroek 	if (write(fd3, "X", 1) != 1) e(0);
2314*3ba6090fSDavid van Moolenbroek 
2315*3ba6090fSDavid van Moolenbroek 	if (sysctl(mib, len, NULL, &oldlen, NULL, 0) != 0) e(0);
2316*3ba6090fSDavid van Moolenbroek 	if (oldlen == 0) e(0);
2317*3ba6090fSDavid van Moolenbroek 
2318*3ba6090fSDavid van Moolenbroek 	/* Add some slack space ourselves to prevent problems with churn. */
2319*3ba6090fSDavid van Moolenbroek 	bdesize = oldlen + sizeof(*bde) * 8;
2320*3ba6090fSDavid van Moolenbroek 	if ((bde = malloc(bdesize)) == NULL) e(0);
2321*3ba6090fSDavid van Moolenbroek 
2322*3ba6090fSDavid van Moolenbroek 	oldlen = bdesize;
2323*3ba6090fSDavid van Moolenbroek 	if (sysctl(mib, len, bde, &oldlen, NULL, 0) != 0) e(0);
2324*3ba6090fSDavid van Moolenbroek 	if (oldlen % sizeof(*bde)) e(0);
2325*3ba6090fSDavid van Moolenbroek 
2326*3ba6090fSDavid van Moolenbroek 	found = 0;
2327*3ba6090fSDavid van Moolenbroek 	for (slot = 0; slot < oldlen / sizeof(*bde); slot++) {
2328*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_pid != getpid())
2329*3ba6090fSDavid van Moolenbroek 			continue;
2330*3ba6090fSDavid van Moolenbroek 
2331*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_bufsize != size) e(0);
2332*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_promisc != 0) e(0);
2333*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_state != BPF_IDLE) e(0);
2334*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_immediate != 0) e(0);
2335*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_hdrcmplt != 0) e(0);
2336*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_seesent != 1) e(0);
2337*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_rcount < count * 3 + 1) e(0);
2338*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_dcount != count) e(0);
2339*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_ccount != count * 3) e(0);
2340*3ba6090fSDavid van Moolenbroek 		if (strcmp(bde[slot].bde_ifname, LOOPBACK_IFNAME) != 0) e(0);
2341*3ba6090fSDavid van Moolenbroek 
2342*3ba6090fSDavid van Moolenbroek 		found++;
2343*3ba6090fSDavid van Moolenbroek 	}
2344*3ba6090fSDavid van Moolenbroek 	if (found != 1) e(0);
2345*3ba6090fSDavid van Moolenbroek 
2346*3ba6090fSDavid van Moolenbroek 	/*
2347*3ba6090fSDavid van Moolenbroek 	 * If global statistics are an accumulation of individual devices'
2348*3ba6090fSDavid van Moolenbroek 	 * statistics (they currently are not) then such a scheme should take
2349*3ba6090fSDavid van Moolenbroek 	 * into account device flushes.
2350*3ba6090fSDavid van Moolenbroek 	 */
2351*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCFLUSH) != 0) e(0);
2352*3ba6090fSDavid van Moolenbroek 
2353*3ba6090fSDavid van Moolenbroek 	test94_cleanup(fd, fd2, fd3, buf);
2354*3ba6090fSDavid van Moolenbroek 
2355*3ba6090fSDavid van Moolenbroek 	/*
2356*3ba6090fSDavid van Moolenbroek 	 * Now see if the global statistics have indeed changed correctly.
2357*3ba6090fSDavid van Moolenbroek 	 */
2358*3ba6090fSDavid van Moolenbroek 	oldlen = sizeof(bs2);
2359*3ba6090fSDavid van Moolenbroek 	if (sysctl(smib, __arraycount(smib), &bs2, &oldlen, NULL, 0) != 0)
2360*3ba6090fSDavid van Moolenbroek 		e(0);
2361*3ba6090fSDavid van Moolenbroek 	if (oldlen != sizeof(bs2)) e(0);
2362*3ba6090fSDavid van Moolenbroek 
2363*3ba6090fSDavid van Moolenbroek 	if (bs2.bs_recv < bs1.bs_recv + count * 3 + 1) e(0);
2364*3ba6090fSDavid van Moolenbroek 	if (bs2.bs_drop != bs1.bs_drop + count) e(0);
2365*3ba6090fSDavid van Moolenbroek 	if (bs2.bs_capt != bs1.bs_capt + count * 3) e(0);
2366*3ba6090fSDavid van Moolenbroek 
2367*3ba6090fSDavid van Moolenbroek 	/*
2368*3ba6090fSDavid van Moolenbroek 	 * Check an unconfigured BPF device as well.
2369*3ba6090fSDavid van Moolenbroek 	 */
2370*3ba6090fSDavid van Moolenbroek 	if ((fd = open(_PATH_BPF, O_RDWR)) < 0) e(0);
2371*3ba6090fSDavid van Moolenbroek 
2372*3ba6090fSDavid van Moolenbroek 	/*
2373*3ba6090fSDavid van Moolenbroek 	 * Toggle some flags.  It is too much effort to test them all
2374*3ba6090fSDavid van Moolenbroek 	 * individually (which, in the light of copy-paste mistakes, would be
2375*3ba6090fSDavid van Moolenbroek 	 * the right thing to do) but at least we'll know something gets set.
2376*3ba6090fSDavid van Moolenbroek 	 */
2377*3ba6090fSDavid van Moolenbroek 	uval = 1;
2378*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCIMMEDIATE, &uval) != 0) e(0);
2379*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSHDRCMPLT, &uval) != 0) e(0);
2380*3ba6090fSDavid van Moolenbroek 
2381*3ba6090fSDavid van Moolenbroek 	uval = 0;
2382*3ba6090fSDavid van Moolenbroek 	if (ioctl(fd, BIOCSSEESENT, &uval) != 0) e(0);
2383*3ba6090fSDavid van Moolenbroek 
2384*3ba6090fSDavid van Moolenbroek 	oldlen = bdesize;
2385*3ba6090fSDavid van Moolenbroek 	if (sysctl(mib, len, bde, &oldlen, NULL, 0) != 0) e(0);
2386*3ba6090fSDavid van Moolenbroek 	if (oldlen % sizeof(*bde)) e(0);
2387*3ba6090fSDavid van Moolenbroek 
2388*3ba6090fSDavid van Moolenbroek 	found = 0;
2389*3ba6090fSDavid van Moolenbroek 	for (slot = 0; slot < oldlen / sizeof(*bde); slot++) {
2390*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_pid != getpid())
2391*3ba6090fSDavid van Moolenbroek 			continue;
2392*3ba6090fSDavid van Moolenbroek 
2393*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_bufsize != size) e(0);
2394*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_promisc != 0) e(0);
2395*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_state != BPF_IDLE) e(0);
2396*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_immediate != 1) e(0);
2397*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_hdrcmplt != 1) e(0);
2398*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_seesent != 0) e(0);
2399*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_rcount != 0) e(0);
2400*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_dcount != 0) e(0);
2401*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_ccount != 0) e(0);
2402*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_ifname[0] != '\0') e(0);
2403*3ba6090fSDavid van Moolenbroek 
2404*3ba6090fSDavid van Moolenbroek 		found++;
2405*3ba6090fSDavid van Moolenbroek 	}
2406*3ba6090fSDavid van Moolenbroek 	if (found != 1) e(0);
2407*3ba6090fSDavid van Moolenbroek 
2408*3ba6090fSDavid van Moolenbroek 	close(fd);
2409*3ba6090fSDavid van Moolenbroek 
2410*3ba6090fSDavid van Moolenbroek 	/*
2411*3ba6090fSDavid van Moolenbroek 	 * At this point there should be no BPF device left for our PID.
2412*3ba6090fSDavid van Moolenbroek 	 */
2413*3ba6090fSDavid van Moolenbroek 	oldlen = bdesize;
2414*3ba6090fSDavid van Moolenbroek 	if (sysctl(mib, len, bde, &oldlen, NULL, 0) != 0) e(0);
2415*3ba6090fSDavid van Moolenbroek 	if (oldlen % sizeof(*bde)) e(0);
2416*3ba6090fSDavid van Moolenbroek 
2417*3ba6090fSDavid van Moolenbroek 	for (slot = 0; slot < oldlen / sizeof(*bde); slot++)
2418*3ba6090fSDavid van Moolenbroek 		if (bde[slot].bde_pid == getpid()) e(0);
2419*3ba6090fSDavid van Moolenbroek 			found++;
2420*3ba6090fSDavid van Moolenbroek 
2421*3ba6090fSDavid van Moolenbroek 	free(bde);
2422*3ba6090fSDavid van Moolenbroek }
2423*3ba6090fSDavid van Moolenbroek 
2424*3ba6090fSDavid van Moolenbroek /*
2425*3ba6090fSDavid van Moolenbroek  * Test privileged operations as an unprivileged caller.
2426*3ba6090fSDavid van Moolenbroek  */
2427*3ba6090fSDavid van Moolenbroek static void
test94k(void)2428*3ba6090fSDavid van Moolenbroek test94k(void)
2429*3ba6090fSDavid van Moolenbroek {
2430*3ba6090fSDavid van Moolenbroek 	struct passwd *pw;
2431*3ba6090fSDavid van Moolenbroek 	pid_t pid;
2432*3ba6090fSDavid van Moolenbroek 	size_t len, oldlen;
2433*3ba6090fSDavid van Moolenbroek 	int mib[5], status;
2434*3ba6090fSDavid van Moolenbroek 
2435*3ba6090fSDavid van Moolenbroek 	subtest = 11;
2436*3ba6090fSDavid van Moolenbroek 
2437*3ba6090fSDavid van Moolenbroek 	pid = fork();
2438*3ba6090fSDavid van Moolenbroek 	switch (pid) {
2439*3ba6090fSDavid van Moolenbroek 	case 0:
2440*3ba6090fSDavid van Moolenbroek 		errct = 0;
2441*3ba6090fSDavid van Moolenbroek 
2442*3ba6090fSDavid van Moolenbroek 		if ((pw = getpwnam(NONROOT_USER)) == NULL) e(0);
2443*3ba6090fSDavid van Moolenbroek 
2444*3ba6090fSDavid van Moolenbroek 		if (setuid(pw->pw_uid) != 0) e(0);
2445*3ba6090fSDavid van Moolenbroek 
2446*3ba6090fSDavid van Moolenbroek 		/*
2447*3ba6090fSDavid van Moolenbroek 		 * Opening /dev/bpf must fail.  Note that this is a system
2448*3ba6090fSDavid van Moolenbroek 		 * configuration issue rather than a LWIP service issue.
2449*3ba6090fSDavid van Moolenbroek 		 */
2450*3ba6090fSDavid van Moolenbroek 		if (open(_PATH_BPF, O_RDWR) != -1) e(0);
2451*3ba6090fSDavid van Moolenbroek 		if (errno != EACCES) e(0);
2452*3ba6090fSDavid van Moolenbroek 
2453*3ba6090fSDavid van Moolenbroek 		/*
2454*3ba6090fSDavid van Moolenbroek 		 * Retrieving the net.bpf.peers list must fail, too.
2455*3ba6090fSDavid van Moolenbroek 		 */
2456*3ba6090fSDavid van Moolenbroek 		memset(mib, 0, sizeof(mib));
2457*3ba6090fSDavid van Moolenbroek 		len = __arraycount(mib);
2458*3ba6090fSDavid van Moolenbroek 		if (sysctlnametomib("net.bpf.peers", mib, &len) != 0) e(0);
2459*3ba6090fSDavid van Moolenbroek 		if (len != 3) e(0);
2460*3ba6090fSDavid van Moolenbroek 		mib[len++] = sizeof(struct bpf_d_ext);
2461*3ba6090fSDavid van Moolenbroek 		mib[len++] = INT_MAX;
2462*3ba6090fSDavid van Moolenbroek 
2463*3ba6090fSDavid van Moolenbroek 		if (sysctl(mib, len, NULL, &oldlen, NULL, 0) != -1) e(0);
2464*3ba6090fSDavid van Moolenbroek 		if (errno != EPERM) e(0);
2465*3ba6090fSDavid van Moolenbroek 
2466*3ba6090fSDavid van Moolenbroek 		exit(errct);
2467*3ba6090fSDavid van Moolenbroek 	case -1:
2468*3ba6090fSDavid van Moolenbroek 		e(0);
2469*3ba6090fSDavid van Moolenbroek 
2470*3ba6090fSDavid van Moolenbroek 		break;
2471*3ba6090fSDavid van Moolenbroek 	default:
2472*3ba6090fSDavid van Moolenbroek 		break;
2473*3ba6090fSDavid van Moolenbroek 	}
2474*3ba6090fSDavid van Moolenbroek 
2475*3ba6090fSDavid van Moolenbroek 	if (wait(&status) != pid) e(0);
2476*3ba6090fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
2477*3ba6090fSDavid van Moolenbroek }
2478*3ba6090fSDavid van Moolenbroek 
2479*3ba6090fSDavid van Moolenbroek /*
2480*3ba6090fSDavid van Moolenbroek  * Test that traffic directed to loopback addresses be dropped on non-loopback
2481*3ba6090fSDavid van Moolenbroek  * interfaces.  In particular, inbound traffic to 127.0.0.1 and ::1 should not
2482*3ba6090fSDavid van Moolenbroek  * be accepted on any interface that does not own those addresses.  This test
2483*3ba6090fSDavid van Moolenbroek  * is here because BPF feedback mode is (currently) the only way in which we
2484*3ba6090fSDavid van Moolenbroek  * can generate inbound traffic the ethernet level, and even then only as a
2485*3ba6090fSDavid van Moolenbroek  * side effect of sending outbound traffic.  That is: this test sends the same
2486*3ba6090fSDavid van Moolenbroek  * test packets to the local network!  As such it must be performed only when
2487*3ba6090fSDavid van Moolenbroek  * USENETWORK=yes and therefore at the user's risk.
2488*3ba6090fSDavid van Moolenbroek  */
2489*3ba6090fSDavid van Moolenbroek static void
test94l(void)2490*3ba6090fSDavid van Moolenbroek test94l(void)
2491*3ba6090fSDavid van Moolenbroek {
2492*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in sin;
2493*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in6 sin6;
2494*3ba6090fSDavid van Moolenbroek 	struct sockaddr_dl sdl;
2495*3ba6090fSDavid van Moolenbroek 	struct ifreq ifr;
2496*3ba6090fSDavid van Moolenbroek 	struct ifaddrs *ifa, *ifp;
2497*3ba6090fSDavid van Moolenbroek 	struct if_data *ifdata;
2498*3ba6090fSDavid van Moolenbroek 	uint8_t buf[sizeof(struct ether_header) + MAX(sizeof(struct ip),
2499*3ba6090fSDavid van Moolenbroek 	    sizeof(struct ip6_hdr)) + sizeof(struct udphdr) + 6];
2500*3ba6090fSDavid van Moolenbroek 	struct ether_header ether;
2501*3ba6090fSDavid van Moolenbroek 	const uint8_t ether_src[ETHER_ADDR_LEN] =
2502*3ba6090fSDavid van Moolenbroek 	    { 0x02, 0x00, 0x01, 0x12, 0x34, 0x56 };
2503*3ba6090fSDavid van Moolenbroek 	unsigned int val;
2504*3ba6090fSDavid van Moolenbroek 	size_t off;
2505*3ba6090fSDavid van Moolenbroek 	int bfd, sfd;
2506*3ba6090fSDavid van Moolenbroek 
2507*3ba6090fSDavid van Moolenbroek 	subtest = 12;
2508*3ba6090fSDavid van Moolenbroek 
2509*3ba6090fSDavid van Moolenbroek 	if (!get_setting_use_network())
2510*3ba6090fSDavid van Moolenbroek 		return;
2511*3ba6090fSDavid van Moolenbroek 
2512*3ba6090fSDavid van Moolenbroek 	memset(&ifr, 0, sizeof(ifr));
2513*3ba6090fSDavid van Moolenbroek 	memset(&ether, 0, sizeof(ether));
2514*3ba6090fSDavid van Moolenbroek 
2515*3ba6090fSDavid van Moolenbroek 	/*
2516*3ba6090fSDavid van Moolenbroek 	 * Start by finding a suitable ethernet interface that is up and of
2517*3ba6090fSDavid van Moolenbroek 	 * which the link is not down.  Without one, we cannot perform this
2518*3ba6090fSDavid van Moolenbroek 	 * test.  Save the interface name and the ethernet address.
2519*3ba6090fSDavid van Moolenbroek 	 */
2520*3ba6090fSDavid van Moolenbroek 	if (getifaddrs(&ifa) != 0) e(0);
2521*3ba6090fSDavid van Moolenbroek 
2522*3ba6090fSDavid van Moolenbroek 	for (ifp = ifa; ifp != NULL; ifp = ifp->ifa_next) {
2523*3ba6090fSDavid van Moolenbroek 		if (!(ifp->ifa_flags & IFF_UP) || ifp->ifa_addr == NULL ||
2524*3ba6090fSDavid van Moolenbroek 		    ifp->ifa_addr->sa_family != AF_LINK)
2525*3ba6090fSDavid van Moolenbroek 			continue;
2526*3ba6090fSDavid van Moolenbroek 
2527*3ba6090fSDavid van Moolenbroek 		ifdata = (struct if_data *)ifp->ifa_data;
2528*3ba6090fSDavid van Moolenbroek 		if (ifdata != NULL && ifdata->ifi_type == IFT_ETHER &&
2529*3ba6090fSDavid van Moolenbroek 		    ifdata->ifi_link_state != LINK_STATE_DOWN) {
2530*3ba6090fSDavid van Moolenbroek 			strlcpy(ifr.ifr_name, ifp->ifa_name,
2531*3ba6090fSDavid van Moolenbroek 			    sizeof(ifr.ifr_name));
2532*3ba6090fSDavid van Moolenbroek 
2533*3ba6090fSDavid van Moolenbroek 			memcpy(&sdl, (struct sockaddr_dl *)ifp->ifa_addr,
2534*3ba6090fSDavid van Moolenbroek 			    offsetof(struct sockaddr_dl, sdl_data));
2535*3ba6090fSDavid van Moolenbroek 			if (sdl.sdl_alen != sizeof(ether.ether_dhost)) e(0);
2536*3ba6090fSDavid van Moolenbroek 			memcpy(ether.ether_dhost,
2537*3ba6090fSDavid van Moolenbroek 			    ((struct sockaddr_dl *)ifp->ifa_addr)->sdl_data +
2538*3ba6090fSDavid van Moolenbroek 			    sdl.sdl_nlen, sdl.sdl_alen);
2539*3ba6090fSDavid van Moolenbroek 			break;
2540*3ba6090fSDavid van Moolenbroek 		}
2541*3ba6090fSDavid van Moolenbroek 	}
2542*3ba6090fSDavid van Moolenbroek 
2543*3ba6090fSDavid van Moolenbroek 	freeifaddrs(ifa);
2544*3ba6090fSDavid van Moolenbroek 
2545*3ba6090fSDavid van Moolenbroek 	if (ifp == NULL)
2546*3ba6090fSDavid van Moolenbroek 		return;
2547*3ba6090fSDavid van Moolenbroek 
2548*3ba6090fSDavid van Moolenbroek 	/* Open a BPF device and bind it to the ethernet interface we found. */
2549*3ba6090fSDavid van Moolenbroek 	if ((bfd = open(_PATH_BPF, O_RDWR)) < 0) e(0);
2550*3ba6090fSDavid van Moolenbroek 
2551*3ba6090fSDavid van Moolenbroek 	if (ioctl(bfd, BIOCSETIF, &ifr) != 0) e(0);
2552*3ba6090fSDavid van Moolenbroek 
2553*3ba6090fSDavid van Moolenbroek 	if (ioctl(bfd, BIOCGDLT, &val) != 0) e(0);
2554*3ba6090fSDavid van Moolenbroek 	if (val != DLT_EN10MB) e(0);
2555*3ba6090fSDavid van Moolenbroek 
2556*3ba6090fSDavid van Moolenbroek 	val = 1;
2557*3ba6090fSDavid van Moolenbroek 	if (ioctl(bfd, BIOCSFEEDBACK, &val) != 0) e(0);
2558*3ba6090fSDavid van Moolenbroek 
2559*3ba6090fSDavid van Moolenbroek 	/* We use UDP traffic for our test packets, IPv4 first. */
2560*3ba6090fSDavid van Moolenbroek 	if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) e(0);
2561*3ba6090fSDavid van Moolenbroek 
2562*3ba6090fSDavid van Moolenbroek 	memset(&sin, 0, sizeof(sin));
2563*3ba6090fSDavid van Moolenbroek 	sin.sin_family = AF_INET;
2564*3ba6090fSDavid van Moolenbroek 	sin.sin_port = htons(TEST_PORT_B);
2565*3ba6090fSDavid van Moolenbroek 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
2566*3ba6090fSDavid van Moolenbroek 	if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) != 0) e(0);
2567*3ba6090fSDavid van Moolenbroek 
2568*3ba6090fSDavid van Moolenbroek 	/*
2569*3ba6090fSDavid van Moolenbroek 	 * Construct and send a packet.  We already filled in the ethernet
2570*3ba6090fSDavid van Moolenbroek 	 * destination address.  Put in a source address that is locally
2571*3ba6090fSDavid van Moolenbroek 	 * administered but valid (and as such no reason for packet rejection).
2572*3ba6090fSDavid van Moolenbroek 	 */
2573*3ba6090fSDavid van Moolenbroek 	memcpy(ether.ether_shost, ether_src, sizeof(ether.ether_shost));
2574*3ba6090fSDavid van Moolenbroek 	ether.ether_type = htons(ETHERTYPE_IP);
2575*3ba6090fSDavid van Moolenbroek 
2576*3ba6090fSDavid van Moolenbroek 	memcpy(buf, &ether, sizeof(ether));
2577*3ba6090fSDavid van Moolenbroek 	off = sizeof(ether);
2578*3ba6090fSDavid van Moolenbroek 	off += test94_make_pkt(buf + off, 6, 0 /*v6*/);
2579*3ba6090fSDavid van Moolenbroek 	if (off + 6 > sizeof(buf)) e(0);
2580*3ba6090fSDavid van Moolenbroek 	memcpy(buf + off, "Hello!", 6);
2581*3ba6090fSDavid van Moolenbroek 
2582*3ba6090fSDavid van Moolenbroek 	if (write(bfd, buf, off + 6) != off + 6) e(0);
2583*3ba6090fSDavid van Moolenbroek 
2584*3ba6090fSDavid van Moolenbroek 	/* The packet MUST NOT arrive. */
2585*3ba6090fSDavid van Moolenbroek 	if (recv(sfd, buf, sizeof(buf), MSG_DONTWAIT) != -1) e(0);
2586*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
2587*3ba6090fSDavid van Moolenbroek 
2588*3ba6090fSDavid van Moolenbroek 	if (close(sfd) != 0) e(0);
2589*3ba6090fSDavid van Moolenbroek 
2590*3ba6090fSDavid van Moolenbroek 	/* Try the same thing, but now with an IPv6 packet. */
2591*3ba6090fSDavid van Moolenbroek 	if ((sfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) e(0);
2592*3ba6090fSDavid van Moolenbroek 
2593*3ba6090fSDavid van Moolenbroek 	memset(&sin6, 0, sizeof(sin6));
2594*3ba6090fSDavid van Moolenbroek 	sin6.sin6_family = AF_INET6;
2595*3ba6090fSDavid van Moolenbroek 	sin6.sin6_port = htons(TEST_PORT_B);
2596*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6.sin6_addr, &in6addr_loopback, sizeof(sin6.sin6_addr));
2597*3ba6090fSDavid van Moolenbroek 	if (bind(sfd, (struct sockaddr *)&sin6, sizeof(sin6)) != 0) e(0);
2598*3ba6090fSDavid van Moolenbroek 
2599*3ba6090fSDavid van Moolenbroek 	ether.ether_type = htons(ETHERTYPE_IPV6);
2600*3ba6090fSDavid van Moolenbroek 
2601*3ba6090fSDavid van Moolenbroek 	memcpy(buf, &ether, sizeof(ether));
2602*3ba6090fSDavid van Moolenbroek 	off = sizeof(ether);
2603*3ba6090fSDavid van Moolenbroek 	off += test94_make_pkt(buf + off, 6, 1 /*v6*/);
2604*3ba6090fSDavid van Moolenbroek 	if (off + 6 > sizeof(buf)) e(0);
2605*3ba6090fSDavid van Moolenbroek 	memcpy(buf + off, "Hello!", 6);
2606*3ba6090fSDavid van Moolenbroek 
2607*3ba6090fSDavid van Moolenbroek 	if (write(bfd, buf, off + 6) != off + 6) e(0);
2608*3ba6090fSDavid van Moolenbroek 
2609*3ba6090fSDavid van Moolenbroek 	if (recv(sfd, buf, sizeof(buf), MSG_DONTWAIT) != -1) e(0);
2610*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
2611*3ba6090fSDavid van Moolenbroek 
2612*3ba6090fSDavid van Moolenbroek 	if (close(sfd) != 0) e(0);
2613*3ba6090fSDavid van Moolenbroek 	if (close(bfd) != 0) e(0);
2614*3ba6090fSDavid van Moolenbroek }
2615*3ba6090fSDavid van Moolenbroek 
2616*3ba6090fSDavid van Moolenbroek /*
2617*3ba6090fSDavid van Moolenbroek  * Test program for LWIP BPF.
2618*3ba6090fSDavid van Moolenbroek  */
2619*3ba6090fSDavid van Moolenbroek int
main(int argc,char ** argv)2620*3ba6090fSDavid van Moolenbroek main(int argc, char ** argv)
2621*3ba6090fSDavid van Moolenbroek {
2622*3ba6090fSDavid van Moolenbroek 	int i, m;
2623*3ba6090fSDavid van Moolenbroek 
2624*3ba6090fSDavid van Moolenbroek 	start(94);
2625*3ba6090fSDavid van Moolenbroek 
2626*3ba6090fSDavid van Moolenbroek 	srand48(time(NULL));
2627*3ba6090fSDavid van Moolenbroek 
2628*3ba6090fSDavid van Moolenbroek 	if (argc == 2)
2629*3ba6090fSDavid van Moolenbroek 		m = atoi(argv[1]);
2630*3ba6090fSDavid van Moolenbroek 	else
2631*3ba6090fSDavid van Moolenbroek 		m = 0xFFF;
2632*3ba6090fSDavid van Moolenbroek 
2633*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < ITERATIONS; i++) {
2634*3ba6090fSDavid van Moolenbroek 		if (m & 0x001) test94a();
2635*3ba6090fSDavid van Moolenbroek 		if (m & 0x002) test94b();
2636*3ba6090fSDavid van Moolenbroek 		if (m & 0x004) test94c();
2637*3ba6090fSDavid van Moolenbroek 		if (m & 0x008) test94d();
2638*3ba6090fSDavid van Moolenbroek 		if (m & 0x010) test94e();
2639*3ba6090fSDavid van Moolenbroek 		if (m & 0x020) test94f();
2640*3ba6090fSDavid van Moolenbroek 		if (m & 0x040) test94g();
2641*3ba6090fSDavid van Moolenbroek 		if (m & 0x080) test94h();
2642*3ba6090fSDavid van Moolenbroek 		if (m & 0x100) test94i();
2643*3ba6090fSDavid van Moolenbroek 		if (m & 0x200) test94j();
2644*3ba6090fSDavid van Moolenbroek 		if (m & 0x400) test94k();
2645*3ba6090fSDavid van Moolenbroek 		if (m & 0x800) test94l();
2646*3ba6090fSDavid van Moolenbroek 	}
2647*3ba6090fSDavid van Moolenbroek 
2648*3ba6090fSDavid van Moolenbroek 	quit();
2649*3ba6090fSDavid van Moolenbroek 	/* NOTREACHED */
2650*3ba6090fSDavid van Moolenbroek }
2651