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 log_info("Lifetime: %" PRIu16
, lifetime
);
67 if (sd_ndisc_router_get_mtu(rt
, &mtu
) < 0)
68 log_info("No MTU set");
70 log_info("MTU: %" PRIu32
, mtu
);
72 r
= sd_ndisc_router_option_rewind(rt
);
81 assert_se(sd_ndisc_router_option_get_type(rt
, &type
) >= 0);
83 log_info(">> Option %u", type
);
87 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS
:
88 case SD_NDISC_OPTION_TARGET_LL_ADDRESS
: {
89 _cleanup_free_
char *c
= NULL
;
93 assert_se(sd_ndisc_router_option_get_raw(rt
, &p
, &n
) >= 0);
95 assert_se(c
= hexmem((uint8_t*) p
+ 2, n
- 2));
97 log_info("Address: %s", c
);
101 case SD_NDISC_OPTION_PREFIX_INFORMATION
: {
102 uint32_t lifetime_valid
, lifetime_preferred
;
107 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt
, &lifetime_valid
) >= 0);
108 log_info("Valid Lifetime: %" PRIu32
, lifetime_valid
);
110 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt
, &lifetime_preferred
) >= 0);
111 log_info("Preferred Lifetime: %" PRIu32
, lifetime_preferred
);
113 assert_se(sd_ndisc_router_prefix_get_flags(rt
, &pfl
) >= 0);
114 log_info("Flags: <%s|%s>",
115 pfl
& ND_OPT_PI_FLAG_ONLINK
? "ONLINK" : "",
116 pfl
& ND_OPT_PI_FLAG_AUTO
? "AUTO" : "");
118 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt
, &prefix_len
) >= 0);
119 log_info("Prefix Length: %u", prefix_len
);
121 assert_se(sd_ndisc_router_prefix_get_address(rt
, &a
) >= 0);
122 log_info("Prefix: %s", IN6_ADDR_TO_STRING(&a
));
127 case SD_NDISC_OPTION_RDNSS
: {
128 const struct in6_addr
*a
;
132 n
= sd_ndisc_router_rdnss_get_addresses(rt
, &a
);
135 for (i
= 0; i
< n
; i
++)
136 log_info("DNS: %s", IN6_ADDR_TO_STRING(a
+ i
));
138 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt
, <
) >= 0);
139 log_info("Lifetime: %" PRIu32
, lt
);
143 case SD_NDISC_OPTION_DNSSL
: {
144 _cleanup_strv_free_
char **l
= NULL
;
148 n
= sd_ndisc_router_dnssl_get_domains(rt
, &l
);
151 for (i
= 0; i
< n
; i
++)
152 log_info("Domain: %s", l
[i
]);
154 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt
, <
) >= 0);
155 log_info("Lifetime: %" PRIu32
, lt
);
159 r
= sd_ndisc_router_option_next(rt
);
163 static int send_ra(uint8_t flags
) {
164 uint8_t advertisement
[] = {
165 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
166 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
167 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
168 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
169 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
171 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
172 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
174 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
175 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
176 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
180 advertisement
[5] = flags
;
182 assert_se(write(test_fd
[1], advertisement
, sizeof(advertisement
)) ==
183 sizeof(advertisement
));
186 printf(" sent RA with flag 0x%02x\n", flags
);
191 static void test_callback(sd_ndisc
*nd
, sd_ndisc_event_t event
, sd_ndisc_router
*rt
, void *userdata
) {
192 sd_event
*e
= userdata
;
193 static unsigned idx
= 0;
194 uint64_t flags_array
[] = {
205 if (event
!= SD_NDISC_EVENT_ROUTER
)
210 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
211 assert_se(flags
== flags_array
[idx
]);
215 printf(" got event 0x%02" PRIx64
"\n", flags
);
217 if (idx
< ELEMENTSOF(flags_array
)) {
218 send_ra(flags_array
[idx
]);
226 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
227 _cleanup_(sd_ndisc_unrefp
) sd_ndisc
*nd
= NULL
;
229 send_ra_function
= send_ra
;
231 assert_se(sd_event_new(&e
) >= 0);
233 assert_se(sd_ndisc_new(&nd
) >= 0);
236 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
238 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
239 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
240 assert_se(sd_ndisc_set_callback(nd
, test_callback
, e
) >= 0);
242 assert_se(sd_event_add_time_relative(e
, NULL
, CLOCK_BOOTTIME
,
243 30 * USEC_PER_SEC
, 0,
244 NULL
, INT_TO_PTR(-ETIMEDOUT
)) >= 0);
246 assert_se(sd_ndisc_stop(nd
) >= 0);
247 assert_se(sd_ndisc_start(nd
) >= 0);
248 assert_se(sd_ndisc_start(nd
) >= 0);
249 assert_se(sd_ndisc_stop(nd
) >= 0);
250 test_fd
[1] = safe_close(test_fd
[1]);
252 assert_se(sd_ndisc_start(nd
) >= 0);
254 assert_se(sd_event_loop(e
) >= 0);
256 test_fd
[1] = safe_close(test_fd
[1]);
259 static int test_timeout_value(uint8_t flags
) {
260 static int count
= 0;
261 static usec_t last
= 0;
262 sd_ndisc
*nd
= test_timeout_nd
;
266 assert_se(nd
->event
);
269 sd_event_exit(nd
->event
, 0);
272 /* initial RT = IRT + RAND*IRT */
273 min
= NDISC_ROUTER_SOLICITATION_INTERVAL
-
274 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
275 max
= NDISC_ROUTER_SOLICITATION_INTERVAL
+
276 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
278 /* next RT = 2*RTprev + RAND*RTprev */
279 min
= 2 * last
- last
/ 10;
280 max
= 2 * last
+ last
/ 10;
284 if (last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
) {
285 min
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
-
286 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
287 max
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
+
288 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
291 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
293 last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
? "(max) ": "",
294 FORMAT_TIMESPAN(min
, USEC_PER_MSEC
),
295 FORMAT_TIMESPAN(nd
->retransmit_time
, USEC_PER_MSEC
),
296 FORMAT_TIMESPAN(max
, USEC_PER_MSEC
));
298 assert_se(min
<= nd
->retransmit_time
);
299 assert_se(max
>= nd
->retransmit_time
);
301 last
= nd
->retransmit_time
;
303 assert_se(sd_event_source_set_time(nd
->timeout_event_source
, 0) >= 0);
309 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
310 _cleanup_(sd_ndisc_unrefp
) sd_ndisc
*nd
= NULL
;
312 send_ra_function
= test_timeout_value
;
314 assert_se(sd_event_new(&e
) >= 0);
316 assert_se(sd_ndisc_new(&nd
) >= 0);
319 test_timeout_nd
= nd
;
321 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
323 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
324 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
326 assert_se(sd_event_add_time_relative(e
, NULL
, CLOCK_BOOTTIME
,
327 30 * USEC_PER_SEC
, 0,
328 NULL
, INT_TO_PTR(-ETIMEDOUT
)) >= 0);
330 assert_se(sd_ndisc_start(nd
) >= 0);
332 assert_se(sd_event_loop(e
) >= 0);
334 test_fd
[1] = safe_close(test_fd
[1]);
337 DEFINE_TEST_MAIN(LOG_DEBUG
);