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