chiark / gitweb /
75908391f0c47944e4201e4d8866f9440164a191
[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 = true;
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 static void test_client_solicit_cb(sd_dhcp6_client *client, int event,
339                                    void *userdata) {
340         sd_event *e = userdata;
341
342         assert_se(e);
343         assert_se(event == DHCP6_EVENT_IP_ACQUIRE);
344
345         assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EBUSY);
346
347         if (verbose)
348                 printf("  got DHCPv6 event %d\n", event);
349
350         sd_event_exit(e, 0);
351 }
352
353 static int test_client_send_reply(DHCP6Message *request) {
354         DHCP6Message reply;
355
356         reply.transaction_id = request->transaction_id;
357         reply.type = DHCP6_REPLY;
358
359         memcpy(msg_reply, &reply.transaction_id, 4);
360
361         memcpy(&msg_reply[26], test_duid, sizeof(test_duid));
362
363         memcpy(&msg_reply[44], &test_iaid, sizeof(test_iaid));
364
365         assert_se(write(test_dhcp_fd[1], msg_reply, sizeof(msg_reply))
366                   == sizeof(msg_reply));
367
368         return 0;
369 }
370
371 static int test_client_verify_request(DHCP6Message *request, uint8_t *option,
372                                       size_t len) {
373         _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
374         uint8_t *optval;
375         uint16_t optcode;
376         size_t optlen;
377         bool found_clientid = false, found_iana = false, found_serverid = false,
378                 found_elapsed_time = false;
379         int r;
380         struct in6_addr addr;
381         be32_t val;
382         uint32_t lt_pref, lt_valid;
383
384         assert_se(request->type == DHCP6_REQUEST);
385
386         assert_se(dhcp6_lease_new(&lease) >= 0);
387
388         while ((r = dhcp6_option_parse(&option, &len,
389                                        &optcode, &optlen, &optval)) >= 0) {
390                 switch(optcode) {
391                 case DHCP6_OPTION_CLIENTID:
392                         assert_se(!found_clientid);
393                         found_clientid = true;
394
395                         assert_se(!memcmp(optval, &test_duid,
396                                           sizeof(test_duid)));
397
398                         break;
399
400                 case DHCP6_OPTION_IA_NA:
401                         assert_se(!found_iana);
402                         found_iana = true;
403
404
405                         assert_se(optlen == 40);
406                         assert_se(!memcmp(optval, &test_iaid, sizeof(test_iaid)));
407
408                         val = htobe32(80);
409                         assert_se(!memcmp(optval + 4, &val, sizeof(val)));
410
411                         val = htobe32(120);
412                         assert_se(!memcmp(optval + 8, &val, sizeof(val)));
413
414                         assert_se(!dhcp6_option_parse_ia(&optval, &optlen,
415                                                          optcode, &lease->ia));
416
417                         break;
418
419                 case DHCP6_OPTION_SERVERID:
420                         assert_se(!found_serverid);
421                         found_serverid = true;
422
423                         assert_se(optlen == 14);
424                         assert_se(!memcmp(&msg_advertise[179], optval, optlen));
425
426                         break;
427
428                 case DHCP6_OPTION_ELAPSED_TIME:
429                         assert_se(!found_elapsed_time);
430                         found_elapsed_time = true;
431
432                         assert_se(optlen == 2);
433
434                         break;
435                 }
436         }
437
438         assert_se(r == -ENOMSG);
439         assert_se(found_clientid && found_iana && found_serverid &&
440                   found_elapsed_time);
441
442         assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, &lt_pref,
443                                                    &lt_valid) >= 0);
444         assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr)));
445         assert_se(lt_pref == 150);
446         assert_se(lt_valid == 180);
447
448         assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, &lt_pref,
449                                                   &lt_valid) == -ENOMSG);
450
451         return 0;
452 }
453
454 static int test_client_send_advertise(DHCP6Message *solicit)
455 {
456         DHCP6Message advertise;
457
458         advertise.transaction_id = solicit->transaction_id;
459         advertise.type = DHCP6_ADVERTISE;
460
461         memcpy(msg_advertise, &advertise.transaction_id, 4);
462
463         memcpy(&msg_advertise[8], test_duid, sizeof(test_duid));
464
465         memcpy(&msg_advertise[26], &test_iaid, sizeof(test_iaid));
466
467         assert_se(write(test_dhcp_fd[1], msg_advertise, sizeof(msg_advertise))
468                   == sizeof(msg_advertise));
469
470         return 0;
471 }
472
473 static int test_client_verify_solicit(DHCP6Message *solicit, uint8_t *option,
474                                       size_t len) {
475         uint8_t *optval;
476         uint16_t optcode;
477         size_t optlen;
478         bool found_clientid = false, found_iana = false,
479                 found_elapsed_time = false;
480         int r;
481
482         assert_se(solicit->type == DHCP6_SOLICIT);
483
484         while ((r = dhcp6_option_parse(&option, &len,
485                                        &optcode, &optlen, &optval)) >= 0) {
486                 switch(optcode) {
487                 case DHCP6_OPTION_CLIENTID:
488                         assert_se(!found_clientid);
489                         found_clientid = true;
490
491                         assert_se(optlen == sizeof(test_duid));
492                         memcpy(&test_duid, optval, sizeof(test_duid));
493
494                         break;
495
496                 case DHCP6_OPTION_IA_NA:
497                         assert_se(!found_iana);
498                         found_iana = true;
499
500                         assert_se(optlen == 12);
501
502                         memcpy(&test_iaid, optval, sizeof(test_iaid));
503
504                         break;
505
506                 case DHCP6_OPTION_ELAPSED_TIME:
507                         assert_se(!found_elapsed_time);
508                         found_elapsed_time = true;
509
510                         assert_se(optlen == 2);
511
512                         break;
513                 }
514         }
515
516         assert_se(r == -ENOMSG);
517         assert_se(found_clientid && found_iana && found_elapsed_time);
518
519         return 0;
520 }
521
522 static void test_client_information_cb(sd_dhcp6_client *client, int event,
523                                        void *userdata) {
524         sd_event *e = userdata;
525
526         assert_se(e);
527         assert_se(event == DHCP6_EVENT_INFORMATION_REQUEST);
528
529         if (verbose)
530                 printf("  got DHCPv6 event %d\n", event);
531
532         assert_se(sd_dhcp6_client_set_information_request(client, false) >= 0);
533         assert_se(sd_dhcp6_client_set_callback(client,
534                                                test_client_solicit_cb, e) >= 0);
535
536         assert_se(sd_dhcp6_client_start(client) >= 0);
537 }
538
539 static int test_client_verify_information_request(DHCP6Message *information_request,
540                                                   uint8_t *option, size_t len) {
541
542         _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
543         uint8_t *optval;
544         uint16_t optcode;
545         size_t optlen;
546         bool found_clientid = false, found_elapsed_time = false;
547         int r;
548         struct in6_addr addr;
549         uint32_t lt_pref, lt_valid;
550
551         assert_se(information_request->type == DHCP6_INFORMATION_REQUEST);
552
553         assert_se(dhcp6_lease_new(&lease) >= 0);
554
555         while ((r = dhcp6_option_parse(&option, &len,
556                                        &optcode, &optlen, &optval)) >= 0) {
557                 switch(optcode) {
558                 case DHCP6_OPTION_CLIENTID:
559                         assert_se(!found_clientid);
560                         found_clientid = true;
561
562                         assert_se(optlen == sizeof(test_duid));
563                         memcpy(&test_duid, optval, sizeof(test_duid));
564
565                         break;
566
567                 case DHCP6_OPTION_IA_NA:
568                         assert_not_reached("IA TA option must not be present");
569
570                         break;
571
572                 case DHCP6_OPTION_SERVERID:
573                         assert_not_reached("Server ID option must not be present");
574
575                         break;
576
577                 case DHCP6_OPTION_ELAPSED_TIME:
578                         assert_se(!found_elapsed_time);
579                         found_elapsed_time = true;
580
581                         assert_se(optlen == 2);
582
583                         break;
584                 }
585         }
586
587         assert_se(r == -ENOMSG);
588         assert_se(found_clientid && found_elapsed_time);
589
590         assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, &lt_pref,
591                                                    &lt_valid) == -ENOMSG);
592
593         assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, &lt_pref,
594                                                   &lt_valid) == -ENOMSG);
595
596         return 0;
597 }
598
599 int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
600                                   const void *packet, size_t len) {
601         struct in6_addr mcast =
602                 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
603         DHCP6Message *message;
604         uint8_t *option;
605
606         assert_se(s == test_dhcp_fd[0]);
607         assert_se(server_address);
608         assert_se(packet);
609         assert_se(len > sizeof(DHCP6Message) + 4);
610
611         assert_se(IN6_ARE_ADDR_EQUAL(server_address, &mcast));
612
613         message = (DHCP6Message *)packet;
614         option = (uint8_t *)(message + 1);
615         len -= sizeof(DHCP6Message);
616
617         assert_se(message->transaction_id & 0x00ffffff);
618
619         if (test_client_message_num == 0) {
620                 test_client_verify_information_request(message, option, len);
621                 test_client_send_reply(message);
622                 test_client_message_num++;
623         } else if (test_client_message_num == 1) {
624                 test_client_verify_solicit(message, option, len);
625                 test_client_send_advertise(message);
626                 test_client_message_num++;
627         } else if (test_client_message_num == 2) {
628                 test_client_verify_request(message, option, len);
629                 test_client_send_reply(message);
630                 test_client_message_num++;
631         }
632
633         return len;
634 }
635
636 int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
637         assert_se(index == test_index);
638
639         if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_dhcp_fd) < 0)
640                 return -errno;
641
642         return test_dhcp_fd[0];
643 }
644
645 static int test_client_solicit(sd_event *e) {
646         sd_dhcp6_client *client;
647         usec_t time_now = now(clock_boottime_or_monotonic());
648         bool val = true;
649
650         if (verbose)
651                 printf("* %s\n", __FUNCTION__);
652
653         assert_se(sd_dhcp6_client_new(&client) >= 0);
654         assert_se(client);
655
656         assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
657
658         assert_se(sd_dhcp6_client_set_index(client, test_index) == 0);
659         assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
660                                           sizeof (mac_addr),
661                                           ARPHRD_ETHER) >= 0);
662
663         assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
664         assert_se(val == false);
665         assert_se(sd_dhcp6_client_set_information_request(client, true) >= 0);
666         assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
667         assert_se(val == true);
668
669         assert_se(sd_dhcp6_client_set_callback(client,
670                                                test_client_information_cb, e) >= 0);
671
672         assert_se(sd_event_add_time(e, &hangcheck, clock_boottime_or_monotonic(),
673                                     time_now + 2 * USEC_PER_SEC, 0,
674                                     test_hangcheck, NULL) >= 0);
675
676         assert_se(sd_dhcp6_client_start(client) >= 0);
677
678         sd_event_loop(e);
679
680         hangcheck = sd_event_source_unref(hangcheck);
681
682         assert_se(!sd_dhcp6_client_unref(client));
683
684         test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]);
685
686         return 0;
687 }
688
689 int main(int argc, char *argv[]) {
690         _cleanup_event_unref_ sd_event *e;
691
692         assert_se(sd_event_new(&e) >= 0);
693
694         log_set_max_level(LOG_DEBUG);
695         log_parse_environment();
696         log_open();
697
698         test_client_basic(e);
699         test_option(e);
700         test_advertise_option(e);
701         test_client_solicit(e);
702
703         assert_se(!sd_event_unref(e));
704
705         return 0;
706 }