]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/test-dhcp-client.c
dhcp: add test for dhcp_identifier_set_iaid()
[thirdparty/systemd.git] / src / libsystemd-network / test-dhcp-client.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
be391925 2/***
810adae9 3 Copyright © 2013 Intel Corporation. All rights reserved.
be391925
PF
4***/
5
be391925 6#include <errno.h>
39b7f596 7#include <stdio.h>
8c00042c
PF
8#include <sys/socket.h>
9#include <unistd.h>
43fc0955 10#include <net/if.h>
be391925 11
07630cea 12#include "sd-dhcp-client.h"
6e00a806 13#include "sd-event.h"
290c7324 14
b5efdb8a 15#include "alloc-util.h"
5bac5235 16#include "dhcp-identifier.h"
290c7324 17#include "dhcp-internal.h"
07630cea 18#include "dhcp-protocol.h"
3ffd4af2 19#include "fd-util.h"
43fc0955 20#include "random-util.h"
6d7c4033 21#include "tests.h"
cf0fbc49 22#include "util.h"
be391925 23
5bac5235 24static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'};
290c7324 25
6c8a0f07
PF
26typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
27
5bac5235 28static bool verbose = true;
8c00042c 29static int test_fd[2];
6c8a0f07 30static test_callback_recv_t callback_recv;
234ed3eb 31static be32_t xid;
8fc8e3ab
PF
32static sd_event_source *test_hangcheck;
33
52efd56a 34static int test_dhcp_hangcheck(sd_event_source *s, uint64_t usec, void *userdata) {
8fc8e3ab
PF
35 assert_not_reached("Test case should have completed in 2 seconds");
36
37 return 0;
38}
8c00042c 39
52efd56a 40static void test_request_basic(sd_event *e) {
b25ef18b
TG
41 int r;
42
be391925
PF
43 sd_dhcp_client *client;
44
ede286f9
PF
45 if (verbose)
46 printf("* %s\n", __FUNCTION__);
47
db3d2358 48 /* Initialize client without Anonymize settings. */
49 r = sd_dhcp_client_new(&client, false);
be391925 50
12e0f830
TG
51 assert_se(r >= 0);
52 assert_se(client);
be391925 53
b25ef18b 54 r = sd_dhcp_client_attach_event(client, e, 0);
12e0f830 55 assert_se(r >= 0);
b25ef18b 56
12e0f830
TG
57 assert_se(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL);
58 assert_se(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL);
2f8e7633 59 assert_se(sd_dhcp_client_set_ifindex(NULL, 0) == -EINVAL);
be391925 60
2f8e7633
LP
61 assert_se(sd_dhcp_client_set_ifindex(client, 15) == 0);
62 assert_se(sd_dhcp_client_set_ifindex(client, -42) == -EINVAL);
63 assert_se(sd_dhcp_client_set_ifindex(client, -1) == -EINVAL);
64 assert_se(sd_dhcp_client_set_ifindex(client, 0) == -EINVAL);
65 assert_se(sd_dhcp_client_set_ifindex(client, 1) == 0);
be391925 66
9740eae6
SA
67 assert_se(sd_dhcp_client_set_hostname(client, "host") == 1);
68 assert_se(sd_dhcp_client_set_hostname(client, "host.domain") == 1);
69 assert_se(sd_dhcp_client_set_hostname(client, NULL) == 1);
70 assert_se(sd_dhcp_client_set_hostname(client, "~host") == -EINVAL);
71 assert_se(sd_dhcp_client_set_hostname(client, "~host.domain") == -EINVAL);
72
12e0f830 73 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 74 SD_DHCP_OPTION_SUBNET_MASK) == -EEXIST);
12e0f830 75 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 76 SD_DHCP_OPTION_ROUTER) == -EEXIST);
db3d2358 77 /* This PRL option is not set when using Anonymize, but in this test
78 * Anonymize settings are not being used. */
12e0f830 79 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 80 SD_DHCP_OPTION_HOST_NAME) == -EEXIST);
12e0f830 81 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 82 SD_DHCP_OPTION_DOMAIN_NAME) == -EEXIST);
12e0f830 83 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 84 SD_DHCP_OPTION_DOMAIN_NAME_SERVER) == -EEXIST);
be391925 85
12e0f830 86 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 87 SD_DHCP_OPTION_PAD) == -EINVAL);
12e0f830 88 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 89 SD_DHCP_OPTION_END) == -EINVAL);
12e0f830 90 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 91 SD_DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
12e0f830 92 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 93 SD_DHCP_OPTION_OVERLOAD) == -EINVAL);
12e0f830 94 assert_se(sd_dhcp_client_set_request_option(client,
22805d92 95 SD_DHCP_OPTION_PARAMETER_REQUEST_LIST)
be391925
PF
96 == -EINVAL);
97
db3d2358 98 /* RFC7844: option 33 (SD_DHCP_OPTION_STATIC_ROUTE) is set in the
99 * default PRL when using Anonymize, so it is changed to other option
da172fa9
FK
100 * that is not set by default, to check that it was set successfully.
101 * Options not set by default (using or not anonymize) are option 17
db3d2358 102 * (SD_DHCP_OPTION_ROOT_PATH) and 42 (SD_DHCP_OPTION_NTP_SERVER) */
103 assert_se(sd_dhcp_client_set_request_option(client, 17) == 0);
104 assert_se(sd_dhcp_client_set_request_option(client, 17) == -EEXIST);
105 assert_se(sd_dhcp_client_set_request_option(client, 42) == 0);
106 assert_se(sd_dhcp_client_set_request_option(client, 17) == -EEXIST);
6e00a806
ZJS
107
108 sd_dhcp_client_unref(client);
be391925
PF
109}
110
dbb35f1f 111static void test_request_anonymize(sd_event *e) {
112 int r;
113
114 sd_dhcp_client *client;
115
116 if (verbose)
117 printf("* %s\n", __FUNCTION__);
118
119 /* Initialize client with Anonymize settings. */
120 r = sd_dhcp_client_new(&client, true);
121
122 assert_se(r >= 0);
123 assert_se(client);
124
125 r = sd_dhcp_client_attach_event(client, e, 0);
126 assert_se(r >= 0);
127
128 assert_se(sd_dhcp_client_set_request_option(client,
129 SD_DHCP_OPTION_NETBIOS_NAMESERVER) == -EEXIST);
130 /* This PRL option is not set when using Anonymize */
131 assert_se(sd_dhcp_client_set_request_option(client,
132 SD_DHCP_OPTION_HOST_NAME) == 0);
133 assert_se(sd_dhcp_client_set_request_option(client,
134 SD_DHCP_OPTION_PARAMETER_REQUEST_LIST)
135 == -EINVAL);
136
137 /* RFC7844: option 101 (SD_DHCP_OPTION_NEW_TZDB_TIMEZONE) is not set in the
138 * default PRL when using Anonymize, */
139 assert_se(sd_dhcp_client_set_request_option(client, 101) == 0);
140 assert_se(sd_dhcp_client_set_request_option(client, 101) == -EEXIST);
141
142 sd_dhcp_client_unref(client);
143}
144
52efd56a 145static void test_checksum(void) {
39b7f596
PF
146 uint8_t buf[20] = {
147 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
148 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
149 0xff, 0xff, 0xff, 0xff
150 };
151
ede286f9
PF
152 if (verbose)
153 printf("* %s\n", __FUNCTION__);
154
0bbc2c1f 155 assert_se(dhcp_packet_checksum((uint8_t*)&buf, 20) == be16toh(0x78ae));
39b7f596
PF
156}
157
43fc0955
TH
158static void test_dhcp_identifier_set_iaid(void) {
159 uint32_t iaid;
160 int ifindex;
161
162 for (;;) {
163 char ifname[IFNAMSIZ];
164
165 /* try to find an ifindex which does not exist. I causes dhcp_identifier_set_iaid()
166 * to hash the MAC address. */
167 pseudo_random_bytes(&ifindex, sizeof(ifindex));
168 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
169 break;
170 }
171
172 assert_se(dhcp_identifier_set_iaid(ifindex, mac_addr, sizeof(mac_addr), &iaid) >= 0);
173
174 /* we expect, that the MAC address was hashed. Note that the value is in native
175 * endianness. */
176 assert_se(iaid == 0x8dde4ba8u);
177}
178
52efd56a 179static int check_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
d790d3f1 180 switch(code) {
22805d92 181 case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
5bac5235
TG
182 {
183 uint32_t iaid;
184 struct duid duid;
185 size_t duid_len;
186
187 assert_se(dhcp_identifier_set_duid_en(&duid, &duid_len) >= 0);
188 assert_se(dhcp_identifier_set_iaid(42, mac_addr, ETH_ALEN, &iaid) >= 0);
189
190 assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid_len);
191 assert_se(len == 19);
e4735228 192 assert_se(((uint8_t*) option)[0] == 0xff);
5bac5235 193
e4735228
LP
194 assert_se(memcmp((uint8_t*) option + 1, &iaid, sizeof(iaid)) == 0);
195 assert_se(memcmp((uint8_t*) option + 5, &duid, duid_len) == 0);
d790d3f1 196 break;
5bac5235 197 }
d790d3f1
PF
198
199 default:
200 break;
201 }
202
290c7324
PF
203 return 0;
204}
205
52efd56a 206int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const void *packet, size_t len) {
290c7324 207 size_t size;
f937d3d6 208 _cleanup_free_ DHCPPacket *discover;
290c7324 209 uint16_t ip_check, udp_check;
290c7324 210
12e0f830
TG
211 assert_se(s >= 0);
212 assert_se(packet);
290c7324 213
d47e1de4 214 size = sizeof(DHCPPacket);
12e0f830 215 assert_se(len > size);
290c7324
PF
216
217 discover = memdup(packet, len);
218
12e0f830
TG
219 assert_se(discover->ip.ttl == IPDEFTTL);
220 assert_se(discover->ip.protocol == IPPROTO_UDP);
221 assert_se(discover->ip.saddr == INADDR_ANY);
222 assert_se(discover->ip.daddr == INADDR_BROADCAST);
223 assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
224 assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
290c7324
PF
225
226 ip_check = discover->ip.check;
227
228 discover->ip.ttl = 0;
229 discover->ip.check = discover->udp.len;
230
0bbc2c1f 231 udp_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip.ttl, len - 8);
12e0f830 232 assert_se(udp_check == 0xffff);
290c7324
PF
233
234 discover->ip.ttl = IPDEFTTL;
235 discover->ip.check = ip_check;
236
0bbc2c1f 237 ip_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip, sizeof(discover->ip));
12e0f830 238 assert_se(ip_check == 0xffff);
290c7324 239
12e0f830 240 assert_se(discover->dhcp.xid);
5bac5235 241 assert_se(memcmp(discover->dhcp.chaddr, &mac_addr, ETH_ALEN) == 0);
6c8a0f07 242
290c7324
PF
243 size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
244
12e0f830 245 assert_se(callback_recv);
6c8a0f07 246 callback_recv(size, &discover->dhcp);
290c7324
PF
247
248 return 575;
249}
250
52efd56a
LP
251int dhcp_network_bind_raw_socket(
252 int index,
253 union sockaddr_union *link,
254 uint32_t id,
255 const uint8_t *addr, size_t addr_len,
9faed222 256 uint16_t arp_type, uint16_t port) {
52efd56a 257
3e29b889 258 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
8c00042c
PF
259 return -errno;
260
261 return test_fd[0];
262}
263
3e7b9f76 264int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
fe0885f8
ZJS
265 int fd;
266
3e29b889 267 fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
fe0885f8
ZJS
268 if (fd < 0)
269 return -errno;
270
271 return fd;
234fc2df
PF
272}
273
52efd56a 274int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, const void *packet, size_t len) {
234fc2df
PF
275 return 0;
276}
277
52efd56a 278static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) {
6c8a0f07
PF
279 int res;
280
f693e9b3 281 res = dhcp_option_parse(dhcp, size, check_options, NULL, NULL);
12e0f830 282 assert_se(res == DHCP_DISCOVER);
6c8a0f07
PF
283
284 if (verbose)
285 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
286
287 return 0;
288}
289
52efd56a 290static void test_discover_message(sd_event *e) {
290c7324 291 sd_dhcp_client *client;
b25ef18b 292 int res, r;
290c7324 293
ede286f9
PF
294 if (verbose)
295 printf("* %s\n", __FUNCTION__);
296
db3d2358 297 r = sd_dhcp_client_new(&client, false);
12e0f830
TG
298 assert_se(r >= 0);
299 assert_se(client);
290c7324 300
b25ef18b 301 r = sd_dhcp_client_attach_event(client, e, 0);
12e0f830 302 assert_se(r >= 0);
b25ef18b 303
2f8e7633 304 assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
5bac5235 305 assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
290c7324 306
12e0f830 307 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
290c7324 308
6c8a0f07
PF
309 callback_recv = test_discover_message_verify;
310
290c7324
PF
311 res = sd_dhcp_client_start(client);
312
4c701096 313 assert_se(IN_SET(res, 0, -EINPROGRESS));
8c00042c 314
6c8a0f07
PF
315 sd_event_run(e, (uint64_t) -1);
316
317 sd_dhcp_client_stop(client);
e5b04c8d 318 sd_dhcp_client_unref(client);
6c8a0f07 319
2afa65c3 320 test_fd[1] = safe_close(test_fd[1]);
6c8a0f07
PF
321
322 callback_recv = NULL;
290c7324
PF
323}
324
234ed3eb
PF
325static uint8_t test_addr_acq_offer[] = {
326 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
327 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
328 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
329 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
330 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
331 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
332 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
333 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
336 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
348 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
349 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
354 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
360 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
361 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
362 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
363 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
364 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
365 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
366 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
367};
368
369static uint8_t test_addr_acq_ack[] = {
370 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
371 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
372 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
373 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
374 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
375 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
376 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
377 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
378 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
379 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
380 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
381 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
382 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
383 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
384 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
388 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
389 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
390 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
391 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
392 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
393 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
395 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
396 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
397 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
398 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
399 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
400 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
401 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
402 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
403 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
404 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
d47e1de4 405 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
234ed3eb
PF
406 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
407 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
408 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
409 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
410 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
411};
412
413static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
c4acff12 414 void *userdata) {
234ed3eb
PF
415 sd_event *e = userdata;
416 sd_dhcp_lease *lease;
417 struct in_addr addr;
418
12e0f830 419 assert_se(client);
03748142 420 assert_se(event == SD_DHCP_CLIENT_EVENT_IP_ACQUIRE);
234ed3eb 421
12e0f830
TG
422 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
423 assert_se(lease);
234ed3eb 424
12e0f830
TG
425 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
426 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
234ed3eb
PF
427 sizeof(addr.s_addr)) == 0);
428
12e0f830
TG
429 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
430 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
234ed3eb
PF
431 sizeof(addr.s_addr)) == 0);
432
12e0f830
TG
433 assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
434 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
234ed3eb
PF
435 sizeof(addr.s_addr)) == 0);
436
437 if (verbose)
438 printf(" DHCP address acquired\n");
439
440 sd_event_exit(e, 0);
441}
442
c4acff12 443static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
234ed3eb 444 uint16_t udp_check = 0;
d790d3f1 445 uint8_t *msg_bytes = (uint8_t *)request;
234ed3eb
PF
446 int res;
447
f693e9b3 448 res = dhcp_option_parse(request, size, check_options, NULL, NULL);
12e0f830
TG
449 assert_se(res == DHCP_REQUEST);
450 assert_se(xid == request->xid);
234ed3eb 451
22805d92 452 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
d790d3f1 453
234ed3eb
PF
454 if (verbose)
455 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
456
457 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
458 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
5bac5235 459 memcpy(&test_addr_acq_ack[56], &mac_addr, ETHER_ADDR_LEN);
234ed3eb
PF
460
461 callback_recv = NULL;
462
463 res = write(test_fd[1], test_addr_acq_ack,
464 sizeof(test_addr_acq_ack));
12e0f830 465 assert_se(res == sizeof(test_addr_acq_ack));
234ed3eb
PF
466
467 if (verbose)
468 printf(" send DHCP Ack\n");
469
470 return 0;
471};
472
c4acff12 473static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
234ed3eb 474 uint16_t udp_check = 0;
d790d3f1 475 uint8_t *msg_bytes = (uint8_t *)discover;
234ed3eb
PF
476 int res;
477
f693e9b3 478 res = dhcp_option_parse(discover, size, check_options, NULL, NULL);
12e0f830 479 assert_se(res == DHCP_DISCOVER);
234ed3eb 480
22805d92 481 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
d790d3f1 482
234ed3eb
PF
483 xid = discover->xid;
484
485 if (verbose)
486 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
487
488 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
489 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
5bac5235 490 memcpy(&test_addr_acq_offer[56], &mac_addr, ETHER_ADDR_LEN);
234ed3eb
PF
491
492 callback_recv = test_addr_acq_recv_request;
493
494 res = write(test_fd[1], test_addr_acq_offer,
495 sizeof(test_addr_acq_offer));
12e0f830 496 assert_se(res == sizeof(test_addr_acq_offer));
234ed3eb
PF
497
498 if (verbose)
c4acff12 499 printf(" sent DHCP Offer\n");
234ed3eb
PF
500
501 return 0;
502}
503
c4acff12 504static void test_addr_acq(sd_event *e) {
fa94c34b 505 usec_t time_now = now(clock_boottime_or_monotonic());
234ed3eb
PF
506 sd_dhcp_client *client;
507 int res, r;
508
509 if (verbose)
510 printf("* %s\n", __FUNCTION__);
511
db3d2358 512 r = sd_dhcp_client_new(&client, false);
12e0f830
TG
513 assert_se(r >= 0);
514 assert_se(client);
234ed3eb
PF
515
516 r = sd_dhcp_client_attach_event(client, e, 0);
12e0f830 517 assert_se(r >= 0);
234ed3eb 518
2f8e7633 519 assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
5bac5235 520 assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
234ed3eb 521
afa3509a 522 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
234ed3eb
PF
523
524 callback_recv = test_addr_acq_recv_discover;
525
6a0f1f6d 526 assert_se(sd_event_add_time(e, &test_hangcheck,
fa94c34b 527 clock_boottime_or_monotonic(),
6a0f1f6d
LP
528 time_now + 2 * USEC_PER_SEC, 0,
529 test_dhcp_hangcheck, NULL) >= 0);
8fc8e3ab 530
234ed3eb 531 res = sd_dhcp_client_start(client);
4c701096 532 assert_se(IN_SET(res, 0, -EINPROGRESS));
234ed3eb 533
fc292b5f 534 assert_se(sd_event_loop(e) >= 0);
234ed3eb 535
8fc8e3ab
PF
536 test_hangcheck = sd_event_source_unref(test_hangcheck);
537
fc292b5f
TG
538 assert_se(sd_dhcp_client_set_callback(client, NULL, NULL) >= 0);
539 assert_se(sd_dhcp_client_stop(client) >= 0);
e5b04c8d 540 sd_dhcp_client_unref(client);
234ed3eb 541
2afa65c3 542 test_fd[1] = safe_close(test_fd[1]);
234ed3eb
PF
543
544 callback_recv = NULL;
545 xid = 0;
546}
547
c4acff12 548int main(int argc, char *argv[]) {
4afd3348 549 _cleanup_(sd_event_unrefp) sd_event *e;
6e00a806 550
6d7c4033 551 test_setup_logging(LOG_DEBUG);
d3d8ac2f 552
12e0f830 553 assert_se(sd_event_new(&e) >= 0);
d3d8ac2f
PF
554
555 test_request_basic(e);
dbb35f1f 556 test_request_anonymize(e);
39b7f596 557 test_checksum();
43fc0955 558 test_dhcp_identifier_set_iaid();
be391925 559
d3d8ac2f 560 test_discover_message(e);
234ed3eb 561 test_addr_acq(e);
290c7324 562
d18cb393 563#if VALGRIND
374c22b3
ZJS
564 /* Make sure the async_close thread has finished.
565 * valgrind would report some of the phread_* structures
566 * as not cleaned up properly. */
567 sleep(1);
568#endif
569
be391925
PF
570 return 0;
571}