1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright (C) 2014 Intel Corporation. All rights reserved.
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <net/ethernet.h>
24 #include <sys/socket.h>
25 #include <sys/types.h>
28 #include "sd-dhcp6-client.h"
31 #include "dhcp6-internal.h"
32 #include "dhcp6-lease-internal.h"
33 #include "dhcp6-protocol.h"
36 #include "socket-util.h"
39 static struct ether_addr mac_addr
= {
40 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
43 static bool verbose
= true;
45 static sd_event_source
*hangcheck
;
46 static int test_dhcp_fd
[2];
47 static int test_index
= 42;
48 static int test_client_message_num
;
49 static be32_t test_iaid
= 0;
50 static uint8_t test_duid
[14] = { };
52 static int test_client_basic(sd_event
*e
) {
53 sd_dhcp6_client
*client
;
56 printf("* %s\n", __FUNCTION__
);
58 assert_se(sd_dhcp6_client_new(&client
) >= 0);
61 assert_se(sd_dhcp6_client_attach_event(client
, e
, 0) >= 0);
63 assert_se(sd_dhcp6_client_set_ifindex(client
, 15) == 0);
64 assert_se(sd_dhcp6_client_set_ifindex(client
, -42) == -EINVAL
);
65 assert_se(sd_dhcp6_client_set_ifindex(client
, -1) == 0);
66 assert_se(sd_dhcp6_client_set_ifindex(client
, 42) >= 0);
68 assert_se(sd_dhcp6_client_set_mac(client
, (const uint8_t *) &mac_addr
,
72 assert_se(sd_dhcp6_client_set_fqdn(client
, "host") == 1);
73 assert_se(sd_dhcp6_client_set_fqdn(client
, "host.domain") == 1);
74 assert_se(sd_dhcp6_client_set_fqdn(client
, NULL
) == 1);
75 assert_se(sd_dhcp6_client_set_fqdn(client
, "~host") == -EINVAL
);
76 assert_se(sd_dhcp6_client_set_fqdn(client
, "~host.domain") == -EINVAL
);
78 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_CLIENTID
) == -EINVAL
);
79 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVERS
) == -EEXIST
);
80 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_NTP_SERVER
) == -EEXIST
);
81 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_SNTP_SERVERS
) == -EEXIST
);
82 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DOMAIN_LIST
) == -EEXIST
);
83 assert_se(sd_dhcp6_client_set_request_option(client
, 10) == -EINVAL
);
85 assert_se(sd_dhcp6_client_set_callback(client
, NULL
, NULL
) >= 0);
87 assert_se(sd_dhcp6_client_detach_event(client
) >= 0);
88 assert_se(!sd_dhcp6_client_unref(client
));
93 static int test_option(sd_event
*e
) {
96 0x00, SD_DHCP6_OPTION_ORO
, 0x00, 0x07,
97 'A', 'B', 'C', 'D', 'E', 'F', 'G',
98 0x00, SD_DHCP6_OPTION_VENDOR_CLASS
, 0x00, 0x09,
99 '1', '2', '3', '4', '5', '6', '7', '8', '9',
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111 uint8_t *optval
, *buf
, *out
;
112 size_t zero
= 0, pos
= 3;
113 size_t buflen
= sizeof(packet
), outlen
= sizeof(result
);
116 printf("* %s\n", __FUNCTION__
);
118 assert_se(buflen
== outlen
);
120 assert_se(dhcp6_option_parse(&buf
, &zero
, &optcode
, &optlen
,
121 &optval
) == -ENOMSG
);
128 assert_se(dhcp6_option_parse(&buf
, &buflen
, &optcode
, &optlen
,
131 assert_se(buf
== &packet
[pos
]);
132 assert_se(optcode
== SD_DHCP6_OPTION_ORO
);
133 assert_se(optlen
== 7);
134 assert_se(buflen
+ pos
== sizeof(packet
));
136 assert_se(dhcp6_option_append(&out
, &outlen
, optcode
, optlen
,
138 assert_se(out
== &result
[pos
]);
139 assert_se(*out
== 0x00);
141 assert_se(dhcp6_option_parse(&buf
, &buflen
, &optcode
, &optlen
,
144 assert_se(buf
== &packet
[pos
]);
145 assert_se(optcode
== SD_DHCP6_OPTION_VENDOR_CLASS
);
146 assert_se(optlen
== 9);
147 assert_se(buflen
+ pos
== sizeof(packet
));
149 assert_se(dhcp6_option_append(&out
, &outlen
, optcode
, optlen
,
151 assert_se(out
== &result
[pos
]);
152 assert_se(*out
== 'B');
154 assert_se(memcmp(packet
, result
, sizeof(packet
)) == 0);
159 static uint8_t msg_advertise
[198] = {
160 0x02, 0x0f, 0xb4, 0xe5, 0x00, 0x01, 0x00, 0x0e,
161 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b, 0xf3, 0x30,
162 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x03,
163 0x00, 0x5e, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x00,
164 0x00, 0x50, 0x00, 0x00, 0x00, 0x78, 0x00, 0x05,
165 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
166 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, 0x09, 0x3c,
167 0x55, 0xad, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00,
168 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x32, 0x00, 0x00,
169 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x28,
170 0x65, 0x73, 0x29, 0x20, 0x72, 0x65, 0x6e, 0x65,
171 0x77, 0x65, 0x64, 0x2e, 0x20, 0x47, 0x72, 0x65,
172 0x65, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x66,
173 0x72, 0x6f, 0x6d, 0x20, 0x70, 0x6c, 0x61, 0x6e,
174 0x65, 0x74, 0x20, 0x45, 0x61, 0x72, 0x74, 0x68,
175 0x00, 0x17, 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8,
176 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00,
177 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b,
178 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
179 0x72, 0x61, 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20,
180 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00,
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
182 0x02, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x19,
183 0x40, 0x5c, 0x53, 0x78, 0x2b, 0xcb, 0xb3, 0x6d,
184 0x53, 0x00, 0x07, 0x00, 0x01, 0x00
187 static uint8_t msg_reply
[173] = {
188 0x07, 0xf7, 0x4e, 0x57, 0x00, 0x02, 0x00, 0x0e,
189 0x00, 0x01, 0x00, 0x01, 0x19, 0x40, 0x5c, 0x53,
190 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, 0x00, 0x01,
191 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b,
192 0xf3, 0x30, 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d,
193 0x00, 0x03, 0x00, 0x4a, 0x0e, 0xcf, 0xa3, 0x7d,
194 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x78,
195 0x00, 0x05, 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8,
196 0xde, 0xad, 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3,
197 0x09, 0x3c, 0x55, 0xad, 0x00, 0x00, 0x00, 0x96,
198 0x00, 0x00, 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x1e,
199 0x00, 0x00, 0x41, 0x6c, 0x6c, 0x20, 0x61, 0x64,
200 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20,
201 0x77, 0x65, 0x72, 0x65, 0x20, 0x61, 0x73, 0x73,
202 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2e, 0x00, 0x17,
203 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
204 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b, 0x03, 0x6c,
206 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, 0x72, 0x61,
207 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20, 0x01, 0x0d,
208 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00,
209 0x00, 0x00, 0x00, 0x00, 0x01
212 static uint8_t fqdn_wire
[16] = {
213 0x04, 'h', 'o', 's', 't', 0x03, 'l', 'a', 'b',
214 0x05, 'i', 'n', 't', 'r', 'a', 0x00
217 static int test_advertise_option(sd_event
*e
) {
218 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
219 DHCP6Message
*advertise
= (DHCP6Message
*)msg_advertise
;
220 uint8_t *optval
, *opt
= msg_advertise
+ sizeof(DHCP6Message
);
222 size_t optlen
, len
= sizeof(msg_advertise
) - sizeof(DHCP6Message
);
224 uint8_t preference
= 255;
225 struct in6_addr addr
;
226 uint32_t lt_pref
, lt_valid
;
228 bool opt_clientid
= false;
229 struct in6_addr
*addrs
;
233 printf("* %s\n", __FUNCTION__
);
235 assert_se(dhcp6_lease_new(&lease
) >= 0);
237 assert_se(advertise
->type
== DHCP6_ADVERTISE
);
238 assert_se((be32toh(advertise
->transaction_id
) & 0x00ffffff) ==
241 while ((r
= dhcp6_option_parse(&opt
, &len
, &optcode
, &optlen
,
245 case SD_DHCP6_OPTION_CLIENTID
:
246 assert_se(optlen
== 14);
251 case SD_DHCP6_OPTION_IA_NA
:
252 assert_se(optlen
== 94);
253 assert_se(!memcmp(optval
, &msg_advertise
[26], optlen
));
255 val
= htobe32(0x0ecfa37d);
256 assert_se(!memcmp(optval
, &val
, sizeof(val
)));
259 assert_se(!memcmp(optval
+ 4, &val
, sizeof(val
)));
262 assert_se(!memcmp(optval
+ 8, &val
, sizeof(val
)));
264 assert_se(dhcp6_option_parse_ia(&optval
, &optlen
,
270 case SD_DHCP6_OPTION_SERVERID
:
271 assert_se(optlen
== 14);
272 assert_se(!memcmp(optval
, &msg_advertise
[179], optlen
));
274 assert_se(dhcp6_lease_set_serverid(lease
, optval
,
278 case SD_DHCP6_OPTION_PREFERENCE
:
279 assert_se(optlen
== 1);
282 assert_se(dhcp6_lease_set_preference(lease
,
286 case SD_DHCP6_OPTION_ELAPSED_TIME
:
287 assert_se(optlen
== 2);
291 case SD_DHCP6_OPTION_DNS_SERVERS
:
292 assert_se(optlen
== 16);
293 assert_se(dhcp6_lease_set_dns(lease
, optval
,
297 case SD_DHCP6_OPTION_DOMAIN_LIST
:
298 assert_se(optlen
== 11);
299 assert_se(dhcp6_lease_set_domains(lease
, optval
,
303 case SD_DHCP6_OPTION_SNTP_SERVERS
:
304 assert_se(optlen
== 16);
305 assert_se(dhcp6_lease_set_sntp(lease
, optval
,
315 assert_se(r
== -ENOMSG
);
317 assert_se(opt_clientid
);
319 sd_dhcp6_lease_reset_address_iter(lease
);
320 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
322 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
323 assert_se(lt_pref
== 150);
324 assert_se(lt_valid
== 180);
325 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
326 <_valid
) == -ENOMSG
);
328 sd_dhcp6_lease_reset_address_iter(lease
);
329 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
331 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
332 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
333 <_valid
) == -ENOMSG
);
334 sd_dhcp6_lease_reset_address_iter(lease
);
335 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
337 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
338 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
339 <_valid
) == -ENOMSG
);
341 assert_se(dhcp6_lease_get_serverid(lease
, &opt
, &len
) >= 0);
342 assert_se(len
== 14);
343 assert_se(!memcmp(opt
, &msg_advertise
[179], len
));
345 assert_se(dhcp6_lease_get_preference(lease
, &preference
) >= 0);
346 assert_se(preference
== 0);
348 r
= sd_dhcp6_lease_get_dns(lease
, &addrs
);
350 assert_se(!memcmp(addrs
, &msg_advertise
[124], r
* 16));
352 r
= sd_dhcp6_lease_get_domains(lease
, &domains
);
354 assert_se(!strcmp("lab.intra", domains
[0]));
355 assert_se(domains
[1] == NULL
);
357 r
= sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
);
359 assert_se(!memcmp(addrs
, &msg_advertise
[159], r
* 16));
364 static int test_hangcheck(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
365 assert_not_reached("Test case should have completed in 2 seconds");
370 static void test_client_solicit_cb(sd_dhcp6_client
*client
, int event
,
372 sd_event
*e
= userdata
;
373 sd_dhcp6_lease
*lease
;
374 struct in6_addr
*addrs
;
378 assert_se(event
== SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
);
380 assert_se(sd_dhcp6_client_get_lease(client
, &lease
) >= 0);
382 assert_se(sd_dhcp6_lease_get_domains(lease
, &domains
) == 1);
383 assert_se(!strcmp("lab.intra", domains
[0]));
384 assert_se(domains
[1] == NULL
);
386 assert_se(sd_dhcp6_lease_get_dns(lease
, &addrs
) == 1);
387 assert_se(!memcmp(addrs
, &msg_advertise
[124], 16));
389 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
) == 1);
390 assert_se(!memcmp(addrs
, &msg_advertise
[159], 16));
392 assert_se(sd_dhcp6_client_set_request_option(client
, SD_DHCP6_OPTION_DNS_SERVERS
) == -EBUSY
);
395 printf(" got DHCPv6 event %d\n", event
);
400 static int test_client_send_reply(DHCP6Message
*request
) {
403 reply
.transaction_id
= request
->transaction_id
;
404 reply
.type
= DHCP6_REPLY
;
406 memcpy(msg_reply
, &reply
.transaction_id
, 4);
408 memcpy(&msg_reply
[26], test_duid
, sizeof(test_duid
));
410 memcpy(&msg_reply
[44], &test_iaid
, sizeof(test_iaid
));
412 assert_se(write(test_dhcp_fd
[1], msg_reply
, sizeof(msg_reply
))
413 == sizeof(msg_reply
));
418 static int test_client_verify_request(DHCP6Message
*request
, uint8_t *option
,
420 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
424 bool found_clientid
= false, found_iana
= false, found_serverid
= false,
425 found_elapsed_time
= false, found_fqdn
= false;
427 struct in6_addr addr
;
429 uint32_t lt_pref
, lt_valid
;
431 assert_se(request
->type
== DHCP6_REQUEST
);
433 assert_se(dhcp6_lease_new(&lease
) >= 0);
435 while ((r
= dhcp6_option_parse(&option
, &len
,
436 &optcode
, &optlen
, &optval
)) >= 0) {
438 case SD_DHCP6_OPTION_CLIENTID
:
439 assert_se(!found_clientid
);
440 found_clientid
= true;
442 assert_se(!memcmp(optval
, &test_duid
,
447 case SD_DHCP6_OPTION_IA_NA
:
448 assert_se(!found_iana
);
452 assert_se(optlen
== 40);
453 assert_se(!memcmp(optval
, &test_iaid
, sizeof(test_iaid
)));
456 assert_se(!memcmp(optval
+ 4, &val
, sizeof(val
)));
459 assert_se(!memcmp(optval
+ 8, &val
, sizeof(val
)));
461 assert_se(!dhcp6_option_parse_ia(&optval
, &optlen
,
462 optcode
, &lease
->ia
));
466 case SD_DHCP6_OPTION_SERVERID
:
467 assert_se(!found_serverid
);
468 found_serverid
= true;
470 assert_se(optlen
== 14);
471 assert_se(!memcmp(&msg_advertise
[179], optval
, optlen
));
475 case SD_DHCP6_OPTION_ELAPSED_TIME
:
476 assert_se(!found_elapsed_time
);
477 found_elapsed_time
= true;
479 assert_se(optlen
== 2);
482 case SD_DHCP6_OPTION_FQDN
:
483 assert_se(!found_fqdn
);
486 assert_se(optlen
== 17);
488 assert_se(optval
[0] == 0x01);
489 assert_se(!memcmp(optval
+ 1, fqdn_wire
, sizeof(fqdn_wire
)));
494 assert_se(r
== -ENOMSG
);
495 assert_se(found_clientid
&& found_iana
&& found_serverid
&&
498 sd_dhcp6_lease_reset_address_iter(lease
);
499 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
501 assert_se(!memcmp(&addr
, &msg_advertise
[42], sizeof(addr
)));
502 assert_se(lt_pref
== 150);
503 assert_se(lt_valid
== 180);
505 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
506 <_valid
) == -ENOMSG
);
511 static int test_client_send_advertise(DHCP6Message
*solicit
) {
512 DHCP6Message advertise
;
514 advertise
.transaction_id
= solicit
->transaction_id
;
515 advertise
.type
= DHCP6_ADVERTISE
;
517 memcpy(msg_advertise
, &advertise
.transaction_id
, 4);
519 memcpy(&msg_advertise
[8], test_duid
, sizeof(test_duid
));
521 memcpy(&msg_advertise
[26], &test_iaid
, sizeof(test_iaid
));
523 assert_se(write(test_dhcp_fd
[1], msg_advertise
, sizeof(msg_advertise
))
524 == sizeof(msg_advertise
));
529 static int test_client_verify_solicit(DHCP6Message
*solicit
, uint8_t *option
,
534 bool found_clientid
= false, found_iana
= false,
535 found_elapsed_time
= false, found_fqdn
= false;
538 assert_se(solicit
->type
== DHCP6_SOLICIT
);
540 while ((r
= dhcp6_option_parse(&option
, &len
,
541 &optcode
, &optlen
, &optval
)) >= 0) {
543 case SD_DHCP6_OPTION_CLIENTID
:
544 assert_se(!found_clientid
);
545 found_clientid
= true;
547 assert_se(optlen
== sizeof(test_duid
));
548 memcpy(&test_duid
, optval
, sizeof(test_duid
));
552 case SD_DHCP6_OPTION_IA_NA
:
553 assert_se(!found_iana
);
556 assert_se(optlen
== 12);
558 memcpy(&test_iaid
, optval
, sizeof(test_iaid
));
562 case SD_DHCP6_OPTION_ELAPSED_TIME
:
563 assert_se(!found_elapsed_time
);
564 found_elapsed_time
= true;
566 assert_se(optlen
== 2);
570 case SD_DHCP6_OPTION_FQDN
:
571 assert_se(!found_fqdn
);
574 assert_se(optlen
== 17);
576 assert_se(optval
[0] == 0x01);
577 assert_se(!memcmp(optval
+ 1, fqdn_wire
, sizeof(fqdn_wire
)));
583 assert_se(r
== -ENOMSG
);
584 assert_se(found_clientid
&& found_iana
&& found_elapsed_time
);
589 static void test_client_information_cb(sd_dhcp6_client
*client
, int event
,
591 sd_event
*e
= userdata
;
592 sd_dhcp6_lease
*lease
;
593 struct in6_addr
*addrs
;
594 struct in6_addr address
= { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
598 assert_se(event
== SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
);
600 assert_se(sd_dhcp6_client_get_lease(client
, &lease
) >= 0);
602 assert_se(sd_dhcp6_lease_get_domains(lease
, &domains
) == 1);
603 assert_se(!strcmp("lab.intra", domains
[0]));
604 assert_se(domains
[1] == NULL
);
606 assert_se(sd_dhcp6_lease_get_dns(lease
, &addrs
) == 1);
607 assert_se(!memcmp(addrs
, &msg_advertise
[124], 16));
609 assert_se(sd_dhcp6_lease_get_ntp_addrs(lease
, &addrs
) == 1);
610 assert_se(!memcmp(addrs
, &msg_advertise
[159], 16));
613 printf(" got DHCPv6 event %d\n", event
);
615 assert_se(sd_dhcp6_client_set_information_request(client
, false) == -EBUSY
);
616 assert_se(sd_dhcp6_client_set_callback(client
, NULL
, e
) >= 0);
617 assert_se(sd_dhcp6_client_stop(client
) >= 0);
618 assert_se(sd_dhcp6_client_set_information_request(client
, false) >= 0);
620 assert_se(sd_dhcp6_client_set_callback(client
,
621 test_client_solicit_cb
, e
) >= 0);
623 assert_se(sd_dhcp6_client_set_local_address(client
, &address
) >= 0);
625 assert_se(sd_dhcp6_client_start(client
) >= 0);
628 static int test_client_verify_information_request(DHCP6Message
*information_request
,
629 uint8_t *option
, size_t len
) {
631 _cleanup_(sd_dhcp6_lease_unrefp
) sd_dhcp6_lease
*lease
= NULL
;
635 bool found_clientid
= false, found_elapsed_time
= false;
637 struct in6_addr addr
;
638 uint32_t lt_pref
, lt_valid
;
640 assert_se(information_request
->type
== DHCP6_INFORMATION_REQUEST
);
642 assert_se(dhcp6_lease_new(&lease
) >= 0);
644 while ((r
= dhcp6_option_parse(&option
, &len
,
645 &optcode
, &optlen
, &optval
)) >= 0) {
647 case SD_DHCP6_OPTION_CLIENTID
:
648 assert_se(!found_clientid
);
649 found_clientid
= true;
651 assert_se(optlen
== sizeof(test_duid
));
652 memcpy(&test_duid
, optval
, sizeof(test_duid
));
656 case SD_DHCP6_OPTION_IA_NA
:
657 assert_not_reached("IA TA option must not be present");
661 case SD_DHCP6_OPTION_SERVERID
:
662 assert_not_reached("Server ID option must not be present");
666 case SD_DHCP6_OPTION_ELAPSED_TIME
:
667 assert_se(!found_elapsed_time
);
668 found_elapsed_time
= true;
670 assert_se(optlen
== 2);
676 assert_se(r
== -ENOMSG
);
677 assert_se(found_clientid
&& found_elapsed_time
);
679 sd_dhcp6_lease_reset_address_iter(lease
);
681 assert_se(sd_dhcp6_lease_get_address(lease
, &addr
, <_pref
,
682 <_valid
) == -ENOMSG
);
687 int dhcp6_network_send_udp_socket(int s
, struct in6_addr
*server_address
,
688 const void *packet
, size_t len
) {
689 struct in6_addr mcast
=
690 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT
;
691 DHCP6Message
*message
;
694 assert_se(s
== test_dhcp_fd
[0]);
695 assert_se(server_address
);
697 assert_se(len
> sizeof(DHCP6Message
) + 4);
699 assert_se(IN6_ARE_ADDR_EQUAL(server_address
, &mcast
));
701 message
= (DHCP6Message
*)packet
;
702 option
= (uint8_t *)(message
+ 1);
703 len
-= sizeof(DHCP6Message
);
705 assert_se(message
->transaction_id
& 0x00ffffff);
707 if (test_client_message_num
== 0) {
708 test_client_verify_information_request(message
, option
, len
);
709 test_client_send_reply(message
);
710 test_client_message_num
++;
711 } else if (test_client_message_num
== 1) {
712 test_client_verify_solicit(message
, option
, len
);
713 test_client_send_advertise(message
);
714 test_client_message_num
++;
715 } else if (test_client_message_num
== 2) {
716 test_client_verify_request(message
, option
, len
);
717 test_client_send_reply(message
);
718 test_client_message_num
++;
724 int dhcp6_network_bind_udp_socket(int index
, struct in6_addr
*local_address
) {
725 assert_se(index
== test_index
);
727 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, test_dhcp_fd
) < 0)
730 return test_dhcp_fd
[0];
733 static int test_client_solicit(sd_event
*e
) {
734 sd_dhcp6_client
*client
;
735 usec_t time_now
= now(clock_boottime_or_monotonic());
736 struct in6_addr address
= { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
740 printf("* %s\n", __FUNCTION__
);
742 assert_se(sd_dhcp6_client_new(&client
) >= 0);
745 assert_se(sd_dhcp6_client_attach_event(client
, e
, 0) >= 0);
747 assert_se(sd_dhcp6_client_set_ifindex(client
, test_index
) == 0);
748 assert_se(sd_dhcp6_client_set_mac(client
, (const uint8_t *) &mac_addr
,
751 assert_se(sd_dhcp6_client_set_fqdn(client
, "host.lab.intra") == 1);
753 assert_se(sd_dhcp6_client_get_information_request(client
, &val
) >= 0);
754 assert_se(val
== false);
755 assert_se(sd_dhcp6_client_set_information_request(client
, true) >= 0);
756 assert_se(sd_dhcp6_client_get_information_request(client
, &val
) >= 0);
757 assert_se(val
== true);
759 assert_se(sd_dhcp6_client_set_callback(client
,
760 test_client_information_cb
, e
) >= 0);
762 assert_se(sd_event_add_time(e
, &hangcheck
, clock_boottime_or_monotonic(),
763 time_now
+ 2 * USEC_PER_SEC
, 0,
764 test_hangcheck
, NULL
) >= 0);
766 assert_se(sd_dhcp6_client_set_local_address(client
, &address
) >= 0);
768 assert_se(sd_dhcp6_client_start(client
) >= 0);
772 hangcheck
= sd_event_source_unref(hangcheck
);
774 assert_se(!sd_dhcp6_client_unref(client
));
776 test_dhcp_fd
[1] = safe_close(test_dhcp_fd
[1]);
781 int main(int argc
, char *argv
[]) {
782 _cleanup_(sd_event_unrefp
) sd_event
*e
;
784 assert_se(sd_event_new(&e
) >= 0);
786 log_set_max_level(LOG_DEBUG
);
787 log_parse_environment();
790 test_client_basic(e
);
792 test_advertise_option(e
);
793 test_client_solicit(e
);