]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-ndisc-rs.c
71af4c24788c614d5485f179f8ac569f06a13494
[thirdparty/systemd.git] / src / libsystemd-network / test-ndisc-rs.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2014 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <netinet/icmp6.h>
7 #include <unistd.h>
8
9 #include "sd-ndisc.h"
10
11 #include "alloc-util.h"
12 #include "fd-util.h"
13 #include "hexdecoct.h"
14 #include "icmp6-packet.h"
15 #include "icmp6-test-util.h"
16 #include "in-addr-util.h"
17 #include "ndisc-internal.h"
18 #include "strv.h"
19 #include "tests.h"
20
21 static struct ether_addr mac_addr = {
22 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
23 };
24
25 static bool verbose = false;
26
27 static void router_dump(sd_ndisc_router *rt) {
28 struct in6_addr addr;
29 uint8_t hop_limit;
30 usec_t t, lifetime, retrans_time;
31 uint64_t flags;
32 uint32_t mtu;
33 uint8_t preference;
34 int r;
35
36 assert_se(rt);
37
38 log_info("--");
39 assert_se(sd_ndisc_router_get_sender_address(rt, &addr) >= 0);
40 log_info("Sender: %s", IN6_ADDR_TO_STRING(&addr));
41
42 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
43 log_info("Timestamp: %s", FORMAT_TIMESTAMP(t));
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);
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));
66
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
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;
93 const uint8_t *p;
94 size_t n;
95
96 assert_se(sd_ndisc_router_option_get_raw(rt, &p, &n) >= 0);
97 assert_se(n > 2);
98 assert_se(c = hexmem(p + 2, n - 2));
99
100 log_info("Address: %s", c);
101 break;
102 }
103
104 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
105 uint8_t prefix_len, pfl;
106 struct in6_addr a;
107
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));
111
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));
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);
125 log_info("Prefix: %s", IN6_ADDR_TO_STRING(&a));
126
127 break;
128 }
129
130 case SD_NDISC_OPTION_RDNSS: {
131 const struct in6_addr *a;
132 int n, i;
133
134 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
135 assert_se(n > 0);
136
137 for (i = 0; i < n; i++)
138 log_info("DNS: %s", IN6_ADDR_TO_STRING(a + i));
139
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));
143 break;
144 }
145
146 case SD_NDISC_OPTION_DNSSL: {
147 char **l;
148
149 assert_se(sd_ndisc_router_dnssl_get_domains(rt, &l) >= 0);
150
151 STRV_FOREACH(s, l)
152 log_info("Domain: %s", *s);
153
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));
157 break;
158 }}
159
160 r = sd_ndisc_router_option_next(rt);
161 }
162 }
163
164 static int send_ra(uint8_t flags) {
165 uint8_t advertisement[] = {
166 /* struct nd_router_advert */
167 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 /* type = 0x03 (SD_NDISC_OPTION_PREFIX_INFORMATION), length = 32 */
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,
174 /* type = 0x19 (SD_NDISC_OPTION_RDNSS), length = 24 */
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,
178 /* type = 0x1f (SD_NDISC_OPTION_DNSSL), length = 24 */
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,
182 /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
183 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
184 };
185
186 advertisement[5] = flags;
187
188 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
189 sizeof(advertisement));
190
191 if (verbose)
192 printf(" sent RA with flag 0x%02x\n", flags);
193
194 return 0;
195 }
196
197 static void test_callback_ra(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata) {
198 sd_event *e = userdata;
199 static unsigned idx = 0;
200 uint64_t flags_array[] = {
201 0,
202 0,
203 0,
204 ND_RA_FLAG_OTHER,
205 ND_RA_FLAG_MANAGED
206 };
207 uint64_t flags;
208
209 assert_se(nd);
210
211 if (event != SD_NDISC_EVENT_ROUTER)
212 return;
213
214 sd_ndisc_router *rt = ASSERT_PTR(message);
215
216 router_dump(rt);
217
218 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
219 assert_se(flags == flags_array[idx]);
220 idx++;
221
222 if (verbose)
223 printf(" got event 0x%02" PRIx64 "\n", flags);
224
225 if (idx < ELEMENTSOF(flags_array)) {
226 send_ra(flags_array[idx]);
227 return;
228 }
229
230 idx = 0;
231 sd_event_exit(e, 0);
232 }
233
234 static 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
241 TEST(rs) {
242 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
243 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
244 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
245
246 assert_se(sd_event_new(&e) >= 0);
247
248 assert_se(sd_ndisc_new(&nd) >= 0);
249 assert_se(nd);
250
251 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
252
253 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
254 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
255 assert_se(sd_ndisc_set_callback(nd, test_callback_ra, e) >= 0);
256
257 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
258 30 * USEC_PER_SEC, 0,
259 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
260
261 assert_se(sd_ndisc_stop(nd) >= 0);
262 assert_se(sd_ndisc_start(nd) >= 0);
263 assert_se(sd_ndisc_start(nd) >= 0);
264 assert_se(sd_ndisc_stop(nd) >= 0);
265 test_fd[1] = safe_close(test_fd[1]);
266
267 assert_se(sd_ndisc_start(nd) >= 0);
268
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
272 assert_se(sd_event_loop(e) >= 0);
273
274 test_fd[1] = -EBADF;
275 }
276
277 static 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,
291 /* type = 0x1f (SD_NDISC_OPTION_DNSSL), length = 112 */
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,
306 /* type = 0x01 (SD_NDISC_OPTION_SOURCE_LL_ADDRESS), length = 8 */
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
323 static 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
330 TEST(invalid_domain) {
331 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
332 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
333 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
334
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);
344 assert_se(sd_ndisc_set_callback(nd, test_callback_ra, e) >= 0);
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
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
355 assert_se(sd_event_loop(e) >= 0);
356
357 test_fd[1] = -EBADF;
358 }
359
360 static 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
381 static 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
400 static 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
437 static 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
444 TEST(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
474 static 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);
477 static int count = 0;
478 static usec_t last = 0;
479 usec_t min, max;
480
481 assert_se(icmp6_packet_receive(fd, &packet) >= 0);
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
506 log_info("backoff timeout interval %2d %s%s <= %s <= %s",
507 count,
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));
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
523 TEST(timeout) {
524 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
525 _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
526 _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
527
528 assert_se(sd_event_new(&e) >= 0);
529
530 assert_se(sd_ndisc_new(&nd) >= 0);
531 assert_se(nd);
532
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
538 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
539 30 * USEC_PER_SEC, 0,
540 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
541
542 assert_se(sd_ndisc_start(nd) >= 0);
543
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
547 assert_se(sd_event_loop(e) >= 0);
548
549 test_fd[1] = -EBADF;
550 }
551
552 DEFINE_TEST_MAIN(LOG_DEBUG);