]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/test-ndisc-rs.c
networkd: rename icmp6 to ndisc
[thirdparty/systemd.git] / src / libsystemd-network / test-ndisc-rs.c
CommitLineData
f20a35cc
PF
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright (C) 2014 Intel Corporation. All rights reserved.
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <netinet/icmp6.h>
23
24#include "socket-util.h"
25
26#include "dhcp6-internal.h"
3ad0c5d8 27#include "sd-ndisc.h"
f20a35cc
PF
28
29static struct ether_addr mac_addr = {
30 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
31};
32
33static bool verbose = false;
34static sd_event_source *test_hangcheck;
35static int test_fd[2];
36
99af546d
PF
37typedef int (*send_ra_t)(uint8_t flags);
38static send_ra_t send_ra_function;
39
f20a35cc
PF
40static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
41 void *userdata) {
787784c4 42 assert_se(false);
f20a35cc
PF
43
44 return 0;
45}
46
47int dhcp_network_icmp6_bind_router_solicitation(int index) {
787784c4 48 assert_se(index == 42);
f20a35cc
PF
49
50 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0)
51 return -errno;
52
53 return test_fd[0];
54}
55
99af546d
PF
56static int send_ra_short_prefix(uint8_t flags) {
57 uint8_t advertisement[] = {
58 0x86, 0x00, 0xbe, 0xd7, 0x40, 0xc0, 0x00, 0xb4,
59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60
61 0x03, 0x04, 0x34, 0xc0, 0x00, 0x00, 0x01, 0xf4,
62 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
63 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
65 };
66
67 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
68 sizeof(advertisement));
69
70 return 0;
71}
72
4d7b83da 73static void test_short_prefix_cb(sd_ndisc *nd, int event, void *userdata) {
99af546d
PF
74 sd_event *e = userdata;
75 struct {
76 struct in6_addr addr;
77 uint8_t prefixlen;
78 bool success;
79 } addrs[] = {
80 { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
82 52, true },
83 { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
85 64, false },
86 { { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
88 60, true },
89 { { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
91 64, true },
92 { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed,
93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
94 52, true },
95 };
96 uint8_t prefixlen;
97 unsigned int i;
98
99 for (i = 0; i < ELEMENTSOF(addrs); i++) {
100 printf(" %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x",
101 __FUNCTION__,
102 addrs[i].addr.s6_addr[0], addrs[i].addr.s6_addr[1],
103 addrs[i].addr.s6_addr[2], addrs[i].addr.s6_addr[3],
104 addrs[i].addr.s6_addr[4], addrs[i].addr.s6_addr[5],
105 addrs[i].addr.s6_addr[6], addrs[i].addr.s6_addr[7]);
106
107 if (addrs[i].success) {
4d7b83da 108 assert_se(sd_ndisc_get_prefixlen(nd, &addrs[i].addr,
99af546d
PF
109 &prefixlen) >= 0);
110 assert_se(addrs[i].prefixlen == prefixlen);
111 printf("/%d onlink\n", prefixlen);
112 } else {
4d7b83da 113 assert_se(sd_ndisc_get_prefixlen(nd, &addrs[i].addr,
99af546d
PF
114 &prefixlen) == -EADDRNOTAVAIL);
115 printf("/128 offlink\n");
116 }
117 }
118
119 sd_event_exit(e, 0);
120}
121
122static int send_ra_prefixes(uint8_t flags) {
123 uint8_t advertisement[] = {
124 0x86, 0x00, 0xbe, 0xd7, 0x40, 0xc0, 0x00, 0xb4,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 0x03, 0x04, 0x3f, 0xc0, 0x00, 0x00, 0x01, 0xf4,
127 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
128 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130 0x03, 0x04, 0x40, 0x00, 0x00, 0x00, 0x02, 0x58,
131 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
132 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134 0x03, 0x04, 0x3c, 0x80, 0x00, 0x00, 0x03, 0x84,
135 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00,
136 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x03, 0x84,
139 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00,
140 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
143 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
145 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
146 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
147 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53
149 };
150
151 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
152 sizeof(advertisement));
153
154 return 0;
155}
156
4d7b83da 157static void test_prefixes_cb(sd_ndisc *nd, int event, void *userdata) {
99af546d
PF
158 sd_event *e = userdata;
159 struct {
160 struct in6_addr addr;
161 uint8_t prefixlen;
162 bool success;
163 } addrs[] = {
164 { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
166 63, true },
167 { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
169 64, false },
170 { { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
172 60, true },
173 { { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
175 64, true },
176 { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed,
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
178 63, false },
179 };
180 uint8_t prefixlen;
181 unsigned int i;
182
183 for (i = 0; i < ELEMENTSOF(addrs); i++) {
184 printf(" %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x",
185 __FUNCTION__,
186 addrs[i].addr.s6_addr[0], addrs[i].addr.s6_addr[1],
187 addrs[i].addr.s6_addr[2], addrs[i].addr.s6_addr[3],
188 addrs[i].addr.s6_addr[4], addrs[i].addr.s6_addr[5],
189 addrs[i].addr.s6_addr[6], addrs[i].addr.s6_addr[7]);
190
191 if (addrs[i].success) {
4d7b83da 192 assert_se(sd_ndisc_get_prefixlen(nd, &addrs[i].addr,
99af546d
PF
193 &prefixlen) >= 0);
194 assert_se(addrs[i].prefixlen == prefixlen);
195 printf("/%d onlink\n", prefixlen);
196 } else {
4d7b83da 197 assert_se(sd_ndisc_get_prefixlen(nd, &addrs[i].addr,
99af546d
PF
198 &prefixlen) == -EADDRNOTAVAIL);
199 printf("/128 offlink\n");
200 }
201 }
202
203 send_ra_function = send_ra_short_prefix;
4d7b83da
TG
204 assert_se(sd_ndisc_set_callback(nd, test_short_prefix_cb, e) >= 0);
205 assert_se(sd_ndisc_stop(nd) >= 0);
206 assert_se(sd_ndisc_router_discovery_start(nd) >= 0);
99af546d
PF
207}
208
209static void test_prefixes(void) {
210 sd_event *e;
4d7b83da 211 sd_ndisc *nd;
99af546d
PF
212
213 if (verbose)
214 printf("* %s\n", __FUNCTION__);
215
216 send_ra_function = send_ra_prefixes;
217
218 assert_se(sd_event_new(&e) >= 0);
219
4d7b83da 220 assert_se(sd_ndisc_new(&nd) >= 0);
99af546d
PF
221 assert_se(nd);
222
4d7b83da 223 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
99af546d 224
4d7b83da
TG
225 assert_se(sd_ndisc_set_index(nd, 42) >= 0);
226 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
227 assert_se(sd_ndisc_set_callback(nd, test_prefixes_cb, e) >= 0);
99af546d 228
4d7b83da 229 assert_se(sd_ndisc_router_discovery_start(nd) >= 0);
99af546d
PF
230
231 sd_event_loop(e);
232
4d7b83da 233 nd = sd_ndisc_unref(nd);
99af546d
PF
234 assert_se(!nd);
235
236 close(test_fd[1]);
237
238 sd_event_unref(e);
239}
240
f20a35cc
PF
241static int send_ra(uint8_t flags) {
242 uint8_t advertisement[] = {
243 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
244 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
246 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
247 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
248 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
249 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
250 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
251 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
252 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
253 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
254 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
255 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
256 };
257
258 advertisement[5] = flags;
259
787784c4 260 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
f20a35cc
PF
261 sizeof(advertisement));
262
263 if (verbose)
264 printf(" sent RA with flag 0x%02x\n", flags);
265
266 return 0;
267}
268
269int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
99af546d 270 return send_ra_function(0);
f20a35cc
PF
271}
272
4d7b83da 273static void test_rs_done(sd_ndisc *nd, int event, void *userdata) {
f20a35cc
PF
274 sd_event *e = userdata;
275 static int idx = 0;
276 struct {
277 uint8_t flag;
278 int event;
279 } flag_event[] = {
4d7b83da
TG
280 { 0, SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE },
281 { ND_RA_FLAG_OTHER, SD_NDISC_EVENT_ROUTER_ADVERTISMENT_OTHER },
282 { ND_RA_FLAG_MANAGED, SD_NDISC_EVENT_ROUTER_ADVERTISMENT_MANAGED }
f20a35cc 283 };
8d7f2c6a
PF
284 uint32_t mtu;
285
787784c4 286 assert_se(nd);
f20a35cc 287
787784c4 288 assert_se(event == flag_event[idx].event);
f20a35cc
PF
289 idx++;
290
291 if (verbose)
292 printf(" got event %d\n", event);
293
8d7f2c6a 294 if (idx < 3) {
f20a35cc 295 send_ra(flag_event[idx].flag);
8d7f2c6a
PF
296 return;
297 }
298
4d7b83da 299 assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENOMSG);
8d7f2c6a
PF
300
301 sd_event_exit(e, 0);
f20a35cc
PF
302}
303
99af546d
PF
304static void test_rs(void) {
305 sd_event *e;
4d7b83da 306 sd_ndisc *nd;
99af546d 307 usec_t time_now = now(clock_boottime_or_monotonic());
f20a35cc
PF
308
309 if (verbose)
310 printf("* %s\n", __FUNCTION__);
311
99af546d
PF
312 send_ra_function = send_ra;
313
314 assert_se(sd_event_new(&e) >= 0);
315
4d7b83da 316 assert_se(sd_ndisc_new(&nd) >= 0);
787784c4 317 assert_se(nd);
f20a35cc 318
4d7b83da 319 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
f20a35cc 320
4d7b83da
TG
321 assert_se(sd_ndisc_set_index(nd, 42) >= 0);
322 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
323 assert_se(sd_ndisc_set_callback(nd, test_rs_done, e) >= 0);
f20a35cc 324
787784c4 325 assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
f20a35cc
PF
326 time_now + 2 *USEC_PER_SEC, 0,
327 test_rs_hangcheck, NULL) >= 0);
328
4d7b83da
TG
329 assert_se(sd_ndisc_stop(nd) >= 0);
330 assert_se(sd_ndisc_router_discovery_start(nd) >= 0);
331 assert_se(sd_ndisc_stop(nd) >= 0);
836cf090 332
4d7b83da 333 assert_se(sd_ndisc_router_discovery_start(nd) >= 0);
f20a35cc
PF
334
335 sd_event_loop(e);
336
337 test_hangcheck = sd_event_source_unref(test_hangcheck);
338
4d7b83da 339 nd = sd_ndisc_unref(nd);
787784c4 340 assert_se(!nd);
f20a35cc 341
f20a35cc 342 close(test_fd[1]);
99af546d
PF
343
344 sd_event_unref(e);
f20a35cc
PF
345}
346
347int main(int argc, char *argv[]) {
f20a35cc
PF
348
349 log_set_max_level(LOG_DEBUG);
350 log_parse_environment();
351 log_open();
352
99af546d
PF
353 test_rs();
354 test_prefixes();
f20a35cc
PF
355
356 return 0;
357}