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"
31 static struct ether_addr mac_addr
= {
32 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
35 static bool verbose
= false;
36 static sd_event_source
*test_hangcheck
;
37 static int test_fd
[2];
39 typedef int (*send_ra_t
)(uint8_t flags
);
40 static send_ra_t send_ra_function
;
42 static void router_dump(sd_ndisc_router
*rt
) {
44 char buf
[FORMAT_TIMESTAMP_MAX
];
55 assert_se(sd_ndisc_router_get_address(rt
, &addr
) == -ENODATA
);
57 assert_se(sd_ndisc_router_get_timestamp(rt
, CLOCK_REALTIME
, &t
) >= 0);
58 log_info("Timestamp: %s", format_timestamp(buf
, sizeof(buf
), t
));
60 assert_se(sd_ndisc_router_get_timestamp(rt
, CLOCK_MONOTONIC
, &t
) >= 0);
61 log_info("Monotonic: %" PRIu64
, t
);
63 if (sd_ndisc_router_get_hop_limit(rt
, &hop_limit
) < 0)
64 log_info("No hop limit set");
66 log_info("Hop limit: %u", hop_limit
);
68 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
69 log_info("Flags: <%s|%s>",
70 flags
& ND_RA_FLAG_OTHER
? "OTHER" : "",
71 flags
& ND_RA_FLAG_MANAGED
? "MANAGED" : "");
73 assert_se(sd_ndisc_router_get_preference(rt
, &preference
) >= 0);
74 log_info("Preference: %s",
75 preference
== SD_NDISC_PREFERENCE_LOW
? "low" :
76 preference
== SD_NDISC_PREFERENCE_HIGH
? "high" : "medium");
78 assert_se(sd_ndisc_router_get_lifetime(rt
, &lifetime
) >= 0);
79 log_info("Lifetime: %" PRIu16
, lifetime
);
81 if (sd_ndisc_router_get_mtu(rt
, &mtu
) < 0)
82 log_info("No MTU set");
84 log_info("MTU: %" PRIu32
, mtu
);
86 r
= sd_ndisc_router_option_rewind(rt
);
95 assert_se(sd_ndisc_router_option_get_type(rt
, &type
) >= 0);
97 log_info(">> Option %u", type
);
101 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS
:
102 case SD_NDISC_OPTION_TARGET_LL_ADDRESS
: {
103 _cleanup_free_
char *c
= NULL
;
107 assert_se(sd_ndisc_router_option_get_raw(rt
, &p
, &n
) >= 0);
109 assert_se(c
= hexmem((uint8_t*) p
+ 2, n
- 2));
111 log_info("Address: %s", c
);
115 case SD_NDISC_OPTION_PREFIX_INFORMATION
: {
116 uint32_t lifetime_valid
, lifetime_preferred
;
120 char buff
[INET6_ADDRSTRLEN
];
122 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt
, &lifetime_valid
) >= 0);
123 log_info("Valid Lifetime: %" PRIu32
, lifetime_valid
);
125 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt
, &lifetime_preferred
) >= 0);
126 log_info("Preferred Lifetime: %" PRIu32
, lifetime_preferred
);
128 assert_se(sd_ndisc_router_prefix_get_flags(rt
, &pfl
) >= 0);
129 log_info("Flags: <%s|%s>",
130 pfl
& ND_OPT_PI_FLAG_ONLINK
? "ONLINK" : "",
131 pfl
& ND_OPT_PI_FLAG_AUTO
? "AUTO" : "");
133 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt
, &prefix_len
) >= 0);
134 log_info("Prefix Length: %u", prefix_len
);
136 assert_se(sd_ndisc_router_prefix_get_address(rt
, &a
) >= 0);
137 log_info("Prefix: %s", inet_ntop(AF_INET6
, &a
, buff
, sizeof(buff
)));
142 case SD_NDISC_OPTION_RDNSS
: {
143 const struct in6_addr
*a
;
147 n
= sd_ndisc_router_rdnss_get_addresses(rt
, &a
);
150 for (i
= 0; i
< n
; i
++) {
151 char buff
[INET6_ADDRSTRLEN
];
152 log_info("DNS: %s", inet_ntop(AF_INET6
, a
+ i
, buff
, sizeof(buff
)));
155 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt
, <
) >= 0);
156 log_info("Lifetime: %" PRIu32
, lt
);
160 case SD_NDISC_OPTION_DNSSL
: {
161 _cleanup_strv_free_
char **l
= NULL
;
165 n
= sd_ndisc_router_dnssl_get_domains(rt
, &l
);
168 for (i
= 0; i
< n
; i
++)
169 log_info("Domain: %s", l
[i
]);
171 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt
, <
) >= 0);
172 log_info("Lifetime: %" PRIu32
, lt
);
176 r
= sd_ndisc_router_option_next(rt
);
180 static int test_rs_hangcheck(sd_event_source
*s
, uint64_t usec
,
187 int icmp6_bind_router_solicitation(int index
) {
188 assert_se(index
== 42);
190 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, test_fd
) < 0)
196 int icmp6_bind_router_advertisement(int index
) {
201 static int send_ra(uint8_t flags
) {
202 uint8_t advertisement
[] = {
203 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
204 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
206 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
207 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
210 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
212 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
213 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
214 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
218 advertisement
[5] = flags
;
220 assert_se(write(test_fd
[1], advertisement
, sizeof(advertisement
)) ==
221 sizeof(advertisement
));
224 printf(" sent RA with flag 0x%02x\n", flags
);
229 int icmp6_send_router_solicitation(int s
, const struct ether_addr
*ether_addr
) {
230 return send_ra_function(0);
233 static void test_callback(sd_ndisc
*nd
, sd_ndisc_event event
, sd_ndisc_router
*rt
, void *userdata
) {
234 sd_event
*e
= userdata
;
235 static unsigned idx
= 0;
236 uint64_t flags_array
[] = {
248 if (event
!= SD_NDISC_EVENT_ROUTER
)
253 assert_se(sd_ndisc_router_get_flags(rt
, &flags
) >= 0);
254 assert_se(flags
== flags_array
[idx
]);
258 printf(" got event 0x%02" PRIx64
"\n", flags
);
260 if (idx
< ELEMENTSOF(flags_array
)) {
261 send_ra(flags_array
[idx
]);
265 assert_se(sd_ndisc_get_mtu(nd
, &mtu
) == -ENODATA
);
270 static void test_rs(void) {
273 usec_t time_now
= now(clock_boottime_or_monotonic());
276 printf("* %s\n", __FUNCTION__
);
278 send_ra_function
= send_ra
;
280 assert_se(sd_event_new(&e
) >= 0);
282 assert_se(sd_ndisc_new(&nd
) >= 0);
285 assert_se(sd_ndisc_attach_event(nd
, e
, 0) >= 0);
287 assert_se(sd_ndisc_set_ifindex(nd
, 42) >= 0);
288 assert_se(sd_ndisc_set_mac(nd
, &mac_addr
) >= 0);
289 assert_se(sd_ndisc_set_callback(nd
, test_callback
, e
) >= 0);
291 assert_se(sd_event_add_time(e
, &test_hangcheck
, clock_boottime_or_monotonic(),
292 time_now
+ 2 *USEC_PER_SEC
, 0,
293 test_rs_hangcheck
, NULL
) >= 0);
295 assert_se(sd_ndisc_stop(nd
) >= 0);
296 assert_se(sd_ndisc_start(nd
) >= 0);
297 assert_se(sd_ndisc_stop(nd
) >= 0);
299 assert_se(sd_ndisc_start(nd
) >= 0);
303 test_hangcheck
= sd_event_source_unref(test_hangcheck
);
305 nd
= sd_ndisc_unref(nd
);
313 int main(int argc
, char *argv
[]) {
315 log_set_max_level(LOG_DEBUG
);
316 log_parse_environment();