2 * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL
);
32 /* Forcibly enable assertions */
38 #include <ipxe/ipv6.h>
39 #include <ipxe/test.h>
41 /** Define inline IPv6 address */
42 #define IPV6(...) { __VA_ARGS__ }
44 /** An IPv6 test routing table entry */
45 struct ipv6_test_route
{
49 unsigned int prefix_len
;
50 /** Router address (if any) */
54 /** An IPv6 test routing table */
55 struct ipv6_test_table
{
56 /** Test routing table entries */
57 const struct ipv6_test_route
*routes
;
58 /** Number of table entries */
60 /** Constructed routing table */
61 struct list_head list
;
64 /** Define a test routing table */
65 #define TABLE( name, ... ) \
66 static const struct ipv6_test_route name ## _routes[] = { \
69 static struct ipv6_test_table name = { \
70 .routes = name ## _routes, \
71 .count = ( sizeof ( name ## _routes ) / \
72 sizeof ( name ## _routes[0] ) ), \
73 .list = LIST_HEAD_INIT ( name.list ), \
76 /** The unspecified IPv6 address */
77 static const struct in6_addr sample_unspecified
= {
78 .s6_addr
= IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ),
82 /** A sample link-local IPv6 address */
83 static const struct in6_addr sample_link_local
= {
84 .s6_addr
= IPV6 ( 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85 0x00, 0x00, 0x69, 0xff, 0xfe, 0x50, 0x58, 0x45 ),
88 /** A sample site-local IPv6 address */
89 static const struct in6_addr sample_site_local
= {
90 .s6_addr
= IPV6 ( 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 ),
94 /** A sample ULA IPv6 address */
95 static const struct in6_addr sample_ula
= {
96 .s6_addr
= IPV6 ( 0xfd, 0x44, 0x91, 0x12, 0x64, 0x42, 0x00, 0x00,
97 0x00, 0x00, 0x69, 0xff, 0xfe, 0x50, 0x58, 0x45 ),
100 /** A sample global IPv6 address */
101 static const struct in6_addr sample_global
= {
102 .s6_addr
= IPV6 ( 0x20, 0x01, 0x0b, 0xa8, 0x00, 0x00, 0x01, 0xd4,
103 0x00, 0x00, 0x00, 0x00, 0x69, 0x50, 0x58, 0x45 ),
106 /** A sample multicast IPv6 address */
107 static const struct in6_addr sample_multicast
= {
108 .s6_addr
= IPV6 ( 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ),
112 /** Dummy network device used for routing tests */
113 static struct net_device ipv6_test_netdev
= {
114 .refcnt
= REF_INIT ( ref_no_free
),
116 .state
= NETDEV_OPEN
,
119 /** Routing table with only a link-local address */
120 TABLE ( table_link_local
,
121 { "fe80::69ff:fe50:5845", 64, NULL
} );
123 /** Routing table with a global address */
124 TABLE ( table_normal
,
125 { "fe80::69ff:fe50:5845", 64, NULL
},
126 { "2001:db8:3::1", 64, "fe80::1" } );
128 /** Routing table with multiple addresses and routers */
130 { "fe80::69ff:fe50:5845", 64, NULL
},
131 { "2001:db8:3::1", 64, "fe80::1" },
132 { "2001:db8:5::1", 64, NULL
},
133 { "2001:db8:42::1", 64, "fe80::2" },
134 { "fd44:9112:6442::69ff:fe50:5845", 64, "fe80::1" },
135 { "fd70:6ba9:50ae::69ff:fe50:5845", 64, "fe80::3" } );
138 * Report an inet6_ntoa() test result
140 * @v addr IPv6 address
141 * @v text Expected textual representation
142 * @v file Test code file
143 * @v line Test code line
145 static void inet6_ntoa_okx ( const struct in6_addr
*addr
, const char *text
,
146 const char *file
, unsigned int line
) {
149 actual
= inet6_ntoa ( addr
);
150 DBG ( "inet6_ntoa ( %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ) "
151 "= %s\n", ntohs ( addr
->s6_addr16
[0] ),
152 ntohs ( addr
->s6_addr16
[1] ), ntohs ( addr
->s6_addr16
[2] ),
153 ntohs ( addr
->s6_addr16
[3] ), ntohs ( addr
->s6_addr16
[4] ),
154 ntohs ( addr
->s6_addr16
[5] ), ntohs ( addr
->s6_addr16
[6] ),
155 ntohs ( addr
->s6_addr16
[7] ), actual
);
156 okx ( strcmp ( actual
, text
) == 0, file
, line
);
158 #define inet6_ntoa_ok( addr, text ) do { \
159 static const struct in6_addr in = { \
162 inet6_ntoa_okx ( &in, text, __FILE__, __LINE__ ); \
166 * Report an inet6_aton() test result
168 * @v text Textual representation
169 * @v addr Expected IPv6 address
170 * @v file Test code file
171 * @v line Test code line
173 static void inet6_aton_okx ( const char *text
, const struct in6_addr
*addr
,
174 const char *file
, unsigned int line
) {
175 struct in6_addr actual
;
177 okx ( inet6_aton ( text
, &actual
) == 0, file
, line
);
178 DBG ( "inet6_aton ( \"%s\" ) = %s\n", text
, inet6_ntoa ( &actual
) );
179 okx ( memcmp ( &actual
, addr
, sizeof ( actual
) ) == 0,
182 #define inet6_aton_ok( text, addr ) do { \
183 static const struct in6_addr in = { \
186 inet6_aton_okx ( text, &in, __FILE__, __LINE__ ); \
190 * Report an inet6_aton() failure test result
192 * @v text Textual representation
193 * @v file Test code file
194 * @v line Test code line
196 static void inet6_aton_fail_okx ( const char *text
, const char *file
,
197 unsigned int line
) {
198 struct in6_addr dummy
;
200 okx ( inet6_aton ( text
, &dummy
) != 0, file
, line
);
202 #define inet6_aton_fail_ok( text ) \
203 inet6_aton_fail_okx ( text, __FILE__, __LINE__ )
206 * Create test routing table
208 * @v table Test routing table
209 * @v file Test code file
210 * @v line Test code line
212 static void ipv6_table_okx ( struct ipv6_test_table
*table
, const char *file
,
213 unsigned int line
) {
214 const struct ipv6_test_route
*route
;
215 struct in6_addr address
;
216 struct in6_addr router
;
217 struct list_head saved
;
221 okx ( list_empty ( &table
->list
), file
, line
);
223 /* Save existing routing table */
224 INIT_LIST_HEAD ( &saved
);
225 list_splice_init ( &ipv6_miniroutes
, &saved
);
227 /* Construct routing table */
228 for ( i
= 0 ; i
< table
->count
; i
++ ) {
230 /* Parse address and router (if applicable) */
231 route
= &table
->routes
[i
];
232 okx ( inet6_aton ( route
->address
, &address
) == 0,
234 if ( route
->router
) {
235 okx ( inet6_aton ( route
->router
, &router
) == 0,
239 /* Add routing table entry */
240 okx ( ipv6_add_miniroute ( &ipv6_test_netdev
, &address
,
243 &router
: NULL
) ) == 0,
247 /* Save constructed routing table */
248 list_splice_init ( &ipv6_miniroutes
, &table
->list
);
250 /* Restore original routing table */
251 list_splice ( &saved
, &ipv6_miniroutes
);
253 #define ipv6_table_ok( table ) \
254 ipv6_table_okx ( table, __FILE__, __LINE__ )
257 * Report an ipv6_route() test result
259 * @v table Test routing table
260 * @v dest Destination address
261 * @v src Expected source address, or NULL to expect failure
262 * @v next Expected next hop address, or NULL to expect destination
263 * @v file Test code file
264 * @v line Test code line
266 static void ipv6_route_okx ( struct ipv6_test_table
*table
, const char *dest
,
267 const char *src
, const char *next
,
268 const char *file
, unsigned int line
) {
269 struct in6_addr in_dest
;
270 struct in6_addr in_src
;
271 struct in6_addr in_next
;
272 struct in6_addr
*actual
;
273 struct ipv6_miniroute
*miniroute
;
274 struct list_head saved
;
276 /* Switch to test routing table */
277 INIT_LIST_HEAD ( &saved
);
278 list_splice_init ( &ipv6_miniroutes
, &saved
);
279 list_splice_init ( &table
->list
, &ipv6_miniroutes
);
281 /* Parse addresses */
282 okx ( inet6_aton ( dest
, &in_dest
) == 0, file
, line
);
284 okx ( inet6_aton ( src
, &in_src
) == 0, file
, line
);
286 okx ( inet6_aton ( next
, &in_next
) == 0, file
, line
);
288 memcpy ( &in_next
, &in_dest
, sizeof ( in_next
) );
291 /* Perform routing */
293 miniroute
= ipv6_route ( ipv6_test_netdev
.index
, &actual
);
295 /* Validate result */
298 /* Check that a route was found */
299 okx ( miniroute
!= NULL
, file
, line
);
300 DBG ( "ipv6_route ( %s ) = %s", dest
, inet6_ntoa ( actual
) );
301 DBG ( " from %s\n", inet6_ntoa ( &miniroute
->address
) );
303 /* Check that expected source address was used */
304 okx ( memcmp ( &miniroute
->address
, &in_src
,
305 sizeof ( in_src
) ) == 0, file
, line
);
307 /* Check that expected next hop address was used */
308 okx ( memcmp ( actual
, &in_next
, sizeof ( *actual
) ) == 0,
313 /* Routing is expected to fail */
314 okx ( miniroute
== NULL
, file
, line
);
317 /* Restore original routing table */
318 list_splice_init ( &ipv6_miniroutes
, &table
->list
);
319 list_splice ( &saved
, &ipv6_miniroutes
);
321 #define ipv6_route_ok( table, dest, src, next ) \
322 ipv6_route_okx ( table, dest, src, next, __FILE__, __LINE__ )
325 * Destroy test routing table
327 * @v table Test routing table
329 static void ipv6_table_del ( struct ipv6_test_table
*table
) {
330 struct ipv6_miniroute
*miniroute
;
331 struct ipv6_miniroute
*tmp
;
332 struct list_head saved
;
334 /* Switch to test routing table */
335 INIT_LIST_HEAD ( &saved
);
336 list_splice_init ( &ipv6_miniroutes
, &saved
);
337 list_splice_init ( &table
->list
, &ipv6_miniroutes
);
339 /* Delete all existing routes */
340 list_for_each_entry_safe ( miniroute
, tmp
, &ipv6_miniroutes
, list
)
341 ipv6_del_miniroute ( miniroute
);
343 /* Restore original routing table */
344 list_splice ( &saved
, &ipv6_miniroutes
);
348 * Perform IPv6 self-tests
351 static void ipv6_test_exec ( void ) {
353 /* Address testing macros */
354 ok ( IN6_IS_ADDR_UNSPECIFIED ( &sample_unspecified
) );
355 ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_link_local
) );
356 ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_site_local
) );
357 ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_ula
) );
358 ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_global
) );
359 ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_multicast
) );
360 ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_unspecified
) );
361 ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_link_local
) );
362 ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_site_local
) );
363 ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_ula
) );
364 ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_global
) );
365 ok ( IN6_IS_ADDR_MULTICAST ( &sample_multicast
) );
366 ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_unspecified
) );
367 ok ( IN6_IS_ADDR_LINKLOCAL ( &sample_link_local
) );
368 ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_site_local
) );
369 ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_ula
) );
370 ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_global
) );
371 ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_multicast
) );
372 ok ( ! IN6_IS_ADDR_SITELOCAL ( &sample_unspecified
) );
373 ok ( ! IN6_IS_ADDR_SITELOCAL ( &sample_link_local
) );
374 ok ( IN6_IS_ADDR_SITELOCAL ( &sample_site_local
) );
375 ok ( ! IN6_IS_ADDR_SITELOCAL ( &sample_ula
) );
376 ok ( ! IN6_IS_ADDR_SITELOCAL ( &sample_global
) );
377 ok ( ! IN6_IS_ADDR_SITELOCAL ( &sample_multicast
) );
378 ok ( ! IN6_IS_ADDR_ULA ( &sample_unspecified
) );
379 ok ( ! IN6_IS_ADDR_ULA ( &sample_link_local
) );
380 ok ( ! IN6_IS_ADDR_ULA ( &sample_site_local
) );
381 ok ( IN6_IS_ADDR_ULA ( &sample_ula
) );
382 ok ( ! IN6_IS_ADDR_ULA ( &sample_global
) );
383 ok ( ! IN6_IS_ADDR_ULA ( &sample_multicast
) );
385 /* inet6_ntoa() tests */
386 inet6_ntoa_ok ( IPV6 ( 0x20, 0x01, 0x0b, 0xa8, 0x00, 0x00, 0x01, 0xd4,
387 0x00, 0x00, 0x00, 0x00, 0x69, 0x50, 0x58, 0x45 ),
388 "2001:ba8:0:1d4::6950:5845" );
390 inet6_ntoa_ok ( IPV6 ( 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x01,
391 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01 ),
392 "2001:db8:1:1:1:1:1:1" );
394 inet6_ntoa_ok ( IPV6 ( 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
395 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ),
397 /* No "::" for single zero */
398 inet6_ntoa_ok ( IPV6 ( 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x01,
399 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01 ),
400 "2001:db8:0:1:1:1:1:1" );
401 /* Use "::" for longest run of zeros */
402 inet6_ntoa_ok ( IPV6 ( 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
403 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ),
405 /* Use "::" for leftmost equal-length run of zeros */
406 inet6_ntoa_ok ( IPV6 ( 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
407 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ),
408 "2001:db8::1:0:0:1" );
409 /* Trailing run of zeros */
410 inet6_ntoa_ok ( IPV6 ( 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
411 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ),
413 /* Leading run of zeros */
414 inet6_ntoa_ok ( IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
415 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ),
418 inet6_ntoa_ok ( IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
419 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ),
422 inet6_ntoa_ok ( IPV6 ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
423 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ),
424 "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" );
426 /* inet6_aton() tests */
427 inet6_aton_ok ( "2001:ba8:0:1d4::6950:5845",
428 IPV6 ( 0x20, 0x01, 0x0b, 0xa8, 0x00, 0x00, 0x01, 0xd4,
429 0x00, 0x00, 0x00, 0x00, 0x69, 0x50, 0x58, 0x45));
431 inet6_aton_ok ( "2001:db8:1:1:1:1:1:1",
432 IPV6 ( 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x01,
433 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01));
434 /* All intervening zeros */
435 inet6_aton_ok ( "fe80::1",
436 IPV6 ( 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
437 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01));
438 /* Trailing run of zeros */
439 inet6_aton_ok ( "fe80::",
440 IPV6 ( 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
441 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
442 /* Leading run of zeros */
443 inet6_aton_ok ( "::1",
444 IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
445 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01));
447 inet6_aton_ok ( "::",
448 IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
449 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
451 /* inet6_aton() failure tests */
452 inet6_aton_fail_ok ( "20012:ba8:0:1d4::6950:5845" );
453 inet6_aton_fail_ok ( "200z:ba8:0:1d4::6950:5845" );
454 inet6_aton_fail_ok ( "2001.ba8:0:1d4::6950:5845" );
455 inet6_aton_fail_ok ( "2001:db8:1:1:1:1:1" );
456 inet6_aton_fail_ok ( "2001:db8:1:1:1:1:1:1:2" );
457 inet6_aton_fail_ok ( "2001:db8::1::2" );
458 inet6_aton_fail_ok ( "2001:ba8:0:1d4:::6950:5845" );
459 inet6_aton_fail_ok ( ":::" );
461 /* Create test routing tables */
462 ipv6_table_ok ( &table_link_local
);
463 ipv6_table_ok ( &table_normal
);
464 ipv6_table_ok ( &table_multi
);
466 /* Routing table with only a link-local address */
467 ipv6_route_ok ( &table_link_local
, "fe80::1",
468 "fe80::69ff:fe50:5845", NULL
);
469 ipv6_route_ok ( &table_link_local
, "2001:db8:1::1",
471 ipv6_route_ok ( &table_link_local
, "ff02::1",
472 "fe80::69ff:fe50:5845", NULL
);
474 /** Routing table with a global address */
475 ipv6_route_ok ( &table_normal
, "fe80::1",
476 "fe80::69ff:fe50:5845", NULL
);
477 ipv6_route_ok ( &table_normal
, "2001:db8:3::42",
478 "2001:db8:3::1", NULL
);
479 ipv6_route_ok ( &table_normal
, "2001:ba8:0:1d4::6950:5845",
480 "2001:db8:3::1", "fe80::1" );
481 ipv6_route_ok ( &table_normal
, "ff02::1",
482 "fe80::69ff:fe50:5845", NULL
);
483 ipv6_route_ok ( &table_normal
, "ff0e::1",
484 "2001:db8:3::1", NULL
);
486 /** Routing table with multiple addresses and routers */
487 ipv6_route_ok ( &table_multi
, "fe80::1",
488 "fe80::69ff:fe50:5845", NULL
);
489 ipv6_route_ok ( &table_multi
, "2001:db8:3::17",
490 "2001:db8:3::1", NULL
);
491 ipv6_route_ok ( &table_multi
, "2001:db8:5::92",
492 "2001:db8:5::1", NULL
);
493 ipv6_route_ok ( &table_multi
, "2001:db8:42::17",
494 "2001:db8:42::1", NULL
);
495 ipv6_route_ok ( &table_multi
, "2001:db8:5:1::17",
496 "2001:db8:3::1", "fe80::1" );
497 ipv6_route_ok ( &table_multi
, "fd44:9112:6442::1",
498 "fd44:9112:6442::69ff:fe50:5845", NULL
);
499 ipv6_route_ok ( &table_multi
, "fd70:6ba9:50ae::1",
500 "fd70:6ba9:50ae::69ff:fe50:5845", NULL
);
501 ipv6_route_ok ( &table_multi
, "fd40::3",
502 "fd44:9112:6442::69ff:fe50:5845", "fe80::1" );
503 ipv6_route_ok ( &table_multi
, "fd70::2",
504 "fd70:6ba9:50ae::69ff:fe50:5845", "fe80::3" );
505 ipv6_route_ok ( &table_multi
, "ff02::1",
506 "fe80::69ff:fe50:5845", NULL
);
508 /* Destroy test routing tables */
509 ipv6_table_del ( &table_link_local
);
510 ipv6_table_del ( &table_normal
);
511 ipv6_table_del ( &table_multi
);
514 /** IPv6 self-test */
515 struct self_test ipv6_test __self_test
= {
517 .exec
= ipv6_test_exec
,