]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/test-ndisc-rs.c
man/systemd-sysext: list ephemeral/ephemeral-import in the list of options
[thirdparty/systemd.git] / src / libsystemd-network / test-ndisc-rs.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
f20a35cc 2/***
810adae9 3 Copyright © 2014 Intel Corporation. All rights reserved.
f20a35cc
PF
4***/
5
1cf40697 6#include <netinet/icmp6.h>
ca78ad1d 7#include <unistd.h>
f20a35cc 8
07630cea 9#include "sd-ndisc.h"
f20a35cc 10
1e7a0e21 11#include "alloc-util.h"
86d82cb8 12#include "fd-util.h"
1e7a0e21 13#include "hexdecoct.h"
8430c4d9 14#include "icmp6-packet.h"
8e41e460 15#include "icmp6-test-util.h"
5cdf13c7 16#include "in-addr-util.h"
1cf40697 17#include "ndisc-internal.h"
1e7a0e21 18#include "strv.h"
6d7c4033 19#include "tests.h"
f20a35cc
PF
20
21static struct ether_addr mac_addr = {
22 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
23};
24
25static bool verbose = false;
f20a35cc 26
1e7a0e21
LP
27static void router_dump(sd_ndisc_router *rt) {
28 struct in6_addr addr;
1e7a0e21 29 uint8_t hop_limit;
d4c8de21 30 usec_t t, lifetime, retrans_time;
6197db53 31 uint64_t flags;
1e7a0e21 32 uint32_t mtu;
9ca04752 33 uint8_t preference;
1e7a0e21
LP
34 int r;
35
36 assert_se(rt);
37
38 log_info("--");
9ca04752 39 assert_se(sd_ndisc_router_get_sender_address(rt, &addr) >= 0);
4961f566 40 log_info("Sender: %s", IN6_ADDR_TO_STRING(&addr));
1e7a0e21
LP
41
42 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
04f5c018 43 log_info("Timestamp: %s", FORMAT_TIMESTAMP(t));
1e7a0e21
LP
44
45 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_MONOTONIC, &t) >= 0);
46 log_info("Monotonic: %" PRIu64, t);
47
48 if (sd_ndisc_router_get_hop_limit(rt, &hop_limit) < 0)
49 log_info("No hop limit set");
50 else
51 log_info("Hop limit: %u", hop_limit);
52
53 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
54 log_info("Flags: <%s|%s>",
55 flags & ND_RA_FLAG_OTHER ? "OTHER" : "",
56 flags & ND_RA_FLAG_MANAGED ? "MANAGED" : "");
57
58 assert_se(sd_ndisc_router_get_preference(rt, &preference) >= 0);
59 log_info("Preference: %s",
60 preference == SD_NDISC_PREFERENCE_LOW ? "low" :
61 preference == SD_NDISC_PREFERENCE_HIGH ? "high" : "medium");
62
63 assert_se(sd_ndisc_router_get_lifetime(rt, &lifetime) >= 0);
6197db53
YW
64 assert_se(sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
65 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
1e7a0e21 66
d4c8de21
MM
67 assert_se(sd_ndisc_router_get_retransmission_time(rt, &retrans_time) >= 0);
68 log_info("Retransmission Time: %s", FORMAT_TIMESPAN(retrans_time, USEC_PER_SEC));
69
1e7a0e21
LP
70 if (sd_ndisc_router_get_mtu(rt, &mtu) < 0)
71 log_info("No MTU set");
72 else
73 log_info("MTU: %" PRIu32, mtu);
74
75 r = sd_ndisc_router_option_rewind(rt);
76 for (;;) {
77 uint8_t type;
78
79 assert_se(r >= 0);
80
81 if (r == 0)
82 break;
83
84 assert_se(sd_ndisc_router_option_get_type(rt, &type) >= 0);
85
86 log_info(">> Option %u", type);
87
88 switch (type) {
89
90 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS:
91 case SD_NDISC_OPTION_TARGET_LL_ADDRESS: {
92 _cleanup_free_ char *c = NULL;
9ca04752 93 const uint8_t *p;
1e7a0e21
LP
94 size_t n;
95
96 assert_se(sd_ndisc_router_option_get_raw(rt, &p, &n) >= 0);
97 assert_se(n > 2);
9ca04752 98 assert_se(c = hexmem(p + 2, n - 2));
1e7a0e21
LP
99
100 log_info("Address: %s", c);
101 break;
102 }
103
104 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
9ca04752 105 uint8_t prefix_len, pfl;
1e7a0e21 106 struct in6_addr a;
1e7a0e21 107
6197db53
YW
108 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime) >= 0);
109 assert_se(sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
110 log_info("Valid Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
1e7a0e21 111
6197db53
YW
112 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime) >= 0);
113 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
114 log_info("Preferred Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
1e7a0e21
LP
115
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" : "");
120
121 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt, &prefix_len) >= 0);
122 log_info("Prefix Length: %u", prefix_len);
123
124 assert_se(sd_ndisc_router_prefix_get_address(rt, &a) >= 0);
071e522e 125 log_info("Prefix: %s", IN6_ADDR_TO_STRING(&a));
1e7a0e21
LP
126
127 break;
128 }
129
130 case SD_NDISC_OPTION_RDNSS: {
131 const struct in6_addr *a;
1e7a0e21
LP
132 int n, i;
133
134 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
135 assert_se(n > 0);
136
071e522e
ZJS
137 for (i = 0; i < n; i++)
138 log_info("DNS: %s", IN6_ADDR_TO_STRING(a + i));
1e7a0e21 139
6197db53
YW
140 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime) >= 0);
141 assert_se(sd_ndisc_router_rdnss_get_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
142 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
1e7a0e21
LP
143 break;
144 }
145
146 case SD_NDISC_OPTION_DNSSL: {
9ca04752 147 char **l;
1e7a0e21 148
9ca04752 149 assert_se(sd_ndisc_router_dnssl_get_domains(rt, &l) >= 0);
1e7a0e21 150
9ca04752
YW
151 STRV_FOREACH(s, l)
152 log_info("Domain: %s", *s);
1e7a0e21 153
6197db53
YW
154 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime) >= 0);
155 assert_se(sd_ndisc_router_dnssl_get_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
156 log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
1e7a0e21
LP
157 break;
158 }}
159
160 r = sd_ndisc_router_option_next(rt);
161 }
162}
163
f20a35cc
PF
164static int send_ra(uint8_t flags) {
165 uint8_t advertisement[] = {
38a80ba1 166 /* struct nd_router_advert */
f20a35cc
PF
167 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38a80ba1 169 /* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */
f20a35cc
PF
170 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
171 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
172 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38a80ba1 174 /* type = 0x19 (SD_NDISC_OPTION_RDNSS), length = 24 */
f20a35cc
PF
175 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
176 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
d9b8acda 178 /* type = 0x1f (SD_NDISC_OPTION_DNSSL), length = 24 */
f20a35cc
PF
179 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
180 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
181 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
d9b8acda 182 /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
f20a35cc
PF
183 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
184 };
185
186 advertisement[5] = flags;
187
787784c4 188 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
c21ed681 189 sizeof(advertisement));
f20a35cc
PF
190
191 if (verbose)
192 printf(" sent RA with flag 0x%02x\n", flags);
193
194 return 0;
195}
196
ecab9b60 197static void test_callback_ra(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata) {
f20a35cc 198 sd_event *e = userdata;
cb53894d 199 static unsigned idx = 0;
1e7a0e21 200 uint64_t flags_array[] = {
9d96e6c3
TG
201 0,
202 0,
203 0,
204 ND_RA_FLAG_OTHER,
205 ND_RA_FLAG_MANAGED
f20a35cc 206 };
1e7a0e21 207 uint64_t flags;
8d7f2c6a 208
787784c4 209 assert_se(nd);
f20a35cc 210
1e7a0e21
LP
211 if (event != SD_NDISC_EVENT_ROUTER)
212 return;
213
28eef158
YW
214 sd_ndisc_router *rt = ASSERT_PTR(message);
215
1e7a0e21
LP
216 router_dump(rt);
217
218 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
9d96e6c3 219 assert_se(flags == flags_array[idx]);
f20a35cc
PF
220 idx++;
221
222 if (verbose)
1e7a0e21 223 printf(" got event 0x%02" PRIx64 "\n", flags);
f20a35cc 224
9d96e6c3
TG
225 if (idx < ELEMENTSOF(flags_array)) {
226 send_ra(flags_array[idx]);
8d7f2c6a
PF
227 return;
228 }
229
a39d8396 230 idx = 0;
8d7f2c6a 231 sd_event_exit(e, 0);
f20a35cc
PF
232}
233
8430c4d9
YW
234static int on_recv_rs(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
235 _cleanup_(icmp6_packet_unrefp) ICMP6Packet *packet = NULL;
236 assert_se(icmp6_packet_receive(fd, &packet) >= 0);
237
238 return send_ra(0);
239}
240
68da8adf 241TEST(rs) {
86d82cb8 242 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
8430c4d9 243 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
86d82cb8 244 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
f20a35cc 245
99af546d
PF
246 assert_se(sd_event_new(&e) >= 0);
247
4d7b83da 248 assert_se(sd_ndisc_new(&nd) >= 0);
787784c4 249 assert_se(nd);
f20a35cc 250
4d7b83da 251 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
f20a35cc 252
2f8e7633 253 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
4d7b83da 254 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
ecab9b60 255 assert_se(sd_ndisc_set_callback(nd, test_callback_ra, e) >= 0);
f20a35cc 256
ba4e0427 257 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
2e37084f
YW
258 30 * USEC_PER_SEC, 0,
259 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
f20a35cc 260
4d7b83da 261 assert_se(sd_ndisc_stop(nd) >= 0);
1e7a0e21 262 assert_se(sd_ndisc_start(nd) >= 0);
6b8a1aa6 263 assert_se(sd_ndisc_start(nd) >= 0);
4d7b83da 264 assert_se(sd_ndisc_stop(nd) >= 0);
86d82cb8 265 test_fd[1] = safe_close(test_fd[1]);
836cf090 266
1e7a0e21 267 assert_se(sd_ndisc_start(nd) >= 0);
f20a35cc 268
8430c4d9
YW
269 assert_se(sd_event_add_io(e, &s, test_fd[1], EPOLLIN, on_recv_rs, nd) >= 0);
270 assert_se(sd_event_source_set_io_fd_own(s, true) >= 0);
271
2e37084f 272 assert_se(sd_event_loop(e) >= 0);
f20a35cc 273
8430c4d9 274 test_fd[1] = -EBADF;
f20a35cc
PF
275}
276
a39d8396
YW
277static int send_ra_invalid_domain(uint8_t flags) {
278 uint8_t advertisement[] = {
279 /* struct nd_router_advert */
280 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 /* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */
283 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
284 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
285 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 /* type = 0x19 (SD_NDISC_OPTION_RDNSS), length = 24 */
288 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
289 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
d9b8acda 291 /* type = 0x1f (SD_NDISC_OPTION_DNSSL), length = 112 */
a39d8396
YW
292 0x1f, 0x0e, 0xee, 0x68, 0xb0, 0xf4, 0x36, 0x39,
293 0x2c, 0xbc, 0x0b, 0xbc, 0xa9, 0x97, 0x71, 0x37,
294 0xad, 0x86, 0x80, 0x14, 0x2e, 0x58, 0xaa, 0x8a,
295 0xb7, 0xa1, 0xbe, 0x91, 0x59, 0x00, 0xc4, 0xe8,
296 0xdd, 0xd8, 0x6d, 0xe5, 0x4a, 0x7a, 0x71, 0x42,
297 0x74, 0x45, 0x9e, 0x2e, 0xfd, 0x9d, 0x71, 0x1d,
298 0xd0, 0xc0, 0x54, 0x0c, 0x4d, 0x1f, 0xbf, 0x90,
299 0xd9, 0x79, 0x58, 0xc0, 0x1d, 0xa3, 0x39, 0xcf,
300 0xb8, 0xec, 0xd2, 0xe4, 0xcd, 0xb6, 0x13, 0x2f,
301 0xc0, 0x46, 0xe8, 0x07, 0x3f, 0xaa, 0x28, 0xa5,
302 0x23, 0xf1, 0xf0, 0xca, 0xd3, 0x19, 0x3f, 0xfa,
303 0x6c, 0x7c, 0xec, 0x1b, 0xcf, 0x71, 0xeb, 0xba,
304 0x68, 0x1b, 0x8e, 0x7d, 0x93, 0x7e, 0x0b, 0x9f,
305 0xdb, 0x12, 0x9c, 0x75, 0x22, 0x5f, 0x12, 0x00,
d9b8acda 306 /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
a39d8396
YW
307 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
308 };
309
310 advertisement[5] = flags;
311
312 printf("sizeof(nd_router_advert)=%zu\n", sizeof(struct nd_router_advert));
313
314 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
315 sizeof(advertisement));
316
317 if (verbose)
318 printf(" sent RA with flag 0x%02x\n", flags);
319
320 return 0;
321}
322
8430c4d9
YW
323static int on_recv_rs_invalid_domain(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
324 _cleanup_(icmp6_packet_unrefp) ICMP6Packet *packet = NULL;
325 assert_se(icmp6_packet_receive(fd, &packet) >= 0);
326
327 return send_ra_invalid_domain(0);
328}
329
a39d8396
YW
330TEST(invalid_domain) {
331 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
8430c4d9 332 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
a39d8396
YW
333 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
334
a39d8396
YW
335 assert_se(sd_event_new(&e) >= 0);
336
337 assert_se(sd_ndisc_new(&nd) >= 0);
338 assert_se(nd);
339
340 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
341
342 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
343 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
ecab9b60 344 assert_se(sd_ndisc_set_callback(nd, test_callback_ra, e) >= 0);
a39d8396
YW
345
346 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
347 30 * USEC_PER_SEC, 0,
348 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
349
350 assert_se(sd_ndisc_start(nd) >= 0);
351
8430c4d9
YW
352 assert_se(sd_event_add_io(e, &s, test_fd[1], EPOLLIN, on_recv_rs_invalid_domain, nd) >= 0);
353 assert_se(sd_event_source_set_io_fd_own(s, true) >= 0);
354
a39d8396
YW
355 assert_se(sd_event_loop(e) >= 0);
356
8430c4d9 357 test_fd[1] = -EBADF;
a39d8396
YW
358}
359
ecab9b60
YW
360static void neighbor_dump(sd_ndisc_neighbor *na) {
361 struct in6_addr addr;
362 uint32_t flags;
363
364 assert_se(na);
365
366 log_info("--");
367 assert_se(sd_ndisc_neighbor_get_sender_address(na, &addr) >= 0);
368 log_info("Sender: %s", IN6_ADDR_TO_STRING(&addr));
369
370 assert_se(sd_ndisc_neighbor_get_flags(na, &flags) >= 0);
371 log_info("Flags: Router:%s, Solicited:%s, Override: %s",
372 yes_no(flags & ND_NA_FLAG_ROUTER),
373 yes_no(flags & ND_NA_FLAG_SOLICITED),
374 yes_no(flags & ND_NA_FLAG_OVERRIDE));
375
376 assert_se(sd_ndisc_neighbor_is_router(na) == FLAGS_SET(flags, ND_NA_FLAG_ROUTER));
377 assert_se(sd_ndisc_neighbor_is_solicited(na) == FLAGS_SET(flags, ND_NA_FLAG_SOLICITED));
378 assert_se(sd_ndisc_neighbor_is_override(na) == FLAGS_SET(flags, ND_NA_FLAG_OVERRIDE));
379}
380
381static int send_na(uint32_t flags) {
382 uint8_t advertisement[] = {
383 /* struct nd_neighbor_advert */
384 0x88, 0x00, 0xde, 0x83, 0x00, 0x00, 0x00, 0x00,
385 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
387 /* type = 0x02 (SD_NDISC_OPTION_TARGET_LL_ADDRESS), length = 8 */
388 0x01, 0x01, 'A', 'B', 'C', '1', '2', '3',
389 };
390
391 ((struct nd_neighbor_advert*) advertisement)->nd_na_flags_reserved = flags;
392
393 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) == sizeof(advertisement));
394 if (verbose)
395 printf(" sent NA with flag 0x%02x\n", flags);
396
397 return 0;
398}
399
400static void test_callback_na(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata) {
401 sd_event *e = userdata;
402 static unsigned idx = 0;
403 uint32_t flags_array[] = {
404 0,
405 0,
406 ND_NA_FLAG_ROUTER,
407 ND_NA_FLAG_SOLICITED,
408 ND_NA_FLAG_SOLICITED | ND_NA_FLAG_OVERRIDE,
409 };
410 uint32_t flags;
411
412 assert_se(nd);
413
414 if (event != SD_NDISC_EVENT_NEIGHBOR)
415 return;
416
417 sd_ndisc_neighbor *rt = ASSERT_PTR(message);
418
419 neighbor_dump(rt);
420
421 assert_se(sd_ndisc_neighbor_get_flags(rt, &flags) >= 0);
422 assert_se(flags == flags_array[idx]);
423 idx++;
424
425 if (verbose)
426 printf(" got event 0x%02" PRIx32 "\n", flags);
427
428 if (idx < ELEMENTSOF(flags_array)) {
429 send_na(flags_array[idx]);
430 return;
431 }
432
433 idx = 0;
434 sd_event_exit(e, 0);
435}
436
437static int on_recv_rs_na(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
438 _cleanup_(icmp6_packet_unrefp) ICMP6Packet *packet = NULL;
439 assert_se(icmp6_packet_receive(fd, &packet) >= 0);
440
441 return send_na(0);
442}
443
444TEST(na) {
445 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
446 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
447 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
448
449 assert_se(sd_event_new(&e) >= 0);
450
451 assert_se(sd_ndisc_new(&nd) >= 0);
452 assert_se(nd);
453
454 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
455
456 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
457 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
458 assert_se(sd_ndisc_set_callback(nd, test_callback_na, e) >= 0);
459
460 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
461 30 * USEC_PER_SEC, 0,
462 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
463
464 assert_se(sd_ndisc_start(nd) >= 0);
465
466 assert_se(sd_event_add_io(e, &s, test_fd[1], EPOLLIN, on_recv_rs_na, nd) >= 0);
467 assert_se(sd_event_source_set_io_fd_own(s, true) >= 0);
468
469 assert_se(sd_event_loop(e) >= 0);
470
471 test_fd[1] = -EBADF;
472}
473
8430c4d9
YW
474static int on_recv_rs_timeout(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
475 _cleanup_(icmp6_packet_unrefp) ICMP6Packet *packet = NULL;
476 sd_ndisc *nd = ASSERT_PTR(userdata);
5a67ed24
PF
477 static int count = 0;
478 static usec_t last = 0;
5a67ed24 479 usec_t min, max;
5a67ed24 480
8430c4d9 481 assert_se(icmp6_packet_receive(fd, &packet) >= 0);
5a67ed24
PF
482
483 if (++count >= 20)
484 sd_event_exit(nd->event, 0);
485
486 if (last == 0) {
487 /* initial RT = IRT + RAND*IRT */
488 min = NDISC_ROUTER_SOLICITATION_INTERVAL -
489 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
490 max = NDISC_ROUTER_SOLICITATION_INTERVAL +
491 NDISC_ROUTER_SOLICITATION_INTERVAL / 10;
492 } else {
493 /* next RT = 2*RTprev + RAND*RTprev */
494 min = 2 * last - last / 10;
495 max = 2 * last + last / 10;
496 }
497
498 /* final RT > MRT */
499 if (last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL) {
500 min = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL -
501 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
502 max = NDISC_MAX_ROUTER_SOLICITATION_INTERVAL +
503 NDISC_MAX_ROUTER_SOLICITATION_INTERVAL / 10;
504 }
505
5a67ed24
PF
506 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
507 count,
5291f26d
ZJS
508 last * 2 > NDISC_MAX_ROUTER_SOLICITATION_INTERVAL ? "(max) ": "",
509 FORMAT_TIMESPAN(min, USEC_PER_MSEC),
510 FORMAT_TIMESPAN(nd->retransmit_time, USEC_PER_MSEC),
511 FORMAT_TIMESPAN(max, USEC_PER_MSEC));
5a67ed24
PF
512
513 assert_se(min <= nd->retransmit_time);
514 assert_se(max >= nd->retransmit_time);
515
516 last = nd->retransmit_time;
517
518 assert_se(sd_event_source_set_time(nd->timeout_event_source, 0) >= 0);
519
520 return 0;
521}
522
68da8adf 523TEST(timeout) {
86d82cb8 524 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
8430c4d9 525 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
86d82cb8 526 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
5a67ed24 527
5a67ed24
PF
528 assert_se(sd_event_new(&e) >= 0);
529
530 assert_se(sd_ndisc_new(&nd) >= 0);
531 assert_se(nd);
532
5a67ed24
PF
533 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
534
535 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
536 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
537
ba4e0427 538 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
2e37084f
YW
539 30 * USEC_PER_SEC, 0,
540 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
5a67ed24
PF
541
542 assert_se(sd_ndisc_start(nd) >= 0);
543
8430c4d9
YW
544 assert_se(sd_event_add_io(e, &s, test_fd[1], EPOLLIN, on_recv_rs_timeout, nd) >= 0);
545 assert_se(sd_event_source_set_io_fd_own(s, true) >= 0);
546
2e37084f 547 assert_se(sd_event_loop(e) >= 0);
5a67ed24 548
8430c4d9 549 test_fd[1] = -EBADF;
5a67ed24
PF
550}
551
68da8adf 552DEFINE_TEST_MAIN(LOG_DEBUG);