summaryrefslogtreecommitdiff
path: root/src/libsystemd-network/test-ndisc-rs.c
diff options
context:
space:
mode:
authorTom Gundersen <teg@jklm.no>2015-10-15 19:25:31 +0200
committerTom Gundersen <teg@jklm.no>2015-10-22 17:19:54 +0200
commit3ad0c5d8a4e2e2fa7ffcccd7f3457f577908494e (patch)
tree037b47783bb77459c692caeee7e3106505956f3b /src/libsystemd-network/test-ndisc-rs.c
parentac691d4abe0970e9255525d1cc6187e553639fea (diff)
sd-icmp6-nd: rename files to sd-ndisc
The actual code rename will follow. The reason for the change of name is to make it simpler and more uniform with how we name other libraries (we don't include the underlying protocol). The new name also matches the naming in the kernel (which is particularly relevent here as we expect to let the kernel do some parts of the protocol and we do others).
Diffstat (limited to 'src/libsystemd-network/test-ndisc-rs.c')
-rw-r--r--src/libsystemd-network/test-ndisc-rs.c357
1 files changed, 357 insertions, 0 deletions
diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c
new file mode 100644
index 0000000000..49305e297b
--- /dev/null
+++ b/src/libsystemd-network/test-ndisc-rs.c
@@ -0,0 +1,357 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <netinet/icmp6.h>
+
+#include "socket-util.h"
+
+#include "dhcp6-internal.h"
+#include "sd-ndisc.h"
+
+static struct ether_addr mac_addr = {
+ .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
+};
+
+static bool verbose = false;
+static sd_event_source *test_hangcheck;
+static int test_fd[2];
+
+typedef int (*send_ra_t)(uint8_t flags);
+static send_ra_t send_ra_function;
+
+static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
+ void *userdata) {
+ assert_se(false);
+
+ return 0;
+}
+
+int dhcp_network_icmp6_bind_router_solicitation(int index) {
+ assert_se(index == 42);
+
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0)
+ return -errno;
+
+ return test_fd[0];
+}
+
+static int send_ra_short_prefix(uint8_t flags) {
+ uint8_t advertisement[] = {
+ 0x86, 0x00, 0xbe, 0xd7, 0x40, 0xc0, 0x00, 0xb4,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ 0x03, 0x04, 0x34, 0xc0, 0x00, 0x00, 0x01, 0xf4,
+ 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
+ sizeof(advertisement));
+
+ return 0;
+}
+
+static void test_short_prefix_cb(sd_icmp6_nd *nd, int event, void *userdata) {
+ sd_event *e = userdata;
+ struct {
+ struct in6_addr addr;
+ uint8_t prefixlen;
+ bool success;
+ } addrs[] = {
+ { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
+ 52, true },
+ { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
+ 64, false },
+ { { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
+ 60, true },
+ { { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
+ 64, true },
+ { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
+ 52, true },
+ };
+ uint8_t prefixlen;
+ unsigned int i;
+
+ for (i = 0; i < ELEMENTSOF(addrs); i++) {
+ printf(" %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x",
+ __FUNCTION__,
+ addrs[i].addr.s6_addr[0], addrs[i].addr.s6_addr[1],
+ addrs[i].addr.s6_addr[2], addrs[i].addr.s6_addr[3],
+ addrs[i].addr.s6_addr[4], addrs[i].addr.s6_addr[5],
+ addrs[i].addr.s6_addr[6], addrs[i].addr.s6_addr[7]);
+
+ if (addrs[i].success) {
+ assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
+ &prefixlen) >= 0);
+ assert_se(addrs[i].prefixlen == prefixlen);
+ printf("/%d onlink\n", prefixlen);
+ } else {
+ assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
+ &prefixlen) == -EADDRNOTAVAIL);
+ printf("/128 offlink\n");
+ }
+ }
+
+ sd_event_exit(e, 0);
+}
+
+static int send_ra_prefixes(uint8_t flags) {
+ uint8_t advertisement[] = {
+ 0x86, 0x00, 0xbe, 0xd7, 0x40, 0xc0, 0x00, 0xb4,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x04, 0x3f, 0xc0, 0x00, 0x00, 0x01, 0xf4,
+ 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x04, 0x40, 0x00, 0x00, 0x00, 0x02, 0x58,
+ 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x04, 0x3c, 0x80, 0x00, 0x00, 0x03, 0x84,
+ 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x03, 0x84,
+ 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+ 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+ 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
+ 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53
+ };
+
+ assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
+ sizeof(advertisement));
+
+ return 0;
+}
+
+static void test_prefixes_cb(sd_icmp6_nd *nd, int event, void *userdata) {
+ sd_event *e = userdata;
+ struct {
+ struct in6_addr addr;
+ uint8_t prefixlen;
+ bool success;
+ } addrs[] = {
+ { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
+ 63, true },
+ { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
+ 64, false },
+ { { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
+ 60, true },
+ { { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
+ 64, true },
+ { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
+ 63, false },
+ };
+ uint8_t prefixlen;
+ unsigned int i;
+
+ for (i = 0; i < ELEMENTSOF(addrs); i++) {
+ printf(" %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x",
+ __FUNCTION__,
+ addrs[i].addr.s6_addr[0], addrs[i].addr.s6_addr[1],
+ addrs[i].addr.s6_addr[2], addrs[i].addr.s6_addr[3],
+ addrs[i].addr.s6_addr[4], addrs[i].addr.s6_addr[5],
+ addrs[i].addr.s6_addr[6], addrs[i].addr.s6_addr[7]);
+
+ if (addrs[i].success) {
+ assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
+ &prefixlen) >= 0);
+ assert_se(addrs[i].prefixlen == prefixlen);
+ printf("/%d onlink\n", prefixlen);
+ } else {
+ assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
+ &prefixlen) == -EADDRNOTAVAIL);
+ printf("/128 offlink\n");
+ }
+ }
+
+ send_ra_function = send_ra_short_prefix;
+ assert_se(sd_icmp6_nd_set_callback(nd, test_short_prefix_cb, e) >= 0);
+ assert_se(sd_icmp6_nd_stop(nd) >= 0);
+ assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
+}
+
+static void test_prefixes(void) {
+ sd_event *e;
+ sd_icmp6_nd *nd;
+
+ if (verbose)
+ printf("* %s\n", __FUNCTION__);
+
+ send_ra_function = send_ra_prefixes;
+
+ assert_se(sd_event_new(&e) >= 0);
+
+ assert_se(sd_icmp6_nd_new(&nd) >= 0);
+ assert_se(nd);
+
+ assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0);
+
+ assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0);
+ assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0);
+ assert_se(sd_icmp6_nd_set_callback(nd, test_prefixes_cb, e) >= 0);
+
+ assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
+
+ sd_event_loop(e);
+
+ nd = sd_icmp6_nd_unref(nd);
+ assert_se(!nd);
+
+ close(test_fd[1]);
+
+ sd_event_unref(e);
+}
+
+static int send_ra(uint8_t flags) {
+ uint8_t advertisement[] = {
+ 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
+ 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+ 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+ 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
+ 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
+ };
+
+ advertisement[5] = flags;
+
+ assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
+ sizeof(advertisement));
+
+ if (verbose)
+ printf(" sent RA with flag 0x%02x\n", flags);
+
+ return 0;
+}
+
+int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
+ return send_ra_function(0);
+}
+
+static void test_rs_done(sd_icmp6_nd *nd, int event, void *userdata) {
+ sd_event *e = userdata;
+ static int idx = 0;
+ struct {
+ uint8_t flag;
+ int event;
+ } flag_event[] = {
+ { 0, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE },
+ { ND_RA_FLAG_OTHER, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER },
+ { ND_RA_FLAG_MANAGED, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED }
+ };
+ uint32_t mtu;
+
+ assert_se(nd);
+
+ assert_se(event == flag_event[idx].event);
+ idx++;
+
+ if (verbose)
+ printf(" got event %d\n", event);
+
+ if (idx < 3) {
+ send_ra(flag_event[idx].flag);
+ return;
+ }
+
+ assert_se(sd_icmp6_ra_get_mtu(nd, &mtu) == -ENOMSG);
+
+ sd_event_exit(e, 0);
+}
+
+static void test_rs(void) {
+ sd_event *e;
+ sd_icmp6_nd *nd;
+ usec_t time_now = now(clock_boottime_or_monotonic());
+
+ if (verbose)
+ printf("* %s\n", __FUNCTION__);
+
+ send_ra_function = send_ra;
+
+ assert_se(sd_event_new(&e) >= 0);
+
+ assert_se(sd_icmp6_nd_new(&nd) >= 0);
+ assert_se(nd);
+
+ assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0);
+
+ assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0);
+ assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0);
+ assert_se(sd_icmp6_nd_set_callback(nd, test_rs_done, e) >= 0);
+
+ assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
+ time_now + 2 *USEC_PER_SEC, 0,
+ test_rs_hangcheck, NULL) >= 0);
+
+ assert_se(sd_icmp6_nd_stop(nd) >= 0);
+ assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
+ assert_se(sd_icmp6_nd_stop(nd) >= 0);
+
+ assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
+
+ sd_event_loop(e);
+
+ test_hangcheck = sd_event_source_unref(test_hangcheck);
+
+ nd = sd_icmp6_nd_unref(nd);
+ assert_se(!nd);
+
+ close(test_fd[1]);
+
+ sd_event_unref(e);
+}
+
+int main(int argc, char *argv[]) {
+
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+ log_open();
+
+ test_rs();
+ test_prefixes();
+
+ return 0;
+}