]>
Commit | Line | Data |
---|---|---|
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); |