xref: /minix3/minix/tests/test92.c (revision 3ba6090f825dfbac97538b19928b0ab1e37909d6)
1*3ba6090fSDavid van Moolenbroek /* Tests for RAW sockets (LWIP) - by D.C. van Moolenbroek */
2*3ba6090fSDavid van Moolenbroek /* This test needs to be run as root: creating raw sockets is root-only. */
3*3ba6090fSDavid van Moolenbroek #include <stdlib.h>
4*3ba6090fSDavid van Moolenbroek #include <string.h>
5*3ba6090fSDavid van Moolenbroek #include <stddef.h>
6*3ba6090fSDavid van Moolenbroek #include <sys/mman.h>
7*3ba6090fSDavid van Moolenbroek #include <sys/param.h>
8*3ba6090fSDavid van Moolenbroek #include <sys/socket.h>
9*3ba6090fSDavid van Moolenbroek #include <net/route.h>
10*3ba6090fSDavid van Moolenbroek #include <netinet/in.h>
11*3ba6090fSDavid van Moolenbroek #include <netinet/ip.h>
12*3ba6090fSDavid van Moolenbroek #include <netinet/udp.h>
13*3ba6090fSDavid van Moolenbroek #include <netinet/icmp6.h>
14*3ba6090fSDavid van Moolenbroek #include <netinet/in_pcb.h>
15*3ba6090fSDavid van Moolenbroek #include <netinet6/in6_pcb.h>
16*3ba6090fSDavid van Moolenbroek #include <arpa/inet.h>
17*3ba6090fSDavid van Moolenbroek #include <machine/vmparam.h>
18*3ba6090fSDavid van Moolenbroek #include <unistd.h>
19*3ba6090fSDavid van Moolenbroek #include <fcntl.h>
20*3ba6090fSDavid van Moolenbroek #include <assert.h>
21*3ba6090fSDavid van Moolenbroek 
22*3ba6090fSDavid van Moolenbroek #include "common.h"
23*3ba6090fSDavid van Moolenbroek #include "socklib.h"
24*3ba6090fSDavid van Moolenbroek 
25*3ba6090fSDavid van Moolenbroek #define ITERATIONS	2
26*3ba6090fSDavid van Moolenbroek 
27*3ba6090fSDavid van Moolenbroek #define TEST_PROTO		253	/* from RFC 3692 */
28*3ba6090fSDavid van Moolenbroek #define TEST_ICMPV6_TYPE_A	200	/* from RFC 4443 */
29*3ba6090fSDavid van Moolenbroek #define TEST_ICMPV6_TYPE_B	201	/* from RFC 4443 */
30*3ba6090fSDavid van Moolenbroek 
31*3ba6090fSDavid van Moolenbroek static const enum state raw_states[] = {
32*3ba6090fSDavid van Moolenbroek 		S_NEW,		S_N_SHUT_R,	S_N_SHUT_W,	S_N_SHUT_RW,
33*3ba6090fSDavid van Moolenbroek 		S_BOUND,	S_CONNECTED,	S_SHUT_R,	S_SHUT_W,
34*3ba6090fSDavid van Moolenbroek 		S_SHUT_RW,
35*3ba6090fSDavid van Moolenbroek };
36*3ba6090fSDavid van Moolenbroek 
37*3ba6090fSDavid van Moolenbroek static const int raw_results[][__arraycount(raw_states)] = {
38*3ba6090fSDavid van Moolenbroek 	[C_ACCEPT]		= {
39*3ba6090fSDavid van Moolenbroek 		-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,
40*3ba6090fSDavid van Moolenbroek 		-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,
41*3ba6090fSDavid van Moolenbroek 		-EOPNOTSUPP,
42*3ba6090fSDavid van Moolenbroek 	},
43*3ba6090fSDavid van Moolenbroek 	[C_BIND]		= {
44*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
45*3ba6090fSDavid van Moolenbroek 		0,		-EINVAL,	-EINVAL,	-EINVAL,
46*3ba6090fSDavid van Moolenbroek 		-EINVAL,
47*3ba6090fSDavid van Moolenbroek 	},
48*3ba6090fSDavid van Moolenbroek 	[C_CONNECT]		= {
49*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
50*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
51*3ba6090fSDavid van Moolenbroek 		0,
52*3ba6090fSDavid van Moolenbroek 	},
53*3ba6090fSDavid van Moolenbroek 	[C_GETPEERNAME]		= {
54*3ba6090fSDavid van Moolenbroek 		-ENOTCONN,	-ENOTCONN,	-ENOTCONN,	-ENOTCONN,
55*3ba6090fSDavid van Moolenbroek 		-ENOTCONN,	0,		0,		0,
56*3ba6090fSDavid van Moolenbroek 		0,
57*3ba6090fSDavid van Moolenbroek 	},
58*3ba6090fSDavid van Moolenbroek 	[C_GETSOCKNAME]		= {
59*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
60*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
61*3ba6090fSDavid van Moolenbroek 		0,
62*3ba6090fSDavid van Moolenbroek 	},
63*3ba6090fSDavid van Moolenbroek 	[C_GETSOCKOPT_ERR]	= {
64*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
65*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
66*3ba6090fSDavid van Moolenbroek 		0,
67*3ba6090fSDavid van Moolenbroek 	},
68*3ba6090fSDavid van Moolenbroek 	[C_GETSOCKOPT_KA]	= {
69*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
70*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
71*3ba6090fSDavid van Moolenbroek 		0,
72*3ba6090fSDavid van Moolenbroek 	},
73*3ba6090fSDavid van Moolenbroek 	[C_GETSOCKOPT_RB]	= {
74*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
75*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
76*3ba6090fSDavid van Moolenbroek 		0,
77*3ba6090fSDavid van Moolenbroek 	},
78*3ba6090fSDavid van Moolenbroek 	[C_IOCTL_NREAD]		= {
79*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
80*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
81*3ba6090fSDavid van Moolenbroek 		0,
82*3ba6090fSDavid van Moolenbroek 	},
83*3ba6090fSDavid van Moolenbroek 	[C_LISTEN]		= {
84*3ba6090fSDavid van Moolenbroek 		-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,
85*3ba6090fSDavid van Moolenbroek 		-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,
86*3ba6090fSDavid van Moolenbroek 		-EOPNOTSUPP,
87*3ba6090fSDavid van Moolenbroek 	},
88*3ba6090fSDavid van Moolenbroek 	[C_RECV]		= {
89*3ba6090fSDavid van Moolenbroek 		-EAGAIN,	0,		-EAGAIN,	0,
90*3ba6090fSDavid van Moolenbroek 		-EAGAIN,	-EAGAIN,	0,		-EAGAIN,
91*3ba6090fSDavid van Moolenbroek 		0,
92*3ba6090fSDavid van Moolenbroek 	},
93*3ba6090fSDavid van Moolenbroek 	[C_RECVFROM]		= {
94*3ba6090fSDavid van Moolenbroek 		-EAGAIN,	0,		-EAGAIN,	0,
95*3ba6090fSDavid van Moolenbroek 		-EAGAIN,	-EAGAIN,	0,		-EAGAIN,
96*3ba6090fSDavid van Moolenbroek 		0,
97*3ba6090fSDavid van Moolenbroek 	},
98*3ba6090fSDavid van Moolenbroek 	[C_SEND]		= {
99*3ba6090fSDavid van Moolenbroek 		-EDESTADDRREQ,	-EDESTADDRREQ,	-EPIPE,		-EPIPE,
100*3ba6090fSDavid van Moolenbroek 		-EDESTADDRREQ,	1,		1,		-EPIPE,
101*3ba6090fSDavid van Moolenbroek 		-EPIPE,
102*3ba6090fSDavid van Moolenbroek 	},
103*3ba6090fSDavid van Moolenbroek 	[C_SENDTO]		= {
104*3ba6090fSDavid van Moolenbroek 		1,		1,		-EPIPE,		-EPIPE,
105*3ba6090fSDavid van Moolenbroek 		1,		1,		1,		-EPIPE,
106*3ba6090fSDavid van Moolenbroek 		-EPIPE,
107*3ba6090fSDavid van Moolenbroek 	},
108*3ba6090fSDavid van Moolenbroek 	[C_SELECT_R]		= {
109*3ba6090fSDavid van Moolenbroek 		0,		1,		0,		1,
110*3ba6090fSDavid van Moolenbroek 		0,		0,		1,		0,
111*3ba6090fSDavid van Moolenbroek 		1,
112*3ba6090fSDavid van Moolenbroek 	},
113*3ba6090fSDavid van Moolenbroek 	[C_SELECT_W]		= {
114*3ba6090fSDavid van Moolenbroek 		1,		1,		1,		1,
115*3ba6090fSDavid van Moolenbroek 		1,		1,		1,		1,
116*3ba6090fSDavid van Moolenbroek 		1,
117*3ba6090fSDavid van Moolenbroek 	},
118*3ba6090fSDavid van Moolenbroek 	[C_SELECT_X]		= {
119*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
120*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
121*3ba6090fSDavid van Moolenbroek 		0,
122*3ba6090fSDavid van Moolenbroek 	},
123*3ba6090fSDavid van Moolenbroek 	[C_SETSOCKOPT_BC]	= {
124*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
125*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
126*3ba6090fSDavid van Moolenbroek 		0,
127*3ba6090fSDavid van Moolenbroek 	},
128*3ba6090fSDavid van Moolenbroek 	[C_SETSOCKOPT_KA]	= {
129*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
130*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
131*3ba6090fSDavid van Moolenbroek 		0,
132*3ba6090fSDavid van Moolenbroek 	},
133*3ba6090fSDavid van Moolenbroek 	[C_SETSOCKOPT_L]	= {
134*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
135*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
136*3ba6090fSDavid van Moolenbroek 		0,
137*3ba6090fSDavid van Moolenbroek 	},
138*3ba6090fSDavid van Moolenbroek 	[C_SETSOCKOPT_RA]	= {
139*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
140*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
141*3ba6090fSDavid van Moolenbroek 		0,
142*3ba6090fSDavid van Moolenbroek 	},
143*3ba6090fSDavid van Moolenbroek 	[C_SHUTDOWN_R]		= {
144*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
145*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
146*3ba6090fSDavid van Moolenbroek 		0,
147*3ba6090fSDavid van Moolenbroek 	},
148*3ba6090fSDavid van Moolenbroek 	[C_SHUTDOWN_RW]		= {
149*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
150*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
151*3ba6090fSDavid van Moolenbroek 		0,
152*3ba6090fSDavid van Moolenbroek 	},
153*3ba6090fSDavid van Moolenbroek 	[C_SHUTDOWN_W]		= {
154*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
155*3ba6090fSDavid van Moolenbroek 		0,		0,		0,		0,
156*3ba6090fSDavid van Moolenbroek 		0,
157*3ba6090fSDavid van Moolenbroek 	},
158*3ba6090fSDavid van Moolenbroek };
159*3ba6090fSDavid van Moolenbroek 
160*3ba6090fSDavid van Moolenbroek /*
161*3ba6090fSDavid van Moolenbroek  * Set up a RAW socket file descriptor in the requested state and pass it to
162*3ba6090fSDavid van Moolenbroek  * socklib_sweep_call() along with local and remote addresses and their length.
163*3ba6090fSDavid van Moolenbroek  */
164*3ba6090fSDavid van Moolenbroek static int
raw_sweep(int domain,int type,int protocol,enum state state,enum call call)165*3ba6090fSDavid van Moolenbroek raw_sweep(int domain, int type, int protocol, enum state state,
166*3ba6090fSDavid van Moolenbroek 	enum call call)
167*3ba6090fSDavid van Moolenbroek {
168*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in sinA, sinB;
169*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in6 sin6A, sin6B;
170*3ba6090fSDavid van Moolenbroek 	struct sockaddr *addrA, *addrB;
171*3ba6090fSDavid van Moolenbroek 	socklen_t addr_len;
172*3ba6090fSDavid van Moolenbroek 	int r, fd, fd2;
173*3ba6090fSDavid van Moolenbroek 
174*3ba6090fSDavid van Moolenbroek 	if (domain == AF_INET) {
175*3ba6090fSDavid van Moolenbroek 		memset(&sinA, 0, sizeof(sinA));
176*3ba6090fSDavid van Moolenbroek 		sinA.sin_family = domain;
177*3ba6090fSDavid van Moolenbroek 		sinA.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
178*3ba6090fSDavid van Moolenbroek 
179*3ba6090fSDavid van Moolenbroek 		memcpy(&sinB, &sinA, sizeof(sinB));
180*3ba6090fSDavid van Moolenbroek 
181*3ba6090fSDavid van Moolenbroek 		addrA = (struct sockaddr *)&sinA;
182*3ba6090fSDavid van Moolenbroek 		addrB = (struct sockaddr *)&sinB;
183*3ba6090fSDavid van Moolenbroek 		addr_len = sizeof(sinA);
184*3ba6090fSDavid van Moolenbroek 	} else {
185*3ba6090fSDavid van Moolenbroek 		assert(domain == AF_INET6);
186*3ba6090fSDavid van Moolenbroek 
187*3ba6090fSDavid van Moolenbroek 		memset(&sin6A, 0, sizeof(sin6A));
188*3ba6090fSDavid van Moolenbroek 		sin6A.sin6_family = domain;
189*3ba6090fSDavid van Moolenbroek 		memcpy(&sin6A.sin6_addr, &in6addr_loopback,
190*3ba6090fSDavid van Moolenbroek 		    sizeof(sin6A.sin6_addr));
191*3ba6090fSDavid van Moolenbroek 
192*3ba6090fSDavid van Moolenbroek 		memcpy(&sin6B, &sin6A, sizeof(sin6B));
193*3ba6090fSDavid van Moolenbroek 
194*3ba6090fSDavid van Moolenbroek 		addrA = (struct sockaddr *)&sin6A;
195*3ba6090fSDavid van Moolenbroek 		addrB = (struct sockaddr *)&sin6B;
196*3ba6090fSDavid van Moolenbroek 		addr_len = sizeof(sin6A);
197*3ba6090fSDavid van Moolenbroek 	}
198*3ba6090fSDavid van Moolenbroek 
199*3ba6090fSDavid van Moolenbroek 	/* Create a bound remote socket. */
200*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(domain, type | SOCK_NONBLOCK, protocol)) < 0) e(0);
201*3ba6090fSDavid van Moolenbroek 
202*3ba6090fSDavid van Moolenbroek 	if (bind(fd2, addrB, addr_len) != 0) e(0);
203*3ba6090fSDavid van Moolenbroek 
204*3ba6090fSDavid van Moolenbroek 	switch (state) {
205*3ba6090fSDavid van Moolenbroek 	case S_NEW:
206*3ba6090fSDavid van Moolenbroek 	case S_N_SHUT_R:
207*3ba6090fSDavid van Moolenbroek 	case S_N_SHUT_W:
208*3ba6090fSDavid van Moolenbroek 	case S_N_SHUT_RW:
209*3ba6090fSDavid van Moolenbroek 		if ((fd = socket(domain, type | SOCK_NONBLOCK,
210*3ba6090fSDavid van Moolenbroek 		    protocol)) < 0) e(0);
211*3ba6090fSDavid van Moolenbroek 
212*3ba6090fSDavid van Moolenbroek 		switch (state) {
213*3ba6090fSDavid van Moolenbroek 		case S_N_SHUT_R: if (shutdown(fd, SHUT_RD)) e(0); break;
214*3ba6090fSDavid van Moolenbroek 		case S_N_SHUT_W: if (shutdown(fd, SHUT_WR)) e(0); break;
215*3ba6090fSDavid van Moolenbroek 		case S_N_SHUT_RW: if (shutdown(fd, SHUT_RDWR)) e(0); break;
216*3ba6090fSDavid van Moolenbroek 		default: break;
217*3ba6090fSDavid van Moolenbroek 		}
218*3ba6090fSDavid van Moolenbroek 
219*3ba6090fSDavid van Moolenbroek 		break;
220*3ba6090fSDavid van Moolenbroek 
221*3ba6090fSDavid van Moolenbroek 	case S_BOUND:
222*3ba6090fSDavid van Moolenbroek 	case S_CONNECTED:
223*3ba6090fSDavid van Moolenbroek 	case S_SHUT_R:
224*3ba6090fSDavid van Moolenbroek 	case S_SHUT_W:
225*3ba6090fSDavid van Moolenbroek 	case S_SHUT_RW:
226*3ba6090fSDavid van Moolenbroek 		if ((fd = socket(domain, type | SOCK_NONBLOCK,
227*3ba6090fSDavid van Moolenbroek 		    protocol)) < 0) e(0);
228*3ba6090fSDavid van Moolenbroek 
229*3ba6090fSDavid van Moolenbroek 		if (bind(fd, addrA, addr_len) != 0) e(0);
230*3ba6090fSDavid van Moolenbroek 
231*3ba6090fSDavid van Moolenbroek 		if (state == S_BOUND)
232*3ba6090fSDavid van Moolenbroek 			break;
233*3ba6090fSDavid van Moolenbroek 
234*3ba6090fSDavid van Moolenbroek 		if (connect(fd, addrB, addr_len) != 0) e(0);
235*3ba6090fSDavid van Moolenbroek 
236*3ba6090fSDavid van Moolenbroek 		switch (state) {
237*3ba6090fSDavid van Moolenbroek 		case S_SHUT_R: if (shutdown(fd, SHUT_RD)) e(0); break;
238*3ba6090fSDavid van Moolenbroek 		case S_SHUT_W: if (shutdown(fd, SHUT_WR)) e(0); break;
239*3ba6090fSDavid van Moolenbroek 		case S_SHUT_RW: if (shutdown(fd, SHUT_RDWR)) e(0); break;
240*3ba6090fSDavid van Moolenbroek 		default: break;
241*3ba6090fSDavid van Moolenbroek 		}
242*3ba6090fSDavid van Moolenbroek 
243*3ba6090fSDavid van Moolenbroek 		break;
244*3ba6090fSDavid van Moolenbroek 
245*3ba6090fSDavid van Moolenbroek 	default:
246*3ba6090fSDavid van Moolenbroek 		fd = -1;
247*3ba6090fSDavid van Moolenbroek 		e(0);
248*3ba6090fSDavid van Moolenbroek 	}
249*3ba6090fSDavid van Moolenbroek 
250*3ba6090fSDavid van Moolenbroek 	r = socklib_sweep_call(call, fd, addrA, addrB, addr_len);
251*3ba6090fSDavid van Moolenbroek 
252*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
253*3ba6090fSDavid van Moolenbroek 	if (fd2 != -1 && close(fd2) != 0) e(0);
254*3ba6090fSDavid van Moolenbroek 
255*3ba6090fSDavid van Moolenbroek 	return r;
256*3ba6090fSDavid van Moolenbroek }
257*3ba6090fSDavid van Moolenbroek 
258*3ba6090fSDavid van Moolenbroek /*
259*3ba6090fSDavid van Moolenbroek  * Sweep test for socket calls versus socket states of RAW sockets.
260*3ba6090fSDavid van Moolenbroek  */
261*3ba6090fSDavid van Moolenbroek static void
test92a(void)262*3ba6090fSDavid van Moolenbroek test92a(void)
263*3ba6090fSDavid van Moolenbroek {
264*3ba6090fSDavid van Moolenbroek 
265*3ba6090fSDavid van Moolenbroek 	subtest = 1;
266*3ba6090fSDavid van Moolenbroek 
267*3ba6090fSDavid van Moolenbroek 	socklib_sweep(AF_INET, SOCK_RAW, TEST_PROTO, raw_states,
268*3ba6090fSDavid van Moolenbroek 	    __arraycount(raw_states), (const int *)raw_results, raw_sweep);
269*3ba6090fSDavid van Moolenbroek 
270*3ba6090fSDavid van Moolenbroek 	socklib_sweep(AF_INET6, SOCK_RAW, TEST_PROTO, raw_states,
271*3ba6090fSDavid van Moolenbroek 	    __arraycount(raw_states), (const int *)raw_results, raw_sweep);
272*3ba6090fSDavid van Moolenbroek }
273*3ba6090fSDavid van Moolenbroek 
274*3ba6090fSDavid van Moolenbroek /*
275*3ba6090fSDavid van Moolenbroek  * Basic I/O test for raw sockets.
276*3ba6090fSDavid van Moolenbroek  */
277*3ba6090fSDavid van Moolenbroek static void
test92b(void)278*3ba6090fSDavid van Moolenbroek test92b(void)
279*3ba6090fSDavid van Moolenbroek {
280*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in sinA, sinB, sinC;
281*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in6 sin6A, sin6B, sin6C;
282*3ba6090fSDavid van Moolenbroek 	socklen_t len;
283*3ba6090fSDavid van Moolenbroek 	unsigned int i;
284*3ba6090fSDavid van Moolenbroek 	uint8_t buf[256], packet[5];
285*3ba6090fSDavid van Moolenbroek 	int fd, fd2;
286*3ba6090fSDavid van Moolenbroek 
287*3ba6090fSDavid van Moolenbroek 	subtest = 2;
288*3ba6090fSDavid van Moolenbroek 
289*3ba6090fSDavid van Moolenbroek 	/* First test IPv4. */
290*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, SOCK_RAW, TEST_PROTO)) < 0) e(0);
291*3ba6090fSDavid van Moolenbroek 
292*3ba6090fSDavid van Moolenbroek 	memset(&sinA, 0, sizeof(sinA));
293*3ba6090fSDavid van Moolenbroek 	sinA.sin_family = AF_INET;
294*3ba6090fSDavid van Moolenbroek 	sinA.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
295*3ba6090fSDavid van Moolenbroek 
296*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < __arraycount(packet); i++)
297*3ba6090fSDavid van Moolenbroek 		packet[i] = (uint8_t)(-i);
298*3ba6090fSDavid van Moolenbroek 
299*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, packet, sizeof(packet), 0, (struct sockaddr *)&sinA,
300*3ba6090fSDavid van Moolenbroek 	    sizeof(sinA)) != sizeof(packet)) e(0);
301*3ba6090fSDavid van Moolenbroek 
302*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, sizeof(buf));
303*3ba6090fSDavid van Moolenbroek 	len = sizeof(sinB);
304*3ba6090fSDavid van Moolenbroek 	if (recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sinB,
305*3ba6090fSDavid van Moolenbroek 	    &len) != sizeof(struct ip) + sizeof(packet)) e(0);
306*3ba6090fSDavid van Moolenbroek 
307*3ba6090fSDavid van Moolenbroek 	if (memcmp(&buf[sizeof(struct ip)], packet, sizeof(packet)) != 0) e(0);
308*3ba6090fSDavid van Moolenbroek 
309*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(sinB)) e(0);
310*3ba6090fSDavid van Moolenbroek 	if (sinB.sin_len != sizeof(sinB)) e(0);
311*3ba6090fSDavid van Moolenbroek 	if (sinB.sin_family != AF_INET) e(0);
312*3ba6090fSDavid van Moolenbroek 	if (sinB.sin_port != htons(0)) e(0);
313*3ba6090fSDavid van Moolenbroek 	if (sinB.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) e(0);
314*3ba6090fSDavid van Moolenbroek 
315*3ba6090fSDavid van Moolenbroek 	/*
316*3ba6090fSDavid van Moolenbroek 	 * Test two additional things:
317*3ba6090fSDavid van Moolenbroek 	 *
318*3ba6090fSDavid van Moolenbroek 	 * 1) a non-zero port number is ignored when sending;
319*3ba6090fSDavid van Moolenbroek 	 * 2) multiple raw sockets may receive the same packet.
320*3ba6090fSDavid van Moolenbroek 	 */
321*3ba6090fSDavid van Moolenbroek 	sinA.sin_port = htons(22);
322*3ba6090fSDavid van Moolenbroek 
323*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET, SOCK_RAW, TEST_PROTO)) < 0) e(0);
324*3ba6090fSDavid van Moolenbroek 
325*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, packet, sizeof(packet), 0, (struct sockaddr *)&sinA,
326*3ba6090fSDavid van Moolenbroek 	    sizeof(sinA)) != sizeof(packet)) e(0);
327*3ba6090fSDavid van Moolenbroek 
328*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, sizeof(buf));
329*3ba6090fSDavid van Moolenbroek 	len = sizeof(sinC);
330*3ba6090fSDavid van Moolenbroek 	if (recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sinC,
331*3ba6090fSDavid van Moolenbroek 	    &len) != sizeof(struct ip) + sizeof(packet)) e(0);
332*3ba6090fSDavid van Moolenbroek 
333*3ba6090fSDavid van Moolenbroek 	if (memcmp(&buf[sizeof(struct ip)], packet, sizeof(packet)) != 0) e(0);
334*3ba6090fSDavid van Moolenbroek 
335*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(sinC)) e(0);
336*3ba6090fSDavid van Moolenbroek 	if (memcmp(&sinB, &sinC, sizeof(sinB)) != 0) e(0);
337*3ba6090fSDavid van Moolenbroek 
338*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, sizeof(buf));
339*3ba6090fSDavid van Moolenbroek 	len = sizeof(sinC);
340*3ba6090fSDavid van Moolenbroek 	if (recvfrom(fd2, buf, sizeof(buf), 0, (struct sockaddr *)&sinC,
341*3ba6090fSDavid van Moolenbroek 	    &len) != sizeof(struct ip) + sizeof(packet)) e(0);
342*3ba6090fSDavid van Moolenbroek 
343*3ba6090fSDavid van Moolenbroek 	if (memcmp(&buf[sizeof(struct ip)], packet, sizeof(packet)) != 0) e(0);
344*3ba6090fSDavid van Moolenbroek 
345*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(sinC)) e(0);
346*3ba6090fSDavid van Moolenbroek 	if (memcmp(&sinB, &sinC, sizeof(sinB)) != 0) e(0);
347*3ba6090fSDavid van Moolenbroek 
348*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
349*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
350*3ba6090fSDavid van Moolenbroek 
351*3ba6090fSDavid van Moolenbroek 	/* Then test IPv6. */
352*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, SOCK_RAW, TEST_PROTO)) < 0) e(0);
353*3ba6090fSDavid van Moolenbroek 
354*3ba6090fSDavid van Moolenbroek 	memset(&sin6A, 0, sizeof(sin6A));
355*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_family = AF_INET6;
356*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6A.sin6_addr, &in6addr_loopback, sizeof(sin6A.sin6_addr));
357*3ba6090fSDavid van Moolenbroek 
358*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, packet, sizeof(packet), 0, (struct sockaddr *)&sin6A,
359*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != sizeof(packet)) e(0);
360*3ba6090fSDavid van Moolenbroek 
361*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, sizeof(buf));
362*3ba6090fSDavid van Moolenbroek 	len = sizeof(sin6B);
363*3ba6090fSDavid van Moolenbroek 	if (recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sin6B,
364*3ba6090fSDavid van Moolenbroek 	    &len) != sizeof(packet)) e(0);
365*3ba6090fSDavid van Moolenbroek 
366*3ba6090fSDavid van Moolenbroek 	if (memcmp(buf, packet, sizeof(packet)) != 0) e(0);
367*3ba6090fSDavid van Moolenbroek 
368*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(sin6B)) e(0);
369*3ba6090fSDavid van Moolenbroek 	if (sin6B.sin6_len != sizeof(sin6B)) e(0);
370*3ba6090fSDavid van Moolenbroek 	if (sin6B.sin6_family != AF_INET6) e(0);
371*3ba6090fSDavid van Moolenbroek 	if (sin6B.sin6_port != htons(0)) e(0);
372*3ba6090fSDavid van Moolenbroek 	if (memcmp(&sin6B.sin6_addr, &in6addr_loopback,
373*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6B.sin6_addr)) != 0) e(0);
374*3ba6090fSDavid van Moolenbroek 
375*3ba6090fSDavid van Moolenbroek 	/* As above. */
376*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_port = htons(22);
377*3ba6090fSDavid van Moolenbroek 
378*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET6, SOCK_RAW, TEST_PROTO)) < 0) e(0);
379*3ba6090fSDavid van Moolenbroek 
380*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, packet, sizeof(packet), 0, (struct sockaddr *)&sin6A,
381*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != sizeof(packet)) e(0);
382*3ba6090fSDavid van Moolenbroek 
383*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, sizeof(buf));
384*3ba6090fSDavid van Moolenbroek 	len = sizeof(sin6C);
385*3ba6090fSDavid van Moolenbroek 	if (recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sin6C,
386*3ba6090fSDavid van Moolenbroek 	    &len) != sizeof(packet)) e(0);
387*3ba6090fSDavid van Moolenbroek 
388*3ba6090fSDavid van Moolenbroek 	if (memcmp(buf, packet, sizeof(packet)) != 0) e(0);
389*3ba6090fSDavid van Moolenbroek 
390*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(sin6C)) e(0);
391*3ba6090fSDavid van Moolenbroek 	if (memcmp(&sin6B, &sin6C, sizeof(sin6B)) != 0) e(0);
392*3ba6090fSDavid van Moolenbroek 
393*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, sizeof(buf));
394*3ba6090fSDavid van Moolenbroek 	len = sizeof(sin6C);
395*3ba6090fSDavid van Moolenbroek 	if (recvfrom(fd2, buf, sizeof(buf), 0, (struct sockaddr *)&sin6C,
396*3ba6090fSDavid van Moolenbroek 	    &len) != sizeof(packet)) e(0);
397*3ba6090fSDavid van Moolenbroek 
398*3ba6090fSDavid van Moolenbroek 	if (memcmp(buf, packet, sizeof(packet)) != 0) e(0);
399*3ba6090fSDavid van Moolenbroek 
400*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(sin6C)) e(0);
401*3ba6090fSDavid van Moolenbroek 	if (memcmp(&sin6B, &sin6C, sizeof(sin6B)) != 0) e(0);
402*3ba6090fSDavid van Moolenbroek 
403*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
404*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
405*3ba6090fSDavid van Moolenbroek }
406*3ba6090fSDavid van Moolenbroek 
407*3ba6090fSDavid van Moolenbroek /*
408*3ba6090fSDavid van Moolenbroek  * Test the IPV6_CHECKSUM socket option.
409*3ba6090fSDavid van Moolenbroek  */
410*3ba6090fSDavid van Moolenbroek static void
test92c(void)411*3ba6090fSDavid van Moolenbroek test92c(void)
412*3ba6090fSDavid van Moolenbroek {
413*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in6 sin6;
414*3ba6090fSDavid van Moolenbroek 	struct icmp6_hdr icmp6_hdr;
415*3ba6090fSDavid van Moolenbroek 	uint8_t buf[6], buf2[6], *buf3;
416*3ba6090fSDavid van Moolenbroek 	socklen_t len;
417*3ba6090fSDavid van Moolenbroek 	unsigned int i;
418*3ba6090fSDavid van Moolenbroek 	int fd, fd2, val;
419*3ba6090fSDavid van Moolenbroek 
420*3ba6090fSDavid van Moolenbroek 	subtest = 3;
421*3ba6090fSDavid van Moolenbroek 
422*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, SOCK_RAW, TEST_PROTO)) < 0) e(0);
423*3ba6090fSDavid van Moolenbroek 
424*3ba6090fSDavid van Moolenbroek 	if (shutdown(fd, SHUT_RD) != 0) e(0);
425*3ba6090fSDavid van Moolenbroek 
426*3ba6090fSDavid van Moolenbroek 	/* For non-ICMPv6 sockets, checksumming is disabled by default. */
427*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
428*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val, &len) != 0) e(0);
429*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
430*3ba6090fSDavid van Moolenbroek 	if (val != -1) e(0);
431*3ba6090fSDavid van Moolenbroek 
432*3ba6090fSDavid van Moolenbroek 	/* Test bad offsets. */
433*3ba6090fSDavid van Moolenbroek 	val = -2;
434*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val,
435*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != -1) e(0);
436*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
437*3ba6090fSDavid van Moolenbroek 
438*3ba6090fSDavid van Moolenbroek 	val = 1;
439*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val,
440*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != -1) e(0);
441*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
442*3ba6090fSDavid van Moolenbroek 
443*3ba6090fSDavid van Moolenbroek 	/* Now test real checksum computation. */
444*3ba6090fSDavid van Moolenbroek 	val = 0;
445*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val,
446*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
447*3ba6090fSDavid van Moolenbroek 
448*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET6, SOCK_RAW, TEST_PROTO)) < 0) e(0);
449*3ba6090fSDavid van Moolenbroek 
450*3ba6090fSDavid van Moolenbroek 	if (shutdown(fd2, SHUT_WR) != 0) e(0);
451*3ba6090fSDavid van Moolenbroek 
452*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, sizeof(buf));
453*3ba6090fSDavid van Moolenbroek 	buf[2] = 0xfe;
454*3ba6090fSDavid van Moolenbroek 	buf[3] = 0x95;
455*3ba6090fSDavid van Moolenbroek 	buf[4] = 0x4d;
456*3ba6090fSDavid van Moolenbroek 
457*3ba6090fSDavid van Moolenbroek 	memset(&sin6, 0, sizeof(sin6));
458*3ba6090fSDavid van Moolenbroek 	sin6.sin6_family = AF_INET6;
459*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6.sin6_addr, &in6addr_loopback, sizeof(sin6.sin6_addr));
460*3ba6090fSDavid van Moolenbroek 
461*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, buf, 5, 0, (struct sockaddr *)&sin6, sizeof(sin6)) != 5)
462*3ba6090fSDavid van Moolenbroek 		e(0);
463*3ba6090fSDavid van Moolenbroek 
464*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf2, sizeof(buf2), 0) != 5) e(0);
465*3ba6090fSDavid van Moolenbroek 
466*3ba6090fSDavid van Moolenbroek 	if (buf2[0] != 0xb3 || buf2[1] != 0x65) e(0);
467*3ba6090fSDavid van Moolenbroek 	if (memcmp(&buf2[2], &buf[2], 3) != 0) e(0);
468*3ba6090fSDavid van Moolenbroek 
469*3ba6090fSDavid van Moolenbroek 	/* Turn on checksum verification on the receiving socket. */
470*3ba6090fSDavid van Moolenbroek 	val = 0;
471*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IPV6, IPV6_CHECKSUM, &val,
472*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
473*3ba6090fSDavid van Moolenbroek 
474*3ba6090fSDavid van Moolenbroek 	/*
475*3ba6090fSDavid van Moolenbroek 	 * The current value of the checksum field should not be incorporated
476*3ba6090fSDavid van Moolenbroek 	 * in the checksum, as that would result in an invalid checksum.
477*3ba6090fSDavid van Moolenbroek 	 */
478*3ba6090fSDavid van Moolenbroek 	buf[0] = 0xab;
479*3ba6090fSDavid van Moolenbroek 	buf[1] = 0xcd;
480*3ba6090fSDavid van Moolenbroek 
481*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, buf, 5, 0, (struct sockaddr *)&sin6, sizeof(sin6)) != 5)
482*3ba6090fSDavid van Moolenbroek 		e(0);
483*3ba6090fSDavid van Moolenbroek 
484*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf2, sizeof(buf2), 0) != 5) e(0);
485*3ba6090fSDavid van Moolenbroek 
486*3ba6090fSDavid van Moolenbroek 	if (buf2[0] != 0xb3 || buf2[1] != 0x65) e(0);
487*3ba6090fSDavid van Moolenbroek 	if (memcmp(&buf2[2], &buf[2], 3) != 0) e(0);
488*3ba6090fSDavid van Moolenbroek 
489*3ba6090fSDavid van Moolenbroek 	/*
490*3ba6090fSDavid van Moolenbroek 	 * Turn off checksum computation on the sending side, so that the
491*3ba6090fSDavid van Moolenbroek 	 * packet ends up being dropped on the receiving side.
492*3ba6090fSDavid van Moolenbroek 	 */
493*3ba6090fSDavid van Moolenbroek 	val = -1;
494*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val,
495*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
496*3ba6090fSDavid van Moolenbroek 
497*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, buf, 5, 0, (struct sockaddr *)&sin6, sizeof(sin6)) != 5)
498*3ba6090fSDavid van Moolenbroek 		e(0);
499*3ba6090fSDavid van Moolenbroek 
500*3ba6090fSDavid van Moolenbroek 	/* Send some packets that are too small to contain the checksum. */
501*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, buf, 0, 0, (struct sockaddr *)&sin6, sizeof(sin6)) != 0)
502*3ba6090fSDavid van Moolenbroek 		e(0);
503*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, buf, 1, 0, (struct sockaddr *)&sin6, sizeof(sin6)) != 1)
504*3ba6090fSDavid van Moolenbroek 		e(0);
505*3ba6090fSDavid van Moolenbroek 
506*3ba6090fSDavid van Moolenbroek 	/*
507*3ba6090fSDavid van Moolenbroek 	 * If this recv call is "too soon" (it should not be) and the packets
508*3ba6090fSDavid van Moolenbroek 	 * arrive later anyway, then we will get a failure below.
509*3ba6090fSDavid van Moolenbroek 	 */
510*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf2, sizeof(buf2), MSG_DONTWAIT) != -1) e(0);
511*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
512*3ba6090fSDavid van Moolenbroek 
513*3ba6090fSDavid van Moolenbroek 	buf[0] = 0;
514*3ba6090fSDavid van Moolenbroek 	buf[1] = 0x67;
515*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, buf, 4, 0, (struct sockaddr *)&sin6,
516*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6)) != 4) e(0);
517*3ba6090fSDavid van Moolenbroek 
518*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf2, sizeof(buf2), 0) != 4) e(0);
519*3ba6090fSDavid van Moolenbroek 	if (memcmp(buf, buf2, 4) != 0) e(0);
520*3ba6090fSDavid van Moolenbroek 
521*3ba6090fSDavid van Moolenbroek 	/*
522*3ba6090fSDavid van Moolenbroek 	 * We repeat some of the tests with a non-zero checksum offset, just to
523*3ba6090fSDavid van Moolenbroek 	 * be sure.
524*3ba6090fSDavid van Moolenbroek 	 */
525*3ba6090fSDavid van Moolenbroek 	val = 2;
526*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val,
527*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
528*3ba6090fSDavid van Moolenbroek 
529*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
530*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val, &len) != 0) e(0);
531*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
532*3ba6090fSDavid van Moolenbroek 	if (val != 2) e(0);
533*3ba6090fSDavid van Moolenbroek 
534*3ba6090fSDavid van Moolenbroek 	buf[0] = 0x56;
535*3ba6090fSDavid van Moolenbroek 	buf[1] = 0x78;
536*3ba6090fSDavid van Moolenbroek 
537*3ba6090fSDavid van Moolenbroek 	for (i = 0; i <= 3; i++) {
538*3ba6090fSDavid van Moolenbroek 		if (sendto(fd, buf, i, 0, (struct sockaddr *)&sin6,
539*3ba6090fSDavid van Moolenbroek 		    sizeof(sin6)) != -1) e(0);
540*3ba6090fSDavid van Moolenbroek 		if (errno != EINVAL) e(0);
541*3ba6090fSDavid van Moolenbroek 	}
542*3ba6090fSDavid van Moolenbroek 
543*3ba6090fSDavid van Moolenbroek 	val = 2;
544*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IPV6, IPV6_CHECKSUM, &val,
545*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
546*3ba6090fSDavid van Moolenbroek 
547*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, buf, 4, 0, (struct sockaddr *)&sin6,
548*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6)) != 4) e(0);
549*3ba6090fSDavid van Moolenbroek 
550*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf2, sizeof(buf2), 0) != 4) e(0);
551*3ba6090fSDavid van Moolenbroek 	if (memcmp(buf, buf2, 2) != 0) e(0);
552*3ba6090fSDavid van Moolenbroek 	if (buf2[2] != 0xa8 || buf2[3] != 0x84) e(0);
553*3ba6090fSDavid van Moolenbroek 
554*3ba6090fSDavid van Moolenbroek 	val = -1;
555*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val,
556*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
557*3ba6090fSDavid van Moolenbroek 
558*3ba6090fSDavid van Moolenbroek 	buf[2] = 0xa8;
559*3ba6090fSDavid van Moolenbroek 	buf[3] = 0x85; /* deliberately bad checksum */
560*3ba6090fSDavid van Moolenbroek 
561*3ba6090fSDavid van Moolenbroek 	/* All these should be dropped on the receiver side. */
562*3ba6090fSDavid van Moolenbroek 	for (i = 0; i <= 4; i++) {
563*3ba6090fSDavid van Moolenbroek 		if (sendto(fd, buf, i, 0, (struct sockaddr *)&sin6,
564*3ba6090fSDavid van Moolenbroek 		    sizeof(sin6)) != i) e(0);
565*3ba6090fSDavid van Moolenbroek 	}
566*3ba6090fSDavid van Moolenbroek 
567*3ba6090fSDavid van Moolenbroek 	buf[3] = 0x84; /* good checksum */
568*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, buf, 4, 0, (struct sockaddr *)&sin6, sizeof(sin6)) != 4)
569*3ba6090fSDavid van Moolenbroek 		e(0);
570*3ba6090fSDavid van Moolenbroek 
571*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf2, sizeof(buf2), 0) != 4) e(0);
572*3ba6090fSDavid van Moolenbroek 	if (memcmp(buf, buf2, 4) != 0) e(0);
573*3ba6090fSDavid van Moolenbroek 
574*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf2, sizeof(buf2), MSG_DONTWAIT) != -1) e(0);
575*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
576*3ba6090fSDavid van Moolenbroek 
577*3ba6090fSDavid van Moolenbroek 	val = -1;
578*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val,
579*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
580*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IPV6, IPV6_CHECKSUM, &val,
581*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
582*3ba6090fSDavid van Moolenbroek 
583*3ba6090fSDavid van Moolenbroek 	buf[3] = 0x85;
584*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, buf, 4, 0, (struct sockaddr *)&sin6, sizeof(sin6)) != 4)
585*3ba6090fSDavid van Moolenbroek 		e(0);
586*3ba6090fSDavid van Moolenbroek 
587*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf2, sizeof(buf2), 0) != 4) e(0);
588*3ba6090fSDavid van Moolenbroek 	if (memcmp(buf, buf2, 4) != 0) e(0);
589*3ba6090fSDavid van Moolenbroek 
590*3ba6090fSDavid van Moolenbroek 	/*
591*3ba6090fSDavid van Moolenbroek 	 * The following is a lwIP-specific test: lwIP does not support storing
592*3ba6090fSDavid van Moolenbroek 	 * generated checksums beyond the first pbuf.  We do not know the size
593*3ba6090fSDavid van Moolenbroek 	 * of the first pbuf until we actually send a packet, so the setsockopt
594*3ba6090fSDavid van Moolenbroek 	 * call will not fail, but sending the packet will.  Depending on the
595*3ba6090fSDavid van Moolenbroek 	 * buffer allocation strategy, the following test may or may not
596*3ba6090fSDavid van Moolenbroek 	 * trigger this case; simply ensure that we do not crash the service.
597*3ba6090fSDavid van Moolenbroek 	 */
598*3ba6090fSDavid van Moolenbroek 	if ((buf3 = malloc(4096)) == NULL) e(0);
599*3ba6090fSDavid van Moolenbroek 
600*3ba6090fSDavid van Moolenbroek 	val = 4094;
601*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val,
602*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
603*3ba6090fSDavid van Moolenbroek 
604*3ba6090fSDavid van Moolenbroek 	/* This call may or may not fail, but if it fails, it yields EINVAL. */
605*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, buf3, 4096, 0, (struct sockaddr *)&sin6,
606*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6)) == -1 && errno != EINVAL) e(0);
607*3ba6090fSDavid van Moolenbroek 
608*3ba6090fSDavid van Moolenbroek 	free(buf3);
609*3ba6090fSDavid van Moolenbroek 
610*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
611*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
612*3ba6090fSDavid van Moolenbroek 
613*3ba6090fSDavid van Moolenbroek 	/* For ICMPv6 packets, checksumming is always enabled. */
614*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) e(0);
615*3ba6090fSDavid van Moolenbroek 
616*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
617*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val, &len) != 0) e(0);
618*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
619*3ba6090fSDavid van Moolenbroek 	if (val != 2) e(0);
620*3ba6090fSDavid van Moolenbroek 
621*3ba6090fSDavid van Moolenbroek 	val = -1;
622*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val,
623*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != -1) e(0);
624*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
625*3ba6090fSDavid van Moolenbroek 
626*3ba6090fSDavid van Moolenbroek 	memset(&icmp6_hdr, 0, sizeof(icmp6_hdr));
627*3ba6090fSDavid van Moolenbroek 	icmp6_hdr.icmp6_type = TEST_ICMPV6_TYPE_A;
628*3ba6090fSDavid van Moolenbroek 	icmp6_hdr.icmp6_code = 123;
629*3ba6090fSDavid van Moolenbroek 	icmp6_hdr.icmp6_cksum = htons(0);
630*3ba6090fSDavid van Moolenbroek 
631*3ba6090fSDavid van Moolenbroek 	len = offsetof(struct icmp6_hdr, icmp6_dataun);
632*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, &icmp6_hdr, len, 0, (struct sockaddr *)&sin6,
633*3ba6090fSDavid van Moolenbroek 	   sizeof(sin6)) != len) e(0);
634*3ba6090fSDavid van Moolenbroek 
635*3ba6090fSDavid van Moolenbroek 	if (recv(fd, &icmp6_hdr, sizeof(icmp6_hdr), 0) != len) e(0);
636*3ba6090fSDavid van Moolenbroek 
637*3ba6090fSDavid van Moolenbroek 	if (icmp6_hdr.icmp6_type != TEST_ICMPV6_TYPE_A) e(0);
638*3ba6090fSDavid van Moolenbroek 	if (icmp6_hdr.icmp6_code != 123) e(0);
639*3ba6090fSDavid van Moolenbroek 	if (ntohs(icmp6_hdr.icmp6_cksum) != 0x3744) e(0);
640*3ba6090fSDavid van Moolenbroek 
641*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
642*3ba6090fSDavid van Moolenbroek 
643*3ba6090fSDavid van Moolenbroek 	/* For IPv4 and non-RAW IPv6 sockets, the option does not work. */
644*3ba6090fSDavid van Moolenbroek 	for (i = 0; i <= 2; i++) {
645*3ba6090fSDavid van Moolenbroek 		switch (i) {
646*3ba6090fSDavid van Moolenbroek 		case 0: fd = socket(AF_INET6, SOCK_DGRAM, 0); break;
647*3ba6090fSDavid van Moolenbroek 		case 1: fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMPV6); break;
648*3ba6090fSDavid van Moolenbroek 		case 2: fd = socket(AF_INET, SOCK_RAW, TEST_PROTO); break;
649*3ba6090fSDavid van Moolenbroek 		}
650*3ba6090fSDavid van Moolenbroek 		if (fd < 0) e(0);
651*3ba6090fSDavid van Moolenbroek 
652*3ba6090fSDavid van Moolenbroek 		val = -1;
653*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val,
654*3ba6090fSDavid van Moolenbroek 		    sizeof(val)) != -1) e(0);
655*3ba6090fSDavid van Moolenbroek 		if (errno != ENOPROTOOPT) e(0);
656*3ba6090fSDavid van Moolenbroek 
657*3ba6090fSDavid van Moolenbroek 		len = sizeof(val);
658*3ba6090fSDavid van Moolenbroek 		if (getsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val,
659*3ba6090fSDavid van Moolenbroek 		    &len) != -1) e(0);
660*3ba6090fSDavid van Moolenbroek 		if (errno != ENOPROTOOPT) e(0);
661*3ba6090fSDavid van Moolenbroek 
662*3ba6090fSDavid van Moolenbroek 		if (close(fd) != 0) e(0);
663*3ba6090fSDavid van Moolenbroek 	}
664*3ba6090fSDavid van Moolenbroek }
665*3ba6090fSDavid van Moolenbroek 
666*3ba6090fSDavid van Moolenbroek /*
667*3ba6090fSDavid van Moolenbroek  * Test the ICMP6_FILTER socket option.
668*3ba6090fSDavid van Moolenbroek  */
669*3ba6090fSDavid van Moolenbroek static void
test92d(void)670*3ba6090fSDavid van Moolenbroek test92d(void)
671*3ba6090fSDavid van Moolenbroek {
672*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in6 sin6;
673*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in sin;
674*3ba6090fSDavid van Moolenbroek 	struct icmp6_filter filter;
675*3ba6090fSDavid van Moolenbroek 	struct icmp6_hdr packet;
676*3ba6090fSDavid van Moolenbroek 	socklen_t len;
677*3ba6090fSDavid van Moolenbroek 	struct timeval tv;
678*3ba6090fSDavid van Moolenbroek 	unsigned int i;
679*3ba6090fSDavid van Moolenbroek 	int fd, fd2;
680*3ba6090fSDavid van Moolenbroek 
681*3ba6090fSDavid van Moolenbroek 	subtest = 4;
682*3ba6090fSDavid van Moolenbroek 
683*3ba6090fSDavid van Moolenbroek 	/*
684*3ba6090fSDavid van Moolenbroek 	 * We use two different sockets to eliminate the possibility that the
685*3ba6090fSDavid van Moolenbroek 	 * filter is also applied when sending packets--it should not be.
686*3ba6090fSDavid van Moolenbroek 	 */
687*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) e(0);
688*3ba6090fSDavid van Moolenbroek 
689*3ba6090fSDavid van Moolenbroek 	if (shutdown(fd, SHUT_WR) != 0) e(0);
690*3ba6090fSDavid van Moolenbroek 
691*3ba6090fSDavid van Moolenbroek 	len = sizeof(filter);
692*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, &len) != 0)
693*3ba6090fSDavid van Moolenbroek 		e(0);
694*3ba6090fSDavid van Moolenbroek 
695*3ba6090fSDavid van Moolenbroek 	/* We do not aim to test the ICMP6_FILTER macros here. */
696*3ba6090fSDavid van Moolenbroek 	for (i = 0; i <= UINT8_MAX; i++)
697*3ba6090fSDavid van Moolenbroek 		if (!ICMP6_FILTER_WILLPASS(i, &filter)) e(0);
698*3ba6090fSDavid van Moolenbroek 
699*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) e(0);
700*3ba6090fSDavid van Moolenbroek 
701*3ba6090fSDavid van Moolenbroek 	ICMP6_FILTER_SETBLOCKALL(&filter);
702*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
703*3ba6090fSDavid van Moolenbroek 	    sizeof(filter)) != 0) e(0);
704*3ba6090fSDavid van Moolenbroek 
705*3ba6090fSDavid van Moolenbroek 	len = sizeof(filter);
706*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd2, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, &len) != 0)
707*3ba6090fSDavid van Moolenbroek 		e(0);
708*3ba6090fSDavid van Moolenbroek 
709*3ba6090fSDavid van Moolenbroek 	for (i = 0; i <= UINT8_MAX; i++)
710*3ba6090fSDavid van Moolenbroek 		if (ICMP6_FILTER_WILLPASS(i, &filter)) e(0);
711*3ba6090fSDavid van Moolenbroek 
712*3ba6090fSDavid van Moolenbroek 	ICMP6_FILTER_SETPASSALL(&filter);
713*3ba6090fSDavid van Moolenbroek 	ICMP6_FILTER_SETBLOCK(TEST_ICMPV6_TYPE_A, &filter);
714*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
715*3ba6090fSDavid van Moolenbroek 	    sizeof(filter)) != 0) e(0);
716*3ba6090fSDavid van Moolenbroek 
717*3ba6090fSDavid van Moolenbroek 	memset(&sin6, 0, sizeof(sin6));
718*3ba6090fSDavid van Moolenbroek 	sin6.sin6_family = AF_INET6;
719*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6.sin6_addr, &in6addr_loopback, sizeof(sin6.sin6_addr));
720*3ba6090fSDavid van Moolenbroek 
721*3ba6090fSDavid van Moolenbroek 	memset(&packet, 0, sizeof(packet));
722*3ba6090fSDavid van Moolenbroek 	packet.icmp6_type = TEST_ICMPV6_TYPE_A;
723*3ba6090fSDavid van Moolenbroek 	packet.icmp6_code = 12;
724*3ba6090fSDavid van Moolenbroek 
725*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, &packet, sizeof(packet), 0, (struct sockaddr *)&sin6,
726*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6)) != sizeof(packet)) e(0);
727*3ba6090fSDavid van Moolenbroek 
728*3ba6090fSDavid van Moolenbroek 	packet.icmp6_type = TEST_ICMPV6_TYPE_B;
729*3ba6090fSDavid van Moolenbroek 	packet.icmp6_code = 34;
730*3ba6090fSDavid van Moolenbroek 
731*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, &packet, sizeof(packet), 0, (struct sockaddr *)&sin6,
732*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6)) != sizeof(packet)) e(0);
733*3ba6090fSDavid van Moolenbroek 
734*3ba6090fSDavid van Moolenbroek 	memset(&packet, 0, sizeof(packet));
735*3ba6090fSDavid van Moolenbroek 
736*3ba6090fSDavid van Moolenbroek 	if (recv(fd, &packet, sizeof(packet), 0) != sizeof(packet)) e(0);
737*3ba6090fSDavid van Moolenbroek 	if (packet.icmp6_type != TEST_ICMPV6_TYPE_B) e(0);
738*3ba6090fSDavid van Moolenbroek 	if (packet.icmp6_code != 34) e(0);
739*3ba6090fSDavid van Moolenbroek 
740*3ba6090fSDavid van Moolenbroek 	if (recv(fd, &packet, sizeof(packet), MSG_DONTWAIT) != -1) e(0);
741*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
742*3ba6090fSDavid van Moolenbroek 
743*3ba6090fSDavid van Moolenbroek 	ICMP6_FILTER_SETBLOCKALL(&filter);
744*3ba6090fSDavid van Moolenbroek 	ICMP6_FILTER_SETPASS(TEST_ICMPV6_TYPE_A, &filter);
745*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
746*3ba6090fSDavid van Moolenbroek 	    sizeof(filter)) != 0) e(0);
747*3ba6090fSDavid van Moolenbroek 
748*3ba6090fSDavid van Moolenbroek 	memset(&packet, 0, sizeof(packet));
749*3ba6090fSDavid van Moolenbroek 	packet.icmp6_type = TEST_ICMPV6_TYPE_B;
750*3ba6090fSDavid van Moolenbroek 	packet.icmp6_code = 56;
751*3ba6090fSDavid van Moolenbroek 
752*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, &packet, sizeof(packet), 0, (struct sockaddr *)&sin6,
753*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6)) != sizeof(packet)) e(0);
754*3ba6090fSDavid van Moolenbroek 
755*3ba6090fSDavid van Moolenbroek 	packet.icmp6_type = TEST_ICMPV6_TYPE_A;
756*3ba6090fSDavid van Moolenbroek 	packet.icmp6_code = 78;
757*3ba6090fSDavid van Moolenbroek 
758*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, &packet, sizeof(packet), 0, (struct sockaddr *)&sin6,
759*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6)) != sizeof(packet)) e(0);
760*3ba6090fSDavid van Moolenbroek 
761*3ba6090fSDavid van Moolenbroek 	/*
762*3ba6090fSDavid van Moolenbroek 	 * RFC 3542 states that setting a zero-length filter resets the filter.
763*3ba6090fSDavid van Moolenbroek 	 * This seems like one of those things that a standardization RFC
764*3ba6090fSDavid van Moolenbroek 	 * should not mandate: it is redundant at the API level (one can set a
765*3ba6090fSDavid van Moolenbroek 	 * PASSALL filter, which is the required default), it relies on an edge
766*3ba6090fSDavid van Moolenbroek 	 * case (setsockopt taking a zero-length argument), and as a "shortcut"
767*3ba6090fSDavid van Moolenbroek 	 * it does not even cover a case that is likely to occur (no actual
768*3ba6090fSDavid van Moolenbroek 	 * program would reset its filter on a regular basis).  Presumably it
769*3ba6090fSDavid van Moolenbroek 	 * is a way to deallocate filter memory on some platforms, but was that
770*3ba6090fSDavid van Moolenbroek 	 * worth the RFC inclusion?  Anyhow, we support it; NetBSD does not.
771*3ba6090fSDavid van Moolenbroek 	 */
772*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, NULL, 0) != 0) e(0);
773*3ba6090fSDavid van Moolenbroek 
774*3ba6090fSDavid van Moolenbroek 	packet.icmp6_type = TEST_ICMPV6_TYPE_B;
775*3ba6090fSDavid van Moolenbroek 	packet.icmp6_code = 90;
776*3ba6090fSDavid van Moolenbroek 
777*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, &packet, sizeof(packet), 0, (struct sockaddr *)&sin6,
778*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6)) != sizeof(packet)) e(0);
779*3ba6090fSDavid van Moolenbroek 
780*3ba6090fSDavid van Moolenbroek 	memset(&packet, 0, sizeof(packet));
781*3ba6090fSDavid van Moolenbroek 
782*3ba6090fSDavid van Moolenbroek 	if (recv(fd, &packet, sizeof(packet), 0) != sizeof(packet)) e(0);
783*3ba6090fSDavid van Moolenbroek 	if (packet.icmp6_type != TEST_ICMPV6_TYPE_A) e(0);
784*3ba6090fSDavid van Moolenbroek 	if (packet.icmp6_code != 78) e(0);
785*3ba6090fSDavid van Moolenbroek 
786*3ba6090fSDavid van Moolenbroek 	if (recv(fd, &packet, sizeof(packet), 0) != sizeof(packet)) e(0);
787*3ba6090fSDavid van Moolenbroek 	if (packet.icmp6_type != TEST_ICMPV6_TYPE_B) e(0);
788*3ba6090fSDavid van Moolenbroek 	if (packet.icmp6_code != 90) e(0);
789*3ba6090fSDavid van Moolenbroek 
790*3ba6090fSDavid van Moolenbroek 	if (recv(fd, &packet, sizeof(packet), MSG_DONTWAIT) != -1) e(0);
791*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
792*3ba6090fSDavid van Moolenbroek 
793*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, &packet, sizeof(packet), MSG_DONTWAIT) != -1) e(0);
794*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
795*3ba6090fSDavid van Moolenbroek 
796*3ba6090fSDavid van Moolenbroek 	len = sizeof(filter);
797*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, &len) != 0)
798*3ba6090fSDavid van Moolenbroek 		e(0);
799*3ba6090fSDavid van Moolenbroek 
800*3ba6090fSDavid van Moolenbroek 	for (i = 0; i <= UINT8_MAX; i++)
801*3ba6090fSDavid van Moolenbroek 		if (!ICMP6_FILTER_WILLPASS(i, &filter)) e(0);
802*3ba6090fSDavid van Moolenbroek 
803*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
804*3ba6090fSDavid van Moolenbroek 
805*3ba6090fSDavid van Moolenbroek 	/*
806*3ba6090fSDavid van Moolenbroek 	 * Let's get weird and send an ICMPv6 packet from an IPv4 socket.
807*3ba6090fSDavid van Moolenbroek 	 * Currently, such packets are always dropped based on the rule that
808*3ba6090fSDavid van Moolenbroek 	 * IPv6 sockets with checksumming enabled drop all IPv4 packets.  As it
809*3ba6090fSDavid van Moolenbroek 	 * happens, that is also all that is keeping this packet from arriving.
810*3ba6090fSDavid van Moolenbroek 	 */
811*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMPV6)) < 0) e(0);
812*3ba6090fSDavid van Moolenbroek 
813*3ba6090fSDavid van Moolenbroek 	ICMP6_FILTER_SETBLOCKALL(&filter);
814*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
815*3ba6090fSDavid van Moolenbroek 	    sizeof(filter)) != 0) e(0);
816*3ba6090fSDavid van Moolenbroek 
817*3ba6090fSDavid van Moolenbroek 	memset(&sin, 0, sizeof(sin));
818*3ba6090fSDavid van Moolenbroek 	sin.sin_family = AF_INET;
819*3ba6090fSDavid van Moolenbroek 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
820*3ba6090fSDavid van Moolenbroek 
821*3ba6090fSDavid van Moolenbroek 	memset(&packet, 0, sizeof(packet));
822*3ba6090fSDavid van Moolenbroek 	packet.icmp6_type = TEST_ICMPV6_TYPE_A;
823*3ba6090fSDavid van Moolenbroek 	packet.icmp6_code = 123;
824*3ba6090fSDavid van Moolenbroek 	packet.icmp6_cksum = htons(0); /* TODO: use valid checksum */
825*3ba6090fSDavid van Moolenbroek 
826*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, &packet, sizeof(packet), 0, (struct sockaddr *)&sin,
827*3ba6090fSDavid van Moolenbroek 	    sizeof(sin)) != sizeof(packet)) e(0);
828*3ba6090fSDavid van Moolenbroek 
829*3ba6090fSDavid van Moolenbroek 	/*
830*3ba6090fSDavid van Moolenbroek 	 * If the packet were to arrive at all, it should arrive instantly, so
831*3ba6090fSDavid van Moolenbroek 	 * this is just an excuse to use SO_RCVTIMEO.
832*3ba6090fSDavid van Moolenbroek 	 */
833*3ba6090fSDavid van Moolenbroek 	tv.tv_sec = 0;
834*3ba6090fSDavid van Moolenbroek 	tv.tv_usec = 100000;
835*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0)
836*3ba6090fSDavid van Moolenbroek 		e(0);
837*3ba6090fSDavid van Moolenbroek 
838*3ba6090fSDavid van Moolenbroek 	if (recv(fd, &packet, sizeof(packet), 0) != -1) e(0);
839*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
840*3ba6090fSDavid van Moolenbroek 
841*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
842*3ba6090fSDavid van Moolenbroek 
843*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
844*3ba6090fSDavid van Moolenbroek 
845*3ba6090fSDavid van Moolenbroek 	/* Make sure ICMP6_FILTER works on IPv6-ICMPv6 sockets only. */
846*3ba6090fSDavid van Moolenbroek 	for (i = 0; i <= 2; i++) {
847*3ba6090fSDavid van Moolenbroek 		switch (i) {
848*3ba6090fSDavid van Moolenbroek 		case 0: fd = socket(AF_INET6, SOCK_DGRAM, 0); break;
849*3ba6090fSDavid van Moolenbroek 		case 1: fd = socket(AF_INET6, SOCK_RAW, TEST_PROTO); break;
850*3ba6090fSDavid van Moolenbroek 		case 2: fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMPV6); break;
851*3ba6090fSDavid van Moolenbroek 		}
852*3ba6090fSDavid van Moolenbroek 		if (fd < 0) e(0);
853*3ba6090fSDavid van Moolenbroek 
854*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
855*3ba6090fSDavid van Moolenbroek 		    sizeof(filter)) != -1) e(0);
856*3ba6090fSDavid van Moolenbroek 		if (errno != ENOPROTOOPT) e(0);
857*3ba6090fSDavid van Moolenbroek 
858*3ba6090fSDavid van Moolenbroek 		len = sizeof(filter);
859*3ba6090fSDavid van Moolenbroek 		if (getsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
860*3ba6090fSDavid van Moolenbroek 		    &len) != -1) e(0);
861*3ba6090fSDavid van Moolenbroek 		if (errno != ENOPROTOOPT) e(0);
862*3ba6090fSDavid van Moolenbroek 
863*3ba6090fSDavid van Moolenbroek 		if (close(fd) != 0) e(0);
864*3ba6090fSDavid van Moolenbroek 	}
865*3ba6090fSDavid van Moolenbroek }
866*3ba6090fSDavid van Moolenbroek 
867*3ba6090fSDavid van Moolenbroek /*
868*3ba6090fSDavid van Moolenbroek  * Test that IPPROTO_ICMPV6 has no special value on IPv4 raw sockets.  In
869*3ba6090fSDavid van Moolenbroek  * particular, test that no checksum is generated or verified.  By now we have
870*3ba6090fSDavid van Moolenbroek  * already tested that none of the IPv6 socket options work on such sockets.
871*3ba6090fSDavid van Moolenbroek  */
872*3ba6090fSDavid van Moolenbroek static void
test92e(void)873*3ba6090fSDavid van Moolenbroek test92e(void)
874*3ba6090fSDavid van Moolenbroek {
875*3ba6090fSDavid van Moolenbroek 	char buf[sizeof(struct ip) + sizeof(struct icmp6_hdr)];
876*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in sin;
877*3ba6090fSDavid van Moolenbroek 	struct icmp6_hdr packet;
878*3ba6090fSDavid van Moolenbroek 	int fd;
879*3ba6090fSDavid van Moolenbroek 
880*3ba6090fSDavid van Moolenbroek 	subtest = 5;
881*3ba6090fSDavid van Moolenbroek 
882*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMPV6)) < 0) e(0);
883*3ba6090fSDavid van Moolenbroek 
884*3ba6090fSDavid van Moolenbroek 	memset(&packet, 0, sizeof(packet));
885*3ba6090fSDavid van Moolenbroek 	packet.icmp6_type = TEST_ICMPV6_TYPE_A;
886*3ba6090fSDavid van Moolenbroek 	packet.icmp6_code = 123;
887*3ba6090fSDavid van Moolenbroek 	packet.icmp6_cksum = htons(0);
888*3ba6090fSDavid van Moolenbroek 
889*3ba6090fSDavid van Moolenbroek 	memset(&sin, 0, sizeof(sin));
890*3ba6090fSDavid van Moolenbroek 	sin.sin_family = AF_INET;
891*3ba6090fSDavid van Moolenbroek 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
892*3ba6090fSDavid van Moolenbroek 
893*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, &packet, sizeof(packet), 0, (struct sockaddr *)&sin,
894*3ba6090fSDavid van Moolenbroek 	    sizeof(sin)) != sizeof(packet)) e(0);
895*3ba6090fSDavid van Moolenbroek 
896*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), 0) != sizeof(buf)) e(0);
897*3ba6090fSDavid van Moolenbroek 
898*3ba6090fSDavid van Moolenbroek 	memcpy(&packet, &buf[sizeof(struct ip)], sizeof(packet));
899*3ba6090fSDavid van Moolenbroek 	if (packet.icmp6_type != TEST_ICMPV6_TYPE_A) e(0);
900*3ba6090fSDavid van Moolenbroek 	if (packet.icmp6_code != 123) e(0);
901*3ba6090fSDavid van Moolenbroek 	if (packet.icmp6_cksum != htons(0)) e(0);
902*3ba6090fSDavid van Moolenbroek 
903*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
904*3ba6090fSDavid van Moolenbroek }
905*3ba6090fSDavid van Moolenbroek 
906*3ba6090fSDavid van Moolenbroek struct testpkt {
907*3ba6090fSDavid van Moolenbroek 	struct ip ip;
908*3ba6090fSDavid van Moolenbroek 	struct udphdr udp;
909*3ba6090fSDavid van Moolenbroek 	uint8_t data[6];
910*3ba6090fSDavid van Moolenbroek } __packed;
911*3ba6090fSDavid van Moolenbroek 
912*3ba6090fSDavid van Moolenbroek /*
913*3ba6090fSDavid van Moolenbroek  * Test the IP_HDRINCL socket option.
914*3ba6090fSDavid van Moolenbroek  */
915*3ba6090fSDavid van Moolenbroek static void
test92f(void)916*3ba6090fSDavid van Moolenbroek test92f(void)
917*3ba6090fSDavid van Moolenbroek {
918*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in sin;
919*3ba6090fSDavid van Moolenbroek 	struct testpkt pkt, pkt2;
920*3ba6090fSDavid van Moolenbroek 	socklen_t len;
921*3ba6090fSDavid van Moolenbroek 	char buf[7];
922*3ba6090fSDavid van Moolenbroek 	unsigned int i;
923*3ba6090fSDavid van Moolenbroek 	int fd, fd2, val;
924*3ba6090fSDavid van Moolenbroek 
925*3ba6090fSDavid van Moolenbroek 	subtest = 6;
926*3ba6090fSDavid van Moolenbroek 
927*3ba6090fSDavid van Moolenbroek 	/* See if we can successfully feign a UDP packet. */
928*3ba6090fSDavid van Moolenbroek 	memset(&pkt, 0, sizeof(pkt));
929*3ba6090fSDavid van Moolenbroek 	pkt.ip.ip_v = IPVERSION;
930*3ba6090fSDavid van Moolenbroek 	pkt.ip.ip_hl = sizeof(pkt.ip) >> 2;
931*3ba6090fSDavid van Moolenbroek 	pkt.ip.ip_tos = 123;
932*3ba6090fSDavid van Moolenbroek 	pkt.ip.ip_len = sizeof(pkt);			/* swapped by OS */
933*3ba6090fSDavid van Moolenbroek 	pkt.ip.ip_id = htons(456);
934*3ba6090fSDavid van Moolenbroek 	pkt.ip.ip_off = IP_DF;				/* swapped by OS */
935*3ba6090fSDavid van Moolenbroek 	pkt.ip.ip_ttl = 78;
936*3ba6090fSDavid van Moolenbroek 	pkt.ip.ip_p = IPPROTO_UDP;
937*3ba6090fSDavid van Moolenbroek 	pkt.ip.ip_sum = htons(0);			/* filled by OS */
938*3ba6090fSDavid van Moolenbroek 	pkt.ip.ip_src.s_addr = htonl(INADDR_LOOPBACK);
939*3ba6090fSDavid van Moolenbroek 	pkt.ip.ip_dst.s_addr = htonl(INADDR_LOOPBACK);
940*3ba6090fSDavid van Moolenbroek 	pkt.udp.uh_sport = htons(TEST_PORT_B);
941*3ba6090fSDavid van Moolenbroek 	pkt.udp.uh_dport = htons(TEST_PORT_A);
942*3ba6090fSDavid van Moolenbroek 	pkt.udp.uh_sum = htons(0); /* lazy.. */
943*3ba6090fSDavid van Moolenbroek 	pkt.udp.uh_ulen = htons(sizeof(pkt.udp) + sizeof(pkt.data));
944*3ba6090fSDavid van Moolenbroek 	memcpy(pkt.data, "Hello!", sizeof(pkt.data));
945*3ba6090fSDavid van Moolenbroek 
946*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) e(0);
947*3ba6090fSDavid van Moolenbroek 
948*3ba6090fSDavid van Moolenbroek 	if (shutdown(fd, SHUT_RD) != 0) e(0);
949*3ba6090fSDavid van Moolenbroek 
950*3ba6090fSDavid van Moolenbroek 	/* IP_HDRINCL is never enabled by default. */
951*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
952*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IP, IP_HDRINCL, &val, &len) != 0) e(0);
953*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
954*3ba6090fSDavid van Moolenbroek 	if (val != 0) e(0);
955*3ba6090fSDavid van Moolenbroek 
956*3ba6090fSDavid van Moolenbroek 	val = 1;
957*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &val, sizeof(val)) != 0)
958*3ba6090fSDavid van Moolenbroek 		e(0);
959*3ba6090fSDavid van Moolenbroek 
960*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
961*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IP, IP_HDRINCL, &val, &len) != 0) e(0);
962*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
963*3ba6090fSDavid van Moolenbroek 	if (val != 1) e(0);
964*3ba6090fSDavid van Moolenbroek 
965*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) e(0);
966*3ba6090fSDavid van Moolenbroek 
967*3ba6090fSDavid van Moolenbroek 	memset(&sin, 0, sizeof(sin));
968*3ba6090fSDavid van Moolenbroek 	sin.sin_family = AF_INET;
969*3ba6090fSDavid van Moolenbroek 	sin.sin_port = htons(TEST_PORT_A);
970*3ba6090fSDavid van Moolenbroek 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
971*3ba6090fSDavid van Moolenbroek 
972*3ba6090fSDavid van Moolenbroek 	if (bind(fd2, (struct sockaddr *)&sin, sizeof(sin)) != 0) e(0);
973*3ba6090fSDavid van Moolenbroek 
974*3ba6090fSDavid van Moolenbroek 	sin.sin_port = htons(0);
975*3ba6090fSDavid van Moolenbroek 
976*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, &pkt, sizeof(pkt), 0, (struct sockaddr *)&sin,
977*3ba6090fSDavid van Moolenbroek 	    sizeof(sin)) != sizeof(pkt)) e(0);
978*3ba6090fSDavid van Moolenbroek 
979*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, &buf, sizeof(buf), 0) != sizeof(pkt.data)) e(0);
980*3ba6090fSDavid van Moolenbroek 	if (memcmp(buf, pkt.data, sizeof(pkt.data)) != 0) e(0);
981*3ba6090fSDavid van Moolenbroek 
982*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
983*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
984*3ba6090fSDavid van Moolenbroek 
985*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, SOCK_RAW, TEST_PROTO)) < 0) e(0);
986*3ba6090fSDavid van Moolenbroek 
987*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
988*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IP, IP_HDRINCL, &val, &len) != 0) e(0);
989*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
990*3ba6090fSDavid van Moolenbroek 	if (val != 0) e(0);
991*3ba6090fSDavid van Moolenbroek 
992*3ba6090fSDavid van Moolenbroek 	if (shutdown(fd, SHUT_RD) != 0) e(0);
993*3ba6090fSDavid van Moolenbroek 
994*3ba6090fSDavid van Moolenbroek 	/* See if we can receive a packet for our own protocol. */
995*3ba6090fSDavid van Moolenbroek 	pkt.ip.ip_p = TEST_PROTO;
996*3ba6090fSDavid van Moolenbroek 
997*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET, SOCK_RAW, TEST_PROTO)) < 0) e(0);
998*3ba6090fSDavid van Moolenbroek 
999*3ba6090fSDavid van Moolenbroek 	val = 1;
1000*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &val, sizeof(val)) != 0)
1001*3ba6090fSDavid van Moolenbroek 		e(0);
1002*3ba6090fSDavid van Moolenbroek 
1003*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, &pkt, sizeof(pkt), 0, (struct sockaddr *)&sin,
1004*3ba6090fSDavid van Moolenbroek 	    sizeof(sin)) != sizeof(pkt)) e(0);
1005*3ba6090fSDavid van Moolenbroek 
1006*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, &pkt2, sizeof(pkt2), 0) != sizeof(pkt2)) e(0);
1007*3ba6090fSDavid van Moolenbroek 
1008*3ba6090fSDavid van Moolenbroek 	if (pkt2.ip.ip_v != pkt.ip.ip_v) e(0);
1009*3ba6090fSDavid van Moolenbroek 	if (pkt2.ip.ip_hl != pkt.ip.ip_hl) e(0);
1010*3ba6090fSDavid van Moolenbroek 	if (pkt2.ip.ip_tos != pkt.ip.ip_tos) e(0);
1011*3ba6090fSDavid van Moolenbroek 	if (pkt2.ip.ip_len != pkt.ip.ip_len) e(0);
1012*3ba6090fSDavid van Moolenbroek 	if (pkt2.ip.ip_id != pkt.ip.ip_id) e(0);
1013*3ba6090fSDavid van Moolenbroek 	if (pkt2.ip.ip_off != pkt.ip.ip_off) e(0);
1014*3ba6090fSDavid van Moolenbroek 	if (pkt2.ip.ip_ttl != pkt.ip.ip_ttl) e(0);
1015*3ba6090fSDavid van Moolenbroek 	if (pkt2.ip.ip_p != pkt.ip.ip_p) e(0);
1016*3ba6090fSDavid van Moolenbroek 	if (pkt2.ip.ip_sum == htons(0)) e(0);
1017*3ba6090fSDavid van Moolenbroek 	if (pkt2.ip.ip_src.s_addr != pkt.ip.ip_src.s_addr) e(0);
1018*3ba6090fSDavid van Moolenbroek 	if (pkt2.ip.ip_dst.s_addr != pkt.ip.ip_dst.s_addr) e(0);
1019*3ba6090fSDavid van Moolenbroek 
1020*3ba6090fSDavid van Moolenbroek 	/*
1021*3ba6090fSDavid van Moolenbroek 	 * Test sending packets with weird sizes to ensure that we do not crash
1022*3ba6090fSDavid van Moolenbroek 	 * the service.  These packets would never arrive anyway.
1023*3ba6090fSDavid van Moolenbroek 	 */
1024*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, &pkt, 0, 0, (struct sockaddr *)&sin,
1025*3ba6090fSDavid van Moolenbroek 	    sizeof(sin)) != -1) e(0);
1026*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
1027*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, &pkt, sizeof(pkt.ip) - 1, 0, (struct sockaddr *)&sin,
1028*3ba6090fSDavid van Moolenbroek 	    sizeof(sin)) != -1) e(0);
1029*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
1030*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, &pkt, sizeof(pkt.ip), 0, (struct sockaddr *)&sin,
1031*3ba6090fSDavid van Moolenbroek 	    sizeof(sin)) != sizeof(pkt.ip)) e(0);
1032*3ba6090fSDavid van Moolenbroek 
1033*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, &pkt2, sizeof(pkt2), MSG_DONTWAIT) != -1) e(0);
1034*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
1035*3ba6090fSDavid van Moolenbroek 
1036*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
1037*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1038*3ba6090fSDavid van Moolenbroek 
1039*3ba6090fSDavid van Moolenbroek 	/* Ensure that the socket option does not work on other types. */
1040*3ba6090fSDavid van Moolenbroek 	for (i = 0; i <= 1; i++) {
1041*3ba6090fSDavid van Moolenbroek 		switch (i) {
1042*3ba6090fSDavid van Moolenbroek 		case 0: fd = socket(AF_INET, SOCK_DGRAM, 0); break;
1043*3ba6090fSDavid van Moolenbroek 		case 1: fd = socket(AF_INET6, SOCK_RAW, TEST_PROTO); break;
1044*3ba6090fSDavid van Moolenbroek 		}
1045*3ba6090fSDavid van Moolenbroek 		if (fd < 0) e(0);
1046*3ba6090fSDavid van Moolenbroek 
1047*3ba6090fSDavid van Moolenbroek 		len = sizeof(val);
1048*3ba6090fSDavid van Moolenbroek 		if (getsockopt(fd, IPPROTO_IP, IP_HDRINCL, &val,
1049*3ba6090fSDavid van Moolenbroek 		    &len) != -1) e(0);
1050*3ba6090fSDavid van Moolenbroek 		if (errno != ENOPROTOOPT) e(0);
1051*3ba6090fSDavid van Moolenbroek 
1052*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &val,
1053*3ba6090fSDavid van Moolenbroek 		    sizeof(val)) != -1) e(0);
1054*3ba6090fSDavid van Moolenbroek 		if (errno != ENOPROTOOPT) e(0);
1055*3ba6090fSDavid van Moolenbroek 
1056*3ba6090fSDavid van Moolenbroek 		if (close(fd) != 0) e(0);
1057*3ba6090fSDavid van Moolenbroek 	}
1058*3ba6090fSDavid van Moolenbroek }
1059*3ba6090fSDavid van Moolenbroek 
1060*3ba6090fSDavid van Moolenbroek /*
1061*3ba6090fSDavid van Moolenbroek  * Test the IPPROTO_RAW socket protocol.  This test mostly shows that the
1062*3ba6090fSDavid van Moolenbroek  * IPPROTO_RAW protocol is nothing special: for both IPv4 and IPv6, it sends
1063*3ba6090fSDavid van Moolenbroek  * and receives packets with that protocol number.  We already tested earlier
1064*3ba6090fSDavid van Moolenbroek  * that IP_HDRINCL is disabled by default on IPPROTO_RAW sockets, too.
1065*3ba6090fSDavid van Moolenbroek  */
1066*3ba6090fSDavid van Moolenbroek static void
test92g(void)1067*3ba6090fSDavid van Moolenbroek test92g(void)
1068*3ba6090fSDavid van Moolenbroek {
1069*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in sin;
1070*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in6 sin6;
1071*3ba6090fSDavid van Moolenbroek 	char buf[sizeof(struct ip) + 1];
1072*3ba6090fSDavid van Moolenbroek 	int fd;
1073*3ba6090fSDavid van Moolenbroek 
1074*3ba6090fSDavid van Moolenbroek 	subtest = 7;
1075*3ba6090fSDavid van Moolenbroek 
1076*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) e(0);
1077*3ba6090fSDavid van Moolenbroek 
1078*3ba6090fSDavid van Moolenbroek 	memset(&sin, 0, sizeof(sin));
1079*3ba6090fSDavid van Moolenbroek 	sin.sin_family = AF_INET;
1080*3ba6090fSDavid van Moolenbroek 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1081*3ba6090fSDavid van Moolenbroek 
1082*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, "A", 1, 0, (struct sockaddr *)&sin,
1083*3ba6090fSDavid van Moolenbroek 	    sizeof(sin)) != 1) e(0);
1084*3ba6090fSDavid van Moolenbroek 
1085*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), MSG_DONTWAIT) != sizeof(buf)) e(0);
1086*3ba6090fSDavid van Moolenbroek 	if (buf[sizeof(struct ip)] != 'A') e(0);
1087*3ba6090fSDavid van Moolenbroek 
1088*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1089*3ba6090fSDavid van Moolenbroek 
1090*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW)) < 0) e(0);
1091*3ba6090fSDavid van Moolenbroek 
1092*3ba6090fSDavid van Moolenbroek 	memset(&sin6, 0, sizeof(sin6));
1093*3ba6090fSDavid van Moolenbroek 	sin6.sin6_family = AF_INET6;
1094*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6.sin6_addr, &in6addr_loopback, sizeof(sin6.sin6_addr));
1095*3ba6090fSDavid van Moolenbroek 
1096*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, "B", 1, 0, (struct sockaddr *)&sin6,
1097*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6)) != 1) e(0);
1098*3ba6090fSDavid van Moolenbroek 
1099*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), MSG_DONTWAIT) != 1) e(0);
1100*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'B') e(0);
1101*3ba6090fSDavid van Moolenbroek 
1102*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1103*3ba6090fSDavid van Moolenbroek }
1104*3ba6090fSDavid van Moolenbroek 
1105*3ba6090fSDavid van Moolenbroek /*
1106*3ba6090fSDavid van Moolenbroek  * Test that connected raw sockets perform correct source-based filtering.
1107*3ba6090fSDavid van Moolenbroek  */
1108*3ba6090fSDavid van Moolenbroek static void
test92h(void)1109*3ba6090fSDavid van Moolenbroek test92h(void)
1110*3ba6090fSDavid van Moolenbroek {
1111*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in sinA, sinB;
1112*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in6 sin6A, sin6B;
1113*3ba6090fSDavid van Moolenbroek 	struct sockaddr sa;
1114*3ba6090fSDavid van Moolenbroek 	socklen_t len;
1115*3ba6090fSDavid van Moolenbroek 	char buf[sizeof(struct ip) + 1];
1116*3ba6090fSDavid van Moolenbroek 	int fd, fd2;
1117*3ba6090fSDavid van Moolenbroek 
1118*3ba6090fSDavid van Moolenbroek 	subtest = 8;
1119*3ba6090fSDavid van Moolenbroek 
1120*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, SOCK_RAW, TEST_PROTO)) < 0) e(0);
1121*3ba6090fSDavid van Moolenbroek 
1122*3ba6090fSDavid van Moolenbroek 	len = sizeof(sinB);
1123*3ba6090fSDavid van Moolenbroek 	if (getpeername(fd, (struct sockaddr *)&sinB, &len) != -1) e(0);
1124*3ba6090fSDavid van Moolenbroek 	if (errno != ENOTCONN) e(0);
1125*3ba6090fSDavid van Moolenbroek 
1126*3ba6090fSDavid van Moolenbroek 	memset(&sinA, 0, sizeof(sinA));
1127*3ba6090fSDavid van Moolenbroek 	sinA.sin_family = AF_INET;
1128*3ba6090fSDavid van Moolenbroek 	sinA.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1129*3ba6090fSDavid van Moolenbroek 
1130*3ba6090fSDavid van Moolenbroek 	/*
1131*3ba6090fSDavid van Moolenbroek 	 * First test that packets with the right source are accepted.
1132*3ba6090fSDavid van Moolenbroek 	 * Unfortunately, source and destination are the same in this case, so
1133*3ba6090fSDavid van Moolenbroek 	 * this test is far from perfect.
1134*3ba6090fSDavid van Moolenbroek 	 */
1135*3ba6090fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&sinA, sizeof(sinA)) != 0) e(0);
1136*3ba6090fSDavid van Moolenbroek 
1137*3ba6090fSDavid van Moolenbroek 	if (getpeername(fd, (struct sockaddr *)&sinB, &len) != 0) e(0);
1138*3ba6090fSDavid van Moolenbroek 
1139*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET, SOCK_RAW, TEST_PROTO)) < 0) e(0);
1140*3ba6090fSDavid van Moolenbroek 
1141*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, "A", 1, 0, (struct sockaddr *)&sinA,
1142*3ba6090fSDavid van Moolenbroek 	    sizeof(sinA)) != 1) e(0);
1143*3ba6090fSDavid van Moolenbroek 
1144*3ba6090fSDavid van Moolenbroek 	buf[0] = '\0';
1145*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf, sizeof(buf), 0) != sizeof(struct ip) + 1) e(0);
1146*3ba6090fSDavid van Moolenbroek 	if (buf[sizeof(struct ip)] != 'A') e(0);
1147*3ba6090fSDavid van Moolenbroek 
1148*3ba6090fSDavid van Moolenbroek 	buf[0] = '\0';
1149*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), MSG_DONTWAIT) !=
1150*3ba6090fSDavid van Moolenbroek 	    sizeof(struct ip) + 1) e(0);
1151*3ba6090fSDavid van Moolenbroek 	if (buf[sizeof(struct ip)] != 'A') e(0);
1152*3ba6090fSDavid van Moolenbroek 
1153*3ba6090fSDavid van Moolenbroek 	memset(&sa, 0, sizeof(sa));
1154*3ba6090fSDavid van Moolenbroek 	sa.sa_family = AF_UNSPEC;
1155*3ba6090fSDavid van Moolenbroek 
1156*3ba6090fSDavid van Moolenbroek 	sinA.sin_addr.s_addr = htonl(INADDR_NONE);
1157*3ba6090fSDavid van Moolenbroek 
1158*3ba6090fSDavid van Moolenbroek 	/* While here, test unconnecting the socket. */
1159*3ba6090fSDavid van Moolenbroek 	if (connect(fd, &sa, sizeof(sa)) != 0) e(0);
1160*3ba6090fSDavid van Moolenbroek 
1161*3ba6090fSDavid van Moolenbroek 	if (getpeername(fd, (struct sockaddr *)&sinB, &len) != -1) e(0);
1162*3ba6090fSDavid van Moolenbroek 	if (errno != ENOTCONN) e(0);
1163*3ba6090fSDavid van Moolenbroek 
1164*3ba6090fSDavid van Moolenbroek 	/* Then test that packets with the wrong source are ignored. */
1165*3ba6090fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&sinA, sizeof(sinA)) != 0) e(0);
1166*3ba6090fSDavid van Moolenbroek 
1167*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, "B", 1, 0, (struct sockaddr *)&sinB,
1168*3ba6090fSDavid van Moolenbroek 	    sizeof(sinB)) != 1) e(0);
1169*3ba6090fSDavid van Moolenbroek 
1170*3ba6090fSDavid van Moolenbroek 	buf[0] = '\0';
1171*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf, sizeof(buf), 0) != sizeof(struct ip) + 1) e(0);
1172*3ba6090fSDavid van Moolenbroek 	if (buf[sizeof(struct ip)] != 'B') e(0);
1173*3ba6090fSDavid van Moolenbroek 
1174*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), MSG_DONTWAIT) != -1) e(0);
1175*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
1176*3ba6090fSDavid van Moolenbroek 
1177*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
1178*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1179*3ba6090fSDavid van Moolenbroek 
1180*3ba6090fSDavid van Moolenbroek 	/* Repeat for IPv6, but now the other way around. */
1181*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, SOCK_RAW, TEST_PROTO)) < 0) e(0);
1182*3ba6090fSDavid van Moolenbroek 
1183*3ba6090fSDavid van Moolenbroek 	len = sizeof(sin6B);
1184*3ba6090fSDavid van Moolenbroek 	if (getpeername(fd, (struct sockaddr *)&sin6B, &len) != -1) e(0);
1185*3ba6090fSDavid van Moolenbroek 	if (errno != ENOTCONN) e(0);
1186*3ba6090fSDavid van Moolenbroek 
1187*3ba6090fSDavid van Moolenbroek 	memset(&sin6A, 0, sizeof(sin6A));
1188*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_family = AF_INET6;
1189*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6A.sin6_addr, &in6addr_loopback, sizeof(sin6A.sin6_addr));
1190*3ba6090fSDavid van Moolenbroek 
1191*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6B, &sin6A, sizeof(sin6B));
1192*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, "::2", &sin6B.sin6_addr) != 1) e(0);
1193*3ba6090fSDavid van Moolenbroek 
1194*3ba6090fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&sin6B, sizeof(sin6B)) != 0) e(0);
1195*3ba6090fSDavid van Moolenbroek 
1196*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET6, SOCK_RAW, TEST_PROTO)) < 0) e(0);
1197*3ba6090fSDavid van Moolenbroek 
1198*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, "C", 1, 0, (struct sockaddr *)&sin6A,
1199*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != 1) e(0);
1200*3ba6090fSDavid van Moolenbroek 
1201*3ba6090fSDavid van Moolenbroek 	buf[0] = '\0';
1202*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf, sizeof(buf), 0) != 1) e(0);
1203*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'C') e(0);
1204*3ba6090fSDavid van Moolenbroek 
1205*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), MSG_DONTWAIT) != -1) e(0);
1206*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
1207*3ba6090fSDavid van Moolenbroek 
1208*3ba6090fSDavid van Moolenbroek 	if (connect(fd, &sa, sizeof(sa)) != 0) e(0);
1209*3ba6090fSDavid van Moolenbroek 
1210*3ba6090fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&sin6A, sizeof(sin6A)) != 0) e(0);
1211*3ba6090fSDavid van Moolenbroek 
1212*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, "D", 1, 0, (struct sockaddr *)&sin6A,
1213*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != 1) e(0);
1214*3ba6090fSDavid van Moolenbroek 
1215*3ba6090fSDavid van Moolenbroek 	buf[0] = '\0';
1216*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf, sizeof(buf), 0) != 1) e(0);
1217*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'D') e(0);
1218*3ba6090fSDavid van Moolenbroek 
1219*3ba6090fSDavid van Moolenbroek 	buf[0] = '\0';
1220*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), 0) != 1) e(0);
1221*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'D') e(0);
1222*3ba6090fSDavid van Moolenbroek 
1223*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
1224*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1225*3ba6090fSDavid van Moolenbroek }
1226*3ba6090fSDavid van Moolenbroek 
1227*3ba6090fSDavid van Moolenbroek /*
1228*3ba6090fSDavid van Moolenbroek  * Test sending large and small RAW packets.  This test is an altered copy of
1229*3ba6090fSDavid van Moolenbroek  * test91e, but has been changed to IPv6 to cover a greater spectrum together.
1230*3ba6090fSDavid van Moolenbroek  */
1231*3ba6090fSDavid van Moolenbroek static void
test92i(void)1232*3ba6090fSDavid van Moolenbroek test92i(void)
1233*3ba6090fSDavid van Moolenbroek {
1234*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in6 sin6;
1235*3ba6090fSDavid van Moolenbroek 	struct msghdr msg;
1236*3ba6090fSDavid van Moolenbroek 	struct iovec iov;
1237*3ba6090fSDavid van Moolenbroek 	char *buf;
1238*3ba6090fSDavid van Moolenbroek 	unsigned int i, j;
1239*3ba6090fSDavid van Moolenbroek 	int r, fd, fd2, val;
1240*3ba6090fSDavid van Moolenbroek 
1241*3ba6090fSDavid van Moolenbroek 	subtest = 9;
1242*3ba6090fSDavid van Moolenbroek 
1243*3ba6090fSDavid van Moolenbroek 	if ((buf = malloc(65536)) == NULL) e(0);
1244*3ba6090fSDavid van Moolenbroek 
1245*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, SOCK_RAW, TEST_PROTO)) < 0) e(0);
1246*3ba6090fSDavid van Moolenbroek 
1247*3ba6090fSDavid van Moolenbroek 	memset(&sin6, 0, sizeof(sin6));
1248*3ba6090fSDavid van Moolenbroek 	sin6.sin6_family = AF_INET6;
1249*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6.sin6_addr, &in6addr_loopback, sizeof(sin6.sin6_addr));
1250*3ba6090fSDavid van Moolenbroek 
1251*3ba6090fSDavid van Moolenbroek 	if (bind(fd, (struct sockaddr *)&sin6, sizeof(sin6)) != 0) e(0);
1252*3ba6090fSDavid van Moolenbroek 
1253*3ba6090fSDavid van Moolenbroek 	val = 65536;
1254*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) != 0)
1255*3ba6090fSDavid van Moolenbroek 		e(0);
1256*3ba6090fSDavid van Moolenbroek 
1257*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET6, SOCK_RAW, TEST_PROTO)) < 0) e(0);
1258*3ba6090fSDavid van Moolenbroek 
1259*3ba6090fSDavid van Moolenbroek 	/*
1260*3ba6090fSDavid van Moolenbroek 	 * A maximum send buffer size of a full packet size's worth may always
1261*3ba6090fSDavid van Moolenbroek 	 * be set, although this is not necessarily the actual maximum.
1262*3ba6090fSDavid van Moolenbroek 	 */
1263*3ba6090fSDavid van Moolenbroek 	val = 65535;
1264*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) != 0)
1265*3ba6090fSDavid van Moolenbroek 		e(0);
1266*3ba6090fSDavid van Moolenbroek 
1267*3ba6090fSDavid van Moolenbroek 	/* Find the largest possible packet size that can actually be sent. */
1268*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < val; i += sizeof(int)) {
1269*3ba6090fSDavid van Moolenbroek 		j = i ^ 0xdeadbeef;
1270*3ba6090fSDavid van Moolenbroek 		memcpy(&buf[i], &j, sizeof(j));
1271*3ba6090fSDavid van Moolenbroek 	}
1272*3ba6090fSDavid van Moolenbroek 
1273*3ba6090fSDavid van Moolenbroek 	for (val = 65536; val > 0; val--) {
1274*3ba6090fSDavid van Moolenbroek 		if ((r = sendto(fd2, buf, val, 0, (struct sockaddr *)&sin6,
1275*3ba6090fSDavid van Moolenbroek 		    sizeof(sin6))) == val)
1276*3ba6090fSDavid van Moolenbroek 			break;
1277*3ba6090fSDavid van Moolenbroek 		if (r != -1) e(0);
1278*3ba6090fSDavid van Moolenbroek 		if (errno != EMSGSIZE) e(0);
1279*3ba6090fSDavid van Moolenbroek 	}
1280*3ba6090fSDavid van Moolenbroek 
1281*3ba6090fSDavid van Moolenbroek 	if (val != 65535 - sizeof(struct ip6_hdr)) e(0);
1282*3ba6090fSDavid van Moolenbroek 
1283*3ba6090fSDavid van Moolenbroek 	memset(buf, 0, val);
1284*3ba6090fSDavid van Moolenbroek 	buf[val] = 'X';
1285*3ba6090fSDavid van Moolenbroek 
1286*3ba6090fSDavid van Moolenbroek 	memset(&iov, 0, sizeof(iov));
1287*3ba6090fSDavid van Moolenbroek 	iov.iov_base = buf;
1288*3ba6090fSDavid van Moolenbroek 	iov.iov_len = val + 1;
1289*3ba6090fSDavid van Moolenbroek 	memset(&msg, 0, sizeof(msg));
1290*3ba6090fSDavid van Moolenbroek 	msg.msg_iov = &iov;
1291*3ba6090fSDavid van Moolenbroek 	msg.msg_iovlen = 1;
1292*3ba6090fSDavid van Moolenbroek 	if (recvmsg(fd, &msg, 0) != val) e(0);
1293*3ba6090fSDavid van Moolenbroek 	if (msg.msg_flags != 0) e(0);
1294*3ba6090fSDavid van Moolenbroek 
1295*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < val; i += sizeof(int)) {
1296*3ba6090fSDavid van Moolenbroek 		j = i ^ 0xdeadbeef;
1297*3ba6090fSDavid van Moolenbroek 		if (memcmp(&buf[i], &j, MIN(sizeof(j), val - i))) e(0);
1298*3ba6090fSDavid van Moolenbroek 	}
1299*3ba6090fSDavid van Moolenbroek 	if (buf[val] != 'X') e(0);
1300*3ba6090fSDavid van Moolenbroek 
1301*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, buf, val, 0, (struct sockaddr *)&sin6, sizeof(sin6)) !=
1302*3ba6090fSDavid van Moolenbroek 	    val) e(0);
1303*3ba6090fSDavid van Moolenbroek 
1304*3ba6090fSDavid van Moolenbroek 	/*
1305*3ba6090fSDavid van Moolenbroek 	 * Make sure that there are no off-by-one errors in the receive code,
1306*3ba6090fSDavid van Moolenbroek 	 * and that MSG_TRUNC is set (only) when not the whole packet was
1307*3ba6090fSDavid van Moolenbroek 	 * received.
1308*3ba6090fSDavid van Moolenbroek 	 */
1309*3ba6090fSDavid van Moolenbroek 	memset(&iov, 0, sizeof(iov));
1310*3ba6090fSDavid van Moolenbroek 	iov.iov_base = buf;
1311*3ba6090fSDavid van Moolenbroek 	iov.iov_len = val;
1312*3ba6090fSDavid van Moolenbroek 	memset(&msg, 0, sizeof(msg));
1313*3ba6090fSDavid van Moolenbroek 	msg.msg_iov = &iov;
1314*3ba6090fSDavid van Moolenbroek 	msg.msg_iovlen = 1;
1315*3ba6090fSDavid van Moolenbroek 	if (recvmsg(fd, &msg, 0) != val) e(0);
1316*3ba6090fSDavid van Moolenbroek 	if (msg.msg_flags != 0) e(0);
1317*3ba6090fSDavid van Moolenbroek 
1318*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, buf, val, 0, (struct sockaddr *)&sin6, sizeof(sin6)) !=
1319*3ba6090fSDavid van Moolenbroek 	    val) e(0);
1320*3ba6090fSDavid van Moolenbroek 
1321*3ba6090fSDavid van Moolenbroek 	buf[val - 1] = 'Y';
1322*3ba6090fSDavid van Moolenbroek 
1323*3ba6090fSDavid van Moolenbroek 	memset(&iov, 0, sizeof(iov));
1324*3ba6090fSDavid van Moolenbroek 	iov.iov_base = buf;
1325*3ba6090fSDavid van Moolenbroek 	iov.iov_len = val - 1;
1326*3ba6090fSDavid van Moolenbroek 	memset(&msg, 0, sizeof(msg));
1327*3ba6090fSDavid van Moolenbroek 	msg.msg_iov = &iov;
1328*3ba6090fSDavid van Moolenbroek 	msg.msg_iovlen = 1;
1329*3ba6090fSDavid van Moolenbroek 	if (recvmsg(fd, &msg, 0) != val - 1) e(0);
1330*3ba6090fSDavid van Moolenbroek 	if (msg.msg_flags != MSG_TRUNC) e(0);
1331*3ba6090fSDavid van Moolenbroek 
1332*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < val - 1; i += sizeof(int)) {
1333*3ba6090fSDavid van Moolenbroek 		j = i ^ 0xdeadbeef;
1334*3ba6090fSDavid van Moolenbroek 		if (memcmp(&buf[i], &j, MIN(sizeof(j), val - 1 - i))) e(0);
1335*3ba6090fSDavid van Moolenbroek 	}
1336*3ba6090fSDavid van Moolenbroek 	if (buf[val - 1] != 'Y') e(0);
1337*3ba6090fSDavid van Moolenbroek 
1338*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, buf, val, 0, (struct sockaddr *)&sin6, sizeof(sin6)) !=
1339*3ba6090fSDavid van Moolenbroek 	    val) e(0);
1340*3ba6090fSDavid van Moolenbroek 
1341*3ba6090fSDavid van Moolenbroek 	buf[0] = 'Z';
1342*3ba6090fSDavid van Moolenbroek 
1343*3ba6090fSDavid van Moolenbroek 	memset(&iov, 0, sizeof(iov));
1344*3ba6090fSDavid van Moolenbroek 	iov.iov_base = buf;
1345*3ba6090fSDavid van Moolenbroek 	iov.iov_len = 0;
1346*3ba6090fSDavid van Moolenbroek 	memset(&msg, 0, sizeof(msg));
1347*3ba6090fSDavid van Moolenbroek 	msg.msg_iov = &iov;
1348*3ba6090fSDavid van Moolenbroek 	msg.msg_iovlen = 1;
1349*3ba6090fSDavid van Moolenbroek 	if (recvmsg(fd, &msg, 0) != 0) e(0);
1350*3ba6090fSDavid van Moolenbroek 	if (msg.msg_flags != MSG_TRUNC) e(0);
1351*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'Z') e(0);
1352*3ba6090fSDavid van Moolenbroek 
1353*3ba6090fSDavid van Moolenbroek 	/* Make sure that zero-sized packets can be sent and received. */
1354*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, buf, 0, 0, (struct sockaddr *)&sin6,
1355*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6)) != 0) e(0);
1356*3ba6090fSDavid van Moolenbroek 
1357*3ba6090fSDavid van Moolenbroek 	/*
1358*3ba6090fSDavid van Moolenbroek 	 * Note how we currently assume that packets sent over localhost will
1359*3ba6090fSDavid van Moolenbroek 	 * arrive immediately, so that we can use MSG_DONTWAIT to avoid that
1360*3ba6090fSDavid van Moolenbroek 	 * the test freezes.
1361*3ba6090fSDavid van Moolenbroek 	 */
1362*3ba6090fSDavid van Moolenbroek 	memset(&msg, 0, sizeof(msg));
1363*3ba6090fSDavid van Moolenbroek 	msg.msg_iov = &iov;
1364*3ba6090fSDavid van Moolenbroek 	msg.msg_iovlen = 1;
1365*3ba6090fSDavid van Moolenbroek 	if (recvmsg(fd, &msg, MSG_DONTWAIT) != 0) e(0);
1366*3ba6090fSDavid van Moolenbroek 	if (msg.msg_flags != 0) e(0);
1367*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'Z') e(0);
1368*3ba6090fSDavid van Moolenbroek 
1369*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, val, MSG_DONTWAIT) != -1) e(0);
1370*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
1371*3ba6090fSDavid van Moolenbroek 
1372*3ba6090fSDavid van Moolenbroek 	/*
1373*3ba6090fSDavid van Moolenbroek 	 * When sending lots of small packets, ensure that fewer packets arrive
1374*3ba6090fSDavid van Moolenbroek 	 * than we sent.  This sounds weird, but we cannot actually check the
1375*3ba6090fSDavid van Moolenbroek 	 * internal TCP/IP buffer granularity and yet we want to make sure that
1376*3ba6090fSDavid van Moolenbroek 	 * the receive queue is measured in terms of buffers rather than packet
1377*3ba6090fSDavid van Moolenbroek 	 * sizes.  In addition, we check that older packets are favored,
1378*3ba6090fSDavid van Moolenbroek 	 * instead discarding new ones when the receive buffer is full.
1379*3ba6090fSDavid van Moolenbroek 	 */
1380*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < 65536 / sizeof(j); i++) {
1381*3ba6090fSDavid van Moolenbroek 		j = i;
1382*3ba6090fSDavid van Moolenbroek 		if (sendto(fd2, &j, sizeof(j), 0, (struct sockaddr *)&sin6,
1383*3ba6090fSDavid van Moolenbroek 		    sizeof(sin6)) != sizeof(j)) e(0);
1384*3ba6090fSDavid van Moolenbroek 	}
1385*3ba6090fSDavid van Moolenbroek 
1386*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < 1025; i++) {
1387*3ba6090fSDavid van Moolenbroek 		r = recv(fd, &j, sizeof(j), MSG_DONTWAIT);
1388*3ba6090fSDavid van Moolenbroek 		if (r == -1) {
1389*3ba6090fSDavid van Moolenbroek 			if (errno != EWOULDBLOCK) e(0);
1390*3ba6090fSDavid van Moolenbroek 			break;
1391*3ba6090fSDavid van Moolenbroek 		}
1392*3ba6090fSDavid van Moolenbroek 		if (r != sizeof(j)) e(0);
1393*3ba6090fSDavid van Moolenbroek 		if (i != j) e(0);
1394*3ba6090fSDavid van Moolenbroek 	}
1395*3ba6090fSDavid van Moolenbroek 	if (i == 1025) e(0);
1396*3ba6090fSDavid van Moolenbroek 
1397*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
1398*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1399*3ba6090fSDavid van Moolenbroek 
1400*3ba6090fSDavid van Moolenbroek 	free(buf);
1401*3ba6090fSDavid van Moolenbroek }
1402*3ba6090fSDavid van Moolenbroek 
1403*3ba6090fSDavid van Moolenbroek /*
1404*3ba6090fSDavid van Moolenbroek  * Test sending and receiving with bad pointers.
1405*3ba6090fSDavid van Moolenbroek  */
1406*3ba6090fSDavid van Moolenbroek static void
test92j(void)1407*3ba6090fSDavid van Moolenbroek test92j(void)
1408*3ba6090fSDavid van Moolenbroek {
1409*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in sin;
1410*3ba6090fSDavid van Moolenbroek 	char *ptr;
1411*3ba6090fSDavid van Moolenbroek 	int i, fd;
1412*3ba6090fSDavid van Moolenbroek 
1413*3ba6090fSDavid van Moolenbroek 	subtest = 10;
1414*3ba6090fSDavid van Moolenbroek 
1415*3ba6090fSDavid van Moolenbroek 	if ((ptr = mmap(NULL, PAGE_SIZE * 2, PROT_READ | PROT_WRITE,
1416*3ba6090fSDavid van Moolenbroek 	    MAP_ANON | MAP_PRIVATE, -1, 0)) == MAP_FAILED) e(0);
1417*3ba6090fSDavid van Moolenbroek 
1418*3ba6090fSDavid van Moolenbroek 	if (munmap(&ptr[PAGE_SIZE], PAGE_SIZE) != 0) e(0);
1419*3ba6090fSDavid van Moolenbroek 
1420*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, SOCK_RAW, TEST_PROTO)) < 0) e(0);
1421*3ba6090fSDavid van Moolenbroek 
1422*3ba6090fSDavid van Moolenbroek 	memset(&sin, 0, sizeof(sin));
1423*3ba6090fSDavid van Moolenbroek 	sin.sin_family = AF_INET;
1424*3ba6090fSDavid van Moolenbroek 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1425*3ba6090fSDavid van Moolenbroek 
1426*3ba6090fSDavid van Moolenbroek 	if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) != 0) e(0);
1427*3ba6090fSDavid van Moolenbroek 
1428*3ba6090fSDavid van Moolenbroek 	memset(ptr, 'A', PAGE_SIZE);
1429*3ba6090fSDavid van Moolenbroek 
1430*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, &ptr[PAGE_SIZE / 2], PAGE_SIZE, 0,
1431*3ba6090fSDavid van Moolenbroek 	    (struct sockaddr *)&sin, sizeof(sin)) != -1) e(0);
1432*3ba6090fSDavid van Moolenbroek 	if (errno != EFAULT) e(0);
1433*3ba6090fSDavid van Moolenbroek 
1434*3ba6090fSDavid van Moolenbroek 	memset(ptr, 'B', PAGE_SIZE);
1435*3ba6090fSDavid van Moolenbroek 
1436*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, ptr, PAGE_SIZE - sizeof(struct ip), 0,
1437*3ba6090fSDavid van Moolenbroek 	    (struct sockaddr *)&sin, sizeof(sin)) !=
1438*3ba6090fSDavid van Moolenbroek 	    PAGE_SIZE - sizeof(struct ip)) e(0);
1439*3ba6090fSDavid van Moolenbroek 
1440*3ba6090fSDavid van Moolenbroek 	memset(ptr, 0, PAGE_SIZE);
1441*3ba6090fSDavid van Moolenbroek 
1442*3ba6090fSDavid van Moolenbroek 	if (recvfrom(fd, &ptr[PAGE_SIZE / 2], PAGE_SIZE, 0, NULL, 0) != -1)
1443*3ba6090fSDavid van Moolenbroek 		e(0);
1444*3ba6090fSDavid van Moolenbroek 	if (errno != EFAULT) e(0);
1445*3ba6090fSDavid van Moolenbroek 
1446*3ba6090fSDavid van Moolenbroek 	if (recvfrom(fd, ptr, PAGE_SIZE * 2, 0, NULL, 0) != PAGE_SIZE) e(0);
1447*3ba6090fSDavid van Moolenbroek 	for (i = sizeof(struct ip); i < PAGE_SIZE; i++)
1448*3ba6090fSDavid van Moolenbroek 		if (ptr[i] != 'B') e(0);
1449*3ba6090fSDavid van Moolenbroek 
1450*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1451*3ba6090fSDavid van Moolenbroek 
1452*3ba6090fSDavid van Moolenbroek 	if (munmap(ptr, PAGE_SIZE) != 0) e(0);
1453*3ba6090fSDavid van Moolenbroek }
1454*3ba6090fSDavid van Moolenbroek 
1455*3ba6090fSDavid van Moolenbroek /*
1456*3ba6090fSDavid van Moolenbroek  * Test basic sysctl(2) socket enumeration support.
1457*3ba6090fSDavid van Moolenbroek  */
1458*3ba6090fSDavid van Moolenbroek static void
test92k(void)1459*3ba6090fSDavid van Moolenbroek test92k(void)
1460*3ba6090fSDavid van Moolenbroek {
1461*3ba6090fSDavid van Moolenbroek 	struct kinfo_pcb ki;
1462*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in lsin, rsin;
1463*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in6 lsin6, rsin6;
1464*3ba6090fSDavid van Moolenbroek 	int fd, fd2, val;
1465*3ba6090fSDavid van Moolenbroek 
1466*3ba6090fSDavid van Moolenbroek 	subtest = 11;
1467*3ba6090fSDavid van Moolenbroek 
1468*3ba6090fSDavid van Moolenbroek 	if (socklib_find_pcb("net.inet.raw.pcblist", TEST_PROTO, 0, 0,
1469*3ba6090fSDavid van Moolenbroek 	    &ki) != 0) e(0);
1470*3ba6090fSDavid van Moolenbroek 
1471*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, SOCK_RAW, TEST_PROTO)) < 0) e(0);
1472*3ba6090fSDavid van Moolenbroek 
1473*3ba6090fSDavid van Moolenbroek 	memset(&lsin, 0, sizeof(lsin));
1474*3ba6090fSDavid van Moolenbroek 	lsin.sin_len = sizeof(lsin);
1475*3ba6090fSDavid van Moolenbroek 	lsin.sin_family = AF_INET;
1476*3ba6090fSDavid van Moolenbroek 
1477*3ba6090fSDavid van Moolenbroek 	memset(&rsin, 0, sizeof(rsin));
1478*3ba6090fSDavid van Moolenbroek 	rsin.sin_len = sizeof(rsin);
1479*3ba6090fSDavid van Moolenbroek 	rsin.sin_family = AF_INET;
1480*3ba6090fSDavid van Moolenbroek 
1481*3ba6090fSDavid van Moolenbroek 	if (socklib_find_pcb("net.inet.raw.pcblist", TEST_PROTO, 0, 0,
1482*3ba6090fSDavid van Moolenbroek 	    &ki) != 1) e(0);
1483*3ba6090fSDavid van Moolenbroek 	if (ki.ki_type != SOCK_RAW) e(0);
1484*3ba6090fSDavid van Moolenbroek 	if (ki.ki_tstate != 0) e(0);
1485*3ba6090fSDavid van Moolenbroek 	if (memcmp(&ki.ki_src, &lsin, sizeof(lsin)) != 0) e(0);
1486*3ba6090fSDavid van Moolenbroek 	if (memcmp(&ki.ki_dst, &rsin, sizeof(rsin)) != 0) e(0);
1487*3ba6090fSDavid van Moolenbroek 	if (ki.ki_sndq != 0) e(0);
1488*3ba6090fSDavid van Moolenbroek 	if (ki.ki_rcvq != 0) e(0);
1489*3ba6090fSDavid van Moolenbroek 
1490*3ba6090fSDavid van Moolenbroek 	if (socklib_find_pcb("net.inet6.raw6.pcblist", TEST_PROTO, 0, 0,
1491*3ba6090fSDavid van Moolenbroek 	    &ki) != 0) e(0);
1492*3ba6090fSDavid van Moolenbroek 
1493*3ba6090fSDavid van Moolenbroek 	lsin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1494*3ba6090fSDavid van Moolenbroek 
1495*3ba6090fSDavid van Moolenbroek 	if (bind(fd, (struct sockaddr *)&lsin, sizeof(lsin)) != 0) e(0);
1496*3ba6090fSDavid van Moolenbroek 
1497*3ba6090fSDavid van Moolenbroek 	if (socklib_find_pcb("net.inet.raw.pcblist", TEST_PROTO, 0, 0,
1498*3ba6090fSDavid van Moolenbroek 	    &ki) != 1) e(0);
1499*3ba6090fSDavid van Moolenbroek 	if (ki.ki_type != SOCK_RAW) e(0);
1500*3ba6090fSDavid van Moolenbroek 	if (ki.ki_tstate != 0) e(0);
1501*3ba6090fSDavid van Moolenbroek 	if (memcmp(&ki.ki_src, &lsin, sizeof(lsin)) != 0) e(0);
1502*3ba6090fSDavid van Moolenbroek 	if (memcmp(&ki.ki_dst, &rsin, sizeof(rsin)) != 0) e(0);
1503*3ba6090fSDavid van Moolenbroek 	if (ki.ki_sndq != 0) e(0);
1504*3ba6090fSDavid van Moolenbroek 	if (ki.ki_rcvq != 0) e(0);
1505*3ba6090fSDavid van Moolenbroek 	if (ki.ki_pflags & INP_HDRINCL) e(0);
1506*3ba6090fSDavid van Moolenbroek 
1507*3ba6090fSDavid van Moolenbroek 	rsin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1508*3ba6090fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&rsin, sizeof(rsin)) != 0) e(0);
1509*3ba6090fSDavid van Moolenbroek 
1510*3ba6090fSDavid van Moolenbroek 	if (socklib_find_pcb("net.inet.raw.pcblist", TEST_PROTO, 0, 0,
1511*3ba6090fSDavid van Moolenbroek 	    &ki) != 1) e(0);
1512*3ba6090fSDavid van Moolenbroek 	if (ki.ki_type != SOCK_RAW) e(0);
1513*3ba6090fSDavid van Moolenbroek 	if (ki.ki_tstate != 0) e(0);
1514*3ba6090fSDavid van Moolenbroek 	if (memcmp(&ki.ki_src, &lsin, sizeof(lsin)) != 0) e(0);
1515*3ba6090fSDavid van Moolenbroek 	if (memcmp(&ki.ki_dst, &rsin, sizeof(rsin)) != 0) e(0);
1516*3ba6090fSDavid van Moolenbroek 	if (ki.ki_sndq != 0) e(0);
1517*3ba6090fSDavid van Moolenbroek 	if (ki.ki_rcvq != 0) e(0);
1518*3ba6090fSDavid van Moolenbroek 
1519*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET, SOCK_RAW, TEST_PROTO)) < 0) e(0);
1520*3ba6090fSDavid van Moolenbroek 
1521*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, "ABC", 3, 0, (struct sockaddr *)&lsin,
1522*3ba6090fSDavid van Moolenbroek 	    sizeof(lsin)) != 3) e(0);
1523*3ba6090fSDavid van Moolenbroek 
1524*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
1525*3ba6090fSDavid van Moolenbroek 
1526*3ba6090fSDavid van Moolenbroek 	val = 1;
1527*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &val, sizeof(val)) != 0)
1528*3ba6090fSDavid van Moolenbroek 		e(0);
1529*3ba6090fSDavid van Moolenbroek 
1530*3ba6090fSDavid van Moolenbroek 	if (socklib_find_pcb("net.inet.raw.pcblist", TEST_PROTO, 0, 0,
1531*3ba6090fSDavid van Moolenbroek 	    &ki) != 1) e(0);
1532*3ba6090fSDavid van Moolenbroek 	if (ki.ki_type != SOCK_RAW) e(0);
1533*3ba6090fSDavid van Moolenbroek 	if (ki.ki_tstate != 0) e(0);
1534*3ba6090fSDavid van Moolenbroek 	if (memcmp(&ki.ki_src, &lsin, sizeof(lsin)) != 0) e(0);
1535*3ba6090fSDavid van Moolenbroek 	if (memcmp(&ki.ki_dst, &rsin, sizeof(rsin)) != 0) e(0);
1536*3ba6090fSDavid van Moolenbroek 	if (ki.ki_sndq != 0) e(0);
1537*3ba6090fSDavid van Moolenbroek 	if (ki.ki_rcvq < 3) e(0);	/* size is rounded up */
1538*3ba6090fSDavid van Moolenbroek 	if (!(ki.ki_pflags & INP_HDRINCL)) e(0);
1539*3ba6090fSDavid van Moolenbroek 
1540*3ba6090fSDavid van Moolenbroek 	if (socklib_find_pcb("net.inet6.raw6.pcblist", TEST_PROTO, 0, 0,
1541*3ba6090fSDavid van Moolenbroek 	    &ki) != 0) e(0);
1542*3ba6090fSDavid van Moolenbroek 
1543*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1544*3ba6090fSDavid van Moolenbroek 
1545*3ba6090fSDavid van Moolenbroek 	/* Test IPv6 sockets as well. */
1546*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, SOCK_RAW, TEST_PROTO)) < 0) e(0);
1547*3ba6090fSDavid van Moolenbroek 
1548*3ba6090fSDavid van Moolenbroek 	memset(&lsin6, 0, sizeof(lsin6));
1549*3ba6090fSDavid van Moolenbroek 	lsin6.sin6_len = sizeof(lsin6);
1550*3ba6090fSDavid van Moolenbroek 	lsin6.sin6_family = AF_INET6;
1551*3ba6090fSDavid van Moolenbroek 
1552*3ba6090fSDavid van Moolenbroek 	memset(&rsin6, 0, sizeof(rsin6));
1553*3ba6090fSDavid van Moolenbroek 	rsin6.sin6_len = sizeof(rsin6);
1554*3ba6090fSDavid van Moolenbroek 	rsin6.sin6_family = AF_INET6;
1555*3ba6090fSDavid van Moolenbroek 
1556*3ba6090fSDavid van Moolenbroek 	if (socklib_find_pcb("net.inet6.raw6.pcblist", TEST_PROTO, 0, 0,
1557*3ba6090fSDavid van Moolenbroek 	    &ki) != 1) e(0);
1558*3ba6090fSDavid van Moolenbroek 	if (ki.ki_type != SOCK_RAW) e(0);
1559*3ba6090fSDavid van Moolenbroek 	if (ki.ki_tstate != 0) e(0);
1560*3ba6090fSDavid van Moolenbroek 	if (memcmp(&ki.ki_src, &lsin6, sizeof(lsin6)) != 0) e(0);
1561*3ba6090fSDavid van Moolenbroek 	if (memcmp(&ki.ki_dst, &rsin6, sizeof(rsin6)) != 0) e(0);
1562*3ba6090fSDavid van Moolenbroek 	if (ki.ki_sndq != 0) e(0);
1563*3ba6090fSDavid van Moolenbroek 	if (ki.ki_rcvq != 0) e(0);
1564*3ba6090fSDavid van Moolenbroek 
1565*3ba6090fSDavid van Moolenbroek 	memcpy(&lsin6.sin6_addr, &in6addr_loopback, sizeof(lsin6.sin6_addr));
1566*3ba6090fSDavid van Moolenbroek 	if (bind(fd, (struct sockaddr *)&lsin6, sizeof(lsin6)) != 0) e(0);
1567*3ba6090fSDavid van Moolenbroek 
1568*3ba6090fSDavid van Moolenbroek 	if (socklib_find_pcb("net.inet6.raw6.pcblist", TEST_PROTO, 0, 0,
1569*3ba6090fSDavid van Moolenbroek 	    &ki) != 1) e(0);
1570*3ba6090fSDavid van Moolenbroek 	if (ki.ki_type != SOCK_RAW) e(0);
1571*3ba6090fSDavid van Moolenbroek 	if (ki.ki_tstate != 0) e(0);
1572*3ba6090fSDavid van Moolenbroek 	if (memcmp(&ki.ki_src, &lsin6, sizeof(lsin6)) != 0) e(0);
1573*3ba6090fSDavid van Moolenbroek 	if (memcmp(&ki.ki_dst, &rsin6, sizeof(rsin6)) != 0) e(0);
1574*3ba6090fSDavid van Moolenbroek 	if (ki.ki_sndq != 0) e(0);
1575*3ba6090fSDavid van Moolenbroek 	if (ki.ki_rcvq != 0) e(0);
1576*3ba6090fSDavid van Moolenbroek 	if (!(ki.ki_pflags & IN6P_IPV6_V6ONLY)) e(0);
1577*3ba6090fSDavid van Moolenbroek 
1578*3ba6090fSDavid van Moolenbroek 	memcpy(&rsin6.sin6_addr, &in6addr_loopback, sizeof(rsin6.sin6_addr));
1579*3ba6090fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&rsin6, sizeof(rsin6)) != 0)
1580*3ba6090fSDavid van Moolenbroek 		e(0);
1581*3ba6090fSDavid van Moolenbroek 
1582*3ba6090fSDavid van Moolenbroek 	if (socklib_find_pcb("net.inet6.raw6.pcblist", TEST_PROTO, 0, 0,
1583*3ba6090fSDavid van Moolenbroek 	    &ki) != 1) e(0);
1584*3ba6090fSDavid van Moolenbroek 	if (ki.ki_type != SOCK_RAW) e(0);
1585*3ba6090fSDavid van Moolenbroek 	if (ki.ki_tstate != 0) e(0);
1586*3ba6090fSDavid van Moolenbroek 	if (memcmp(&ki.ki_src, &lsin6, sizeof(lsin6)) != 0) e(0);
1587*3ba6090fSDavid van Moolenbroek 	if (memcmp(&ki.ki_dst, &rsin6, sizeof(rsin6)) != 0) e(0);
1588*3ba6090fSDavid van Moolenbroek 	if (ki.ki_sndq != 0) e(0);
1589*3ba6090fSDavid van Moolenbroek 	if (ki.ki_rcvq != 0) e(0);
1590*3ba6090fSDavid van Moolenbroek 	if (!(ki.ki_pflags & IN6P_IPV6_V6ONLY)) e(0);
1591*3ba6090fSDavid van Moolenbroek 
1592*3ba6090fSDavid van Moolenbroek 	if (socklib_find_pcb("net.inet.raw.pcblist", TEST_PROTO, 0, 0,
1593*3ba6090fSDavid van Moolenbroek 	    &ki) != 0) e(0);
1594*3ba6090fSDavid van Moolenbroek 
1595*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1596*3ba6090fSDavid van Moolenbroek 
1597*3ba6090fSDavid van Moolenbroek 	if (socklib_find_pcb("net.inet6.raw6.pcblist", TEST_PROTO, 0, 0,
1598*3ba6090fSDavid van Moolenbroek 	    &ki) != 0) e(0);
1599*3ba6090fSDavid van Moolenbroek }
1600*3ba6090fSDavid van Moolenbroek 
1601*3ba6090fSDavid van Moolenbroek /*
1602*3ba6090fSDavid van Moolenbroek  * Test local and remote IPv6 address handling.  In particular, test scope IDs
1603*3ba6090fSDavid van Moolenbroek  * and IPv4-mapped IPv6 addresses.
1604*3ba6090fSDavid van Moolenbroek  */
1605*3ba6090fSDavid van Moolenbroek static void
test92l(void)1606*3ba6090fSDavid van Moolenbroek test92l(void)
1607*3ba6090fSDavid van Moolenbroek {
1608*3ba6090fSDavid van Moolenbroek 
1609*3ba6090fSDavid van Moolenbroek 	subtest = 12;
1610*3ba6090fSDavid van Moolenbroek 
1611*3ba6090fSDavid van Moolenbroek 	socklib_test_addrs(SOCK_RAW, TEST_PROTO);
1612*3ba6090fSDavid van Moolenbroek }
1613*3ba6090fSDavid van Moolenbroek 
1614*3ba6090fSDavid van Moolenbroek /*
1615*3ba6090fSDavid van Moolenbroek  * Test setting and retrieving basic multicast transmission options.
1616*3ba6090fSDavid van Moolenbroek  */
1617*3ba6090fSDavid van Moolenbroek static void
test92m(void)1618*3ba6090fSDavid van Moolenbroek test92m(void)
1619*3ba6090fSDavid van Moolenbroek {
1620*3ba6090fSDavid van Moolenbroek 
1621*3ba6090fSDavid van Moolenbroek 	subtest = 13;
1622*3ba6090fSDavid van Moolenbroek 
1623*3ba6090fSDavid van Moolenbroek 	socklib_multicast_tx_options(SOCK_RAW);
1624*3ba6090fSDavid van Moolenbroek }
1625*3ba6090fSDavid van Moolenbroek 
1626*3ba6090fSDavid van Moolenbroek /*
1627*3ba6090fSDavid van Moolenbroek  * Test multicast support.
1628*3ba6090fSDavid van Moolenbroek  */
1629*3ba6090fSDavid van Moolenbroek static void
test92n(void)1630*3ba6090fSDavid van Moolenbroek test92n(void)
1631*3ba6090fSDavid van Moolenbroek {
1632*3ba6090fSDavid van Moolenbroek 
1633*3ba6090fSDavid van Moolenbroek 	subtest = 14;
1634*3ba6090fSDavid van Moolenbroek 
1635*3ba6090fSDavid van Moolenbroek 	socklib_test_multicast(SOCK_RAW, TEST_PROTO);
1636*3ba6090fSDavid van Moolenbroek }
1637*3ba6090fSDavid van Moolenbroek 
1638*3ba6090fSDavid van Moolenbroek /*
1639*3ba6090fSDavid van Moolenbroek  * Test small and large ICMP echo ("ping") packets.  This test aims to confirm
1640*3ba6090fSDavid van Moolenbroek  * expected behavior resulting from the LWIP service's memory pool policies:
1641*3ba6090fSDavid van Moolenbroek  * lwIP should reply to ICMP echo requests that fit in a single 512-byte buffer
1642*3ba6090fSDavid van Moolenbroek  * (including space for ethernet headers, even on loopback interfaces), but not
1643*3ba6090fSDavid van Moolenbroek  * to requests exceeding a single buffer.
1644*3ba6090fSDavid van Moolenbroek  */
1645*3ba6090fSDavid van Moolenbroek static void
test92o(void)1646*3ba6090fSDavid van Moolenbroek test92o(void)
1647*3ba6090fSDavid van Moolenbroek {
1648*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in6 sin6;
1649*3ba6090fSDavid van Moolenbroek 	struct icmp6_hdr packet;
1650*3ba6090fSDavid van Moolenbroek 	char buf[512];
1651*3ba6090fSDavid van Moolenbroek 	int fd;
1652*3ba6090fSDavid van Moolenbroek 
1653*3ba6090fSDavid van Moolenbroek 	subtest = 15;
1654*3ba6090fSDavid van Moolenbroek 
1655*3ba6090fSDavid van Moolenbroek 	/* IPv6 only for now, for simplicity reasons. */
1656*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) e(0);
1657*3ba6090fSDavid van Moolenbroek 
1658*3ba6090fSDavid van Moolenbroek 	memset(&sin6, 0, sizeof(sin6));
1659*3ba6090fSDavid van Moolenbroek 	sin6.sin6_family = AF_INET6;
1660*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6.sin6_addr, &in6addr_loopback, sizeof(sin6.sin6_addr));
1661*3ba6090fSDavid van Moolenbroek 
1662*3ba6090fSDavid van Moolenbroek 	memset(&packet, 0, sizeof(packet));
1663*3ba6090fSDavid van Moolenbroek 	packet.icmp6_type = ICMP6_ECHO_REQUEST;
1664*3ba6090fSDavid van Moolenbroek 	packet.icmp6_code = 0;
1665*3ba6090fSDavid van Moolenbroek 	packet.icmp6_id = getpid();
1666*3ba6090fSDavid van Moolenbroek 	packet.icmp6_seq = 1;
1667*3ba6090fSDavid van Moolenbroek 
1668*3ba6090fSDavid van Moolenbroek 	memset(buf, 'A', sizeof(buf));
1669*3ba6090fSDavid van Moolenbroek 	memcpy(buf, &packet, sizeof(packet));
1670*3ba6090fSDavid van Moolenbroek 
1671*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sin6,
1672*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6)) != sizeof(buf)) e(0);
1673*3ba6090fSDavid van Moolenbroek 
1674*3ba6090fSDavid van Moolenbroek 	packet.icmp6_seq = 2;
1675*3ba6090fSDavid van Moolenbroek 
1676*3ba6090fSDavid van Moolenbroek 	memset(buf, 'B', sizeof(buf));
1677*3ba6090fSDavid van Moolenbroek 	memcpy(buf, &packet, sizeof(packet));
1678*3ba6090fSDavid van Moolenbroek 
1679*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, buf, sizeof(buf) - 100, 0, (struct sockaddr *)&sin6,
1680*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6)) != sizeof(buf) - 100) e(0);
1681*3ba6090fSDavid van Moolenbroek 
1682*3ba6090fSDavid van Moolenbroek 	do {
1683*3ba6090fSDavid van Moolenbroek 		memset(buf, '\0', sizeof(buf));
1684*3ba6090fSDavid van Moolenbroek 
1685*3ba6090fSDavid van Moolenbroek 		if (recv(fd, buf, sizeof(buf), 0) <= 0) e(0);
1686*3ba6090fSDavid van Moolenbroek 
1687*3ba6090fSDavid van Moolenbroek 		memcpy(&packet, buf, sizeof(packet));
1688*3ba6090fSDavid van Moolenbroek 	} while (packet.icmp6_type == ICMP6_ECHO_REQUEST);
1689*3ba6090fSDavid van Moolenbroek 
1690*3ba6090fSDavid van Moolenbroek 	if (packet.icmp6_type != ICMP6_ECHO_REPLY) e(0);
1691*3ba6090fSDavid van Moolenbroek 	if (packet.icmp6_code != 0) e(0);
1692*3ba6090fSDavid van Moolenbroek 	if (packet.icmp6_id != getpid()) e(0);
1693*3ba6090fSDavid van Moolenbroek 	if (packet.icmp6_seq != 2) e(0);
1694*3ba6090fSDavid van Moolenbroek 	if (buf[sizeof(buf) - 101] != 'B') e(0);
1695*3ba6090fSDavid van Moolenbroek 
1696*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1697*3ba6090fSDavid van Moolenbroek }
1698*3ba6090fSDavid van Moolenbroek 
1699*3ba6090fSDavid van Moolenbroek /*
1700*3ba6090fSDavid van Moolenbroek  * Test program for LWIP RAW sockets.
1701*3ba6090fSDavid van Moolenbroek  */
1702*3ba6090fSDavid van Moolenbroek int
main(int argc,char ** argv)1703*3ba6090fSDavid van Moolenbroek main(int argc, char ** argv)
1704*3ba6090fSDavid van Moolenbroek {
1705*3ba6090fSDavid van Moolenbroek 	int i, m;
1706*3ba6090fSDavid van Moolenbroek 
1707*3ba6090fSDavid van Moolenbroek 	start(92);
1708*3ba6090fSDavid van Moolenbroek 
1709*3ba6090fSDavid van Moolenbroek 	if (argc == 2)
1710*3ba6090fSDavid van Moolenbroek 		m = atoi(argv[1]);
1711*3ba6090fSDavid van Moolenbroek 	else
1712*3ba6090fSDavid van Moolenbroek 		m = 0xFFFF;
1713*3ba6090fSDavid van Moolenbroek 
1714*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < ITERATIONS; i++) {
1715*3ba6090fSDavid van Moolenbroek 		if (m & 0x0001) test92a();
1716*3ba6090fSDavid van Moolenbroek 		if (m & 0x0002) test92b();
1717*3ba6090fSDavid van Moolenbroek 		if (m & 0x0004) test92c();
1718*3ba6090fSDavid van Moolenbroek 		if (m & 0x0008) test92d();
1719*3ba6090fSDavid van Moolenbroek 		if (m & 0x0010) test92e();
1720*3ba6090fSDavid van Moolenbroek 		if (m & 0x0020) test92f();
1721*3ba6090fSDavid van Moolenbroek 		if (m & 0x0040) test92g();
1722*3ba6090fSDavid van Moolenbroek 		if (m & 0x0080) test92h();
1723*3ba6090fSDavid van Moolenbroek 		if (m & 0x0100) test92i();
1724*3ba6090fSDavid van Moolenbroek 		if (m & 0x0200) test92j();
1725*3ba6090fSDavid van Moolenbroek 		if (m & 0x0400) test92k();
1726*3ba6090fSDavid van Moolenbroek 		if (m & 0x0400) test92k();
1727*3ba6090fSDavid van Moolenbroek 		if (m & 0x0800) test92l();
1728*3ba6090fSDavid van Moolenbroek 		if (m & 0x1000) test92m();
1729*3ba6090fSDavid van Moolenbroek 		if (m & 0x2000) test92n();
1730*3ba6090fSDavid van Moolenbroek 		if (m & 0x4000) test92o();
1731*3ba6090fSDavid van Moolenbroek 	}
1732*3ba6090fSDavid van Moolenbroek 
1733*3ba6090fSDavid van Moolenbroek 	quit();
1734*3ba6090fSDavid van Moolenbroek 	/* NOTREACHED */
1735*3ba6090fSDavid van Moolenbroek }
1736