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