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