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