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. */
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.
15 #include <sys/socket.h>
16 #include <sys/ioctl.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>
27 #define TEST_IFNAME "lo93"
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
)] = {
37 -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
,
40 -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
,
43 -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
,
51 [C_GETSOCKOPT_ERR
] = {
64 -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
,
67 -EAGAIN
, 0, -EAGAIN
, 0,
70 -EAGAIN
, 0, -EAGAIN
, 0,
73 -ENOBUFS
, -ENOBUFS
, -EPIPE
, -EPIPE
,
76 -EISCONN
, -EISCONN
, -EPIPE
, -EPIPE
,
110 static const int lnk_results
[][__arraycount(rtlnk_states
)] = {
112 -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
,
115 -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
,
118 -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
,
121 -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
,
124 -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
,
126 [C_GETSOCKOPT_ERR
] = {
129 [C_GETSOCKOPT_KA
] = {
132 [C_GETSOCKOPT_RB
] = {
133 -ENOPROTOOPT
, -ENOPROTOOPT
, -ENOPROTOOPT
, -ENOPROTOOPT
,
139 -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
, -EOPNOTSUPP
,
142 -EOPNOTSUPP
, 0, -EOPNOTSUPP
, 0,
145 -EOPNOTSUPP
, 0, -EOPNOTSUPP
, 0,
148 -EOPNOTSUPP
, -EOPNOTSUPP
, -EPIPE
, -EPIPE
,
151 -EOPNOTSUPP
, -EOPNOTSUPP
, -EPIPE
, -EPIPE
,
162 [C_SETSOCKOPT_BC
] = {
165 [C_SETSOCKOPT_KA
] = {
171 [C_SETSOCKOPT_RA
] = {
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
191 rtlnk_sweep(int domain
, int type
, int protocol
, enum state state
,
197 memset(&sa
, 0, sizeof(sa
));
198 sa
.sa_family
= domain
;
200 if ((fd
= socket(domain
, type
| SOCK_NONBLOCK
, protocol
)) < 0) e(0);
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;
210 r
= socklib_sweep_call(call
, fd
, &sa
, &sa
,
211 offsetof(struct sockaddr
, sa_data
));
213 if (close(fd
) != 0) e(0);
219 * Sweep test for socket calls versus socket states of routing and link
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.
247 test93_destroy_if(void)
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);
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.
270 test93_destroy_if_atexit(void)
272 static int atexit_set
= 0;
275 (void)test93_destroy_if();
282 * Attempt to create a test loopback interface. Return 0 if creation was
283 * successful, or -1 if no more interfaces could be created.
286 test93_create_if(void)
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
);
309 * Set the interface-up value for an interface to the given boolean value.
312 test93_set_if_up(const char * ifname
, int up
)
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);
325 ifr
.ifr_flags
|= IFF_UP
;
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.
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
;
350 memset(sin6
->sin6_addr
.s6_addr
, 0xff, byte
);
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.
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
;
375 unsigned int i
, iovlen
;
378 memset(&rtm
, 0, sizeof(rtm
));
379 rtm
.rtm_version
= RTM_VERSION
;
381 rtm
.rtm_flags
= flags
;
382 rtm
.rtm_addrs
= RTA_DST
| RTA_NETMASK
;
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
));
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
) {
410 if (prefix
> 32) e(0);
411 memset(&mask4
, 0, sizeof(mask4
));
412 mask4
.sin_family
= AF_INET
;
414 mask4
.sin_addr
.s_addr
= htonl(0xffffffffUL
<< prefix
);
416 memcpy(&maskss
, &mask4
, sizeof(mask4
));
417 maskss
.ss_len
= sizeof(mask4
);
422 test93_make_netmask6(&mask6
, prefix
);
424 memcpy(&maskss
, &mask6
, sizeof(mask6
));
425 maskss
.ss_len
= sizeof(mask6
);
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
) +
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
,
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
));
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);
467 * We could just shut down the socket for reading, but this is just an
468 * extra test we can do basically for free.
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
);
479 if (rtm
.rtm_errno
!= err
) e(0);
480 if (rtm
.rtm_flags
& RTF_DONE
) e(0);
482 if (rtm
.rtm_errno
!= 0) e(0);
483 if (!(rtm
.rtm_flags
& RTF_DONE
)) e(0);
486 if (close(fd
) != 0) e(0);
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.
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
;
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)
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
;
528 const char *src1_addr
;
529 unsigned int src1_prefix
;
531 const char *src2_addr
;
532 unsigned int src2_prefix
;
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,
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,
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 },
612 struct sockaddr_in6 addr
;
618 * Test source address selection with a particular destination address and two
619 * or three source addresses.
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
;
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
);
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)
667 /* Obtain the selected source address. */
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
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);
691 if (close(fd
) != 0) e(0);
694 if (test93_route_cmd(RTM_DELETE
, (struct sockaddr
*)dest
,
695 sizeof(*dest
), 128, 0, NULL
, NULL
, 0) != 0) e(0);
699 test93_ipv6_addr(0, TEST_IFNAME
, &src2
->addr
, src2
->prefix
, 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.
713 static const int order
[][3] = {
721 struct sockaddr_in6 dest
;
722 struct src_addr src
[3];
723 unsigned int i
, j
, k
, count
, ifindex
;
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
;
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
)
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.
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
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
)
831 for (i
= 0; i
< ITERATIONS
; i
++) {
832 if (m
& 0x01) test93a();
833 if (m
& 0x02) test93b();
834 if (m
& 0x04) test93c();