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.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 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
) {
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(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
;
110 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt
, &lifetime_valid
) >= 0);
111 log_info("Valid Lifetime: %" PRIu32
, lifetime_valid
);
113 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt
, &lifetime_preferred
) >= 0);
114 log_info("Preferred Lifetime: %" PRIu32
, lifetime_preferred
);
116 assert_se(sd_ndisc_router_prefix_get_flags(rt
, &pfl
) >= 0);
117 log_info("Flags: <%s|%s>",
118 pfl
& ND_OPT_PI_FLAG_ONLINK
? "ONLINK" : "",
119 pfl
& ND_OPT_PI_FLAG_AUTO
? "AUTO" : "");
121 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt
, &prefix_len
) >= 0);
122 log_info("Prefix Length: %u", prefix_len
);
124 assert_se(sd_ndisc_router_prefix_get_address(rt
, &a
) >= 0);
125 log_info("Prefix: %s", IN6_ADDR_TO_STRING(&a
));
130 case SD_NDISC_OPTION_RDNSS
: {
131 const struct in6_addr
*a
;
135 n
= sd_ndisc_router_rdnss_get_addresses(rt
, &a
);
138 for (i
= 0; i
< n
; i
++)
139 log_info("DNS: %s", IN6_ADDR_TO_STRING(a
+ i
));
141 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt
, <
) >= 0);
142 log_info("Lifetime: %" PRIu32
, lt
);
146 case SD_NDISC_OPTION_DNSSL
: {
147 _cleanup_strv_free_
char **l
= NULL
;
151 n
= sd_ndisc_router_dnssl_get_domains(rt
, &l
);
154 for (i
= 0; i
< n
; i
++)
155 log_info("Domain: %s", l
[i
]);
157 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt
, <
) >= 0);
158 log_info("Lifetime: %" PRIu32
, lt
);
162 r
= sd_ndisc_router_option_next(rt
);
166 int icmp6_bind_router_solicitation(int ifindex
) {
167 assert_se(ifindex
== 42);
169 if (socketpair(AF_UNIX
, SOCK_DGRAM
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, 0, test_fd
) < 0)
175 int icmp6_bind_router_advertisement(int ifindex
) {
179 int icmp6_receive(int fd
, void *iov_base
, size_t iov_len
,
180 struct in6_addr
*dst
, triple_timestamp
*timestamp
) {
181 assert_se(read (fd
, iov_base
, iov_len
) == (ssize_t
)iov_len
);
184 triple_timestamp_get(timestamp
);
189 static int send_ra(uint8_t flags
) {
190 uint8_t advertisement
[] = {
191 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
192 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
194 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
195 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
196 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
197 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
198 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
200 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
201 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
202 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
206 advertisement
[5] = flags
;
208 assert_se(write(test_fd
[1], advertisement
, sizeof(advertisement
)) ==
209 sizeof(advertisement
));
212 printf(" sent RA with flag 0x%02x\n", flags
);
217 int icmp6_send_router_solicitation(int s
, const struct ether_addr
*ether_addr
) {
218 if (!send_ra_function
)
221 return send_ra_function(0);
224 static void test_callback(sd_ndisc
*nd
, sd_ndisc_event_t event
, sd_ndisc_router
*rt
, void *userdata
) {
225 sd_event
*e
= userdata
;
226 static unsigned idx
= 0;
227 uint64_t flags_array
[] = {
238 if (event
!= SD_NDISC_EVENT_ROUTER
)
243 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
244 assert_se(flags
== flags_array
[idx
]);
248 printf(" got event 0x%02" PRIx64
"\n", flags
);
250 if (idx
< ELEMENTSOF(flags_array
)) {
251 send_ra(flags_array
[idx
]);
259 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
260 _cleanup_(sd_ndisc_unrefp
) sd_ndisc
*nd
= NULL
;
262 send_ra_function
= send_ra
;
264 assert_se(sd_event_new(&e
) >= 0);
266 assert_se(sd_ndisc_new(&nd
) >= 0);
269 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
271 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
272 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
273 assert_se(sd_ndisc_set_callback(nd
, test_callback
, e
) >= 0);
275 assert_se(sd_event_add_time_relative(e
, NULL
, CLOCK_BOOTTIME
,
276 30 * USEC_PER_SEC
, 0,
277 NULL
, INT_TO_PTR(-ETIMEDOUT
)) >= 0);
279 assert_se(sd_ndisc_stop(nd
) >= 0);
280 assert_se(sd_ndisc_start(nd
) >= 0);
281 assert_se(sd_ndisc_start(nd
) >= 0);
282 assert_se(sd_ndisc_stop(nd
) >= 0);
283 test_fd
[1] = safe_close(test_fd
[1]);
285 assert_se(sd_ndisc_start(nd
) >= 0);
287 assert_se(sd_event_loop(e
) >= 0);
289 test_fd
[1] = safe_close(test_fd
[1]);
292 static int test_timeout_value(uint8_t flags
) {
293 static int count
= 0;
294 static usec_t last
= 0;
295 sd_ndisc
*nd
= test_timeout_nd
;
299 assert_se(nd
->event
);
302 sd_event_exit(nd
->event
, 0);
305 /* initial RT = IRT + RAND*IRT */
306 min
= NDISC_ROUTER_SOLICITATION_INTERVAL
-
307 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
308 max
= NDISC_ROUTER_SOLICITATION_INTERVAL
+
309 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
311 /* next RT = 2*RTprev + RAND*RTprev */
312 min
= 2 * last
- last
/ 10;
313 max
= 2 * last
+ last
/ 10;
317 if (last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
) {
318 min
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
-
319 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
320 max
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
+
321 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
324 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
326 last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
? "(max) ": "",
327 FORMAT_TIMESPAN(min
, USEC_PER_MSEC
),
328 FORMAT_TIMESPAN(nd
->retransmit_time
, USEC_PER_MSEC
),
329 FORMAT_TIMESPAN(max
, USEC_PER_MSEC
));
331 assert_se(min
<= nd
->retransmit_time
);
332 assert_se(max
>= nd
->retransmit_time
);
334 last
= nd
->retransmit_time
;
336 assert_se(sd_event_source_set_time(nd
->timeout_event_source
, 0) >= 0);
342 _cleanup_(sd_event_unrefp
) sd_event
*e
= NULL
;
343 _cleanup_(sd_ndisc_unrefp
) sd_ndisc
*nd
= NULL
;
345 send_ra_function
= test_timeout_value
;
347 assert_se(sd_event_new(&e
) >= 0);
349 assert_se(sd_ndisc_new(&nd
) >= 0);
352 test_timeout_nd
= nd
;
354 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
356 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
357 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
359 assert_se(sd_event_add_time_relative(e
, NULL
, CLOCK_BOOTTIME
,
360 30 * USEC_PER_SEC
, 0,
361 NULL
, INT_TO_PTR(-ETIMEDOUT
)) >= 0);
363 assert_se(sd_ndisc_start(nd
) >= 0);
365 assert_se(sd_event_loop(e
) >= 0);
367 test_fd
[1] = safe_close(test_fd
[1]);
370 DEFINE_TEST_MAIN(LOG_DEBUG
);