1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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 ifindex
) {
178 assert_se(ifindex
== 42);
180 if (socketpair(AF_UNIX
, SOCK_DGRAM
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, 0, test_fd
) < 0)
186 int icmp6_bind_router_advertisement(int ifindex
) {
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) {
277 printf("* %s\n", __FUNCTION__
);
279 send_ra_function
= send_ra
;
281 assert_se(sd_event_new(&e
) >= 0);
283 assert_se(sd_ndisc_new(&nd
) >= 0);
286 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
288 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
289 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
290 assert_se(sd_ndisc_set_callback(nd
, test_callback
, e
) >= 0);
292 assert_se(sd_event_add_time_relative(
293 e
, &test_hangcheck
, clock_boottime_or_monotonic(),
294 30 * 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_start(nd
) >= 0);
300 assert_se(sd_ndisc_stop(nd
) >= 0);
302 assert_se(sd_ndisc_start(nd
) >= 0);
306 test_hangcheck
= sd_event_source_unref(test_hangcheck
);
308 nd
= sd_ndisc_unref(nd
);
316 static int test_timeout_value(uint8_t flags
) {
317 static int count
= 0;
318 static usec_t last
= 0;
319 sd_ndisc
*nd
= test_timeout_nd
;
321 char time_string_min
[FORMAT_TIMESPAN_MAX
];
322 char time_string_nd
[FORMAT_TIMESPAN_MAX
];
323 char time_string_max
[FORMAT_TIMESPAN_MAX
];
326 assert_se(nd
->event
);
329 sd_event_exit(nd
->event
, 0);
332 /* initial RT = IRT + RAND*IRT */
333 min
= NDISC_ROUTER_SOLICITATION_INTERVAL
-
334 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
335 max
= NDISC_ROUTER_SOLICITATION_INTERVAL
+
336 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
338 /* next RT = 2*RTprev + RAND*RTprev */
339 min
= 2 * last
- last
/ 10;
340 max
= 2 * last
+ last
/ 10;
344 if (last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
) {
345 min
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
-
346 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
347 max
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
+
348 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
351 format_timespan(time_string_min
, FORMAT_TIMESPAN_MAX
,
353 format_timespan(time_string_nd
, FORMAT_TIMESPAN_MAX
,
354 nd
->retransmit_time
, USEC_PER_MSEC
);
355 format_timespan(time_string_max
, FORMAT_TIMESPAN_MAX
,
358 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
360 (last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
)? "(max) ": "",
361 time_string_min
, time_string_nd
, time_string_max
);
363 assert_se(min
<= nd
->retransmit_time
);
364 assert_se(max
>= nd
->retransmit_time
);
366 last
= nd
->retransmit_time
;
368 assert_se(sd_event_source_set_time(nd
->timeout_event_source
, 0) >= 0);
373 static void test_timeout(void) {
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_relative(
395 e
, &test_hangcheck
, clock_boottime_or_monotonic(),
396 30 * USEC_PER_SEC
, 0,
397 test_rs_hangcheck
, NULL
) >= 0);
399 assert_se(sd_ndisc_start(nd
) >= 0);
403 test_hangcheck
= sd_event_source_unref(test_hangcheck
);
405 nd
= sd_ndisc_unref(nd
);
410 int main(int argc
, char *argv
[]) {
412 test_setup_logging(LOG_DEBUG
);