]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-dhcp-client.c
Merge pull request #27483 from yuwata/udev-id-path-usb-revision
[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 #if HAVE_VALGRIND_VALGRIND_H
13 # include <valgrind/valgrind.h>
14 #endif
15
16 #include "sd-dhcp-client.h"
17 #include "sd-event.h"
18
19 #include "alloc-util.h"
20 #include "dhcp-identifier.h"
21 #include "dhcp-internal.h"
22 #include "dhcp-protocol.h"
23 #include "ether-addr-util.h"
24 #include "fd-util.h"
25 #include "random-util.h"
26 #include "tests.h"
27
28 static struct hw_addr_data hw_addr = {
29 .length = ETH_ALEN,
30 .ether = {{ 'A', 'B', 'C', '1', '2', '3' }},
31 }, bcast_addr = {
32 .length = ETH_ALEN,
33 .ether = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }},
34 };
35 typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
36
37 static bool verbose = true;
38 static int test_fd[2];
39 static test_callback_recv_t callback_recv;
40 static be32_t xid;
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", __func__);
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", __func__);
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_NAME_SERVER) == 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", __func__);
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
149 assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy = */ true, &iaid_legacy) >= 0);
150 assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy = */ false, &iaid) >= 0);
151
152 /* we expect, that the MAC address was hashed. The legacy value is in native
153 * endianness. */
154 assert_se(iaid_legacy == 0x8dde4ba8u);
155 assert_se(iaid == htole32(0x8dde4ba8u));
156 #if __BYTE_ORDER == __LITTLE_ENDIAN
157 assert_se(iaid == iaid_legacy);
158 #else
159 assert_se(iaid == bswap_32(iaid_legacy));
160 #endif
161 }
162
163 static int check_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
164 switch (code) {
165 case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
166 {
167 uint32_t iaid;
168 struct duid duid;
169 size_t duid_len;
170
171 assert_se(dhcp_identifier_set_duid_en(/* test_mode = */ true, &duid, &duid_len) >= 0);
172 assert_se(dhcp_identifier_set_iaid(NULL, &hw_addr, /* legacy = */ true, &iaid) >= 0);
173
174 assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid_len);
175 assert_se(len == 19);
176 assert_se(((uint8_t*) option)[0] == 0xff);
177
178 assert_se(memcmp((uint8_t*) option + 1, &iaid, sizeof(iaid)) == 0);
179 assert_se(memcmp((uint8_t*) option + 5, &duid, duid_len) == 0);
180 break;
181 }
182
183 default:
184 break;
185 }
186
187 return 0;
188 }
189
190 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const void *packet, size_t len) {
191 size_t size;
192 _cleanup_free_ DHCPPacket *discover = NULL;
193 uint16_t ip_check, udp_check;
194
195 assert_se(s >= 0);
196 assert_se(packet);
197
198 size = sizeof(DHCPPacket);
199 assert_se(len > size);
200
201 discover = memdup(packet, len);
202
203 assert_se(discover->ip.ttl == IPDEFTTL);
204 assert_se(discover->ip.protocol == IPPROTO_UDP);
205 assert_se(discover->ip.saddr == INADDR_ANY);
206 assert_se(discover->ip.daddr == INADDR_BROADCAST);
207 assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
208 assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
209
210 ip_check = discover->ip.check;
211
212 discover->ip.ttl = 0;
213 discover->ip.check = discover->udp.len;
214
215 udp_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip.ttl, len - 8);
216 assert_se(udp_check == 0xffff);
217
218 discover->ip.ttl = IPDEFTTL;
219 discover->ip.check = ip_check;
220
221 ip_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip, sizeof(discover->ip));
222 assert_se(ip_check == 0xffff);
223
224 assert_se(discover->dhcp.xid);
225 assert_se(memcmp(discover->dhcp.chaddr, hw_addr.bytes, hw_addr.length) == 0);
226
227 size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
228
229 assert_se(callback_recv);
230 callback_recv(size, &discover->dhcp);
231
232 return 575;
233 }
234
235 int dhcp_network_bind_raw_socket(
236 int ifindex,
237 union sockaddr_union *link,
238 uint32_t id,
239 const struct hw_addr_data *_hw_addr,
240 const struct hw_addr_data *_bcast_addr,
241 uint16_t arp_type,
242 uint16_t port,
243 bool so_priority_set,
244 int so_priority) {
245
246 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
247 return -errno;
248
249 return test_fd[0];
250 }
251
252 int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
253 int fd;
254
255 fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
256 if (fd < 0)
257 return -errno;
258
259 return fd;
260 }
261
262 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, const void *packet, size_t len) {
263 return 0;
264 }
265
266 static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) {
267 int res;
268
269 res = dhcp_option_parse(dhcp, size, check_options, NULL, NULL);
270 assert_se(res == DHCP_DISCOVER);
271
272 if (verbose)
273 printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
274
275 return 0;
276 }
277
278 static void test_discover_message(sd_event *e) {
279 sd_dhcp_client *client;
280 int res, r;
281
282 if (verbose)
283 printf("* %s\n", __func__);
284
285 r = sd_dhcp_client_new(&client, false);
286 assert_se(r >= 0);
287 assert_se(client);
288
289 r = sd_dhcp_client_attach_event(client, e, 0);
290 assert_se(r >= 0);
291
292 assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
293 assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0);
294 dhcp_client_set_test_mode(client, true);
295
296 assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
297
298 callback_recv = test_discover_message_verify;
299
300 res = sd_dhcp_client_start(client);
301
302 assert_se(IN_SET(res, 0, -EINPROGRESS));
303
304 sd_event_run(e, UINT64_MAX);
305
306 sd_dhcp_client_stop(client);
307 sd_dhcp_client_unref(client);
308
309 test_fd[1] = safe_close(test_fd[1]);
310
311 callback_recv = NULL;
312 }
313
314 static uint8_t test_addr_acq_offer[] = {
315 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
316 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
317 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
318 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
319 0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
320 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
321 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
322 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 0x00, 0x00, 0x00, 0x00, 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x02, 0x36,
349 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
350 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
351 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
352 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
353 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
354 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356 };
357
358 static uint8_t test_addr_acq_ack[] = {
359 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
360 0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
361 0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
362 0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
363 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
364 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
365 0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
366 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
367 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
368 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
369 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
370 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
371 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
372 0x00, 0x00, 0x00, 0x00, 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 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36,
393 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
394 0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
395 0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
396 0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
397 0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
398 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
399 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
400 };
401
402 static int test_addr_acq_acquired(sd_dhcp_client *client, int event,
403 void *userdata) {
404 sd_event *e = userdata;
405 sd_dhcp_lease *lease;
406 struct in_addr addr;
407 const struct in_addr *addrs;
408
409 assert_se(client);
410 assert_se(IN_SET(event, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE, SD_DHCP_CLIENT_EVENT_SELECTING));
411
412 assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
413 assert_se(lease);
414
415 assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
416 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
417 sizeof(addr.s_addr)) == 0);
418
419 assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
420 assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
421 sizeof(addr.s_addr)) == 0);
422
423 assert_se(sd_dhcp_lease_get_router(lease, &addrs) == 1);
424 assert_se(memcmp(&addrs[0].s_addr, &test_addr_acq_ack[308],
425 sizeof(addrs[0].s_addr)) == 0);
426
427 if (verbose)
428 printf(" DHCP address acquired\n");
429
430 sd_event_exit(e, 0);
431
432 return 0;
433 }
434
435 static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
436 uint16_t udp_check = 0;
437 uint8_t *msg_bytes = (uint8_t *)request;
438 int res;
439
440 res = dhcp_option_parse(request, size, check_options, NULL, NULL);
441 assert_se(res == DHCP_REQUEST);
442 assert_se(xid == request->xid);
443
444 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
445
446 if (verbose)
447 printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
448
449 memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
450 memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
451 memcpy(&test_addr_acq_ack[56], hw_addr.bytes, hw_addr.length);
452
453 callback_recv = NULL;
454
455 res = write(test_fd[1], test_addr_acq_ack,
456 sizeof(test_addr_acq_ack));
457 assert_se(res == sizeof(test_addr_acq_ack));
458
459 if (verbose)
460 printf(" send DHCP Ack\n");
461
462 return 0;
463 };
464
465 static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
466 uint16_t udp_check = 0;
467 uint8_t *msg_bytes = (uint8_t *)discover;
468 int res;
469
470 res = dhcp_option_parse(discover, size, check_options, NULL, NULL);
471 assert_se(res == DHCP_DISCOVER);
472
473 assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END);
474
475 xid = discover->xid;
476
477 if (verbose)
478 printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
479
480 memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
481 memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
482 memcpy(&test_addr_acq_offer[56], hw_addr.bytes, hw_addr.length);
483
484 callback_recv = test_addr_acq_recv_request;
485
486 res = write(test_fd[1], test_addr_acq_offer,
487 sizeof(test_addr_acq_offer));
488 assert_se(res == sizeof(test_addr_acq_offer));
489
490 if (verbose)
491 printf(" sent DHCP Offer\n");
492
493 return 0;
494 }
495
496 static void test_addr_acq(sd_event *e) {
497 sd_dhcp_client *client;
498 int res, r;
499
500 if (verbose)
501 printf("* %s\n", __func__);
502
503 r = sd_dhcp_client_new(&client, false);
504 assert_se(r >= 0);
505 assert_se(client);
506
507 r = sd_dhcp_client_attach_event(client, e, 0);
508 assert_se(r >= 0);
509
510 assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0);
511 assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0);
512 dhcp_client_set_test_mode(client, true);
513
514 assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0);
515
516 callback_recv = test_addr_acq_recv_discover;
517
518 assert_se(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
519 2 * USEC_PER_SEC, 0,
520 NULL, INT_TO_PTR(-ETIMEDOUT)) >= 0);
521
522 res = sd_dhcp_client_start(client);
523 assert_se(IN_SET(res, 0, -EINPROGRESS));
524
525 assert_se(sd_event_loop(e) >= 0);
526
527 assert_se(sd_dhcp_client_set_callback(client, NULL, NULL) >= 0);
528 assert_se(sd_dhcp_client_stop(client) >= 0);
529 sd_dhcp_client_unref(client);
530
531 test_fd[1] = safe_close(test_fd[1]);
532
533 callback_recv = NULL;
534 xid = 0;
535 }
536
537 int main(int argc, char *argv[]) {
538 _cleanup_(sd_event_unrefp) sd_event *e;
539
540 test_setup_logging(LOG_DEBUG);
541
542 assert_se(sd_event_new(&e) >= 0);
543
544 test_request_basic(e);
545 test_request_anonymize(e);
546 test_checksum();
547 test_dhcp_identifier_set_iaid();
548
549 test_discover_message(e);
550 test_addr_acq(e);
551
552 #if HAVE_VALGRIND_VALGRIND_H
553 /* Make sure the async_close thread has finished.
554 * valgrind would report some of the phread_* structures
555 * as not cleaned up properly. */
556 if (RUNNING_ON_VALGRIND)
557 sleep(1);
558 #endif
559
560 return 0;
561 }