1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 2014 Intel Corporation. All rights reserved.
6 #include <netinet/icmp6.h>
11 #include "alloc-util.h"
12 #include "hexdecoct.h"
13 #include "icmp6-util.h"
14 #include "socket-util.h"
16 #include "ndisc-internal.h"
19 static struct ether_addr mac_addr
= {
20 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
23 static bool verbose
= false;
24 static sd_event_source
*test_hangcheck
;
25 static int test_fd
[2];
26 static sd_ndisc
*test_timeout_nd
;
28 typedef int (*send_ra_t
)(uint8_t flags
);
29 static send_ra_t send_ra_function
;
31 static void router_dump(sd_ndisc_router
*rt
) {
33 char buf
[FORMAT_TIMESTAMP_MAX
];
44 assert_se(sd_ndisc_router_get_address(rt
, &addr
) == -ENODATA
);
46 assert_se(sd_ndisc_router_get_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
47 log_info("Timestamp: %s", format_timestamp(buf
, sizeof(buf
), t
));
49 assert_se(sd_ndisc_router_get_timestamp(rt
, CLOCK_MONOTONIC
, &t
) >= 0);
50 log_info("Monotonic: %" PRIu64
, t
);
52 if (sd_ndisc_router_get_hop_limit(rt
, &hop_limit
) < 0)
53 log_info("No hop limit set");
55 log_info("Hop limit: %u", hop_limit
);
57 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
58 log_info("Flags: <%s|%s>",
59 flags
& ND_RA_FLAG_OTHER
? "OTHER" : "",
60 flags
& ND_RA_FLAG_MANAGED
? "MANAGED" : "");
62 assert_se(sd_ndisc_router_get_preference(rt
, &preference
) >= 0);
63 log_info("Preference: %s",
64 preference
== SD_NDISC_PREFERENCE_LOW
? "low" :
65 preference
== SD_NDISC_PREFERENCE_HIGH
? "high" : "medium");
67 assert_se(sd_ndisc_router_get_lifetime(rt
, &lifetime
) >= 0);
68 log_info("Lifetime: %" PRIu16
, lifetime
);
70 if (sd_ndisc_router_get_mtu(rt
, &mtu
) < 0)
71 log_info("No MTU set");
73 log_info("MTU: %" PRIu32
, mtu
);
75 r
= sd_ndisc_router_option_rewind(rt
);
84 assert_se(sd_ndisc_router_option_get_type(rt
, &type
) >= 0);
86 log_info(">> Option %u", type
);
90 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS
:
91 case SD_NDISC_OPTION_TARGET_LL_ADDRESS
: {
92 _cleanup_free_
char *c
= NULL
;
96 assert_se(sd_ndisc_router_option_get_raw(rt
, &p
, &n
) >= 0);
98 assert_se(c
= hexmem((uint8_t*) p
+ 2, n
- 2));
100 log_info("Address: %s", c
);
104 case SD_NDISC_OPTION_PREFIX_INFORMATION
: {
105 uint32_t lifetime_valid
, lifetime_preferred
;
109 char buff
[INET6_ADDRSTRLEN
];
111 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt
, &lifetime_valid
) >= 0);
112 log_info("Valid Lifetime: %" PRIu32
, lifetime_valid
);
114 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt
, &lifetime_preferred
) >= 0);
115 log_info("Preferred Lifetime: %" PRIu32
, lifetime_preferred
);
117 assert_se(sd_ndisc_router_prefix_get_flags(rt
, &pfl
) >= 0);
118 log_info("Flags: <%s|%s>",
119 pfl
& ND_OPT_PI_FLAG_ONLINK
? "ONLINK" : "",
120 pfl
& ND_OPT_PI_FLAG_AUTO
? "AUTO" : "");
122 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt
, &prefix_len
) >= 0);
123 log_info("Prefix Length: %u", prefix_len
);
125 assert_se(sd_ndisc_router_prefix_get_address(rt
, &a
) >= 0);
126 log_info("Prefix: %s", inet_ntop(AF_INET6
, &a
, buff
, sizeof(buff
)));
131 case SD_NDISC_OPTION_RDNSS
: {
132 const struct in6_addr
*a
;
136 n
= sd_ndisc_router_rdnss_get_addresses(rt
, &a
);
139 for (i
= 0; i
< n
; i
++) {
140 char buff
[INET6_ADDRSTRLEN
];
141 log_info("DNS: %s", inet_ntop(AF_INET6
, a
+ i
, buff
, sizeof(buff
)));
144 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt
, <
) >= 0);
145 log_info("Lifetime: %" PRIu32
, lt
);
149 case SD_NDISC_OPTION_DNSSL
: {
150 _cleanup_strv_free_
char **l
= NULL
;
154 n
= sd_ndisc_router_dnssl_get_domains(rt
, &l
);
157 for (i
= 0; i
< n
; i
++)
158 log_info("Domain: %s", l
[i
]);
160 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt
, <
) >= 0);
161 log_info("Lifetime: %" PRIu32
, lt
);
165 r
= sd_ndisc_router_option_next(rt
);
169 static int test_rs_hangcheck(sd_event_source
*s
, uint64_t usec
,
176 int icmp6_bind_router_solicitation(int index
) {
177 assert_se(index
== 42);
179 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, test_fd
) < 0)
185 int icmp6_bind_router_advertisement(int index
) {
190 int icmp6_receive(int fd
, void *iov_base
, size_t iov_len
,
191 struct in6_addr
*dst
, triple_timestamp
*timestamp
) {
192 assert_se(read (fd
, iov_base
, iov_len
) == (ssize_t
)iov_len
);
195 triple_timestamp_get(timestamp
);
200 static int send_ra(uint8_t flags
) {
201 uint8_t advertisement
[] = {
202 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
203 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
205 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
206 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
207 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
209 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
210 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
211 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
212 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
213 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
217 advertisement
[5] = flags
;
219 assert_se(write(test_fd
[1], advertisement
, sizeof(advertisement
)) ==
220 sizeof(advertisement
));
223 printf(" sent RA with flag 0x%02x\n", flags
);
228 int icmp6_send_router_solicitation(int s
, const struct ether_addr
*ether_addr
) {
229 if (!send_ra_function
)
232 return send_ra_function(0);
235 static void test_callback(sd_ndisc
*nd
, sd_ndisc_event event
, sd_ndisc_router
*rt
, void *userdata
) {
236 sd_event
*e
= userdata
;
237 static unsigned idx
= 0;
238 uint64_t flags_array
[] = {
250 if (event
!= SD_NDISC_EVENT_ROUTER
)
255 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
256 assert_se(flags
== flags_array
[idx
]);
260 printf(" got event 0x%02" PRIx64
"\n", flags
);
262 if (idx
< ELEMENTSOF(flags_array
)) {
263 send_ra(flags_array
[idx
]);
267 assert_se(sd_ndisc_get_mtu(nd
, &mtu
) == -ENODATA
);
272 static void test_rs(void) {
275 usec_t time_now
= now(clock_boottime_or_monotonic());
278 printf("* %s\n", __FUNCTION__
);
280 send_ra_function
= send_ra
;
282 assert_se(sd_event_new(&e
) >= 0);
284 assert_se(sd_ndisc_new(&nd
) >= 0);
287 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
289 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
290 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
291 assert_se(sd_ndisc_set_callback(nd
, test_callback
, e
) >= 0);
293 assert_se(sd_event_add_time(e
, &test_hangcheck
, clock_boottime_or_monotonic(),
294 time_now
+ 2 *USEC_PER_SEC
, 0,
295 test_rs_hangcheck
, NULL
) >= 0);
297 assert_se(sd_ndisc_stop(nd
) >= 0);
298 assert_se(sd_ndisc_start(nd
) >= 0);
299 assert_se(sd_ndisc_stop(nd
) >= 0);
301 assert_se(sd_ndisc_start(nd
) >= 0);
305 test_hangcheck
= sd_event_source_unref(test_hangcheck
);
307 nd
= sd_ndisc_unref(nd
);
315 static int test_timeout_value(uint8_t flags
) {
316 static int count
= 0;
317 static usec_t last
= 0;
318 sd_ndisc
*nd
= test_timeout_nd
;
320 char time_string_min
[FORMAT_TIMESPAN_MAX
];
321 char time_string_nd
[FORMAT_TIMESPAN_MAX
];
322 char time_string_max
[FORMAT_TIMESPAN_MAX
];
325 assert_se(nd
->event
);
328 sd_event_exit(nd
->event
, 0);
331 /* initial RT = IRT + RAND*IRT */
332 min
= NDISC_ROUTER_SOLICITATION_INTERVAL
-
333 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
334 max
= NDISC_ROUTER_SOLICITATION_INTERVAL
+
335 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
337 /* next RT = 2*RTprev + RAND*RTprev */
338 min
= 2 * last
- last
/ 10;
339 max
= 2 * last
+ last
/ 10;
343 if (last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
) {
344 min
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
-
345 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
346 max
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
+
347 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
350 format_timespan(time_string_min
, FORMAT_TIMESPAN_MAX
,
352 format_timespan(time_string_nd
, FORMAT_TIMESPAN_MAX
,
353 nd
->retransmit_time
, USEC_PER_MSEC
);
354 format_timespan(time_string_max
, FORMAT_TIMESPAN_MAX
,
357 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
359 (last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
)? "(max) ": "",
360 time_string_min
, time_string_nd
, time_string_max
);
362 assert_se(min
<= nd
->retransmit_time
);
363 assert_se(max
>= nd
->retransmit_time
);
365 last
= nd
->retransmit_time
;
367 assert_se(sd_event_source_set_time(nd
->timeout_event_source
, 0) >= 0);
372 static void test_timeout(void) {
375 usec_t time_now
= now(clock_boottime_or_monotonic());
378 printf("* %s\n", __FUNCTION__
);
380 send_ra_function
= test_timeout_value
;
382 assert_se(sd_event_new(&e
) >= 0);
384 assert_se(sd_ndisc_new(&nd
) >= 0);
387 test_timeout_nd
= nd
;
389 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
391 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
392 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
394 assert_se(sd_event_add_time(e
, &test_hangcheck
, clock_boottime_or_monotonic(),
395 time_now
+ 2U * USEC_PER_SEC
, 0,
396 test_rs_hangcheck
, NULL
) >= 0);
398 assert_se(sd_ndisc_start(nd
) >= 0);
402 test_hangcheck
= sd_event_source_unref(test_hangcheck
);
404 nd
= sd_ndisc_unref(nd
);
409 int main(int argc
, char *argv
[]) {
411 test_setup_logging(LOG_DEBUG
);