1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2014 Intel Corporation. All rights reserved.
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.
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.
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/>.
22 #include <netinet/icmp6.h>
24 #include "socket-util.h"
26 #include "dhcp6-internal.h"
27 #include "sd-icmp6-nd.h"
29 static struct ether_addr mac_addr = {
30 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
33 static bool verbose = false;
34 static sd_event_source *test_hangcheck;
35 static int test_fd[2];
37 typedef int (*send_ra_t)(uint8_t flags);
38 static send_ra_t send_ra_function;
40 static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
47 int dhcp_network_icmp6_bind_router_solicitation(int index) {
48 assert_se(index == 42);
50 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0)
56 static 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,
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
67 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
68 sizeof(advertisement));
73 static void test_short_prefix_cb(sd_icmp6_nd *nd, int event, void *userdata) {
74 sd_event *e = userdata;
80 { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
83 { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
86 { { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
89 { { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
92 { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed,
93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
99 for (i = 0; i < ELEMENTSOF(addrs); i++) {
100 printf(" %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x",
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]);
107 if (addrs[i].success) {
108 assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
110 assert_se(addrs[i].prefixlen == prefixlen);
111 printf("/%d onlink\n", prefixlen);
113 assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
114 &prefixlen) == -EADDRNOTAVAIL);
115 printf("/128 offlink\n");
122 static 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
151 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
152 sizeof(advertisement));
157 static void test_prefixes_cb(sd_icmp6_nd *nd, int event, void *userdata) {
158 sd_event *e = userdata;
160 struct in6_addr addr;
164 { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
167 { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
170 { { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
173 { { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
176 { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed,
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
183 for (i = 0; i < ELEMENTSOF(addrs); i++) {
184 printf(" %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x",
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]);
191 if (addrs[i].success) {
192 assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
194 assert_se(addrs[i].prefixlen == prefixlen);
195 printf("/%d onlink\n", prefixlen);
197 assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
198 &prefixlen) == -EADDRNOTAVAIL);
199 printf("/128 offlink\n");
203 send_ra_function = send_ra_short_prefix;
204 assert_se(sd_icmp6_nd_set_callback(nd, test_short_prefix_cb, e) >= 0);
205 assert_se(sd_icmp6_nd_stop(nd) >= 0);
206 assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
209 static void test_prefixes(void) {
214 printf("* %s\n", __FUNCTION__);
216 send_ra_function = send_ra_prefixes;
218 assert_se(sd_event_new(&e) >= 0);
220 assert_se(sd_icmp6_nd_new(&nd) >= 0);
223 assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0);
225 assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0);
226 assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0);
227 assert_se(sd_icmp6_nd_set_callback(nd, test_prefixes_cb, e) >= 0);
229 assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
233 nd = sd_icmp6_nd_unref(nd);
241 static 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,
258 advertisement[5] = flags;
260 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
261 sizeof(advertisement));
264 printf(" sent RA with flag 0x%02x\n", flags);
269 int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
270 return send_ra_function(0);
273 static void test_rs_done(sd_icmp6_nd *nd, int event, void *userdata) {
274 sd_event *e = userdata;
280 { 0, ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE },
281 { ND_RA_FLAG_OTHER, ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER },
282 { ND_RA_FLAG_MANAGED, ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED }
288 assert_se(event == flag_event[idx].event);
292 printf(" got event %d\n", event);
295 send_ra(flag_event[idx].flag);
299 assert_se(sd_icmp6_ra_get_mtu(nd, &mtu) == -ENOMSG);
304 static void test_rs(void) {
307 usec_t time_now = now(clock_boottime_or_monotonic());
310 printf("* %s\n", __FUNCTION__);
312 send_ra_function = send_ra;
314 assert_se(sd_event_new(&e) >= 0);
316 assert_se(sd_icmp6_nd_new(&nd) >= 0);
319 assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0);
321 assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0);
322 assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0);
323 assert_se(sd_icmp6_nd_set_callback(nd, test_rs_done, e) >= 0);
325 assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
326 time_now + 2 *USEC_PER_SEC, 0,
327 test_rs_hangcheck, NULL) >= 0);
329 assert_se(sd_icmp6_nd_stop(nd) >= 0);
330 assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
331 assert_se(sd_icmp6_nd_stop(nd) >= 0);
333 assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
337 test_hangcheck = sd_event_source_unref(test_hangcheck);
339 nd = sd_icmp6_nd_unref(nd);
347 int main(int argc, char *argv[]) {
349 log_set_max_level(LOG_DEBUG);
350 log_parse_environment();