chiark / gitweb /
libsystemd-dhcp: Add capability to print out test steps
[elogind.git] / src / libsystemd-dhcp / test-dhcp-client.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) 2013 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 <stdlib.h>
23 #include <assert.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <unistd.h>
29
30 #include "util.h"
31 #include "socket-util.h"
32
33 #include "dhcp-protocol.h"
34 #include "dhcp-internal.h"
35 #include "sd-dhcp-client.h"
36
37 static struct ether_addr mac_addr = {
38         .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
39 };
40
41 static bool verbose = false;
42 static int test_fd[2];
43
44 static void test_request_basic(sd_event *e)
45 {
46         int r;
47
48         sd_dhcp_client *client;
49
50         if (verbose)
51                 printf("* %s\n", __FUNCTION__);
52
53         r = sd_dhcp_client_new(&client);
54
55         assert(r >= 0);
56         assert(client);
57
58         r = sd_dhcp_client_attach_event(client, e, 0);
59         assert(r >= 0);
60
61         assert(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL);
62         assert(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL);
63         assert(sd_dhcp_client_set_index(NULL, 0) == -EINVAL);
64
65         assert(sd_dhcp_client_set_index(client, 15) == 0);
66         assert(sd_dhcp_client_set_index(client, -42) == -EINVAL);
67         assert(sd_dhcp_client_set_index(client, -1) == 0);
68
69         assert(sd_dhcp_client_set_request_option(client,
70                                         DHCP_OPTION_SUBNET_MASK) == -EEXIST);
71         assert(sd_dhcp_client_set_request_option(client,
72                                         DHCP_OPTION_ROUTER) == -EEXIST);
73         assert(sd_dhcp_client_set_request_option(client,
74                                         DHCP_OPTION_HOST_NAME) == -EEXIST);
75         assert(sd_dhcp_client_set_request_option(client,
76                                         DHCP_OPTION_DOMAIN_NAME) == -EEXIST);
77         assert(sd_dhcp_client_set_request_option(client,
78                                         DHCP_OPTION_DOMAIN_NAME_SERVER)
79                         == -EEXIST);
80         assert(sd_dhcp_client_set_request_option(client,
81                                         DHCP_OPTION_NTP_SERVER) == -EEXIST);
82
83         assert(sd_dhcp_client_set_request_option(client,
84                                         DHCP_OPTION_PAD) == -EINVAL);
85         assert(sd_dhcp_client_set_request_option(client,
86                                         DHCP_OPTION_END) == -EINVAL);
87         assert(sd_dhcp_client_set_request_option(client,
88                                         DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
89         assert(sd_dhcp_client_set_request_option(client,
90                                         DHCP_OPTION_OVERLOAD) == -EINVAL);
91         assert(sd_dhcp_client_set_request_option(client,
92                                         DHCP_OPTION_PARAMETER_REQUEST_LIST)
93                         == -EINVAL);
94
95         assert(sd_dhcp_client_set_request_option(client, 33) == 0);
96         assert(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
97         assert(sd_dhcp_client_set_request_option(client, 44) == 0);
98         assert(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
99 }
100
101 static uint16_t client_checksum(void *buf, int len)
102 {
103         uint32_t sum;
104         uint16_t *check;
105         int i;
106         uint8_t *odd;
107
108         sum = 0;
109         check = buf;
110
111         for (i = 0; i < len / 2 ; i++)
112                 sum += check[i];
113
114         if (len & 0x01) {
115                 odd = buf;
116                 sum += odd[len - 1];
117         }
118
119         while (sum >> 16)
120                 sum = (sum & 0xffff) + (sum >> 16);
121
122         return ~sum;
123 }
124
125 static void test_checksum(void)
126 {
127         uint8_t buf[20] = {
128                 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
129                 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130                 0xff, 0xff, 0xff, 0xff
131         };
132
133         if (verbose)
134                 printf("* %s\n", __FUNCTION__);
135
136         assert(client_checksum(&buf, 20) == be16toh(0x78ae));
137 }
138
139 static int check_options(uint8_t code, uint8_t len, const uint8_t *option,
140                 void *user_data)
141 {
142         return 0;
143 }
144
145 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
146                                  const void *packet, size_t len)
147 {
148         size_t size;
149         _cleanup_free_ DHCPPacket *discover;
150         uint16_t ip_check, udp_check;
151         int res;
152
153         assert(s >= 0);
154         assert(packet);
155
156         size = sizeof(DHCPPacket) + 4;
157         assert(len > size);
158
159         discover = memdup(packet, len);
160
161         assert(memcmp(discover->dhcp.chaddr,
162                       &mac_addr.ether_addr_octet, 6) == 0);
163         assert(discover->ip.ttl == IPDEFTTL);
164         assert(discover->ip.protocol == IPPROTO_UDP);
165         assert(discover->ip.saddr == INADDR_ANY);
166         assert(discover->ip.daddr == INADDR_BROADCAST);
167         assert(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
168         assert(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
169
170         ip_check = discover->ip.check;
171
172         discover->ip.ttl = 0;
173         discover->ip.check = discover->udp.len;
174
175         udp_check = ~client_checksum(&discover->ip.ttl, len - 8);
176         assert(udp_check == 0xffff);
177
178         discover->ip.ttl = IPDEFTTL;
179         discover->ip.check = ip_check;
180
181         ip_check = ~client_checksum(&discover->ip, sizeof(discover->ip));
182         assert(ip_check == 0xffff);
183
184         size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
185
186         res = dhcp_option_parse(&discover->dhcp, size, check_options, NULL);
187         if (res < 0)
188                 return res;
189
190         return 575;
191 }
192
193 int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link)
194 {
195         if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
196                 return -errno;
197
198         return test_fd[0];
199 }
200
201 int dhcp_network_bind_udp_socket(int index, be32_t address, uint16_t port)
202 {
203         return 0;
204 }
205
206 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
207                                  const void *packet, size_t len)
208 {
209         return 0;
210 }
211
212 static void test_discover_message(sd_event *e)
213 {
214         sd_dhcp_client *client;
215         int res, r;
216
217         if (verbose)
218                 printf("* %s\n", __FUNCTION__);
219
220         r = sd_dhcp_client_new(&client);
221         assert(r >= 0);
222         assert(client);
223
224         r = sd_dhcp_client_attach_event(client, e, 0);
225         assert(r >= 0);
226
227         assert(sd_dhcp_client_set_index(client, 42) >= 0);
228         assert(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
229
230         assert(sd_dhcp_client_set_request_option(client, 248) >= 0);
231
232         res = sd_dhcp_client_start(client);
233
234         assert(res == 0 || res == -EINPROGRESS);
235
236         close(test_fd[0]);
237         close(test_fd[1]);
238 }
239
240 int main(int argc, char *argv[])
241 {
242         sd_event *e;
243
244         assert(sd_event_new(&e) >= 0);
245
246         test_request_basic(e);
247         test_checksum();
248
249         test_discover_message(e);
250         sd_event_run(e, (uint64_t) -1);
251
252         return 0;
253 }