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