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