1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 2014 Intel Corporation. All rights reserved.
6 #include <netinet/icmp6.h>
12 #include "alloc-util.h"
13 #include "hexdecoct.h"
14 #include "icmp6-util.h"
15 #include "socket-util.h"
17 #include "ndisc-internal.h"
20 static struct ether_addr mac_addr
= {
21 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
24 static bool verbose
= false;
25 static sd_event_source
*test_hangcheck
;
26 static int test_fd
[2];
27 static sd_ndisc
*test_timeout_nd
;
29 typedef int (*send_ra_t
)(uint8_t flags
);
30 static send_ra_t send_ra_function
;
32 static void router_dump(sd_ndisc_router
*rt
) {
34 char buf
[FORMAT_TIMESTAMP_MAX
];
45 assert_se(sd_ndisc_router_get_address(rt
, &addr
) == -ENODATA
);
47 assert_se(sd_ndisc_router_get_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
48 log_info("Timestamp: %s", format_timestamp(buf
, sizeof(buf
), t
));
50 assert_se(sd_ndisc_router_get_timestamp(rt
, CLOCK_MONOTONIC
, &t
) >= 0);
51 log_info("Monotonic: %" PRIu64
, t
);
53 if (sd_ndisc_router_get_hop_limit(rt
, &hop_limit
) < 0)
54 log_info("No hop limit set");
56 log_info("Hop limit: %u", hop_limit
);
58 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
59 log_info("Flags: <%s|%s>",
60 flags
& ND_RA_FLAG_OTHER
? "OTHER" : "",
61 flags
& ND_RA_FLAG_MANAGED
? "MANAGED" : "");
63 assert_se(sd_ndisc_router_get_preference(rt
, &preference
) >= 0);
64 log_info("Preference: %s",
65 preference
== SD_NDISC_PREFERENCE_LOW
? "low" :
66 preference
== SD_NDISC_PREFERENCE_HIGH
? "high" : "medium");
68 assert_se(sd_ndisc_router_get_lifetime(rt
, &lifetime
) >= 0);
69 log_info("Lifetime: %" PRIu16
, lifetime
);
71 if (sd_ndisc_router_get_mtu(rt
, &mtu
) < 0)
72 log_info("No MTU set");
74 log_info("MTU: %" PRIu32
, mtu
);
76 r
= sd_ndisc_router_option_rewind(rt
);
85 assert_se(sd_ndisc_router_option_get_type(rt
, &type
) >= 0);
87 log_info(">> Option %u", type
);
91 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS
:
92 case SD_NDISC_OPTION_TARGET_LL_ADDRESS
: {
93 _cleanup_free_
char *c
= NULL
;
97 assert_se(sd_ndisc_router_option_get_raw(rt
, &p
, &n
) >= 0);
99 assert_se(c
= hexmem((uint8_t*) p
+ 2, n
- 2));
101 log_info("Address: %s", c
);
105 case SD_NDISC_OPTION_PREFIX_INFORMATION
: {
106 uint32_t lifetime_valid
, lifetime_preferred
;
110 char buff
[INET6_ADDRSTRLEN
];
112 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt
, &lifetime_valid
) >= 0);
113 log_info("Valid Lifetime: %" PRIu32
, lifetime_valid
);
115 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt
, &lifetime_preferred
) >= 0);
116 log_info("Preferred Lifetime: %" PRIu32
, lifetime_preferred
);
118 assert_se(sd_ndisc_router_prefix_get_flags(rt
, &pfl
) >= 0);
119 log_info("Flags: <%s|%s>",
120 pfl
& ND_OPT_PI_FLAG_ONLINK
? "ONLINK" : "",
121 pfl
& ND_OPT_PI_FLAG_AUTO
? "AUTO" : "");
123 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt
, &prefix_len
) >= 0);
124 log_info("Prefix Length: %u", prefix_len
);
126 assert_se(sd_ndisc_router_prefix_get_address(rt
, &a
) >= 0);
127 log_info("Prefix: %s", inet_ntop(AF_INET6
, &a
, buff
, sizeof(buff
)));
132 case SD_NDISC_OPTION_RDNSS
: {
133 const struct in6_addr
*a
;
137 n
= sd_ndisc_router_rdnss_get_addresses(rt
, &a
);
140 for (i
= 0; i
< n
; i
++) {
141 char buff
[INET6_ADDRSTRLEN
];
142 log_info("DNS: %s", inet_ntop(AF_INET6
, a
+ i
, buff
, sizeof(buff
)));
145 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt
, <
) >= 0);
146 log_info("Lifetime: %" PRIu32
, lt
);
150 case SD_NDISC_OPTION_DNSSL
: {
151 _cleanup_strv_free_
char **l
= NULL
;
155 n
= sd_ndisc_router_dnssl_get_domains(rt
, &l
);
158 for (i
= 0; i
< n
; i
++)
159 log_info("Domain: %s", l
[i
]);
161 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt
, <
) >= 0);
162 log_info("Lifetime: %" PRIu32
, lt
);
166 r
= sd_ndisc_router_option_next(rt
);
170 static int test_rs_hangcheck(sd_event_source
*s
, uint64_t usec
,
177 int icmp6_bind_router_solicitation(int index
) {
178 assert_se(index
== 42);
180 if (socketpair(AF_UNIX
, SOCK_DGRAM
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, 0, test_fd
) < 0)
186 int icmp6_bind_router_advertisement(int index
) {
191 int icmp6_receive(int fd
, void *iov_base
, size_t iov_len
,
192 struct in6_addr
*dst
, triple_timestamp
*timestamp
) {
193 assert_se(read (fd
, iov_base
, iov_len
) == (ssize_t
)iov_len
);
196 triple_timestamp_get(timestamp
);
201 static int send_ra(uint8_t flags
) {
202 uint8_t advertisement
[] = {
203 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
204 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
206 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
207 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
210 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
212 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
213 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
214 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
218 advertisement
[5] = flags
;
220 assert_se(write(test_fd
[1], advertisement
, sizeof(advertisement
)) ==
221 sizeof(advertisement
));
224 printf(" sent RA with flag 0x%02x\n", flags
);
229 int icmp6_send_router_solicitation(int s
, const struct ether_addr
*ether_addr
) {
230 if (!send_ra_function
)
233 return send_ra_function(0);
236 static void test_callback(sd_ndisc
*nd
, sd_ndisc_event event
, sd_ndisc_router
*rt
, void *userdata
) {
237 sd_event
*e
= userdata
;
238 static unsigned idx
= 0;
239 uint64_t flags_array
[] = {
251 if (event
!= SD_NDISC_EVENT_ROUTER
)
256 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
257 assert_se(flags
== flags_array
[idx
]);
261 printf(" got event 0x%02" PRIx64
"\n", flags
);
263 if (idx
< ELEMENTSOF(flags_array
)) {
264 send_ra(flags_array
[idx
]);
268 assert_se(sd_ndisc_get_mtu(nd
, &mtu
) == -ENODATA
);
273 static void test_rs(void) {
276 usec_t time_now
= now(clock_boottime_or_monotonic());
279 printf("* %s\n", __FUNCTION__
);
281 send_ra_function
= send_ra
;
283 assert_se(sd_event_new(&e
) >= 0);
285 assert_se(sd_ndisc_new(&nd
) >= 0);
288 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
290 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
291 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
292 assert_se(sd_ndisc_set_callback(nd
, test_callback
, e
) >= 0);
294 assert_se(sd_event_add_time(e
, &test_hangcheck
, clock_boottime_or_monotonic(),
295 time_now
+ 2 *USEC_PER_SEC
, 0,
296 test_rs_hangcheck
, NULL
) >= 0);
298 assert_se(sd_ndisc_stop(nd
) >= 0);
299 assert_se(sd_ndisc_start(nd
) >= 0);
300 assert_se(sd_ndisc_start(nd
) >= 0);
301 assert_se(sd_ndisc_stop(nd
) >= 0);
303 assert_se(sd_ndisc_start(nd
) >= 0);
307 test_hangcheck
= sd_event_source_unref(test_hangcheck
);
309 nd
= sd_ndisc_unref(nd
);
317 static int test_timeout_value(uint8_t flags
) {
318 static int count
= 0;
319 static usec_t last
= 0;
320 sd_ndisc
*nd
= test_timeout_nd
;
322 char time_string_min
[FORMAT_TIMESPAN_MAX
];
323 char time_string_nd
[FORMAT_TIMESPAN_MAX
];
324 char time_string_max
[FORMAT_TIMESPAN_MAX
];
327 assert_se(nd
->event
);
330 sd_event_exit(nd
->event
, 0);
333 /* initial RT = IRT + RAND*IRT */
334 min
= NDISC_ROUTER_SOLICITATION_INTERVAL
-
335 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
336 max
= NDISC_ROUTER_SOLICITATION_INTERVAL
+
337 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
339 /* next RT = 2*RTprev + RAND*RTprev */
340 min
= 2 * last
- last
/ 10;
341 max
= 2 * last
+ last
/ 10;
345 if (last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
) {
346 min
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
-
347 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
348 max
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
+
349 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
352 format_timespan(time_string_min
, FORMAT_TIMESPAN_MAX
,
354 format_timespan(time_string_nd
, FORMAT_TIMESPAN_MAX
,
355 nd
->retransmit_time
, USEC_PER_MSEC
);
356 format_timespan(time_string_max
, FORMAT_TIMESPAN_MAX
,
359 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
361 (last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
)? "(max) ": "",
362 time_string_min
, time_string_nd
, time_string_max
);
364 assert_se(min
<= nd
->retransmit_time
);
365 assert_se(max
>= nd
->retransmit_time
);
367 last
= nd
->retransmit_time
;
369 assert_se(sd_event_source_set_time(nd
->timeout_event_source
, 0) >= 0);
374 static void test_timeout(void) {
377 usec_t time_now
= now(clock_boottime_or_monotonic());
380 printf("* %s\n", __FUNCTION__
);
382 send_ra_function
= test_timeout_value
;
384 assert_se(sd_event_new(&e
) >= 0);
386 assert_se(sd_ndisc_new(&nd
) >= 0);
389 test_timeout_nd
= nd
;
391 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
393 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
394 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
396 assert_se(sd_event_add_time(e
, &test_hangcheck
, clock_boottime_or_monotonic(),
397 time_now
+ 2U * USEC_PER_SEC
, 0,
398 test_rs_hangcheck
, NULL
) >= 0);
400 assert_se(sd_ndisc_start(nd
) >= 0);
404 test_hangcheck
= sd_event_source_unref(test_hangcheck
);
406 nd
= sd_ndisc_unref(nd
);
411 int main(int argc
, char *argv
[]) {
413 test_setup_logging(LOG_DEBUG
);