chiark / gitweb /
9d50c579275ca76a7edcc02bd85fba4795a9517a
[elogind.git] / src / libsystemd-network / test-icmp6-rs.c
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"
27 #include "sd-icmp6-nd.h"
28
29 static struct ether_addr mac_addr = {
30         .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
31 };
32
33 static bool verbose = false;
34 static sd_event_source *test_hangcheck;
35 static int test_fd[2];
36
37 static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
38                              void *userdata) {
39         assert_se(false);
40
41         return 0;
42 }
43
44 int dhcp_network_icmp6_bind_router_solicitation(int index) {
45         assert_se(index == 42);
46
47         if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0)
48                 return -errno;
49
50         return test_fd[0];
51 }
52
53 static int send_ra(uint8_t flags) {
54         uint8_t advertisement[] = {
55                 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
56                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57                 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
58                 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
59                 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
60                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61                 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
62                 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
63                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
64                 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
65                 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
66                 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67                 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
68         };
69
70         advertisement[5] = flags;
71
72         assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
73                sizeof(advertisement));
74
75         if (verbose)
76                 printf("  sent RA with flag 0x%02x\n", flags);
77
78         return 0;
79 }
80
81 int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
82         return send_ra(0);
83 }
84
85 static void test_rs_done(sd_icmp6_nd *nd, int event, void *userdata) {
86         sd_event *e = userdata;
87         static int idx = 0;
88         struct {
89                 uint8_t flag;
90                 int event;
91         } flag_event[] = {
92                 { 0, ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE },
93                 { ND_RA_FLAG_OTHER, ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER },
94                 { ND_RA_FLAG_MANAGED, ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED }
95         };
96         uint32_t mtu;
97
98         assert_se(nd);
99
100         assert_se(event == flag_event[idx].event);
101         idx++;
102
103         if (verbose)
104                 printf("  got event %d\n", event);
105
106         if (idx < 3) {
107                 send_ra(flag_event[idx].flag);
108                 return;
109         }
110
111         assert_se(sd_icmp6_ra_get_mtu(nd, &mtu) == -ENOMSG);
112
113         sd_event_exit(e, 0);
114 }
115
116 static void test_rs(sd_event *e) {
117         usec_t time_now = now(clock_boottime_or_monotonic());
118         sd_icmp6_nd *nd;
119
120         if (verbose)
121                 printf("* %s\n", __FUNCTION__);
122
123         assert_se(sd_icmp6_nd_new(&nd) >= 0);
124         assert_se(nd);
125
126         assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0);
127
128         assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0);
129         assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0);
130         assert_se(sd_icmp6_nd_set_callback(nd, test_rs_done, e) >= 0);
131
132         assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
133                                  time_now + 2 *USEC_PER_SEC, 0,
134                                  test_rs_hangcheck, NULL) >= 0);
135
136         assert_se(sd_icmp6_nd_stop(nd) >= 0);
137         assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
138         assert_se(sd_icmp6_nd_stop(nd) >= 0);
139
140         assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
141
142         sd_event_loop(e);
143
144         test_hangcheck = sd_event_source_unref(test_hangcheck);
145
146         nd = sd_icmp6_nd_unref(nd);
147         assert_se(!nd);
148
149         close(test_fd[1]);
150 }
151
152 int main(int argc, char *argv[]) {
153         sd_event *e;
154
155         assert_se(sd_event_new(&e) >= 0);
156
157         log_set_max_level(LOG_DEBUG);
158         log_parse_environment();
159         log_open();
160
161         test_rs(e);
162
163         return 0;
164 }