chiark / gitweb /
26b28a20e848b53b387815dd7e0ce33ab8f49015
[elogind.git] / src / libsystemd-network / test-dhcp6-client.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright (C) 2014 Intel Corporation. All rights reserved.
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdbool.h>
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <unistd.h>
27 #include <net/ethernet.h>
28
29 #include "socket-util.h"
30 #include "macro.h"
31 #include "sd-event.h"
32 #include "event-util.h"
33 #include "virt.h"
34
35 #include "sd-dhcp6-client.h"
36 #include "dhcp6-protocol.h"
37 #include "dhcp6-internal.h"
38 #include "dhcp6-lease-internal.h"
39
40 static struct ether_addr mac_addr = {
41         .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
42 };
43
44 static bool verbose = false;
45
46 static sd_event_source *hangcheck;
47 static int test_dhcp_fd[2];
48 static int test_index = 42;
49 static int test_client_message_num;
50 static be32_t test_iaid = 0;
51 static uint8_t test_duid[14] = { };
52
53 static int test_client_basic(sd_event *e) {
54         sd_dhcp6_client *client;
55
56         if (verbose)
57                 printf("* %s\n", __FUNCTION__);
58
59         assert_se(sd_dhcp6_client_new(&client) >= 0);
60         assert_se(client);
61
62         assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
63
64         assert_se(sd_dhcp6_client_set_index(client, 15) == 0);
65         assert_se(sd_dhcp6_client_set_index(client, -42) == -EINVAL);
66         assert_se(sd_dhcp6_client_set_index(client, -1) == 0);
67         assert_se(sd_dhcp6_client_set_index(client, 42) >= 0);
68
69         assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
70                                           sizeof (mac_addr),
71                                           ARPHRD_ETHER) >= 0);
72
73         assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_CLIENTID) == -EINVAL);
74         assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EEXIST);
75         assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_NTP_SERVER) == -EEXIST);
76         assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_SNTP_SERVERS) == 0);
77         assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DOMAIN_LIST) == -EEXIST);
78         assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL);
79
80         assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0);
81
82         assert_se(sd_dhcp6_client_detach_event(client) >= 0);
83         assert_se(!sd_dhcp6_client_unref(client));
84
85         return 0;
86 }
87
88 static int test_option(sd_event *e) {
89         uint8_t packet[] = {
90                 'F', 'O', 'O',
91                 0x00, DHCP6_OPTION_ORO, 0x00, 0x07,
92                 'A', 'B', 'C', 'D', 'E', 'F', 'G',
93                 0x00, DHCP6_OPTION_VENDOR_CLASS, 0x00, 0x09,
94                 '1', '2', '3', '4', '5', '6', '7', '8', '9',
95                 'B', 'A', 'R',
96         };
97         uint8_t result[] = {
98                 'F', 'O', 'O',
99                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102                 'B', 'A', 'R',
103         };
104         uint16_t optcode;
105         size_t optlen;
106         uint8_t *optval, *buf, *out;
107         size_t zero = 0, pos = 3;
108         size_t buflen = sizeof(packet), outlen = sizeof(result);
109
110         if (verbose)
111                 printf("* %s\n", __FUNCTION__);
112
113         assert_se(buflen == outlen);
114
115         assert_se(dhcp6_option_parse(&buf, &zero, &optcode, &optlen,
116                                      &optval) == -ENOMSG);
117
118         buflen -= 3;
119         buf = &packet[3];
120         outlen -= 3;
121         out = &result[3];
122
123         assert_se(dhcp6_option_parse(&buf, &buflen, &optcode, &optlen,
124                                      &optval) >= 0);
125         pos += 4 + optlen;
126         assert_se(buf == &packet[pos]);
127         assert_se(optcode == DHCP6_OPTION_ORO);
128         assert_se(optlen == 7);
129         assert_se(buflen + pos == sizeof(packet));
130
131         assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen,
132                                       optval) >= 0);
133         assert_se(out == &result[pos]);
134         assert_se(*out == 0x00);
135
136         assert_se(dhcp6_option_parse(&buf, &buflen, &optcode, &optlen,
137                                      &optval) >= 0);
138         pos += 4 + optlen;
139         assert_se(buf == &packet[pos]);
140         assert_se(optcode == DHCP6_OPTION_VENDOR_CLASS);
141         assert_se(optlen == 9);
142         assert_se(buflen + pos == sizeof(packet));
143
144         assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen,
145                                       optval) >= 0);
146         assert_se(out == &result[pos]);
147         assert_se(*out == 'B');
148
149         assert_se(memcmp(packet, result, sizeof(packet)) == 0);
150
151         return 0;
152 }
153
154 static uint8_t msg_advertise[198] = {
155         0x02, 0x0f, 0xb4, 0xe5, 0x00, 0x01, 0x00, 0x0e,
156         0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b, 0xf3, 0x30,
157         0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x03,
158         0x00, 0x5e, 0x0e, 0xcf, 0xa3, 0x7d, 0x00, 0x00,
159         0x00, 0x50, 0x00, 0x00, 0x00, 0x78, 0x00, 0x05,
160         0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
161         0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3, 0x09, 0x3c,
162         0x55, 0xad, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00,
163         0x00, 0xb4, 0x00, 0x0d, 0x00, 0x32, 0x00, 0x00,
164         0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x28,
165         0x65, 0x73, 0x29, 0x20, 0x72, 0x65, 0x6e, 0x65,
166         0x77, 0x65, 0x64, 0x2e, 0x20, 0x47, 0x72, 0x65,
167         0x65, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x66,
168         0x72, 0x6f, 0x6d, 0x20, 0x70, 0x6c, 0x61, 0x6e,
169         0x65, 0x74, 0x20, 0x45, 0x61, 0x72, 0x74, 0x68,
170         0x00, 0x17, 0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8,
171         0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00,
172         0x00, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x0b,
173         0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
174         0x72, 0x61, 0x00, 0x00, 0x1f, 0x00, 0x10, 0x20,
175         0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00,
176         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
177         0x02, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x19,
178         0x40, 0x5c, 0x53, 0x78, 0x2b, 0xcb, 0xb3, 0x6d,
179         0x53, 0x00, 0x07, 0x00, 0x01, 0x00
180 };
181
182 static uint8_t msg_reply[173] = {
183         0x07, 0xf7, 0x4e, 0x57, 0x00, 0x02, 0x00, 0x0e,
184         0x00, 0x01, 0x00, 0x01, 0x19, 0x40, 0x5c, 0x53,
185         0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, 0x00, 0x01,
186         0x00, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x1a, 0x6b,
187         0xf3, 0x30, 0x3c, 0x97, 0x0e, 0xcf, 0xa3, 0x7d,
188         0x00, 0x03, 0x00, 0x4a, 0x0e, 0xcf, 0xa3, 0x7d,
189         0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x78,
190         0x00, 0x05, 0x00, 0x18, 0x20, 0x01, 0x0d, 0xb8,
191         0xde, 0xad, 0xbe, 0xef, 0x78, 0xee, 0x1c, 0xf3,
192         0x09, 0x3c, 0x55, 0xad, 0x00, 0x00, 0x00, 0x96,
193         0x00, 0x00, 0x00, 0xb4, 0x00, 0x0d, 0x00, 0x1e,
194         0x00, 0x00, 0x41, 0x6c, 0x6c, 0x20, 0x61, 0x64,
195         0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20,
196         0x77, 0x65, 0x72, 0x65, 0x20, 0x61, 0x73, 0x73,
197         0x69, 0x67, 0x6e, 0x65, 0x64, 0x2e, 0x00, 0x17,
198         0x00, 0x10, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad,
199         0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200         0x00, 0x01, 0x00, 0x18, 0x00, 0x0b, 0x03, 0x6c,
201         0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, 0x72, 0x61,
202         0x00, 0x00, 0x1f, 0x00, 0x10, 0x20, 0x01, 0x0d,
203         0xb8, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00,
204         0x00, 0x00, 0x00, 0x00, 0x01
205 };
206
207 static int test_advertise_option(sd_event *e) {
208         _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
209         DHCP6Message *advertise = (DHCP6Message *)msg_advertise;
210         uint8_t *optval, *opt = msg_advertise + sizeof(DHCP6Message);
211         uint16_t optcode;
212         size_t optlen, len = sizeof(msg_advertise) - sizeof(DHCP6Message);
213         be32_t val;
214         uint8_t preference = 255;
215         struct in6_addr addr;
216         uint32_t lt_pref, lt_valid;
217         int r;
218         bool opt_clientid = false;
219
220         if (verbose)
221                 printf("* %s\n", __FUNCTION__);
222
223         assert_se(dhcp6_lease_new(&lease) >= 0);
224
225         assert_se(advertise->type == DHCP6_ADVERTISE);
226         assert_se((be32toh(advertise->transaction_id) & 0x00ffffff) ==
227                   0x0fb4e5);
228
229         while ((r = dhcp6_option_parse(&opt, &len, &optcode, &optlen,
230                                        &optval)) >= 0) {
231
232                 switch(optcode) {
233                 case DHCP6_OPTION_CLIENTID:
234                         assert_se(optlen == 14);
235
236                         opt_clientid = true;
237                         break;
238
239                 case DHCP6_OPTION_IA_NA:
240                         assert_se(optlen == 94);
241                         assert_se(!memcmp(optval, &msg_advertise[26], optlen));
242
243                         val = htobe32(0x0ecfa37d);
244                         assert_se(!memcmp(optval, &val, sizeof(val)));
245
246                         val = htobe32(80);
247                         assert_se(!memcmp(optval + 4, &val, sizeof(val)));
248
249                         val = htobe32(120);
250                         assert_se(!memcmp(optval + 8, &val, sizeof(val)));
251
252                         assert_se(dhcp6_option_parse_ia(&optval, &optlen,
253                                                         optcode,
254                                                         &lease->ia) >= 0);
255
256                         break;
257
258                 case DHCP6_OPTION_SERVERID:
259                         assert_se(optlen == 14);
260                         assert_se(!memcmp(optval, &msg_advertise[179], optlen));
261
262                         assert_se(dhcp6_lease_set_serverid(lease, optval,
263                                                            optlen) >= 0);
264                         break;
265
266                 case DHCP6_OPTION_PREFERENCE:
267                         assert_se(optlen == 1);
268                         assert_se(!*optval);
269
270                         assert_se(dhcp6_lease_set_preference(lease,
271                                                              *optval) >= 0);
272                         break;
273
274                 case DHCP6_OPTION_ELAPSED_TIME:
275                         assert_se(optlen == 2);
276
277                         break;
278
279                 default:
280                         break;
281                 }
282         }
283
284
285         assert_se(r == -ENOMSG);
286
287         assert_se(opt_clientid);
288
289         assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, &lt_pref,
290                                                    &lt_valid) >= 0);
291         assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
292         assert_se(lt_pref == 150);
293         assert_se(lt_valid == 180);
294         assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, &lt_pref,
295                                                   &lt_valid) == -ENOMSG);
296
297         assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, &lt_pref,
298                                                    &lt_valid) >= 0);
299         assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
300         assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, &lt_pref,
301                                                   &lt_valid) == -ENOMSG);
302         assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, &lt_pref,
303                                                   &lt_valid) == -ENOMSG);
304         assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, &lt_pref,
305                                                    &lt_valid) >= 0);
306         assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
307         assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, &lt_pref,
308                                                   &lt_valid) == -ENOMSG);
309
310         assert_se(dhcp6_lease_get_serverid(lease, &opt, &len) >= 0);
311         assert_se(len == 14);
312         assert_se(!memcmp(opt, &msg_advertise[179], len));
313
314         assert_se(dhcp6_lease_get_preference(lease, &preference) >= 0);
315         assert_se(preference == 0);
316
317         return 0;
318 }
319
320 static int test_hangcheck(sd_event_source *s, uint64_t usec, void *userdata) {
321         assert_not_reached("Test case should have completed in 2 seconds");
322
323         return 0;
324 }
325
326 int detect_vm(const char **id) {
327         return 1;
328 }
329
330 int detect_container(const char **id) {
331         return 1;
332 }
333
334 int detect_virtualization(const char **id) {
335         return 1;
336 }
337
338 int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
339         assert_se(index == test_index);
340
341         if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_dhcp_fd) < 0)
342                 return -errno;
343
344         return test_dhcp_fd[0];
345 }
346
347 static int test_client_send_reply(DHCP6Message *request) {
348         DHCP6Message reply;
349
350         reply.transaction_id = request->transaction_id;
351         reply.type = DHCP6_REPLY;
352
353         memcpy(msg_reply, &reply.transaction_id, 4);
354
355         memcpy(&msg_reply[26], test_duid, sizeof(test_duid));
356
357         memcpy(&msg_reply[44], &test_iaid, sizeof(test_iaid));
358
359         assert_se(write(test_dhcp_fd[1], msg_reply, sizeof(msg_reply))
360                   == sizeof(msg_reply));
361
362         return 0;
363 }
364
365 static int test_client_verify_request(DHCP6Message *request, uint8_t *option,
366                                       size_t len) {
367         _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
368         uint8_t *optval;
369         uint16_t optcode;
370         size_t optlen;
371         bool found_clientid = false, found_iana = false, found_serverid = false,
372                 found_elapsed_time = false;
373         int r;
374         struct in6_addr addr;
375         be32_t val;
376         uint32_t lt_pref, lt_valid;
377
378         assert_se(request->type == DHCP6_REQUEST);
379
380         assert_se(dhcp6_lease_new(&lease) >= 0);
381
382         while ((r = dhcp6_option_parse(&option, &len,
383                                        &optcode, &optlen, &optval)) >= 0) {
384                 switch(optcode) {
385                 case DHCP6_OPTION_CLIENTID:
386                         assert_se(!found_clientid);
387                         found_clientid = true;
388
389                         assert_se(!memcmp(optval, &test_duid,
390                                           sizeof(test_duid)));
391
392                         break;
393
394                 case DHCP6_OPTION_IA_NA:
395                         assert_se(!found_iana);
396                         found_iana = true;
397
398
399                         assert_se(optlen == 40);
400                         assert_se(!memcmp(optval, &test_iaid, sizeof(test_iaid)));
401
402                         val = htobe32(80);
403                         assert_se(!memcmp(optval + 4, &val, sizeof(val)));
404
405                         val = htobe32(120);
406                         assert_se(!memcmp(optval + 8, &val, sizeof(val)));
407
408                         assert_se(!dhcp6_option_parse_ia(&optval, &optlen,
409                                                          optcode, &lease->ia));
410
411                         break;
412
413                 case DHCP6_OPTION_SERVERID:
414                         assert_se(!found_serverid);
415                         found_serverid = true;
416
417                         assert_se(optlen == 14);
418                         assert_se(!memcmp(&msg_advertise[179], optval, optlen));
419
420                         break;
421
422                 case DHCP6_OPTION_ELAPSED_TIME:
423                         assert_se(!found_elapsed_time);
424                         found_elapsed_time = true;
425
426                         assert_se(optlen == 2);
427
428                         break;
429                 }
430         }
431
432         assert_se(r == -ENOMSG);
433         assert_se(found_clientid && found_iana && found_serverid &&
434                   found_elapsed_time);
435
436         assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, &lt_pref,
437                                                    &lt_valid) >= 0);
438         assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
439         assert_se(lt_pref == 150);
440         assert_se(lt_valid == 180);
441
442         assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, &lt_pref,
443                                                   &lt_valid) == -ENOMSG);
444
445         return 0;
446 }
447
448 static int test_client_send_advertise(DHCP6Message *solicit)
449 {
450         DHCP6Message advertise;
451
452         advertise.transaction_id = solicit->transaction_id;
453         advertise.type = DHCP6_ADVERTISE;
454
455         memcpy(msg_advertise, &advertise.transaction_id, 4);
456
457         memcpy(&msg_advertise[8], test_duid, sizeof(test_duid));
458
459         memcpy(&msg_advertise[26], &test_iaid, sizeof(test_iaid));
460
461         assert_se(write(test_dhcp_fd[1], msg_advertise, sizeof(msg_advertise))
462                   == sizeof(msg_advertise));
463
464         return 0;
465 }
466
467 static int test_client_verify_solicit(DHCP6Message *solicit, uint8_t *option,
468                                       size_t len) {
469         uint8_t *optval;
470         uint16_t optcode;
471         size_t optlen;
472         bool found_clientid = false, found_iana = false,
473                 found_elapsed_time = false;
474         int r;
475
476         assert_se(solicit->type == DHCP6_SOLICIT);
477
478         while ((r = dhcp6_option_parse(&option, &len,
479                                        &optcode, &optlen, &optval)) >= 0) {
480                 switch(optcode) {
481                 case DHCP6_OPTION_CLIENTID:
482                         assert_se(!found_clientid);
483                         found_clientid = true;
484
485                         assert_se(optlen == sizeof(test_duid));
486                         memcpy(&test_duid, optval, sizeof(test_duid));
487
488                         break;
489
490                 case DHCP6_OPTION_IA_NA:
491                         assert_se(!found_iana);
492                         found_iana = true;
493
494                         assert_se(optlen == 12);
495
496                         memcpy(&test_iaid, optval, sizeof(test_iaid));
497
498                         break;
499
500                 case DHCP6_OPTION_ELAPSED_TIME:
501                         assert_se(!found_elapsed_time);
502                         found_elapsed_time = true;
503
504                         assert_se(optlen == 2);
505
506                         break;
507                 }
508         }
509
510         assert_se(r == -ENOMSG);
511         assert_se(found_clientid && found_iana && found_elapsed_time);
512
513         return 0;
514 }
515
516 int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
517                                   const void *packet, size_t len) {
518         struct in6_addr mcast =
519                 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
520         DHCP6Message *message;
521         uint8_t *option;
522
523         assert_se(s == test_dhcp_fd[0]);
524         assert_se(server_address);
525         assert_se(packet);
526         assert_se(len > sizeof(DHCP6Message) + 4);
527
528         assert_se(IN6_ARE_ADDR_EQUAL(server_address, &mcast));
529
530         message = (DHCP6Message *)packet;
531         option = (uint8_t *)(message + 1);
532         len -= sizeof(DHCP6Message);
533
534         assert_se(message->transaction_id & 0x00ffffff);
535
536         if (test_client_message_num == 0) {
537                 test_client_verify_solicit(message, option, len);
538                 test_client_send_advertise(message);
539                 test_client_message_num++;
540         } else if (test_client_message_num == 1) {
541                 test_client_verify_request(message, option, len);
542                 test_client_send_reply(message);
543                 test_client_message_num++;
544         }
545
546         return len;
547 }
548
549 static void test_client_solicit_cb(sd_dhcp6_client *client, int event,
550                                    void *userdata) {
551         sd_event *e = userdata;
552
553         assert_se(e);
554         assert_se(event == DHCP6_EVENT_IP_ACQUIRE);
555
556         assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EBUSY);
557
558         if (verbose)
559                 printf("  got DHCPv6 event %d\n", event);
560
561         sd_event_exit(e, 0);
562 }
563
564 static int test_client_solicit(sd_event *e) {
565         sd_dhcp6_client *client;
566         usec_t time_now = now(clock_boottime_or_monotonic());
567
568         if (verbose)
569                 printf("* %s\n", __FUNCTION__);
570
571         assert_se(sd_dhcp6_client_new(&client) >= 0);
572         assert_se(client);
573
574         assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
575
576         assert_se(sd_dhcp6_client_set_index(client, test_index) == 0);
577         assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
578                                           sizeof (mac_addr),
579                                           ARPHRD_ETHER) >= 0);
580
581         assert_se(sd_dhcp6_client_set_callback(client,
582                                                test_client_solicit_cb, e) >= 0);
583
584         assert_se(sd_event_add_time(e, &hangcheck, clock_boottime_or_monotonic(),
585                                     time_now + 2 * USEC_PER_SEC, 0,
586                                     test_hangcheck, NULL) >= 0);
587
588         assert_se(sd_dhcp6_client_start(client) >= 0);
589
590         sd_event_loop(e);
591
592         hangcheck = sd_event_source_unref(hangcheck);
593
594         assert_se(!sd_dhcp6_client_unref(client));
595
596         test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]);
597
598         return 0;
599 }
600
601 int main(int argc, char *argv[]) {
602         _cleanup_event_unref_ sd_event *e;
603
604         assert_se(sd_event_new(&e) >= 0);
605
606         log_set_max_level(LOG_DEBUG);
607         log_parse_environment();
608         log_open();
609
610         test_client_basic(e);
611         test_option(e);
612         test_advertise_option(e);
613         test_client_solicit(e);
614
615         assert_se(!sd_event_unref(e));
616
617         return 0;
618 }