1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright (C) 2014 Intel Corporation. All rights reserved.
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <netinet/icmp6.h>
22 #include <arpa/inet.h>
26 #include "alloc-util.h"
27 #include "hexdecoct.h"
28 #include "icmp6-util.h"
29 #include "socket-util.h"
31 #include "ndisc-internal.h"
33 static struct ether_addr mac_addr
= {
34 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
37 static bool verbose
= false;
38 static sd_event_source
*test_hangcheck
;
39 static int test_fd
[2];
40 static sd_ndisc
*test_timeout_nd
;
42 typedef int (*send_ra_t
)(uint8_t flags
);
43 static send_ra_t send_ra_function
;
45 static void router_dump(sd_ndisc_router
*rt
) {
47 char buf
[FORMAT_TIMESTAMP_MAX
];
58 assert_se(sd_ndisc_router_get_address(rt
, &addr
) == -ENODATA
);
60 assert_se(sd_ndisc_router_get_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
61 log_info("Timestamp: %s", format_timestamp(buf
, sizeof(buf
), t
));
63 assert_se(sd_ndisc_router_get_timestamp(rt
, CLOCK_MONOTONIC
, &t
) >= 0);
64 log_info("Monotonic: %" PRIu64
, t
);
66 if (sd_ndisc_router_get_hop_limit(rt
, &hop_limit
) < 0)
67 log_info("No hop limit set");
69 log_info("Hop limit: %u", hop_limit
);
71 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
72 log_info("Flags: <%s|%s>",
73 flags
& ND_RA_FLAG_OTHER
? "OTHER" : "",
74 flags
& ND_RA_FLAG_MANAGED
? "MANAGED" : "");
76 assert_se(sd_ndisc_router_get_preference(rt
, &preference
) >= 0);
77 log_info("Preference: %s",
78 preference
== SD_NDISC_PREFERENCE_LOW
? "low" :
79 preference
== SD_NDISC_PREFERENCE_HIGH
? "high" : "medium");
81 assert_se(sd_ndisc_router_get_lifetime(rt
, &lifetime
) >= 0);
82 log_info("Lifetime: %" PRIu16
, lifetime
);
84 if (sd_ndisc_router_get_mtu(rt
, &mtu
) < 0)
85 log_info("No MTU set");
87 log_info("MTU: %" PRIu32
, mtu
);
89 r
= sd_ndisc_router_option_rewind(rt
);
98 assert_se(sd_ndisc_router_option_get_type(rt
, &type
) >= 0);
100 log_info(">> Option %u", type
);
104 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS
:
105 case SD_NDISC_OPTION_TARGET_LL_ADDRESS
: {
106 _cleanup_free_
char *c
= NULL
;
110 assert_se(sd_ndisc_router_option_get_raw(rt
, &p
, &n
) >= 0);
112 assert_se(c
= hexmem((uint8_t*) p
+ 2, n
- 2));
114 log_info("Address: %s", c
);
118 case SD_NDISC_OPTION_PREFIX_INFORMATION
: {
119 uint32_t lifetime_valid
, lifetime_preferred
;
123 char buff
[INET6_ADDRSTRLEN
];
125 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt
, &lifetime_valid
) >= 0);
126 log_info("Valid Lifetime: %" PRIu32
, lifetime_valid
);
128 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt
, &lifetime_preferred
) >= 0);
129 log_info("Preferred Lifetime: %" PRIu32
, lifetime_preferred
);
131 assert_se(sd_ndisc_router_prefix_get_flags(rt
, &pfl
) >= 0);
132 log_info("Flags: <%s|%s>",
133 pfl
& ND_OPT_PI_FLAG_ONLINK
? "ONLINK" : "",
134 pfl
& ND_OPT_PI_FLAG_AUTO
? "AUTO" : "");
136 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt
, &prefix_len
) >= 0);
137 log_info("Prefix Length: %u", prefix_len
);
139 assert_se(sd_ndisc_router_prefix_get_address(rt
, &a
) >= 0);
140 log_info("Prefix: %s", inet_ntop(AF_INET6
, &a
, buff
, sizeof(buff
)));
145 case SD_NDISC_OPTION_RDNSS
: {
146 const struct in6_addr
*a
;
150 n
= sd_ndisc_router_rdnss_get_addresses(rt
, &a
);
153 for (i
= 0; i
< n
; i
++) {
154 char buff
[INET6_ADDRSTRLEN
];
155 log_info("DNS: %s", inet_ntop(AF_INET6
, a
+ i
, buff
, sizeof(buff
)));
158 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt
, <
) >= 0);
159 log_info("Lifetime: %" PRIu32
, lt
);
163 case SD_NDISC_OPTION_DNSSL
: {
164 _cleanup_strv_free_
char **l
= NULL
;
168 n
= sd_ndisc_router_dnssl_get_domains(rt
, &l
);
171 for (i
= 0; i
< n
; i
++)
172 log_info("Domain: %s", l
[i
]);
174 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt
, <
) >= 0);
175 log_info("Lifetime: %" PRIu32
, lt
);
179 r
= sd_ndisc_router_option_next(rt
);
183 static int test_rs_hangcheck(sd_event_source
*s
, uint64_t usec
,
190 int icmp6_bind_router_solicitation(int index
) {
191 assert_se(index
== 42);
193 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, test_fd
) < 0)
199 int icmp6_bind_router_advertisement(int index
) {
204 int icmp6_receive(int fd
, void *iov_base
, size_t iov_len
,
205 struct in6_addr
*dst
, triple_timestamp
*timestamp
) {
206 assert_se(read (fd
, iov_base
, iov_len
) == (ssize_t
)iov_len
);
209 triple_timestamp_get(timestamp
);
214 static int send_ra(uint8_t flags
) {
215 uint8_t advertisement
[] = {
216 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
219 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
220 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
223 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
225 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
226 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
227 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
231 advertisement
[5] = flags
;
233 assert_se(write(test_fd
[1], advertisement
, sizeof(advertisement
)) ==
234 sizeof(advertisement
));
237 printf(" sent RA with flag 0x%02x\n", flags
);
242 int icmp6_send_router_solicitation(int s
, const struct ether_addr
*ether_addr
) {
243 if (!send_ra_function
)
246 return send_ra_function(0);
249 static void test_callback(sd_ndisc
*nd
, sd_ndisc_event event
, sd_ndisc_router
*rt
, void *userdata
) {
250 sd_event
*e
= userdata
;
251 static unsigned idx
= 0;
252 uint64_t flags_array
[] = {
264 if (event
!= SD_NDISC_EVENT_ROUTER
)
269 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
270 assert_se(flags
== flags_array
[idx
]);
274 printf(" got event 0x%02" PRIx64
"\n", flags
);
276 if (idx
< ELEMENTSOF(flags_array
)) {
277 send_ra(flags_array
[idx
]);
281 assert_se(sd_ndisc_get_mtu(nd
, &mtu
) == -ENODATA
);
286 static void test_rs(void) {
289 usec_t time_now
= now(clock_boottime_or_monotonic());
292 printf("* %s\n", __FUNCTION__
);
294 send_ra_function
= send_ra
;
296 assert_se(sd_event_new(&e
) >= 0);
298 assert_se(sd_ndisc_new(&nd
) >= 0);
301 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
303 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
304 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
305 assert_se(sd_ndisc_set_callback(nd
, test_callback
, e
) >= 0);
307 assert_se(sd_event_add_time(e
, &test_hangcheck
, clock_boottime_or_monotonic(),
308 time_now
+ 2 *USEC_PER_SEC
, 0,
309 test_rs_hangcheck
, NULL
) >= 0);
311 assert_se(sd_ndisc_stop(nd
) >= 0);
312 assert_se(sd_ndisc_start(nd
) >= 0);
313 assert_se(sd_ndisc_stop(nd
) >= 0);
315 assert_se(sd_ndisc_start(nd
) >= 0);
319 test_hangcheck
= sd_event_source_unref(test_hangcheck
);
321 nd
= sd_ndisc_unref(nd
);
329 static int test_timeout_value(uint8_t flags
) {
330 static int count
= 0;
331 static usec_t last
= 0;
332 sd_ndisc
*nd
= test_timeout_nd
;
334 char time_string_min
[FORMAT_TIMESPAN_MAX
];
335 char time_string_nd
[FORMAT_TIMESPAN_MAX
];
336 char time_string_max
[FORMAT_TIMESPAN_MAX
];
339 assert_se(nd
->event
);
342 sd_event_exit(nd
->event
, 0);
345 /* initial RT = IRT + RAND*IRT */
346 min
= NDISC_ROUTER_SOLICITATION_INTERVAL
-
347 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
348 max
= NDISC_ROUTER_SOLICITATION_INTERVAL
+
349 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
351 /* next RT = 2*RTprev + RAND*RTprev */
352 min
= 2 * last
- last
/ 10;
353 max
= 2 * last
+ last
/ 10;
357 if (last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
) {
358 min
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
-
359 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
360 max
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
+
361 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
364 format_timespan(time_string_min
, FORMAT_TIMESPAN_MAX
,
366 format_timespan(time_string_nd
, FORMAT_TIMESPAN_MAX
,
367 nd
->retransmit_time
, USEC_PER_MSEC
);
368 format_timespan(time_string_max
, FORMAT_TIMESPAN_MAX
,
371 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
373 (last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
)? "(max) ": "",
374 time_string_min
, time_string_nd
, time_string_max
);
376 assert_se(min
<= nd
->retransmit_time
);
377 assert_se(max
>= nd
->retransmit_time
);
379 last
= nd
->retransmit_time
;
381 assert_se(sd_event_source_set_time(nd
->timeout_event_source
, 0) >= 0);
386 static void test_timeout(void) {
389 usec_t time_now
= now(clock_boottime_or_monotonic());
392 printf("* %s\n", __FUNCTION__
);
394 send_ra_function
= test_timeout_value
;
396 assert_se(sd_event_new(&e
) >= 0);
398 assert_se(sd_ndisc_new(&nd
) >= 0);
401 test_timeout_nd
= nd
;
403 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
405 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
406 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
408 assert_se(sd_event_add_time(e
, &test_hangcheck
, clock_boottime_or_monotonic(),
409 time_now
+ 2U * USEC_PER_SEC
, 0,
410 test_rs_hangcheck
, NULL
) >= 0);
412 assert_se(sd_ndisc_start(nd
) >= 0);
416 test_hangcheck
= sd_event_source_unref(test_hangcheck
);
418 nd
= sd_ndisc_unref(nd
);
423 int main(int argc
, char *argv
[]) {
425 log_set_max_level(LOG_DEBUG
);
426 log_parse_environment();