]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/test-dhcp-client.c
sd-dhcp-client: refactor client_{free,new}
[thirdparty/systemd.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 }