xref: /minix3/minix/tests/socklib.c (revision 3ba6090f825dfbac97538b19928b0ab1e37909d6)
1*3ba6090fSDavid van Moolenbroek /*
2*3ba6090fSDavid van Moolenbroek  * Socket test code library.  This file contains code that is worth sharing
3*3ba6090fSDavid van Moolenbroek  * between TCP/IP and UDS tests, as well as code that is worth sharing between
4*3ba6090fSDavid van Moolenbroek  * various TCP/IP tests.
5*3ba6090fSDavid van Moolenbroek  */
6baa5830fSDavid van Moolenbroek #include <stdlib.h>
7baa5830fSDavid van Moolenbroek #include <stdio.h>
8baa5830fSDavid van Moolenbroek #include <string.h>
9baa5830fSDavid van Moolenbroek #include <signal.h>
10baa5830fSDavid van Moolenbroek #include <sys/param.h>
11baa5830fSDavid van Moolenbroek #include <sys/wait.h>
12baa5830fSDavid van Moolenbroek #include <sys/socket.h>
13baa5830fSDavid van Moolenbroek #include <sys/ioctl.h>
14*3ba6090fSDavid van Moolenbroek #include <sys/sysctl.h>
15*3ba6090fSDavid van Moolenbroek #include <net/if.h>
16*3ba6090fSDavid van Moolenbroek #include <netinet/in.h>
17*3ba6090fSDavid van Moolenbroek #include <netinet/ip.h>
18*3ba6090fSDavid van Moolenbroek #include <netinet6/in6_var.h>
19*3ba6090fSDavid van Moolenbroek #include <arpa/inet.h>
20*3ba6090fSDavid van Moolenbroek #include <ifaddrs.h>
21baa5830fSDavid van Moolenbroek #include <unistd.h>
22baa5830fSDavid van Moolenbroek #include <fcntl.h>
23baa5830fSDavid van Moolenbroek 
24baa5830fSDavid van Moolenbroek #include "common.h"
25baa5830fSDavid van Moolenbroek #include "socklib.h"
26baa5830fSDavid van Moolenbroek 
27*3ba6090fSDavid van Moolenbroek #define TEST_PORT_A	12345	/* this port should be free and usable */
28*3ba6090fSDavid van Moolenbroek #define TEST_PORT_B	12346	/* this port should be free and usable */
29*3ba6090fSDavid van Moolenbroek 
30*3ba6090fSDavid van Moolenbroek #define LOOPBACK_IFNAME		"lo0"		/* loopback interface name */
31*3ba6090fSDavid van Moolenbroek #define LOOPBACK_IPV4		"127.0.0.1"	/* IPv4 address */
32*3ba6090fSDavid van Moolenbroek #define LOOPBACK_IPV6_LL	"fe80::1"	/* link-local IPv6 address */
33*3ba6090fSDavid van Moolenbroek 
34*3ba6090fSDavid van Moolenbroek /* These address should simply eat all packets. */
35*3ba6090fSDavid van Moolenbroek #define TEST_BLACKHOLE_IPV4	"127.255.0.254"
36*3ba6090fSDavid van Moolenbroek #define TEST_BLACKHOLE_IPV6	"::2"
37*3ba6090fSDavid van Moolenbroek #define TEST_BLACKHOLE_IPV6_LL	"fe80::ffff"
38*3ba6090fSDavid van Moolenbroek 
39*3ba6090fSDavid van Moolenbroek /* Addresses for multicast-related testing. */
40*3ba6090fSDavid van Moolenbroek #define TEST_MULTICAST_IPV4	"233.252.0.1"		/* RFC 5771 Sec. 9.2 */
41*3ba6090fSDavid van Moolenbroek #define TEST_MULTICAST_IPV6	"ff0e::db8:0:1"		/* RFC 6676 Sec. 3 */
42*3ba6090fSDavid van Moolenbroek #define TEST_MULTICAST_IPV6_LL	"ff02::db8:0:1"
43*3ba6090fSDavid van Moolenbroek #define TEST_MULTICAST_IPV6_BAD	"ff00::db8:0:1"
44*3ba6090fSDavid van Moolenbroek 
45*3ba6090fSDavid van Moolenbroek #define BAD_IFINDEX	255	/* guaranteed not to belong to an interface */
46*3ba6090fSDavid van Moolenbroek 
47baa5830fSDavid van Moolenbroek /* 0 = check, 1 = generate source, 2 = generate CSV */
48baa5830fSDavid van Moolenbroek #define SOCKLIB_SWEEP_GENERATE 0
49baa5830fSDavid van Moolenbroek 
50baa5830fSDavid van Moolenbroek #if SOCKLIB_SWEEP_GENERATE
51baa5830fSDavid van Moolenbroek /* Link against minix/usr.bin/trace/error.o to make this work! */
52baa5830fSDavid van Moolenbroek const char *get_error_name(int err);
53baa5830fSDavid van Moolenbroek 
54baa5830fSDavid van Moolenbroek #if SOCKLIB_SWEEP_GENERATE == 2
55baa5830fSDavid van Moolenbroek static const char *statename[S_MAX] = {
56baa5830fSDavid van Moolenbroek 	"S_NEW",
57baa5830fSDavid van Moolenbroek 	"S_N_SHUT_R",
58baa5830fSDavid van Moolenbroek 	"S_N_SHUT_W",
59baa5830fSDavid van Moolenbroek 	"S_N_SHUT_RW",
60baa5830fSDavid van Moolenbroek 	"S_BOUND",
61baa5830fSDavid van Moolenbroek 	"S_LISTENING",
62baa5830fSDavid van Moolenbroek 	"S_L_SHUT_R",
63baa5830fSDavid van Moolenbroek 	"S_L_SHUT_W",
64baa5830fSDavid van Moolenbroek 	"S_L_SHUT_RW",
65baa5830fSDavid van Moolenbroek 	"S_CONNECTING",
66baa5830fSDavid van Moolenbroek 	"S_C_SHUT_R",
67baa5830fSDavid van Moolenbroek 	"S_C_SHUT_W",
68baa5830fSDavid van Moolenbroek 	"S_C_SHUT_RW",
69baa5830fSDavid van Moolenbroek 	"S_CONNECTED",
70baa5830fSDavid van Moolenbroek 	"S_ACCEPTED",
71baa5830fSDavid van Moolenbroek 	"S_SHUT_R",
72baa5830fSDavid van Moolenbroek 	"S_SHUT_W",
73baa5830fSDavid van Moolenbroek 	"S_SHUT_RW",
74baa5830fSDavid van Moolenbroek 	"S_RSHUT_R",
75baa5830fSDavid van Moolenbroek 	"S_RSHUT_W",
76baa5830fSDavid van Moolenbroek 	"S_RSHUT_RW",
77baa5830fSDavid van Moolenbroek 	"S_SHUT2_R",
78baa5830fSDavid van Moolenbroek 	"S_SHUT2_W",
79baa5830fSDavid van Moolenbroek 	"S_SHUT2_RW",
80baa5830fSDavid van Moolenbroek 	"S_PRE_EOF",
81baa5830fSDavid van Moolenbroek 	"S_AT_EOF",
82baa5830fSDavid van Moolenbroek 	"S_POST_EOF",
83baa5830fSDavid van Moolenbroek 	"S_PRE_SHUT_R",
84baa5830fSDavid van Moolenbroek 	"S_EOF_SHUT_R",
85baa5830fSDavid van Moolenbroek 	"S_POST_SHUT_R",
86baa5830fSDavid van Moolenbroek 	"S_PRE_SHUT_W",
87baa5830fSDavid van Moolenbroek 	"S_EOF_SHUT_W",
88baa5830fSDavid van Moolenbroek 	"S_POST_SHUT_W",
89baa5830fSDavid van Moolenbroek 	"S_PRE_SHUT_RW",
90baa5830fSDavid van Moolenbroek 	"S_EOF_SHUT_RW",
91baa5830fSDavid van Moolenbroek 	"S_POST_SHUT_RW",
92baa5830fSDavid van Moolenbroek 	"S_PRE_RESET",
93baa5830fSDavid van Moolenbroek 	"S_AT_RESET",
94baa5830fSDavid van Moolenbroek 	"S_POST_RESET",
95baa5830fSDavid van Moolenbroek 	"S_FAILED",
96baa5830fSDavid van Moolenbroek 	"S_POST_FAILED",
97baa5830fSDavid van Moolenbroek };
98baa5830fSDavid van Moolenbroek #endif
99baa5830fSDavid van Moolenbroek 
100baa5830fSDavid van Moolenbroek static const char *callname[C_MAX] = {
101baa5830fSDavid van Moolenbroek 	"C_ACCEPT",
102baa5830fSDavid van Moolenbroek 	"C_BIND",
103baa5830fSDavid van Moolenbroek 	"C_CONNECT",
104baa5830fSDavid van Moolenbroek 	"C_GETPEERNAME",
105baa5830fSDavid van Moolenbroek 	"C_GETSOCKNAME",
106baa5830fSDavid van Moolenbroek 	"C_GETSOCKOPT_ERR",
107baa5830fSDavid van Moolenbroek 	"C_GETSOCKOPT_KA",
108baa5830fSDavid van Moolenbroek 	"C_GETSOCKOPT_RB",
109baa5830fSDavid van Moolenbroek 	"C_IOCTL_NREAD",
110baa5830fSDavid van Moolenbroek 	"C_LISTEN",
111baa5830fSDavid van Moolenbroek 	"C_RECV",
112baa5830fSDavid van Moolenbroek 	"C_RECVFROM",
113baa5830fSDavid van Moolenbroek 	"C_SEND",
114baa5830fSDavid van Moolenbroek 	"C_SENDTO",
115baa5830fSDavid van Moolenbroek 	"C_SELECT_R",
116baa5830fSDavid van Moolenbroek 	"C_SELECT_W",
117baa5830fSDavid van Moolenbroek 	"C_SELECT_X",
118baa5830fSDavid van Moolenbroek 	"C_SETSOCKOPT_BC",
119baa5830fSDavid van Moolenbroek 	"C_SETSOCKOPT_KA",
120baa5830fSDavid van Moolenbroek 	"C_SETSOCKOPT_L",
121baa5830fSDavid van Moolenbroek 	"C_SETSOCKOPT_RA",
122baa5830fSDavid van Moolenbroek 	"C_SHUTDOWN_R",
123baa5830fSDavid van Moolenbroek 	"C_SHUTDOWN_RW",
124baa5830fSDavid van Moolenbroek 	"C_SHUTDOWN_W",
125baa5830fSDavid van Moolenbroek };
126baa5830fSDavid van Moolenbroek #endif
127baa5830fSDavid van Moolenbroek 
128baa5830fSDavid van Moolenbroek static int socklib_sigpipe;
129baa5830fSDavid van Moolenbroek 
130baa5830fSDavid van Moolenbroek /*
131baa5830fSDavid van Moolenbroek  * Signal handler for SIGPIPE signals.
132baa5830fSDavid van Moolenbroek  */
133baa5830fSDavid van Moolenbroek static void
socklib_signal(int sig)134baa5830fSDavid van Moolenbroek socklib_signal(int sig)
135baa5830fSDavid van Moolenbroek {
136baa5830fSDavid van Moolenbroek 
137baa5830fSDavid van Moolenbroek 	if (sig != SIGPIPE) e(0);
138baa5830fSDavid van Moolenbroek 
139baa5830fSDavid van Moolenbroek 	socklib_sigpipe++;
140baa5830fSDavid van Moolenbroek }
141baa5830fSDavid van Moolenbroek 
142baa5830fSDavid van Moolenbroek /*
143baa5830fSDavid van Moolenbroek  * The given socket file descriptor 'fd' has been set up in the desired state.
144baa5830fSDavid van Moolenbroek  * Perform the given call 'call' on it, possibly using local socket address
145baa5830fSDavid van Moolenbroek  * 'local_addr' (for binding) or remote socket address 'remote_addr' (for
146baa5830fSDavid van Moolenbroek  * connecting or to store resulting addresses), both of size 'addr_len'.
147baa5830fSDavid van Moolenbroek  * Return the result of the call, using a positive value if the call succeeded,
148baa5830fSDavid van Moolenbroek  * or a negated errno code if the call failed.
149baa5830fSDavid van Moolenbroek  */
150baa5830fSDavid van Moolenbroek int
socklib_sweep_call(enum call call,int fd,struct sockaddr * local_addr,struct sockaddr * remote_addr,socklen_t addr_len)151baa5830fSDavid van Moolenbroek socklib_sweep_call(enum call call, int fd, struct sockaddr * local_addr,
152baa5830fSDavid van Moolenbroek 	struct sockaddr * remote_addr, socklen_t addr_len)
153baa5830fSDavid van Moolenbroek {
154baa5830fSDavid van Moolenbroek 	char data[1];
155baa5830fSDavid van Moolenbroek 	struct linger l;
156baa5830fSDavid van Moolenbroek 	fd_set fd_set;
157baa5830fSDavid van Moolenbroek 	struct timeval tv;
158baa5830fSDavid van Moolenbroek 	socklen_t len;
159baa5830fSDavid van Moolenbroek 	int i, r, fd2;
160baa5830fSDavid van Moolenbroek 
161baa5830fSDavid van Moolenbroek 	fd2 = -1;
162baa5830fSDavid van Moolenbroek 
163baa5830fSDavid van Moolenbroek 	switch (call) {
164baa5830fSDavid van Moolenbroek 	case C_ACCEPT:
165baa5830fSDavid van Moolenbroek 		r = accept(fd, remote_addr, &addr_len);
166baa5830fSDavid van Moolenbroek 
167baa5830fSDavid van Moolenbroek 		if (r >= 0)
168baa5830fSDavid van Moolenbroek 			fd2 = r;
169baa5830fSDavid van Moolenbroek 
170baa5830fSDavid van Moolenbroek 		break;
171baa5830fSDavid van Moolenbroek 
172baa5830fSDavid van Moolenbroek 	case C_BIND:
173baa5830fSDavid van Moolenbroek 		r = bind(fd, local_addr, addr_len);
174baa5830fSDavid van Moolenbroek 
175baa5830fSDavid van Moolenbroek 		break;
176baa5830fSDavid van Moolenbroek 
177baa5830fSDavid van Moolenbroek 	case C_CONNECT:
178baa5830fSDavid van Moolenbroek 		r = connect(fd, remote_addr, addr_len);
179baa5830fSDavid van Moolenbroek 
180baa5830fSDavid van Moolenbroek 		break;
181baa5830fSDavid van Moolenbroek 
182baa5830fSDavid van Moolenbroek 	case C_GETPEERNAME:
183baa5830fSDavid van Moolenbroek 		r = getpeername(fd, remote_addr, &addr_len);
184baa5830fSDavid van Moolenbroek 
185baa5830fSDavid van Moolenbroek 		break;
186baa5830fSDavid van Moolenbroek 
187baa5830fSDavid van Moolenbroek 	case C_GETSOCKNAME:
188baa5830fSDavid van Moolenbroek 		r = getsockname(fd, remote_addr, &addr_len);
189baa5830fSDavid van Moolenbroek 
190baa5830fSDavid van Moolenbroek 		break;
191baa5830fSDavid van Moolenbroek 
192baa5830fSDavid van Moolenbroek 	case C_GETSOCKOPT_ERR:
193baa5830fSDavid van Moolenbroek 		len = sizeof(i);
194baa5830fSDavid van Moolenbroek 
195baa5830fSDavid van Moolenbroek 		r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &i, &len);
196baa5830fSDavid van Moolenbroek 
197baa5830fSDavid van Moolenbroek 		/*
198baa5830fSDavid van Moolenbroek 		 * We assume this call always succeeds, and test against the
199baa5830fSDavid van Moolenbroek 		 * pending error.
200baa5830fSDavid van Moolenbroek 		 */
201baa5830fSDavid van Moolenbroek 		if (r != 0) e(0);
202baa5830fSDavid van Moolenbroek 		if (i != 0) {
203baa5830fSDavid van Moolenbroek 			r = -1;
204baa5830fSDavid van Moolenbroek 			errno = i;
205baa5830fSDavid van Moolenbroek 		}
206baa5830fSDavid van Moolenbroek 
207baa5830fSDavid van Moolenbroek 		break;
208baa5830fSDavid van Moolenbroek 
209baa5830fSDavid van Moolenbroek 	case C_GETSOCKOPT_KA:
210baa5830fSDavid van Moolenbroek 		len = sizeof(i);
211baa5830fSDavid van Moolenbroek 
212baa5830fSDavid van Moolenbroek 		r = getsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &i, &len);
213baa5830fSDavid van Moolenbroek 
214baa5830fSDavid van Moolenbroek 		break;
215baa5830fSDavid van Moolenbroek 
216baa5830fSDavid van Moolenbroek 	case C_GETSOCKOPT_RB:
217baa5830fSDavid van Moolenbroek 		len = sizeof(i);
218baa5830fSDavid van Moolenbroek 
219baa5830fSDavid van Moolenbroek 		r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &i, &len);
220baa5830fSDavid van Moolenbroek 
221baa5830fSDavid van Moolenbroek 		break;
222baa5830fSDavid van Moolenbroek 
223baa5830fSDavid van Moolenbroek 	case C_IOCTL_NREAD:
224baa5830fSDavid van Moolenbroek 		r = ioctl(fd, FIONREAD, &i);
225baa5830fSDavid van Moolenbroek 
226baa5830fSDavid van Moolenbroek 		/* On success, we test against the returned value here. */
227baa5830fSDavid van Moolenbroek 		if (r == 0)
228baa5830fSDavid van Moolenbroek 			r = i;
229baa5830fSDavid van Moolenbroek 
230baa5830fSDavid van Moolenbroek 		break;
231baa5830fSDavid van Moolenbroek 
232baa5830fSDavid van Moolenbroek 	case C_LISTEN:
233baa5830fSDavid van Moolenbroek 		r = listen(fd, 1);
234baa5830fSDavid van Moolenbroek 
235baa5830fSDavid van Moolenbroek 		break;
236baa5830fSDavid van Moolenbroek 
237baa5830fSDavid van Moolenbroek 	case C_RECV:
238baa5830fSDavid van Moolenbroek 		r = recv(fd, data, sizeof(data), 0);
239baa5830fSDavid van Moolenbroek 
240baa5830fSDavid van Moolenbroek 		break;
241baa5830fSDavid van Moolenbroek 
242baa5830fSDavid van Moolenbroek 	case C_RECVFROM:
243baa5830fSDavid van Moolenbroek 		r = recvfrom(fd, data, sizeof(data), 0, remote_addr,
244baa5830fSDavid van Moolenbroek 		    &addr_len);
245baa5830fSDavid van Moolenbroek 
246baa5830fSDavid van Moolenbroek 		break;
247baa5830fSDavid van Moolenbroek 
248baa5830fSDavid van Moolenbroek 	case C_SEND:
249baa5830fSDavid van Moolenbroek 		data[0] = 0;
250baa5830fSDavid van Moolenbroek 
251baa5830fSDavid van Moolenbroek 		r = send(fd, data, sizeof(data), 0);
252baa5830fSDavid van Moolenbroek 
253baa5830fSDavid van Moolenbroek 		break;
254baa5830fSDavid van Moolenbroek 
255baa5830fSDavid van Moolenbroek 	case C_SENDTO:
256baa5830fSDavid van Moolenbroek 		data[0] = 0;
257baa5830fSDavid van Moolenbroek 
258baa5830fSDavid van Moolenbroek 		r = sendto(fd, data, sizeof(data), 0, remote_addr, addr_len);
259baa5830fSDavid van Moolenbroek 
260baa5830fSDavid van Moolenbroek 		break;
261baa5830fSDavid van Moolenbroek 
262baa5830fSDavid van Moolenbroek 	case C_SETSOCKOPT_BC:
263baa5830fSDavid van Moolenbroek 		i = 0;
264baa5830fSDavid van Moolenbroek 
265baa5830fSDavid van Moolenbroek 		r = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i));
266baa5830fSDavid van Moolenbroek 
267baa5830fSDavid van Moolenbroek 		break;
268baa5830fSDavid van Moolenbroek 
269baa5830fSDavid van Moolenbroek 	case C_SETSOCKOPT_KA:
270baa5830fSDavid van Moolenbroek 		i = 1;
271baa5830fSDavid van Moolenbroek 
272baa5830fSDavid van Moolenbroek 		r = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &i, sizeof(i));
273baa5830fSDavid van Moolenbroek 
274baa5830fSDavid van Moolenbroek 		break;
275baa5830fSDavid van Moolenbroek 
276baa5830fSDavid van Moolenbroek 	case C_SETSOCKOPT_L:
277baa5830fSDavid van Moolenbroek 		l.l_onoff = 1;
278baa5830fSDavid van Moolenbroek 		l.l_linger = 0;
279baa5830fSDavid van Moolenbroek 
280baa5830fSDavid van Moolenbroek 		r = setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
281baa5830fSDavid van Moolenbroek 
282baa5830fSDavid van Moolenbroek 		break;
283baa5830fSDavid van Moolenbroek 
284baa5830fSDavid van Moolenbroek 	case C_SETSOCKOPT_RA:
285baa5830fSDavid van Moolenbroek 		i = 1;
286baa5830fSDavid van Moolenbroek 
287baa5830fSDavid van Moolenbroek 		r = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
288baa5830fSDavid van Moolenbroek 
289baa5830fSDavid van Moolenbroek 		break;
290baa5830fSDavid van Moolenbroek 
291baa5830fSDavid van Moolenbroek 	case C_SELECT_R:
292baa5830fSDavid van Moolenbroek 	case C_SELECT_W:
293baa5830fSDavid van Moolenbroek 	case C_SELECT_X:
294baa5830fSDavid van Moolenbroek 		FD_ZERO(&fd_set);
295baa5830fSDavid van Moolenbroek 		FD_SET(fd, &fd_set);
296baa5830fSDavid van Moolenbroek 
297baa5830fSDavid van Moolenbroek 		tv.tv_sec = 0;
298baa5830fSDavid van Moolenbroek 		tv.tv_usec = 0;
299baa5830fSDavid van Moolenbroek 
300baa5830fSDavid van Moolenbroek 		r = select(fd + 1, (call == C_SELECT_R) ? &fd_set : NULL,
301baa5830fSDavid van Moolenbroek 		    (call == C_SELECT_W) ? &fd_set : NULL,
302baa5830fSDavid van Moolenbroek 		    (call == C_SELECT_X) ? &fd_set : NULL, &tv);
303baa5830fSDavid van Moolenbroek 
304baa5830fSDavid van Moolenbroek 		break;
305baa5830fSDavid van Moolenbroek 
306baa5830fSDavid van Moolenbroek 	case C_SHUTDOWN_R:
307baa5830fSDavid van Moolenbroek 		r = shutdown(fd, SHUT_RD);
308baa5830fSDavid van Moolenbroek 
309baa5830fSDavid van Moolenbroek 		break;
310baa5830fSDavid van Moolenbroek 
311baa5830fSDavid van Moolenbroek 	case C_SHUTDOWN_W:
312baa5830fSDavid van Moolenbroek 		r = shutdown(fd, SHUT_WR);
313baa5830fSDavid van Moolenbroek 
314baa5830fSDavid van Moolenbroek 		break;
315baa5830fSDavid van Moolenbroek 
316baa5830fSDavid van Moolenbroek 	case C_SHUTDOWN_RW:
317baa5830fSDavid van Moolenbroek 		r = shutdown(fd, SHUT_RDWR);
318baa5830fSDavid van Moolenbroek 
319baa5830fSDavid van Moolenbroek 		break;
320baa5830fSDavid van Moolenbroek 
321baa5830fSDavid van Moolenbroek 	default:
322baa5830fSDavid van Moolenbroek 		r = -1;
323baa5830fSDavid van Moolenbroek 		errno = EINVAL;
324baa5830fSDavid van Moolenbroek 		e(0);
325baa5830fSDavid van Moolenbroek 	}
326baa5830fSDavid van Moolenbroek 
327baa5830fSDavid van Moolenbroek 	if (r < -1) e(0);
328baa5830fSDavid van Moolenbroek 
329baa5830fSDavid van Moolenbroek 	if (r == -1)
330baa5830fSDavid van Moolenbroek 		r = -errno;
331baa5830fSDavid van Moolenbroek 
332baa5830fSDavid van Moolenbroek 	if (fd2 >= 0 && close(fd2) != 0) e(0);
333baa5830fSDavid van Moolenbroek 
334baa5830fSDavid van Moolenbroek 	return r;
335baa5830fSDavid van Moolenbroek }
336baa5830fSDavid van Moolenbroek 
337baa5830fSDavid van Moolenbroek /*
338baa5830fSDavid van Moolenbroek  * Perform a sweep of socket calls vs socket states, testing the outcomes
339baa5830fSDavid van Moolenbroek  * against provided tables or (if SOCKLIB_SWEEP_GENERATE is set) reporting on
340baa5830fSDavid van Moolenbroek  * the outcomes instead.  The caller must provide the following:
341baa5830fSDavid van Moolenbroek  *
342baa5830fSDavid van Moolenbroek  * - the socket domain, type, and protocol to test; these are simply forwarded
343baa5830fSDavid van Moolenbroek  *   to the callback function (see below);
344baa5830fSDavid van Moolenbroek  * - the set of S_ states to test, as array 'states' with 'nstates' elements;
345baa5830fSDavid van Moolenbroek  * - unless generating output, a matrix of expected results as 'results', which
346baa5830fSDavid van Moolenbroek  *   is actually a two-dimensional array with dimensions [C_MAX][nstates], with
347baa5830fSDavid van Moolenbroek  *   either positive call output or a negated call errno code in each cell;
348baa5830fSDavid van Moolenbroek  * - a callback function 'proc' that must set up a socket in the given state
349baa5830fSDavid van Moolenbroek  *   and pass it to socklib_sweep_call().
350baa5830fSDavid van Moolenbroek  *
351baa5830fSDavid van Moolenbroek  * The 'states' array allows each socket sweep test to support a different set
352baa5830fSDavid van Moolenbroek  * of states, because not every type of socket can be put in every possible
353baa5830fSDavid van Moolenbroek  * state.  All calls are always tried in each state, though.
354baa5830fSDavid van Moolenbroek  *
355baa5830fSDavid van Moolenbroek  * The sweep also tests for SIGPIPE generation, which assumes that all calls on
356baa5830fSDavid van Moolenbroek  * SOCK_STREAM sockets that return EPIPE, also raise a SIGPIPE signal, and that
357baa5830fSDavid van Moolenbroek  * no other SIGPIPE signal is ever raised otherwise.
358baa5830fSDavid van Moolenbroek  *
359baa5830fSDavid van Moolenbroek  * Standard e() error throwing is used for set-up and result mismatches.
360baa5830fSDavid van Moolenbroek  */
361baa5830fSDavid van Moolenbroek void
socklib_sweep(int domain,int type,int protocol,const enum state * states,unsigned int nstates,const int * results,int (* proc)(int domain,int type,int protocol,enum state,enum call))362baa5830fSDavid van Moolenbroek socklib_sweep(int domain, int type, int protocol, const enum state * states,
363baa5830fSDavid van Moolenbroek 	unsigned int nstates, const int * results, int (* proc)(int domain,
364baa5830fSDavid van Moolenbroek 	int type, int protocol, enum state, enum call))
365baa5830fSDavid van Moolenbroek {
366baa5830fSDavid van Moolenbroek 	struct sigaction act, oact;
367baa5830fSDavid van Moolenbroek 	enum state state;
368baa5830fSDavid van Moolenbroek 	enum call call;
369baa5830fSDavid van Moolenbroek #if SOCKLIB_SWEEP_GENERATE
370baa5830fSDavid van Moolenbroek 	const char *name;
371baa5830fSDavid van Moolenbroek 	int res, *nresults;
372baa5830fSDavid van Moolenbroek #else
373baa5830fSDavid van Moolenbroek 	int res, exp;
374baa5830fSDavid van Moolenbroek #endif
375baa5830fSDavid van Moolenbroek 
376baa5830fSDavid van Moolenbroek 	memset(&act, 0, sizeof(act));
377baa5830fSDavid van Moolenbroek 	act.sa_handler = socklib_signal;
378baa5830fSDavid van Moolenbroek 	if (sigaction(SIGPIPE, &act, &oact) != 0) e(0);
379baa5830fSDavid van Moolenbroek 
380baa5830fSDavid van Moolenbroek #if SOCKLIB_SWEEP_GENERATE
381baa5830fSDavid van Moolenbroek 	if ((nresults = malloc(nstates * C_MAX)) == NULL) e(0);
382baa5830fSDavid van Moolenbroek #endif
383baa5830fSDavid van Moolenbroek 
384baa5830fSDavid van Moolenbroek 	for (state = 0; state < nstates; state++) {
385baa5830fSDavid van Moolenbroek 		for (call = 0; call < C_MAX; call++) {
386baa5830fSDavid van Moolenbroek 			socklib_sigpipe = 0;
387baa5830fSDavid van Moolenbroek 
388baa5830fSDavid van Moolenbroek 			res = proc(domain, type, protocol, states[state],
389baa5830fSDavid van Moolenbroek 			    call);
390baa5830fSDavid van Moolenbroek 
391baa5830fSDavid van Moolenbroek 			/*
392baa5830fSDavid van Moolenbroek 			 * If the result was EPIPE and this is a stream-type
393baa5830fSDavid van Moolenbroek 			 * socket, we must have received exactly one SIGPIPE
394baa5830fSDavid van Moolenbroek 			 * signal.  Otherwise, we must not have received one.
395baa5830fSDavid van Moolenbroek 			 * Note that technically, the SIGPIPE could arrive
396baa5830fSDavid van Moolenbroek 			 * sometime after this check, but with regular system
397baa5830fSDavid van Moolenbroek 			 * service scheduling that will never happen.
398baa5830fSDavid van Moolenbroek 			 */
399baa5830fSDavid van Moolenbroek 			if (socklib_sigpipe !=
400baa5830fSDavid van Moolenbroek 			    (res == -EPIPE && type == SOCK_STREAM)) e(0);
401baa5830fSDavid van Moolenbroek 
402baa5830fSDavid van Moolenbroek #if SOCKLIB_SWEEP_GENERATE
403baa5830fSDavid van Moolenbroek 			nresults[call * nstates + state] = res;
404baa5830fSDavid van Moolenbroek #else
405baa5830fSDavid van Moolenbroek 			exp = results[call * nstates + state];
406baa5830fSDavid van Moolenbroek 
407baa5830fSDavid van Moolenbroek 			if (res != exp) {
408baa5830fSDavid van Moolenbroek 				printf("FAIL state %d call %d res %d exp %d\n",
409baa5830fSDavid van Moolenbroek 				    state, call, res, exp);
410baa5830fSDavid van Moolenbroek 				e(0);
411baa5830fSDavid van Moolenbroek 			}
412baa5830fSDavid van Moolenbroek #endif
413baa5830fSDavid van Moolenbroek 		}
414baa5830fSDavid van Moolenbroek 	}
415baa5830fSDavid van Moolenbroek 
416baa5830fSDavid van Moolenbroek 	if (sigaction(SIGPIPE, &oact, NULL) != 0) e(0);
417baa5830fSDavid van Moolenbroek 
418baa5830fSDavid van Moolenbroek #if SOCKLIB_SWEEP_GENERATE
419baa5830fSDavid van Moolenbroek #if SOCKLIB_SWEEP_GENERATE == 1
420baa5830fSDavid van Moolenbroek 	/*
421baa5830fSDavid van Moolenbroek 	 * Generate a table in C form, ready to be pasted into test source.
422baa5830fSDavid van Moolenbroek 	 * Obviously, generated results should be hand-checked carefully before
423baa5830fSDavid van Moolenbroek 	 * being pasted into a test.  Arguably these tables should be hand-made
424baa5830fSDavid van Moolenbroek 	 * for maximum scrutiny, but I already checked the results from the
425baa5830fSDavid van Moolenbroek 	 * CSV form (#define SOCKLIB_SWEEP_GENERATE 2) and have no desire for
426baa5830fSDavid van Moolenbroek 	 * RSI -dcvmoole
427baa5830fSDavid van Moolenbroek 	 */
428baa5830fSDavid van Moolenbroek 	printf("\nstatic const int X_results[][__arraycount(X_states)] = {\n");
429baa5830fSDavid van Moolenbroek 	for (call = 0; call < C_MAX; call++) {
430baa5830fSDavid van Moolenbroek 		if ((name = callname[call]) == NULL) e(0);
431baa5830fSDavid van Moolenbroek 		printf("\t[%s]%s%s%s= {", name,
432baa5830fSDavid van Moolenbroek 		    (strlen(name) <= 21) ? "\t" : "",
433baa5830fSDavid van Moolenbroek 		    (strlen(name) <= 13) ? "\t" : "",
434baa5830fSDavid van Moolenbroek 		    (strlen(name) <= 5) ? "\t" : "");
435baa5830fSDavid van Moolenbroek 		for (state = 0; state < nstates; state++) {
436baa5830fSDavid van Moolenbroek 			if (state % 4 == 0)
437baa5830fSDavid van Moolenbroek 				printf("\n\t\t");
438baa5830fSDavid van Moolenbroek 			res = nresults[call * nstates + state];
439baa5830fSDavid van Moolenbroek 			name = (res < 0) ? get_error_name(-res) : NULL;
440baa5830fSDavid van Moolenbroek 			if (name != NULL) {
441baa5830fSDavid van Moolenbroek 				printf("-%s,", name);
442baa5830fSDavid van Moolenbroek 				if ((state + 1) % 4 != 0 &&
443baa5830fSDavid van Moolenbroek 				    state < nstates - 1)
444baa5830fSDavid van Moolenbroek 					printf("%s%s",
445baa5830fSDavid van Moolenbroek 					    (strlen(name) <= 13) ? "\t" : "",
446baa5830fSDavid van Moolenbroek 					    (strlen(name) <= 5) ? "\t" : "");
447baa5830fSDavid van Moolenbroek 			} else {
448baa5830fSDavid van Moolenbroek 				printf("%d,", res);
449baa5830fSDavid van Moolenbroek 				if ((state + 1) % 4 != 0 &&
450baa5830fSDavid van Moolenbroek 				    state < nstates - 1)
451baa5830fSDavid van Moolenbroek 					printf("\t\t");
452baa5830fSDavid van Moolenbroek 			}
453baa5830fSDavid van Moolenbroek 		}
454baa5830fSDavid van Moolenbroek 		printf("\n\t},\n");
455baa5830fSDavid van Moolenbroek 	}
456baa5830fSDavid van Moolenbroek 	printf("};\n");
457baa5830fSDavid van Moolenbroek #elif SOCKLIB_SWEEP_GENERATE == 2
458baa5830fSDavid van Moolenbroek 	/* Generate table in CSV form. */
459baa5830fSDavid van Moolenbroek 	printf("\n");
460baa5830fSDavid van Moolenbroek 	for (state = 0; state < nstates; state++)
461baa5830fSDavid van Moolenbroek 		printf(",%s", statename[states[state]] + 2);
462baa5830fSDavid van Moolenbroek 	for (call = 0; call < C_MAX; call++) {
463baa5830fSDavid van Moolenbroek 		printf("\n%s", callname[call] + 2);
464baa5830fSDavid van Moolenbroek 		for (state = 0; state < nstates; state++) {
465baa5830fSDavid van Moolenbroek 			res = nresults[call * nstates + state];
466baa5830fSDavid van Moolenbroek 			name = (res < 0) ? get_error_name(-res) : NULL;
467baa5830fSDavid van Moolenbroek 			if (name != NULL)
468baa5830fSDavid van Moolenbroek 				printf(",%s", name);
469baa5830fSDavid van Moolenbroek 			else
470baa5830fSDavid van Moolenbroek 				printf(",%d", res);
471baa5830fSDavid van Moolenbroek 		}
472baa5830fSDavid van Moolenbroek 	}
473baa5830fSDavid van Moolenbroek 	printf("\n");
474baa5830fSDavid van Moolenbroek #endif
475baa5830fSDavid van Moolenbroek 
476baa5830fSDavid van Moolenbroek 	free(nresults);
477baa5830fSDavid van Moolenbroek #endif
478baa5830fSDavid van Moolenbroek }
479baa5830fSDavid van Moolenbroek 
480baa5830fSDavid van Moolenbroek /*
481*3ba6090fSDavid van Moolenbroek  * Test for setting and retrieving UDP/RAW multicast transmission options.
482*3ba6090fSDavid van Moolenbroek  * This is an interface-level test only: we do not (yet) test whether the
483*3ba6090fSDavid van Moolenbroek  * options have any effect.  The given 'type' must be SOCK_DGRAM or SOCK_RAW.
484*3ba6090fSDavid van Moolenbroek  */
485*3ba6090fSDavid van Moolenbroek void
socklib_multicast_tx_options(int type)486*3ba6090fSDavid van Moolenbroek socklib_multicast_tx_options(int type)
487*3ba6090fSDavid van Moolenbroek {
488*3ba6090fSDavid van Moolenbroek 	struct in_addr in_addr;
489*3ba6090fSDavid van Moolenbroek 	socklen_t len;
490*3ba6090fSDavid van Moolenbroek 	unsigned int ifindex;
491*3ba6090fSDavid van Moolenbroek 	uint8_t byte;
492*3ba6090fSDavid van Moolenbroek 	int fd, val;
493*3ba6090fSDavid van Moolenbroek 
494*3ba6090fSDavid van Moolenbroek 	subtest = 10;
495*3ba6090fSDavid van Moolenbroek 
496*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, type, 0)) < 0) e(0);
497*3ba6090fSDavid van Moolenbroek 
498*3ba6090fSDavid van Moolenbroek 	/*
499*3ba6090fSDavid van Moolenbroek 	 * Initially, the multicast TTL is expected be 1, looping should be
500*3ba6090fSDavid van Moolenbroek 	 * enabled, and the multicast source address should be <any>.
501*3ba6090fSDavid van Moolenbroek 	 */
502*3ba6090fSDavid van Moolenbroek 	byte = 0;
503*3ba6090fSDavid van Moolenbroek 	len = sizeof(byte);
504*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &byte, &len) != 0)
505*3ba6090fSDavid van Moolenbroek 		e(0);
506*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(byte)) e(0);
507*3ba6090fSDavid van Moolenbroek 	if (type != SOCK_STREAM && byte != 1) e(0);
508*3ba6090fSDavid van Moolenbroek 
509*3ba6090fSDavid van Moolenbroek 	byte = 0;
510*3ba6090fSDavid van Moolenbroek 	len = sizeof(byte);
511*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &byte, &len) != 0)
512*3ba6090fSDavid van Moolenbroek 		e(0);
513*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(byte)) e(0);
514*3ba6090fSDavid van Moolenbroek 	if (byte != 1) e(0);
515*3ba6090fSDavid van Moolenbroek 
516*3ba6090fSDavid van Moolenbroek 	len = sizeof(in_addr);
517*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &in_addr, &len) != 0)
518*3ba6090fSDavid van Moolenbroek 		e(0);
519*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(in_addr)) e(0);
520*3ba6090fSDavid van Moolenbroek 	if (in_addr.s_addr != htonl(INADDR_ANY)) e(0);
521*3ba6090fSDavid van Moolenbroek 
522*3ba6090fSDavid van Moolenbroek 	/* It must not be possible to get/set IPv6 options on IPv4 sockets. */
523*3ba6090fSDavid van Moolenbroek 	val = 0;
524*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val,
525*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != -1) e(0);
526*3ba6090fSDavid van Moolenbroek 	if (errno != ENOPROTOOPT) e(0);
527*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
528*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != -1) e(0);
529*3ba6090fSDavid van Moolenbroek 	if (errno != ENOPROTOOPT) e(0);
530*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val,
531*3ba6090fSDavid van Moolenbroek 	    sizeof(val) /*wrong but it doesn't matter*/) != -1) e(0);
532*3ba6090fSDavid van Moolenbroek 	if (errno != ENOPROTOOPT) e(0);
533*3ba6090fSDavid van Moolenbroek 
534*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
535*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val,
536*3ba6090fSDavid van Moolenbroek 	    &len) != -1) e(0);
537*3ba6090fSDavid van Moolenbroek 	if (errno != ENOPROTOOPT) e(0);
538*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
539*3ba6090fSDavid van Moolenbroek 	    &len) != -1) e(0);
540*3ba6090fSDavid van Moolenbroek 	if (errno != ENOPROTOOPT) e(0);
541*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val, &len) != -1)
542*3ba6090fSDavid van Moolenbroek 		e(0);
543*3ba6090fSDavid van Moolenbroek 	if (errno != ENOPROTOOPT) e(0);
544*3ba6090fSDavid van Moolenbroek 
545*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
546*3ba6090fSDavid van Moolenbroek 
547*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, type, 0)) < 0) e(0);
548*3ba6090fSDavid van Moolenbroek 
549*3ba6090fSDavid van Moolenbroek 	/*
550*3ba6090fSDavid van Moolenbroek 	 * Expect the same defaults as for IPv4.  IPV6_MULTICAST_IF uses an
551*3ba6090fSDavid van Moolenbroek 	 * interface index rather than an IP address, though.
552*3ba6090fSDavid van Moolenbroek 	 */
553*3ba6090fSDavid van Moolenbroek 	val = 0;
554*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
555*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, &len) != 0)
556*3ba6090fSDavid van Moolenbroek 		e(0);
557*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
558*3ba6090fSDavid van Moolenbroek 	if (type != SOCK_STREAM && val != 1) e(0);
559*3ba6090fSDavid van Moolenbroek 
560*3ba6090fSDavid van Moolenbroek 	val = 0;
561*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
562*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, &len) != 0)
563*3ba6090fSDavid van Moolenbroek 		e(0);
564*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
565*3ba6090fSDavid van Moolenbroek 	if (val != 1) e(0);
566*3ba6090fSDavid van Moolenbroek 
567*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
568*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val, &len) != 0)
569*3ba6090fSDavid van Moolenbroek 		e(0);
570*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
571*3ba6090fSDavid van Moolenbroek 	if (val != 0) e(0);
572*3ba6090fSDavid van Moolenbroek 
573*3ba6090fSDavid van Moolenbroek 	/* It must not be possible to get/set IPv4 options on IPv6 sockets. */
574*3ba6090fSDavid van Moolenbroek 	byte = 0;
575*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &byte,
576*3ba6090fSDavid van Moolenbroek 	    sizeof(byte)) != -1) e(0);
577*3ba6090fSDavid van Moolenbroek 	if (errno != ENOPROTOOPT) e(0);
578*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &byte,
579*3ba6090fSDavid van Moolenbroek 	    sizeof(byte)) != -1) e(0);
580*3ba6090fSDavid van Moolenbroek 	if (errno != ENOPROTOOPT) e(0);
581*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &byte,
582*3ba6090fSDavid van Moolenbroek 	    sizeof(byte) /* wrong but it doesn't matter */) != -1) e(0);
583*3ba6090fSDavid van Moolenbroek 	if (errno != ENOPROTOOPT) e(0);
584*3ba6090fSDavid van Moolenbroek 
585*3ba6090fSDavid van Moolenbroek 	len = sizeof(byte);
586*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &val, &len) != -1)
587*3ba6090fSDavid van Moolenbroek 		e(0);
588*3ba6090fSDavid van Moolenbroek 	if (errno != ENOPROTOOPT) e(0);
589*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &val, &len) != -1)
590*3ba6090fSDavid van Moolenbroek 		e(0);
591*3ba6090fSDavid van Moolenbroek 	if (errno != ENOPROTOOPT) e(0);
592*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &val, &len) != -1)
593*3ba6090fSDavid van Moolenbroek 		e(0);
594*3ba6090fSDavid van Moolenbroek 	if (errno != ENOPROTOOPT) e(0);
595*3ba6090fSDavid van Moolenbroek 
596*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
597*3ba6090fSDavid van Moolenbroek 
598*3ba6090fSDavid van Moolenbroek 	/* Test changing options. */
599*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, type, 0)) < 0) e(0);
600*3ba6090fSDavid van Moolenbroek 
601*3ba6090fSDavid van Moolenbroek 	byte = 129;
602*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &byte,
603*3ba6090fSDavid van Moolenbroek 	    sizeof(byte)) != 0) e(0);
604*3ba6090fSDavid van Moolenbroek 
605*3ba6090fSDavid van Moolenbroek 	byte = 0;
606*3ba6090fSDavid van Moolenbroek 	len = sizeof(byte);
607*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &byte, &len) != 0)
608*3ba6090fSDavid van Moolenbroek 		e(0);
609*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(byte)) e(0);
610*3ba6090fSDavid van Moolenbroek 	if (byte != 129) e(0);
611*3ba6090fSDavid van Moolenbroek 
612*3ba6090fSDavid van Moolenbroek 	byte = 0;
613*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &byte,
614*3ba6090fSDavid van Moolenbroek 	    sizeof(byte)) != 0)
615*3ba6090fSDavid van Moolenbroek 		e(0);
616*3ba6090fSDavid van Moolenbroek 
617*3ba6090fSDavid van Moolenbroek 	byte = 1;
618*3ba6090fSDavid van Moolenbroek 	len = sizeof(byte);
619*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &byte, &len) != 0)
620*3ba6090fSDavid van Moolenbroek 		e(0);
621*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(byte)) e(0);
622*3ba6090fSDavid van Moolenbroek 	if (byte != 0) e(0);
623*3ba6090fSDavid van Moolenbroek 
624*3ba6090fSDavid van Moolenbroek 	in_addr.s_addr = htonl(INADDR_LOOPBACK);
625*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &in_addr,
626*3ba6090fSDavid van Moolenbroek 	   sizeof(in_addr)) != 0)
627*3ba6090fSDavid van Moolenbroek 		e(0);
628*3ba6090fSDavid van Moolenbroek 
629*3ba6090fSDavid van Moolenbroek 	in_addr.s_addr = htonl(INADDR_ANY);
630*3ba6090fSDavid van Moolenbroek 	len = sizeof(in_addr);
631*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &in_addr, &len) != 0)
632*3ba6090fSDavid van Moolenbroek 		e(0);
633*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(in_addr)) e(0);
634*3ba6090fSDavid van Moolenbroek 	if (in_addr.s_addr != htonl(INADDR_LOOPBACK)) e(0);
635*3ba6090fSDavid van Moolenbroek 
636*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
637*3ba6090fSDavid van Moolenbroek 
638*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, type, 0)) < 0) e(0);
639*3ba6090fSDavid van Moolenbroek 
640*3ba6090fSDavid van Moolenbroek 	val = 137;
641*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val,
642*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
643*3ba6090fSDavid van Moolenbroek 
644*3ba6090fSDavid van Moolenbroek 	val = 0;
645*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
646*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, &len) != 0)
647*3ba6090fSDavid van Moolenbroek 		e(0);
648*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
649*3ba6090fSDavid van Moolenbroek 	if (val != 137) e(0);
650*3ba6090fSDavid van Moolenbroek 
651*3ba6090fSDavid van Moolenbroek 	val = -2;
652*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val,
653*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != -1) e(0);
654*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
655*3ba6090fSDavid van Moolenbroek 
656*3ba6090fSDavid van Moolenbroek 	val = 256;
657*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val,
658*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != -1) e(0);
659*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
660*3ba6090fSDavid van Moolenbroek 
661*3ba6090fSDavid van Moolenbroek 	val = 0;
662*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
663*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, &len) != 0)
664*3ba6090fSDavid van Moolenbroek 		e(0);
665*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
666*3ba6090fSDavid van Moolenbroek 	if (val != 137) e(0);
667*3ba6090fSDavid van Moolenbroek 
668*3ba6090fSDavid van Moolenbroek 	val = -1; /* use default */
669*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val,
670*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
671*3ba6090fSDavid van Moolenbroek 
672*3ba6090fSDavid van Moolenbroek 	val = 0;
673*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
674*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, &len) != 0)
675*3ba6090fSDavid van Moolenbroek 		e(0);
676*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
677*3ba6090fSDavid van Moolenbroek 	if (val != 1) e(0);
678*3ba6090fSDavid van Moolenbroek 
679*3ba6090fSDavid van Moolenbroek 	val = 0;
680*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
681*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
682*3ba6090fSDavid van Moolenbroek 
683*3ba6090fSDavid van Moolenbroek 	val = 1;
684*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
685*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, &len) != 0)
686*3ba6090fSDavid van Moolenbroek 		e(0);
687*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
688*3ba6090fSDavid van Moolenbroek 	if (val != 0) e(0);
689*3ba6090fSDavid van Moolenbroek 
690*3ba6090fSDavid van Moolenbroek 	val = 1;
691*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
692*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
693*3ba6090fSDavid van Moolenbroek 
694*3ba6090fSDavid van Moolenbroek 	val = -1;
695*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
696*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != -1) e(0);
697*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
698*3ba6090fSDavid van Moolenbroek 
699*3ba6090fSDavid van Moolenbroek 	val = 2;
700*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
701*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != -1) e(0);
702*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
703*3ba6090fSDavid van Moolenbroek 
704*3ba6090fSDavid van Moolenbroek 	val = 0;
705*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
706*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val, &len) != 0)
707*3ba6090fSDavid van Moolenbroek 		e(0);
708*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
709*3ba6090fSDavid van Moolenbroek 	if (val != 1) e(0);
710*3ba6090fSDavid van Moolenbroek 
711*3ba6090fSDavid van Moolenbroek 	val = -1;
712*3ba6090fSDavid van Moolenbroek 	ifindex = if_nametoindex(LOOPBACK_IFNAME);
713*3ba6090fSDavid van Moolenbroek 
714*3ba6090fSDavid van Moolenbroek 	val = ifindex;
715*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val,
716*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
717*3ba6090fSDavid van Moolenbroek 
718*3ba6090fSDavid van Moolenbroek 	val = 0;
719*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
720*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val, &len) != 0)
721*3ba6090fSDavid van Moolenbroek 		e(0);
722*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
723*3ba6090fSDavid van Moolenbroek 	if (val != ifindex) e(0);
724*3ba6090fSDavid van Moolenbroek 
725*3ba6090fSDavid van Moolenbroek 	val = BAD_IFINDEX;
726*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val,
727*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != -1) e(0);
728*3ba6090fSDavid van Moolenbroek 
729*3ba6090fSDavid van Moolenbroek 	val = -1;
730*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val,
731*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != -1) e(0);
732*3ba6090fSDavid van Moolenbroek 
733*3ba6090fSDavid van Moolenbroek 	val = 0;
734*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
735*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val, &len) != 0)
736*3ba6090fSDavid van Moolenbroek 		e(0);
737*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
738*3ba6090fSDavid van Moolenbroek 	if (val != ifindex) e(0);
739*3ba6090fSDavid van Moolenbroek 
740*3ba6090fSDavid van Moolenbroek 	val = 0;
741*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val,
742*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
743*3ba6090fSDavid van Moolenbroek 
744*3ba6090fSDavid van Moolenbroek 	val = ifindex;
745*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
746*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val, &len) != 0)
747*3ba6090fSDavid van Moolenbroek 		e(0);
748*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
749*3ba6090fSDavid van Moolenbroek 	if (val != 0) e(0);
750*3ba6090fSDavid van Moolenbroek 
751*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
752*3ba6090fSDavid van Moolenbroek }
753*3ba6090fSDavid van Moolenbroek 
754*3ba6090fSDavid van Moolenbroek /*
755baa5830fSDavid van Moolenbroek  * Test for large sends and receives on stream sockets with MSG_WAITALL.
756baa5830fSDavid van Moolenbroek  */
757baa5830fSDavid van Moolenbroek void
socklib_large_transfers(int fd[2])758baa5830fSDavid van Moolenbroek socklib_large_transfers(int fd[2])
759baa5830fSDavid van Moolenbroek {
760baa5830fSDavid van Moolenbroek 	char *buf;
761baa5830fSDavid van Moolenbroek 	pid_t pid;
762baa5830fSDavid van Moolenbroek 	int i, status;
763baa5830fSDavid van Moolenbroek 
764baa5830fSDavid van Moolenbroek #define LARGE_BUF	(4096*1024)
765baa5830fSDavid van Moolenbroek 
766baa5830fSDavid van Moolenbroek 	if ((buf = malloc(LARGE_BUF)) == NULL) e(0);
767baa5830fSDavid van Moolenbroek 	memset(buf, 0, LARGE_BUF);
768baa5830fSDavid van Moolenbroek 
769baa5830fSDavid van Moolenbroek 	pid = fork();
770baa5830fSDavid van Moolenbroek 	switch (pid) {
771baa5830fSDavid van Moolenbroek 	case 0:
772baa5830fSDavid van Moolenbroek 		errct = 0;
773baa5830fSDavid van Moolenbroek 
774baa5830fSDavid van Moolenbroek 		if (close(fd[0]) != 0) e(0);
775baa5830fSDavid van Moolenbroek 
776baa5830fSDavid van Moolenbroek 		/* Part 1. */
777baa5830fSDavid van Moolenbroek 		if (recv(fd[1], buf, LARGE_BUF, MSG_WAITALL) != LARGE_BUF)
778baa5830fSDavid van Moolenbroek 			e(0);
779baa5830fSDavid van Moolenbroek 
780baa5830fSDavid van Moolenbroek 		for (i = 0; i < LARGE_BUF; i++)
781baa5830fSDavid van Moolenbroek 			if (buf[i] != (char)(i + (i >> 16))) e(0);
782baa5830fSDavid van Moolenbroek 
783baa5830fSDavid van Moolenbroek 		if (recv(fd[1], buf, LARGE_BUF,
784baa5830fSDavid van Moolenbroek 		    MSG_DONTWAIT | MSG_WAITALL) != -1) e(0);
785baa5830fSDavid van Moolenbroek 		if (errno != EWOULDBLOCK) e(0);
786baa5830fSDavid van Moolenbroek 
787baa5830fSDavid van Moolenbroek 		/* Part 2. */
788baa5830fSDavid van Moolenbroek 		if (send(fd[1], buf, LARGE_BUF / 2, 0) != LARGE_BUF / 2) e(0);
789baa5830fSDavid van Moolenbroek 
790baa5830fSDavid van Moolenbroek 		if (shutdown(fd[1], SHUT_WR) != 0) e(0);
791baa5830fSDavid van Moolenbroek 
792baa5830fSDavid van Moolenbroek 		/* Part 3. */
793baa5830fSDavid van Moolenbroek 		memset(buf, 'y', LARGE_BUF);
794baa5830fSDavid van Moolenbroek 
795baa5830fSDavid van Moolenbroek 		if (recv(fd[1], buf, LARGE_BUF, MSG_WAITALL) != LARGE_BUF - 1)
796baa5830fSDavid van Moolenbroek 			e(0);
797baa5830fSDavid van Moolenbroek 
798baa5830fSDavid van Moolenbroek 		for (i = 0; i < LARGE_BUF - 1; i++)
799baa5830fSDavid van Moolenbroek 			if (buf[i] != (char)(i + (i >> 16))) e(0);
800baa5830fSDavid van Moolenbroek 		if (buf[LARGE_BUF - 1] != 'y') e(0);
801baa5830fSDavid van Moolenbroek 
802baa5830fSDavid van Moolenbroek 		if (recv(fd[1], buf, LARGE_BUF, MSG_WAITALL) != 0) e(0);
803baa5830fSDavid van Moolenbroek 
804baa5830fSDavid van Moolenbroek 		exit(errct);
805baa5830fSDavid van Moolenbroek 	case -1:
806baa5830fSDavid van Moolenbroek 		e(0);
807baa5830fSDavid van Moolenbroek 	}
808baa5830fSDavid van Moolenbroek 
809baa5830fSDavid van Moolenbroek 	if (close(fd[1]) != 0) e(0);
810baa5830fSDavid van Moolenbroek 
811baa5830fSDavid van Moolenbroek 	/* Part 1: check that a large send fully arrives. */
812baa5830fSDavid van Moolenbroek 	for (i = 0; i < LARGE_BUF; i++)
813baa5830fSDavid van Moolenbroek 		buf[i] = (char)(i + (i >> 16));
814baa5830fSDavid van Moolenbroek 
815baa5830fSDavid van Moolenbroek 	if (send(fd[0], buf, LARGE_BUF, 0) != LARGE_BUF) e(0);
816baa5830fSDavid van Moolenbroek 
817baa5830fSDavid van Moolenbroek 	/* Part 2: check that remote shutdown terminates a partial receive. */
818baa5830fSDavid van Moolenbroek 	memset(buf, 'x', LARGE_BUF);
819baa5830fSDavid van Moolenbroek 
820baa5830fSDavid van Moolenbroek 	if (recv(fd[0], buf, LARGE_BUF, MSG_WAITALL) != LARGE_BUF / 2) e(0);
821baa5830fSDavid van Moolenbroek 
822baa5830fSDavid van Moolenbroek 	for (i = 0; i < LARGE_BUF / 2; i++)
823baa5830fSDavid van Moolenbroek 		if (buf[i] != (char)(i + (i >> 16))) e(0);
824baa5830fSDavid van Moolenbroek 	for (; i < LARGE_BUF; i++)
825baa5830fSDavid van Moolenbroek 		if (buf[i] != 'x') e(0);
826baa5830fSDavid van Moolenbroek 
827baa5830fSDavid van Moolenbroek 	if (recv(fd[0], buf, LARGE_BUF, MSG_WAITALL) != 0) e(0);
828baa5830fSDavid van Moolenbroek 
829baa5830fSDavid van Moolenbroek 	/* Part 3: check that remote close terminates a partial receive. */
830baa5830fSDavid van Moolenbroek 	for (i = 0; i < LARGE_BUF; i++)
831baa5830fSDavid van Moolenbroek 		buf[i] = (char)(i + (i >> 16));
832baa5830fSDavid van Moolenbroek 
833baa5830fSDavid van Moolenbroek 	if (send(fd[0], buf, LARGE_BUF - 1, 0) != LARGE_BUF - 1) e(0);
834baa5830fSDavid van Moolenbroek 
835baa5830fSDavid van Moolenbroek 	if (close(fd[0]) != 0) e(0);
836baa5830fSDavid van Moolenbroek 
837baa5830fSDavid van Moolenbroek 	if (waitpid(pid, &status, 0) != pid) e(0);
838baa5830fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
839baa5830fSDavid van Moolenbroek 
840baa5830fSDavid van Moolenbroek 	free(buf);
841baa5830fSDavid van Moolenbroek }
842baa5830fSDavid van Moolenbroek 
843baa5830fSDavid van Moolenbroek #define PRINT_STATS	0
844baa5830fSDavid van Moolenbroek 
845baa5830fSDavid van Moolenbroek /*
846baa5830fSDavid van Moolenbroek  * A randomized producer-consumer test for stream sockets.  As part of this,
847baa5830fSDavid van Moolenbroek  * we also perform very basic bulk functionality tests of FIONREAD, MSG_PEEK,
848baa5830fSDavid van Moolenbroek  * MSG_DONTWAIT, and MSG_WAITALL.
849baa5830fSDavid van Moolenbroek  */
850baa5830fSDavid van Moolenbroek void
socklib_producer_consumer(int fd[2])851baa5830fSDavid van Moolenbroek socklib_producer_consumer(int fd[2])
852baa5830fSDavid van Moolenbroek {
853baa5830fSDavid van Moolenbroek 	char *buf;
854baa5830fSDavid van Moolenbroek 	time_t t;
855baa5830fSDavid van Moolenbroek 	socklen_t len, size, off;
856baa5830fSDavid van Moolenbroek 	ssize_t r;
857baa5830fSDavid van Moolenbroek 	pid_t pid;
858baa5830fSDavid van Moolenbroek 	int i, rcvlen, status, exp, flags, num, stat[3] = { 0, 0, 0 };
859baa5830fSDavid van Moolenbroek 
860baa5830fSDavid van Moolenbroek 	len = sizeof(rcvlen);
861baa5830fSDavid van Moolenbroek 	if (getsockopt(fd[0], SOL_SOCKET, SO_RCVBUF, &rcvlen, &len) != 0) e(0);
862baa5830fSDavid van Moolenbroek 	if (len != sizeof(rcvlen)) e(0);
863baa5830fSDavid van Moolenbroek 
864baa5830fSDavid van Moolenbroek 	size = rcvlen * 3;
865baa5830fSDavid van Moolenbroek 
866baa5830fSDavid van Moolenbroek 	if ((buf = malloc(size)) == NULL) e(0);
867baa5830fSDavid van Moolenbroek 
868baa5830fSDavid van Moolenbroek 	t = time(NULL);
869baa5830fSDavid van Moolenbroek 
870baa5830fSDavid van Moolenbroek 	/*
871baa5830fSDavid van Moolenbroek 	 * We vary small versus large (random) send and receive sizes,
872baa5830fSDavid van Moolenbroek 	 * splitting the entire transfer in four phases along those lines.
873baa5830fSDavid van Moolenbroek 	 *
874baa5830fSDavid van Moolenbroek 	 * In theory, the use of an extra system call, the use of MSG_PEEK, and
875baa5830fSDavid van Moolenbroek 	 * the fact that without MSG_WAITALL a receive call may return any
876baa5830fSDavid van Moolenbroek 	 * partial result, all contribute to the expectation that the consumer
877baa5830fSDavid van Moolenbroek 	 * side will fall behind the producer.  In order to test both filling
878baa5830fSDavid van Moolenbroek 	 * and draining the receive queue, we use a somewhat larger small
879baa5830fSDavid van Moolenbroek 	 * receive size for the consumer size (up to 256 bytes rather than 64)
880baa5830fSDavid van Moolenbroek 	 * during each half of the four phases.  The effectiveness of these
881baa5830fSDavid van Moolenbroek 	 * numbers can be verified with statistics (disabled by default).
882baa5830fSDavid van Moolenbroek 	 */
883baa5830fSDavid van Moolenbroek #define TRANSFER_SIZE	(16 * 1024 * 1024)
884baa5830fSDavid van Moolenbroek 
885baa5830fSDavid van Moolenbroek 	pid = fork();
886baa5830fSDavid van Moolenbroek 	switch (pid) {
887baa5830fSDavid van Moolenbroek 	case 0:
888baa5830fSDavid van Moolenbroek 		errct = 0;
889baa5830fSDavid van Moolenbroek 
890baa5830fSDavid van Moolenbroek 		if (close(fd[0]) != 0) e(0);
891baa5830fSDavid van Moolenbroek 
892baa5830fSDavid van Moolenbroek 		srand48(t + 1);
893baa5830fSDavid van Moolenbroek 
894baa5830fSDavid van Moolenbroek 		for (off = 0; off < TRANSFER_SIZE; ) {
895baa5830fSDavid van Moolenbroek 			if (off < TRANSFER_SIZE / 2)
896baa5830fSDavid van Moolenbroek 				len = lrand48() %
897baa5830fSDavid van Moolenbroek 				    ((off / (TRANSFER_SIZE / 8) % 2) ? 64 :
898baa5830fSDavid van Moolenbroek 				    256);
899baa5830fSDavid van Moolenbroek 			else
900baa5830fSDavid van Moolenbroek 				len = lrand48() % size;
901baa5830fSDavid van Moolenbroek 
902baa5830fSDavid van Moolenbroek 			num = lrand48() % 16;
903baa5830fSDavid van Moolenbroek 			flags = 0;
904baa5830fSDavid van Moolenbroek 			if (num & 1) flags |= MSG_PEEK;
905baa5830fSDavid van Moolenbroek 			if (num & 2) flags |= MSG_WAITALL;
906baa5830fSDavid van Moolenbroek 			if (num & 4) flags |= MSG_DONTWAIT;
907baa5830fSDavid van Moolenbroek 			if (num & 8) {
908baa5830fSDavid van Moolenbroek 				/*
909baa5830fSDavid van Moolenbroek 				 * Obviously there are race conditions here but
910baa5830fSDavid van Moolenbroek 				 * the returned number should be a lower bound.
911baa5830fSDavid van Moolenbroek 				 */
912baa5830fSDavid van Moolenbroek 				if (ioctl(fd[1], FIONREAD, &exp) != 0) e(0);
913baa5830fSDavid van Moolenbroek 				if (exp < 0 || exp > rcvlen) e(0);
914baa5830fSDavid van Moolenbroek 			} else
915baa5830fSDavid van Moolenbroek 				exp = -1;
916baa5830fSDavid van Moolenbroek 
917baa5830fSDavid van Moolenbroek 			stat[0]++;
918baa5830fSDavid van Moolenbroek 
919baa5830fSDavid van Moolenbroek 			if ((r = recv(fd[1], buf, len, flags)) == -1) {
920baa5830fSDavid van Moolenbroek 				if (errno != EWOULDBLOCK) e(0);
921baa5830fSDavid van Moolenbroek 				if (exp > 0) e(0);
922baa5830fSDavid van Moolenbroek 
923baa5830fSDavid van Moolenbroek 				stat[2]++;
924baa5830fSDavid van Moolenbroek 				continue;
925baa5830fSDavid van Moolenbroek 			}
926baa5830fSDavid van Moolenbroek 
927baa5830fSDavid van Moolenbroek 			if (r < len) {
928baa5830fSDavid van Moolenbroek 				stat[1]++;
929baa5830fSDavid van Moolenbroek 
930baa5830fSDavid van Moolenbroek 				if (exp > r) e(0);
931baa5830fSDavid van Moolenbroek 			}
932baa5830fSDavid van Moolenbroek 
933baa5830fSDavid van Moolenbroek 			for (i = 0; i < r; i++)
934baa5830fSDavid van Moolenbroek 				if (buf[i] != (char)((off + i) +
935baa5830fSDavid van Moolenbroek 				    ((off + i) >> 16))) e(0);
936baa5830fSDavid van Moolenbroek 
937baa5830fSDavid van Moolenbroek 			if (!(flags & MSG_PEEK)) {
938baa5830fSDavid van Moolenbroek 				off += r;
939baa5830fSDavid van Moolenbroek 
940baa5830fSDavid van Moolenbroek 				if ((flags & (MSG_DONTWAIT | MSG_WAITALL)) ==
941baa5830fSDavid van Moolenbroek 				    MSG_WAITALL && r != len &&
942baa5830fSDavid van Moolenbroek 				    off < TRANSFER_SIZE) e(0);
943baa5830fSDavid van Moolenbroek 			}
944baa5830fSDavid van Moolenbroek 		}
945baa5830fSDavid van Moolenbroek 
946baa5830fSDavid van Moolenbroek #if PRINT_STATS
947baa5830fSDavid van Moolenbroek 		/*
948baa5830fSDavid van Moolenbroek 		 * The second and third numbers should ideally be a large but
949baa5830fSDavid van Moolenbroek 		 * non-dominating fraction of the first one.
950baa5830fSDavid van Moolenbroek 		 */
951baa5830fSDavid van Moolenbroek 		printf("RECV: total %d short %d again %d\n",
952baa5830fSDavid van Moolenbroek 		    stat[0], stat[1], stat[2]);
953baa5830fSDavid van Moolenbroek #endif
954baa5830fSDavid van Moolenbroek 
955baa5830fSDavid van Moolenbroek 		if (close(fd[1]) != 0) e(0);
956baa5830fSDavid van Moolenbroek 		exit(errct);
957baa5830fSDavid van Moolenbroek 	case -1:
958baa5830fSDavid van Moolenbroek 		e(0);
959baa5830fSDavid van Moolenbroek 	}
960baa5830fSDavid van Moolenbroek 
961baa5830fSDavid van Moolenbroek 	if (close(fd[1]) != 0) e(0);
962baa5830fSDavid van Moolenbroek 
963baa5830fSDavid van Moolenbroek 	srand48(t);
964baa5830fSDavid van Moolenbroek 
965baa5830fSDavid van Moolenbroek 	for (off = 0; off < TRANSFER_SIZE; ) {
966baa5830fSDavid van Moolenbroek 		if (off < TRANSFER_SIZE / 4 ||
967baa5830fSDavid van Moolenbroek 		    (off >= TRANSFER_SIZE / 2 && off < TRANSFER_SIZE * 3 / 4))
968baa5830fSDavid van Moolenbroek 			len = lrand48() % 64;
969baa5830fSDavid van Moolenbroek 		else
970baa5830fSDavid van Moolenbroek 			len = lrand48() % size;
971baa5830fSDavid van Moolenbroek 
972baa5830fSDavid van Moolenbroek 		if (len > TRANSFER_SIZE - off)
973baa5830fSDavid van Moolenbroek 			len = TRANSFER_SIZE - off;
974baa5830fSDavid van Moolenbroek 
975baa5830fSDavid van Moolenbroek 		for (i = 0; i < len; i++)
976baa5830fSDavid van Moolenbroek 			buf[i] = (off + i) + ((off + i) >> 16);
977baa5830fSDavid van Moolenbroek 
978baa5830fSDavid van Moolenbroek 		flags = (lrand48() % 2) ? MSG_DONTWAIT : 0;
979baa5830fSDavid van Moolenbroek 
980baa5830fSDavid van Moolenbroek 		stat[0]++;
981baa5830fSDavid van Moolenbroek 
982baa5830fSDavid van Moolenbroek 		r = send(fd[0], buf, len, flags);
983baa5830fSDavid van Moolenbroek 
984baa5830fSDavid van Moolenbroek 		if (r != len) {
985baa5830fSDavid van Moolenbroek 			if (r > (ssize_t)len) e(0);
986baa5830fSDavid van Moolenbroek 			if (!(flags & MSG_DONTWAIT)) e(0);
987baa5830fSDavid van Moolenbroek 			if (r == -1) {
988baa5830fSDavid van Moolenbroek 				if (errno != EWOULDBLOCK) e(0);
989baa5830fSDavid van Moolenbroek 				r = 0;
990baa5830fSDavid van Moolenbroek 
991baa5830fSDavid van Moolenbroek 				stat[2]++;
992baa5830fSDavid van Moolenbroek 			} else
993baa5830fSDavid van Moolenbroek 				stat[1]++;
994baa5830fSDavid van Moolenbroek 		}
995baa5830fSDavid van Moolenbroek 
996baa5830fSDavid van Moolenbroek 		if (off / (TRANSFER_SIZE / 4) !=
997baa5830fSDavid van Moolenbroek 		    (off + r) / (TRANSFER_SIZE / 4))
998baa5830fSDavid van Moolenbroek 			sleep(1);
999baa5830fSDavid van Moolenbroek 
1000baa5830fSDavid van Moolenbroek 		off += r;
1001baa5830fSDavid van Moolenbroek 	}
1002baa5830fSDavid van Moolenbroek 
1003baa5830fSDavid van Moolenbroek #if PRINT_STATS
1004baa5830fSDavid van Moolenbroek 	/*
1005baa5830fSDavid van Moolenbroek 	 * The second and third numbers should ideally be a large but non-
1006baa5830fSDavid van Moolenbroek 	 * dominating fraction of the first one.
1007baa5830fSDavid van Moolenbroek 	 */
1008baa5830fSDavid van Moolenbroek 	printf("SEND: total %d short %d again %d\n",
1009baa5830fSDavid van Moolenbroek 	    stat[0], stat[1], stat[2]);
1010baa5830fSDavid van Moolenbroek #endif
1011baa5830fSDavid van Moolenbroek 
1012baa5830fSDavid van Moolenbroek 	free(buf);
1013baa5830fSDavid van Moolenbroek 
1014baa5830fSDavid van Moolenbroek 	if (close(fd[0]) != 0) e(0);
1015baa5830fSDavid van Moolenbroek 
1016baa5830fSDavid van Moolenbroek 	if (waitpid(pid, &status, 0) != pid) e(0);
1017baa5830fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
1018baa5830fSDavid van Moolenbroek }
1019baa5830fSDavid van Moolenbroek 
1020baa5830fSDavid van Moolenbroek /*
1021baa5830fSDavid van Moolenbroek  * Signal handler which just needs to exist, so that invoking it will interrupt
1022baa5830fSDavid van Moolenbroek  * an ongoing system call.
1023baa5830fSDavid van Moolenbroek  */
1024baa5830fSDavid van Moolenbroek static void
socklib_got_signal(int sig __unused)1025baa5830fSDavid van Moolenbroek socklib_got_signal(int sig __unused)
1026baa5830fSDavid van Moolenbroek {
1027baa5830fSDavid van Moolenbroek 
1028baa5830fSDavid van Moolenbroek 	/* Nothing. */
1029baa5830fSDavid van Moolenbroek }
1030baa5830fSDavid van Moolenbroek 
1031baa5830fSDavid van Moolenbroek /*
1032baa5830fSDavid van Moolenbroek  * Test for receiving on stream sockets.  The quick summary here is that
1033baa5830fSDavid van Moolenbroek  * recv(MSG_WAITALL) should keep suspending until as many bytes as requested
1034baa5830fSDavid van Moolenbroek  * are also received (or the call is interrupted, or no more can possibly be
1035baa5830fSDavid van Moolenbroek  * received - the meaning of the latter depends on the domain), and,
1036baa5830fSDavid van Moolenbroek  * SO_RCVLOWAT acts as an admission test for the receive: nothing is received
1037baa5830fSDavid van Moolenbroek  * until there are at least as many bytes are available in the receive buffer
1038baa5830fSDavid van Moolenbroek  * as the low receive watermark, or the whole receive request length, whichever
1039baa5830fSDavid van Moolenbroek  * is smaller. In addition, select(2) should use the same threshold.
1040baa5830fSDavid van Moolenbroek  */
1041baa5830fSDavid van Moolenbroek #define MAX_BYTES	2	/* set to 3 for slightly better(?) testing */
1042baa5830fSDavid van Moolenbroek #define USLEEP_TIME	250000	/* increase on wimpy platforms if needed */
1043baa5830fSDavid van Moolenbroek 
1044baa5830fSDavid van Moolenbroek static void
socklib_stream_recv_sub(int (* socket_pair)(int,int,int,int *),int domain,int type,int idata,int istate,int rlowat,int len,int bits,int act,int (* break_recv)(int,const char *,size_t))1045baa5830fSDavid van Moolenbroek socklib_stream_recv_sub(int (* socket_pair)(int, int, int, int *), int domain,
1046baa5830fSDavid van Moolenbroek 	int type, int idata, int istate, int rlowat, int len, int bits,
1047baa5830fSDavid van Moolenbroek 	int act, int (* break_recv)(int, const char *, size_t))
1048baa5830fSDavid van Moolenbroek {
1049baa5830fSDavid van Moolenbroek 	const char *data = "ABCDE";	/* this limits MAX_BYTES to 3 */
1050baa5830fSDavid van Moolenbroek 	struct sigaction sa;
1051baa5830fSDavid van Moolenbroek 	struct timeval tv;
1052baa5830fSDavid van Moolenbroek 	fd_set fds;
1053baa5830fSDavid van Moolenbroek 	char buf[3];
1054baa5830fSDavid van Moolenbroek 	pid_t pid;
1055baa5830fSDavid van Moolenbroek 	int fd[2], val, flags, min, res, err;
1056baa5830fSDavid van Moolenbroek 	int pfd[2], edata, tstate, fl, status;
1057baa5830fSDavid van Moolenbroek 
1058baa5830fSDavid van Moolenbroek 	if (socket_pair(domain, type, 0, fd) != 0) e(0);
1059baa5830fSDavid van Moolenbroek 
1060baa5830fSDavid van Moolenbroek 	/*
1061baa5830fSDavid van Moolenbroek 	 * Set up the initial condition on the sockets.
1062baa5830fSDavid van Moolenbroek 	 */
1063baa5830fSDavid van Moolenbroek 	if (idata > 0)
1064baa5830fSDavid van Moolenbroek 		if (send(fd[1], data, idata, 0) != idata) e(0);
1065baa5830fSDavid van Moolenbroek 
1066baa5830fSDavid van Moolenbroek 	switch (istate) {
1067baa5830fSDavid van Moolenbroek 	case 0: break;
1068baa5830fSDavid van Moolenbroek 	case 1: if (shutdown(fd[0], SHUT_RD) != 0) e(0); break;
1069baa5830fSDavid van Moolenbroek 	case 2: if (shutdown(fd[1], SHUT_WR) != 0) e(0); break;
1070baa5830fSDavid van Moolenbroek 	case 3: if (close(fd[1]) != 0) e(0); break;
1071baa5830fSDavid van Moolenbroek 	}
1072baa5830fSDavid van Moolenbroek 
1073baa5830fSDavid van Moolenbroek 	/* Set the low receive water mark. */
1074baa5830fSDavid van Moolenbroek 	if (setsockopt(fd[0], SOL_SOCKET, SO_RCVLOWAT, &rlowat,
1075baa5830fSDavid van Moolenbroek 	    sizeof(rlowat)) != 0) e(0);
1076baa5830fSDavid van Moolenbroek 
1077baa5830fSDavid van Moolenbroek 	/* SO_RCVLOWAT is always bounded by the actual receive length. */
1078baa5830fSDavid van Moolenbroek 	min = MIN(len, rlowat);
1079baa5830fSDavid van Moolenbroek 
1080baa5830fSDavid van Moolenbroek 	/*
1081baa5830fSDavid van Moolenbroek 	 * Do a quick select test to see if its result indeed matches whether
1082baa5830fSDavid van Moolenbroek 	 * the available data in the receive buffer meets the threshold.
1083baa5830fSDavid van Moolenbroek 	 */
1084baa5830fSDavid van Moolenbroek 	FD_ZERO(&fds);
1085baa5830fSDavid van Moolenbroek 	FD_SET(fd[0], &fds);
1086baa5830fSDavid van Moolenbroek 	tv.tv_sec = 0;
1087baa5830fSDavid van Moolenbroek 	tv.tv_usec = 0;
1088baa5830fSDavid van Moolenbroek 	res = select(fd[0] + 1, &fds, NULL, NULL, &tv);
1089baa5830fSDavid van Moolenbroek 	if (res < 0 || res > 1) e(0);
1090baa5830fSDavid van Moolenbroek 	if (res != (idata >= rlowat || istate > 0)) e(0);
1091baa5830fSDavid van Moolenbroek 	if (res == 1 && !FD_ISSET(fd[0], &fds)) e(0);
1092baa5830fSDavid van Moolenbroek 
1093baa5830fSDavid van Moolenbroek 	/* Also do a quick test for ioctl(FIONREAD). */
1094baa5830fSDavid van Moolenbroek 	if (ioctl(fd[0], FIONREAD, &val) != 0) e(0);
1095baa5830fSDavid van Moolenbroek 	if (val != ((istate != 1) ? idata : 0)) e(0);
1096baa5830fSDavid van Moolenbroek 
1097baa5830fSDavid van Moolenbroek 	/* Translate the given bits to receive call flags. */
1098baa5830fSDavid van Moolenbroek 	flags = 0;
1099baa5830fSDavid van Moolenbroek 	if (bits & 1) flags |= MSG_PEEK;
1100baa5830fSDavid van Moolenbroek 	if (bits & 2) flags |= MSG_DONTWAIT;
1101baa5830fSDavid van Moolenbroek 	if (bits & 4) flags |= MSG_WAITALL;
1102baa5830fSDavid van Moolenbroek 
1103baa5830fSDavid van Moolenbroek 	/*
1104baa5830fSDavid van Moolenbroek 	 * Cut short a whole lot of cases, to avoid the overhead of forking,
1105baa5830fSDavid van Moolenbroek 	 * namely when we know the call should return immediately.  This is
1106baa5830fSDavid van Moolenbroek 	 * the case when MSG_DONTWAIT is set, or if a termination condition has
1107baa5830fSDavid van Moolenbroek 	 * been raised, or if enough initial data are available to meet the
1108baa5830fSDavid van Moolenbroek 	 * conditions for the receive call.
1109baa5830fSDavid van Moolenbroek 	 */
1110baa5830fSDavid van Moolenbroek 	if ((flags & MSG_DONTWAIT) || istate > 0 || (idata >= min &&
1111baa5830fSDavid van Moolenbroek 	    ((flags & (MSG_PEEK | MSG_WAITALL)) != MSG_WAITALL ||
1112baa5830fSDavid van Moolenbroek 	    idata >= len))) {
1113baa5830fSDavid van Moolenbroek 		res = recv(fd[0], buf, len, flags);
1114baa5830fSDavid van Moolenbroek 
1115baa5830fSDavid van Moolenbroek 		if (res == -1 && errno != EWOULDBLOCK) e(0);
1116baa5830fSDavid van Moolenbroek 
1117baa5830fSDavid van Moolenbroek 		/*
1118baa5830fSDavid van Moolenbroek 		 * If the socket has been shutdown locally, we will never get
1119baa5830fSDavid van Moolenbroek 		 * anything but zero.  Otherwise, if we meet the SO_RCVLOWAT
1120baa5830fSDavid van Moolenbroek 		 * test, we should have received as much as was available and
1121baa5830fSDavid van Moolenbroek 		 * requested.  Otherwise, if the remote end has been shut down
1122baa5830fSDavid van Moolenbroek 		 * or closed, we expected to get any available data or
1123baa5830fSDavid van Moolenbroek 		 * otherwise EOF (implied with idata==0).  If none of these
1124baa5830fSDavid van Moolenbroek 		 * cases apply, we should have gotten EWOULDBLOCK.
1125baa5830fSDavid van Moolenbroek 		 */
1126baa5830fSDavid van Moolenbroek 		if (istate == 1) {
1127baa5830fSDavid van Moolenbroek 			if (res != 0) e(0);
1128baa5830fSDavid van Moolenbroek 		} else if (idata >= min) {
1129baa5830fSDavid van Moolenbroek 			if (res != MIN(len, idata)) e(0);
1130baa5830fSDavid van Moolenbroek 			if (strncmp(buf, data, res)) e(0);
1131baa5830fSDavid van Moolenbroek 		} else if (istate > 0) {
1132baa5830fSDavid van Moolenbroek 			if (res != idata) e(0);
1133baa5830fSDavid van Moolenbroek 			if (strncmp(buf, data, res)) e(0);
1134baa5830fSDavid van Moolenbroek 		} else
1135baa5830fSDavid van Moolenbroek 			if (res != -1) e(0);
1136baa5830fSDavid van Moolenbroek 
1137baa5830fSDavid van Moolenbroek 		/* Early cleanup and return to avoid even more code clutter. */
1138baa5830fSDavid van Moolenbroek 		if (istate != 3 && close(fd[1]) != 0) e(0);
1139baa5830fSDavid van Moolenbroek 		if (close(fd[0]) != 0) e(0);
1140baa5830fSDavid van Moolenbroek 
1141baa5830fSDavid van Moolenbroek 		return;
1142baa5830fSDavid van Moolenbroek 	}
1143baa5830fSDavid van Moolenbroek 
1144baa5830fSDavid van Moolenbroek 	/*
1145baa5830fSDavid van Moolenbroek 	 * Now starts the interesting stuff: the receive call should now block,
1146baa5830fSDavid van Moolenbroek 	 * even though if we add MSG_DONTWAIT it may not return EWOULDBLOCK,
1147baa5830fSDavid van Moolenbroek 	 * because MSG_DONTWAIT overrides MSG_WAITALL.  As such, we can only
1148baa5830fSDavid van Moolenbroek 	 * test our expectations by actually letting the call block, in a child
1149baa5830fSDavid van Moolenbroek 	 * process, and waiting.  We do test as much of the above assumption as
1150baa5830fSDavid van Moolenbroek 	 * we can just for safety right here, but this is not a substitute for
1151baa5830fSDavid van Moolenbroek 	 * actually blocking even in these cases!
1152baa5830fSDavid van Moolenbroek 	 */
1153baa5830fSDavid van Moolenbroek 	if (!(flags & MSG_WAITALL)) {
1154baa5830fSDavid van Moolenbroek 		if (recv(fd[0], buf, len, flags | MSG_DONTWAIT) != -1) e(0);
1155baa5830fSDavid van Moolenbroek 		if (errno != EWOULDBLOCK) e(0);
1156baa5830fSDavid van Moolenbroek 	}
1157baa5830fSDavid van Moolenbroek 
1158baa5830fSDavid van Moolenbroek 	/*
1159baa5830fSDavid van Moolenbroek 	 * If (act < 12), we send 0, 1, or 2 extra data bytes before forcing
1160baa5830fSDavid van Moolenbroek 	 * the receive call to terminate in one of four ways.
1161baa5830fSDavid van Moolenbroek 	 *
1162baa5830fSDavid van Moolenbroek 	 * If (act == 12), we use a signal to interrupt the receive call.
1163baa5830fSDavid van Moolenbroek 	 */
1164baa5830fSDavid van Moolenbroek 	if (act < 12) {
1165baa5830fSDavid van Moolenbroek 		edata = act % 3;
1166baa5830fSDavid van Moolenbroek 		tstate = act / 3;
1167baa5830fSDavid van Moolenbroek 	} else
1168baa5830fSDavid van Moolenbroek 		edata = tstate = 0;
1169baa5830fSDavid van Moolenbroek 
1170baa5830fSDavid van Moolenbroek 	if (pipe2(pfd, O_NONBLOCK) != 0) e(0);
1171baa5830fSDavid van Moolenbroek 
1172baa5830fSDavid van Moolenbroek 	pid = fork();
1173baa5830fSDavid van Moolenbroek 	switch (pid) {
1174baa5830fSDavid van Moolenbroek 	case 0:
1175baa5830fSDavid van Moolenbroek 		errct = 0;
1176baa5830fSDavid van Moolenbroek 
1177baa5830fSDavid van Moolenbroek 		if (close(fd[1]) != 0) e(0);
1178baa5830fSDavid van Moolenbroek 		if (close(pfd[0]) != 0) e(0);
1179baa5830fSDavid van Moolenbroek 
1180baa5830fSDavid van Moolenbroek 		if (act == 12) {
1181baa5830fSDavid van Moolenbroek 			memset(&sa, 0, sizeof(sa));
1182baa5830fSDavid van Moolenbroek 			sa.sa_handler = socklib_got_signal;
1183baa5830fSDavid van Moolenbroek 			if (sigaction(SIGUSR1, &sa, NULL) != 0) e(0);
1184baa5830fSDavid van Moolenbroek 		}
1185baa5830fSDavid van Moolenbroek 
1186baa5830fSDavid van Moolenbroek 		res = recv(fd[0], buf, len, flags);
1187baa5830fSDavid van Moolenbroek 		err = errno;
1188baa5830fSDavid van Moolenbroek 
1189baa5830fSDavid van Moolenbroek 		if (write(pfd[1], &res, sizeof(res)) != sizeof(res)) e(0);
1190baa5830fSDavid van Moolenbroek 		if (write(pfd[1], &err, sizeof(err)) != sizeof(err)) e(0);
1191baa5830fSDavid van Moolenbroek 
1192baa5830fSDavid van Moolenbroek 		if (res > 0 && strncmp(buf, data, res)) e(0);
1193baa5830fSDavid van Moolenbroek 
1194baa5830fSDavid van Moolenbroek 		exit(errct);
1195baa5830fSDavid van Moolenbroek 	case -1:
1196baa5830fSDavid van Moolenbroek 		e(0);
1197baa5830fSDavid van Moolenbroek 	}
1198baa5830fSDavid van Moolenbroek 
1199baa5830fSDavid van Moolenbroek 	if (close(pfd[1]) != 0) e(0);
1200baa5830fSDavid van Moolenbroek 
1201baa5830fSDavid van Moolenbroek 	/*
1202baa5830fSDavid van Moolenbroek 	 * Allow the child to enter the blocking recv(2), and check the pipe
1203baa5830fSDavid van Moolenbroek 	 * to see if it is really blocked.
1204baa5830fSDavid van Moolenbroek 	 */
1205baa5830fSDavid van Moolenbroek 	if (usleep(USLEEP_TIME) != 0) e(0);
1206baa5830fSDavid van Moolenbroek 
1207baa5830fSDavid van Moolenbroek 	if (read(pfd[0], buf, 1) != -1) e(0);
1208baa5830fSDavid van Moolenbroek 	if (errno != EAGAIN) e(0);
1209baa5830fSDavid van Moolenbroek 
1210baa5830fSDavid van Moolenbroek 	if (edata > 0) {
1211baa5830fSDavid van Moolenbroek 		if (send(fd[1], &data[idata], edata, 0) != edata) e(0);
1212baa5830fSDavid van Moolenbroek 
1213baa5830fSDavid van Moolenbroek 		/*
1214baa5830fSDavid van Moolenbroek 		 * The threshold for the receive is now met if both the minimum
1215baa5830fSDavid van Moolenbroek 		 * is met and MSG_WAITALL was not set (or overridden by
1216baa5830fSDavid van Moolenbroek 		 * MSG_PEEK) or the entire request has been satisfied.
1217baa5830fSDavid van Moolenbroek 		 */
1218baa5830fSDavid van Moolenbroek 		if (idata + edata >= min &&
1219baa5830fSDavid van Moolenbroek 		    ((flags & (MSG_PEEK | MSG_WAITALL)) != MSG_WAITALL ||
1220baa5830fSDavid van Moolenbroek 		    idata + edata >= len)) {
1221baa5830fSDavid van Moolenbroek 			if ((fl = fcntl(pfd[0], F_GETFL, 0)) == -1) e(0);
1222baa5830fSDavid van Moolenbroek 			if (fcntl(pfd[0], F_SETFL, fl & ~O_NONBLOCK) != 0)
1223baa5830fSDavid van Moolenbroek 			    e(0);
1224baa5830fSDavid van Moolenbroek 
1225baa5830fSDavid van Moolenbroek 			if (read(pfd[0], &res, sizeof(res)) != sizeof(res))
1226baa5830fSDavid van Moolenbroek 			    e(0);
1227baa5830fSDavid van Moolenbroek 			if (read(pfd[0], &err, sizeof(err)) != sizeof(err))
1228baa5830fSDavid van Moolenbroek 			    e(0);
1229baa5830fSDavid van Moolenbroek 
1230baa5830fSDavid van Moolenbroek 			if (res != MIN(idata + edata, len)) e(0);
1231baa5830fSDavid van Moolenbroek 
1232baa5830fSDavid van Moolenbroek 			/* Bail out. */
1233baa5830fSDavid van Moolenbroek 			goto cleanup;
1234baa5830fSDavid van Moolenbroek 		}
1235baa5830fSDavid van Moolenbroek 
1236baa5830fSDavid van Moolenbroek 		/* Sleep and test once more. */
1237baa5830fSDavid van Moolenbroek 		if (usleep(USLEEP_TIME) != 0) e(0);
1238baa5830fSDavid van Moolenbroek 
1239baa5830fSDavid van Moolenbroek 		if (read(pfd[0], buf, 1) != -1) e(0);
1240baa5830fSDavid van Moolenbroek 		if (errno != EAGAIN) e(0);
1241baa5830fSDavid van Moolenbroek 	}
1242baa5830fSDavid van Moolenbroek 
1243baa5830fSDavid van Moolenbroek 	if (act < 12) {
1244baa5830fSDavid van Moolenbroek 		/*
1245baa5830fSDavid van Moolenbroek 		 * Now test various ways to terminate the receive call.
1246baa5830fSDavid van Moolenbroek 		 */
1247baa5830fSDavid van Moolenbroek 		switch (tstate) {
1248baa5830fSDavid van Moolenbroek 		case 0: if (shutdown(fd[0], SHUT_RD) != 0) e(0); break;
1249baa5830fSDavid van Moolenbroek 		case 1: if (shutdown(fd[1], SHUT_WR) != 0) e(0); break;
1250baa5830fSDavid van Moolenbroek 		case 2: if (close(fd[1]) != 0) e(0); fd[1] = -1; break;
1251baa5830fSDavid van Moolenbroek 		case 3: fd[1] = break_recv(fd[1], data, strlen(data)); break;
1252baa5830fSDavid van Moolenbroek 		}
1253baa5830fSDavid van Moolenbroek 	} else
1254baa5830fSDavid van Moolenbroek 		if (kill(pid, SIGUSR1) != 0) e(0);
1255baa5830fSDavid van Moolenbroek 
1256baa5830fSDavid van Moolenbroek 	if ((fl = fcntl(pfd[0], F_GETFL, 0)) == -1) e(0);
1257baa5830fSDavid van Moolenbroek 	if (fcntl(pfd[0], F_SETFL, fl & ~O_NONBLOCK) != 0) e(0);
1258baa5830fSDavid van Moolenbroek 
1259baa5830fSDavid van Moolenbroek 	if (read(pfd[0], &res, sizeof(res)) != sizeof(res)) e(0);
1260baa5830fSDavid van Moolenbroek 	if (read(pfd[0], &err, sizeof(err)) != sizeof(err)) e(0);
1261baa5830fSDavid van Moolenbroek 
1262baa5830fSDavid van Moolenbroek 	if (act < 12) {
1263baa5830fSDavid van Moolenbroek 		/*
1264baa5830fSDavid van Moolenbroek 		 * If there were any data we should have received them now;
1265baa5830fSDavid van Moolenbroek 		 * after all the receive minimum stops being relevant when
1266baa5830fSDavid van Moolenbroek 		 * another condition has been raised.  There is one exception:
1267baa5830fSDavid van Moolenbroek 		 * if the receive threshold was never met and we now shut down
1268baa5830fSDavid van Moolenbroek 		 * the socket for reading, EOF is acceptable as return value.
1269baa5830fSDavid van Moolenbroek 		 */
1270baa5830fSDavid van Moolenbroek 		if (tstate == 0 && idata + edata < min) {
1271baa5830fSDavid van Moolenbroek 			if (res != 0) e(0);
1272baa5830fSDavid van Moolenbroek 		} else if (idata + edata > 0) {
1273baa5830fSDavid van Moolenbroek 			if (res != MIN(idata + edata, len)) e(0);
1274baa5830fSDavid van Moolenbroek 		} else if (tstate == 3) {
1275baa5830fSDavid van Moolenbroek 			if (fd[1] == -1) {
1276baa5830fSDavid van Moolenbroek 				if (res != -1) e(0);
1277baa5830fSDavid van Moolenbroek 				if (err != ECONNRESET) e(0);
1278baa5830fSDavid van Moolenbroek 			} else
1279baa5830fSDavid van Moolenbroek 				if (res != len) e(0);
1280baa5830fSDavid van Moolenbroek 		} else
1281baa5830fSDavid van Moolenbroek 			if (res != 0) e(0);
1282baa5830fSDavid van Moolenbroek 	} else {
1283baa5830fSDavid van Moolenbroek 		/*
1284baa5830fSDavid van Moolenbroek 		 * If the receive met the threshold before being interrupted,
1285baa5830fSDavid van Moolenbroek 		 * we should have received at least something.  Otherwise, the
1286baa5830fSDavid van Moolenbroek 		 * receive was never admitted and should just return EINTR.
1287baa5830fSDavid van Moolenbroek 		 */
1288baa5830fSDavid van Moolenbroek 		if (idata >= min) {
1289baa5830fSDavid van Moolenbroek 			if (res != MIN(idata, len)) e(0);
1290baa5830fSDavid van Moolenbroek 		} else {
1291baa5830fSDavid van Moolenbroek 			if (res != -1) e(0);
1292baa5830fSDavid van Moolenbroek 			if (err != EINTR) e(0);
1293baa5830fSDavid van Moolenbroek 		}
1294baa5830fSDavid van Moolenbroek 	}
1295baa5830fSDavid van Moolenbroek 
1296baa5830fSDavid van Moolenbroek cleanup:
1297baa5830fSDavid van Moolenbroek 	if (close(pfd[0]) != 0) e(0);
1298baa5830fSDavid van Moolenbroek 
1299baa5830fSDavid van Moolenbroek 	if (wait(&status) != pid) e(0);
1300baa5830fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
1301baa5830fSDavid van Moolenbroek 
1302baa5830fSDavid van Moolenbroek 	if (fd[1] != -1 && close(fd[1]) != 0) e(0);
1303baa5830fSDavid van Moolenbroek 	if (close(fd[0]) != 0) e(0);
1304baa5830fSDavid van Moolenbroek }
1305baa5830fSDavid van Moolenbroek 
1306baa5830fSDavid van Moolenbroek /*
1307baa5830fSDavid van Moolenbroek  * Test for receiving on stream sockets.  In particular, test SO_RCVLOWAT,
1308baa5830fSDavid van Moolenbroek  * MSG_PEEK, MSG_DONTWAIT, and MSG_WAITALL.
1309baa5830fSDavid van Moolenbroek  */
1310baa5830fSDavid van Moolenbroek void
socklib_stream_recv(int (* socket_pair)(int,int,int,int *),int domain,int type,int (* break_recv)(int,const char *,size_t))1311baa5830fSDavid van Moolenbroek socklib_stream_recv(int (* socket_pair)(int, int, int, int *), int domain,
1312baa5830fSDavid van Moolenbroek 	int type, int (* break_recv)(int, const char *, size_t))
1313baa5830fSDavid van Moolenbroek {
1314baa5830fSDavid van Moolenbroek 	int idata, istate, rlowat, len, bits, act;
1315baa5830fSDavid van Moolenbroek 
1316baa5830fSDavid van Moolenbroek 	/* Insanity. */
1317baa5830fSDavid van Moolenbroek 	for (idata = 0; idata <= MAX_BYTES; idata++)
1318baa5830fSDavid van Moolenbroek 		for (istate = 0; istate <= 3; istate++)
1319baa5830fSDavid van Moolenbroek 			for (rlowat = 1; rlowat <= MAX_BYTES; rlowat++)
1320baa5830fSDavid van Moolenbroek 				for (len = 1; len <= MAX_BYTES; len++)
1321baa5830fSDavid van Moolenbroek 					for (bits = 0; bits < 8; bits++)
1322baa5830fSDavid van Moolenbroek 						for (act = 0; act <= 12; act++)
1323baa5830fSDavid van Moolenbroek 							socklib_stream_recv_sub
1324baa5830fSDavid van Moolenbroek 							    (socket_pair,
1325baa5830fSDavid van Moolenbroek 							    domain, type,
1326baa5830fSDavid van Moolenbroek 							    idata, istate,
1327baa5830fSDavid van Moolenbroek 							    rlowat, len, bits,
1328baa5830fSDavid van Moolenbroek 							    act, break_recv);
1329baa5830fSDavid van Moolenbroek }
1330*3ba6090fSDavid van Moolenbroek 
1331*3ba6090fSDavid van Moolenbroek /*
1332*3ba6090fSDavid van Moolenbroek  * Obtain information for a matching protocol control block, using sysctl(7).
1333*3ba6090fSDavid van Moolenbroek  * The PCB is to be obtained through the given sysctl path string, and must
1334*3ba6090fSDavid van Moolenbroek  * match the other given parameters.  Return 1 if found with 'ki' filled with
1335*3ba6090fSDavid van Moolenbroek  * the PCB information, or 0 if not.
1336*3ba6090fSDavid van Moolenbroek  */
1337*3ba6090fSDavid van Moolenbroek int
socklib_find_pcb(const char * path,int protocol,uint16_t local_port,uint16_t remote_port,struct kinfo_pcb * ki)1338*3ba6090fSDavid van Moolenbroek socklib_find_pcb(const char * path, int protocol, uint16_t local_port,
1339*3ba6090fSDavid van Moolenbroek 	uint16_t remote_port, struct kinfo_pcb * ki)
1340*3ba6090fSDavid van Moolenbroek {
1341*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in sin;
1342*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in6 sin6;
1343*3ba6090fSDavid van Moolenbroek 	struct kinfo_pcb *array;
1344*3ba6090fSDavid van Moolenbroek 	size_t i, miblen, oldlen;
1345*3ba6090fSDavid van Moolenbroek 	uint16_t lport, rport;
1346*3ba6090fSDavid van Moolenbroek 	int mib[CTL_MAXNAME], found;
1347*3ba6090fSDavid van Moolenbroek 
1348*3ba6090fSDavid van Moolenbroek 	miblen = __arraycount(mib);
1349*3ba6090fSDavid van Moolenbroek 	if (sysctlnametomib(path, mib, &miblen) != 0) e(0);
1350*3ba6090fSDavid van Moolenbroek 	if (miblen > __arraycount(mib) - 4) e(0);
1351*3ba6090fSDavid van Moolenbroek 	mib[miblen++] = 0;
1352*3ba6090fSDavid van Moolenbroek 	mib[miblen++] = 0;
1353*3ba6090fSDavid van Moolenbroek 	mib[miblen++] = sizeof(*array);
1354*3ba6090fSDavid van Moolenbroek 	mib[miblen++] = 0;
1355*3ba6090fSDavid van Moolenbroek 
1356*3ba6090fSDavid van Moolenbroek 	if (sysctl(mib, miblen, NULL, &oldlen, NULL, 0) != 0) e(0);
1357*3ba6090fSDavid van Moolenbroek 	if (oldlen == 0)
1358*3ba6090fSDavid van Moolenbroek 		return 0;	/* should not happen due to added slop space */
1359*3ba6090fSDavid van Moolenbroek 	if (oldlen % sizeof(*array)) e(0);
1360*3ba6090fSDavid van Moolenbroek 
1361*3ba6090fSDavid van Moolenbroek 	if ((array = (struct kinfo_pcb *)malloc(oldlen)) == NULL) e(0);
1362*3ba6090fSDavid van Moolenbroek 
1363*3ba6090fSDavid van Moolenbroek 	if (sysctl(mib, miblen, array, &oldlen, NULL, 0) != 0) e(0);
1364*3ba6090fSDavid van Moolenbroek 	if (oldlen % sizeof(*array)) e(0);
1365*3ba6090fSDavid van Moolenbroek 
1366*3ba6090fSDavid van Moolenbroek 	found = -1;
1367*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < oldlen / sizeof(*array); i++) {
1368*3ba6090fSDavid van Moolenbroek 		/* Perform some basic checks. */
1369*3ba6090fSDavid van Moolenbroek 		if (array[i].ki_pcbaddr == 0) e(0);
1370*3ba6090fSDavid van Moolenbroek 		if (array[i].ki_ppcbaddr == 0) e(0);
1371*3ba6090fSDavid van Moolenbroek 		if (array[i].ki_family != mib[1]) e(0);
1372*3ba6090fSDavid van Moolenbroek 
1373*3ba6090fSDavid van Moolenbroek 		if (mib[1] == AF_INET6) {
1374*3ba6090fSDavid van Moolenbroek 			memcpy(&sin6, &array[i].ki_src, sizeof(sin6));
1375*3ba6090fSDavid van Moolenbroek 			if (sin6.sin6_family != AF_INET6) e(0);
1376*3ba6090fSDavid van Moolenbroek 			if (sin6.sin6_len != sizeof(sin6)) e(0);
1377*3ba6090fSDavid van Moolenbroek 			lport = ntohs(sin6.sin6_port);
1378*3ba6090fSDavid van Moolenbroek 
1379*3ba6090fSDavid van Moolenbroek 			memcpy(&sin6, &array[i].ki_dst, sizeof(sin6));
1380*3ba6090fSDavid van Moolenbroek 			if (sin6.sin6_family != AF_INET6) e(0);
1381*3ba6090fSDavid van Moolenbroek 			if (sin6.sin6_len != sizeof(sin6)) e(0);
1382*3ba6090fSDavid van Moolenbroek 			rport = ntohs(sin6.sin6_port);
1383*3ba6090fSDavid van Moolenbroek 		} else {
1384*3ba6090fSDavid van Moolenbroek 			memcpy(&sin, &array[i].ki_src, sizeof(sin));
1385*3ba6090fSDavid van Moolenbroek 			if (sin.sin_family != AF_INET) e(0);
1386*3ba6090fSDavid van Moolenbroek 			if (sin.sin_len != sizeof(sin)) e(0);
1387*3ba6090fSDavid van Moolenbroek 			lport = ntohs(sin.sin_port);
1388*3ba6090fSDavid van Moolenbroek 
1389*3ba6090fSDavid van Moolenbroek 			memcpy(&sin, &array[i].ki_dst, sizeof(sin));
1390*3ba6090fSDavid van Moolenbroek 			if (sin.sin_family != AF_UNSPEC) {
1391*3ba6090fSDavid van Moolenbroek 				if (sin.sin_family != AF_INET) e(0);
1392*3ba6090fSDavid van Moolenbroek 				if (sin.sin_len != sizeof(sin)) e(0);
1393*3ba6090fSDavid van Moolenbroek 				rport = ntohs(sin.sin_port);
1394*3ba6090fSDavid van Moolenbroek 			} else
1395*3ba6090fSDavid van Moolenbroek 				rport = 0;
1396*3ba6090fSDavid van Moolenbroek 		}
1397*3ba6090fSDavid van Moolenbroek 
1398*3ba6090fSDavid van Moolenbroek 		/* Try to match every PCB.  We must find at most one match. */
1399*3ba6090fSDavid van Moolenbroek 		if (array[i].ki_protocol == protocol && lport == local_port &&
1400*3ba6090fSDavid van Moolenbroek 		    rport == remote_port) {
1401*3ba6090fSDavid van Moolenbroek 			if (found != -1) e(0);
1402*3ba6090fSDavid van Moolenbroek 
1403*3ba6090fSDavid van Moolenbroek 			found = (int)i;
1404*3ba6090fSDavid van Moolenbroek 		}
1405*3ba6090fSDavid van Moolenbroek 	}
1406*3ba6090fSDavid van Moolenbroek 
1407*3ba6090fSDavid van Moolenbroek 	if (found >= 0)
1408*3ba6090fSDavid van Moolenbroek 		memcpy(ki, &array[found], sizeof(*ki));
1409*3ba6090fSDavid van Moolenbroek 
1410*3ba6090fSDavid van Moolenbroek 	free(array);
1411*3ba6090fSDavid van Moolenbroek 
1412*3ba6090fSDavid van Moolenbroek 	return (found != -1);
1413*3ba6090fSDavid van Moolenbroek }
1414*3ba6090fSDavid van Moolenbroek 
1415*3ba6090fSDavid van Moolenbroek #ifdef NO_INET6
1416*3ba6090fSDavid van Moolenbroek const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
1417*3ba6090fSDavid van Moolenbroek const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
1418*3ba6090fSDavid van Moolenbroek 
1419*3ba6090fSDavid van Moolenbroek void
inet6_getscopeid(struct sockaddr_in6 * sin6 __unused,int flags __unused)1420*3ba6090fSDavid van Moolenbroek inet6_getscopeid(struct sockaddr_in6 * sin6 __unused, int flags __unused)
1421*3ba6090fSDavid van Moolenbroek {
1422*3ba6090fSDavid van Moolenbroek 
1423*3ba6090fSDavid van Moolenbroek 	/*
1424*3ba6090fSDavid van Moolenbroek 	 * Nothing.  The tests linked to socklib make heavy use of IPv6, and
1425*3ba6090fSDavid van Moolenbroek 	 * are expected to fail if IPv6 support is disabled at compile time.
1426*3ba6090fSDavid van Moolenbroek 	 * Therefore, what this replacement function does is not relevant.
1427*3ba6090fSDavid van Moolenbroek 	 */
1428*3ba6090fSDavid van Moolenbroek }
1429*3ba6090fSDavid van Moolenbroek #endif /* NO_INET6 */
1430*3ba6090fSDavid van Moolenbroek 
1431*3ba6090fSDavid van Moolenbroek #define F_ANY	0x01	/* not bound, or bound to an 'any' address */
1432*3ba6090fSDavid van Moolenbroek #define F_V4	0x02	/* address is IPv4-mapped IPv6 address */
1433*3ba6090fSDavid van Moolenbroek #define F_REM	0x04	/* address is remote (not assigned to an interface) */
1434*3ba6090fSDavid van Moolenbroek #define F_MIX	0x08	/* address has non-loopback scope */
1435*3ba6090fSDavid van Moolenbroek 
1436*3ba6090fSDavid van Moolenbroek /*
1437*3ba6090fSDavid van Moolenbroek  * Test local and remote IPv6 address handling on TCP or UDP sockets.
1438*3ba6090fSDavid van Moolenbroek  */
1439*3ba6090fSDavid van Moolenbroek void
socklib_test_addrs(int type,int protocol)1440*3ba6090fSDavid van Moolenbroek socklib_test_addrs(int type, int protocol)
1441*3ba6090fSDavid van Moolenbroek {
1442*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in6 sin6, sin6_any, sin6_any_scope, sin6_lo,
1443*3ba6090fSDavid van Moolenbroek 	    sin6_lo_scope, sin6_ll_all, sin6_ll_lo, sin6_ll_rem, sin6_ll_kame,
1444*3ba6090fSDavid van Moolenbroek 	    sin6_ll_bad, sin6_ll_mix, sin6_rem, sin6_v4_any, sin6_v4_lo,
1445*3ba6090fSDavid van Moolenbroek 	    sin6_v4_rem, rsin6;
1446*3ba6090fSDavid van Moolenbroek 	const struct sockaddr_in6 *sin6p;
1447*3ba6090fSDavid van Moolenbroek 	const struct {
1448*3ba6090fSDavid van Moolenbroek 		const struct sockaddr_in6 *addr;
1449*3ba6090fSDavid van Moolenbroek 		int res;
1450*3ba6090fSDavid van Moolenbroek 		int flags;
1451*3ba6090fSDavid van Moolenbroek 		const struct sockaddr_in6 *name;
1452*3ba6090fSDavid van Moolenbroek 	} bind_array[] = {
1453*3ba6090fSDavid van Moolenbroek 		{ NULL,			0, F_ANY,	&sin6_any },
1454*3ba6090fSDavid van Moolenbroek 		{ &sin6_any,		0, F_ANY,	&sin6_any },
1455*3ba6090fSDavid van Moolenbroek 		{ &sin6_any_scope,	0, F_ANY,	&sin6_any },
1456*3ba6090fSDavid van Moolenbroek 		{ &sin6_lo,		0, 0,		&sin6_lo },
1457*3ba6090fSDavid van Moolenbroek 		{ &sin6_lo_scope,	0, 0,		&sin6_lo },
1458*3ba6090fSDavid van Moolenbroek 		{ &sin6_ll_lo,		0, 0,		&sin6_ll_lo },
1459*3ba6090fSDavid van Moolenbroek 		{ &sin6_v4_lo,		0, F_V4,	&sin6_v4_lo },
1460*3ba6090fSDavid van Moolenbroek 		{ &sin6_rem,		EADDRNOTAVAIL },
1461*3ba6090fSDavid van Moolenbroek 		{ &sin6_ll_all,		EADDRNOTAVAIL },
1462*3ba6090fSDavid van Moolenbroek 		{ &sin6_ll_rem,		EADDRNOTAVAIL },
1463*3ba6090fSDavid van Moolenbroek 		{ &sin6_ll_kame,	EINVAL },
1464*3ba6090fSDavid van Moolenbroek 		{ &sin6_ll_bad,		ENXIO },
1465*3ba6090fSDavid van Moolenbroek 		{ &sin6_v4_any,		EADDRNOTAVAIL },
1466*3ba6090fSDavid van Moolenbroek 		{ &sin6_v4_rem,		EADDRNOTAVAIL },
1467*3ba6090fSDavid van Moolenbroek 		/* The following entry MUST be last. */
1468*3ba6090fSDavid van Moolenbroek 		{ &sin6_ll_mix,		EADDRNOTAVAIL },
1469*3ba6090fSDavid van Moolenbroek 	}, *bp;
1470*3ba6090fSDavid van Moolenbroek 	const struct {
1471*3ba6090fSDavid van Moolenbroek 		const struct sockaddr_in6 *addr;
1472*3ba6090fSDavid van Moolenbroek 		int res;
1473*3ba6090fSDavid van Moolenbroek 		int flags;
1474*3ba6090fSDavid van Moolenbroek 		const struct sockaddr_in6 *name;
1475*3ba6090fSDavid van Moolenbroek 	} conn_array[] = {
1476*3ba6090fSDavid van Moolenbroek 		{ &sin6_any,		EHOSTUNREACH, 0 },
1477*3ba6090fSDavid van Moolenbroek 		{ &sin6_any_scope,	EHOSTUNREACH, 0 },
1478*3ba6090fSDavid van Moolenbroek 		{ &sin6_ll_kame,	EINVAL, 0 },
1479*3ba6090fSDavid van Moolenbroek 		{ &sin6_ll_bad,		ENXIO, 0 },
1480*3ba6090fSDavid van Moolenbroek 		{ &sin6_v4_any,		EHOSTUNREACH, F_V4 },
1481*3ba6090fSDavid van Moolenbroek 		{ &sin6_lo,		0, 0,		&sin6_lo },
1482*3ba6090fSDavid van Moolenbroek 		{ &sin6_lo_scope,	0, 0,		&sin6_lo },
1483*3ba6090fSDavid van Moolenbroek 		{ &sin6_ll_all,		0, 0,		&sin6_ll_lo },
1484*3ba6090fSDavid van Moolenbroek 		{ &sin6_ll_lo,		0, 0,		&sin6_ll_lo },
1485*3ba6090fSDavid van Moolenbroek 		{ &sin6_v4_lo,		0, F_V4,	&sin6_v4_lo },
1486*3ba6090fSDavid van Moolenbroek 		{ &sin6_rem,		0, F_REM,	&sin6_rem },
1487*3ba6090fSDavid van Moolenbroek 		{ &sin6_ll_rem,		0, F_REM,	&sin6_ll_rem },
1488*3ba6090fSDavid van Moolenbroek 		{ &sin6_v4_rem,		0, F_V4|F_REM,	&sin6_v4_rem },
1489*3ba6090fSDavid van Moolenbroek 		/* The following entry MUST be last. */
1490*3ba6090fSDavid van Moolenbroek 		{ &sin6_ll_mix,		0, F_REM|F_MIX,	&sin6_ll_mix },
1491*3ba6090fSDavid van Moolenbroek 	}, *cp;
1492*3ba6090fSDavid van Moolenbroek 	struct ifaddrs *ifa, *ifp, *ifp2;
1493*3ba6090fSDavid van Moolenbroek 	struct in6_ifreq ifr;
1494*3ba6090fSDavid van Moolenbroek 	char name[IF_NAMESIZE], buf[1];
1495*3ba6090fSDavid van Moolenbroek 	socklen_t len;
1496*3ba6090fSDavid van Moolenbroek 	uint32_t port;
1497*3ba6090fSDavid van Moolenbroek 	unsigned int i, j, ifindex, ifindex2, have_mix, found;
1498*3ba6090fSDavid van Moolenbroek 	int r, fd, fd2, fd3, val, sfl, exp, link_state;
1499*3ba6090fSDavid van Moolenbroek 
1500*3ba6090fSDavid van Moolenbroek 	ifindex = if_nametoindex(LOOPBACK_IFNAME);
1501*3ba6090fSDavid van Moolenbroek 	if (ifindex == 0) e(0);
1502*3ba6090fSDavid van Moolenbroek 
1503*3ba6090fSDavid van Moolenbroek 	/* An IPv6 'any' address - ::0. */
1504*3ba6090fSDavid van Moolenbroek 	memset(&sin6_any, 0, sizeof(sin6_any));
1505*3ba6090fSDavid van Moolenbroek 	sin6_any.sin6_len = sizeof(sin6_any);
1506*3ba6090fSDavid van Moolenbroek 	sin6_any.sin6_family = AF_INET6;
1507*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6_any.sin6_addr, &in6addr_any, sizeof(sin6_any.sin6_addr));
1508*3ba6090fSDavid van Moolenbroek 
1509*3ba6090fSDavid van Moolenbroek 	/* An IPv6 'any' address, but with a bad scope ID set. */
1510*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6_any_scope, &sin6_any, sizeof(sin6_any_scope));
1511*3ba6090fSDavid van Moolenbroek 	sin6_any_scope.sin6_scope_id = BAD_IFINDEX;
1512*3ba6090fSDavid van Moolenbroek 
1513*3ba6090fSDavid van Moolenbroek 	/* An IPv6 loopback address - ::1. */
1514*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6_lo, &sin6_any, sizeof(sin6_lo));
1515*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6_lo.sin6_addr, &in6addr_loopback,
1516*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6_lo.sin6_addr));
1517*3ba6090fSDavid van Moolenbroek 
1518*3ba6090fSDavid van Moolenbroek 	/* An IPv6 loopback address, but with a bad scope ID set. */
1519*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6_lo_scope, &sin6_lo, sizeof(sin6_lo_scope));
1520*3ba6090fSDavid van Moolenbroek 	sin6_lo_scope.sin6_scope_id = BAD_IFINDEX;
1521*3ba6090fSDavid van Moolenbroek 
1522*3ba6090fSDavid van Moolenbroek 	/* An IPv6 link-local address without scope - fe80::1. */
1523*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6_ll_all, &sin6_any, sizeof(sin6_ll_all));
1524*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, LOOPBACK_IPV6_LL, &sin6_ll_all.sin6_addr) != 1)
1525*3ba6090fSDavid van Moolenbroek 		e(0);
1526*3ba6090fSDavid van Moolenbroek 
1527*3ba6090fSDavid van Moolenbroek 	/* An IPv6 link-local address with the loopback scope - fe80::1%lo0. */
1528*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6_ll_lo, &sin6_ll_all, sizeof(sin6_ll_lo));
1529*3ba6090fSDavid van Moolenbroek 	sin6_ll_lo.sin6_scope_id = ifindex;
1530*3ba6090fSDavid van Moolenbroek 
1531*3ba6090fSDavid van Moolenbroek 	/* An unassigned IPv6 link-local address - fe80::ffff%lo0. */
1532*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6_ll_rem, &sin6_ll_lo, sizeof(sin6_ll_rem));
1533*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_BLACKHOLE_IPV6_LL,
1534*3ba6090fSDavid van Moolenbroek 	    &sin6_ll_rem.sin6_addr) != 1) e(0);
1535*3ba6090fSDavid van Moolenbroek 
1536*3ba6090fSDavid van Moolenbroek 	/* A KAME-style IPv6 link-local loopback address - fe80:ifindex::1. */
1537*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6_ll_kame, &sin6_ll_all, sizeof(sin6_ll_kame));
1538*3ba6090fSDavid van Moolenbroek 	sin6_ll_kame.sin6_addr.s6_addr[2] = ifindex >> 8;
1539*3ba6090fSDavid van Moolenbroek 	sin6_ll_kame.sin6_addr.s6_addr[3] = ifindex % 0xff;
1540*3ba6090fSDavid van Moolenbroek 
1541*3ba6090fSDavid van Moolenbroek 	/* An IPv6 link-local address with a bad scope - fe80::1%<bad>. */
1542*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6_ll_bad, &sin6_ll_all, sizeof(sin6_ll_bad));
1543*3ba6090fSDavid van Moolenbroek 	sin6_ll_bad.sin6_scope_id = BAD_IFINDEX;
1544*3ba6090fSDavid van Moolenbroek 
1545*3ba6090fSDavid van Moolenbroek 	/* A global IPv6 address not assigned to any interface - ::2. */
1546*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6_rem, &sin6_any, sizeof(sin6_rem));
1547*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_BLACKHOLE_IPV6,
1548*3ba6090fSDavid van Moolenbroek 	    &sin6_rem.sin6_addr) != 1) e(0);
1549*3ba6090fSDavid van Moolenbroek 
1550*3ba6090fSDavid van Moolenbroek 	/* An IPv4-mapped IPv6 address for 'any' - ::ffff:0.0.0.0. */
1551*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6_v4_any, &sin6_any, sizeof(sin6_v4_any));
1552*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, "::ffff:0:0", &sin6_v4_any.sin6_addr) != 1)
1553*3ba6090fSDavid van Moolenbroek 		e(0);
1554*3ba6090fSDavid van Moolenbroek 
1555*3ba6090fSDavid van Moolenbroek 	/* An IPv4-mapped IPv6 loopback address - ::ffff:127.0.0.1. */
1556*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6_v4_lo, &sin6_any, sizeof(sin6_v4_lo));
1557*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, "::ffff:"LOOPBACK_IPV4,
1558*3ba6090fSDavid van Moolenbroek 	    &sin6_v4_lo.sin6_addr) != 1) e(0);
1559*3ba6090fSDavid van Moolenbroek 
1560*3ba6090fSDavid van Moolenbroek 	/* An unassigned IPv4-mapped IPv6 address - ::ffff:127.255.0.254. */
1561*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6_v4_rem, &sin6_any, sizeof(sin6_v4_rem));
1562*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, "::ffff:"TEST_BLACKHOLE_IPV4,
1563*3ba6090fSDavid van Moolenbroek 	    &sin6_v4_rem.sin6_addr) != 1) e(0);
1564*3ba6090fSDavid van Moolenbroek 
1565*3ba6090fSDavid van Moolenbroek 	/*
1566*3ba6090fSDavid van Moolenbroek 	 * An IPv6 link-local address with a scope for another interface, for
1567*3ba6090fSDavid van Moolenbroek 	 * example fe80::1%em0.  Since no other interfaces may be present, we
1568*3ba6090fSDavid van Moolenbroek 	 * may not be able to generate such an address.
1569*3ba6090fSDavid van Moolenbroek 	 */
1570*3ba6090fSDavid van Moolenbroek 	have_mix = 0;
1571*3ba6090fSDavid van Moolenbroek 	for (i = 1; i < BAD_IFINDEX; i++) {
1572*3ba6090fSDavid van Moolenbroek 		if (if_indextoname(i, name) == NULL) {
1573*3ba6090fSDavid van Moolenbroek 			if (errno != ENXIO) e(0);
1574*3ba6090fSDavid van Moolenbroek 			continue;
1575*3ba6090fSDavid van Moolenbroek 		}
1576*3ba6090fSDavid van Moolenbroek 
1577*3ba6090fSDavid van Moolenbroek 		if (!strcmp(name, LOOPBACK_IFNAME))
1578*3ba6090fSDavid van Moolenbroek 			continue;
1579*3ba6090fSDavid van Moolenbroek 
1580*3ba6090fSDavid van Moolenbroek 		/* Found one! */
1581*3ba6090fSDavid van Moolenbroek 		memcpy(&sin6_ll_mix, &sin6_ll_all, sizeof(sin6_ll_mix));
1582*3ba6090fSDavid van Moolenbroek 		sin6_ll_mix.sin6_scope_id = i;
1583*3ba6090fSDavid van Moolenbroek 		have_mix = 1;
1584*3ba6090fSDavid van Moolenbroek 		break;
1585*3ba6090fSDavid van Moolenbroek 	}
1586*3ba6090fSDavid van Moolenbroek 
1587*3ba6090fSDavid van Moolenbroek 	/*
1588*3ba6090fSDavid van Moolenbroek 	 * Test a whole range of combinations of local and remote addresses,
1589*3ba6090fSDavid van Moolenbroek 	 * both for TCP and UDP, and for UDP both for connect+send and sendto.
1590*3ba6090fSDavid van Moolenbroek 	 * Not all addresses and not all combinations are compatible, and that
1591*3ba6090fSDavid van Moolenbroek 	 * is exactly what we want to test.  We first test binding to local
1592*3ba6090fSDavid van Moolenbroek 	 * addresses.  Then we test connect (and for UDP, on success, send)
1593*3ba6090fSDavid van Moolenbroek 	 * with remote addresses on those local addresses that could be bound
1594*3ba6090fSDavid van Moolenbroek 	 * to.  Finally, for UDP sockets, we separately test sendto.
1595*3ba6090fSDavid van Moolenbroek 	 */
1596*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < __arraycount(bind_array) - !have_mix; i++) {
1597*3ba6090fSDavid van Moolenbroek 		bp = &bind_array[i];
1598*3ba6090fSDavid van Moolenbroek 
1599*3ba6090fSDavid van Moolenbroek 		/* Test bind(2) and getsockname(2). */
1600*3ba6090fSDavid van Moolenbroek 		if (bind_array[i].addr != NULL) {
1601*3ba6090fSDavid van Moolenbroek 			if ((fd = socket(AF_INET6, type, protocol)) < 0) e(0);
1602*3ba6090fSDavid van Moolenbroek 
1603*3ba6090fSDavid van Moolenbroek 			val = 0;
1604*3ba6090fSDavid van Moolenbroek 			if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
1605*3ba6090fSDavid van Moolenbroek 			    sizeof(val)) != 0) e(0);
1606*3ba6090fSDavid van Moolenbroek 
1607*3ba6090fSDavid van Moolenbroek 			r = bind(fd, (struct sockaddr *)bp->addr,
1608*3ba6090fSDavid van Moolenbroek 			    sizeof(*bp->addr));
1609*3ba6090fSDavid van Moolenbroek 
1610*3ba6090fSDavid van Moolenbroek 			/* Did the bind(2) call produce the expected result? */
1611*3ba6090fSDavid van Moolenbroek 			if (r == 0) {
1612*3ba6090fSDavid van Moolenbroek 				if (bp->res != 0) e(0);
1613*3ba6090fSDavid van Moolenbroek 			} else
1614*3ba6090fSDavid van Moolenbroek 				if (r != -1 || bp->res != errno) e(0);
1615*3ba6090fSDavid van Moolenbroek 
1616*3ba6090fSDavid van Moolenbroek 			/* The rest is for successful bind(2) calls. */
1617*3ba6090fSDavid van Moolenbroek 			if (r != 0) {
1618*3ba6090fSDavid van Moolenbroek 				if (close(fd) != 0) e(0);
1619*3ba6090fSDavid van Moolenbroek 
1620*3ba6090fSDavid van Moolenbroek 				continue;
1621*3ba6090fSDavid van Moolenbroek 			}
1622*3ba6090fSDavid van Moolenbroek 
1623*3ba6090fSDavid van Moolenbroek 			/* Get the bound address. */
1624*3ba6090fSDavid van Moolenbroek 			len = sizeof(sin6);
1625*3ba6090fSDavid van Moolenbroek 			if (getsockname(fd, (struct sockaddr *)&sin6,
1626*3ba6090fSDavid van Moolenbroek 			    &len) != 0) e(0);
1627*3ba6090fSDavid van Moolenbroek 			if (len != sizeof(sin6)) e(0);
1628*3ba6090fSDavid van Moolenbroek 
1629*3ba6090fSDavid van Moolenbroek 			/* A port must be set.  Clear it for the comparison. */
1630*3ba6090fSDavid van Moolenbroek 			if ((sin6.sin6_port == 0) == (type != SOCK_RAW)) e(0);
1631*3ba6090fSDavid van Moolenbroek 
1632*3ba6090fSDavid van Moolenbroek 			sin6.sin6_port = 0;
1633*3ba6090fSDavid van Moolenbroek 			if (memcmp(&sin6, bp->name, sizeof(sin6)) != 0) e(0);
1634*3ba6090fSDavid van Moolenbroek 
1635*3ba6090fSDavid van Moolenbroek 			if (close(fd) != 0) e(0);
1636*3ba6090fSDavid van Moolenbroek 		}
1637*3ba6090fSDavid van Moolenbroek 
1638*3ba6090fSDavid van Moolenbroek 		/* Test connect(2), send(2), and getpeername(2). */
1639*3ba6090fSDavid van Moolenbroek 		for (j = 0; j < __arraycount(conn_array) - !have_mix; j++) {
1640*3ba6090fSDavid van Moolenbroek 			cp = &conn_array[j];
1641*3ba6090fSDavid van Moolenbroek 
1642*3ba6090fSDavid van Moolenbroek 			/*
1643*3ba6090fSDavid van Moolenbroek 			 * We cannot test remote addresses without having bound
1644*3ba6090fSDavid van Moolenbroek 			 * to a local address, because we may end up generating
1645*3ba6090fSDavid van Moolenbroek 			 * external traffic as a result.
1646*3ba6090fSDavid van Moolenbroek 			 */
1647*3ba6090fSDavid van Moolenbroek 			if ((bp->flags & F_ANY) && (cp->flags & F_REM))
1648*3ba6090fSDavid van Moolenbroek 				continue;
1649*3ba6090fSDavid van Moolenbroek 
1650*3ba6090fSDavid van Moolenbroek 			/*
1651*3ba6090fSDavid van Moolenbroek 			 * Use non-blocking sockets only if connecting is going
1652*3ba6090fSDavid van Moolenbroek 			 * to take a while before ultimately failing; TCP only.
1653*3ba6090fSDavid van Moolenbroek 			 */
1654*3ba6090fSDavid van Moolenbroek 			sfl = ((cp->flags & F_REM) && (type == SOCK_STREAM)) ?
1655*3ba6090fSDavid van Moolenbroek 			    SOCK_NONBLOCK : 0;
1656*3ba6090fSDavid van Moolenbroek 			if ((fd = socket(AF_INET6, type | sfl, protocol)) < 0)
1657*3ba6090fSDavid van Moolenbroek 				e(0);
1658*3ba6090fSDavid van Moolenbroek 
1659*3ba6090fSDavid van Moolenbroek 			val = 0;
1660*3ba6090fSDavid van Moolenbroek 			if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
1661*3ba6090fSDavid van Moolenbroek 			    sizeof(val)) != 0) e(0);
1662*3ba6090fSDavid van Moolenbroek 
1663*3ba6090fSDavid van Moolenbroek 			if (bp->addr != NULL) {
1664*3ba6090fSDavid van Moolenbroek 				if (bind(fd, (struct sockaddr *)bp->addr,
1665*3ba6090fSDavid van Moolenbroek 				    sizeof(*bp->addr)) != 0) e(0);
1666*3ba6090fSDavid van Moolenbroek 
1667*3ba6090fSDavid van Moolenbroek 				len = sizeof(sin6);
1668*3ba6090fSDavid van Moolenbroek 				if (getsockname(fd, (struct sockaddr *)&sin6,
1669*3ba6090fSDavid van Moolenbroek 				    &len) != 0) e(0);
1670*3ba6090fSDavid van Moolenbroek 
1671*3ba6090fSDavid van Moolenbroek 				port = sin6.sin6_port;
1672*3ba6090fSDavid van Moolenbroek 			} else
1673*3ba6090fSDavid van Moolenbroek 				port = 0;
1674*3ba6090fSDavid van Moolenbroek 
1675*3ba6090fSDavid van Moolenbroek 			memcpy(&sin6, cp->addr, sizeof(sin6));
1676*3ba6090fSDavid van Moolenbroek 			sin6.sin6_port = htons(TEST_PORT_A);
1677*3ba6090fSDavid van Moolenbroek 
1678*3ba6090fSDavid van Moolenbroek 			if ((exp = cp->res) == 0 && type == SOCK_STREAM) {
1679*3ba6090fSDavid van Moolenbroek 				if (cp->flags & F_REM)
1680*3ba6090fSDavid van Moolenbroek 					exp = EINPROGRESS;
1681*3ba6090fSDavid van Moolenbroek 				if (cp->flags & F_MIX)
1682*3ba6090fSDavid van Moolenbroek 					exp = EHOSTUNREACH;
1683*3ba6090fSDavid van Moolenbroek 			}
1684*3ba6090fSDavid van Moolenbroek 
1685*3ba6090fSDavid van Moolenbroek 			/*
1686*3ba6090fSDavid van Moolenbroek 			 * The IPv4/IPv6 mismatch check precedes most other
1687*3ba6090fSDavid van Moolenbroek 			 * checks, but (currently) not the bad-scope-ID check.
1688*3ba6090fSDavid van Moolenbroek 			 */
1689*3ba6090fSDavid van Moolenbroek 			if (exp != ENXIO && !(bp->flags & F_ANY) &&
1690*3ba6090fSDavid van Moolenbroek 			    ((bp->flags ^ cp->flags) & F_V4))
1691*3ba6090fSDavid van Moolenbroek 				exp = EINVAL;
1692*3ba6090fSDavid van Moolenbroek 
1693*3ba6090fSDavid van Moolenbroek 			/*
1694*3ba6090fSDavid van Moolenbroek 			 * Create a listening or receiving socket if we expect
1695*3ba6090fSDavid van Moolenbroek 			 * the test to succeed and operate on a loopback target
1696*3ba6090fSDavid van Moolenbroek 			 * so that we can test addresses on that end as well.
1697*3ba6090fSDavid van Moolenbroek 			 */
1698*3ba6090fSDavid van Moolenbroek 			if (exp == 0 && !(cp->flags & F_REM)) {
1699*3ba6090fSDavid van Moolenbroek 				if ((fd2 = socket(AF_INET6, type,
1700*3ba6090fSDavid van Moolenbroek 				    protocol)) < 0) e(0);
1701*3ba6090fSDavid van Moolenbroek 
1702*3ba6090fSDavid van Moolenbroek 				val = 0;
1703*3ba6090fSDavid van Moolenbroek 				if (setsockopt(fd2, IPPROTO_IPV6, IPV6_V6ONLY,
1704*3ba6090fSDavid van Moolenbroek 				    &val, sizeof(val)) != 0) e(0);
1705*3ba6090fSDavid van Moolenbroek 
1706*3ba6090fSDavid van Moolenbroek 				val = 1;
1707*3ba6090fSDavid van Moolenbroek 				if (setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR,
1708*3ba6090fSDavid van Moolenbroek 				    &val, sizeof(val)) != 0) e(0);
1709*3ba6090fSDavid van Moolenbroek 
1710*3ba6090fSDavid van Moolenbroek 				memcpy(&rsin6, cp->name, sizeof(rsin6));
1711*3ba6090fSDavid van Moolenbroek 				rsin6.sin6_port = htons(TEST_PORT_A);
1712*3ba6090fSDavid van Moolenbroek 
1713*3ba6090fSDavid van Moolenbroek 				if (bind(fd2, (struct sockaddr *)&rsin6,
1714*3ba6090fSDavid van Moolenbroek 				    sizeof(rsin6)) != 0) e(0);
1715*3ba6090fSDavid van Moolenbroek 
1716*3ba6090fSDavid van Moolenbroek 				if (type == SOCK_STREAM && listen(fd2, 1) != 0)
1717*3ba6090fSDavid van Moolenbroek 					e(0);
1718*3ba6090fSDavid van Moolenbroek 			} else
1719*3ba6090fSDavid van Moolenbroek 				fd2 = -1;
1720*3ba6090fSDavid van Moolenbroek 
1721*3ba6090fSDavid van Moolenbroek 			r = connect(fd, (struct sockaddr *)&sin6,
1722*3ba6090fSDavid van Moolenbroek 			    sizeof(sin6));
1723*3ba6090fSDavid van Moolenbroek 
1724*3ba6090fSDavid van Moolenbroek 			if (r == 0) {
1725*3ba6090fSDavid van Moolenbroek 				if (exp != 0) e(0);
1726*3ba6090fSDavid van Moolenbroek 			} else
1727*3ba6090fSDavid van Moolenbroek 				if (r != -1 || exp != errno) e(0);
1728*3ba6090fSDavid van Moolenbroek 
1729*3ba6090fSDavid van Moolenbroek 			if (r != 0) {
1730*3ba6090fSDavid van Moolenbroek 				if (close(fd) != 0) e(0);
1731*3ba6090fSDavid van Moolenbroek 
1732*3ba6090fSDavid van Moolenbroek 				continue;
1733*3ba6090fSDavid van Moolenbroek 			}
1734*3ba6090fSDavid van Moolenbroek 
1735*3ba6090fSDavid van Moolenbroek 			/*
1736*3ba6090fSDavid van Moolenbroek 			 * Connecting should always assign a local address if
1737*3ba6090fSDavid van Moolenbroek 			 * no address was assigned, even if a port was assigned
1738*3ba6090fSDavid van Moolenbroek 			 * already.  In the latter case, the port number must
1739*3ba6090fSDavid van Moolenbroek 			 * obviously not change.  Test getsockname(2) again, if
1740*3ba6090fSDavid van Moolenbroek 			 * we can.
1741*3ba6090fSDavid van Moolenbroek 			 */
1742*3ba6090fSDavid van Moolenbroek 			len = sizeof(sin6);
1743*3ba6090fSDavid van Moolenbroek 			if (getsockname(fd, (struct sockaddr *)&sin6,
1744*3ba6090fSDavid van Moolenbroek 			    &len) != 0) e(0);
1745*3ba6090fSDavid van Moolenbroek 			if (len != sizeof(sin6)) e(0);
1746*3ba6090fSDavid van Moolenbroek 
1747*3ba6090fSDavid van Moolenbroek 			if (type != SOCK_RAW) {
1748*3ba6090fSDavid van Moolenbroek 				if (sin6.sin6_port == 0) e(0);
1749*3ba6090fSDavid van Moolenbroek 				if (port != 0 && port != sin6.sin6_port) e(0);
1750*3ba6090fSDavid van Moolenbroek 			} else
1751*3ba6090fSDavid van Moolenbroek 				if (sin6.sin6_port != 0) e(0);
1752*3ba6090fSDavid van Moolenbroek 			port = sin6.sin6_port;
1753*3ba6090fSDavid van Moolenbroek 
1754*3ba6090fSDavid van Moolenbroek 			if (!(bp->flags & F_ANY))
1755*3ba6090fSDavid van Moolenbroek 				sin6p = bp->name;
1756*3ba6090fSDavid van Moolenbroek 			else if (!(cp->flags & F_REM))
1757*3ba6090fSDavid van Moolenbroek 				sin6p = cp->name;
1758*3ba6090fSDavid van Moolenbroek 			else
1759*3ba6090fSDavid van Moolenbroek 				sin6p = NULL; /* can't test: may vary */
1760*3ba6090fSDavid van Moolenbroek 
1761*3ba6090fSDavid van Moolenbroek 			if (sin6p != NULL) {
1762*3ba6090fSDavid van Moolenbroek 				sin6.sin6_port = 0;
1763*3ba6090fSDavid van Moolenbroek 
1764*3ba6090fSDavid van Moolenbroek 				if (memcmp(&sin6, sin6p, sizeof(sin6)) != 0)
1765*3ba6090fSDavid van Moolenbroek 					e(0);
1766*3ba6090fSDavid van Moolenbroek 			}
1767*3ba6090fSDavid van Moolenbroek 
1768*3ba6090fSDavid van Moolenbroek 			/*
1769*3ba6090fSDavid van Moolenbroek 			 * Test getpeername(2).  It should always be the
1770*3ba6090fSDavid van Moolenbroek 			 * "normalized" version of the target address.
1771*3ba6090fSDavid van Moolenbroek 			 */
1772*3ba6090fSDavid van Moolenbroek 			len = sizeof(sin6);
1773*3ba6090fSDavid van Moolenbroek 			if (getpeername(fd, (struct sockaddr *)&sin6,
1774*3ba6090fSDavid van Moolenbroek 			    &len) != 0) e(0);
1775*3ba6090fSDavid van Moolenbroek 			if (len != sizeof(sin6)) e(0);
1776*3ba6090fSDavid van Moolenbroek 
1777*3ba6090fSDavid van Moolenbroek 			if (type != SOCK_RAW) {
1778*3ba6090fSDavid van Moolenbroek 				if (sin6.sin6_port != htons(TEST_PORT_A)) e(0);
1779*3ba6090fSDavid van Moolenbroek 			} else {
1780*3ba6090fSDavid van Moolenbroek 				if (sin6.sin6_port != 0) e(0);
1781*3ba6090fSDavid van Moolenbroek 			}
1782*3ba6090fSDavid van Moolenbroek 
1783*3ba6090fSDavid van Moolenbroek 			sin6.sin6_port = 0;
1784*3ba6090fSDavid van Moolenbroek 			if (memcmp(&sin6, cp->name, sizeof(sin6)) != 0) e(0);
1785*3ba6090fSDavid van Moolenbroek 
1786*3ba6090fSDavid van Moolenbroek 			/* Test send(2) on UDP sockets. */
1787*3ba6090fSDavid van Moolenbroek 			if (type != SOCK_STREAM) {
1788*3ba6090fSDavid van Moolenbroek 				r = send(fd, "A", 1, 0);
1789*3ba6090fSDavid van Moolenbroek 
1790*3ba6090fSDavid van Moolenbroek 				/*
1791*3ba6090fSDavid van Moolenbroek 				 * For remote (rejected) addresses and scope
1792*3ba6090fSDavid van Moolenbroek 				 * mixing, actual send calls may fail after the
1793*3ba6090fSDavid van Moolenbroek 				 * connect succeeded.
1794*3ba6090fSDavid van Moolenbroek 				 */
1795*3ba6090fSDavid van Moolenbroek 				if (r == -1 &&
1796*3ba6090fSDavid van Moolenbroek 				    !(cp->flags & (F_REM | F_MIX))) e(0);
1797*3ba6090fSDavid van Moolenbroek 				else if (r != -1 && r != 1) e(0);
1798*3ba6090fSDavid van Moolenbroek 
1799*3ba6090fSDavid van Moolenbroek 				if (r != 1 && fd2 != -1) {
1800*3ba6090fSDavid van Moolenbroek 					if (close(fd2) != 0) e(0);
1801*3ba6090fSDavid van Moolenbroek 					fd2 = -1;
1802*3ba6090fSDavid van Moolenbroek 				}
1803*3ba6090fSDavid van Moolenbroek 			}
1804*3ba6090fSDavid van Moolenbroek 
1805*3ba6090fSDavid van Moolenbroek 			if (fd2 == -1) {
1806*3ba6090fSDavid van Moolenbroek 				if (close(fd) != 0) e(0);
1807*3ba6090fSDavid van Moolenbroek 
1808*3ba6090fSDavid van Moolenbroek 				continue;
1809*3ba6090fSDavid van Moolenbroek 			}
1810*3ba6090fSDavid van Moolenbroek 
1811*3ba6090fSDavid van Moolenbroek 			/*
1812*3ba6090fSDavid van Moolenbroek 			 * The connect or send call succeeded, so we should now
1813*3ba6090fSDavid van Moolenbroek 			 * be able to check the other end.
1814*3ba6090fSDavid van Moolenbroek 			 */
1815*3ba6090fSDavid van Moolenbroek 			if (type == SOCK_STREAM) {
1816*3ba6090fSDavid van Moolenbroek 				/* Test accept(2). */
1817*3ba6090fSDavid van Moolenbroek 				len = sizeof(sin6);
1818*3ba6090fSDavid van Moolenbroek 				if ((fd3 = accept(fd2,
1819*3ba6090fSDavid van Moolenbroek 				    (struct sockaddr *)&sin6, &len)) < 0) e(0);
1820*3ba6090fSDavid van Moolenbroek 				if (len != sizeof(sin6)) e(0);
1821*3ba6090fSDavid van Moolenbroek 
1822*3ba6090fSDavid van Moolenbroek 				if (close(fd2) != 0) e(0);
1823*3ba6090fSDavid van Moolenbroek 
1824*3ba6090fSDavid van Moolenbroek 				if (sin6.sin6_port != port) e(0);
1825*3ba6090fSDavid van Moolenbroek 				sin6.sin6_port = 0;
1826*3ba6090fSDavid van Moolenbroek 
1827*3ba6090fSDavid van Moolenbroek 				if (memcmp(&sin6, sin6p, sizeof(sin6)) != 0)
1828*3ba6090fSDavid van Moolenbroek 					e(0);
1829*3ba6090fSDavid van Moolenbroek 
1830*3ba6090fSDavid van Moolenbroek 				/* Test getpeername(2). */
1831*3ba6090fSDavid van Moolenbroek 				if (getpeername(fd3, (struct sockaddr *)&sin6,
1832*3ba6090fSDavid van Moolenbroek 				    &len) != 0) e(0);
1833*3ba6090fSDavid van Moolenbroek 				if (len != sizeof(sin6)) e(0);
1834*3ba6090fSDavid van Moolenbroek 
1835*3ba6090fSDavid van Moolenbroek 				if (sin6.sin6_port != port) e(0);
1836*3ba6090fSDavid van Moolenbroek 				sin6.sin6_port = 0;
1837*3ba6090fSDavid van Moolenbroek 
1838*3ba6090fSDavid van Moolenbroek 				if (memcmp(&sin6, sin6p, sizeof(sin6)) != 0)
1839*3ba6090fSDavid van Moolenbroek 					e(0);
1840*3ba6090fSDavid van Moolenbroek 
1841*3ba6090fSDavid van Moolenbroek 				/* Test getsockname(2). */
1842*3ba6090fSDavid van Moolenbroek 				if (getsockname(fd3, (struct sockaddr *)&sin6,
1843*3ba6090fSDavid van Moolenbroek 				    &len) != 0) e(0);
1844*3ba6090fSDavid van Moolenbroek 				if (len != sizeof(sin6)) e(0);
1845*3ba6090fSDavid van Moolenbroek 
1846*3ba6090fSDavid van Moolenbroek 				if (sin6.sin6_port != htons(TEST_PORT_A)) e(0);
1847*3ba6090fSDavid van Moolenbroek 				sin6.sin6_port = 0;
1848*3ba6090fSDavid van Moolenbroek 
1849*3ba6090fSDavid van Moolenbroek 				if (memcmp(&sin6, cp->name, sizeof(sin6)) != 0)
1850*3ba6090fSDavid van Moolenbroek 					e(0);
1851*3ba6090fSDavid van Moolenbroek 
1852*3ba6090fSDavid van Moolenbroek 				if (close(fd3) != 0) e(0);
1853*3ba6090fSDavid van Moolenbroek 			} else {
1854*3ba6090fSDavid van Moolenbroek 				/* Test recvfrom(2). */
1855*3ba6090fSDavid van Moolenbroek 				len = sizeof(sin6);
1856*3ba6090fSDavid van Moolenbroek 				if (recvfrom(fd2, buf, sizeof(buf), 0,
1857*3ba6090fSDavid van Moolenbroek 				    (struct sockaddr *)&sin6, &len) != 1) e(0);
1858*3ba6090fSDavid van Moolenbroek 
1859*3ba6090fSDavid van Moolenbroek 				if (buf[0] != 'A') e(0);
1860*3ba6090fSDavid van Moolenbroek 				if (len != sizeof(sin6)) e(0);
1861*3ba6090fSDavid van Moolenbroek 
1862*3ba6090fSDavid van Moolenbroek 				if (sin6.sin6_port != port) e(0);
1863*3ba6090fSDavid van Moolenbroek 				sin6.sin6_port = 0;
1864*3ba6090fSDavid van Moolenbroek 
1865*3ba6090fSDavid van Moolenbroek 				if (memcmp(&sin6, sin6p, sizeof(sin6)) != 0)
1866*3ba6090fSDavid van Moolenbroek 					e(0);
1867*3ba6090fSDavid van Moolenbroek 
1868*3ba6090fSDavid van Moolenbroek 				if (close(fd2) != 0) e(0);
1869*3ba6090fSDavid van Moolenbroek 			}
1870*3ba6090fSDavid van Moolenbroek 
1871*3ba6090fSDavid van Moolenbroek 			if (close(fd) != 0) e(0);
1872*3ba6090fSDavid van Moolenbroek 		}
1873*3ba6090fSDavid van Moolenbroek 
1874*3ba6090fSDavid van Moolenbroek 		if (type == SOCK_STREAM)
1875*3ba6090fSDavid van Moolenbroek 			continue;
1876*3ba6090fSDavid van Moolenbroek 
1877*3ba6090fSDavid van Moolenbroek 		/* Test sendto(2). */
1878*3ba6090fSDavid van Moolenbroek 		for (j = 0; j < __arraycount(conn_array) - !have_mix; j++) {
1879*3ba6090fSDavid van Moolenbroek 			cp = &conn_array[j];
1880*3ba6090fSDavid van Moolenbroek 
1881*3ba6090fSDavid van Moolenbroek 			/*
1882*3ba6090fSDavid van Moolenbroek 			 * We cannot test remote addresses without having bound
1883*3ba6090fSDavid van Moolenbroek 			 * to a local address, because we may end up generating
1884*3ba6090fSDavid van Moolenbroek 			 * external traffic as a result.
1885*3ba6090fSDavid van Moolenbroek 			 */
1886*3ba6090fSDavid van Moolenbroek 			if ((bp->flags & F_ANY) && (cp->flags & F_REM))
1887*3ba6090fSDavid van Moolenbroek 				continue;
1888*3ba6090fSDavid van Moolenbroek 
1889*3ba6090fSDavid van Moolenbroek 			if ((fd = socket(AF_INET6, type, protocol)) < 0) e(0);
1890*3ba6090fSDavid van Moolenbroek 
1891*3ba6090fSDavid van Moolenbroek 			val = 0;
1892*3ba6090fSDavid van Moolenbroek 			if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
1893*3ba6090fSDavid van Moolenbroek 			    sizeof(val)) != 0) e(0);
1894*3ba6090fSDavid van Moolenbroek 
1895*3ba6090fSDavid van Moolenbroek 			if (bp->addr != NULL) {
1896*3ba6090fSDavid van Moolenbroek 				if (bind(fd, (struct sockaddr *)bp->addr,
1897*3ba6090fSDavid van Moolenbroek 				   sizeof(*bp->addr)) != 0) e(0);
1898*3ba6090fSDavid van Moolenbroek 
1899*3ba6090fSDavid van Moolenbroek 				len = sizeof(sin6);
1900*3ba6090fSDavid van Moolenbroek 				if (getsockname(fd, (struct sockaddr *)&sin6,
1901*3ba6090fSDavid van Moolenbroek 				    &len) != 0) e(0);
1902*3ba6090fSDavid van Moolenbroek 
1903*3ba6090fSDavid van Moolenbroek 				port = sin6.sin6_port;
1904*3ba6090fSDavid van Moolenbroek 			} else
1905*3ba6090fSDavid van Moolenbroek 				port = 0;
1906*3ba6090fSDavid van Moolenbroek 
1907*3ba6090fSDavid van Moolenbroek 			memcpy(&sin6, cp->addr, sizeof(sin6));
1908*3ba6090fSDavid van Moolenbroek 			if (type != SOCK_RAW)
1909*3ba6090fSDavid van Moolenbroek 				sin6.sin6_port = htons(TEST_PORT_B);
1910*3ba6090fSDavid van Moolenbroek 
1911*3ba6090fSDavid van Moolenbroek 			if ((exp = cp->res) == 0) {
1912*3ba6090fSDavid van Moolenbroek 				if (cp->flags & (F_REM | F_MIX))
1913*3ba6090fSDavid van Moolenbroek 					exp = EHOSTUNREACH;
1914*3ba6090fSDavid van Moolenbroek 			}
1915*3ba6090fSDavid van Moolenbroek 
1916*3ba6090fSDavid van Moolenbroek 			/*
1917*3ba6090fSDavid van Moolenbroek 			 * The IPv4/IPv6 mismatch check precedes most other
1918*3ba6090fSDavid van Moolenbroek 			 * checks, but (currently) not the bad-scope-ID check.
1919*3ba6090fSDavid van Moolenbroek 			 */
1920*3ba6090fSDavid van Moolenbroek 			if (exp != ENXIO && !(bp->flags & F_ANY) &&
1921*3ba6090fSDavid van Moolenbroek 			    ((bp->flags ^ cp->flags) & F_V4))
1922*3ba6090fSDavid van Moolenbroek 				exp = EINVAL;
1923*3ba6090fSDavid van Moolenbroek 
1924*3ba6090fSDavid van Moolenbroek 			/*
1925*3ba6090fSDavid van Moolenbroek 			 * If we expect the sendto(2) call to succeed and to be
1926*3ba6090fSDavid van Moolenbroek 			 * able to receive the packet, create a receiving
1927*3ba6090fSDavid van Moolenbroek 			 * socket to test recvfrom(2) addresses.
1928*3ba6090fSDavid van Moolenbroek 			 */
1929*3ba6090fSDavid van Moolenbroek 			if (exp == 0 && !(cp->flags & F_REM)) {
1930*3ba6090fSDavid van Moolenbroek 				if ((fd2 = socket(AF_INET6, type,
1931*3ba6090fSDavid van Moolenbroek 				    protocol)) < 0) e(0);
1932*3ba6090fSDavid van Moolenbroek 
1933*3ba6090fSDavid van Moolenbroek 				val = 0;
1934*3ba6090fSDavid van Moolenbroek 				if (setsockopt(fd2, IPPROTO_IPV6, IPV6_V6ONLY,
1935*3ba6090fSDavid van Moolenbroek 				    &val, sizeof(val)) != 0) e(0);
1936*3ba6090fSDavid van Moolenbroek 
1937*3ba6090fSDavid van Moolenbroek 				val = 1;
1938*3ba6090fSDavid van Moolenbroek 				if (setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR,
1939*3ba6090fSDavid van Moolenbroek 				    &val, sizeof(val)) != 0) e(0);
1940*3ba6090fSDavid van Moolenbroek 
1941*3ba6090fSDavid van Moolenbroek 				memcpy(&rsin6, cp->name, sizeof(rsin6));
1942*3ba6090fSDavid van Moolenbroek 				if (type != SOCK_RAW)
1943*3ba6090fSDavid van Moolenbroek 					rsin6.sin6_port = htons(TEST_PORT_B);
1944*3ba6090fSDavid van Moolenbroek 
1945*3ba6090fSDavid van Moolenbroek 				if (bind(fd2, (struct sockaddr *)&rsin6,
1946*3ba6090fSDavid van Moolenbroek 				    sizeof(rsin6)) != 0) e(0);
1947*3ba6090fSDavid van Moolenbroek 			} else
1948*3ba6090fSDavid van Moolenbroek 				fd2 = -1;
1949*3ba6090fSDavid van Moolenbroek 
1950*3ba6090fSDavid van Moolenbroek 			r = sendto(fd, "B", 1, 0, (struct sockaddr *)&sin6,
1951*3ba6090fSDavid van Moolenbroek 			    sizeof(sin6));
1952*3ba6090fSDavid van Moolenbroek 
1953*3ba6090fSDavid van Moolenbroek 			if (r != 1) {
1954*3ba6090fSDavid van Moolenbroek 				if (r != -1 || exp != errno) e(0);
1955*3ba6090fSDavid van Moolenbroek 
1956*3ba6090fSDavid van Moolenbroek 				if (close(fd) != 0) e(0);
1957*3ba6090fSDavid van Moolenbroek 
1958*3ba6090fSDavid van Moolenbroek 				continue;
1959*3ba6090fSDavid van Moolenbroek 			}
1960*3ba6090fSDavid van Moolenbroek 
1961*3ba6090fSDavid van Moolenbroek 			if (exp != 0) e(0);
1962*3ba6090fSDavid van Moolenbroek 
1963*3ba6090fSDavid van Moolenbroek 			/*
1964*3ba6090fSDavid van Moolenbroek 			 * The sendto(2) call should assign a local port to the
1965*3ba6090fSDavid van Moolenbroek 			 * socket if none was assigned before, but it must not
1966*3ba6090fSDavid van Moolenbroek 			 * assign a local address.
1967*3ba6090fSDavid van Moolenbroek 			 */
1968*3ba6090fSDavid van Moolenbroek 			len = sizeof(sin6);
1969*3ba6090fSDavid van Moolenbroek 			if (getsockname(fd, (struct sockaddr *)&sin6,
1970*3ba6090fSDavid van Moolenbroek 			    &len) != 0) e(0);
1971*3ba6090fSDavid van Moolenbroek 			if (len != sizeof(sin6)) e(0);
1972*3ba6090fSDavid van Moolenbroek 
1973*3ba6090fSDavid van Moolenbroek 			if (type != SOCK_RAW) {
1974*3ba6090fSDavid van Moolenbroek 				if (sin6.sin6_port == 0) e(0);
1975*3ba6090fSDavid van Moolenbroek 				if (port != 0 && port != sin6.sin6_port) e(0);
1976*3ba6090fSDavid van Moolenbroek 			} else
1977*3ba6090fSDavid van Moolenbroek 				if (sin6.sin6_port != 0) e(0);
1978*3ba6090fSDavid van Moolenbroek 			port = sin6.sin6_port;
1979*3ba6090fSDavid van Moolenbroek 
1980*3ba6090fSDavid van Moolenbroek 			sin6.sin6_port = 0;
1981*3ba6090fSDavid van Moolenbroek 			if (memcmp(&sin6, bp->name, sizeof(sin6)) != 0) e(0);
1982*3ba6090fSDavid van Moolenbroek 
1983*3ba6090fSDavid van Moolenbroek 			if (fd2 != -1) {
1984*3ba6090fSDavid van Moolenbroek 				/* Test recvfrom(2) on the receiving socket. */
1985*3ba6090fSDavid van Moolenbroek 				len = sizeof(sin6);
1986*3ba6090fSDavid van Moolenbroek 				if (recvfrom(fd2, buf, sizeof(buf), 0,
1987*3ba6090fSDavid van Moolenbroek 				    (struct sockaddr *)&sin6, &len) != 1) e(0);
1988*3ba6090fSDavid van Moolenbroek 
1989*3ba6090fSDavid van Moolenbroek 				if (buf[0] != 'B') e(0);
1990*3ba6090fSDavid van Moolenbroek 				if (len != sizeof(sin6)) e(0);
1991*3ba6090fSDavid van Moolenbroek 
1992*3ba6090fSDavid van Moolenbroek 				if (sin6.sin6_port != port) e(0);
1993*3ba6090fSDavid van Moolenbroek 				sin6.sin6_port = 0;
1994*3ba6090fSDavid van Moolenbroek 
1995*3ba6090fSDavid van Moolenbroek 				if (bp->flags & F_ANY)
1996*3ba6090fSDavid van Moolenbroek 					sin6p = cp->name;
1997*3ba6090fSDavid van Moolenbroek 				else
1998*3ba6090fSDavid van Moolenbroek 					sin6p = bp->name;
1999*3ba6090fSDavid van Moolenbroek 
2000*3ba6090fSDavid van Moolenbroek 				if (memcmp(&sin6, sin6p, sizeof(sin6)) != 0)
2001*3ba6090fSDavid van Moolenbroek 					e(0);
2002*3ba6090fSDavid van Moolenbroek 
2003*3ba6090fSDavid van Moolenbroek 				if (close(fd2) != 0) e(0);
2004*3ba6090fSDavid van Moolenbroek 			}
2005*3ba6090fSDavid van Moolenbroek 
2006*3ba6090fSDavid van Moolenbroek 			if (close(fd) != 0) e(0);
2007*3ba6090fSDavid van Moolenbroek 		}
2008*3ba6090fSDavid van Moolenbroek 	}
2009*3ba6090fSDavid van Moolenbroek 
2010*3ba6090fSDavid van Moolenbroek 	/*
2011*3ba6090fSDavid van Moolenbroek 	 * Test that scoped addresses actually work as expected.  For this we
2012*3ba6090fSDavid van Moolenbroek 	 * need two interfaces with assigned link-local addresses, one of which
2013*3ba6090fSDavid van Moolenbroek 	 * being the loopback interface.  Start by finding another one.
2014*3ba6090fSDavid van Moolenbroek 	 */
2015*3ba6090fSDavid van Moolenbroek 	if (getifaddrs(&ifa) != 0) e(0);
2016*3ba6090fSDavid van Moolenbroek 
2017*3ba6090fSDavid van Moolenbroek 	found = 0;
2018*3ba6090fSDavid van Moolenbroek 	for (ifp = ifa; ifp != NULL; ifp = ifp->ifa_next) {
2019*3ba6090fSDavid van Moolenbroek 		if (strcmp(ifp->ifa_name, LOOPBACK_IFNAME) == 0)
2020*3ba6090fSDavid van Moolenbroek 			continue;
2021*3ba6090fSDavid van Moolenbroek 
2022*3ba6090fSDavid van Moolenbroek 		if (!(ifp->ifa_flags & IFF_UP) || ifp->ifa_addr == NULL ||
2023*3ba6090fSDavid van Moolenbroek 		    ifp->ifa_addr->sa_family != AF_INET6)
2024*3ba6090fSDavid van Moolenbroek 			continue;
2025*3ba6090fSDavid van Moolenbroek 
2026*3ba6090fSDavid van Moolenbroek 		memcpy(&sin6, ifp->ifa_addr, sizeof(sin6));
2027*3ba6090fSDavid van Moolenbroek 
2028*3ba6090fSDavid van Moolenbroek 		if (!IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
2029*3ba6090fSDavid van Moolenbroek 			continue;
2030*3ba6090fSDavid van Moolenbroek 
2031*3ba6090fSDavid van Moolenbroek 		/*
2032*3ba6090fSDavid van Moolenbroek 		 * Not only the interface, but also the link has to be up for
2033*3ba6090fSDavid van Moolenbroek 		 * this to work.  lwIP will drop all packets, including those
2034*3ba6090fSDavid van Moolenbroek 		 * sent to locally assigned addresses, if the link is down.
2035*3ba6090fSDavid van Moolenbroek 		 * Of course, figuring out whether the interface link is down
2036*3ba6090fSDavid van Moolenbroek 		 * is by no means convenient, especially if we want to do it
2037*3ba6090fSDavid van Moolenbroek 		 * right (i.e., not rely on getifaddrs' address sorting).
2038*3ba6090fSDavid van Moolenbroek 		 */
2039*3ba6090fSDavid van Moolenbroek 		link_state = LINK_STATE_DOWN;
2040*3ba6090fSDavid van Moolenbroek 
2041*3ba6090fSDavid van Moolenbroek 		for (ifp2 = ifa; ifp2 != NULL; ifp2 = ifp2->ifa_next) {
2042*3ba6090fSDavid van Moolenbroek 			if (!strcmp(ifp2->ifa_name, ifp->ifa_name) &&
2043*3ba6090fSDavid van Moolenbroek 			    ifp2->ifa_addr != NULL &&
2044*3ba6090fSDavid van Moolenbroek 			    ifp2->ifa_addr->sa_family == AF_LINK &&
2045*3ba6090fSDavid van Moolenbroek 			    ifp2->ifa_data != NULL) {
2046*3ba6090fSDavid van Moolenbroek 				memcpy(&link_state, &((struct if_data *)
2047*3ba6090fSDavid van Moolenbroek 				    ifp2->ifa_data)->ifi_link_state,
2048*3ba6090fSDavid van Moolenbroek 				    sizeof(link_state));
2049*3ba6090fSDavid van Moolenbroek 
2050*3ba6090fSDavid van Moolenbroek 				break;
2051*3ba6090fSDavid van Moolenbroek 			}
2052*3ba6090fSDavid van Moolenbroek 		}
2053*3ba6090fSDavid van Moolenbroek 
2054*3ba6090fSDavid van Moolenbroek 		if (link_state == LINK_STATE_DOWN)
2055*3ba6090fSDavid van Moolenbroek 			continue;
2056*3ba6090fSDavid van Moolenbroek 
2057*3ba6090fSDavid van Moolenbroek 		/*
2058*3ba6090fSDavid van Moolenbroek 		 * In addition, the address has to be in a state where it can
2059*3ba6090fSDavid van Moolenbroek 		 * be used as source address.  In practice, that means it must
2060*3ba6090fSDavid van Moolenbroek 		 * not be in ND6 duplicated or tentative state.
2061*3ba6090fSDavid van Moolenbroek 		 */
2062*3ba6090fSDavid van Moolenbroek 		memset(&ifr, 0, sizeof(ifr));
2063*3ba6090fSDavid van Moolenbroek 		strlcpy(ifr.ifr_name, ifp->ifa_name, sizeof(ifr.ifr_name));
2064*3ba6090fSDavid van Moolenbroek 		memcpy(&ifr.ifr_addr, &sin6, sizeof(sin6));
2065*3ba6090fSDavid van Moolenbroek 
2066*3ba6090fSDavid van Moolenbroek 		if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) e(0);
2067*3ba6090fSDavid van Moolenbroek 
2068*3ba6090fSDavid van Moolenbroek 		if (ioctl(fd, SIOCGIFAFLAG_IN6, &ifr) != 0) e(0);
2069*3ba6090fSDavid van Moolenbroek 
2070*3ba6090fSDavid van Moolenbroek 		if (close(fd) != 0) e(0);
2071*3ba6090fSDavid van Moolenbroek 
2072*3ba6090fSDavid van Moolenbroek 		if (ifr.ifr_ifru.ifru_flags6 &
2073*3ba6090fSDavid van Moolenbroek 		    (IN6_IFF_DUPLICATED | IN6_IFF_TENTATIVE))
2074*3ba6090fSDavid van Moolenbroek 			continue;
2075*3ba6090fSDavid van Moolenbroek 
2076*3ba6090fSDavid van Moolenbroek 		/* Compensate for poor decisions made by the KAME project. */
2077*3ba6090fSDavid van Moolenbroek 		inet6_getscopeid(&sin6, INET6_IS_ADDR_LINKLOCAL);
2078*3ba6090fSDavid van Moolenbroek 
2079*3ba6090fSDavid van Moolenbroek 		if (sin6.sin6_scope_id == 0 || sin6.sin6_scope_id == ifindex)
2080*3ba6090fSDavid van Moolenbroek 			e(0);
2081*3ba6090fSDavid van Moolenbroek 
2082*3ba6090fSDavid van Moolenbroek 		found = 1;
2083*3ba6090fSDavid van Moolenbroek 
2084*3ba6090fSDavid van Moolenbroek 		break;
2085*3ba6090fSDavid van Moolenbroek 	}
2086*3ba6090fSDavid van Moolenbroek 
2087*3ba6090fSDavid van Moolenbroek 	freeifaddrs(ifa);
2088*3ba6090fSDavid van Moolenbroek 
2089*3ba6090fSDavid van Moolenbroek 	/*
2090*3ba6090fSDavid van Moolenbroek 	 * If no second interface with a link-local address was found, we
2091*3ba6090fSDavid van Moolenbroek 	 * cannot perform the rest of this subtest.
2092*3ba6090fSDavid van Moolenbroek 	 */
2093*3ba6090fSDavid van Moolenbroek 	if (!found)
2094*3ba6090fSDavid van Moolenbroek 		return;
2095*3ba6090fSDavid van Moolenbroek 
2096*3ba6090fSDavid van Moolenbroek 	/*
2097*3ba6090fSDavid van Moolenbroek 	 * Create one socket that binds to the link-local address of the
2098*3ba6090fSDavid van Moolenbroek 	 * non-loopback interface.  The main goal of this subtest is to ensure
2099*3ba6090fSDavid van Moolenbroek 	 * that traffic directed to that same link-local address but with the
2100*3ba6090fSDavid van Moolenbroek 	 * loopback scope ID does not arrive on this socket.
2101*3ba6090fSDavid van Moolenbroek 	 */
2102*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, type, protocol)) < 0) e(0);
2103*3ba6090fSDavid van Moolenbroek 
2104*3ba6090fSDavid van Moolenbroek 	if (bind(fd, (struct sockaddr *)&sin6, sizeof(sin6)) != 0) e(0);
2105*3ba6090fSDavid van Moolenbroek 
2106*3ba6090fSDavid van Moolenbroek 	len = sizeof(sin6);
2107*3ba6090fSDavid van Moolenbroek 	if (getsockname(fd, (struct sockaddr *)&sin6, &len) != 0) e(0);
2108*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(sin6)) e(0);
2109*3ba6090fSDavid van Moolenbroek 
2110*3ba6090fSDavid van Moolenbroek 	ifindex2 = sin6.sin6_scope_id;
2111*3ba6090fSDavid van Moolenbroek 
2112*3ba6090fSDavid van Moolenbroek 	if (type == SOCK_STREAM) {
2113*3ba6090fSDavid van Moolenbroek 		if (listen(fd, 2) != 0) e(0);
2114*3ba6090fSDavid van Moolenbroek 
2115*3ba6090fSDavid van Moolenbroek 		if ((fd2 = socket(AF_INET6, type, protocol)) < 0) e(0);
2116*3ba6090fSDavid van Moolenbroek 
2117*3ba6090fSDavid van Moolenbroek 		/* Connecting to the loopback-scope address should time out. */
2118*3ba6090fSDavid van Moolenbroek 		signal(SIGALRM, socklib_got_signal);
2119*3ba6090fSDavid van Moolenbroek 		alarm(1);
2120*3ba6090fSDavid van Moolenbroek 
2121*3ba6090fSDavid van Moolenbroek 		sin6.sin6_scope_id = ifindex;
2122*3ba6090fSDavid van Moolenbroek 
2123*3ba6090fSDavid van Moolenbroek 		if (connect(fd2, (struct sockaddr *)&sin6, sizeof(sin6)) != -1)
2124*3ba6090fSDavid van Moolenbroek 			e(0);
2125*3ba6090fSDavid van Moolenbroek 
2126*3ba6090fSDavid van Moolenbroek 		if (errno != EINTR) e(0);
2127*3ba6090fSDavid van Moolenbroek 
2128*3ba6090fSDavid van Moolenbroek 		if (close(fd2) != 0) e(0);
2129*3ba6090fSDavid van Moolenbroek 
2130*3ba6090fSDavid van Moolenbroek 		/* Connecting to the real interface's address should work. */
2131*3ba6090fSDavid van Moolenbroek 		if ((fd2 = socket(AF_INET6, type, protocol)) < 0) e(0);
2132*3ba6090fSDavid van Moolenbroek 
2133*3ba6090fSDavid van Moolenbroek 		sin6.sin6_scope_id = ifindex2;
2134*3ba6090fSDavid van Moolenbroek 
2135*3ba6090fSDavid van Moolenbroek 		if (connect(fd2, (struct sockaddr *)&sin6, sizeof(sin6)) != 0)
2136*3ba6090fSDavid van Moolenbroek 			e(0);
2137*3ba6090fSDavid van Moolenbroek 
2138*3ba6090fSDavid van Moolenbroek 		if (close(fd2) != 0) e(0);
2139*3ba6090fSDavid van Moolenbroek 	} else {
2140*3ba6090fSDavid van Moolenbroek 		/*
2141*3ba6090fSDavid van Moolenbroek 		 * First connect+send.  Sending to the loopback-scope address
2142*3ba6090fSDavid van Moolenbroek 		 * should result in a rejected packet.
2143*3ba6090fSDavid van Moolenbroek 		 */
2144*3ba6090fSDavid van Moolenbroek 		if ((fd2 = socket(AF_INET6, type, protocol)) < 0) e(0);
2145*3ba6090fSDavid van Moolenbroek 
2146*3ba6090fSDavid van Moolenbroek 		sin6.sin6_scope_id = ifindex;
2147*3ba6090fSDavid van Moolenbroek 
2148*3ba6090fSDavid van Moolenbroek 		if (connect(fd2, (struct sockaddr *)&sin6, sizeof(sin6)) != 0)
2149*3ba6090fSDavid van Moolenbroek 			e(0);
2150*3ba6090fSDavid van Moolenbroek 
2151*3ba6090fSDavid van Moolenbroek 		if (send(fd2, "C", 1, 0) != -1) e(0);
2152*3ba6090fSDavid van Moolenbroek 		if (errno != EHOSTUNREACH) e(0);
2153*3ba6090fSDavid van Moolenbroek 
2154*3ba6090fSDavid van Moolenbroek 		if (close(fd2) != 0) e(0);
2155*3ba6090fSDavid van Moolenbroek 
2156*3ba6090fSDavid van Moolenbroek 		/* Sending to the real-interface address should work. */
2157*3ba6090fSDavid van Moolenbroek 		if ((fd2 = socket(AF_INET6, type, protocol)) < 0) e(0);
2158*3ba6090fSDavid van Moolenbroek 
2159*3ba6090fSDavid van Moolenbroek 		sin6.sin6_scope_id = ifindex2;
2160*3ba6090fSDavid van Moolenbroek 
2161*3ba6090fSDavid van Moolenbroek 		if (connect(fd2, (struct sockaddr *)&sin6, sizeof(sin6)) != 0)
2162*3ba6090fSDavid van Moolenbroek 			e(0);
2163*3ba6090fSDavid van Moolenbroek 
2164*3ba6090fSDavid van Moolenbroek 		if (send(fd2, "D", 1, 0) != 1) e(0);
2165*3ba6090fSDavid van Moolenbroek 
2166*3ba6090fSDavid van Moolenbroek 		if (close(fd2) != 0) e(0);
2167*3ba6090fSDavid van Moolenbroek 
2168*3ba6090fSDavid van Moolenbroek 		/*
2169*3ba6090fSDavid van Moolenbroek 		 * Then sendto.  Sending to the loopback-scope address should
2170*3ba6090fSDavid van Moolenbroek 		 * result in a rejected packet.
2171*3ba6090fSDavid van Moolenbroek 		 */
2172*3ba6090fSDavid van Moolenbroek 		if ((fd2 = socket(AF_INET6, type, protocol)) < 0) e(0);
2173*3ba6090fSDavid van Moolenbroek 
2174*3ba6090fSDavid van Moolenbroek 		sin6.sin6_scope_id = ifindex;
2175*3ba6090fSDavid van Moolenbroek 
2176*3ba6090fSDavid van Moolenbroek 		if (sendto(fd2, "E", 1, 0, (struct sockaddr *)&sin6,
2177*3ba6090fSDavid van Moolenbroek 		    sizeof(sin6)) != -1) e(0);
2178*3ba6090fSDavid van Moolenbroek 		if (errno != EHOSTUNREACH) e(0);
2179*3ba6090fSDavid van Moolenbroek 
2180*3ba6090fSDavid van Moolenbroek 		if (close(fd2) != 0) e(0);
2181*3ba6090fSDavid van Moolenbroek 
2182*3ba6090fSDavid van Moolenbroek 		/* Sending to the real-interface address should work. */
2183*3ba6090fSDavid van Moolenbroek 		if ((fd2 = socket(AF_INET6, type, protocol)) < 0) e(0);
2184*3ba6090fSDavid van Moolenbroek 
2185*3ba6090fSDavid van Moolenbroek 		sin6.sin6_scope_id = ifindex2;
2186*3ba6090fSDavid van Moolenbroek 
2187*3ba6090fSDavid van Moolenbroek 		if (sendto(fd2, "F", 1, 0, (struct sockaddr *)&sin6,
2188*3ba6090fSDavid van Moolenbroek 		    sizeof(sin6)) != 1) e(0);
2189*3ba6090fSDavid van Moolenbroek 
2190*3ba6090fSDavid van Moolenbroek 		if (close(fd2) != 0) e(0);
2191*3ba6090fSDavid van Moolenbroek 
2192*3ba6090fSDavid van Moolenbroek 		len = sizeof(sin6);
2193*3ba6090fSDavid van Moolenbroek 		if (recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sin6,
2194*3ba6090fSDavid van Moolenbroek 		    &len) != 1) e(0);
2195*3ba6090fSDavid van Moolenbroek 		if (buf[0] != 'D') e(0);
2196*3ba6090fSDavid van Moolenbroek 
2197*3ba6090fSDavid van Moolenbroek 		if (recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sin6,
2198*3ba6090fSDavid van Moolenbroek 		    &len) != 1) e(0);
2199*3ba6090fSDavid van Moolenbroek 		if (buf[0] != 'F') e(0);
2200*3ba6090fSDavid van Moolenbroek 	}
2201*3ba6090fSDavid van Moolenbroek 
2202*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
2203*3ba6090fSDavid van Moolenbroek }
2204*3ba6090fSDavid van Moolenbroek 
2205*3ba6090fSDavid van Moolenbroek /*
2206*3ba6090fSDavid van Moolenbroek  * Test multicast support for the given socket type, which may be SOCK_DGRAM or
2207*3ba6090fSDavid van Moolenbroek  * SOCK_RAW.
2208*3ba6090fSDavid van Moolenbroek  */
2209*3ba6090fSDavid van Moolenbroek void
socklib_test_multicast(int type,int protocol)2210*3ba6090fSDavid van Moolenbroek socklib_test_multicast(int type, int protocol)
2211*3ba6090fSDavid van Moolenbroek {
2212*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in sinA, sinB, sin_array[3];
2213*3ba6090fSDavid van Moolenbroek 	struct sockaddr_in6 sin6A, sin6B, sin6_array[3];
2214*3ba6090fSDavid van Moolenbroek 	struct ip_mreq imr;
2215*3ba6090fSDavid van Moolenbroek 	struct ipv6_mreq ipv6mr;
2216*3ba6090fSDavid van Moolenbroek 	struct in6_pktinfo ipi6;
2217*3ba6090fSDavid van Moolenbroek 	struct iovec iov;
2218*3ba6090fSDavid van Moolenbroek 	struct msghdr msg;
2219*3ba6090fSDavid van Moolenbroek 	struct cmsghdr *cmsg;
2220*3ba6090fSDavid van Moolenbroek 	socklen_t len, hdrlen;
2221*3ba6090fSDavid van Moolenbroek 	unsigned int count, ifindex, ifindex2;
2222*3ba6090fSDavid van Moolenbroek 	union {
2223*3ba6090fSDavid van Moolenbroek 		struct cmsghdr cmsg;
2224*3ba6090fSDavid van Moolenbroek 		char buf[256];
2225*3ba6090fSDavid van Moolenbroek 	} control;
2226*3ba6090fSDavid van Moolenbroek 	char buf[sizeof(struct ip) + 1], *buf2, name[IF_NAMESIZE];
2227*3ba6090fSDavid van Moolenbroek 	uint8_t byte, ttl;
2228*3ba6090fSDavid van Moolenbroek 	int i, j, r, fd, fd2, val;
2229*3ba6090fSDavid van Moolenbroek 
2230*3ba6090fSDavid van Moolenbroek 	/*
2231*3ba6090fSDavid van Moolenbroek 	 * Start with testing join/leave mechanics, for both IPv4 and IPv6.
2232*3ba6090fSDavid van Moolenbroek 	 * Note that we cannot test specifying no interface along with a
2233*3ba6090fSDavid van Moolenbroek 	 * multicast address (except for scoped IPv6 addresses), because the
2234*3ba6090fSDavid van Moolenbroek 	 * auto-selected interface is likely a public one, and joining the
2235*3ba6090fSDavid van Moolenbroek 	 * group will thus create external traffic, which is generally
2236*3ba6090fSDavid van Moolenbroek 	 * something we want to avoid in the tests.
2237*3ba6090fSDavid van Moolenbroek 	 */
2238*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, type, protocol)) < 0) e(0);
2239*3ba6090fSDavid van Moolenbroek 
2240*3ba6090fSDavid van Moolenbroek 	memset(&imr, 0, sizeof(imr));
2241*3ba6090fSDavid van Moolenbroek 
2242*3ba6090fSDavid van Moolenbroek 	/* Basic join-leave combo. */
2243*3ba6090fSDavid van Moolenbroek 	imr.imr_multiaddr.s_addr = inet_addr(TEST_MULTICAST_IPV4);
2244*3ba6090fSDavid van Moolenbroek 	imr.imr_interface.s_addr = htonl(INADDR_LOOPBACK);
2245*3ba6090fSDavid van Moolenbroek 
2246*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
2247*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != 0) e(0);
2248*3ba6090fSDavid van Moolenbroek 
2249*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr,
2250*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != 0) e(0);
2251*3ba6090fSDavid van Moolenbroek 
2252*3ba6090fSDavid van Moolenbroek 	/* Joining the same multicast group twice is an error. */
2253*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
2254*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != 0) e(0);
2255*3ba6090fSDavid van Moolenbroek 
2256*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
2257*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != -1) e(0);
2258*3ba6090fSDavid van Moolenbroek 	if (errno != EEXIST) e(0);
2259*3ba6090fSDavid van Moolenbroek 
2260*3ba6090fSDavid van Moolenbroek 	/* If an interface address is specified, it must match an interface. */
2261*3ba6090fSDavid van Moolenbroek 	imr.imr_interface.s_addr = htonl(TEST_BLACKHOLE_IPV4);
2262*3ba6090fSDavid van Moolenbroek 
2263*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
2264*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != -1) e(0);
2265*3ba6090fSDavid van Moolenbroek 	if (errno != EADDRNOTAVAIL) e(0);
2266*3ba6090fSDavid van Moolenbroek 
2267*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr,
2268*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != -1) e(0);
2269*3ba6090fSDavid van Moolenbroek 	if (errno != EADDRNOTAVAIL) e(0);
2270*3ba6090fSDavid van Moolenbroek 
2271*3ba6090fSDavid van Moolenbroek 	/* The given multicast address must be an actual multicast address. */
2272*3ba6090fSDavid van Moolenbroek 	imr.imr_multiaddr.s_addr = htonl(INADDR_ANY);
2273*3ba6090fSDavid van Moolenbroek 	imr.imr_interface.s_addr = htonl(INADDR_LOOPBACK);
2274*3ba6090fSDavid van Moolenbroek 
2275*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
2276*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != -1) e(0);
2277*3ba6090fSDavid van Moolenbroek 	if (errno != EADDRNOTAVAIL) e(0);
2278*3ba6090fSDavid van Moolenbroek 
2279*3ba6090fSDavid van Moolenbroek 	imr.imr_multiaddr.s_addr = htonl(INADDR_LOOPBACK);
2280*3ba6090fSDavid van Moolenbroek 
2281*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
2282*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != -1) e(0);
2283*3ba6090fSDavid van Moolenbroek 	if (errno != EADDRNOTAVAIL) e(0);
2284*3ba6090fSDavid van Moolenbroek 
2285*3ba6090fSDavid van Moolenbroek 	/* Leaving a multicast group not joined is an error. */
2286*3ba6090fSDavid van Moolenbroek 	imr.imr_multiaddr.s_addr =
2287*3ba6090fSDavid van Moolenbroek 	    htonl(ntohl(inet_addr(TEST_MULTICAST_IPV4)) + 1);
2288*3ba6090fSDavid van Moolenbroek 
2289*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr,
2290*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != -1) e(0);
2291*3ba6090fSDavid van Moolenbroek 	if (errno != ESRCH) e(0);
2292*3ba6090fSDavid van Moolenbroek 
2293*3ba6090fSDavid van Moolenbroek 	/*
2294*3ba6090fSDavid van Moolenbroek 	 * When leaving a group, an interface address need not be specified,
2295*3ba6090fSDavid van Moolenbroek 	 * even if one was specified when joining.  As mentioned, we cannot
2296*3ba6090fSDavid van Moolenbroek 	 * test joining the same address on multiple interfaces, though.
2297*3ba6090fSDavid van Moolenbroek 	 */
2298*3ba6090fSDavid van Moolenbroek 	imr.imr_multiaddr.s_addr = inet_addr(TEST_MULTICAST_IPV4);
2299*3ba6090fSDavid van Moolenbroek 	imr.imr_interface.s_addr = htonl(INADDR_ANY);
2300*3ba6090fSDavid van Moolenbroek 
2301*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr,
2302*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != 0) e(0);
2303*3ba6090fSDavid van Moolenbroek 
2304*3ba6090fSDavid van Moolenbroek 	/* There must be a reasonable per-socket group membership limit. */
2305*3ba6090fSDavid van Moolenbroek 	imr.imr_interface.s_addr = htonl(INADDR_LOOPBACK);
2306*3ba6090fSDavid van Moolenbroek 
2307*3ba6090fSDavid van Moolenbroek 	for (count = 0; count < IP_MAX_MEMBERSHIPS + 1; count++) {
2308*3ba6090fSDavid van Moolenbroek 		imr.imr_multiaddr.s_addr =
2309*3ba6090fSDavid van Moolenbroek 		    htonl(ntohl(inet_addr(TEST_MULTICAST_IPV4)) + count);
2310*3ba6090fSDavid van Moolenbroek 
2311*3ba6090fSDavid van Moolenbroek 		r = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
2312*3ba6090fSDavid van Moolenbroek 		    sizeof(imr));
2313*3ba6090fSDavid van Moolenbroek 
2314*3ba6090fSDavid van Moolenbroek 		if (r != 0) {
2315*3ba6090fSDavid van Moolenbroek 			if (r != -1 || errno != ENOBUFS) e(0);
2316*3ba6090fSDavid van Moolenbroek 			break;
2317*3ba6090fSDavid van Moolenbroek 		}
2318*3ba6090fSDavid van Moolenbroek 	}
2319*3ba6090fSDavid van Moolenbroek 	if (count < 8 || count > IP_MAX_MEMBERSHIPS) e(0);
2320*3ba6090fSDavid van Moolenbroek 
2321*3ba6090fSDavid van Moolenbroek 	/* Test leaving a group at the start of the per-socket list. */
2322*3ba6090fSDavid van Moolenbroek 	imr.imr_multiaddr.s_addr =
2323*3ba6090fSDavid van Moolenbroek 	    htonl(ntohl(inet_addr(TEST_MULTICAST_IPV4)) + count - 1);
2324*3ba6090fSDavid van Moolenbroek 
2325*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr,
2326*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != 0) e(0);
2327*3ba6090fSDavid van Moolenbroek 
2328*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr,
2329*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != -1) e(0);
2330*3ba6090fSDavid van Moolenbroek 	if (errno != ESRCH) e(0);
2331*3ba6090fSDavid van Moolenbroek 
2332*3ba6090fSDavid van Moolenbroek 	/* Test leaving a group in the middle of the per-socket list. */
2333*3ba6090fSDavid van Moolenbroek 	imr.imr_multiaddr.s_addr =
2334*3ba6090fSDavid van Moolenbroek 	    htonl(ntohl(inet_addr(TEST_MULTICAST_IPV4)) + count / 2);
2335*3ba6090fSDavid van Moolenbroek 
2336*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr,
2337*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != 0) e(0);
2338*3ba6090fSDavid van Moolenbroek 
2339*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr,
2340*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != -1) e(0);
2341*3ba6090fSDavid van Moolenbroek 	if (errno != ESRCH) e(0);
2342*3ba6090fSDavid van Moolenbroek 
2343*3ba6090fSDavid van Moolenbroek 	/* Test leaving a group at the end of the per-socket list. */
2344*3ba6090fSDavid van Moolenbroek 	imr.imr_multiaddr.s_addr = inet_addr(TEST_MULTICAST_IPV4);
2345*3ba6090fSDavid van Moolenbroek 
2346*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr,
2347*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != 0) e(0);
2348*3ba6090fSDavid van Moolenbroek 
2349*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr,
2350*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != -1) e(0);
2351*3ba6090fSDavid van Moolenbroek 	if (errno != ESRCH) e(0);
2352*3ba6090fSDavid van Moolenbroek 
2353*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
2354*3ba6090fSDavid van Moolenbroek 
2355*3ba6090fSDavid van Moolenbroek 	/* Still basic join/leave mechanics.. on to IPv6.. */
2356*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, type, protocol)) < 0) e(0);
2357*3ba6090fSDavid van Moolenbroek 
2358*3ba6090fSDavid van Moolenbroek 	memset(&ipv6mr, 0, sizeof(ipv6mr));
2359*3ba6090fSDavid van Moolenbroek 
2360*3ba6090fSDavid van Moolenbroek 	/* Basic join-leave combo. */
2361*3ba6090fSDavid van Moolenbroek 	ifindex = if_nametoindex(LOOPBACK_IFNAME);
2362*3ba6090fSDavid van Moolenbroek 
2363*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6,
2364*3ba6090fSDavid van Moolenbroek 	    &ipv6mr.ipv6mr_multiaddr) != 1) e(0);
2365*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = ifindex;
2366*3ba6090fSDavid van Moolenbroek 
2367*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
2368*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
2369*3ba6090fSDavid van Moolenbroek 
2370*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &ipv6mr,
2371*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
2372*3ba6090fSDavid van Moolenbroek 
2373*3ba6090fSDavid van Moolenbroek 	/* Joining the same multicast group twice is an error. */
2374*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
2375*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
2376*3ba6090fSDavid van Moolenbroek 
2377*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
2378*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
2379*3ba6090fSDavid van Moolenbroek 	if (errno != EEXIST) e(0);
2380*3ba6090fSDavid van Moolenbroek 
2381*3ba6090fSDavid van Moolenbroek 	/* If an interface index is specified, it must be valid. */
2382*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = BAD_IFINDEX;
2383*3ba6090fSDavid van Moolenbroek 
2384*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
2385*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
2386*3ba6090fSDavid van Moolenbroek 	if (errno != ENXIO) e(0);
2387*3ba6090fSDavid van Moolenbroek 
2388*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &ipv6mr,
2389*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
2390*3ba6090fSDavid van Moolenbroek 	if (errno != ENXIO) e(0);
2391*3ba6090fSDavid van Moolenbroek 
2392*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = 0x80000000UL | ifindex;
2393*3ba6090fSDavid van Moolenbroek 
2394*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
2395*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
2396*3ba6090fSDavid van Moolenbroek 	if (errno != ENXIO) e(0);
2397*3ba6090fSDavid van Moolenbroek 
2398*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &ipv6mr,
2399*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
2400*3ba6090fSDavid van Moolenbroek 	if (errno != ENXIO) e(0);
2401*3ba6090fSDavid van Moolenbroek 
2402*3ba6090fSDavid van Moolenbroek 	/* The given multicast address must be an actual multicast address. */
2403*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = ifindex;
2404*3ba6090fSDavid van Moolenbroek 	memcpy(&ipv6mr.ipv6mr_multiaddr, &in6addr_any, sizeof(in6addr_any));
2405*3ba6090fSDavid van Moolenbroek 
2406*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
2407*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
2408*3ba6090fSDavid van Moolenbroek 	if (errno != EADDRNOTAVAIL) e(0);
2409*3ba6090fSDavid van Moolenbroek 
2410*3ba6090fSDavid van Moolenbroek 	memcpy(&ipv6mr.ipv6mr_multiaddr, &in6addr_loopback,
2411*3ba6090fSDavid van Moolenbroek 	    sizeof(in6addr_loopback));
2412*3ba6090fSDavid van Moolenbroek 
2413*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
2414*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
2415*3ba6090fSDavid van Moolenbroek 	if (errno != EADDRNOTAVAIL) e(0);
2416*3ba6090fSDavid van Moolenbroek 
2417*3ba6090fSDavid van Moolenbroek 	/* Leaving a multicast group not joined is an error. */
2418*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6,
2419*3ba6090fSDavid van Moolenbroek 	    &ipv6mr.ipv6mr_multiaddr) != 1) e(0);
2420*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_multiaddr.s6_addr[15]++;
2421*3ba6090fSDavid van Moolenbroek 
2422*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &ipv6mr,
2423*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
2424*3ba6090fSDavid van Moolenbroek 	if (errno != ESRCH) e(0);
2425*3ba6090fSDavid van Moolenbroek 
2426*3ba6090fSDavid van Moolenbroek 	/*
2427*3ba6090fSDavid van Moolenbroek 	 * When leaving a group, an interface index need not be specified,
2428*3ba6090fSDavid van Moolenbroek 	 * even if one was specified when joining.  If one is specified, it
2429*3ba6090fSDavid van Moolenbroek 	 * must match, though.  As mentioned, we cannot test joining the same
2430*3ba6090fSDavid van Moolenbroek 	 * address on multiple interfaces, though.
2431*3ba6090fSDavid van Moolenbroek 	 */
2432*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_multiaddr.s6_addr[15]--;
2433*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = ifindex + 1; /* lazy: may or may not exist */
2434*3ba6090fSDavid van Moolenbroek 
2435*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &ipv6mr,
2436*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
2437*3ba6090fSDavid van Moolenbroek 	if (errno != ENXIO && errno != ESRCH) e(0);
2438*3ba6090fSDavid van Moolenbroek 
2439*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = 0;
2440*3ba6090fSDavid van Moolenbroek 
2441*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &ipv6mr,
2442*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
2443*3ba6090fSDavid van Moolenbroek 
2444*3ba6090fSDavid van Moolenbroek 	/* For link-local addresses, an interface must always be specified. */
2445*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6_LL,
2446*3ba6090fSDavid van Moolenbroek 	    &ipv6mr.ipv6mr_multiaddr) != 1) e(0);
2447*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = 0;
2448*3ba6090fSDavid van Moolenbroek 
2449*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
2450*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
2451*3ba6090fSDavid van Moolenbroek 	if (errno != EADDRNOTAVAIL) e(0);
2452*3ba6090fSDavid van Moolenbroek 
2453*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = ifindex;
2454*3ba6090fSDavid van Moolenbroek 
2455*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
2456*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
2457*3ba6090fSDavid van Moolenbroek 
2458*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = 0;
2459*3ba6090fSDavid van Moolenbroek 
2460*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &ipv6mr,
2461*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
2462*3ba6090fSDavid van Moolenbroek 	if (errno != EADDRNOTAVAIL) e(0);
2463*3ba6090fSDavid van Moolenbroek 
2464*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = ifindex;
2465*3ba6090fSDavid van Moolenbroek 
2466*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &ipv6mr,
2467*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
2468*3ba6090fSDavid van Moolenbroek 
2469*3ba6090fSDavid van Moolenbroek 	/* IPv4-mapped IPv6 multicast addresses are currently not supported. */
2470*3ba6090fSDavid van Moolenbroek 	val = 0;
2471*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)) != 0)
2472*3ba6090fSDavid van Moolenbroek 		e(0);
2473*3ba6090fSDavid van Moolenbroek 
2474*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, "::ffff:"TEST_MULTICAST_IPV4,
2475*3ba6090fSDavid van Moolenbroek 	    &ipv6mr.ipv6mr_multiaddr) != 1) e(0);
2476*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = ifindex;
2477*3ba6090fSDavid van Moolenbroek 
2478*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
2479*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
2480*3ba6090fSDavid van Moolenbroek 	if (errno != EADDRNOTAVAIL) e(0);
2481*3ba6090fSDavid van Moolenbroek 
2482*3ba6090fSDavid van Moolenbroek 	/*
2483*3ba6090fSDavid van Moolenbroek 	 * There must be a reasonable per-socket group membership limit.
2484*3ba6090fSDavid van Moolenbroek 	 * Apparently there is no IPv6 equivalent of IP_MAX_MEMBERSHIPS..
2485*3ba6090fSDavid van Moolenbroek 	 */
2486*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6,
2487*3ba6090fSDavid van Moolenbroek 	    &ipv6mr.ipv6mr_multiaddr) != 1) e(0);
2488*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = ifindex;
2489*3ba6090fSDavid van Moolenbroek 
2490*3ba6090fSDavid van Moolenbroek 	for (count = 0; count < IP_MAX_MEMBERSHIPS + 1; count++) {
2491*3ba6090fSDavid van Moolenbroek 		r = setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
2492*3ba6090fSDavid van Moolenbroek 		    sizeof(ipv6mr));
2493*3ba6090fSDavid van Moolenbroek 
2494*3ba6090fSDavid van Moolenbroek 		if (r != 0) {
2495*3ba6090fSDavid van Moolenbroek 			if (r != -1 || errno != ENOBUFS) e(0);
2496*3ba6090fSDavid van Moolenbroek 			break;
2497*3ba6090fSDavid van Moolenbroek 		}
2498*3ba6090fSDavid van Moolenbroek 
2499*3ba6090fSDavid van Moolenbroek 		ipv6mr.ipv6mr_multiaddr.s6_addr[15]++;
2500*3ba6090fSDavid van Moolenbroek 	}
2501*3ba6090fSDavid van Moolenbroek 	if (count < 8 || count > IP_MAX_MEMBERSHIPS) e(0);
2502*3ba6090fSDavid van Moolenbroek 
2503*3ba6090fSDavid van Moolenbroek 	/* Test leaving a group at the start of the per-socket list. */
2504*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_multiaddr.s6_addr[15]--;
2505*3ba6090fSDavid van Moolenbroek 
2506*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &ipv6mr,
2507*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
2508*3ba6090fSDavid van Moolenbroek 
2509*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &ipv6mr,
2510*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
2511*3ba6090fSDavid van Moolenbroek 	if (errno != ESRCH) e(0);
2512*3ba6090fSDavid van Moolenbroek 
2513*3ba6090fSDavid van Moolenbroek 	/* Test leaving a group in the middle of the per-socket list. */
2514*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_multiaddr.s6_addr[15] -= count / 2;
2515*3ba6090fSDavid van Moolenbroek 
2516*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &ipv6mr,
2517*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
2518*3ba6090fSDavid van Moolenbroek 
2519*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &ipv6mr,
2520*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
2521*3ba6090fSDavid van Moolenbroek 	if (errno != ESRCH) e(0);
2522*3ba6090fSDavid van Moolenbroek 
2523*3ba6090fSDavid van Moolenbroek 	/* Test leaving a group at the end of the per-socket list. */
2524*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6,
2525*3ba6090fSDavid van Moolenbroek 	    &ipv6mr.ipv6mr_multiaddr) != 1) e(0);
2526*3ba6090fSDavid van Moolenbroek 
2527*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &ipv6mr,
2528*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
2529*3ba6090fSDavid van Moolenbroek 
2530*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &ipv6mr,
2531*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
2532*3ba6090fSDavid van Moolenbroek 	if (errno != ESRCH) e(0);
2533*3ba6090fSDavid van Moolenbroek 
2534*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
2535*3ba6090fSDavid van Moolenbroek 
2536*3ba6090fSDavid van Moolenbroek 	/*
2537*3ba6090fSDavid van Moolenbroek 	 * Test sending multicast packets, multicast transmission options, and
2538*3ba6090fSDavid van Moolenbroek 	 * basic receipt.  Note that we cannot test IP(V6)_MULTICAST_LOOP
2539*3ba6090fSDavid van Moolenbroek 	 * because no extra duplicates are generated on loopback interfaces.
2540*3ba6090fSDavid van Moolenbroek 	 */
2541*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, type, protocol)) < 0) e(0);
2542*3ba6090fSDavid van Moolenbroek 
2543*3ba6090fSDavid van Moolenbroek 	/* For UDP, get an assigned port number. */
2544*3ba6090fSDavid van Moolenbroek 	memset(&sinA, 0, sizeof(sinA));
2545*3ba6090fSDavid van Moolenbroek 	sinA.sin_family = AF_INET;
2546*3ba6090fSDavid van Moolenbroek 
2547*3ba6090fSDavid van Moolenbroek 	if (type == SOCK_DGRAM) {
2548*3ba6090fSDavid van Moolenbroek 		sinA.sin_addr.s_addr = htonl(INADDR_ANY);
2549*3ba6090fSDavid van Moolenbroek 
2550*3ba6090fSDavid van Moolenbroek 		if (bind(fd, (struct sockaddr *)&sinA,
2551*3ba6090fSDavid van Moolenbroek 		    sizeof(sinA)) != 0) e(0);
2552*3ba6090fSDavid van Moolenbroek 
2553*3ba6090fSDavid van Moolenbroek 		len = sizeof(sinA);
2554*3ba6090fSDavid van Moolenbroek 		if (getsockname(fd, (struct sockaddr *)&sinA, &len) != 0) e(0);
2555*3ba6090fSDavid van Moolenbroek 	}
2556*3ba6090fSDavid van Moolenbroek 
2557*3ba6090fSDavid van Moolenbroek 	imr.imr_multiaddr.s_addr = inet_addr(TEST_MULTICAST_IPV4);
2558*3ba6090fSDavid van Moolenbroek 	imr.imr_interface.s_addr = htonl(INADDR_LOOPBACK);
2559*3ba6090fSDavid van Moolenbroek 
2560*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
2561*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != 0) e(0);
2562*3ba6090fSDavid van Moolenbroek 
2563*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET, type, protocol)) < 0) e(0);
2564*3ba6090fSDavid van Moolenbroek 
2565*3ba6090fSDavid van Moolenbroek 	/* Regular packet, default unicast TTL, sendto. */
2566*3ba6090fSDavid van Moolenbroek 	sinA.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
2567*3ba6090fSDavid van Moolenbroek 
2568*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, "A", 1, 0, (struct sockaddr *)&sinA,
2569*3ba6090fSDavid van Moolenbroek 	    sizeof(sinA)) != 1) e(0);
2570*3ba6090fSDavid van Moolenbroek 
2571*3ba6090fSDavid van Moolenbroek 	/* Multicast packet, default multicast TTL, sendto. */
2572*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IP, IP_MULTICAST_IF, &sinA.sin_addr,
2573*3ba6090fSDavid van Moolenbroek 	    sizeof(sinA.sin_addr)) != 0) e(0);
2574*3ba6090fSDavid van Moolenbroek 
2575*3ba6090fSDavid van Moolenbroek 	sinA.sin_addr.s_addr = inet_addr(TEST_MULTICAST_IPV4);
2576*3ba6090fSDavid van Moolenbroek 
2577*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, "B", 1, 0, (struct sockaddr *)&sinA,
2578*3ba6090fSDavid van Moolenbroek 	    sizeof(sinA)) != 1) e(0);
2579*3ba6090fSDavid van Moolenbroek 
2580*3ba6090fSDavid van Moolenbroek 	/* Multicast packet, custom multicast TTL, connect+send. */
2581*3ba6090fSDavid van Moolenbroek 	byte = 123;
2582*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IP, IP_MULTICAST_TTL, &byte,
2583*3ba6090fSDavid van Moolenbroek 	    sizeof(byte)) != 0) e(0);
2584*3ba6090fSDavid van Moolenbroek 
2585*3ba6090fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sinA, sizeof(sinA)) != 0) e(0);
2586*3ba6090fSDavid van Moolenbroek 
2587*3ba6090fSDavid van Moolenbroek 	if (send(fd2, "C", 1, 0) != 1) e(0);
2588*3ba6090fSDavid van Moolenbroek 
2589*3ba6090fSDavid van Moolenbroek 	/* Receive and validate what we sent. */
2590*3ba6090fSDavid van Moolenbroek 	len = sizeof(sinA);
2591*3ba6090fSDavid van Moolenbroek 	if (getsockname(fd2, (struct sockaddr *)&sinA, &len) != 0) e(0);
2592*3ba6090fSDavid van Moolenbroek 
2593*3ba6090fSDavid van Moolenbroek 	len = sizeof(ttl);
2594*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd2, IPPROTO_IP, IP_TTL, &ttl, &len) != 0) e(0);
2595*3ba6090fSDavid van Moolenbroek 
2596*3ba6090fSDavid van Moolenbroek 	val = 1;
2597*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &val, sizeof(val)) != 0)
2598*3ba6090fSDavid van Moolenbroek 		e(0);
2599*3ba6090fSDavid van Moolenbroek 
2600*3ba6090fSDavid van Moolenbroek 	hdrlen = (type == SOCK_RAW) ? sizeof(struct ip) : 0;
2601*3ba6090fSDavid van Moolenbroek 
2602*3ba6090fSDavid van Moolenbroek 	memset(&iov, 0, sizeof(iov));
2603*3ba6090fSDavid van Moolenbroek 	iov.iov_base = buf;
2604*3ba6090fSDavid van Moolenbroek 	iov.iov_len = hdrlen + 1;
2605*3ba6090fSDavid van Moolenbroek 
2606*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < 3; ) {
2607*3ba6090fSDavid van Moolenbroek 		memset(&msg, 0, sizeof(msg));
2608*3ba6090fSDavid van Moolenbroek 		msg.msg_name = &sinB;
2609*3ba6090fSDavid van Moolenbroek 		msg.msg_namelen = sizeof(sinB);
2610*3ba6090fSDavid van Moolenbroek 		msg.msg_iov = &iov;
2611*3ba6090fSDavid van Moolenbroek 		msg.msg_iovlen = 1;
2612*3ba6090fSDavid van Moolenbroek 		msg.msg_control = control.buf;
2613*3ba6090fSDavid van Moolenbroek 		msg.msg_controllen = sizeof(control);
2614*3ba6090fSDavid van Moolenbroek 
2615*3ba6090fSDavid van Moolenbroek 		r = recvmsg(fd, &msg, 0);
2616*3ba6090fSDavid van Moolenbroek 		if (r < 0) e(0);
2617*3ba6090fSDavid van Moolenbroek 
2618*3ba6090fSDavid van Moolenbroek 		if (msg.msg_namelen != sizeof(sinB)) e(0);
2619*3ba6090fSDavid van Moolenbroek 
2620*3ba6090fSDavid van Moolenbroek 		/*
2621*3ba6090fSDavid van Moolenbroek 		 * There is a tiny possibility that we receive other packets
2622*3ba6090fSDavid van Moolenbroek 		 * on the receiving socket, as it is not bound to a particular
2623*3ba6090fSDavid van Moolenbroek 		 * address, and there is currently no way to bind a socket to
2624*3ba6090fSDavid van Moolenbroek 		 * a particular interface.  We therefore skip packets not from
2625*3ba6090fSDavid van Moolenbroek 		 * the sending socket, conveniently testing the accuracy of the
2626*3ba6090fSDavid van Moolenbroek 		 * reported source address as a side effect.
2627*3ba6090fSDavid van Moolenbroek 		 */
2628*3ba6090fSDavid van Moolenbroek 		if (memcmp(&sinA, &sinB, sizeof(sinA)))
2629*3ba6090fSDavid van Moolenbroek 			continue;
2630*3ba6090fSDavid van Moolenbroek 
2631*3ba6090fSDavid van Moolenbroek 		if (r != hdrlen + 1) e(0);
2632*3ba6090fSDavid van Moolenbroek 		if (buf[hdrlen] != 'A' + i) e(0);
2633*3ba6090fSDavid van Moolenbroek 
2634*3ba6090fSDavid van Moolenbroek 		if (msg.msg_flags & MSG_BCAST) e(0);
2635*3ba6090fSDavid van Moolenbroek 
2636*3ba6090fSDavid van Moolenbroek 		if ((cmsg = CMSG_FIRSTHDR(&msg)) == NULL) e(0);
2637*3ba6090fSDavid van Moolenbroek 		if (cmsg->cmsg_level != IPPROTO_IP) e(0);
2638*3ba6090fSDavid van Moolenbroek 		if (cmsg->cmsg_type != IP_TTL) e(0);
2639*3ba6090fSDavid van Moolenbroek 		if (cmsg->cmsg_len != CMSG_LEN(sizeof(byte))) e(0);
2640*3ba6090fSDavid van Moolenbroek 		memcpy(&byte, CMSG_DATA(cmsg), sizeof(byte));
2641*3ba6090fSDavid van Moolenbroek 
2642*3ba6090fSDavid van Moolenbroek 		switch (i) {
2643*3ba6090fSDavid van Moolenbroek 		case 0:
2644*3ba6090fSDavid van Moolenbroek 			if (msg.msg_flags & MSG_MCAST) e(0);
2645*3ba6090fSDavid van Moolenbroek 			if (byte != ttl) e(0);
2646*3ba6090fSDavid van Moolenbroek 			break;
2647*3ba6090fSDavid van Moolenbroek 		case 1:
2648*3ba6090fSDavid van Moolenbroek 			if (!(msg.msg_flags & MSG_MCAST)) e(0);
2649*3ba6090fSDavid van Moolenbroek 			if (byte != 1) e(0);
2650*3ba6090fSDavid van Moolenbroek 			break;
2651*3ba6090fSDavid van Moolenbroek 		case 2:
2652*3ba6090fSDavid van Moolenbroek 			if (!(msg.msg_flags & MSG_MCAST)) e(0);
2653*3ba6090fSDavid van Moolenbroek 			if (byte != 123) e(0);
2654*3ba6090fSDavid van Moolenbroek 			break;
2655*3ba6090fSDavid van Moolenbroek 		}
2656*3ba6090fSDavid van Moolenbroek 
2657*3ba6090fSDavid van Moolenbroek 		i++;
2658*3ba6090fSDavid van Moolenbroek 	}
2659*3ba6090fSDavid van Moolenbroek 
2660*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
2661*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
2662*3ba6090fSDavid van Moolenbroek 
2663*3ba6090fSDavid van Moolenbroek 	/* Still the send tests, but now IPv6.. */
2664*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, type, protocol)) < 0) e(0);
2665*3ba6090fSDavid van Moolenbroek 
2666*3ba6090fSDavid van Moolenbroek 	/* For UDP, get an assigned port number. */
2667*3ba6090fSDavid van Moolenbroek 	memset(&sin6A, 0, sizeof(sin6A));
2668*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_family = AF_INET6;
2669*3ba6090fSDavid van Moolenbroek 
2670*3ba6090fSDavid van Moolenbroek 	if (type == SOCK_DGRAM) {
2671*3ba6090fSDavid van Moolenbroek 		if (bind(fd, (struct sockaddr *)&sin6A,
2672*3ba6090fSDavid van Moolenbroek 		    sizeof(sin6A)) != 0) e(0);
2673*3ba6090fSDavid van Moolenbroek 
2674*3ba6090fSDavid van Moolenbroek 		len = sizeof(sin6A);
2675*3ba6090fSDavid van Moolenbroek 		if (getsockname(fd, (struct sockaddr *)&sin6A, &len) != 0)
2676*3ba6090fSDavid van Moolenbroek 			e(0);
2677*3ba6090fSDavid van Moolenbroek 	}
2678*3ba6090fSDavid van Moolenbroek 
2679*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6B, &sin6A, sizeof(sin6B));
2680*3ba6090fSDavid van Moolenbroek 
2681*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6,
2682*3ba6090fSDavid van Moolenbroek 	    &ipv6mr.ipv6mr_multiaddr) != 1) e(0);
2683*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = ifindex;
2684*3ba6090fSDavid van Moolenbroek 
2685*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
2686*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
2687*3ba6090fSDavid van Moolenbroek 
2688*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET6, type, protocol)) < 0) e(0);
2689*3ba6090fSDavid van Moolenbroek 
2690*3ba6090fSDavid van Moolenbroek 	/* Regular packet, default unicast TTL, sendto. */
2691*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, LOOPBACK_IPV6_LL, &sin6A.sin6_addr) != 1) e(0);
2692*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_scope_id = ifindex;
2693*3ba6090fSDavid van Moolenbroek 
2694*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, "D", 1, 0, (struct sockaddr *)&sin6A,
2695*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != 1) e(0);
2696*3ba6090fSDavid van Moolenbroek 
2697*3ba6090fSDavid van Moolenbroek 	/* Multicast packet, default multicast TTL, sendto. */
2698*3ba6090fSDavid van Moolenbroek 	val = (int)ifindex;
2699*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val,
2700*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
2701*3ba6090fSDavid van Moolenbroek 
2702*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6,
2703*3ba6090fSDavid van Moolenbroek 	    &sin6A.sin6_addr) != 1) e(0);
2704*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_scope_id = 0;
2705*3ba6090fSDavid van Moolenbroek 
2706*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, "E", 1, 0, (struct sockaddr *)&sin6A,
2707*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != 1) e(0);
2708*3ba6090fSDavid van Moolenbroek 
2709*3ba6090fSDavid van Moolenbroek 	/* Multicast packet, custom multicast TTL, connect+send. */
2710*3ba6090fSDavid van Moolenbroek 	val = 125;
2711*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val,
2712*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
2713*3ba6090fSDavid van Moolenbroek 
2714*3ba6090fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sin6A, sizeof(sin6A)) != 0) e(0);
2715*3ba6090fSDavid van Moolenbroek 
2716*3ba6090fSDavid van Moolenbroek 	if (send(fd2, "F", 1, 0) != 1) e(0);
2717*3ba6090fSDavid van Moolenbroek 
2718*3ba6090fSDavid van Moolenbroek 	len = sizeof(sin6A);
2719*3ba6090fSDavid van Moolenbroek 	if (getsockname(fd2, (struct sockaddr *)&sin6A, &len) != 0) e(0);
2720*3ba6090fSDavid van Moolenbroek 
2721*3ba6090fSDavid van Moolenbroek 	/*
2722*3ba6090fSDavid van Moolenbroek 	 * Repeat the last two tests, but now with a link-local multicast
2723*3ba6090fSDavid van Moolenbroek 	 * address.  In particular link-local destination addresses do not need
2724*3ba6090fSDavid van Moolenbroek 	 * a zone ID, and the system should be smart enough to pick the right
2725*3ba6090fSDavid van Moolenbroek 	 * zone ID if an outgoing multicast interface is configured.  Zone
2726*3ba6090fSDavid van Moolenbroek 	 * violations should be detected and result in errors.
2727*3ba6090fSDavid van Moolenbroek 	 */
2728*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
2729*3ba6090fSDavid van Moolenbroek 
2730*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET6, type, protocol)) < 0) e(0);
2731*3ba6090fSDavid van Moolenbroek 
2732*3ba6090fSDavid van Moolenbroek 	if (bind(fd2, (struct sockaddr *)&sin6A, sizeof(sin6A)) != 0) e(0);
2733*3ba6090fSDavid van Moolenbroek 
2734*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6A, &sin6B, sizeof(sin6A));
2735*3ba6090fSDavid van Moolenbroek 
2736*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6_LL,
2737*3ba6090fSDavid van Moolenbroek 	    &ipv6mr.ipv6mr_multiaddr) != 1) e(0);
2738*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = ifindex;
2739*3ba6090fSDavid van Moolenbroek 
2740*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
2741*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
2742*3ba6090fSDavid van Moolenbroek 
2743*3ba6090fSDavid van Moolenbroek 	/* Link-local multicast packet, sendto. */
2744*3ba6090fSDavid van Moolenbroek 	val = (int)ifindex;
2745*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val,
2746*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
2747*3ba6090fSDavid van Moolenbroek 
2748*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6_LL,
2749*3ba6090fSDavid van Moolenbroek 	    &sin6A.sin6_addr) != 1) e(0);
2750*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_scope_id = 0;
2751*3ba6090fSDavid van Moolenbroek 
2752*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, "G", 1, 0, (struct sockaddr *)&sin6A,
2753*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != 1) e(0);
2754*3ba6090fSDavid van Moolenbroek 
2755*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_scope_id = ifindex + 1; /* lazy: may or may not be valid */
2756*3ba6090fSDavid van Moolenbroek 
2757*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, "X", 1, 0, (struct sockaddr *)&sin6A,
2758*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != -1) e(0);
2759*3ba6090fSDavid van Moolenbroek 	if (errno != ENXIO && errno != EHOSTUNREACH) e(0);
2760*3ba6090fSDavid van Moolenbroek 
2761*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_scope_id = ifindex;
2762*3ba6090fSDavid van Moolenbroek 
2763*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, "H", 1, 0, (struct sockaddr *)&sin6A,
2764*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != 1) e(0);
2765*3ba6090fSDavid van Moolenbroek 
2766*3ba6090fSDavid van Moolenbroek 	/* Link-local multicast packet, connect+send. */
2767*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_scope_id = 0;
2768*3ba6090fSDavid van Moolenbroek 
2769*3ba6090fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sin6A, sizeof(sin6A)) != 0) e(0);
2770*3ba6090fSDavid van Moolenbroek 
2771*3ba6090fSDavid van Moolenbroek 	if (send(fd2, "I", 1, 0) != 1) e(0);
2772*3ba6090fSDavid van Moolenbroek 
2773*3ba6090fSDavid van Moolenbroek 	len = sizeof(sin6A);
2774*3ba6090fSDavid van Moolenbroek 	if (getsockname(fd2, (struct sockaddr *)&sin6A, &len) != 0) e(0);
2775*3ba6090fSDavid van Moolenbroek 
2776*3ba6090fSDavid van Moolenbroek 	/* Receive and validate what we sent. */
2777*3ba6090fSDavid van Moolenbroek 	len = sizeof(val);
2778*3ba6090fSDavid van Moolenbroek 	if (getsockopt(fd2, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val,
2779*3ba6090fSDavid van Moolenbroek 	    &len) != 0) e(0);
2780*3ba6090fSDavid van Moolenbroek 	ttl = (uint8_t)val;
2781*3ba6090fSDavid van Moolenbroek 
2782*3ba6090fSDavid van Moolenbroek 	val = 1;
2783*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val,
2784*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
2785*3ba6090fSDavid van Moolenbroek 
2786*3ba6090fSDavid van Moolenbroek 	memset(&iov, 0, sizeof(iov));
2787*3ba6090fSDavid van Moolenbroek 	iov.iov_base = buf;
2788*3ba6090fSDavid van Moolenbroek 	iov.iov_len = 1;
2789*3ba6090fSDavid van Moolenbroek 
2790*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < 6; ) {
2791*3ba6090fSDavid van Moolenbroek 		memset(&msg, 0, sizeof(msg));
2792*3ba6090fSDavid van Moolenbroek 		msg.msg_name = &sin6B;
2793*3ba6090fSDavid van Moolenbroek 		msg.msg_namelen = sizeof(sin6B);
2794*3ba6090fSDavid van Moolenbroek 		msg.msg_iov = &iov;
2795*3ba6090fSDavid van Moolenbroek 		msg.msg_iovlen = 1;
2796*3ba6090fSDavid van Moolenbroek 		msg.msg_control = control.buf;
2797*3ba6090fSDavid van Moolenbroek 		msg.msg_controllen = sizeof(control);
2798*3ba6090fSDavid van Moolenbroek 
2799*3ba6090fSDavid van Moolenbroek 		r = recvmsg(fd, &msg, 0);
2800*3ba6090fSDavid van Moolenbroek 		if (r < 0) e(0);
2801*3ba6090fSDavid van Moolenbroek 
2802*3ba6090fSDavid van Moolenbroek 		if (msg.msg_namelen != sizeof(sin6B)) e(0);
2803*3ba6090fSDavid van Moolenbroek 
2804*3ba6090fSDavid van Moolenbroek 		if (memcmp(&sin6A, &sin6B, sizeof(sin6A)))
2805*3ba6090fSDavid van Moolenbroek 			continue;
2806*3ba6090fSDavid van Moolenbroek 
2807*3ba6090fSDavid van Moolenbroek 		if (r != 1) e(0);
2808*3ba6090fSDavid van Moolenbroek 		if (buf[0] != 'D' + i) e(0);
2809*3ba6090fSDavid van Moolenbroek 
2810*3ba6090fSDavid van Moolenbroek 		if (msg.msg_flags & MSG_BCAST) e(0);
2811*3ba6090fSDavid van Moolenbroek 
2812*3ba6090fSDavid van Moolenbroek 		if ((cmsg = CMSG_FIRSTHDR(&msg)) == NULL) e(0);
2813*3ba6090fSDavid van Moolenbroek 		if (cmsg->cmsg_level != IPPROTO_IPV6) e(0);
2814*3ba6090fSDavid van Moolenbroek 		if (cmsg->cmsg_type != IPV6_HOPLIMIT) e(0);
2815*3ba6090fSDavid van Moolenbroek 		if (cmsg->cmsg_len != CMSG_LEN(sizeof(val))) e(0);
2816*3ba6090fSDavid van Moolenbroek 		memcpy(&val, CMSG_DATA(cmsg), sizeof(val));
2817*3ba6090fSDavid van Moolenbroek 
2818*3ba6090fSDavid van Moolenbroek 		switch (i) {
2819*3ba6090fSDavid van Moolenbroek 		case 0:
2820*3ba6090fSDavid van Moolenbroek 			if (msg.msg_flags & MSG_MCAST) e(0);
2821*3ba6090fSDavid van Moolenbroek 			if (val != (int)ttl) e(0);
2822*3ba6090fSDavid van Moolenbroek 			break;
2823*3ba6090fSDavid van Moolenbroek 		case 1:
2824*3ba6090fSDavid van Moolenbroek 		case 3:
2825*3ba6090fSDavid van Moolenbroek 		case 4:
2826*3ba6090fSDavid van Moolenbroek 		case 5:
2827*3ba6090fSDavid van Moolenbroek 			if (!(msg.msg_flags & MSG_MCAST)) e(0);
2828*3ba6090fSDavid van Moolenbroek 			if (val != 1) e(0);
2829*3ba6090fSDavid van Moolenbroek 			break;
2830*3ba6090fSDavid van Moolenbroek 		case 2:
2831*3ba6090fSDavid van Moolenbroek 			if (!(msg.msg_flags & MSG_MCAST)) e(0);
2832*3ba6090fSDavid van Moolenbroek 			if (val != 125) e(0);
2833*3ba6090fSDavid van Moolenbroek 			break;
2834*3ba6090fSDavid van Moolenbroek 		}
2835*3ba6090fSDavid van Moolenbroek 
2836*3ba6090fSDavid van Moolenbroek 		i++;
2837*3ba6090fSDavid van Moolenbroek 	}
2838*3ba6090fSDavid van Moolenbroek 
2839*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
2840*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
2841*3ba6090fSDavid van Moolenbroek 
2842*3ba6090fSDavid van Moolenbroek 	/*
2843*3ba6090fSDavid van Moolenbroek 	 * Test receiving multicast packets on a bound socket.  We have already
2844*3ba6090fSDavid van Moolenbroek 	 * tested receiving packets on an unbound socket, so we need not
2845*3ba6090fSDavid van Moolenbroek 	 * incorporate that into this test as well.
2846*3ba6090fSDavid van Moolenbroek 	 */
2847*3ba6090fSDavid van Moolenbroek 	memset(sin_array, 0, sizeof(sin_array));
2848*3ba6090fSDavid van Moolenbroek 	sin_array[0].sin_family = AF_INET;
2849*3ba6090fSDavid van Moolenbroek 	sin_array[0].sin_addr.s_addr = htonl(INADDR_LOOPBACK);
2850*3ba6090fSDavid van Moolenbroek 	sin_array[1].sin_family = AF_INET;
2851*3ba6090fSDavid van Moolenbroek 	sin_array[1].sin_addr.s_addr = inet_addr(TEST_MULTICAST_IPV4);
2852*3ba6090fSDavid van Moolenbroek 	sin_array[2].sin_family = AF_INET;
2853*3ba6090fSDavid van Moolenbroek 	sin_array[2].sin_addr.s_addr =
2854*3ba6090fSDavid van Moolenbroek 	    htonl(ntohl(sin_array[1].sin_addr.s_addr) + 1);
2855*3ba6090fSDavid van Moolenbroek 
2856*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < __arraycount(sin_array); i++) {
2857*3ba6090fSDavid van Moolenbroek 		if ((fd = socket(AF_INET, type, protocol)) < 0) e(0);
2858*3ba6090fSDavid van Moolenbroek 
2859*3ba6090fSDavid van Moolenbroek 		if (bind(fd, (struct sockaddr *)&sin_array[i],
2860*3ba6090fSDavid van Moolenbroek 		    sizeof(sin_array[i])) != 0) e(0);
2861*3ba6090fSDavid van Moolenbroek 
2862*3ba6090fSDavid van Moolenbroek 		imr.imr_interface.s_addr = htonl(INADDR_LOOPBACK);
2863*3ba6090fSDavid van Moolenbroek 		memcpy(&imr.imr_multiaddr, &sin_array[1].sin_addr,
2864*3ba6090fSDavid van Moolenbroek 		    sizeof(imr.imr_multiaddr));
2865*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
2866*3ba6090fSDavid van Moolenbroek 		    sizeof(imr)) != 0) e(0);
2867*3ba6090fSDavid van Moolenbroek 
2868*3ba6090fSDavid van Moolenbroek 		memcpy(&imr.imr_multiaddr, &sin_array[2].sin_addr,
2869*3ba6090fSDavid van Moolenbroek 		    sizeof(imr.imr_multiaddr));
2870*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
2871*3ba6090fSDavid van Moolenbroek 		    sizeof(imr)) != 0) e(0);
2872*3ba6090fSDavid van Moolenbroek 
2873*3ba6090fSDavid van Moolenbroek 		len = sizeof(sinA);
2874*3ba6090fSDavid van Moolenbroek 		if (getsockname(fd, (struct sockaddr *)&sinA, &len) != 0) e(0);
2875*3ba6090fSDavid van Moolenbroek 
2876*3ba6090fSDavid van Moolenbroek 		if ((fd2 = socket(AF_INET, type, protocol)) < 0) e(0);
2877*3ba6090fSDavid van Moolenbroek 
2878*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd2, IPPROTO_IP, IP_MULTICAST_IF,
2879*3ba6090fSDavid van Moolenbroek 		    &imr.imr_interface, sizeof(imr.imr_interface)) != 0) e(0);
2880*3ba6090fSDavid van Moolenbroek 
2881*3ba6090fSDavid van Moolenbroek 		for (j = 0; j < __arraycount(sin_array); j++) {
2882*3ba6090fSDavid van Moolenbroek 			memcpy(&sinA.sin_addr, &sin_array[j].sin_addr,
2883*3ba6090fSDavid van Moolenbroek 			    sizeof(sinA.sin_addr));
2884*3ba6090fSDavid van Moolenbroek 
2885*3ba6090fSDavid van Moolenbroek 			byte = 'A' + j;
2886*3ba6090fSDavid van Moolenbroek 			if (sendto(fd2, &byte, sizeof(byte), 0,
2887*3ba6090fSDavid van Moolenbroek 			    (struct sockaddr *)&sinA,
2888*3ba6090fSDavid van Moolenbroek 			    sizeof(sinA)) != sizeof(byte)) e(0);
2889*3ba6090fSDavid van Moolenbroek 		}
2890*3ba6090fSDavid van Moolenbroek 
2891*3ba6090fSDavid van Moolenbroek 		if (recv(fd, buf, sizeof(buf), 0) !=
2892*3ba6090fSDavid van Moolenbroek 		    hdrlen + sizeof(byte)) e(0);
2893*3ba6090fSDavid van Moolenbroek 		if (buf[hdrlen] != 'A' + i) e(0);
2894*3ba6090fSDavid van Moolenbroek 
2895*3ba6090fSDavid van Moolenbroek 		if (recv(fd, buf, sizeof(buf), MSG_DONTWAIT) != -1) e(0);
2896*3ba6090fSDavid van Moolenbroek 		if (errno != EWOULDBLOCK) e(0);
2897*3ba6090fSDavid van Moolenbroek 
2898*3ba6090fSDavid van Moolenbroek 		if (close(fd2) != 0) e(0);
2899*3ba6090fSDavid van Moolenbroek 		if (close(fd) != 0) e(0);
2900*3ba6090fSDavid van Moolenbroek 	}
2901*3ba6090fSDavid van Moolenbroek 
2902*3ba6090fSDavid van Moolenbroek 	/* Still testing receiving on bound sockets, now IPv6.. */
2903*3ba6090fSDavid van Moolenbroek 	memset(sin6_array, 0, sizeof(sin6_array));
2904*3ba6090fSDavid van Moolenbroek 	sin6_array[0].sin6_family = AF_INET6;
2905*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6_array[0].sin6_addr, &in6addr_loopback,
2906*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6_array[0].sin6_addr));
2907*3ba6090fSDavid van Moolenbroek 	sin6_array[1].sin6_family = AF_INET6;
2908*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6,
2909*3ba6090fSDavid van Moolenbroek 	    &sin6_array[1].sin6_addr) != 1) e(0);
2910*3ba6090fSDavid van Moolenbroek 	sin6_array[2].sin6_family = AF_INET6;
2911*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6_LL,
2912*3ba6090fSDavid van Moolenbroek 	    &sin6_array[2].sin6_addr) != 1) e(0);
2913*3ba6090fSDavid van Moolenbroek 
2914*3ba6090fSDavid van Moolenbroek 	/*
2915*3ba6090fSDavid van Moolenbroek 	 * As with unicast addresses, binding to link-local multicast addresses
2916*3ba6090fSDavid van Moolenbroek 	 * requires a proper zone ID.
2917*3ba6090fSDavid van Moolenbroek 	 */
2918*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, type, protocol)) < 0) e(0);
2919*3ba6090fSDavid van Moolenbroek 
2920*3ba6090fSDavid van Moolenbroek 	if (bind(fd, (struct sockaddr *)&sin6_array[2],
2921*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6_array[2])) != -1) e(0);
2922*3ba6090fSDavid van Moolenbroek 	if (errno != EADDRNOTAVAIL) e(0);
2923*3ba6090fSDavid van Moolenbroek 
2924*3ba6090fSDavid van Moolenbroek 	sin6_array[2].sin6_scope_id = BAD_IFINDEX;
2925*3ba6090fSDavid van Moolenbroek 
2926*3ba6090fSDavid van Moolenbroek 	if (bind(fd, (struct sockaddr *)&sin6_array[2],
2927*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6_array[2])) != -1) e(0);
2928*3ba6090fSDavid van Moolenbroek 	if (errno != ENXIO) e(0);
2929*3ba6090fSDavid van Moolenbroek 
2930*3ba6090fSDavid van Moolenbroek 	sin6_array[2].sin6_scope_id = ifindex;
2931*3ba6090fSDavid van Moolenbroek 
2932*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
2933*3ba6090fSDavid van Moolenbroek 
2934*3ba6090fSDavid van Moolenbroek 	for (i = 0; i < __arraycount(sin6_array); i++) {
2935*3ba6090fSDavid van Moolenbroek 		if ((fd = socket(AF_INET6, type, protocol)) < 0) e(0);
2936*3ba6090fSDavid van Moolenbroek 
2937*3ba6090fSDavid van Moolenbroek 		if (bind(fd, (struct sockaddr *)&sin6_array[i],
2938*3ba6090fSDavid van Moolenbroek 		    sizeof(sin6_array[i])) != 0) e(0);
2939*3ba6090fSDavid van Moolenbroek 
2940*3ba6090fSDavid van Moolenbroek 		ipv6mr.ipv6mr_interface = ifindex;
2941*3ba6090fSDavid van Moolenbroek 		memcpy(&ipv6mr.ipv6mr_multiaddr, &sin6_array[1].sin6_addr,
2942*3ba6090fSDavid van Moolenbroek 		    sizeof(ipv6mr.ipv6mr_multiaddr));
2943*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
2944*3ba6090fSDavid van Moolenbroek 		    sizeof(ipv6mr)) != 0) e(0);
2945*3ba6090fSDavid van Moolenbroek 
2946*3ba6090fSDavid van Moolenbroek 		memcpy(&ipv6mr.ipv6mr_multiaddr, &sin6_array[2].sin6_addr,
2947*3ba6090fSDavid van Moolenbroek 		    sizeof(ipv6mr.ipv6mr_multiaddr));
2948*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
2949*3ba6090fSDavid van Moolenbroek 		    sizeof(ipv6mr)) != 0) e(0);
2950*3ba6090fSDavid van Moolenbroek 
2951*3ba6090fSDavid van Moolenbroek 		len = sizeof(sin6A);
2952*3ba6090fSDavid van Moolenbroek 		if (getsockname(fd, (struct sockaddr *)&sin6A,
2953*3ba6090fSDavid van Moolenbroek 		    &len) != 0) e(0);
2954*3ba6090fSDavid van Moolenbroek 
2955*3ba6090fSDavid van Moolenbroek 		if ((fd2 = socket(AF_INET6, type, protocol)) < 0) e(0);
2956*3ba6090fSDavid van Moolenbroek 
2957*3ba6090fSDavid van Moolenbroek 		val = (int)ifindex;
2958*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd2, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val,
2959*3ba6090fSDavid van Moolenbroek 		    sizeof(val)) != 0) e(0);
2960*3ba6090fSDavid van Moolenbroek 
2961*3ba6090fSDavid van Moolenbroek 		for (j = 0; j < __arraycount(sin6_array); j++) {
2962*3ba6090fSDavid van Moolenbroek 			memcpy(&sin6A.sin6_addr, &sin6_array[j].sin6_addr,
2963*3ba6090fSDavid van Moolenbroek 			    sizeof(sin6A.sin6_addr));
2964*3ba6090fSDavid van Moolenbroek 
2965*3ba6090fSDavid van Moolenbroek 			byte = 'A' + j;
2966*3ba6090fSDavid van Moolenbroek 			if (sendto(fd2, &byte, sizeof(byte), 0,
2967*3ba6090fSDavid van Moolenbroek 			    (struct sockaddr *)&sin6A,
2968*3ba6090fSDavid van Moolenbroek 			    sizeof(sin6A)) != sizeof(byte)) e(0);
2969*3ba6090fSDavid van Moolenbroek 		}
2970*3ba6090fSDavid van Moolenbroek 
2971*3ba6090fSDavid van Moolenbroek 		if (recv(fd, buf, sizeof(buf), 0) != sizeof(byte)) e(0);
2972*3ba6090fSDavid van Moolenbroek 		if (buf[0] != 'A' + i) e(0);
2973*3ba6090fSDavid van Moolenbroek 
2974*3ba6090fSDavid van Moolenbroek 		if (recv(fd, buf, sizeof(buf), MSG_DONTWAIT) != -1) e(0);
2975*3ba6090fSDavid van Moolenbroek 		if (errno != EWOULDBLOCK) e(0);
2976*3ba6090fSDavid van Moolenbroek 
2977*3ba6090fSDavid van Moolenbroek 		if (close(fd2) != 0) e(0);
2978*3ba6090fSDavid van Moolenbroek 		if (close(fd) != 0) e(0);
2979*3ba6090fSDavid van Moolenbroek 	}
2980*3ba6090fSDavid van Moolenbroek 
2981*3ba6090fSDavid van Moolenbroek 	/*
2982*3ba6090fSDavid van Moolenbroek 	 * Now test *sending* on a socket bound to a multicast address.  The
2983*3ba6090fSDavid van Moolenbroek 	 * multicast address must not show up as the packet's source address.
2984*3ba6090fSDavid van Moolenbroek 	 * No actual multicast groups are involved here.
2985*3ba6090fSDavid van Moolenbroek 	 */
2986*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, type, protocol)) < 0) e(0);
2987*3ba6090fSDavid van Moolenbroek 
2988*3ba6090fSDavid van Moolenbroek 	if (bind(fd, (struct sockaddr *)&sin_array[1],
2989*3ba6090fSDavid van Moolenbroek 	    sizeof(sin_array[1])) != 0) e(0);
2990*3ba6090fSDavid van Moolenbroek 
2991*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET, type, protocol)) < 0) e(0);
2992*3ba6090fSDavid van Moolenbroek 
2993*3ba6090fSDavid van Moolenbroek 	if (bind(fd2, (struct sockaddr *)&sin_array[0],
2994*3ba6090fSDavid van Moolenbroek 	    sizeof(sin_array[0])) != 0) e(0);
2995*3ba6090fSDavid van Moolenbroek 
2996*3ba6090fSDavid van Moolenbroek 	len = sizeof(sinA);
2997*3ba6090fSDavid van Moolenbroek 	if (getsockname(fd2, (struct sockaddr *)&sinA, &len) != 0) e(0);
2998*3ba6090fSDavid van Moolenbroek 
2999*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, "D", 1, 0, (struct sockaddr *)&sinA, sizeof(sinA)) != 1)
3000*3ba6090fSDavid van Moolenbroek 		e(0);
3001*3ba6090fSDavid van Moolenbroek 
3002*3ba6090fSDavid van Moolenbroek 	len = sizeof(sinB);
3003*3ba6090fSDavid van Moolenbroek 	if (recvfrom(fd2, buf, sizeof(buf), 0, (struct sockaddr *)&sinB,
3004*3ba6090fSDavid van Moolenbroek 	    &len) != hdrlen + 1) e(0);
3005*3ba6090fSDavid van Moolenbroek 	if (buf[hdrlen] != 'D') e(0);
3006*3ba6090fSDavid van Moolenbroek 
3007*3ba6090fSDavid van Moolenbroek 	if (sinB.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) e(0);
3008*3ba6090fSDavid van Moolenbroek 
3009*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3010*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3011*3ba6090fSDavid van Moolenbroek 
3012*3ba6090fSDavid van Moolenbroek 	/* Sending from a bound socket, IPv6 version.. */
3013*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, type, protocol)) < 0) e(0);
3014*3ba6090fSDavid van Moolenbroek 
3015*3ba6090fSDavid van Moolenbroek 	if (bind(fd, (struct sockaddr *)&sin6_array[1],
3016*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6_array[1])) != 0) e(0);
3017*3ba6090fSDavid van Moolenbroek 
3018*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET6, type, protocol)) < 0) e(0);
3019*3ba6090fSDavid van Moolenbroek 
3020*3ba6090fSDavid van Moolenbroek 	if (bind(fd2, (struct sockaddr *)&sin6_array[0],
3021*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6_array[0])) != 0) e(0);
3022*3ba6090fSDavid van Moolenbroek 
3023*3ba6090fSDavid van Moolenbroek 	len = sizeof(sin6A);
3024*3ba6090fSDavid van Moolenbroek 	if (getsockname(fd2, (struct sockaddr *)&sin6A, &len) != 0) e(0);
3025*3ba6090fSDavid van Moolenbroek 
3026*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, "E", 1, 0, (struct sockaddr *)&sin6A,
3027*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != 1) e(0);
3028*3ba6090fSDavid van Moolenbroek 
3029*3ba6090fSDavid van Moolenbroek 	len = sizeof(sin6B);
3030*3ba6090fSDavid van Moolenbroek 	if (recvfrom(fd2, buf, sizeof(buf), 0, (struct sockaddr *)&sin6B,
3031*3ba6090fSDavid van Moolenbroek 	    &len) != 1) e(0);
3032*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'E') e(0);
3033*3ba6090fSDavid van Moolenbroek 
3034*3ba6090fSDavid van Moolenbroek 	if (!IN6_IS_ADDR_LOOPBACK(&sin6B.sin6_addr)) e(0);
3035*3ba6090fSDavid van Moolenbroek 
3036*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3037*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3038*3ba6090fSDavid van Moolenbroek 
3039*3ba6090fSDavid van Moolenbroek 	/*
3040*3ba6090fSDavid van Moolenbroek 	 * A quick, partial test to see if connecting to a particular address
3041*3ba6090fSDavid van Moolenbroek 	 * does not accidentally block packet receipt.  What we do not test is
3042*3ba6090fSDavid van Moolenbroek 	 * whether connecting does filter traffic from other sources.
3043*3ba6090fSDavid van Moolenbroek 	 */
3044*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, type, protocol)) < 0) e(0);
3045*3ba6090fSDavid van Moolenbroek 
3046*3ba6090fSDavid van Moolenbroek 	memset(&sinA, 0, sizeof(sinA));
3047*3ba6090fSDavid van Moolenbroek 	sinA.sin_family = AF_INET;
3048*3ba6090fSDavid van Moolenbroek 	sinA.sin_addr.s_addr = inet_addr(TEST_MULTICAST_IPV4);
3049*3ba6090fSDavid van Moolenbroek 
3050*3ba6090fSDavid van Moolenbroek 	if (bind(fd, (struct sockaddr *)&sinA, sizeof(sinA)) != 0) e(0);
3051*3ba6090fSDavid van Moolenbroek 
3052*3ba6090fSDavid van Moolenbroek 	len = sizeof(sinA);
3053*3ba6090fSDavid van Moolenbroek 	if (getsockname(fd, (struct sockaddr *)&sinA, &len) != 0) e(0);
3054*3ba6090fSDavid van Moolenbroek 
3055*3ba6090fSDavid van Moolenbroek 	imr.imr_interface.s_addr = htonl(INADDR_LOOPBACK);
3056*3ba6090fSDavid van Moolenbroek 	imr.imr_multiaddr.s_addr = sinA.sin_addr.s_addr;
3057*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
3058*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != 0) e(0);
3059*3ba6090fSDavid van Moolenbroek 
3060*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET, type, protocol)) < 0) e(0);
3061*3ba6090fSDavid van Moolenbroek 
3062*3ba6090fSDavid van Moolenbroek 	memset(&sinB, 0, sizeof(sinB));
3063*3ba6090fSDavid van Moolenbroek 	sinB.sin_family = AF_INET;
3064*3ba6090fSDavid van Moolenbroek 	sinB.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3065*3ba6090fSDavid van Moolenbroek 
3066*3ba6090fSDavid van Moolenbroek 	if (bind(fd2, (struct sockaddr *)&sinB, sizeof(sinB)) != 0) e(0);
3067*3ba6090fSDavid van Moolenbroek 
3068*3ba6090fSDavid van Moolenbroek 	len = sizeof(sinB);
3069*3ba6090fSDavid van Moolenbroek 	if (getsockname(fd2, (struct sockaddr *)&sinB, &len) != 0) e(0);
3070*3ba6090fSDavid van Moolenbroek 
3071*3ba6090fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&sinB, sizeof(sinB)) != 0) e(0);
3072*3ba6090fSDavid van Moolenbroek 
3073*3ba6090fSDavid van Moolenbroek 	/* Note that binding to a particular source address is not enough! */
3074*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IP, IP_MULTICAST_IF, &imr.imr_interface,
3075*3ba6090fSDavid van Moolenbroek 	    sizeof(imr.imr_interface)) != 0) e(0);
3076*3ba6090fSDavid van Moolenbroek 
3077*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, "F", 1, 0, (struct sockaddr *)&sinA,
3078*3ba6090fSDavid van Moolenbroek 	    sizeof(sinA)) != 1) e(0);
3079*3ba6090fSDavid van Moolenbroek 
3080*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), 0) != hdrlen + 1) e(0);
3081*3ba6090fSDavid van Moolenbroek 	if (buf[hdrlen] != 'F') e(0);
3082*3ba6090fSDavid van Moolenbroek 
3083*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3084*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3085*3ba6090fSDavid van Moolenbroek 
3086*3ba6090fSDavid van Moolenbroek 	/* Also try connecting with IPv6. */
3087*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, type, protocol)) < 0) e(0);
3088*3ba6090fSDavid van Moolenbroek 
3089*3ba6090fSDavid van Moolenbroek 	memset(&sin6A, 0, sizeof(sin6A));
3090*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_family = AF_INET6;
3091*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6_LL,
3092*3ba6090fSDavid van Moolenbroek 	    &sin6A.sin6_addr) != 1) e(0);
3093*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_scope_id = ifindex;
3094*3ba6090fSDavid van Moolenbroek 
3095*3ba6090fSDavid van Moolenbroek 	if (bind(fd, (struct sockaddr *)&sin6A, sizeof(sin6A)) != 0) e(0);
3096*3ba6090fSDavid van Moolenbroek 
3097*3ba6090fSDavid van Moolenbroek 	len = sizeof(sin6A);
3098*3ba6090fSDavid van Moolenbroek 	if (getsockname(fd, (struct sockaddr *)&sin6A, &len) != 0) e(0);
3099*3ba6090fSDavid van Moolenbroek 
3100*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = ifindex;
3101*3ba6090fSDavid van Moolenbroek 	memcpy(&ipv6mr.ipv6mr_multiaddr, &sin6A.sin6_addr,
3102*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr.ipv6mr_multiaddr));
3103*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
3104*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
3105*3ba6090fSDavid van Moolenbroek 
3106*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET6, type, protocol)) < 0) e(0);
3107*3ba6090fSDavid van Moolenbroek 
3108*3ba6090fSDavid van Moolenbroek 	memset(&sin6B, 0, sizeof(sin6B));
3109*3ba6090fSDavid van Moolenbroek 	sin6B.sin6_family = AF_INET6;
3110*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6B.sin6_addr, &in6addr_loopback, sizeof(sin6B.sin6_addr));
3111*3ba6090fSDavid van Moolenbroek 
3112*3ba6090fSDavid van Moolenbroek 	if (bind(fd2, (struct sockaddr *)&sin6B, sizeof(sin6B)) != 0) e(0);
3113*3ba6090fSDavid van Moolenbroek 
3114*3ba6090fSDavid van Moolenbroek 	len = sizeof(sin6B);
3115*3ba6090fSDavid van Moolenbroek 	if (getsockname(fd2, (struct sockaddr *)&sin6B, &len) != 0) e(0);
3116*3ba6090fSDavid van Moolenbroek 
3117*3ba6090fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&sin6B, sizeof(sin6B)) != 0) e(0);
3118*3ba6090fSDavid van Moolenbroek 
3119*3ba6090fSDavid van Moolenbroek 	/* Unlike with IPv4, here the interface is implied by the zone. */
3120*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, "G", 1, 0, (struct sockaddr *)&sin6A,
3121*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != 1) e(0);
3122*3ba6090fSDavid van Moolenbroek 
3123*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), 0) != 1) e(0);
3124*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'G') e(0);
3125*3ba6090fSDavid van Moolenbroek 
3126*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3127*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3128*3ba6090fSDavid van Moolenbroek 
3129*3ba6090fSDavid van Moolenbroek 	/*
3130*3ba6090fSDavid van Moolenbroek 	 * Test multiple receivers.  For UDP, we need to set the SO_REUSEADDR
3131*3ba6090fSDavid van Moolenbroek 	 * option on all sockets for this to be guaranteed to work.
3132*3ba6090fSDavid van Moolenbroek 	 */
3133*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, type, protocol)) < 0) e(0);
3134*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET, type, protocol)) < 0) e(0);
3135*3ba6090fSDavid van Moolenbroek 
3136*3ba6090fSDavid van Moolenbroek 	memset(&sinA, 0, sizeof(sinA));
3137*3ba6090fSDavid van Moolenbroek 	sinA.sin_family = AF_INET;
3138*3ba6090fSDavid van Moolenbroek 
3139*3ba6090fSDavid van Moolenbroek 	if (type == SOCK_DGRAM) {
3140*3ba6090fSDavid van Moolenbroek 		if (bind(fd, (struct sockaddr *)&sinA, sizeof(sinA)) != 0)
3141*3ba6090fSDavid van Moolenbroek 			e(0);
3142*3ba6090fSDavid van Moolenbroek 
3143*3ba6090fSDavid van Moolenbroek 		len = sizeof(sinA);
3144*3ba6090fSDavid van Moolenbroek 		if (getsockname(fd, (struct sockaddr *)&sinA, &len) != 0)
3145*3ba6090fSDavid van Moolenbroek 			e(0);
3146*3ba6090fSDavid van Moolenbroek 
3147*3ba6090fSDavid van Moolenbroek 		val = 1;
3148*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
3149*3ba6090fSDavid van Moolenbroek 		    sizeof(val)) != 0) e(0);
3150*3ba6090fSDavid van Moolenbroek 
3151*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR, &val,
3152*3ba6090fSDavid van Moolenbroek 		    sizeof(val)) != 0) e(0);
3153*3ba6090fSDavid van Moolenbroek 
3154*3ba6090fSDavid van Moolenbroek 		if (bind(fd2, (struct sockaddr *)&sinA, sizeof(sinA)) != 0)
3155*3ba6090fSDavid van Moolenbroek 			e(0);
3156*3ba6090fSDavid van Moolenbroek 	}
3157*3ba6090fSDavid van Moolenbroek 
3158*3ba6090fSDavid van Moolenbroek 	imr.imr_multiaddr.s_addr = inet_addr(TEST_MULTICAST_IPV4);
3159*3ba6090fSDavid van Moolenbroek 	imr.imr_interface.s_addr = htonl(INADDR_LOOPBACK);
3160*3ba6090fSDavid van Moolenbroek 
3161*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
3162*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != 0) e(0);
3163*3ba6090fSDavid van Moolenbroek 
3164*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
3165*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != 0) e(0);
3166*3ba6090fSDavid van Moolenbroek 
3167*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &imr.imr_interface,
3168*3ba6090fSDavid van Moolenbroek 	    sizeof(imr.imr_interface)) != 0) e(0);
3169*3ba6090fSDavid van Moolenbroek 
3170*3ba6090fSDavid van Moolenbroek 	sinA.sin_addr.s_addr = imr.imr_multiaddr.s_addr;
3171*3ba6090fSDavid van Moolenbroek 
3172*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, "H", 1, 0, (struct sockaddr *)&sinA, sizeof(sinA)) != 1)
3173*3ba6090fSDavid van Moolenbroek 		e(0);
3174*3ba6090fSDavid van Moolenbroek 
3175*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), 0) != hdrlen + 1) e(0);
3176*3ba6090fSDavid van Moolenbroek 	if (buf[hdrlen] != 'H') e(0);
3177*3ba6090fSDavid van Moolenbroek 
3178*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf, sizeof(buf), 0) != hdrlen + 1) e(0);
3179*3ba6090fSDavid van Moolenbroek 	if (buf[hdrlen] != 'H') e(0);
3180*3ba6090fSDavid van Moolenbroek 
3181*3ba6090fSDavid van Moolenbroek 	/*
3182*3ba6090fSDavid van Moolenbroek 	 * Also test with a larger buffer, to ensure that packet duplication
3183*3ba6090fSDavid van Moolenbroek 	 * actually works properly.  As of writing, we need to patch lwIP to
3184*3ba6090fSDavid van Moolenbroek 	 * make this work at all.
3185*3ba6090fSDavid van Moolenbroek 	 */
3186*3ba6090fSDavid van Moolenbroek 	len = 8000;
3187*3ba6090fSDavid van Moolenbroek 	if ((buf2 = malloc(hdrlen + len + 1)) == NULL) e(0);
3188*3ba6090fSDavid van Moolenbroek 	buf2[len - 1] = 'I';
3189*3ba6090fSDavid van Moolenbroek 
3190*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, buf2, len, 0, (struct sockaddr *)&sinA,
3191*3ba6090fSDavid van Moolenbroek 	    sizeof(sinA)) != len) e(0);
3192*3ba6090fSDavid van Moolenbroek 
3193*3ba6090fSDavid van Moolenbroek 	buf2[hdrlen + len - 1] = '\0';
3194*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf2, hdrlen + len + 1, 0) != hdrlen + len) e(0);
3195*3ba6090fSDavid van Moolenbroek 	if (buf2[hdrlen + len - 1] != 'I') e(0);
3196*3ba6090fSDavid van Moolenbroek 
3197*3ba6090fSDavid van Moolenbroek 	buf2[hdrlen + len - 1] = '\0';
3198*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf2, hdrlen + len + 1, 0) != hdrlen + len) e(0);
3199*3ba6090fSDavid van Moolenbroek 	if (buf2[hdrlen + len - 1] != 'I') e(0);
3200*3ba6090fSDavid van Moolenbroek 
3201*3ba6090fSDavid van Moolenbroek 	free(buf2);
3202*3ba6090fSDavid van Moolenbroek 
3203*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3204*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3205*3ba6090fSDavid van Moolenbroek 
3206*3ba6090fSDavid van Moolenbroek 	/* Multiple-receivers test, IPv6 version. */
3207*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, type, protocol)) < 0) e(0);
3208*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET6, type, protocol)) < 0) e(0);
3209*3ba6090fSDavid van Moolenbroek 
3210*3ba6090fSDavid van Moolenbroek 	memset(&sin6A, 0, sizeof(sin6A));
3211*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_family = AF_INET6;
3212*3ba6090fSDavid van Moolenbroek 
3213*3ba6090fSDavid van Moolenbroek 	if (type == SOCK_DGRAM) {
3214*3ba6090fSDavid van Moolenbroek 		if (bind(fd, (struct sockaddr *)&sin6A, sizeof(sin6A)) != 0)
3215*3ba6090fSDavid van Moolenbroek 			e(0);
3216*3ba6090fSDavid van Moolenbroek 
3217*3ba6090fSDavid van Moolenbroek 		len = sizeof(sin6A);
3218*3ba6090fSDavid van Moolenbroek 		if (getsockname(fd, (struct sockaddr *)&sin6A, &len) != 0)
3219*3ba6090fSDavid van Moolenbroek 			e(0);
3220*3ba6090fSDavid van Moolenbroek 
3221*3ba6090fSDavid van Moolenbroek 		val = 1;
3222*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
3223*3ba6090fSDavid van Moolenbroek 		    sizeof(val)) != 0) e(0);
3224*3ba6090fSDavid van Moolenbroek 
3225*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR, &val,
3226*3ba6090fSDavid van Moolenbroek 		    sizeof(val)) != 0) e(0);
3227*3ba6090fSDavid van Moolenbroek 
3228*3ba6090fSDavid van Moolenbroek 		if (bind(fd2, (struct sockaddr *)&sin6A, sizeof(sin6A)) != 0)
3229*3ba6090fSDavid van Moolenbroek 			e(0);
3230*3ba6090fSDavid van Moolenbroek 	}
3231*3ba6090fSDavid van Moolenbroek 
3232*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6,
3233*3ba6090fSDavid van Moolenbroek 	    &ipv6mr.ipv6mr_multiaddr) != 1) e(0);
3234*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = ifindex;
3235*3ba6090fSDavid van Moolenbroek 
3236*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
3237*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
3238*3ba6090fSDavid van Moolenbroek 
3239*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
3240*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
3241*3ba6090fSDavid van Moolenbroek 
3242*3ba6090fSDavid van Moolenbroek 	val = (int)ifindex;
3243*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val,
3244*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
3245*3ba6090fSDavid van Moolenbroek 
3246*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6A.sin6_addr, &ipv6mr.ipv6mr_multiaddr,
3247*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A.sin6_addr));
3248*3ba6090fSDavid van Moolenbroek 
3249*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, "J", 1, 0, (struct sockaddr *)&sin6A,
3250*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != 1) e(0);
3251*3ba6090fSDavid van Moolenbroek 
3252*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), 0) != 1) e(0);
3253*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'J') e(0);
3254*3ba6090fSDavid van Moolenbroek 
3255*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf, sizeof(buf), 0) != 1) e(0);
3256*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'J') e(0);
3257*3ba6090fSDavid van Moolenbroek 
3258*3ba6090fSDavid van Moolenbroek 	len = 8000;
3259*3ba6090fSDavid van Moolenbroek 	if ((buf2 = malloc(len + 1)) == NULL) e(0);
3260*3ba6090fSDavid van Moolenbroek 	buf2[len - 1] = 'K';
3261*3ba6090fSDavid van Moolenbroek 
3262*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, buf2, len, 0, (struct sockaddr *)&sin6A,
3263*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != len) e(0);
3264*3ba6090fSDavid van Moolenbroek 
3265*3ba6090fSDavid van Moolenbroek 	buf2[len - 1] = '\0';
3266*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf2, len + 1, 0) != len) e(0);
3267*3ba6090fSDavid van Moolenbroek 	if (buf2[len - 1] != 'K') e(0);
3268*3ba6090fSDavid van Moolenbroek 
3269*3ba6090fSDavid van Moolenbroek 	buf2[len - 1] = '\0';
3270*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf2, len + 1, 0) != len) e(0);
3271*3ba6090fSDavid van Moolenbroek 	if (buf2[len - 1] != 'K') e(0);
3272*3ba6090fSDavid van Moolenbroek 
3273*3ba6090fSDavid van Moolenbroek 	free(buf2);
3274*3ba6090fSDavid van Moolenbroek 
3275*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3276*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3277*3ba6090fSDavid van Moolenbroek 
3278*3ba6090fSDavid van Moolenbroek 	/*
3279*3ba6090fSDavid van Moolenbroek 	 * Test proper multicast group departure.  This test relies on the fact
3280*3ba6090fSDavid van Moolenbroek 	 * that actual group membership is not checked on arrival of a
3281*3ba6090fSDavid van Moolenbroek 	 * multicast-destined packet, so that membership of one socket can be
3282*3ba6090fSDavid van Moolenbroek 	 * tested by another socket sending packets to itself while having
3283*3ba6090fSDavid van Moolenbroek 	 * joined a different group.  We test both explicit group departure
3284*3ba6090fSDavid van Moolenbroek 	 * and implicit departure on close.
3285*3ba6090fSDavid van Moolenbroek 	 */
3286*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET, type, protocol)) < 0) e(0);
3287*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET, type, protocol)) < 0) e(0);
3288*3ba6090fSDavid van Moolenbroek 
3289*3ba6090fSDavid van Moolenbroek 	memset(&sinA, 0, sizeof(sinA));
3290*3ba6090fSDavid van Moolenbroek 	sinA.sin_family = AF_INET;
3291*3ba6090fSDavid van Moolenbroek 
3292*3ba6090fSDavid van Moolenbroek 	if (type == SOCK_DGRAM) {
3293*3ba6090fSDavid van Moolenbroek 		if (bind(fd, (struct sockaddr *)&sinA, sizeof(sinA)) != 0)
3294*3ba6090fSDavid van Moolenbroek 			e(0);
3295*3ba6090fSDavid van Moolenbroek 
3296*3ba6090fSDavid van Moolenbroek 		len = sizeof(sinA);
3297*3ba6090fSDavid van Moolenbroek 		if (getsockname(fd, (struct sockaddr *)&sinA, &len) != 0)
3298*3ba6090fSDavid van Moolenbroek 			e(0);
3299*3ba6090fSDavid van Moolenbroek 
3300*3ba6090fSDavid van Moolenbroek 		val = 1;
3301*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
3302*3ba6090fSDavid van Moolenbroek 		    sizeof(val)) != 0) e(0);
3303*3ba6090fSDavid van Moolenbroek 
3304*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR, &val,
3305*3ba6090fSDavid van Moolenbroek 		    sizeof(val)) != 0) e(0);
3306*3ba6090fSDavid van Moolenbroek 
3307*3ba6090fSDavid van Moolenbroek 		if (bind(fd2, (struct sockaddr *)&sinA, sizeof(sinA)) != 0)
3308*3ba6090fSDavid van Moolenbroek 			e(0);
3309*3ba6090fSDavid van Moolenbroek 	}
3310*3ba6090fSDavid van Moolenbroek 
3311*3ba6090fSDavid van Moolenbroek 	imr.imr_multiaddr.s_addr = inet_addr(TEST_MULTICAST_IPV4);
3312*3ba6090fSDavid van Moolenbroek 	imr.imr_interface.s_addr = htonl(INADDR_LOOPBACK);
3313*3ba6090fSDavid van Moolenbroek 
3314*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
3315*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != 0) e(0);
3316*3ba6090fSDavid van Moolenbroek 
3317*3ba6090fSDavid van Moolenbroek 	imr.imr_multiaddr.s_addr = htonl(ntohl(imr.imr_multiaddr.s_addr) + 1);
3318*3ba6090fSDavid van Moolenbroek 
3319*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
3320*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != 0) e(0);
3321*3ba6090fSDavid van Moolenbroek 
3322*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &imr.imr_interface,
3323*3ba6090fSDavid van Moolenbroek 	    sizeof(imr.imr_interface)) != 0) e(0);
3324*3ba6090fSDavid van Moolenbroek 
3325*3ba6090fSDavid van Moolenbroek 	sinA.sin_addr.s_addr = imr.imr_multiaddr.s_addr;
3326*3ba6090fSDavid van Moolenbroek 
3327*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, "L", 1, 0, (struct sockaddr *)&sinA, sizeof(sinA)) != 1)
3328*3ba6090fSDavid van Moolenbroek 		e(0);
3329*3ba6090fSDavid van Moolenbroek 
3330*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf, sizeof(buf), 0) != hdrlen + 1) e(0);
3331*3ba6090fSDavid van Moolenbroek 	if (buf[hdrlen] != 'L') e(0);
3332*3ba6090fSDavid van Moolenbroek 
3333*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr,
3334*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != 0) e(0);
3335*3ba6090fSDavid van Moolenbroek 
3336*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, "M", 1, 0, (struct sockaddr *)&sinA, sizeof(sinA)) != 1)
3337*3ba6090fSDavid van Moolenbroek 		e(0);
3338*3ba6090fSDavid van Moolenbroek 
3339*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), 0) != hdrlen + 1) e(0);
3340*3ba6090fSDavid van Moolenbroek 	if (buf[hdrlen] != 'L') e(0);
3341*3ba6090fSDavid van Moolenbroek 
3342*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), MSG_DONTWAIT) != -1) e(0);
3343*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
3344*3ba6090fSDavid van Moolenbroek 
3345*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr,
3346*3ba6090fSDavid van Moolenbroek 	    sizeof(imr)) != 0) e(0);
3347*3ba6090fSDavid van Moolenbroek 
3348*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, "N", 1, 0, (struct sockaddr *)&sinA, sizeof(sinA)) != 1)
3349*3ba6090fSDavid van Moolenbroek 		e(0);
3350*3ba6090fSDavid van Moolenbroek 
3351*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf, sizeof(buf), 0) != hdrlen + 1) e(0);
3352*3ba6090fSDavid van Moolenbroek 	if (buf[hdrlen] != 'N') e(0);
3353*3ba6090fSDavid van Moolenbroek 
3354*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3355*3ba6090fSDavid van Moolenbroek 
3356*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, "O", 1, 0, (struct sockaddr *)&sinA, sizeof(sinA)) != 1)
3357*3ba6090fSDavid van Moolenbroek 		e(0);
3358*3ba6090fSDavid van Moolenbroek 
3359*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), 0) != hdrlen + 1) e(0);
3360*3ba6090fSDavid van Moolenbroek 	if (buf[hdrlen] != 'N') e(0);
3361*3ba6090fSDavid van Moolenbroek 
3362*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), MSG_DONTWAIT) != -1) e(0);
3363*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
3364*3ba6090fSDavid van Moolenbroek 
3365*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3366*3ba6090fSDavid van Moolenbroek 
3367*3ba6090fSDavid van Moolenbroek 	/* Multicast group departure, now IPv6.. this is getting boring. */
3368*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, type, protocol)) < 0) e(0);
3369*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET6, type, protocol)) < 0) e(0);
3370*3ba6090fSDavid van Moolenbroek 
3371*3ba6090fSDavid van Moolenbroek 	memset(&sin6A, 0, sizeof(sin6A));
3372*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_family = AF_INET6;
3373*3ba6090fSDavid van Moolenbroek 
3374*3ba6090fSDavid van Moolenbroek 	if (type == SOCK_DGRAM) {
3375*3ba6090fSDavid van Moolenbroek 		if (bind(fd, (struct sockaddr *)&sin6A, sizeof(sin6A)) != 0)
3376*3ba6090fSDavid van Moolenbroek 			e(0);
3377*3ba6090fSDavid van Moolenbroek 
3378*3ba6090fSDavid van Moolenbroek 		len = sizeof(sin6A);
3379*3ba6090fSDavid van Moolenbroek 		if (getsockname(fd, (struct sockaddr *)&sin6A, &len) != 0)
3380*3ba6090fSDavid van Moolenbroek 			e(0);
3381*3ba6090fSDavid van Moolenbroek 
3382*3ba6090fSDavid van Moolenbroek 		val = 1;
3383*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
3384*3ba6090fSDavid van Moolenbroek 		    sizeof(val)) != 0) e(0);
3385*3ba6090fSDavid van Moolenbroek 
3386*3ba6090fSDavid van Moolenbroek 		if (setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR, &val,
3387*3ba6090fSDavid van Moolenbroek 		    sizeof(val)) != 0) e(0);
3388*3ba6090fSDavid van Moolenbroek 
3389*3ba6090fSDavid van Moolenbroek 		if (bind(fd2, (struct sockaddr *)&sin6A, sizeof(sin6A)) != 0)
3390*3ba6090fSDavid van Moolenbroek 			e(0);
3391*3ba6090fSDavid van Moolenbroek 	}
3392*3ba6090fSDavid van Moolenbroek 
3393*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6,
3394*3ba6090fSDavid van Moolenbroek 	    &ipv6mr.ipv6mr_multiaddr) != 1) e(0);
3395*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = ifindex;
3396*3ba6090fSDavid van Moolenbroek 
3397*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
3398*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
3399*3ba6090fSDavid van Moolenbroek 
3400*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_multiaddr.s6_addr[15]++;
3401*3ba6090fSDavid van Moolenbroek 
3402*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
3403*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
3404*3ba6090fSDavid van Moolenbroek 
3405*3ba6090fSDavid van Moolenbroek 	val = (int)ifindex;
3406*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val,
3407*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
3408*3ba6090fSDavid van Moolenbroek 
3409*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6A.sin6_addr, &ipv6mr.ipv6mr_multiaddr,
3410*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A.sin6_addr));
3411*3ba6090fSDavid van Moolenbroek 
3412*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, "P", 1, 0, (struct sockaddr *)&sin6A,
3413*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != 1) e(0);
3414*3ba6090fSDavid van Moolenbroek 
3415*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf, sizeof(buf), 0) != 1) e(0);
3416*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'P') e(0);
3417*3ba6090fSDavid van Moolenbroek 
3418*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &ipv6mr,
3419*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
3420*3ba6090fSDavid van Moolenbroek 
3421*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, "Q", 1, 0, (struct sockaddr *)&sin6A,
3422*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != 1) e(0);
3423*3ba6090fSDavid van Moolenbroek 
3424*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), 0) != 1) e(0);
3425*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'P') e(0);
3426*3ba6090fSDavid van Moolenbroek 
3427*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), MSG_DONTWAIT) != -1) e(0);
3428*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
3429*3ba6090fSDavid van Moolenbroek 
3430*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
3431*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
3432*3ba6090fSDavid van Moolenbroek 
3433*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, "R", 1, 0, (struct sockaddr *)&sin6A,
3434*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != 1) e(0);
3435*3ba6090fSDavid van Moolenbroek 
3436*3ba6090fSDavid van Moolenbroek 	if (recv(fd2, buf, sizeof(buf), 0) != 1) e(0);
3437*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'R') e(0);
3438*3ba6090fSDavid van Moolenbroek 
3439*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3440*3ba6090fSDavid van Moolenbroek 
3441*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, "S", 1, 0, (struct sockaddr *)&sin6A,
3442*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != 1) e(0);
3443*3ba6090fSDavid van Moolenbroek 
3444*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), 0) != 1) e(0);
3445*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'R') e(0);
3446*3ba6090fSDavid van Moolenbroek 
3447*3ba6090fSDavid van Moolenbroek 	if (recv(fd, buf, sizeof(buf), MSG_DONTWAIT) != -1) e(0);
3448*3ba6090fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
3449*3ba6090fSDavid van Moolenbroek 
3450*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3451*3ba6090fSDavid van Moolenbroek 
3452*3ba6090fSDavid van Moolenbroek 	/*
3453*3ba6090fSDavid van Moolenbroek 	 * Lastly, some IPv6-only tests.
3454*3ba6090fSDavid van Moolenbroek 	 */
3455*3ba6090fSDavid van Moolenbroek 	/*
3456*3ba6090fSDavid van Moolenbroek 	 * Test that IPV6_PKTINFO overrides IPV6_MULTICAST_IF.  For this we
3457*3ba6090fSDavid van Moolenbroek 	 * need two valid interface indices.  If we cannot find a second one,
3458*3ba6090fSDavid van Moolenbroek 	 * simply test that the IPV6_PKTINFO information is used at all.
3459*3ba6090fSDavid van Moolenbroek 	 */
3460*3ba6090fSDavid van Moolenbroek 	for (ifindex2 = 1; ifindex2 < BAD_IFINDEX; ifindex2++) {
3461*3ba6090fSDavid van Moolenbroek 		if (if_indextoname(ifindex2, name) == NULL) {
3462*3ba6090fSDavid van Moolenbroek 			if (errno != ENXIO) e(0);
3463*3ba6090fSDavid van Moolenbroek 			continue;
3464*3ba6090fSDavid van Moolenbroek 		}
3465*3ba6090fSDavid van Moolenbroek 
3466*3ba6090fSDavid van Moolenbroek 		if (strcmp(name, LOOPBACK_IFNAME))
3467*3ba6090fSDavid van Moolenbroek 			break;
3468*3ba6090fSDavid van Moolenbroek 	}
3469*3ba6090fSDavid van Moolenbroek 
3470*3ba6090fSDavid van Moolenbroek 	if (ifindex2 == BAD_IFINDEX)
3471*3ba6090fSDavid van Moolenbroek 		ifindex2 = 0; /* too bad; fallback mode */
3472*3ba6090fSDavid van Moolenbroek 
3473*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, type, protocol)) < 0) e(0);
3474*3ba6090fSDavid van Moolenbroek 
3475*3ba6090fSDavid van Moolenbroek 	memset(&sin6A, 0, sizeof(sin6A));
3476*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_family = AF_INET6;
3477*3ba6090fSDavid van Moolenbroek 
3478*3ba6090fSDavid van Moolenbroek 	if (type == SOCK_DGRAM) {
3479*3ba6090fSDavid van Moolenbroek 		if (bind(fd, (struct sockaddr *)&sin6A, sizeof(sin6A)) != 0)
3480*3ba6090fSDavid van Moolenbroek 			e(0);
3481*3ba6090fSDavid van Moolenbroek 
3482*3ba6090fSDavid van Moolenbroek 		len = sizeof(sin6A);
3483*3ba6090fSDavid van Moolenbroek 		if (getsockname(fd, (struct sockaddr *)&sin6A, &len) != 0)
3484*3ba6090fSDavid van Moolenbroek 			e(0);
3485*3ba6090fSDavid van Moolenbroek 	}
3486*3ba6090fSDavid van Moolenbroek 
3487*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6_LL,
3488*3ba6090fSDavid van Moolenbroek 	    &ipv6mr.ipv6mr_multiaddr) != 1) e(0);
3489*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = ifindex;
3490*3ba6090fSDavid van Moolenbroek 
3491*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
3492*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != 0) e(0);
3493*3ba6090fSDavid van Moolenbroek 
3494*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET6, type, protocol)) < 0) e(0);
3495*3ba6090fSDavid van Moolenbroek 
3496*3ba6090fSDavid van Moolenbroek 	memcpy(&sin6A.sin6_addr, &ipv6mr.ipv6mr_multiaddr,
3497*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A.sin6_addr));
3498*3ba6090fSDavid van Moolenbroek 
3499*3ba6090fSDavid van Moolenbroek 	val = (int)ifindex2;
3500*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val,
3501*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
3502*3ba6090fSDavid van Moolenbroek 
3503*3ba6090fSDavid van Moolenbroek 	memset(&iov, 0, sizeof(iov));
3504*3ba6090fSDavid van Moolenbroek 	iov.iov_base = "T";
3505*3ba6090fSDavid van Moolenbroek 	iov.iov_len = 1;
3506*3ba6090fSDavid van Moolenbroek 
3507*3ba6090fSDavid van Moolenbroek 	memset(&ipi6, 0, sizeof(ipi6));
3508*3ba6090fSDavid van Moolenbroek 	memcpy(&ipi6.ipi6_addr, &in6addr_loopback, sizeof(ipi6.ipi6_addr));
3509*3ba6090fSDavid van Moolenbroek 	ipi6.ipi6_ifindex = ifindex;
3510*3ba6090fSDavid van Moolenbroek 
3511*3ba6090fSDavid van Moolenbroek 	control.cmsg.cmsg_len = CMSG_LEN(sizeof(ipi6));
3512*3ba6090fSDavid van Moolenbroek 	control.cmsg.cmsg_level = IPPROTO_IPV6;
3513*3ba6090fSDavid van Moolenbroek 	control.cmsg.cmsg_type = IPV6_PKTINFO;
3514*3ba6090fSDavid van Moolenbroek 	memcpy(CMSG_DATA(&control.cmsg), &ipi6, sizeof(ipi6));
3515*3ba6090fSDavid van Moolenbroek 
3516*3ba6090fSDavid van Moolenbroek 	memset(&msg, 0, sizeof(msg));
3517*3ba6090fSDavid van Moolenbroek 	msg.msg_name = &sin6A;
3518*3ba6090fSDavid van Moolenbroek 	msg.msg_namelen = sizeof(sin6A);
3519*3ba6090fSDavid van Moolenbroek 	msg.msg_iov = &iov;
3520*3ba6090fSDavid van Moolenbroek 	msg.msg_iovlen = 1;
3521*3ba6090fSDavid van Moolenbroek 	msg.msg_control = control.buf;
3522*3ba6090fSDavid van Moolenbroek 	msg.msg_controllen = control.cmsg.cmsg_len;
3523*3ba6090fSDavid van Moolenbroek 
3524*3ba6090fSDavid van Moolenbroek 	if (sendmsg(fd2, &msg, 0) != 1) e(0);
3525*3ba6090fSDavid van Moolenbroek 
3526*3ba6090fSDavid van Moolenbroek 	len = sizeof(sin6B);
3527*3ba6090fSDavid van Moolenbroek 	if (recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sin6B,
3528*3ba6090fSDavid van Moolenbroek 	    &len) != 1) e(0);
3529*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'T') e(0);
3530*3ba6090fSDavid van Moolenbroek 
3531*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(sin6B)) e(0);
3532*3ba6090fSDavid van Moolenbroek 	if (sin6B.sin6_len != sizeof(sin6B)) e(0);
3533*3ba6090fSDavid van Moolenbroek 	if (sin6B.sin6_family != AF_INET6) e(0);
3534*3ba6090fSDavid van Moolenbroek 	if (memcmp(&sin6B.sin6_addr, &in6addr_loopback,
3535*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6B.sin6_addr)) != 0) e(0);
3536*3ba6090fSDavid van Moolenbroek 
3537*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3538*3ba6090fSDavid van Moolenbroek 
3539*3ba6090fSDavid van Moolenbroek 	/* Repeat the same test, but now with a sticky IPV6_PKTINFO setting. */
3540*3ba6090fSDavid van Moolenbroek 	if ((fd2 = socket(AF_INET6, type, protocol)) < 0) e(0);
3541*3ba6090fSDavid van Moolenbroek 
3542*3ba6090fSDavid van Moolenbroek 	memset(&ipi6, 0, sizeof(ipi6));
3543*3ba6090fSDavid van Moolenbroek 	memcpy(&ipi6.ipi6_addr, &in6addr_loopback, sizeof(ipi6.ipi6_addr));
3544*3ba6090fSDavid van Moolenbroek 	ipi6.ipi6_ifindex = ifindex;
3545*3ba6090fSDavid van Moolenbroek 
3546*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IPV6, IPV6_PKTINFO, &ipi6,
3547*3ba6090fSDavid van Moolenbroek 	    sizeof(ipi6)) != 0) e(0);
3548*3ba6090fSDavid van Moolenbroek 
3549*3ba6090fSDavid van Moolenbroek 	val = (int)ifindex2;
3550*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd2, IPPROTO_IPV6, IPV6_MULTICAST_IF, &val,
3551*3ba6090fSDavid van Moolenbroek 	    sizeof(val)) != 0) e(0);
3552*3ba6090fSDavid van Moolenbroek 
3553*3ba6090fSDavid van Moolenbroek 	if (sendto(fd2, "U", 1, 0, (struct sockaddr *)&sin6A,
3554*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != 1) e(0);
3555*3ba6090fSDavid van Moolenbroek 
3556*3ba6090fSDavid van Moolenbroek 	len = sizeof(sin6B);
3557*3ba6090fSDavid van Moolenbroek 	if (recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sin6B,
3558*3ba6090fSDavid van Moolenbroek 	    &len) != 1) e(0);
3559*3ba6090fSDavid van Moolenbroek 	if (buf[0] != 'U') e(0);
3560*3ba6090fSDavid van Moolenbroek 
3561*3ba6090fSDavid van Moolenbroek 	if (len != sizeof(sin6B)) e(0);
3562*3ba6090fSDavid van Moolenbroek 	if (sin6B.sin6_len != sizeof(sin6B)) e(0);
3563*3ba6090fSDavid van Moolenbroek 	if (sin6B.sin6_family != AF_INET6) e(0);
3564*3ba6090fSDavid van Moolenbroek 	if (memcmp(&sin6B.sin6_addr, &in6addr_loopback,
3565*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6B.sin6_addr)) != 0) e(0);
3566*3ba6090fSDavid van Moolenbroek 
3567*3ba6090fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3568*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3569*3ba6090fSDavid van Moolenbroek 
3570*3ba6090fSDavid van Moolenbroek 	/*
3571*3ba6090fSDavid van Moolenbroek 	 * Test that invalid multicast addresses are not accepted anywhere.
3572*3ba6090fSDavid van Moolenbroek 	 */
3573*3ba6090fSDavid van Moolenbroek 	if ((fd = socket(AF_INET6, type, protocol)) < 0) e(0);
3574*3ba6090fSDavid van Moolenbroek 
3575*3ba6090fSDavid van Moolenbroek 	memset(&sin6A, 0, sizeof(sin6A));
3576*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_family = AF_INET6;
3577*3ba6090fSDavid van Moolenbroek 	if (inet_pton(AF_INET6, TEST_MULTICAST_IPV6_BAD,
3578*3ba6090fSDavid van Moolenbroek 	    &sin6A.sin6_addr) != 1) e(0);
3579*3ba6090fSDavid van Moolenbroek 
3580*3ba6090fSDavid van Moolenbroek 	if (bind(fd, (struct sockaddr *)&sin6A, sizeof(sin6A)) != -1) e(0);
3581*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
3582*3ba6090fSDavid van Moolenbroek 
3583*3ba6090fSDavid van Moolenbroek 	sin6A.sin6_port = htons(TEST_PORT_A);
3584*3ba6090fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&sin6A, sizeof(sin6A)) != -1) e(0);
3585*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
3586*3ba6090fSDavid van Moolenbroek 
3587*3ba6090fSDavid van Moolenbroek 	if (sendto(fd, "X", 1, 0, (struct sockaddr *)&sin6A,
3588*3ba6090fSDavid van Moolenbroek 	    sizeof(sin6A)) != -1) e(0);
3589*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
3590*3ba6090fSDavid van Moolenbroek 
3591*3ba6090fSDavid van Moolenbroek 	memcpy(&ipv6mr.ipv6mr_multiaddr, &sin6A.sin6_addr,
3592*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr.ipv6mr_multiaddr));
3593*3ba6090fSDavid van Moolenbroek 	ipv6mr.ipv6mr_interface = ifindex;
3594*3ba6090fSDavid van Moolenbroek 
3595*3ba6090fSDavid van Moolenbroek 	if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &ipv6mr,
3596*3ba6090fSDavid van Moolenbroek 	    sizeof(ipv6mr)) != -1) e(0);
3597*3ba6090fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
3598*3ba6090fSDavid van Moolenbroek 
3599*3ba6090fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3600*3ba6090fSDavid van Moolenbroek }
3601