2 This file is part of systemd.
4 Copyright (C) 2014 Intel Corporation. All rights reserved.
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include <netinet/icmp6.h>
21 #include <arpa/inet.h>
25 #include "alloc-util.h"
26 #include "hexdecoct.h"
27 #include "icmp6-util.h"
28 #include "socket-util.h"
30 #include "ndisc-internal.h"
32 static struct ether_addr mac_addr
= {
33 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
36 static bool verbose
= false;
37 static sd_event_source
*test_hangcheck
;
38 static int test_fd
[2];
39 static sd_ndisc
*test_timeout_nd
;
41 typedef int (*send_ra_t
)(uint8_t flags
);
42 static send_ra_t send_ra_function
;
44 static void router_dump(sd_ndisc_router
*rt
) {
46 char buf
[FORMAT_TIMESTAMP_MAX
];
57 assert_se(sd_ndisc_router_get_address(rt
, &addr
) == -ENODATA
);
59 assert_se(sd_ndisc_router_get_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
60 log_info("Timestamp: %s", format_timestamp(buf
, sizeof(buf
), t
));
62 assert_se(sd_ndisc_router_get_timestamp(rt
, CLOCK_MONOTONIC
, &t
) >= 0);
63 log_info("Monotonic: %" PRIu64
, t
);
65 if (sd_ndisc_router_get_hop_limit(rt
, &hop_limit
) < 0)
66 log_info("No hop limit set");
68 log_info("Hop limit: %u", hop_limit
);
70 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
71 log_info("Flags: <%s|%s>",
72 flags
& ND_RA_FLAG_OTHER
? "OTHER" : "",
73 flags
& ND_RA_FLAG_MANAGED
? "MANAGED" : "");
75 assert_se(sd_ndisc_router_get_preference(rt
, &preference
) >= 0);
76 log_info("Preference: %s",
77 preference
== SD_NDISC_PREFERENCE_LOW
? "low" :
78 preference
== SD_NDISC_PREFERENCE_HIGH
? "high" : "medium");
80 assert_se(sd_ndisc_router_get_lifetime(rt
, &lifetime
) >= 0);
81 log_info("Lifetime: %" PRIu16
, lifetime
);
83 if (sd_ndisc_router_get_mtu(rt
, &mtu
) < 0)
84 log_info("No MTU set");
86 log_info("MTU: %" PRIu32
, mtu
);
88 r
= sd_ndisc_router_option_rewind(rt
);
97 assert_se(sd_ndisc_router_option_get_type(rt
, &type
) >= 0);
99 log_info(">> Option %u", type
);
103 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS
:
104 case SD_NDISC_OPTION_TARGET_LL_ADDRESS
: {
105 _cleanup_free_
char *c
= NULL
;
109 assert_se(sd_ndisc_router_option_get_raw(rt
, &p
, &n
) >= 0);
111 assert_se(c
= hexmem((uint8_t*) p
+ 2, n
- 2));
113 log_info("Address: %s", c
);
117 case SD_NDISC_OPTION_PREFIX_INFORMATION
: {
118 uint32_t lifetime_valid
, lifetime_preferred
;
122 char buff
[INET6_ADDRSTRLEN
];
124 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt
, &lifetime_valid
) >= 0);
125 log_info("Valid Lifetime: %" PRIu32
, lifetime_valid
);
127 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt
, &lifetime_preferred
) >= 0);
128 log_info("Preferred Lifetime: %" PRIu32
, lifetime_preferred
);
130 assert_se(sd_ndisc_router_prefix_get_flags(rt
, &pfl
) >= 0);
131 log_info("Flags: <%s|%s>",
132 pfl
& ND_OPT_PI_FLAG_ONLINK
? "ONLINK" : "",
133 pfl
& ND_OPT_PI_FLAG_AUTO
? "AUTO" : "");
135 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt
, &prefix_len
) >= 0);
136 log_info("Prefix Length: %u", prefix_len
);
138 assert_se(sd_ndisc_router_prefix_get_address(rt
, &a
) >= 0);
139 log_info("Prefix: %s", inet_ntop(AF_INET6
, &a
, buff
, sizeof(buff
)));
144 case SD_NDISC_OPTION_RDNSS
: {
145 const struct in6_addr
*a
;
149 n
= sd_ndisc_router_rdnss_get_addresses(rt
, &a
);
152 for (i
= 0; i
< n
; i
++) {
153 char buff
[INET6_ADDRSTRLEN
];
154 log_info("DNS: %s", inet_ntop(AF_INET6
, a
+ i
, buff
, sizeof(buff
)));
157 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt
, <
) >= 0);
158 log_info("Lifetime: %" PRIu32
, lt
);
162 case SD_NDISC_OPTION_DNSSL
: {
163 _cleanup_strv_free_
char **l
= NULL
;
167 n
= sd_ndisc_router_dnssl_get_domains(rt
, &l
);
170 for (i
= 0; i
< n
; i
++)
171 log_info("Domain: %s", l
[i
]);
173 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt
, <
) >= 0);
174 log_info("Lifetime: %" PRIu32
, lt
);
178 r
= sd_ndisc_router_option_next(rt
);
182 static int test_rs_hangcheck(sd_event_source
*s
, uint64_t usec
,
189 int icmp6_bind_router_solicitation(int index
) {
190 assert_se(index
== 42);
192 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, test_fd
) < 0)
198 int icmp6_bind_router_advertisement(int index
) {
203 int icmp6_receive(int fd
, void *iov_base
, size_t iov_len
,
204 struct in6_addr
*dst
, triple_timestamp
*timestamp
) {
205 assert_se(read (fd
, iov_base
, iov_len
) == (ssize_t
)iov_len
);
208 triple_timestamp_get(timestamp
);
213 static int send_ra(uint8_t flags
) {
214 uint8_t advertisement
[] = {
215 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
218 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
219 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
220 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
222 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
223 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
224 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
225 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
226 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
230 advertisement
[5] = flags
;
232 assert_se(write(test_fd
[1], advertisement
, sizeof(advertisement
)) ==
233 sizeof(advertisement
));
236 printf(" sent RA with flag 0x%02x\n", flags
);
241 int icmp6_send_router_solicitation(int s
, const struct ether_addr
*ether_addr
) {
242 if (!send_ra_function
)
245 return send_ra_function(0);
248 static void test_callback(sd_ndisc
*nd
, sd_ndisc_event event
, sd_ndisc_router
*rt
, void *userdata
) {
249 sd_event
*e
= userdata
;
250 static unsigned idx
= 0;
251 uint64_t flags_array
[] = {
263 if (event
!= SD_NDISC_EVENT_ROUTER
)
268 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
269 assert_se(flags
== flags_array
[idx
]);
273 printf(" got event 0x%02" PRIx64
"\n", flags
);
275 if (idx
< ELEMENTSOF(flags_array
)) {
276 send_ra(flags_array
[idx
]);
280 assert_se(sd_ndisc_get_mtu(nd
, &mtu
) == -ENODATA
);
285 static void test_rs(void) {
288 usec_t time_now
= now(clock_boottime_or_monotonic());
291 printf("* %s\n", __FUNCTION__
);
293 send_ra_function
= send_ra
;
295 assert_se(sd_event_new(&e
) >= 0);
297 assert_se(sd_ndisc_new(&nd
) >= 0);
300 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
302 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
303 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
304 assert_se(sd_ndisc_set_callback(nd
, test_callback
, e
) >= 0);
306 assert_se(sd_event_add_time(e
, &test_hangcheck
, clock_boottime_or_monotonic(),
307 time_now
+ 2 *USEC_PER_SEC
, 0,
308 test_rs_hangcheck
, NULL
) >= 0);
310 assert_se(sd_ndisc_stop(nd
) >= 0);
311 assert_se(sd_ndisc_start(nd
) >= 0);
312 assert_se(sd_ndisc_stop(nd
) >= 0);
314 assert_se(sd_ndisc_start(nd
) >= 0);
318 test_hangcheck
= sd_event_source_unref(test_hangcheck
);
320 nd
= sd_ndisc_unref(nd
);
328 static int test_timeout_value(uint8_t flags
) {
329 static int count
= 0;
330 static usec_t last
= 0;
331 sd_ndisc
*nd
= test_timeout_nd
;
333 char time_string_min
[FORMAT_TIMESPAN_MAX
];
334 char time_string_nd
[FORMAT_TIMESPAN_MAX
];
335 char time_string_max
[FORMAT_TIMESPAN_MAX
];
338 assert_se(nd
->event
);
341 sd_event_exit(nd
->event
, 0);
344 /* initial RT = IRT + RAND*IRT */
345 min
= NDISC_ROUTER_SOLICITATION_INTERVAL
-
346 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
347 max
= NDISC_ROUTER_SOLICITATION_INTERVAL
+
348 NDISC_ROUTER_SOLICITATION_INTERVAL
/ 10;
350 /* next RT = 2*RTprev + RAND*RTprev */
351 min
= 2 * last
- last
/ 10;
352 max
= 2 * last
+ last
/ 10;
356 if (last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
) {
357 min
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
-
358 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
359 max
= NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
+
360 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
/ 10;
363 format_timespan(time_string_min
, FORMAT_TIMESPAN_MAX
,
365 format_timespan(time_string_nd
, FORMAT_TIMESPAN_MAX
,
366 nd
->retransmit_time
, USEC_PER_MSEC
);
367 format_timespan(time_string_max
, FORMAT_TIMESPAN_MAX
,
370 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
372 (last
* 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL
)? "(max) ": "",
373 time_string_min
, time_string_nd
, time_string_max
);
375 assert_se(min
<= nd
->retransmit_time
);
376 assert_se(max
>= nd
->retransmit_time
);
378 last
= nd
->retransmit_time
;
380 assert_se(sd_event_source_set_time(nd
->timeout_event_source
, 0) >= 0);
385 static void test_timeout(void) {
388 usec_t time_now
= now(clock_boottime_or_monotonic());
391 printf("* %s\n", __FUNCTION__
);
393 send_ra_function
= test_timeout_value
;
395 assert_se(sd_event_new(&e
) >= 0);
397 assert_se(sd_ndisc_new(&nd
) >= 0);
400 test_timeout_nd
= nd
;
402 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
404 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
405 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
407 assert_se(sd_event_add_time(e
, &test_hangcheck
, clock_boottime_or_monotonic(),
408 time_now
+ 2U * USEC_PER_SEC
, 0,
409 test_rs_hangcheck
, NULL
) >= 0);
411 assert_se(sd_ndisc_start(nd
) >= 0);
415 test_hangcheck
= sd_event_source_unref(test_hangcheck
);
417 nd
= sd_ndisc_unref(nd
);
422 int main(int argc
, char *argv
[]) {
424 log_set_max_level(LOG_DEBUG
);
425 log_parse_environment();