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"
14 #include "hexdecoct.h"
15 #include "icmp6-util-unix.h"
16 #include "socket-util.h"
18 #include "ndisc-internal.h"
21 static struct ether_addr mac_addr
= {
22 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
25 static bool verbose
= false;
26 static sd_ndisc
*test_timeout_nd
;
28 static void router_dump(sd_ndisc_router
*rt
) {
40 assert_se(sd_ndisc_router_get_address(rt
, &addr
) >= 0);
41 log_info("Sender: %s", IN6_ADDR_TO_STRING(&addr
));
43 assert_se(sd_ndisc_router_get_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
44 log_info("Timestamp: %s", FORMAT_TIMESTAMP(t
));
46 assert_se(sd_ndisc_router_get_timestamp(rt
, CLOCK_MONOTONIC
, &t
) >= 0);
47 log_info("Monotonic: %" PRIu64
, t
);
49 if (sd_ndisc_router_get_hop_limit(rt
, &hop_limit
) < 0)
50 log_info("No hop limit set");
52 log_info("Hop limit: %u", hop_limit
);
54 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
55 log_info("Flags: <%s|%s>",
56 flags
& ND_RA_FLAG_OTHER
? "OTHER" : "",
57 flags
& ND_RA_FLAG_MANAGED
? "MANAGED" : "");
59 assert_se(sd_ndisc_router_get_preference(rt
, &preference
) >= 0);
60 log_info("Preference: %s",
61 preference
== SD_NDISC_PREFERENCE_LOW
? "low" :
62 preference
== SD_NDISC_PREFERENCE_HIGH
? "high" : "medium");
64 assert_se(sd_ndisc_router_get_lifetime(rt
, &lifetime
) >= 0);
65 assert_se(sd_ndisc_router_get_lifetime_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
66 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime
, USEC_PER_SEC
), FORMAT_TIMESTAMP(t
));
68 if (sd_ndisc_router_get_mtu(rt
, &mtu
) < 0)
69 log_info("No MTU set");
71 log_info("MTU: %" PRIu32
, mtu
);
73 r
= sd_ndisc_router_option_rewind(rt
);
82 assert_se(sd_ndisc_router_option_get_type(rt
, &type
) >= 0);
84 log_info(">> Option %u", type
);
88 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS
:
89 case SD_NDISC_OPTION_TARGET_LL_ADDRESS
: {
90 _cleanup_free_
char *c
= NULL
;
94 assert_se(sd_ndisc_router_option_get_raw(rt
, &p
, &n
) >= 0);
96 assert_se(c
= hexmem((uint8_t*) p
+ 2, n
- 2));
98 log_info("Address: %s", c
);
102 case SD_NDISC_OPTION_PREFIX_INFORMATION
: {
107 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt
, &lifetime
) >= 0);
108 assert_se(sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
109 log_info("Valid Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime
, USEC_PER_SEC
), FORMAT_TIMESTAMP(t
));
111 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt
, &lifetime
) >= 0);
112 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
113 log_info("Preferred Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime
, USEC_PER_SEC
), FORMAT_TIMESTAMP(t
));
115 assert_se(sd_ndisc_router_prefix_get_flags(rt
, &pfl
) >= 0);
116 log_info("Flags: <%s|%s>",
117 pfl
& ND_OPT_PI_FLAG_ONLINK
? "ONLINK" : "",
118 pfl
& ND_OPT_PI_FLAG_AUTO
? "AUTO" : "");
120 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt
, &prefix_len
) >= 0);
121 log_info("Prefix Length: %u", prefix_len
);
123 assert_se(sd_ndisc_router_prefix_get_address(rt
, &a
) >= 0);
124 log_info("Prefix: %s", IN6_ADDR_TO_STRING(&a
));
129 case SD_NDISC_OPTION_RDNSS
: {
130 const struct in6_addr
*a
;
133 n
= sd_ndisc_router_rdnss_get_addresses(rt
, &a
);
136 for (i
= 0; i
< n
; i
++)
137 log_info("DNS: %s", IN6_ADDR_TO_STRING(a
+ i
));
139 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt
, &lifetime
) >= 0);
140 assert_se(sd_ndisc_router_rdnss_get_lifetime_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
141 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime
, USEC_PER_SEC
), FORMAT_TIMESTAMP(t
));
145 case SD_NDISC_OPTION_DNSSL
: {
146 _cleanup_strv_free_
char **l
= NULL
;
149 n
= sd_ndisc_router_dnssl_get_domains(rt
, &l
);
152 for (i
= 0; i
< n
; i
++)
153 log_info("Domain: %s", l
[i
]);
155 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt
, &lifetime
) >= 0);
156 assert_se(sd_ndisc_router_dnssl_get_lifetime_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
157 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime
, USEC_PER_SEC
), FORMAT_TIMESTAMP(t
));
161 r
= sd_ndisc_router_option_next(rt
);
165 static int send_ra(uint8_t flags
) {
166 uint8_t advertisement
[] = {
167 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
170 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
171 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
174 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
176 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
177 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
178 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
182 advertisement
[5] = flags
;
184 assert_se(write(test_fd
[1], advertisement
, sizeof(advertisement
)) ==
185 sizeof(advertisement
));
188 printf(" sent RA with flag 0x%02x\n", flags
);
193 static void test_callback(sd_ndisc
*nd
, sd_ndisc_event_t event
, sd_ndisc_router
*rt
, void *userdata
) {
194 sd_event
*e
= userdata
;
195 static unsigned idx
= 0;
196 uint64_t flags_array
[] = {
207 if (event
!= SD_NDISC_EVENT_ROUTER
)
212 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
213 assert_se(flags
== flags_array
[idx
]);
217 printf(" got event 0x%02" PRIx64
"\n", flags
);
219 if (idx
< ELEMENTSOF(flags_array
)) {
220 send_ra(flags_array
[idx
]);
228 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
229 _cleanup_(sd_ndisc_unrefp
) sd_ndisc
*nd
= NULL
;
231 send_ra_function
= send_ra
;
233 assert_se(sd_event_new(&e
) >= 0);
235 assert_se(sd_ndisc_new(&nd
) >= 0);
238 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
240 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
241 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
242 assert_se(sd_ndisc_set_callback(nd
, test_callback
, e
) >= 0);
244 assert_se(sd_event_add_time_relative(e
, NULL
, CLOCK_BOOTTIME
,
245 30 * USEC_PER_SEC
, 0,
246 NULL
, INT_TO_PTR(-ETIMEDOUT
)) >= 0);
248 assert_se(sd_ndisc_stop(nd
) >= 0);
249 assert_se(sd_ndisc_start(nd
) >= 0);
250 assert_se(sd_ndisc_start(nd
) >= 0);
251 assert_se(sd_ndisc_stop(nd
) >= 0);
252 test_fd
[1] = safe_close(test_fd
[1]);
254 assert_se(sd_ndisc_start(nd
) >= 0);
256 assert_se(sd_event_loop(e
) >= 0);
258 test_fd
[1] = safe_close(test_fd
[1]);
261 static int test_timeout_value(uint8_t flags
) {
262 static int count
= 0;
263 static usec_t last
= 0;
264 sd_ndisc
*nd
= test_timeout_nd
;
268 assert_se(nd
->event
);
271 sd_event_exit(nd
->event
, 0);
274 /* initial RT = IRT + RAND*IRT */
275 min
= NDISC_ROUTER_SOLICITATION_INTERVAL
-
276 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
277 max
= NDISC_ROUTER_SOLICITATION_INTERVAL
+
278 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
280 /* next RT = 2*RTprev + RAND*RTprev */
281 min
= 2 * last
- last
/ 10;
282 max
= 2 * last
+ last
/ 10;
286 if (last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
) {
287 min
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
-
288 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
289 max
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
+
290 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
293 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
295 last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
? "(max) ": "",
296 FORMAT_TIMESPAN(min
, USEC_PER_MSEC
),
297 FORMAT_TIMESPAN(nd
->retransmit_time
, USEC_PER_MSEC
),
298 FORMAT_TIMESPAN(max
, USEC_PER_MSEC
));
300 assert_se(min
<= nd
->retransmit_time
);
301 assert_se(max
>= nd
->retransmit_time
);
303 last
= nd
->retransmit_time
;
305 assert_se(sd_event_source_set_time(nd
->timeout_event_source
, 0) >= 0);
311 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
312 _cleanup_(sd_ndisc_unrefp
) sd_ndisc
*nd
= NULL
;
314 send_ra_function
= test_timeout_value
;
316 assert_se(sd_event_new(&e
) >= 0);
318 assert_se(sd_ndisc_new(&nd
) >= 0);
321 test_timeout_nd
= nd
;
323 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
325 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
326 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
328 assert_se(sd_event_add_time_relative(e
, NULL
, CLOCK_BOOTTIME
,
329 30 * USEC_PER_SEC
, 0,
330 NULL
, INT_TO_PTR(-ETIMEDOUT
)) >= 0);
332 assert_se(sd_ndisc_start(nd
) >= 0);
334 assert_se(sd_event_loop(e
) >= 0);
336 test_fd
[1] = safe_close(test_fd
[1]);
339 DEFINE_TEST_MAIN(LOG_DEBUG
);