1*3ba6090fSDavid van Moolenbroek /* Tests for network interfaces and routing (LWIP) - by D.C. van Moolenbroek */
2*3ba6090fSDavid van Moolenbroek /* This test needs to be run as root: it manipulates network settings. */
3*3ba6090fSDavid van Moolenbroek /*
4*3ba6090fSDavid van Moolenbroek * TODO: due to time constraints, this test is currently absolutely minimal.
5*3ba6090fSDavid van Moolenbroek * It does not yet test by far most of the service code it is supposed to test,
6*3ba6090fSDavid van Moolenbroek * in particular interface management code, interface address assignment code,
7*3ba6090fSDavid van Moolenbroek * routing sockets code, and routing code. The second subtest (test93b) in this
8*3ba6090fSDavid van Moolenbroek * file serves as a reasonable example of how many of the future subtests
9*3ba6090fSDavid van Moolenbroek * should operate, though: by issuing interface IOCTLs and routing commands on
10*3ba6090fSDavid van Moolenbroek * a loopback interface created for the occasion.
11*3ba6090fSDavid van Moolenbroek */
12*3ba6090fSDavid van Moolenbroek #include <stdlib.h>
13*3ba6090fSDavid van Moolenbroek #include <string.h>
14*3ba6090fSDavid van Moolenbroek #include <stddef.h>
15*3ba6090fSDavid van Moolenbroek #include <sys/socket.h>
16*3ba6090fSDavid van Moolenbroek #include <sys/ioctl.h>
17*3ba6090fSDavid van Moolenbroek #include <net/if.h>
18*3ba6090fSDavid van Moolenbroek #include <net/if_dl.h>
19*3ba6090fSDavid van Moolenbroek #include <net/route.h>
20*3ba6090fSDavid van Moolenbroek #include <netinet/in.h>
21*3ba6090fSDavid van Moolenbroek #include <netinet6/in6_var.h>
22*3ba6090fSDavid van Moolenbroek #include <arpa/inet.h>
23*3ba6090fSDavid van Moolenbroek
24*3ba6090fSDavid van Moolenbroek #include "common.h"
25*3ba6090fSDavid van Moolenbroek #include "socklib.h"
26*3ba6090fSDavid van Moolenbroek
27*3ba6090fSDavid van Moolenbroek #define TEST_IFNAME "lo93"
28*3ba6090fSDavid van Moolenbroek
29*3ba6090fSDavid van Moolenbroek #define ITERATIONS 2
30*3ba6090fSDavid van Moolenbroek
31*3ba6090fSDavid van Moolenbroek static const enum state rtlnk_states[] = {
32*3ba6090fSDavid van Moolenbroek S_NEW, S_N_SHUT_R, S_N_SHUT_W, S_N_SHUT_RW,
33*3ba6090fSDavid van Moolenbroek };
34*3ba6090fSDavid van Moolenbroek
35*3ba6090fSDavid van Moolenbroek static const int rt_results[][__arraycount(rtlnk_states)] = {
36*3ba6090fSDavid van Moolenbroek [C_ACCEPT] = {
37*3ba6090fSDavid van Moolenbroek -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
38*3ba6090fSDavid van Moolenbroek },
39*3ba6090fSDavid van Moolenbroek [C_BIND] = {
40*3ba6090fSDavid van Moolenbroek -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
41*3ba6090fSDavid van Moolenbroek },
42*3ba6090fSDavid van Moolenbroek [C_CONNECT] = {
43*3ba6090fSDavid van Moolenbroek -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
44*3ba6090fSDavid van Moolenbroek },
45*3ba6090fSDavid van Moolenbroek [C_GETPEERNAME] = {
46*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
47*3ba6090fSDavid van Moolenbroek },
48*3ba6090fSDavid van Moolenbroek [C_GETSOCKNAME] = {
49*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
50*3ba6090fSDavid van Moolenbroek },
51*3ba6090fSDavid van Moolenbroek [C_GETSOCKOPT_ERR] = {
52*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
53*3ba6090fSDavid van Moolenbroek },
54*3ba6090fSDavid van Moolenbroek [C_GETSOCKOPT_KA] = {
55*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
56*3ba6090fSDavid van Moolenbroek },
57*3ba6090fSDavid van Moolenbroek [C_GETSOCKOPT_RB] = {
58*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
59*3ba6090fSDavid van Moolenbroek },
60*3ba6090fSDavid van Moolenbroek [C_IOCTL_NREAD] = {
61*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
62*3ba6090fSDavid van Moolenbroek },
63*3ba6090fSDavid van Moolenbroek [C_LISTEN] = {
64*3ba6090fSDavid van Moolenbroek -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
65*3ba6090fSDavid van Moolenbroek },
66*3ba6090fSDavid van Moolenbroek [C_RECV] = {
67*3ba6090fSDavid van Moolenbroek -EAGAIN, 0, -EAGAIN, 0,
68*3ba6090fSDavid van Moolenbroek },
69*3ba6090fSDavid van Moolenbroek [C_RECVFROM] = {
70*3ba6090fSDavid van Moolenbroek -EAGAIN, 0, -EAGAIN, 0,
71*3ba6090fSDavid van Moolenbroek },
72*3ba6090fSDavid van Moolenbroek [C_SEND] = {
73*3ba6090fSDavid van Moolenbroek -ENOBUFS, -ENOBUFS, -EPIPE, -EPIPE,
74*3ba6090fSDavid van Moolenbroek },
75*3ba6090fSDavid van Moolenbroek [C_SENDTO] = {
76*3ba6090fSDavid van Moolenbroek -EISCONN, -EISCONN, -EPIPE, -EPIPE,
77*3ba6090fSDavid van Moolenbroek },
78*3ba6090fSDavid van Moolenbroek [C_SELECT_R] = {
79*3ba6090fSDavid van Moolenbroek 0, 1, 0, 1,
80*3ba6090fSDavid van Moolenbroek },
81*3ba6090fSDavid van Moolenbroek [C_SELECT_W] = {
82*3ba6090fSDavid van Moolenbroek 1, 1, 1, 1,
83*3ba6090fSDavid van Moolenbroek },
84*3ba6090fSDavid van Moolenbroek [C_SELECT_X] = {
85*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
86*3ba6090fSDavid van Moolenbroek },
87*3ba6090fSDavid van Moolenbroek [C_SETSOCKOPT_BC] = {
88*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
89*3ba6090fSDavid van Moolenbroek },
90*3ba6090fSDavid van Moolenbroek [C_SETSOCKOPT_KA] = {
91*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
92*3ba6090fSDavid van Moolenbroek },
93*3ba6090fSDavid van Moolenbroek [C_SETSOCKOPT_L] = {
94*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
95*3ba6090fSDavid van Moolenbroek },
96*3ba6090fSDavid van Moolenbroek [C_SETSOCKOPT_RA] = {
97*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
98*3ba6090fSDavid van Moolenbroek },
99*3ba6090fSDavid van Moolenbroek [C_SHUTDOWN_R] = {
100*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
101*3ba6090fSDavid van Moolenbroek },
102*3ba6090fSDavid van Moolenbroek [C_SHUTDOWN_RW] = {
103*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
104*3ba6090fSDavid van Moolenbroek },
105*3ba6090fSDavid van Moolenbroek [C_SHUTDOWN_W] = {
106*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
107*3ba6090fSDavid van Moolenbroek },
108*3ba6090fSDavid van Moolenbroek };
109*3ba6090fSDavid van Moolenbroek
110*3ba6090fSDavid van Moolenbroek static const int lnk_results[][__arraycount(rtlnk_states)] = {
111*3ba6090fSDavid van Moolenbroek [C_ACCEPT] = {
112*3ba6090fSDavid van Moolenbroek -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
113*3ba6090fSDavid van Moolenbroek },
114*3ba6090fSDavid van Moolenbroek [C_BIND] = {
115*3ba6090fSDavid van Moolenbroek -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
116*3ba6090fSDavid van Moolenbroek },
117*3ba6090fSDavid van Moolenbroek [C_CONNECT] = {
118*3ba6090fSDavid van Moolenbroek -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
119*3ba6090fSDavid van Moolenbroek },
120*3ba6090fSDavid van Moolenbroek [C_GETPEERNAME] = {
121*3ba6090fSDavid van Moolenbroek -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
122*3ba6090fSDavid van Moolenbroek },
123*3ba6090fSDavid van Moolenbroek [C_GETSOCKNAME] = {
124*3ba6090fSDavid van Moolenbroek -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
125*3ba6090fSDavid van Moolenbroek },
126*3ba6090fSDavid van Moolenbroek [C_GETSOCKOPT_ERR] = {
127*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
128*3ba6090fSDavid van Moolenbroek },
129*3ba6090fSDavid van Moolenbroek [C_GETSOCKOPT_KA] = {
130*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
131*3ba6090fSDavid van Moolenbroek },
132*3ba6090fSDavid van Moolenbroek [C_GETSOCKOPT_RB] = {
133*3ba6090fSDavid van Moolenbroek -ENOPROTOOPT, -ENOPROTOOPT, -ENOPROTOOPT, -ENOPROTOOPT,
134*3ba6090fSDavid van Moolenbroek },
135*3ba6090fSDavid van Moolenbroek [C_IOCTL_NREAD] = {
136*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
137*3ba6090fSDavid van Moolenbroek },
138*3ba6090fSDavid van Moolenbroek [C_LISTEN] = {
139*3ba6090fSDavid van Moolenbroek -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
140*3ba6090fSDavid van Moolenbroek },
141*3ba6090fSDavid van Moolenbroek [C_RECV] = {
142*3ba6090fSDavid van Moolenbroek -EOPNOTSUPP, 0, -EOPNOTSUPP, 0,
143*3ba6090fSDavid van Moolenbroek },
144*3ba6090fSDavid van Moolenbroek [C_RECVFROM] = {
145*3ba6090fSDavid van Moolenbroek -EOPNOTSUPP, 0, -EOPNOTSUPP, 0,
146*3ba6090fSDavid van Moolenbroek },
147*3ba6090fSDavid van Moolenbroek [C_SEND] = {
148*3ba6090fSDavid van Moolenbroek -EOPNOTSUPP, -EOPNOTSUPP, -EPIPE, -EPIPE,
149*3ba6090fSDavid van Moolenbroek },
150*3ba6090fSDavid van Moolenbroek [C_SENDTO] = {
151*3ba6090fSDavid van Moolenbroek -EOPNOTSUPP, -EOPNOTSUPP, -EPIPE, -EPIPE,
152*3ba6090fSDavid van Moolenbroek },
153*3ba6090fSDavid van Moolenbroek [C_SELECT_R] = {
154*3ba6090fSDavid van Moolenbroek 1, 1, 1, 1,
155*3ba6090fSDavid van Moolenbroek },
156*3ba6090fSDavid van Moolenbroek [C_SELECT_W] = {
157*3ba6090fSDavid van Moolenbroek 1, 1, 1, 1,
158*3ba6090fSDavid van Moolenbroek },
159*3ba6090fSDavid van Moolenbroek [C_SELECT_X] = {
160*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
161*3ba6090fSDavid van Moolenbroek },
162*3ba6090fSDavid van Moolenbroek [C_SETSOCKOPT_BC] = {
163*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
164*3ba6090fSDavid van Moolenbroek },
165*3ba6090fSDavid van Moolenbroek [C_SETSOCKOPT_KA] = {
166*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
167*3ba6090fSDavid van Moolenbroek },
168*3ba6090fSDavid van Moolenbroek [C_SETSOCKOPT_L] = {
169*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
170*3ba6090fSDavid van Moolenbroek },
171*3ba6090fSDavid van Moolenbroek [C_SETSOCKOPT_RA] = {
172*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
173*3ba6090fSDavid van Moolenbroek },
174*3ba6090fSDavid van Moolenbroek [C_SHUTDOWN_R] = {
175*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
176*3ba6090fSDavid van Moolenbroek },
177*3ba6090fSDavid van Moolenbroek [C_SHUTDOWN_RW] = {
178*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
179*3ba6090fSDavid van Moolenbroek },
180*3ba6090fSDavid van Moolenbroek [C_SHUTDOWN_W] = {
181*3ba6090fSDavid van Moolenbroek 0, 0, 0, 0,
182*3ba6090fSDavid van Moolenbroek },
183*3ba6090fSDavid van Moolenbroek };
184*3ba6090fSDavid van Moolenbroek
185*3ba6090fSDavid van Moolenbroek /*
186*3ba6090fSDavid van Moolenbroek * Set up a routing or link socket file descriptor in the requested state and
187*3ba6090fSDavid van Moolenbroek * pass it to socklib_sweep_call() along with local and remote addresses and
188*3ba6090fSDavid van Moolenbroek * their lengths.
189*3ba6090fSDavid van Moolenbroek */
190*3ba6090fSDavid van Moolenbroek static int
rtlnk_sweep(int domain,int type,int protocol,enum state state,enum call call)191*3ba6090fSDavid van Moolenbroek rtlnk_sweep(int domain, int type, int protocol, enum state state,
192*3ba6090fSDavid van Moolenbroek enum call call)
193*3ba6090fSDavid van Moolenbroek {
194*3ba6090fSDavid van Moolenbroek struct sockaddr sa;
195*3ba6090fSDavid van Moolenbroek int r, fd;
196*3ba6090fSDavid van Moolenbroek
197*3ba6090fSDavid van Moolenbroek memset(&sa, 0, sizeof(sa));
198*3ba6090fSDavid van Moolenbroek sa.sa_family = domain;
199*3ba6090fSDavid van Moolenbroek
200*3ba6090fSDavid van Moolenbroek if ((fd = socket(domain, type | SOCK_NONBLOCK, protocol)) < 0) e(0);
201*3ba6090fSDavid van Moolenbroek
202*3ba6090fSDavid van Moolenbroek switch (state) {
203*3ba6090fSDavid van Moolenbroek case S_NEW: break;
204*3ba6090fSDavid van Moolenbroek case S_N_SHUT_R: if (shutdown(fd, SHUT_RD)) e(0); break;
205*3ba6090fSDavid van Moolenbroek case S_N_SHUT_W: if (shutdown(fd, SHUT_WR)) e(0); break;
206*3ba6090fSDavid van Moolenbroek case S_N_SHUT_RW: if (shutdown(fd, SHUT_RDWR)) e(0); break;
207*3ba6090fSDavid van Moolenbroek default: e(0);
208*3ba6090fSDavid van Moolenbroek }
209*3ba6090fSDavid van Moolenbroek
210*3ba6090fSDavid van Moolenbroek r = socklib_sweep_call(call, fd, &sa, &sa,
211*3ba6090fSDavid van Moolenbroek offsetof(struct sockaddr, sa_data));
212*3ba6090fSDavid van Moolenbroek
213*3ba6090fSDavid van Moolenbroek if (close(fd) != 0) e(0);
214*3ba6090fSDavid van Moolenbroek
215*3ba6090fSDavid van Moolenbroek return r;
216*3ba6090fSDavid van Moolenbroek }
217*3ba6090fSDavid van Moolenbroek
218*3ba6090fSDavid van Moolenbroek /*
219*3ba6090fSDavid van Moolenbroek * Sweep test for socket calls versus socket states of routing and link
220*3ba6090fSDavid van Moolenbroek * sockets.
221*3ba6090fSDavid van Moolenbroek */
222*3ba6090fSDavid van Moolenbroek static void
test93a(void)223*3ba6090fSDavid van Moolenbroek test93a(void)
224*3ba6090fSDavid van Moolenbroek {
225*3ba6090fSDavid van Moolenbroek
226*3ba6090fSDavid van Moolenbroek subtest = 1;
227*3ba6090fSDavid van Moolenbroek
228*3ba6090fSDavid van Moolenbroek socklib_sweep(AF_ROUTE, SOCK_RAW, 0, rtlnk_states,
229*3ba6090fSDavid van Moolenbroek __arraycount(rtlnk_states), (const int *)rt_results, rtlnk_sweep);
230*3ba6090fSDavid van Moolenbroek
231*3ba6090fSDavid van Moolenbroek /*
232*3ba6090fSDavid van Moolenbroek * Our implementation of link sockets currently serves only one
233*3ba6090fSDavid van Moolenbroek * purpose, and that is to pass on ioctl() calls issued on the socket.
234*3ba6090fSDavid van Moolenbroek * As such, the results here are not too important. The test mostly
235*3ba6090fSDavid van Moolenbroek * ensures that all calls actually complete--for example, that there is
236*3ba6090fSDavid van Moolenbroek * no function pointer NULL check missing in libsockevent.
237*3ba6090fSDavid van Moolenbroek */
238*3ba6090fSDavid van Moolenbroek socklib_sweep(AF_LINK, SOCK_DGRAM, 0, rtlnk_states,
239*3ba6090fSDavid van Moolenbroek __arraycount(rtlnk_states), (const int *)lnk_results, rtlnk_sweep);
240*3ba6090fSDavid van Moolenbroek }
241*3ba6090fSDavid van Moolenbroek
242*3ba6090fSDavid van Moolenbroek /*
243*3ba6090fSDavid van Moolenbroek * Attempt to destroy the test loopback interface. Return 0 if destruction was
244*3ba6090fSDavid van Moolenbroek * successful, or -1 if no such interface existed.
245*3ba6090fSDavid van Moolenbroek */
246*3ba6090fSDavid van Moolenbroek static int
test93_destroy_if(void)247*3ba6090fSDavid van Moolenbroek test93_destroy_if(void)
248*3ba6090fSDavid van Moolenbroek {
249*3ba6090fSDavid van Moolenbroek struct ifreq ifr;
250*3ba6090fSDavid van Moolenbroek int r, fd;
251*3ba6090fSDavid van Moolenbroek
252*3ba6090fSDavid van Moolenbroek if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) e(0);
253*3ba6090fSDavid van Moolenbroek
254*3ba6090fSDavid van Moolenbroek memset(&ifr, 0, sizeof(ifr));
255*3ba6090fSDavid van Moolenbroek strlcpy(ifr.ifr_name, TEST_IFNAME, sizeof(ifr.ifr_name));
256*3ba6090fSDavid van Moolenbroek
257*3ba6090fSDavid van Moolenbroek r = ioctl(fd, SIOCIFDESTROY, &ifr);
258*3ba6090fSDavid van Moolenbroek if (r != 0 && (r != -1 || errno != ENXIO)) e(0);
259*3ba6090fSDavid van Moolenbroek
260*3ba6090fSDavid van Moolenbroek if (close(fd) != 0) e(0);
261*3ba6090fSDavid van Moolenbroek
262*3ba6090fSDavid van Moolenbroek return r;
263*3ba6090fSDavid van Moolenbroek }
264*3ba6090fSDavid van Moolenbroek
265*3ba6090fSDavid van Moolenbroek /*
266*3ba6090fSDavid van Moolenbroek * Destroy the test interface at exit. It is always safe to do so as its name
267*3ba6090fSDavid van Moolenbroek * is sufficiently unique, and we do not want to leave it around.
268*3ba6090fSDavid van Moolenbroek */
269*3ba6090fSDavid van Moolenbroek static void
test93_destroy_if_atexit(void)270*3ba6090fSDavid van Moolenbroek test93_destroy_if_atexit(void)
271*3ba6090fSDavid van Moolenbroek {
272*3ba6090fSDavid van Moolenbroek static int atexit_set = 0;
273*3ba6090fSDavid van Moolenbroek
274*3ba6090fSDavid van Moolenbroek if (!atexit_set) {
275*3ba6090fSDavid van Moolenbroek (void)test93_destroy_if();
276*3ba6090fSDavid van Moolenbroek
277*3ba6090fSDavid van Moolenbroek atexit_set = 1;
278*3ba6090fSDavid van Moolenbroek }
279*3ba6090fSDavid van Moolenbroek }
280*3ba6090fSDavid van Moolenbroek
281*3ba6090fSDavid van Moolenbroek /*
282*3ba6090fSDavid van Moolenbroek * Attempt to create a test loopback interface. Return 0 if creation was
283*3ba6090fSDavid van Moolenbroek * successful, or -1 if no more interfaces could be created.
284*3ba6090fSDavid van Moolenbroek */
285*3ba6090fSDavid van Moolenbroek static int
test93_create_if(void)286*3ba6090fSDavid van Moolenbroek test93_create_if(void)
287*3ba6090fSDavid van Moolenbroek {
288*3ba6090fSDavid van Moolenbroek struct ifreq ifr;
289*3ba6090fSDavid van Moolenbroek int r, fd;
290*3ba6090fSDavid van Moolenbroek
291*3ba6090fSDavid van Moolenbroek (void)test93_destroy_if();
292*3ba6090fSDavid van Moolenbroek
293*3ba6090fSDavid van Moolenbroek if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) e(0);
294*3ba6090fSDavid van Moolenbroek
295*3ba6090fSDavid van Moolenbroek memset(&ifr, 0, sizeof(ifr));
296*3ba6090fSDavid van Moolenbroek strlcpy(ifr.ifr_name, TEST_IFNAME, sizeof(ifr.ifr_name));
297*3ba6090fSDavid van Moolenbroek
298*3ba6090fSDavid van Moolenbroek r = ioctl(fd, SIOCIFCREATE, &ifr);
299*3ba6090fSDavid van Moolenbroek if (r != 0 && (r != -1 || errno != ENOBUFS)) e(0);
300*3ba6090fSDavid van Moolenbroek
301*3ba6090fSDavid van Moolenbroek if (close(fd) != 0) e(0);
302*3ba6090fSDavid van Moolenbroek
303*3ba6090fSDavid van Moolenbroek atexit(test93_destroy_if_atexit);
304*3ba6090fSDavid van Moolenbroek
305*3ba6090fSDavid van Moolenbroek return r;
306*3ba6090fSDavid van Moolenbroek }
307*3ba6090fSDavid van Moolenbroek
308*3ba6090fSDavid van Moolenbroek /*
309*3ba6090fSDavid van Moolenbroek * Set the interface-up value for an interface to the given boolean value.
310*3ba6090fSDavid van Moolenbroek */
311*3ba6090fSDavid van Moolenbroek static void
test93_set_if_up(const char * ifname,int up)312*3ba6090fSDavid van Moolenbroek test93_set_if_up(const char * ifname, int up)
313*3ba6090fSDavid van Moolenbroek {
314*3ba6090fSDavid van Moolenbroek struct ifreq ifr;
315*3ba6090fSDavid van Moolenbroek int fd;
316*3ba6090fSDavid van Moolenbroek
317*3ba6090fSDavid van Moolenbroek if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) e(0);
318*3ba6090fSDavid van Moolenbroek
319*3ba6090fSDavid van Moolenbroek memset(&ifr, 0, sizeof(ifr));
320*3ba6090fSDavid van Moolenbroek strlcpy(ifr.ifr_name, TEST_IFNAME, sizeof(ifr.ifr_name));
321*3ba6090fSDavid van Moolenbroek
322*3ba6090fSDavid van Moolenbroek if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) e(0);
323*3ba6090fSDavid van Moolenbroek
324*3ba6090fSDavid van Moolenbroek if (up)
325*3ba6090fSDavid van Moolenbroek ifr.ifr_flags |= IFF_UP;
326*3ba6090fSDavid van Moolenbroek else
327*3ba6090fSDavid van Moolenbroek ifr.ifr_flags &= ~IFF_UP;
328*3ba6090fSDavid van Moolenbroek
329*3ba6090fSDavid van Moolenbroek if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) e(0);
330*3ba6090fSDavid van Moolenbroek
331*3ba6090fSDavid van Moolenbroek if (close(fd) != 0) e(0);
332*3ba6090fSDavid van Moolenbroek }
333*3ba6090fSDavid van Moolenbroek
334*3ba6090fSDavid van Moolenbroek /*
335*3ba6090fSDavid van Moolenbroek * Construct an IPv6 network mask for a certain prefix length.
336*3ba6090fSDavid van Moolenbroek */
337*3ba6090fSDavid van Moolenbroek static void
test93_make_netmask6(struct sockaddr_in6 * sin6,unsigned int prefix)338*3ba6090fSDavid van Moolenbroek test93_make_netmask6(struct sockaddr_in6 * sin6, unsigned int prefix)
339*3ba6090fSDavid van Moolenbroek {
340*3ba6090fSDavid van Moolenbroek unsigned int byte, bit;
341*3ba6090fSDavid van Moolenbroek
342*3ba6090fSDavid van Moolenbroek if (prefix > 128) e(0);
343*3ba6090fSDavid van Moolenbroek memset(sin6, 0, sizeof(*sin6));
344*3ba6090fSDavid van Moolenbroek sin6->sin6_family = AF_INET6;
345*3ba6090fSDavid van Moolenbroek
346*3ba6090fSDavid van Moolenbroek byte = prefix / NBBY;
347*3ba6090fSDavid van Moolenbroek bit = prefix % NBBY;
348*3ba6090fSDavid van Moolenbroek
349*3ba6090fSDavid van Moolenbroek if (byte > 0)
350*3ba6090fSDavid van Moolenbroek memset(sin6->sin6_addr.s6_addr, 0xff, byte);
351*3ba6090fSDavid van Moolenbroek if (bit != 0)
352*3ba6090fSDavid van Moolenbroek sin6->sin6_addr.s6_addr[byte] = 0xff << (NBBY - bit);
353*3ba6090fSDavid van Moolenbroek }
354*3ba6090fSDavid van Moolenbroek
355*3ba6090fSDavid van Moolenbroek /*
356*3ba6090fSDavid van Moolenbroek * Issue a modifying routing command, which must be one of RTM_ADD, RTM_CHANGE,
357*3ba6090fSDavid van Moolenbroek * RTM_DELETE, or RTM_LOCK. The destination address (IPv4 or IPv6) and netmask
358*3ba6090fSDavid van Moolenbroek * prefix are required. The flags (RTF_), interface name, and gateway are
359*3ba6090fSDavid van Moolenbroek * optional depending on the command (and flags) being issued. Return 0 on
360*3ba6090fSDavid van Moolenbroek * success, and -1 with errno set on failure.
361*3ba6090fSDavid van Moolenbroek */
362*3ba6090fSDavid van Moolenbroek static int
test93_route_cmd(int cmd,const struct sockaddr * dest,socklen_t dest_len,unsigned int prefix,int flags,const char * ifname,const struct sockaddr * gw,socklen_t gw_len)363*3ba6090fSDavid van Moolenbroek test93_route_cmd(int cmd, const struct sockaddr * dest, socklen_t dest_len,
364*3ba6090fSDavid van Moolenbroek unsigned int prefix, int flags, const char * ifname,
365*3ba6090fSDavid van Moolenbroek const struct sockaddr * gw, socklen_t gw_len)
366*3ba6090fSDavid van Moolenbroek {
367*3ba6090fSDavid van Moolenbroek static unsigned int seq = 0;
368*3ba6090fSDavid van Moolenbroek struct sockaddr_storage destss, maskss, ifpss, gwss;
369*3ba6090fSDavid van Moolenbroek struct sockaddr_in mask4;
370*3ba6090fSDavid van Moolenbroek struct sockaddr_in6 mask6;
371*3ba6090fSDavid van Moolenbroek struct sockaddr_dl ifp;
372*3ba6090fSDavid van Moolenbroek struct rt_msghdr rtm;
373*3ba6090fSDavid van Moolenbroek struct iovec iov[5];
374*3ba6090fSDavid van Moolenbroek struct msghdr msg;
375*3ba6090fSDavid van Moolenbroek unsigned int i, iovlen;
376*3ba6090fSDavid van Moolenbroek int r, fd, err;
377*3ba6090fSDavid van Moolenbroek
378*3ba6090fSDavid van Moolenbroek memset(&rtm, 0, sizeof(rtm));
379*3ba6090fSDavid van Moolenbroek rtm.rtm_version = RTM_VERSION;
380*3ba6090fSDavid van Moolenbroek rtm.rtm_type = cmd;
381*3ba6090fSDavid van Moolenbroek rtm.rtm_flags = flags;
382*3ba6090fSDavid van Moolenbroek rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
383*3ba6090fSDavid van Moolenbroek rtm.rtm_seq = ++seq;
384*3ba6090fSDavid van Moolenbroek
385*3ba6090fSDavid van Moolenbroek iovlen = 0;
386*3ba6090fSDavid van Moolenbroek iov[iovlen].iov_base = &rtm;
387*3ba6090fSDavid van Moolenbroek iov[iovlen++].iov_len = sizeof(rtm);
388*3ba6090fSDavid van Moolenbroek
389*3ba6090fSDavid van Moolenbroek memset(&destss, 0, sizeof(destss));
390*3ba6090fSDavid van Moolenbroek memcpy(&destss, dest, dest_len);
391*3ba6090fSDavid van Moolenbroek destss.ss_len = dest_len;
392*3ba6090fSDavid van Moolenbroek
393*3ba6090fSDavid van Moolenbroek iov[iovlen].iov_base = &destss;
394*3ba6090fSDavid van Moolenbroek iov[iovlen++].iov_len = RT_ROUNDUP(dest_len);
395*3ba6090fSDavid van Moolenbroek
396*3ba6090fSDavid van Moolenbroek /* Do this in RTA order. */
397*3ba6090fSDavid van Moolenbroek memset(&gwss, 0, sizeof(gwss));
398*3ba6090fSDavid van Moolenbroek if (gw != NULL) {
399*3ba6090fSDavid van Moolenbroek memcpy(&gwss, gw, gw_len);
400*3ba6090fSDavid van Moolenbroek gwss.ss_len = gw_len;
401*3ba6090fSDavid van Moolenbroek
402*3ba6090fSDavid van Moolenbroek rtm.rtm_addrs |= RTA_GATEWAY;
403*3ba6090fSDavid van Moolenbroek iov[iovlen].iov_base = &gwss;
404*3ba6090fSDavid van Moolenbroek iov[iovlen++].iov_len = RT_ROUNDUP(gwss.ss_len);
405*3ba6090fSDavid van Moolenbroek }
406*3ba6090fSDavid van Moolenbroek
407*3ba6090fSDavid van Moolenbroek memset(&maskss, 0, sizeof(maskss));
408*3ba6090fSDavid van Moolenbroek switch (dest->sa_family) {
409*3ba6090fSDavid van Moolenbroek case AF_INET:
410*3ba6090fSDavid van Moolenbroek if (prefix > 32) e(0);
411*3ba6090fSDavid van Moolenbroek memset(&mask4, 0, sizeof(mask4));
412*3ba6090fSDavid van Moolenbroek mask4.sin_family = AF_INET;
413*3ba6090fSDavid van Moolenbroek if (prefix < 32)
414*3ba6090fSDavid van Moolenbroek mask4.sin_addr.s_addr = htonl(0xffffffffUL << prefix);
415*3ba6090fSDavid van Moolenbroek
416*3ba6090fSDavid van Moolenbroek memcpy(&maskss, &mask4, sizeof(mask4));
417*3ba6090fSDavid van Moolenbroek maskss.ss_len = sizeof(mask4);
418*3ba6090fSDavid van Moolenbroek
419*3ba6090fSDavid van Moolenbroek break;
420*3ba6090fSDavid van Moolenbroek
421*3ba6090fSDavid van Moolenbroek case AF_INET6:
422*3ba6090fSDavid van Moolenbroek test93_make_netmask6(&mask6, prefix);
423*3ba6090fSDavid van Moolenbroek
424*3ba6090fSDavid van Moolenbroek memcpy(&maskss, &mask6, sizeof(mask6));
425*3ba6090fSDavid van Moolenbroek maskss.ss_len = sizeof(mask6);
426*3ba6090fSDavid van Moolenbroek
427*3ba6090fSDavid van Moolenbroek break;
428*3ba6090fSDavid van Moolenbroek
429*3ba6090fSDavid van Moolenbroek default:
430*3ba6090fSDavid van Moolenbroek e(0);
431*3ba6090fSDavid van Moolenbroek }
432*3ba6090fSDavid van Moolenbroek
433*3ba6090fSDavid van Moolenbroek iov[iovlen].iov_base = &maskss;
434*3ba6090fSDavid van Moolenbroek iov[iovlen++].iov_len = RT_ROUNDUP(maskss.ss_len);
435*3ba6090fSDavid van Moolenbroek
436*3ba6090fSDavid van Moolenbroek if (ifname != NULL) {
437*3ba6090fSDavid van Moolenbroek memset(&ifp, 0, sizeof(ifp));
438*3ba6090fSDavid van Moolenbroek ifp.sdl_nlen = strlen(ifname);
439*3ba6090fSDavid van Moolenbroek ifp.sdl_len = offsetof(struct sockaddr_dl, sdl_data) +
440*3ba6090fSDavid van Moolenbroek ifp.sdl_nlen;
441*3ba6090fSDavid van Moolenbroek ifp.sdl_family = AF_LINK;
442*3ba6090fSDavid van Moolenbroek
443*3ba6090fSDavid van Moolenbroek memset(&ifpss, 0, sizeof(ifpss));
444*3ba6090fSDavid van Moolenbroek memcpy(&ifpss, &ifp, ifp.sdl_len);
445*3ba6090fSDavid van Moolenbroek memcpy(&((struct sockaddr_dl *)&ifpss)->sdl_data, ifname,
446*3ba6090fSDavid van Moolenbroek ifp.sdl_nlen);
447*3ba6090fSDavid van Moolenbroek
448*3ba6090fSDavid van Moolenbroek rtm.rtm_addrs |= RTA_IFP;
449*3ba6090fSDavid van Moolenbroek iov[iovlen].iov_base = &ifpss;
450*3ba6090fSDavid van Moolenbroek iov[iovlen++].iov_len = RT_ROUNDUP(ifpss.ss_len);
451*3ba6090fSDavid van Moolenbroek }
452*3ba6090fSDavid van Moolenbroek
453*3ba6090fSDavid van Moolenbroek memset(&msg, 0, sizeof(msg));
454*3ba6090fSDavid van Moolenbroek msg.msg_iov = iov;
455*3ba6090fSDavid van Moolenbroek msg.msg_iovlen = iovlen;
456*3ba6090fSDavid van Moolenbroek
457*3ba6090fSDavid van Moolenbroek if ((fd = socket(AF_ROUTE, SOCK_RAW, 0)) < 0) e(0);
458*3ba6090fSDavid van Moolenbroek
459*3ba6090fSDavid van Moolenbroek for (i = 0; i < iovlen; i++)
460*3ba6090fSDavid van Moolenbroek rtm.rtm_msglen += iov[i].iov_len;
461*3ba6090fSDavid van Moolenbroek
462*3ba6090fSDavid van Moolenbroek r = sendmsg(fd, &msg, 0);
463*3ba6090fSDavid van Moolenbroek if (r != rtm.rtm_msglen && r != -1) e(0);
464*3ba6090fSDavid van Moolenbroek err = errno;
465*3ba6090fSDavid van Moolenbroek
466*3ba6090fSDavid van Moolenbroek /*
467*3ba6090fSDavid van Moolenbroek * We could just shut down the socket for reading, but this is just an
468*3ba6090fSDavid van Moolenbroek * extra test we can do basically for free.
469*3ba6090fSDavid van Moolenbroek */
470*3ba6090fSDavid van Moolenbroek rtm.rtm_seq = 0;
471*3ba6090fSDavid van Moolenbroek do {
472*3ba6090fSDavid van Moolenbroek iov[0].iov_base = &rtm;
473*3ba6090fSDavid van Moolenbroek iov[0].iov_len = sizeof(rtm);
474*3ba6090fSDavid van Moolenbroek
475*3ba6090fSDavid van Moolenbroek if (recvmsg(fd, &msg, 0) <= 0) e(0);
476*3ba6090fSDavid van Moolenbroek } while (rtm.rtm_pid != getpid() || rtm.rtm_seq != seq);
477*3ba6090fSDavid van Moolenbroek
478*3ba6090fSDavid van Moolenbroek if (r == -1) {
479*3ba6090fSDavid van Moolenbroek if (rtm.rtm_errno != err) e(0);
480*3ba6090fSDavid van Moolenbroek if (rtm.rtm_flags & RTF_DONE) e(0);
481*3ba6090fSDavid van Moolenbroek } else {
482*3ba6090fSDavid van Moolenbroek if (rtm.rtm_errno != 0) e(0);
483*3ba6090fSDavid van Moolenbroek if (!(rtm.rtm_flags & RTF_DONE)) e(0);
484*3ba6090fSDavid van Moolenbroek }
485*3ba6090fSDavid van Moolenbroek
486*3ba6090fSDavid van Moolenbroek if (close(fd) != 0) e(0);
487*3ba6090fSDavid van Moolenbroek
488*3ba6090fSDavid van Moolenbroek errno = err;
489*3ba6090fSDavid van Moolenbroek return (r > 0) ? 0 : -1;
490*3ba6090fSDavid van Moolenbroek }
491*3ba6090fSDavid van Moolenbroek
492*3ba6090fSDavid van Moolenbroek /*
493*3ba6090fSDavid van Moolenbroek * Add or delete an IPv6 address to or from an interface. The interface name,
494*3ba6090fSDavid van Moolenbroek * address, and prefix length must always be given. When adding, a set of
495*3ba6090fSDavid van Moolenbroek * flags (IN6_IFF) and lifetimes must be given as well.
496*3ba6090fSDavid van Moolenbroek */
497*3ba6090fSDavid van Moolenbroek static void
test93_ipv6_addr(int add,const char * ifname,const struct sockaddr_in6 * sin6,unsigned int prefix,int flags,uint32_t valid_life,uint32_t pref_life)498*3ba6090fSDavid van Moolenbroek test93_ipv6_addr(int add, const char * ifname,
499*3ba6090fSDavid van Moolenbroek const struct sockaddr_in6 * sin6, unsigned int prefix, int flags,
500*3ba6090fSDavid van Moolenbroek uint32_t valid_life, uint32_t pref_life)
501*3ba6090fSDavid van Moolenbroek {
502*3ba6090fSDavid van Moolenbroek struct in6_aliasreq ifra;
503*3ba6090fSDavid van Moolenbroek int fd;
504*3ba6090fSDavid van Moolenbroek
505*3ba6090fSDavid van Moolenbroek memset(&ifra, 0, sizeof(ifra));
506*3ba6090fSDavid van Moolenbroek strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
507*3ba6090fSDavid van Moolenbroek memcpy(&ifra.ifra_addr, sin6, sizeof(ifra.ifra_addr));
508*3ba6090fSDavid van Moolenbroek /* leave ifra_dstaddr blank */
509*3ba6090fSDavid van Moolenbroek test93_make_netmask6(&ifra.ifra_prefixmask, prefix);
510*3ba6090fSDavid van Moolenbroek ifra.ifra_flags = flags;
511*3ba6090fSDavid van Moolenbroek ifra.ifra_lifetime.ia6t_vltime = valid_life;
512*3ba6090fSDavid van Moolenbroek ifra.ifra_lifetime.ia6t_pltime = pref_life;
513*3ba6090fSDavid van Moolenbroek
514*3ba6090fSDavid van Moolenbroek if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) e(0);
515*3ba6090fSDavid van Moolenbroek
516*3ba6090fSDavid van Moolenbroek if (ioctl(fd, (add) ? SIOCAIFADDR_IN6 : SIOCDIFADDR_IN6, &ifra) != 0)
517*3ba6090fSDavid van Moolenbroek e(0);
518*3ba6090fSDavid van Moolenbroek
519*3ba6090fSDavid van Moolenbroek if (close(fd) != 0) e(0);
520*3ba6090fSDavid van Moolenbroek }
521*3ba6090fSDavid van Moolenbroek
522*3ba6090fSDavid van Moolenbroek static const struct {
523*3ba6090fSDavid van Moolenbroek int result; /* 0..2 = prefer srcN, -1 = no preference */
524*3ba6090fSDavid van Moolenbroek const char *dest_addr;
525*3ba6090fSDavid van Moolenbroek const char *src0_addr;
526*3ba6090fSDavid van Moolenbroek unsigned int src0_prefix;
527*3ba6090fSDavid van Moolenbroek int src0_flags;
528*3ba6090fSDavid van Moolenbroek const char *src1_addr;
529*3ba6090fSDavid van Moolenbroek unsigned int src1_prefix;
530*3ba6090fSDavid van Moolenbroek int src1_flags;
531*3ba6090fSDavid van Moolenbroek const char *src2_addr;
532*3ba6090fSDavid van Moolenbroek unsigned int src2_prefix;
533*3ba6090fSDavid van Moolenbroek int src2_flags;
534*3ba6090fSDavid van Moolenbroek } test93b_table[] = {
535*3ba6090fSDavid van Moolenbroek /*
536*3ba6090fSDavid van Moolenbroek * These are all the applicable tests from RFC 6724 Sec. 10.1, slightly
537*3ba6090fSDavid van Moolenbroek * changed not to use the default link-local address of lo0.
538*3ba6090fSDavid van Moolenbroek */
539*3ba6090fSDavid van Moolenbroek /* Prefer appropriate scope: */
540*3ba6090fSDavid van Moolenbroek { 0, "2001:db8:1::1", "2001:db8:3::1", 64, 0, "fe80::93:1", 64, 0 },
541*3ba6090fSDavid van Moolenbroek /* Prefer appropriate scope: */
542*3ba6090fSDavid van Moolenbroek { 0, "ff05::1", "2001:db8:3::1", 64, 0, "fe80::93:1", 64, 0 },
543*3ba6090fSDavid van Moolenbroek /* Prefer same address: */
544*3ba6090fSDavid van Moolenbroek { 0, "2001:db8:1::1", "2001:db8:1::1", 64, IN6_IFF_DEPRECATED,
545*3ba6090fSDavid van Moolenbroek "2001:db8:2::1", 64, 0 },
546*3ba6090fSDavid van Moolenbroek /* Prefer appropriate scope: */
547*3ba6090fSDavid van Moolenbroek { 0, "fe80::93:1", "fe80::93:2", 64, IN6_IFF_DEPRECATED,
548*3ba6090fSDavid van Moolenbroek "2001:db8:2::1", 64, 0 },
549*3ba6090fSDavid van Moolenbroek /* Longest matching prefix: */
550*3ba6090fSDavid van Moolenbroek { 0, "2001:db8:1::1", "2001:db8:1::2", 64, 0, "2001:db8:3::2", 64, 0 },
551*3ba6090fSDavid van Moolenbroek /* Prefer matching label: */
552*3ba6090fSDavid van Moolenbroek { 0, "2002:c633:6401::1", "2002:c633:6401::d5e3:7953:13eb:22e8", 64,
553*3ba6090fSDavid van Moolenbroek IN6_IFF_TEMPORARY, "2001:db8:1::2", 64, 0 },
554*3ba6090fSDavid van Moolenbroek /* Prefer temporary address: */
555*3ba6090fSDavid van Moolenbroek { 1, "2001:db8:1::d5e3:0:0:1", "2001:db8:1::2", 64, 0,
556*3ba6090fSDavid van Moolenbroek "2001:db8:1::d5e3:7953:13eb:22e8", 64, IN6_IFF_TEMPORARY },
557*3ba6090fSDavid van Moolenbroek /*
558*3ba6090fSDavid van Moolenbroek * Our own additional tests.
559*3ba6090fSDavid van Moolenbroek */
560*3ba6090fSDavid van Moolenbroek /* Prefer same address: */
561*3ba6090fSDavid van Moolenbroek { 1, "4000:93::1", "2001:db8:3::1", 64, 0, "4000:93::1", 64, 0 },
562*3ba6090fSDavid van Moolenbroek { 2, "2001:db8:1::1", "2001:db8:3::1", 64, 0, "fe80::93:1", 64, 0,
563*3ba6090fSDavid van Moolenbroek "2001:db8:1::1", 64, 0 },
564*3ba6090fSDavid van Moolenbroek /* Prefer appropriate scope: */
565*3ba6090fSDavid van Moolenbroek { 1, "ff01::1", "2001:db8:3::1", 64, 0, "fe80::93:1", 64, 0 },
566*3ba6090fSDavid van Moolenbroek { 1, "ff02::1", "2001:db8:3::1", 64, 0, "fe80::93:1", 64, 0 },
567*3ba6090fSDavid van Moolenbroek { 0, "ff0e::1", "2001:db8:3::1", 64, 0, "fe80::93:1", 64, 0 },
568*3ba6090fSDavid van Moolenbroek { 1, "fd00:93::1", "2001:db8:3::1", 64, 0, "fd00::93:2", 64, 0 },
569*3ba6090fSDavid van Moolenbroek { 1, "fd00:93::1", "fe80::93:1", 64, 0, "fd00::93:2", 64, 0 },
570*3ba6090fSDavid van Moolenbroek { 0, "fd00:93::1", "2001:db8:3::1", 64, 0, "fe80::93:1", 64, 0 },
571*3ba6090fSDavid van Moolenbroek { 1, "2001:db8:1::1", "fe80::93:1", 64, 0, "fd00::93:2", 64, 0 },
572*3ba6090fSDavid van Moolenbroek { 0, "2001:db8:1::1", "2001:db8:3::1", 64, 0, "4000:93::1", 64, 0 },
573*3ba6090fSDavid van Moolenbroek { 0, "4000:93::2", "2001:db8:3::1", 64, 0, "4000:93::1", 64, 0 },
574*3ba6090fSDavid van Moolenbroek { 2, "2001:db8:1::1", "fe80::93:1", 64, 0, "fd00::93:1", 64, 0,
575*3ba6090fSDavid van Moolenbroek "2001:db8:3::1", 64, 0 },
576*3ba6090fSDavid van Moolenbroek { 2, "2001:db8:1::1", "fe80::93:1", 64, IN6_IFF_DEPRECATED,
577*3ba6090fSDavid van Moolenbroek "fe80::93:2", 64, 0, "2001:db8:3::1", 64, 0 },
578*3ba6090fSDavid van Moolenbroek /* Avoid deprecated address: */
579*3ba6090fSDavid van Moolenbroek { 1, "2002:c633:6401::1", "2002:c633:6401::d5e3:7953:13eb:22e8", 64,
580*3ba6090fSDavid van Moolenbroek IN6_IFF_DEPRECATED, "2001:db8:1::2", 64, 0 },
581*3ba6090fSDavid van Moolenbroek { 2, "2001:db8:1::1", "2001:db8:1::3", 64, IN6_IFF_DEPRECATED,
582*3ba6090fSDavid van Moolenbroek "2001:db8:2::1", 64, IN6_IFF_DEPRECATED, "2001:db8:3::1", 64, 0 },
583*3ba6090fSDavid van Moolenbroek { 2, "2001:db8:1::1", "2002:db8:1::3", 64, IN6_IFF_DEPRECATED,
584*3ba6090fSDavid van Moolenbroek "2001:db8:2::1", 64, IN6_IFF_DEPRECATED, "2001:db8:3::1", 64, 0 },
585*3ba6090fSDavid van Moolenbroek /* Prefer matching label: */
586*3ba6090fSDavid van Moolenbroek { 0, "2002:c633:6401::1", "2002:c633:6401::d5e3:7953:13eb:22e8", 64, 0,
587*3ba6090fSDavid van Moolenbroek "2001:db8:1::2", 64, IN6_IFF_TEMPORARY },
588*3ba6090fSDavid van Moolenbroek { 2, "2002:c633:6401::1", "2001:db8:3::2", 64, 0, "2001:db8:1::2", 64,
589*3ba6090fSDavid van Moolenbroek IN6_IFF_TEMPORARY, "2002:c633:6401::d5e3:7953:13eb:22e8", 64, 0 },
590*3ba6090fSDavid van Moolenbroek { 2, "2001:db8:1::1", "2003:db8::1", 64, 0, "3ffe:db8::1", 64, 0,
591*3ba6090fSDavid van Moolenbroek "2001:db8:3::1", 64, 0 },
592*3ba6090fSDavid van Moolenbroek /* Prefer temporary address: */
593*3ba6090fSDavid van Moolenbroek { 0, "2001:db8:1::d5e3:0:0:1", "2001:db8:1::2", 96, IN6_IFF_TEMPORARY,
594*3ba6090fSDavid van Moolenbroek "2001:db8:1::d5e3:7953:13eb:22e8", 96, 0 },
595*3ba6090fSDavid van Moolenbroek { 2, "2002:c633:6401::1", "2001:db8:3::2", 64, 0, "2002:c633:6401::2",
596*3ba6090fSDavid van Moolenbroek 64, 0, "2002:c633:6401::d5e3:7953:13eb:22e8", 64,
597*3ba6090fSDavid van Moolenbroek IN6_IFF_TEMPORARY },
598*3ba6090fSDavid van Moolenbroek /* Longest matching prefix: */
599*3ba6090fSDavid van Moolenbroek { 1, "2001:db8:1::d5e3:0:0:1", "2001:db8:1::2", 96, 0,
600*3ba6090fSDavid van Moolenbroek "2001:db8:1::d5e3:7953:13eb:22e8", 96, 0 },
601*3ba6090fSDavid van Moolenbroek { 2, "2001:db8:1:1::1", "2001:db8:2:1::2", 64, 0, "2001:db8:1:2::2",
602*3ba6090fSDavid van Moolenbroek 64, 0, "2001:db8:1:1::2", 64, 0 },
603*3ba6090fSDavid van Moolenbroek { 0, "2001:db8:1::1", "2001:db8:1::2", 47, 0, "2001:db8:3::2", 47, 0 },
604*3ba6090fSDavid van Moolenbroek /* No preference (a tie): */
605*3ba6090fSDavid van Moolenbroek { -1, "2001:db8:1::1", "2001:db8:1::2", 46, 0, "2001:db8:3::2", 46,
606*3ba6090fSDavid van Moolenbroek 0 },
607*3ba6090fSDavid van Moolenbroek { -1, "2001:db8::1:0:0:1", "2001:db8::1:0:0:2", 64, 0,
608*3ba6090fSDavid van Moolenbroek "2001:db8::2:0:0:2", 64, 0, "2001:db8::3:0:0:2", 64, 0 },
609*3ba6090fSDavid van Moolenbroek };
610*3ba6090fSDavid van Moolenbroek
611*3ba6090fSDavid van Moolenbroek struct src_addr {
612*3ba6090fSDavid van Moolenbroek struct sockaddr_in6 addr;
613*3ba6090fSDavid van Moolenbroek unsigned int prefix;
614*3ba6090fSDavid van Moolenbroek int flags;
615*3ba6090fSDavid van Moolenbroek };
616*3ba6090fSDavid van Moolenbroek
617*3ba6090fSDavid van Moolenbroek /*
618*3ba6090fSDavid van Moolenbroek * Test source address selection with a particular destination address and two
619*3ba6090fSDavid van Moolenbroek * or three source addresses.
620*3ba6090fSDavid van Moolenbroek */
621*3ba6090fSDavid van Moolenbroek static void
sub93b(int result,const struct sockaddr_in6 * dest,unsigned int ifindex,const struct src_addr * src0,const struct src_addr * src1,const struct src_addr * src2)622*3ba6090fSDavid van Moolenbroek sub93b(int result, const struct sockaddr_in6 * dest, unsigned int ifindex,
623*3ba6090fSDavid van Moolenbroek const struct src_addr * src0, const struct src_addr * src1,
624*3ba6090fSDavid van Moolenbroek const struct src_addr * src2)
625*3ba6090fSDavid van Moolenbroek {
626*3ba6090fSDavid van Moolenbroek struct sockaddr_in6 dest_copy, src;
627*3ba6090fSDavid van Moolenbroek socklen_t len;
628*3ba6090fSDavid van Moolenbroek int fd, rt_res;
629*3ba6090fSDavid van Moolenbroek
630*3ba6090fSDavid van Moolenbroek /* Add the candidate source addresses. */
631*3ba6090fSDavid van Moolenbroek test93_ipv6_addr(1, TEST_IFNAME, &src0->addr, src0->prefix,
632*3ba6090fSDavid van Moolenbroek src0->flags, 0xffffffffUL, 0xffffffffUL);
633*3ba6090fSDavid van Moolenbroek
634*3ba6090fSDavid van Moolenbroek test93_ipv6_addr(1, TEST_IFNAME, &src1->addr, src1->prefix,
635*3ba6090fSDavid van Moolenbroek src1->flags, 0xffffffffUL, 0xffffffffUL);
636*3ba6090fSDavid van Moolenbroek
637*3ba6090fSDavid van Moolenbroek if (src2 != NULL)
638*3ba6090fSDavid van Moolenbroek test93_ipv6_addr(1, TEST_IFNAME, &src2->addr, src2->prefix,
639*3ba6090fSDavid van Moolenbroek src2->flags, 0xffffffffUL, 0xffffffffUL);
640*3ba6090fSDavid van Moolenbroek
641*3ba6090fSDavid van Moolenbroek /*
642*3ba6090fSDavid van Moolenbroek * We need to make sure that packets to the destination are routed to
643*3ba6090fSDavid van Moolenbroek * our test interface at all, so create a route for it. Creating the
644*3ba6090fSDavid van Moolenbroek * route may fail if the destination address is equal to either of the
645*3ba6090fSDavid van Moolenbroek * source addresses, but that is fine. We use a blackhole route here,
646*3ba6090fSDavid van Moolenbroek * but this test should not generate any traffic anyway.
647*3ba6090fSDavid van Moolenbroek */
648*3ba6090fSDavid van Moolenbroek rt_res = test93_route_cmd(RTM_ADD, (struct sockaddr *)dest,
649*3ba6090fSDavid van Moolenbroek sizeof(*dest), 128, RTF_UP | RTF_BLACKHOLE | RTF_STATIC,
650*3ba6090fSDavid van Moolenbroek TEST_IFNAME, NULL, 0);
651*3ba6090fSDavid van Moolenbroek if (rt_res != 0 && (rt_res != -1 || errno != EEXIST)) e(0);
652*3ba6090fSDavid van Moolenbroek
653*3ba6090fSDavid van Moolenbroek if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) e(0);
654*3ba6090fSDavid van Moolenbroek
655*3ba6090fSDavid van Moolenbroek /* Set a scope ID if necessary. */
656*3ba6090fSDavid van Moolenbroek memcpy(&dest_copy, dest, sizeof(dest_copy));
657*3ba6090fSDavid van Moolenbroek dest_copy.sin6_port = 1; /* anything that is not zero */
658*3ba6090fSDavid van Moolenbroek if (IN6_IS_ADDR_LINKLOCAL(&dest_copy.sin6_addr) ||
659*3ba6090fSDavid van Moolenbroek IN6_IS_ADDR_MC_NODELOCAL(&dest_copy.sin6_addr) ||
660*3ba6090fSDavid van Moolenbroek IN6_IS_ADDR_MC_LINKLOCAL(&dest_copy.sin6_addr))
661*3ba6090fSDavid van Moolenbroek dest_copy.sin6_scope_id = ifindex;
662*3ba6090fSDavid van Moolenbroek
663*3ba6090fSDavid van Moolenbroek /* Connecting also selects a source address. */
664*3ba6090fSDavid van Moolenbroek if (connect(fd, (struct sockaddr *)&dest_copy, sizeof(dest_copy)) != 0)
665*3ba6090fSDavid van Moolenbroek e(0);
666*3ba6090fSDavid van Moolenbroek
667*3ba6090fSDavid van Moolenbroek /* Obtain the selected source address. */
668*3ba6090fSDavid van Moolenbroek len = sizeof(src);
669*3ba6090fSDavid van Moolenbroek if (getsockname(fd, (struct sockaddr *)&src, &len) != 0) e(0);
670*3ba6090fSDavid van Moolenbroek
671*3ba6090fSDavid van Moolenbroek /*
672*3ba6090fSDavid van Moolenbroek * If the chosen destination address has a scope ID, it must be for our
673*3ba6090fSDavid van Moolenbroek * test interface.
674*3ba6090fSDavid van Moolenbroek */
675*3ba6090fSDavid van Moolenbroek if (src.sin6_scope_id != 0 && src.sin6_scope_id != ifindex) e(0);
676*3ba6090fSDavid van Moolenbroek
677*3ba6090fSDavid van Moolenbroek /* Is it the expected candidate source address? */
678*3ba6090fSDavid van Moolenbroek if (!memcmp(&src.sin6_addr, &src0->addr.sin6_addr,
679*3ba6090fSDavid van Moolenbroek sizeof(src.sin6_addr))) {
680*3ba6090fSDavid van Moolenbroek if (result != 0) e(0);
681*3ba6090fSDavid van Moolenbroek } else if (!memcmp(&src.sin6_addr, &src1->addr.sin6_addr,
682*3ba6090fSDavid van Moolenbroek sizeof(src.sin6_addr))) {
683*3ba6090fSDavid van Moolenbroek if (result != 1) e(0);
684*3ba6090fSDavid van Moolenbroek } else if (src2 != NULL && !memcmp(&src.sin6_addr,
685*3ba6090fSDavid van Moolenbroek &src2->addr.sin6_addr, sizeof(src.sin6_addr))) {
686*3ba6090fSDavid van Moolenbroek if (result != 2) e(0);
687*3ba6090fSDavid van Moolenbroek } else
688*3ba6090fSDavid van Moolenbroek e(0);
689*3ba6090fSDavid van Moolenbroek
690*3ba6090fSDavid van Moolenbroek /* Clean up. */
691*3ba6090fSDavid van Moolenbroek if (close(fd) != 0) e(0);
692*3ba6090fSDavid van Moolenbroek
693*3ba6090fSDavid van Moolenbroek if (rt_res == 0) {
694*3ba6090fSDavid van Moolenbroek if (test93_route_cmd(RTM_DELETE, (struct sockaddr *)dest,
695*3ba6090fSDavid van Moolenbroek sizeof(*dest), 128, 0, NULL, NULL, 0) != 0) e(0);
696*3ba6090fSDavid van Moolenbroek }
697*3ba6090fSDavid van Moolenbroek
698*3ba6090fSDavid van Moolenbroek if (src2 != NULL)
699*3ba6090fSDavid van Moolenbroek test93_ipv6_addr(0, TEST_IFNAME, &src2->addr, src2->prefix, 0,
700*3ba6090fSDavid van Moolenbroek 0, 0);
701*3ba6090fSDavid van Moolenbroek
702*3ba6090fSDavid van Moolenbroek test93_ipv6_addr(0, TEST_IFNAME, &src1->addr, src1->prefix, 0, 0, 0);
703*3ba6090fSDavid van Moolenbroek
704*3ba6090fSDavid van Moolenbroek test93_ipv6_addr(0, TEST_IFNAME, &src0->addr, src0->prefix, 0, 0, 0);
705*3ba6090fSDavid van Moolenbroek }
706*3ba6090fSDavid van Moolenbroek
707*3ba6090fSDavid van Moolenbroek /*
708*3ba6090fSDavid van Moolenbroek * IPv6 source address selection algorithm test.
709*3ba6090fSDavid van Moolenbroek */
710*3ba6090fSDavid van Moolenbroek static void
test93b(void)711*3ba6090fSDavid van Moolenbroek test93b(void)
712*3ba6090fSDavid van Moolenbroek {
713*3ba6090fSDavid van Moolenbroek static const int order[][3] = {
714*3ba6090fSDavid van Moolenbroek { 0, 1, 2 },
715*3ba6090fSDavid van Moolenbroek { 1, 0, 2 },
716*3ba6090fSDavid van Moolenbroek { 0, 2, 1 },
717*3ba6090fSDavid van Moolenbroek { 1, 2, 0 },
718*3ba6090fSDavid van Moolenbroek { 2, 0, 1 },
719*3ba6090fSDavid van Moolenbroek { 2, 1, 0 }
720*3ba6090fSDavid van Moolenbroek };
721*3ba6090fSDavid van Moolenbroek struct sockaddr_in6 dest;
722*3ba6090fSDavid van Moolenbroek struct src_addr src[3];
723*3ba6090fSDavid van Moolenbroek unsigned int i, j, k, count, ifindex;
724*3ba6090fSDavid van Moolenbroek int result;
725*3ba6090fSDavid van Moolenbroek
726*3ba6090fSDavid van Moolenbroek subtest = 2;
727*3ba6090fSDavid van Moolenbroek
728*3ba6090fSDavid van Moolenbroek if (test93_create_if() != 0)
729*3ba6090fSDavid van Moolenbroek return; /* skip this test */
730*3ba6090fSDavid van Moolenbroek
731*3ba6090fSDavid van Moolenbroek if ((ifindex = if_nametoindex(TEST_IFNAME)) == 0) e(0);
732*3ba6090fSDavid van Moolenbroek
733*3ba6090fSDavid van Moolenbroek test93_set_if_up(TEST_IFNAME, 1);
734*3ba6090fSDavid van Moolenbroek
735*3ba6090fSDavid van Moolenbroek for (i = 0; i < __arraycount(test93b_table); i++) {
736*3ba6090fSDavid van Moolenbroek memset(&dest, 0, sizeof(dest));
737*3ba6090fSDavid van Moolenbroek dest.sin6_family = AF_INET6;
738*3ba6090fSDavid van Moolenbroek if (inet_pton(AF_INET6, test93b_table[i].dest_addr,
739*3ba6090fSDavid van Moolenbroek &dest.sin6_addr) != 1) e(0);
740*3ba6090fSDavid van Moolenbroek
741*3ba6090fSDavid van Moolenbroek memset(&src[0].addr, 0, sizeof(src[0].addr));
742*3ba6090fSDavid van Moolenbroek src[0].addr.sin6_family = AF_INET6;
743*3ba6090fSDavid van Moolenbroek if (inet_pton(AF_INET6, test93b_table[i].src0_addr,
744*3ba6090fSDavid van Moolenbroek &src[0].addr.sin6_addr) != 1) e(0);
745*3ba6090fSDavid van Moolenbroek src[0].prefix = test93b_table[i].src0_prefix;
746*3ba6090fSDavid van Moolenbroek src[0].flags = test93b_table[i].src0_flags;
747*3ba6090fSDavid van Moolenbroek
748*3ba6090fSDavid van Moolenbroek memset(&src[1].addr, 0, sizeof(src[1].addr));
749*3ba6090fSDavid van Moolenbroek src[1].addr.sin6_family = AF_INET6;
750*3ba6090fSDavid van Moolenbroek if (inet_pton(AF_INET6, test93b_table[i].src1_addr,
751*3ba6090fSDavid van Moolenbroek &src[1].addr.sin6_addr) != 1) e(0);
752*3ba6090fSDavid van Moolenbroek src[1].prefix = test93b_table[i].src1_prefix;
753*3ba6090fSDavid van Moolenbroek src[1].flags = test93b_table[i].src1_flags;
754*3ba6090fSDavid van Moolenbroek
755*3ba6090fSDavid van Moolenbroek if (test93b_table[i].src2_addr != NULL) {
756*3ba6090fSDavid van Moolenbroek memset(&src[2].addr, 0, sizeof(src[2].addr));
757*3ba6090fSDavid van Moolenbroek src[2].addr.sin6_family = AF_INET6;
758*3ba6090fSDavid van Moolenbroek if (inet_pton(AF_INET6, test93b_table[i].src2_addr,
759*3ba6090fSDavid van Moolenbroek &src[2].addr.sin6_addr) != 1) e(0);
760*3ba6090fSDavid van Moolenbroek src[2].prefix = test93b_table[i].src2_prefix;
761*3ba6090fSDavid van Moolenbroek src[2].flags = test93b_table[i].src2_flags;
762*3ba6090fSDavid van Moolenbroek
763*3ba6090fSDavid van Moolenbroek count = 6;
764*3ba6090fSDavid van Moolenbroek } else
765*3ba6090fSDavid van Moolenbroek count = 2;
766*3ba6090fSDavid van Moolenbroek
767*3ba6090fSDavid van Moolenbroek result = test93b_table[i].result;
768*3ba6090fSDavid van Moolenbroek
769*3ba6090fSDavid van Moolenbroek /*
770*3ba6090fSDavid van Moolenbroek * Try all orders for the source addresses. The permutation
771*3ba6090fSDavid van Moolenbroek * part can be done much better, but it really does not matter.
772*3ba6090fSDavid van Moolenbroek */
773*3ba6090fSDavid van Moolenbroek for (j = 0; j < count; j++) {
774*3ba6090fSDavid van Moolenbroek for (k = 0; k < count; k++)
775*3ba6090fSDavid van Moolenbroek if (result == -1 || order[j][k] == result)
776*3ba6090fSDavid van Moolenbroek break;
777*3ba6090fSDavid van Moolenbroek
778*3ba6090fSDavid van Moolenbroek sub93b((result != -1) ? k : 0, &dest, ifindex,
779*3ba6090fSDavid van Moolenbroek &src[order[j][0]], &src[order[j][1]],
780*3ba6090fSDavid van Moolenbroek (count > 2) ? &src[order[j][2]] : NULL);
781*3ba6090fSDavid van Moolenbroek }
782*3ba6090fSDavid van Moolenbroek }
783*3ba6090fSDavid van Moolenbroek
784*3ba6090fSDavid van Moolenbroek if (test93_destroy_if() != 0) e(0);
785*3ba6090fSDavid van Moolenbroek }
786*3ba6090fSDavid van Moolenbroek
787*3ba6090fSDavid van Moolenbroek /*
788*3ba6090fSDavid van Moolenbroek * Interface index number wrapping test.
789*3ba6090fSDavid van Moolenbroek */
790*3ba6090fSDavid van Moolenbroek static void
test93c(void)791*3ba6090fSDavid van Moolenbroek test93c(void)
792*3ba6090fSDavid van Moolenbroek {
793*3ba6090fSDavid van Moolenbroek unsigned int i;
794*3ba6090fSDavid van Moolenbroek
795*3ba6090fSDavid van Moolenbroek subtest = 3;
796*3ba6090fSDavid van Moolenbroek
797*3ba6090fSDavid van Moolenbroek /* There might not be an available loopback interface at all. */
798*3ba6090fSDavid van Moolenbroek if (test93_create_if() != 0)
799*3ba6090fSDavid van Moolenbroek return; /* skip this test */
800*3ba6090fSDavid van Moolenbroek
801*3ba6090fSDavid van Moolenbroek if (test93_destroy_if() != 0) e(0);
802*3ba6090fSDavid van Moolenbroek
803*3ba6090fSDavid van Moolenbroek /*
804*3ba6090fSDavid van Moolenbroek * During the development of the LWIP service, the lwIP library's
805*3ba6090fSDavid van Moolenbroek * interface index assignment was still in its infancy. This test aims
806*3ba6090fSDavid van Moolenbroek * to ensure that future changes in the library do not break our
807*3ba6090fSDavid van Moolenbroek * service.
808*3ba6090fSDavid van Moolenbroek */
809*3ba6090fSDavid van Moolenbroek for (i = 0; i < UINT8_MAX + 1; i++) {
810*3ba6090fSDavid van Moolenbroek if (test93_create_if() != 0) e(0);
811*3ba6090fSDavid van Moolenbroek
812*3ba6090fSDavid van Moolenbroek if (test93_destroy_if() != 0) e(0);
813*3ba6090fSDavid van Moolenbroek }
814*3ba6090fSDavid van Moolenbroek }
815*3ba6090fSDavid van Moolenbroek
816*3ba6090fSDavid van Moolenbroek /*
817*3ba6090fSDavid van Moolenbroek * Test program for LWIP interface and routing management.
818*3ba6090fSDavid van Moolenbroek */
819*3ba6090fSDavid van Moolenbroek int
main(int argc,char ** argv)820*3ba6090fSDavid van Moolenbroek main(int argc, char ** argv)
821*3ba6090fSDavid van Moolenbroek {
822*3ba6090fSDavid van Moolenbroek int i, m;
823*3ba6090fSDavid van Moolenbroek
824*3ba6090fSDavid van Moolenbroek start(93);
825*3ba6090fSDavid van Moolenbroek
826*3ba6090fSDavid van Moolenbroek if (argc == 2)
827*3ba6090fSDavid van Moolenbroek m = atoi(argv[1]);
828*3ba6090fSDavid van Moolenbroek else
829*3ba6090fSDavid van Moolenbroek m = 0xFF;
830*3ba6090fSDavid van Moolenbroek
831*3ba6090fSDavid van Moolenbroek for (i = 0; i < ITERATIONS; i++) {
832*3ba6090fSDavid van Moolenbroek if (m & 0x01) test93a();
833*3ba6090fSDavid van Moolenbroek if (m & 0x02) test93b();
834*3ba6090fSDavid van Moolenbroek if (m & 0x04) test93c();
835*3ba6090fSDavid van Moolenbroek }
836*3ba6090fSDavid van Moolenbroek
837*3ba6090fSDavid van Moolenbroek quit();
838*3ba6090fSDavid van Moolenbroek /* NOTREACHED */
839*3ba6090fSDavid van Moolenbroek }
840