client: Add ReportError handling
[platform/upstream/connman.git] / gdhcp / client.c
1 /*
2  *
3  *  DHCP client library with GLib integration
4  *
5  *  Copyright (C) 2009-2012  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #define _GNU_SOURCE
27 #include <stdio.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/ioctl.h>
33 #include <arpa/inet.h>
34 #include <sys/time.h>
35
36 #include <netpacket/packet.h>
37 #include <netinet/if_ether.h>
38 #include <net/ethernet.h>
39
40 #include <linux/if.h>
41 #include <linux/filter.h>
42
43 #include <glib.h>
44
45 #include "gdhcp.h"
46 #include "common.h"
47 #include "ipv4ll.h"
48
49 #define DISCOVER_TIMEOUT 3
50 #define DISCOVER_RETRIES 10
51
52 #define REQUEST_TIMEOUT 3
53 #define REQUEST_RETRIES 5
54
55 typedef enum _listen_mode {
56         L_NONE,
57         L2,
58         L3,
59         L_ARP,
60 } ListenMode;
61
62 typedef enum _dhcp_client_state {
63         INIT_SELECTING,
64         REQUESTING,
65         BOUND,
66         RENEWING,
67         REBINDING,
68         RELEASED,
69         IPV4LL_PROBE,
70         IPV4LL_ANNOUNCE,
71         IPV4LL_MONITOR,
72         IPV4LL_DEFEND,
73         INFORMATION_REQ,
74         SOLICITATION,
75         REQUEST,
76         RENEW,
77         REBIND,
78         RELEASE,
79 } ClientState;
80
81 struct _GDHCPClient {
82         int ref_count;
83         GDHCPType type;
84         ClientState state;
85         int ifindex;
86         char *interface;
87         uint8_t mac_address[6];
88         uint32_t xid;
89         uint32_t server_ip;
90         uint32_t requested_ip;
91         char *assigned_ip;
92         time_t start;
93         uint32_t lease_seconds;
94         ListenMode listen_mode;
95         int listener_sockfd;
96         uint8_t retry_times;
97         uint8_t ack_retry_times;
98         uint8_t conflicts;
99         guint timeout;
100         guint listener_watch;
101         GIOChannel *listener_channel;
102         GList *require_list;
103         GList *request_list;
104         GHashTable *code_value_hash;
105         GHashTable *send_value_hash;
106         GDHCPClientEventFunc lease_available_cb;
107         gpointer lease_available_data;
108         GDHCPClientEventFunc ipv4ll_available_cb;
109         gpointer ipv4ll_available_data;
110         GDHCPClientEventFunc no_lease_cb;
111         gpointer no_lease_data;
112         GDHCPClientEventFunc lease_lost_cb;
113         gpointer lease_lost_data;
114         GDHCPClientEventFunc ipv4ll_lost_cb;
115         gpointer ipv4ll_lost_data;
116         GDHCPClientEventFunc address_conflict_cb;
117         gpointer address_conflict_data;
118         GDHCPDebugFunc debug_func;
119         gpointer debug_data;
120         GDHCPClientEventFunc information_req_cb;
121         gpointer information_req_data;
122         GDHCPClientEventFunc solicitation_cb;
123         gpointer solicitation_data;
124         GDHCPClientEventFunc advertise_cb;
125         gpointer advertise_data;
126         GDHCPClientEventFunc request_cb;
127         gpointer request_data;
128         GDHCPClientEventFunc renew_cb;
129         gpointer renew_data;
130         GDHCPClientEventFunc rebind_cb;
131         gpointer rebind_data;
132         GDHCPClientEventFunc release_cb;
133         gpointer release_data;
134         char *last_address;
135         unsigned char *duid;
136         int duid_len;
137         unsigned char *server_duid;
138         int server_duid_len;
139         uint16_t status_code;
140         uint32_t iaid;
141         uint32_t T1, T2;
142         struct in6_addr ia_na;
143         struct in6_addr ia_ta;
144         time_t last_renew;
145         time_t last_rebind;
146         time_t expire;
147         gboolean retransmit;
148         struct timeval start_time;
149 };
150
151 static inline void debug(GDHCPClient *client, const char *format, ...)
152 {
153         char str[256];
154         va_list ap;
155
156         if (client->debug_func == NULL)
157                 return;
158
159         va_start(ap, format);
160
161         if (vsnprintf(str, sizeof(str), format, ap) > 0)
162                 client->debug_func(str, client->debug_data);
163
164         va_end(ap);
165 }
166
167 /* Initialize the packet with the proper defaults */
168 static void init_packet(GDHCPClient *dhcp_client, gpointer pkt, char type)
169 {
170         if (dhcp_client->type == G_DHCP_IPV6)
171                 dhcpv6_init_header(pkt, type);
172         else {
173                 struct dhcp_packet *packet = pkt;
174
175                 dhcp_init_header(packet, type);
176                 memcpy(packet->chaddr, dhcp_client->mac_address, 6);
177         }
178 }
179
180 static void add_request_options(GDHCPClient *dhcp_client,
181                                 struct dhcp_packet *packet)
182 {
183         int len = 0;
184         GList *list;
185         uint8_t code;
186         int end = dhcp_end_option(packet->options);
187
188         for (list = dhcp_client->request_list; list; list = list->next) {
189                 code = (uint8_t) GPOINTER_TO_INT(list->data);
190
191                 packet->options[end + OPT_DATA + len] = code;
192                 len++;
193         }
194
195         if (len) {
196                 packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
197                 packet->options[end + OPT_LEN] = len;
198                 packet->options[end + OPT_DATA + len] = DHCP_END;
199         }
200 }
201
202 struct hash_params {
203         unsigned char *buf;
204         int max_buf;
205         unsigned char **ptr_buf;
206 };
207
208 static void add_dhcpv6_binary_option(gpointer key, gpointer value,
209                                         gpointer user_data)
210 {
211         uint8_t *option = value;
212         uint16_t len;
213         struct hash_params *params = user_data;
214
215         /* option[0][1] contains option code */
216         len = option[2] << 8 | option[3];
217
218         if ((*params->ptr_buf + len + 2 + 2) > (params->buf + params->max_buf))
219                 return;
220
221         memcpy(*params->ptr_buf, option, len + 2 + 2);
222         (*params->ptr_buf) += len + 2 + 2;
223 }
224
225 static void add_dhcpv6_send_options(GDHCPClient *dhcp_client,
226                                 unsigned char *buf, int max_buf,
227                                 unsigned char **ptr_buf)
228 {
229         struct hash_params params = {
230                 .buf = buf,
231                 .max_buf = max_buf,
232                 .ptr_buf = ptr_buf
233         };
234
235         if (dhcp_client->type == G_DHCP_IPV4)
236                 return;
237
238         g_hash_table_foreach(dhcp_client->send_value_hash,
239                                 add_dhcpv6_binary_option, &params);
240
241         *ptr_buf = *params.ptr_buf;
242 }
243
244 static void copy_option(uint8_t *buf, uint16_t code, uint16_t len,
245                         uint8_t *msg)
246 {
247         buf[0] = code >> 8;
248         buf[1] = code & 0xff;
249         buf[2] = len >> 8;
250         buf[3] = len & 0xff;
251         if (len > 0 && msg != NULL)
252                 memcpy(&buf[4], msg, len);
253 }
254
255 static int32_t get_time_diff(struct timeval *tv)
256 {
257         struct timeval now;
258         int32_t hsec;
259
260         gettimeofday(&now, NULL);
261
262         hsec = (now.tv_sec - tv->tv_sec) * 100;
263         hsec += (now.tv_usec - tv->tv_usec) / 10000;
264
265         return hsec;
266 }
267
268 static void add_dhcpv6_request_options(GDHCPClient *dhcp_client,
269                                 struct dhcpv6_packet *packet,
270                                 unsigned char *buf, int max_buf,
271                                 unsigned char **ptr_buf)
272 {
273         GList *list;
274         uint16_t code, value;
275         int32_t diff;
276         int len;
277
278         if (dhcp_client->type == G_DHCP_IPV4)
279                 return;
280
281         for (list = dhcp_client->request_list; list; list = list->next) {
282                 code = (uint16_t) GPOINTER_TO_INT(list->data);
283
284                 switch (code) {
285                 case G_DHCPV6_CLIENTID:
286                         if (dhcp_client->duid == NULL)
287                                 return;
288
289                         len = 2 + 2 + dhcp_client->duid_len;
290                         if ((*ptr_buf + len) > (buf + max_buf)) {
291                                 debug(dhcp_client, "Too long dhcpv6 message "
292                                         "when writing client id option");
293                                 return;
294                         }
295
296                         copy_option(*ptr_buf, G_DHCPV6_CLIENTID,
297                                 dhcp_client->duid_len, dhcp_client->duid);
298                         (*ptr_buf) += len;
299                         break;
300
301                 case G_DHCPV6_SERVERID:
302                         if (dhcp_client->server_duid == NULL)
303                                 return;
304
305                         len = 2 + 2 + dhcp_client->server_duid_len;
306                         if ((*ptr_buf + len) > (buf + max_buf)) {
307                                 debug(dhcp_client, "Too long dhcpv6 message "
308                                         "when writing server id option");
309                                 return;
310                         }
311
312                         copy_option(*ptr_buf, G_DHCPV6_SERVERID,
313                                 dhcp_client->server_duid_len,
314                                 dhcp_client->server_duid);
315                         (*ptr_buf) += len;
316                         break;
317
318                 case G_DHCPV6_RAPID_COMMIT:
319                         len = 2 + 2;
320                         if ((*ptr_buf + len) > (buf + max_buf)) {
321                                 debug(dhcp_client, "Too long dhcpv6 message "
322                                         "when writing rapid commit option");
323                                 return;
324                         }
325
326                         copy_option(*ptr_buf, G_DHCPV6_RAPID_COMMIT, 0, 0);
327                         (*ptr_buf) += len;
328                         break;
329
330                 case G_DHCPV6_ORO:
331                         break;
332
333                 case G_DHCPV6_ELAPSED_TIME:
334                         if (dhcp_client->retransmit == FALSE) {
335                                 /*
336                                  * Initial message, elapsed time is 0.
337                                  */
338                                 diff = 0;
339                         } else {
340                                 diff = get_time_diff(&dhcp_client->start_time);
341                                 if (diff < 0 || diff > 0xffff)
342                                         diff = 0xffff;
343                         }
344
345                         len = 2 + 2 + 2;
346                         if ((*ptr_buf + len) > (buf + max_buf)) {
347                                 debug(dhcp_client, "Too long dhcpv6 message "
348                                         "when writing elapsed time option");
349                                 return;
350                         }
351
352                         value = htons((uint16_t)diff);
353                         copy_option(*ptr_buf, G_DHCPV6_ELAPSED_TIME,
354                                 2, (uint8_t *)&value);
355                         (*ptr_buf) += len;
356                         break;
357
358                 case G_DHCPV6_DNS_SERVERS:
359                         break;
360
361                 case G_DHCPV6_SNTP_SERVERS:
362                         break;
363
364                 default:
365                         break;
366                 }
367         }
368 }
369
370 static void add_binary_option(gpointer key, gpointer value, gpointer user_data)
371 {
372         uint8_t *option = value;
373         struct dhcp_packet *packet = user_data;
374
375         dhcp_add_binary_option(packet, option);
376 }
377
378 static void add_send_options(GDHCPClient *dhcp_client,
379                                 struct dhcp_packet *packet)
380 {
381         g_hash_table_foreach(dhcp_client->send_value_hash,
382                                 add_binary_option, packet);
383 }
384
385 /*
386  * Return an RFC 951- and 2131-complaint BOOTP 'secs' value that
387  * represents the number of seconds elapsed from the start of
388  * attempting DHCP to satisfy some DHCP servers that allow for an
389  * "authoritative" reply before responding.
390  */
391 static uint16_t dhcp_attempt_secs(GDHCPClient *dhcp_client)
392 {
393         return htons(MIN(time(NULL) - dhcp_client->start, UINT16_MAX));
394 }
395
396 static int send_discover(GDHCPClient *dhcp_client, uint32_t requested)
397 {
398         struct dhcp_packet packet;
399
400         debug(dhcp_client, "sending DHCP discover request");
401
402         init_packet(dhcp_client, &packet, DHCPDISCOVER);
403
404         packet.xid = dhcp_client->xid;
405         packet.secs = dhcp_attempt_secs(dhcp_client);
406
407         if (requested)
408                 dhcp_add_option_uint32(&packet, DHCP_REQUESTED_IP, requested);
409
410         /* Explicitly saying that we want RFC-compliant packets helps
411          * some buggy DHCP servers to NOT send bigger packets */
412         dhcp_add_option_uint16(&packet, DHCP_MAX_SIZE, 576);
413
414         add_request_options(dhcp_client, &packet);
415
416         add_send_options(dhcp_client, &packet);
417
418         return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
419                                         INADDR_BROADCAST, SERVER_PORT,
420                                         MAC_BCAST_ADDR, dhcp_client->ifindex);
421 }
422
423 static int send_select(GDHCPClient *dhcp_client)
424 {
425         struct dhcp_packet packet;
426
427         debug(dhcp_client, "sending DHCP select request");
428
429         init_packet(dhcp_client, &packet, DHCPREQUEST);
430
431         packet.xid = dhcp_client->xid;
432         packet.secs = dhcp_attempt_secs(dhcp_client);
433
434         dhcp_add_option_uint32(&packet, DHCP_REQUESTED_IP,
435                                                 dhcp_client->requested_ip);
436         dhcp_add_option_uint32(&packet, DHCP_SERVER_ID,
437                                                 dhcp_client->server_ip);
438
439         add_request_options(dhcp_client, &packet);
440
441         add_send_options(dhcp_client, &packet);
442
443         return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
444                                         INADDR_BROADCAST, SERVER_PORT,
445                                         MAC_BCAST_ADDR, dhcp_client->ifindex);
446 }
447
448 static int send_renew(GDHCPClient *dhcp_client)
449 {
450         struct dhcp_packet packet;
451
452         debug(dhcp_client, "sending DHCP renew request");
453
454         init_packet(dhcp_client , &packet, DHCPREQUEST);
455         packet.xid = dhcp_client->xid;
456         packet.ciaddr = htonl(dhcp_client->requested_ip);
457
458         add_request_options(dhcp_client, &packet);
459
460         add_send_options(dhcp_client, &packet);
461
462         return dhcp_send_kernel_packet(&packet,
463                 dhcp_client->requested_ip, CLIENT_PORT,
464                 dhcp_client->server_ip, SERVER_PORT);
465 }
466
467 static int send_rebound(GDHCPClient *dhcp_client)
468 {
469         struct dhcp_packet packet;
470
471         debug(dhcp_client, "sending DHCP rebound request");
472
473         init_packet(dhcp_client , &packet, DHCPREQUEST);
474         packet.xid = dhcp_client->xid;
475         packet.ciaddr = htonl(dhcp_client->requested_ip);
476
477         add_request_options(dhcp_client, &packet);
478
479         add_send_options(dhcp_client, &packet);
480
481         return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
482                                         INADDR_BROADCAST, SERVER_PORT,
483                                         MAC_BCAST_ADDR, dhcp_client->ifindex);
484 }
485
486 static int send_release(GDHCPClient *dhcp_client,
487                         uint32_t server, uint32_t ciaddr)
488 {
489         struct dhcp_packet packet;
490
491         debug(dhcp_client, "sending DHCP release request");
492
493         init_packet(dhcp_client, &packet, DHCPRELEASE);
494         packet.xid = rand();
495         packet.ciaddr = htonl(ciaddr);
496
497         dhcp_add_option_uint32(&packet, DHCP_SERVER_ID, server);
498
499         return dhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT,
500                                                 server, SERVER_PORT);
501 }
502
503 static gboolean ipv4ll_probe_timeout(gpointer dhcp_data);
504 static int switch_listening_mode(GDHCPClient *dhcp_client,
505                                         ListenMode listen_mode);
506
507 static gboolean send_probe_packet(gpointer dhcp_data)
508 {
509         GDHCPClient *dhcp_client;
510         guint timeout;
511
512         dhcp_client = dhcp_data;
513         /* if requested_ip is not valid, pick a new address*/
514         if (dhcp_client->requested_ip == 0) {
515                 debug(dhcp_client, "pick a new random address");
516                 dhcp_client->requested_ip = ipv4ll_random_ip(0);
517         }
518
519         debug(dhcp_client, "sending IPV4LL probe request");
520
521         if (dhcp_client->retry_times == 1) {
522                 dhcp_client->state = IPV4LL_PROBE;
523                 switch_listening_mode(dhcp_client, L_ARP);
524         }
525         ipv4ll_send_arp_packet(dhcp_client->mac_address, 0,
526                         dhcp_client->requested_ip, dhcp_client->ifindex);
527
528         if (dhcp_client->retry_times < PROBE_NUM) {
529                 /*add a random timeout in range of PROBE_MIN to PROBE_MAX*/
530                 timeout = ipv4ll_random_delay_ms(PROBE_MAX-PROBE_MIN);
531                 timeout += PROBE_MIN*1000;
532         } else
533                 timeout = (ANNOUNCE_WAIT * 1000);
534
535         dhcp_client->timeout = g_timeout_add_full(G_PRIORITY_HIGH,
536                                                  timeout,
537                                                  ipv4ll_probe_timeout,
538                                                  dhcp_client,
539                                                  NULL);
540         return FALSE;
541 }
542
543 static gboolean ipv4ll_announce_timeout(gpointer dhcp_data);
544 static gboolean ipv4ll_defend_timeout(gpointer dhcp_data);
545
546 static gboolean send_announce_packet(gpointer dhcp_data)
547 {
548         GDHCPClient *dhcp_client;
549
550         dhcp_client = dhcp_data;
551
552         debug(dhcp_client, "sending IPV4LL announce request");
553
554         ipv4ll_send_arp_packet(dhcp_client->mac_address,
555                                 dhcp_client->requested_ip,
556                                 dhcp_client->requested_ip,
557                                 dhcp_client->ifindex);
558
559         if (dhcp_client->timeout > 0)
560                 g_source_remove(dhcp_client->timeout);
561         dhcp_client->timeout = 0;
562
563         if (dhcp_client->state == IPV4LL_DEFEND) {
564                 dhcp_client->timeout =
565                         g_timeout_add_seconds_full(G_PRIORITY_HIGH,
566                                                 DEFEND_INTERVAL,
567                                                 ipv4ll_defend_timeout,
568                                                 dhcp_client,
569                                                 NULL);
570                 return TRUE;
571         } else
572                 dhcp_client->timeout =
573                         g_timeout_add_seconds_full(G_PRIORITY_HIGH,
574                                                 ANNOUNCE_INTERVAL,
575                                                 ipv4ll_announce_timeout,
576                                                 dhcp_client,
577                                                 NULL);
578         return TRUE;
579 }
580
581 static void get_interface_mac_address(int index, uint8_t *mac_address)
582 {
583         struct ifreq ifr;
584         int sk, err;
585
586         sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
587         if (sk < 0) {
588                 perror("Open socket error");
589                 return;
590         }
591
592         memset(&ifr, 0, sizeof(ifr));
593         ifr.ifr_ifindex = index;
594
595         err = ioctl(sk, SIOCGIFNAME, &ifr);
596         if (err < 0) {
597                 perror("Get interface name error");
598                 goto done;
599         }
600
601         err = ioctl(sk, SIOCGIFHWADDR, &ifr);
602         if (err < 0) {
603                 perror("Get mac address error");
604                 goto done;
605         }
606
607         memcpy(mac_address, ifr.ifr_hwaddr.sa_data, 6);
608
609 done:
610         close(sk);
611 }
612
613 void g_dhcpv6_client_set_retransmit(GDHCPClient *dhcp_client)
614 {
615         if (dhcp_client == NULL)
616                 return;
617
618         dhcp_client->retransmit = TRUE;
619 }
620
621 void g_dhcpv6_client_clear_retransmit(GDHCPClient *dhcp_client)
622 {
623         if (dhcp_client == NULL)
624                 return;
625
626         dhcp_client->retransmit = FALSE;
627 }
628
629 int g_dhcpv6_create_duid(GDHCPDuidType duid_type, int index, int type,
630                         unsigned char **duid, int *duid_len)
631 {
632         time_t duid_time;
633
634         switch (duid_type) {
635         case G_DHCPV6_DUID_LLT:
636                 *duid_len = 2 + 2 + 4 + ETH_ALEN;
637                 *duid = g_try_malloc(*duid_len);
638                 if (*duid == NULL)
639                         return -ENOMEM;
640
641                 (*duid)[0] = 0;
642                 (*duid)[1] = 1;
643                 get_interface_mac_address(index, &(*duid)[2 + 2 + 4]);
644                 (*duid)[2] = 0;
645                 (*duid)[3] = type;
646                 duid_time = time(NULL) - DUID_TIME_EPOCH;
647                 (*duid)[4] = duid_time >> 24;
648                 (*duid)[5] = duid_time >> 16;
649                 (*duid)[6] = duid_time >> 8;
650                 (*duid)[7] = duid_time & 0xff;
651                 break;
652         case G_DHCPV6_DUID_EN:
653                 return -EINVAL;
654         case G_DHCPV6_DUID_LL:
655                 *duid_len = 2 + 2 + ETH_ALEN;
656                 *duid = g_try_malloc(*duid_len);
657                 if (*duid == NULL)
658                         return -ENOMEM;
659
660                 (*duid)[0] = 0;
661                 (*duid)[1] = 3;
662                 get_interface_mac_address(index, &(*duid)[2 + 2]);
663                 (*duid)[2] = 0;
664                 (*duid)[3] = type;
665                 break;
666         }
667
668         return 0;
669 }
670
671 int g_dhcpv6_client_set_duid(GDHCPClient *dhcp_client, unsigned char *duid,
672                         int duid_len)
673 {
674         if (dhcp_client == NULL || dhcp_client->type == G_DHCP_IPV4)
675                 return -EINVAL;
676
677         g_free(dhcp_client->duid);
678
679         dhcp_client->duid = duid;
680         dhcp_client->duid_len = duid_len;
681
682         return 0;
683 }
684
685 uint32_t g_dhcpv6_client_get_iaid(GDHCPClient *dhcp_client)
686 {
687         if (dhcp_client == NULL || dhcp_client->type == G_DHCP_IPV4)
688                 return 0;
689
690         return dhcp_client->iaid;
691 }
692
693 void g_dhcpv6_client_create_iaid(GDHCPClient *dhcp_client, int index,
694                                 unsigned char *iaid)
695 {
696         uint8_t buf[6];
697
698         get_interface_mac_address(index, buf);
699
700         memcpy(iaid, &buf[2], 4);
701         dhcp_client->iaid = iaid[0] << 24 |
702                         iaid[1] << 16 | iaid[2] << 8 | iaid[3];
703 }
704
705 int g_dhcpv6_client_get_timeouts(GDHCPClient *dhcp_client,
706                                 uint32_t *T1, uint32_t *T2,
707                                 time_t *last_renew, time_t *last_rebind,
708                                 time_t *expire)
709 {
710         if (dhcp_client == NULL || dhcp_client->type == G_DHCP_IPV4)
711                 return -EINVAL;
712
713         if (T1 != NULL)
714                 *T1 = dhcp_client->T1;
715
716         if (T2 != NULL)
717                 *T2 = dhcp_client->T2;
718
719         if (last_renew != NULL)
720                 *last_renew = dhcp_client->last_renew;
721
722         if (last_rebind != NULL)
723                 *last_rebind = dhcp_client->last_rebind;
724
725         if (expire != NULL)
726                 *expire = dhcp_client->expire;
727
728         return 0;
729 }
730
731 static uint8_t *create_iaaddr(GDHCPClient *dhcp_client, uint8_t *buf,
732                                 uint16_t len)
733 {
734         buf[0] = 0;
735         buf[1] = G_DHCPV6_IAADDR;
736         buf[2] = 0;
737         buf[3] = len;
738         memcpy(&buf[4], &dhcp_client->ia_na, 16);
739         memset(&buf[20], 0, 4); /* preferred */
740         memset(&buf[24], 0, 4); /* valid */
741         return buf;
742 }
743
744 static void put_iaid(GDHCPClient *dhcp_client, int index, uint8_t *buf)
745 {
746         uint32_t iaid;
747
748         iaid = g_dhcpv6_client_get_iaid(dhcp_client);
749         if (iaid == 0) {
750                 g_dhcpv6_client_create_iaid(dhcp_client, index, buf);
751                 return;
752         }
753
754         buf[0] = iaid >> 24;
755         buf[1] = iaid >> 16;
756         buf[2] = iaid >> 8;
757         buf[3] = iaid;
758 }
759
760 int g_dhcpv6_client_set_ia(GDHCPClient *dhcp_client, int index,
761                         int code, uint32_t *T1, uint32_t *T2,
762                         gboolean add_iaaddr)
763 {
764         if (code == G_DHCPV6_IA_TA) {
765                 uint8_t ia_options[4];
766
767                 put_iaid(dhcp_client, index, ia_options);
768
769                 g_dhcp_client_set_request(dhcp_client, G_DHCPV6_IA_TA);
770                 g_dhcpv6_client_set_send(dhcp_client, G_DHCPV6_IA_TA,
771                                         ia_options, sizeof(ia_options));
772
773         } else if (code == G_DHCPV6_IA_NA) {
774
775                 g_dhcp_client_set_request(dhcp_client, G_DHCPV6_IA_NA);
776
777                 if (add_iaaddr == TRUE) {
778 #define IAADDR_LEN (16+4+4)
779                         uint8_t ia_options[4+4+4+2+2+IAADDR_LEN];
780
781                         put_iaid(dhcp_client, index, ia_options);
782
783                         if (T1 != NULL) {
784                                 ia_options[4] = *T1 >> 24;
785                                 ia_options[5] = *T1 >> 16;
786                                 ia_options[6] = *T1 >> 8;
787                                 ia_options[7] = *T1;
788                         } else
789                                 memset(&ia_options[4], 0x00, 4);
790
791                         if (T2 != NULL) {
792                                 ia_options[8] = *T2 >> 24;
793                                 ia_options[9] = *T2 >> 16;
794                                 ia_options[10] = *T2 >> 8;
795                                 ia_options[11] = *T2;
796                         } else
797                                 memset(&ia_options[8], 0x00, 4);
798
799                         create_iaaddr(dhcp_client, &ia_options[12],
800                                         IAADDR_LEN);
801
802                         g_dhcpv6_client_set_send(dhcp_client, G_DHCPV6_IA_NA,
803                                         ia_options, sizeof(ia_options));
804                 } else {
805                         uint8_t ia_options[4+4+4];
806
807                         put_iaid(dhcp_client, index, ia_options);
808
809                         memset(&ia_options[4], 0x00, 4); /* T1 (4 bytes) */
810                         memset(&ia_options[8], 0x00, 4); /* T2 (4 bytes) */
811
812                         g_dhcpv6_client_set_send(dhcp_client, G_DHCPV6_IA_NA,
813                                         ia_options, sizeof(ia_options));
814                 }
815
816         } else
817                 return -EINVAL;
818
819         return 0;
820 }
821
822 int g_dhcpv6_client_set_oro(GDHCPClient *dhcp_client, int args, ...)
823 {
824         va_list va;
825         int i, j, len = sizeof(uint16_t) * args;
826         uint8_t *values;
827
828         values = g_try_malloc(len);
829         if (values == NULL)
830                 return -ENOMEM;
831
832         va_start(va, args);
833         for (i = 0, j = 0; i < args; i++) {
834                 uint16_t value = va_arg(va, int);
835                 values[j++] = value >> 8;
836                 values[j++] = value & 0xff;
837         }
838         va_end(va);
839
840         g_dhcpv6_client_set_send(dhcp_client, G_DHCPV6_ORO, values, len);
841
842         g_free(values);
843
844         return 0;
845 }
846
847 static int send_dhcpv6_msg(GDHCPClient *dhcp_client, int type, char *msg)
848 {
849         struct dhcpv6_packet *packet;
850         uint8_t buf[MAX_DHCPV6_PKT_SIZE];
851         unsigned char *ptr;
852         int ret, max_buf;
853
854         memset(buf, 0, sizeof(buf));
855         packet = (struct dhcpv6_packet *)&buf[0];
856         ptr = buf + sizeof(struct dhcpv6_packet);
857
858         init_packet(dhcp_client, packet, type);
859
860         if (dhcp_client->retransmit == FALSE) {
861                 dhcp_client->xid = packet->transaction_id[0] << 16 |
862                                 packet->transaction_id[1] << 8 |
863                                 packet->transaction_id[2];
864                 gettimeofday(&dhcp_client->start_time, NULL);
865         } else {
866                 packet->transaction_id[0] = dhcp_client->xid >> 16;
867                 packet->transaction_id[1] = dhcp_client->xid >> 8 ;
868                 packet->transaction_id[2] = dhcp_client->xid;
869         }
870
871         g_dhcp_client_set_request(dhcp_client, G_DHCPV6_ELAPSED_TIME);
872
873         debug(dhcp_client, "sending DHCPv6 %s message xid 0x%04x", msg,
874                                                         dhcp_client->xid);
875
876         max_buf = MAX_DHCPV6_PKT_SIZE - sizeof(struct dhcpv6_packet);
877
878         add_dhcpv6_request_options(dhcp_client, packet, buf, max_buf, &ptr);
879
880         add_dhcpv6_send_options(dhcp_client, buf, max_buf, &ptr);
881
882         ret = dhcpv6_send_packet(dhcp_client->ifindex, packet, ptr - buf);
883
884         debug(dhcp_client, "sent %d pkt %p len %d", ret, packet, ptr - buf);
885         return ret;
886 }
887
888 static int send_solicitation(GDHCPClient *dhcp_client)
889 {
890         return send_dhcpv6_msg(dhcp_client, DHCPV6_SOLICIT, "solicit");
891 }
892
893 static int send_dhcpv6_request(GDHCPClient *dhcp_client)
894 {
895         return send_dhcpv6_msg(dhcp_client, DHCPV6_REQUEST, "request");
896 }
897
898 static int send_dhcpv6_renew(GDHCPClient *dhcp_client)
899 {
900         return send_dhcpv6_msg(dhcp_client, DHCPV6_RENEW, "renew");
901 }
902
903 static int send_dhcpv6_rebind(GDHCPClient *dhcp_client)
904 {
905         return send_dhcpv6_msg(dhcp_client, DHCPV6_REBIND, "rebind");
906 }
907
908 static int send_dhcpv6_release(GDHCPClient *dhcp_client)
909 {
910         return send_dhcpv6_msg(dhcp_client, DHCPV6_RELEASE, "release");
911 }
912
913 static int send_information_req(GDHCPClient *dhcp_client)
914 {
915         return send_dhcpv6_msg(dhcp_client, DHCPV6_INFORMATION_REQ,
916                                 "information-req");
917 }
918
919 static void remove_value(gpointer data, gpointer user_data)
920 {
921         char *value = data;
922         g_free(value);
923 }
924
925 static void remove_option_value(gpointer data)
926 {
927         GList *option_value = data;
928
929         g_list_foreach(option_value, remove_value, NULL);
930 }
931
932 GDHCPClient *g_dhcp_client_new(GDHCPType type,
933                         int ifindex, GDHCPClientError *error)
934 {
935         GDHCPClient *dhcp_client;
936
937         if (ifindex < 0) {
938                 *error = G_DHCP_CLIENT_ERROR_INVALID_INDEX;
939                 return NULL;
940         }
941
942         dhcp_client = g_try_new0(GDHCPClient, 1);
943         if (dhcp_client == NULL) {
944                 *error = G_DHCP_CLIENT_ERROR_NOMEM;
945                 return NULL;
946         }
947
948         dhcp_client->interface = get_interface_name(ifindex);
949         if (dhcp_client->interface == NULL) {
950                 *error = G_DHCP_CLIENT_ERROR_INTERFACE_UNAVAILABLE;
951                 goto error;
952         }
953
954         if (interface_is_up(ifindex) == FALSE) {
955                 *error = G_DHCP_CLIENT_ERROR_INTERFACE_DOWN;
956                 goto error;
957         }
958
959         get_interface_mac_address(ifindex, dhcp_client->mac_address);
960
961         dhcp_client->listener_sockfd = -1;
962         dhcp_client->listener_channel = NULL;
963         dhcp_client->listen_mode = L_NONE;
964         dhcp_client->ref_count = 1;
965         dhcp_client->type = type;
966         dhcp_client->ifindex = ifindex;
967         dhcp_client->lease_available_cb = NULL;
968         dhcp_client->ipv4ll_available_cb = NULL;
969         dhcp_client->no_lease_cb = NULL;
970         dhcp_client->lease_lost_cb = NULL;
971         dhcp_client->ipv4ll_lost_cb = NULL;
972         dhcp_client->address_conflict_cb = NULL;
973         dhcp_client->listener_watch = 0;
974         dhcp_client->retry_times = 0;
975         dhcp_client->ack_retry_times = 0;
976         dhcp_client->code_value_hash = g_hash_table_new_full(g_direct_hash,
977                                 g_direct_equal, NULL, remove_option_value);
978         dhcp_client->send_value_hash = g_hash_table_new_full(g_direct_hash,
979                                 g_direct_equal, NULL, g_free);
980         dhcp_client->request_list = NULL;
981         dhcp_client->require_list = NULL;
982         dhcp_client->duid = NULL;
983         dhcp_client->duid_len = 0;
984         dhcp_client->last_renew = dhcp_client->last_rebind = time(NULL);
985         dhcp_client->expire = 0;
986
987         *error = G_DHCP_CLIENT_ERROR_NONE;
988
989         return dhcp_client;
990
991 error:
992         g_free(dhcp_client->interface);
993         g_free(dhcp_client);
994         return NULL;
995 }
996
997 #define SERVER_AND_CLIENT_PORTS  ((67 << 16) + 68)
998
999 static int dhcp_l2_socket(int ifindex)
1000 {
1001         int fd;
1002         struct sockaddr_ll sock;
1003
1004         /*
1005          * Comment:
1006          *
1007          *      I've selected not to see LL header, so BPF doesn't see it, too.
1008          *      The filter may also pass non-IP and non-ARP packets, but we do
1009          *      a more complete check when receiving the message in userspace.
1010          *
1011          * and filter shamelessly stolen from:
1012          *
1013          *      http://www.flamewarmaster.de/software/dhcpclient/
1014          *
1015          * There are a few other interesting ideas on that page (look under
1016          * "Motivation").  Use of netlink events is most interesting.  Think
1017          * of various network servers listening for events and reconfiguring.
1018          * That would obsolete sending HUP signals and/or make use of restarts.
1019          *
1020          * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
1021          * License: GPL v2.
1022          *
1023          * TODO: make conditional?
1024          */
1025         static const struct sock_filter filter_instr[] = {
1026                 /* check for udp */
1027                 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
1028                 /* L5, L1, is UDP? */
1029                 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 2, 0),
1030                 /* ugly check for arp on ethernet-like and IPv4 */
1031                 BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2), /* L1: */
1032                 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x08000604, 3, 4),/* L3, L4 */
1033                 /* skip IP header */
1034                 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), /* L5: */
1035                 /* check udp source and destination ports */
1036                 BPF_STMT(BPF_LD|BPF_W|BPF_IND, 0),
1037                 /* L3, L4 */
1038                 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_AND_CLIENT_PORTS, 0, 1),
1039                 /* returns */
1040                 BPF_STMT(BPF_RET|BPF_K, 0x0fffffff), /* L3: pass */
1041                 BPF_STMT(BPF_RET|BPF_K, 0), /* L4: reject */
1042         };
1043
1044         static const struct sock_fprog filter_prog = {
1045                 .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
1046                 /* casting const away: */
1047                 .filter = (struct sock_filter *) filter_instr,
1048         };
1049
1050         fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_IP));
1051         if (fd < 0)
1052                 return fd;
1053
1054         if (SERVER_PORT == 67 && CLIENT_PORT == 68)
1055                 /* Use only if standard ports are in use */
1056                 setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
1057                                                         sizeof(filter_prog));
1058
1059         memset(&sock, 0, sizeof(sock));
1060         sock.sll_family = AF_PACKET;
1061         sock.sll_protocol = htons(ETH_P_IP);
1062         sock.sll_ifindex = ifindex;
1063
1064         if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) != 0) {
1065                 close(fd);
1066                 return -errno;
1067         }
1068
1069         return fd;
1070 }
1071
1072 static gboolean sanity_check(struct ip_udp_dhcp_packet *packet, int bytes)
1073 {
1074         if (packet->ip.protocol != IPPROTO_UDP)
1075                 return FALSE;
1076
1077         if (packet->ip.version != IPVERSION)
1078                 return FALSE;
1079
1080         if (packet->ip.ihl != sizeof(packet->ip) >> 2)
1081                 return FALSE;
1082
1083         if (packet->udp.dest != htons(CLIENT_PORT))
1084                 return FALSE;
1085
1086         if (ntohs(packet->udp.len) != (uint16_t)(bytes - sizeof(packet->ip)))
1087                 return FALSE;
1088
1089         return TRUE;
1090 }
1091
1092 static int dhcp_recv_l2_packet(struct dhcp_packet *dhcp_pkt, int fd)
1093 {
1094         int bytes;
1095         struct ip_udp_dhcp_packet packet;
1096         uint16_t check;
1097
1098         memset(&packet, 0, sizeof(packet));
1099
1100         bytes = read(fd, &packet, sizeof(packet));
1101         if (bytes < 0)
1102                 return -1;
1103
1104         if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp)))
1105                 return -1;
1106
1107         if (bytes < ntohs(packet.ip.tot_len))
1108                 /* packet is bigger than sizeof(packet), we did partial read */
1109                 return -1;
1110
1111         /* ignore any extra garbage bytes */
1112         bytes = ntohs(packet.ip.tot_len);
1113
1114         if (sanity_check(&packet, bytes) == FALSE)
1115                 return -1;
1116
1117         check = packet.ip.check;
1118         packet.ip.check = 0;
1119         if (check != dhcp_checksum(&packet.ip, sizeof(packet.ip)))
1120                 return -1;
1121
1122         /* verify UDP checksum. IP header has to be modified for this */
1123         memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
1124         /* ip.xx fields which are not memset: protocol, check, saddr, daddr */
1125         packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
1126         check = packet.udp.check;
1127         packet.udp.check = 0;
1128         if (check && check != dhcp_checksum(&packet, bytes))
1129                 return -1;
1130
1131         memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) +
1132                                                         sizeof(packet.udp)));
1133
1134         if (dhcp_pkt->cookie != htonl(DHCP_MAGIC))
1135                 return -1;
1136
1137         return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
1138 }
1139
1140 static void ipv4ll_start(GDHCPClient *dhcp_client)
1141 {
1142         guint timeout;
1143         int seed;
1144
1145         if (dhcp_client->timeout > 0) {
1146                 g_source_remove(dhcp_client->timeout);
1147                 dhcp_client->timeout = 0;
1148         }
1149
1150         switch_listening_mode(dhcp_client, L_NONE);
1151         dhcp_client->type = G_DHCP_IPV4LL;
1152         dhcp_client->retry_times = 0;
1153         dhcp_client->requested_ip = 0;
1154
1155         /*try to start with a based mac address ip*/
1156         seed = (dhcp_client->mac_address[4] << 8 | dhcp_client->mac_address[4]);
1157         dhcp_client->requested_ip = ipv4ll_random_ip(seed);
1158
1159         /*first wait a random delay to avoid storm of arp request on boot*/
1160         timeout = ipv4ll_random_delay_ms(PROBE_WAIT);
1161
1162         dhcp_client->retry_times++;
1163         dhcp_client->timeout = g_timeout_add_full(G_PRIORITY_HIGH,
1164                                                 timeout,
1165                                                 send_probe_packet,
1166                                                 dhcp_client,
1167                                                 NULL);
1168 }
1169
1170 static void ipv4ll_stop(GDHCPClient *dhcp_client)
1171 {
1172
1173         switch_listening_mode(dhcp_client, L_NONE);
1174
1175         if (dhcp_client->timeout > 0)
1176                 g_source_remove(dhcp_client->timeout);
1177
1178         if (dhcp_client->listener_watch > 0) {
1179                 g_source_remove(dhcp_client->listener_watch);
1180                 dhcp_client->listener_watch = 0;
1181         }
1182
1183         dhcp_client->state = IPV4LL_PROBE;
1184         dhcp_client->retry_times = 0;
1185         dhcp_client->requested_ip = 0;
1186
1187         g_free(dhcp_client->assigned_ip);
1188         dhcp_client->assigned_ip = NULL;
1189 }
1190
1191 static int ipv4ll_recv_arp_packet(GDHCPClient *dhcp_client)
1192 {
1193         int bytes;
1194         struct ether_arp arp;
1195         uint32_t ip_requested;
1196         int source_conflict;
1197         int target_conflict;
1198
1199         memset(&arp, 0, sizeof(arp));
1200         bytes = read(dhcp_client->listener_sockfd, &arp, sizeof(arp));
1201         if (bytes < 0)
1202                 return bytes;
1203
1204         if (arp.arp_op != htons(ARPOP_REPLY) &&
1205                         arp.arp_op != htons(ARPOP_REQUEST))
1206                 return -EINVAL;
1207
1208         ip_requested = htonl(dhcp_client->requested_ip);
1209         source_conflict = !memcmp(arp.arp_spa, &ip_requested,
1210                                                 sizeof(ip_requested));
1211
1212         target_conflict = !memcmp(arp.arp_tpa, &ip_requested,
1213                                 sizeof(ip_requested));
1214
1215         if (!source_conflict && !target_conflict)
1216                 return 0;
1217
1218         dhcp_client->conflicts++;
1219
1220         debug(dhcp_client, "IPV4LL conflict detected");
1221
1222         if (dhcp_client->state == IPV4LL_MONITOR) {
1223                 if (!source_conflict)
1224                         return 0;
1225                 dhcp_client->state = IPV4LL_DEFEND;
1226                 debug(dhcp_client, "DEFEND mode conflicts : %d",
1227                         dhcp_client->conflicts);
1228                 /*Try to defend with a single announce*/
1229                 send_announce_packet(dhcp_client);
1230                 return 0;
1231         }
1232
1233         if (dhcp_client->state == IPV4LL_DEFEND) {
1234                 if (!source_conflict)
1235                         return 0;
1236                 else if (dhcp_client->ipv4ll_lost_cb != NULL)
1237                         dhcp_client->ipv4ll_lost_cb(dhcp_client,
1238                                                 dhcp_client->ipv4ll_lost_data);
1239         }
1240
1241         ipv4ll_stop(dhcp_client);
1242
1243         if (dhcp_client->conflicts < MAX_CONFLICTS) {
1244                 /*restart whole state machine*/
1245                 dhcp_client->retry_times++;
1246                 dhcp_client->timeout =
1247                         g_timeout_add_full(G_PRIORITY_HIGH,
1248                                         ipv4ll_random_delay_ms(PROBE_WAIT),
1249                                         send_probe_packet,
1250                                         dhcp_client,
1251                                         NULL);
1252         }
1253         /* Here we got a lot of conflicts, RFC3927 states that we have
1254          * to wait RATE_LIMIT_INTERVAL before retrying,
1255          * but we just report failure.
1256          */
1257         else if (dhcp_client->no_lease_cb != NULL)
1258                         dhcp_client->no_lease_cb(dhcp_client,
1259                                                 dhcp_client->no_lease_data);
1260
1261         return 0;
1262 }
1263
1264 static gboolean check_package_owner(GDHCPClient *dhcp_client, gpointer pkt)
1265 {
1266         if (dhcp_client->type == G_DHCP_IPV6) {
1267                 struct dhcpv6_packet *packet6 = pkt;
1268                 uint32_t xid;
1269
1270                 if (packet6 == NULL)
1271                         return FALSE;
1272
1273                 xid = packet6->transaction_id[0] << 16 |
1274                         packet6->transaction_id[1] << 8 |
1275                         packet6->transaction_id[2];
1276
1277                 if (xid != dhcp_client->xid)
1278                         return FALSE;
1279         } else {
1280                 struct dhcp_packet *packet = pkt;
1281
1282                 if (packet->xid != dhcp_client->xid)
1283                         return FALSE;
1284
1285                 if (packet->hlen != 6)
1286                         return FALSE;
1287
1288                 if (memcmp(packet->chaddr, dhcp_client->mac_address, 6))
1289                         return FALSE;
1290         }
1291
1292         return TRUE;
1293 }
1294
1295 static void start_request(GDHCPClient *dhcp_client);
1296
1297 static gboolean request_timeout(gpointer user_data)
1298 {
1299         GDHCPClient *dhcp_client = user_data;
1300
1301         debug(dhcp_client, "request timeout (retries %d)",
1302                                         dhcp_client->retry_times);
1303
1304         dhcp_client->retry_times++;
1305
1306         start_request(dhcp_client);
1307
1308         return FALSE;
1309 }
1310
1311 static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
1312                                                         gpointer user_data);
1313
1314 static int switch_listening_mode(GDHCPClient *dhcp_client,
1315                                         ListenMode listen_mode)
1316 {
1317         GIOChannel *listener_channel;
1318         int listener_sockfd;
1319
1320         if (dhcp_client->listen_mode == listen_mode)
1321                 return 0;
1322
1323         debug(dhcp_client, "switch listening mode (%d ==> %d)",
1324                                 dhcp_client->listen_mode, listen_mode);
1325
1326         if (dhcp_client->listen_mode != L_NONE) {
1327                 if (dhcp_client->listener_watch > 0)
1328                         g_source_remove(dhcp_client->listener_watch);
1329                 dhcp_client->listener_channel = NULL;
1330                 dhcp_client->listen_mode = L_NONE;
1331                 dhcp_client->listener_sockfd = -1;
1332                 dhcp_client->listener_watch = 0;
1333         }
1334
1335         if (listen_mode == L_NONE)
1336                 return 0;
1337
1338         if (listen_mode == L2)
1339                 listener_sockfd = dhcp_l2_socket(dhcp_client->ifindex);
1340         else if (listen_mode == L3) {
1341                 if (dhcp_client->type == G_DHCP_IPV6)
1342                         listener_sockfd = dhcp_l3_socket(DHCPV6_CLIENT_PORT,
1343                                                         dhcp_client->interface,
1344                                                         AF_INET6);
1345                 else
1346                         listener_sockfd = dhcp_l3_socket(CLIENT_PORT,
1347                                                         dhcp_client->interface,
1348                                                         AF_INET);
1349         } else if (listen_mode == L_ARP)
1350                 listener_sockfd = ipv4ll_arp_socket(dhcp_client->ifindex);
1351         else
1352                 return -EIO;
1353
1354         if (listener_sockfd < 0)
1355                 return -EIO;
1356
1357         listener_channel = g_io_channel_unix_new(listener_sockfd);
1358         if (listener_channel == NULL) {
1359                 /* Failed to create listener channel */
1360                 close(listener_sockfd);
1361                 return -EIO;
1362         }
1363
1364         dhcp_client->listen_mode = listen_mode;
1365         dhcp_client->listener_sockfd = listener_sockfd;
1366         dhcp_client->listener_channel = listener_channel;
1367
1368         g_io_channel_set_close_on_unref(listener_channel, TRUE);
1369         dhcp_client->listener_watch =
1370                         g_io_add_watch_full(listener_channel, G_PRIORITY_HIGH,
1371                                 G_IO_IN | G_IO_NVAL | G_IO_ERR | G_IO_HUP,
1372                                                 listener_event, dhcp_client,
1373                                                                 NULL);
1374         g_io_channel_unref(dhcp_client->listener_channel);
1375
1376         return 0;
1377 }
1378
1379 static void start_request(GDHCPClient *dhcp_client)
1380 {
1381         debug(dhcp_client, "start request (retries %d)",
1382                                         dhcp_client->retry_times);
1383
1384         if (dhcp_client->retry_times == REQUEST_RETRIES) {
1385                 dhcp_client->state = INIT_SELECTING;
1386                 ipv4ll_start(dhcp_client);
1387
1388                 return;
1389         }
1390
1391         if (dhcp_client->retry_times == 0) {
1392                 dhcp_client->state = REQUESTING;
1393                 switch_listening_mode(dhcp_client, L2);
1394         }
1395
1396         send_select(dhcp_client);
1397
1398         dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
1399                                                         REQUEST_TIMEOUT,
1400                                                         request_timeout,
1401                                                         dhcp_client,
1402                                                         NULL);
1403 }
1404
1405 static uint32_t get_lease(struct dhcp_packet *packet)
1406 {
1407         uint8_t *option;
1408         uint32_t lease_seconds;
1409
1410         option = dhcp_get_option(packet, DHCP_LEASE_TIME);
1411         if (option == NULL)
1412                 return 3600;
1413
1414         lease_seconds = get_be32(option);
1415         /* paranoia: must not be prone to overflows */
1416         lease_seconds &= 0x0fffffff;
1417         if (lease_seconds < 10)
1418                 lease_seconds = 10;
1419
1420         return lease_seconds;
1421 }
1422
1423 static void restart_dhcp(GDHCPClient *dhcp_client, int retry_times)
1424 {
1425         debug(dhcp_client, "restart DHCP (retries %d)", retry_times);
1426
1427         if (dhcp_client->timeout > 0) {
1428                 g_source_remove(dhcp_client->timeout);
1429                 dhcp_client->timeout = 0;
1430         }
1431
1432         dhcp_client->retry_times = retry_times;
1433         dhcp_client->requested_ip = 0;
1434         dhcp_client->state = INIT_SELECTING;
1435         switch_listening_mode(dhcp_client, L2);
1436
1437         g_dhcp_client_start(dhcp_client, dhcp_client->last_address);
1438 }
1439
1440 static gboolean start_rebound_timeout(gpointer user_data)
1441 {
1442         GDHCPClient *dhcp_client = user_data;
1443
1444         debug(dhcp_client, "start rebound timeout");
1445
1446         switch_listening_mode(dhcp_client, L2);
1447
1448         dhcp_client->lease_seconds >>= 1;
1449
1450         /* We need to have enough time to receive ACK package*/
1451         if (dhcp_client->lease_seconds <= 6) {
1452
1453                 /* ip need to be cleared */
1454                 if (dhcp_client->lease_lost_cb != NULL)
1455                         dhcp_client->lease_lost_cb(dhcp_client,
1456                                         dhcp_client->lease_lost_data);
1457
1458                 restart_dhcp(dhcp_client, 0);
1459         } else {
1460                 send_rebound(dhcp_client);
1461
1462                 dhcp_client->timeout =
1463                                 g_timeout_add_seconds_full(G_PRIORITY_HIGH,
1464                                                 dhcp_client->lease_seconds >> 1,
1465                                                         start_rebound_timeout,
1466                                                                 dhcp_client,
1467                                                                 NULL);
1468         }
1469
1470         return FALSE;
1471 }
1472
1473 static void start_rebound(GDHCPClient *dhcp_client)
1474 {
1475         debug(dhcp_client, "start rebound");
1476
1477         dhcp_client->state = REBINDING;
1478
1479         dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
1480                                                 dhcp_client->lease_seconds >> 1,
1481                                                         start_rebound_timeout,
1482                                                                 dhcp_client,
1483                                                                 NULL);
1484 }
1485
1486 static gboolean start_renew_timeout(gpointer user_data)
1487 {
1488         GDHCPClient *dhcp_client = user_data;
1489
1490         debug(dhcp_client, "start renew timeout");
1491
1492         dhcp_client->state = RENEWING;
1493
1494         dhcp_client->lease_seconds >>= 1;
1495
1496         switch_listening_mode(dhcp_client, L3);
1497         if (dhcp_client->lease_seconds <= 60)
1498                 start_rebound(dhcp_client);
1499         else {
1500                 send_renew(dhcp_client);
1501
1502                 if (dhcp_client->timeout > 0)
1503                         g_source_remove(dhcp_client->timeout);
1504
1505                 dhcp_client->timeout =
1506                                 g_timeout_add_seconds_full(G_PRIORITY_HIGH,
1507                                                 dhcp_client->lease_seconds >> 1,
1508                                                         start_renew_timeout,
1509                                                                 dhcp_client,
1510                                                                 NULL);
1511         }
1512
1513         return FALSE;
1514 }
1515
1516 static void start_bound(GDHCPClient *dhcp_client)
1517 {
1518         debug(dhcp_client, "start bound");
1519
1520         dhcp_client->state = BOUND;
1521
1522         if (dhcp_client->timeout > 0)
1523                 g_source_remove(dhcp_client->timeout);
1524
1525         dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
1526                                         dhcp_client->lease_seconds >> 1,
1527                                         start_renew_timeout, dhcp_client,
1528                                                         NULL);
1529 }
1530
1531 static gboolean restart_dhcp_timeout(gpointer user_data)
1532 {
1533         GDHCPClient *dhcp_client = user_data;
1534
1535         debug(dhcp_client, "restart DHCP timeout");
1536
1537         dhcp_client->ack_retry_times++;
1538
1539         restart_dhcp(dhcp_client, dhcp_client->ack_retry_times);
1540
1541         return FALSE;
1542 }
1543
1544 static char *get_ip(uint32_t ip)
1545 {
1546         struct in_addr addr;
1547
1548         addr.s_addr = ip;
1549
1550         return g_strdup(inet_ntoa(addr));
1551 }
1552
1553 /* get a rough idea of how long an option will be */
1554 static const uint8_t len_of_option_as_string[] = {
1555         [OPTION_IP] = sizeof("255.255.255.255 "),
1556         [OPTION_STRING] = 1,
1557         [OPTION_U8] = sizeof("255 "),
1558         [OPTION_U16] = sizeof("65535 "),
1559         [OPTION_U32] = sizeof("4294967295 "),
1560 };
1561
1562 static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
1563 {
1564         return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
1565 }
1566
1567 /* Create "opt_value1 option_value2 ..." string */
1568 static char *malloc_option_value_string(uint8_t *option, GDHCPOptionType type)
1569 {
1570         unsigned upper_length;
1571         int len, optlen;
1572         char *dest, *ret;
1573
1574         len = option[OPT_LEN - OPT_DATA];
1575         type &= OPTION_TYPE_MASK;
1576         optlen = dhcp_option_lengths[type];
1577         if (optlen == 0)
1578                 return NULL;
1579         upper_length = len_of_option_as_string[type] *
1580                         ((unsigned)len / (unsigned)optlen);
1581         dest = ret = g_malloc(upper_length + 1);
1582         if (ret == NULL)
1583                 return NULL;
1584
1585         while (len >= optlen) {
1586                 switch (type) {
1587                 case OPTION_IP:
1588                         dest += sprint_nip(dest, "", option);
1589                         break;
1590                 case OPTION_U16: {
1591                         uint16_t val_u16 = get_be16(option);
1592                         dest += sprintf(dest, "%u", val_u16);
1593                         break;
1594                 }
1595                 case OPTION_U32: {
1596                         uint32_t val_u32 = get_be32(option);
1597                         dest += sprintf(dest, "%u", val_u32);
1598                         break;
1599                 }
1600                 case OPTION_STRING:
1601                         memcpy(dest, option, len);
1602                         dest[len] = '\0';
1603                         return ret;
1604                 default:
1605                         break;
1606                 }
1607                 option += optlen;
1608                 len -= optlen;
1609                 if (len <= 0)
1610                         break;
1611                 *dest++ = ' ';
1612                 *dest = '\0';
1613         }
1614
1615         return ret;
1616 }
1617
1618 static GList *get_option_value_list(char *value, GDHCPOptionType type)
1619 {
1620         char *pos = value;
1621         GList *list = NULL;
1622
1623         if (pos == NULL)
1624                 return NULL;
1625
1626         if (type == OPTION_STRING)
1627                 return g_list_append(list, g_strdup(value));
1628
1629         while ((pos = strchr(pos, ' ')) != NULL) {
1630                 *pos = '\0';
1631
1632                 list = g_list_append(list, g_strdup(value));
1633
1634                 value = ++pos;
1635         }
1636
1637         list = g_list_append(list, g_strdup(value));
1638
1639         return list;
1640 }
1641
1642 static inline uint32_t get_uint32(unsigned char *value)
1643 {
1644         return value[0] << 24 | value[1] << 16 |
1645                 value[2] << 8 | value[3];
1646 }
1647
1648 static inline uint16_t get_uint16(unsigned char *value)
1649 {
1650         return value[0] << 8 | value[1];
1651 }
1652
1653 static GList *get_addresses(GDHCPClient *dhcp_client,
1654                                 int code, int len,
1655                                 unsigned char *value,
1656                                 uint16_t *status)
1657 {
1658         GList *list = NULL;
1659         struct in6_addr addr;
1660         uint32_t iaid, T1 = 0, T2 = 0, preferred = 0, valid = 0;
1661         uint16_t option_len, option_code, st = 0, max_len;
1662         int addr_count = 0, i, pos;
1663         uint8_t *option;
1664         char *str;
1665
1666         if (value == NULL || len < 4)
1667                 return NULL;
1668
1669         iaid = get_uint32(&value[0]);
1670         if (dhcp_client->iaid != iaid)
1671                 return NULL;
1672
1673         if (code == G_DHCPV6_IA_NA) {
1674                 T1 = get_uint32(&value[4]);
1675                 T2 = get_uint32(&value[8]);
1676
1677                 if (T1 > T2)
1678                         /* RFC 3315, 22.4 */
1679                         return NULL;
1680
1681                 pos = 12;
1682         } else
1683                 pos = 4;
1684
1685         if (len <= pos)
1686                 return NULL;
1687
1688         max_len = len - pos;
1689
1690         /* We have more sub-options in this packet. */
1691         do {
1692                 option = dhcpv6_get_sub_option(&value[pos], max_len,
1693                                         &option_code, &option_len);
1694
1695                 debug(dhcp_client, "pos %d option %p code %d len %d",
1696                         pos, option, option_code, option_len);
1697
1698                 if (option == NULL)
1699                         break;
1700
1701                 if (pos >= max_len)
1702                         break;
1703
1704                 switch (option_code) {
1705                 case G_DHCPV6_IAADDR:
1706                         i = 0;
1707                         memcpy(&addr, &option[0], sizeof(addr));
1708                         i += sizeof(addr);
1709                         preferred = get_uint32(&option[i]);
1710                         i += 4;
1711                         valid = get_uint32(&option[i]);
1712
1713                         addr_count++;
1714                         break;
1715
1716                 case G_DHCPV6_STATUS_CODE:
1717                         st = get_uint16(&option[0]);
1718                         debug(dhcp_client, "error code %d", st);
1719                         if (option_len > 2) {
1720                                 str = g_strndup((gchar *)&option[2],
1721                                                 option_len - 2);
1722                                 debug(dhcp_client, "error text: %s", str);
1723                                 g_free(str);
1724                         }
1725
1726                         *status = st;
1727                         break;
1728                 }
1729
1730                 pos += 2 + 2 + option_len;
1731
1732         } while (option != NULL);
1733
1734         if (addr_count > 0 && st == 0) {
1735                 /* We only support one address atm */
1736                 char addr_str[INET6_ADDRSTRLEN + 1];
1737
1738                 if (preferred > valid)
1739                         /* RFC 3315, 22.6 */
1740                         return NULL;
1741
1742                 dhcp_client->T1 = T1;
1743                 dhcp_client->T2 = T2;
1744
1745                 inet_ntop(AF_INET6, &addr, addr_str, INET6_ADDRSTRLEN);
1746                 debug(dhcp_client, "count %d addr %s T1 %u T2 %u",
1747                         addr_count, addr_str, T1, T2);
1748
1749                 list = g_list_append(list, g_strdup(addr_str));
1750
1751                 if (code == G_DHCPV6_IA_NA)
1752                         memcpy(&dhcp_client->ia_na, &addr,
1753                                                 sizeof(struct in6_addr));
1754                 else
1755                         memcpy(&dhcp_client->ia_ta, &addr,
1756                                                 sizeof(struct in6_addr));
1757
1758                 g_dhcpv6_client_set_expire(dhcp_client, valid);
1759         }
1760
1761         return list;
1762 }
1763
1764 static GList *get_dhcpv6_option_value_list(GDHCPClient *dhcp_client,
1765                                         int code, int len,
1766                                         unsigned char *value,
1767                                         uint16_t *status)
1768 {
1769         GList *list = NULL;
1770         char *str;
1771         int i;
1772
1773         if (value == NULL)
1774                 return NULL;
1775
1776         switch (code) {
1777         case G_DHCPV6_DNS_SERVERS:      /* RFC 3646, chapter 3 */
1778         case G_DHCPV6_SNTP_SERVERS:     /* RFC 4075, chapter 4 */
1779                 if (len % 16) {
1780                         debug(dhcp_client,
1781                                 "%s server list length (%d) is invalid",
1782                                 code == G_DHCPV6_DNS_SERVERS ? "DNS" : "SNTP",
1783                                 len);
1784                         return NULL;
1785                 }
1786                 for (i = 0; i < len; i += 16) {
1787
1788                         str = g_try_malloc0(INET6_ADDRSTRLEN+1);
1789                         if (str == NULL)
1790                                 return list;
1791
1792                         if (inet_ntop(AF_INET6, &value[i], str,
1793                                         INET6_ADDRSTRLEN) == NULL)
1794                                 g_free(str);
1795                         else
1796                                 list = g_list_append(list, str);
1797                 }
1798                 break;
1799
1800         case G_DHCPV6_IA_NA:            /* RFC 3315, chapter 22.4 */
1801         case G_DHCPV6_IA_TA:            /* RFC 3315, chapter 22.5 */
1802                 list = get_addresses(dhcp_client, code, len, value, status);
1803                 break;
1804
1805         default:
1806                 break;
1807         }
1808
1809         return list;
1810 }
1811
1812 static void get_dhcpv6_request(GDHCPClient *dhcp_client,
1813                                 struct dhcpv6_packet *packet,
1814                                 uint16_t pkt_len, uint16_t *status)
1815 {
1816         GList *list, *value_list;
1817         uint8_t *option;
1818         uint16_t code;
1819         uint16_t option_len;
1820
1821         for (list = dhcp_client->request_list; list; list = list->next) {
1822                 code = (uint16_t) GPOINTER_TO_INT(list->data);
1823
1824                 option = dhcpv6_get_option(packet, pkt_len, code, &option_len,
1825                                                 NULL);
1826                 if (option == NULL) {
1827                         g_hash_table_remove(dhcp_client->code_value_hash,
1828                                                 GINT_TO_POINTER((int) code));
1829                         continue;
1830                 }
1831
1832                 value_list = get_dhcpv6_option_value_list(dhcp_client, code,
1833                                                 option_len, option, status);
1834
1835                 debug(dhcp_client, "code %d %p len %d list %p", code, option,
1836                         option_len, value_list);
1837
1838                 if (value_list == NULL)
1839                         g_hash_table_remove(dhcp_client->code_value_hash,
1840                                                 GINT_TO_POINTER((int) code));
1841                 else
1842                         g_hash_table_insert(dhcp_client->code_value_hash,
1843                                 GINT_TO_POINTER((int) code), value_list);
1844         }
1845 }
1846
1847 static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet)
1848 {
1849         GDHCPOptionType type;
1850         GList *list, *value_list;
1851         char *option_value;
1852         uint8_t *option;
1853         uint8_t code;
1854
1855         for (list = dhcp_client->request_list; list; list = list->next) {
1856                 code = (uint8_t) GPOINTER_TO_INT(list->data);
1857
1858                 option = dhcp_get_option(packet, code);
1859                 if (option == NULL) {
1860                         g_hash_table_remove(dhcp_client->code_value_hash,
1861                                                 GINT_TO_POINTER((int) code));
1862                         continue;
1863                 }
1864
1865                 type =  dhcp_get_code_type(code);
1866
1867                 option_value = malloc_option_value_string(option, type);
1868                 if (option_value == NULL)
1869                         g_hash_table_remove(dhcp_client->code_value_hash,
1870                                                 GINT_TO_POINTER((int) code));
1871
1872                 value_list = get_option_value_list(option_value, type);
1873
1874                 g_free(option_value);
1875
1876                 if (value_list == NULL)
1877                         g_hash_table_remove(dhcp_client->code_value_hash,
1878                                                 GINT_TO_POINTER((int) code));
1879                 else
1880                         g_hash_table_insert(dhcp_client->code_value_hash,
1881                                 GINT_TO_POINTER((int) code), value_list);
1882         }
1883 }
1884
1885 static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
1886                                                         gpointer user_data)
1887 {
1888         GDHCPClient *dhcp_client = user_data;
1889         struct dhcp_packet packet;
1890         struct dhcpv6_packet *packet6 = NULL;
1891         uint8_t *message_type = NULL, *client_id = NULL, *option,
1892                 *server_id = NULL;
1893         uint16_t option_len = 0, status = 0;
1894         uint32_t xid = 0;
1895         gpointer pkt;
1896         unsigned char buf[MAX_DHCPV6_PKT_SIZE];
1897         uint16_t pkt_len = 0;
1898         int count;
1899         int re;
1900
1901         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
1902                 dhcp_client->listener_watch = 0;
1903                 return FALSE;
1904         }
1905
1906         if (dhcp_client->listen_mode == L_NONE)
1907                 return FALSE;
1908
1909         pkt = &packet;
1910
1911         if (dhcp_client->listen_mode == L2)
1912                 re = dhcp_recv_l2_packet(&packet,
1913                                         dhcp_client->listener_sockfd);
1914         else if (dhcp_client->listen_mode == L3) {
1915                 if (dhcp_client->type == G_DHCP_IPV6) {
1916                         re = dhcpv6_recv_l3_packet(&packet6, buf, sizeof(buf),
1917                                                 dhcp_client->listener_sockfd);
1918                         pkt_len = re;
1919                         pkt = packet6;
1920                         xid = packet6->transaction_id[0] << 16 |
1921                                 packet6->transaction_id[1] << 8 |
1922                                 packet6->transaction_id[2];
1923                 } else {
1924                         re = dhcp_recv_l3_packet(&packet,
1925                                                 dhcp_client->listener_sockfd);
1926                         xid = packet.xid;
1927                 }
1928         } else if (dhcp_client->listen_mode == L_ARP) {
1929                 ipv4ll_recv_arp_packet(dhcp_client);
1930                 return TRUE;
1931         }
1932         else
1933                 re = -EIO;
1934
1935         if (re < 0)
1936                 return TRUE;
1937
1938         if (check_package_owner(dhcp_client, pkt) == FALSE)
1939                 return TRUE;
1940
1941         if (dhcp_client->type == G_DHCP_IPV6) {
1942                 if (packet6 == NULL)
1943                         return TRUE;
1944
1945                 count = 0;
1946                 client_id = dhcpv6_get_option(packet6, pkt_len,
1947                                 G_DHCPV6_CLIENTID, &option_len, &count);
1948
1949                 if (client_id == NULL || count == 0 || option_len == 0 ||
1950                                 memcmp(dhcp_client->duid, client_id,
1951                                         dhcp_client->duid_len) != 0) {
1952                         debug(dhcp_client,
1953                                 "client duid error, discarding msg %p/%d/%d",
1954                                 client_id, option_len, count);
1955                         return TRUE;
1956                 }
1957
1958                 option = dhcpv6_get_option(packet6, pkt_len,
1959                                 G_DHCPV6_STATUS_CODE, &option_len, NULL);
1960                 if (option != 0 && option_len > 0) {
1961                         status = option[0]<<8 | option[1];
1962                         if (status != 0) {
1963                                 debug(dhcp_client, "error code %d", status);
1964                                 if (option_len > 2) {
1965                                         gchar *txt = g_strndup(
1966                                                 (gchar *)&option[2],
1967                                                 option_len - 2);
1968                                         debug(dhcp_client, "error text: %s",
1969                                                 txt);
1970                                         g_free(txt);
1971                                 }
1972                         }
1973                         dhcp_client->status_code = status;
1974                 } else
1975                         dhcp_client->status_code = 0;
1976
1977         } else {
1978                 message_type = dhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
1979                 if (message_type == NULL)
1980                         return TRUE;
1981         }
1982
1983         if (message_type == NULL && client_id == NULL)
1984                 /* No message type / client id option, ignore package */
1985                 return TRUE;
1986
1987         debug(dhcp_client, "received DHCP packet xid 0x%04x "
1988                         "(current state %d)", xid, dhcp_client->state);
1989
1990         switch (dhcp_client->state) {
1991         case INIT_SELECTING:
1992                 if (*message_type != DHCPOFFER)
1993                         return TRUE;
1994
1995                 g_source_remove(dhcp_client->timeout);
1996                 dhcp_client->timeout = 0;
1997                 dhcp_client->retry_times = 0;
1998
1999                 option = dhcp_get_option(&packet, DHCP_SERVER_ID);
2000                 dhcp_client->server_ip = get_be32(option);
2001                 dhcp_client->requested_ip = ntohl(packet.yiaddr);
2002
2003                 dhcp_client->state = REQUESTING;
2004
2005                 start_request(dhcp_client);
2006
2007                 return TRUE;
2008         case REQUESTING:
2009         case RENEWING:
2010         case REBINDING:
2011                 if (*message_type == DHCPACK) {
2012                         dhcp_client->retry_times = 0;
2013
2014                         if (dhcp_client->timeout > 0)
2015                                 g_source_remove(dhcp_client->timeout);
2016                         dhcp_client->timeout = 0;
2017
2018                         dhcp_client->lease_seconds = get_lease(&packet);
2019
2020                         get_request(dhcp_client, &packet);
2021
2022                         switch_listening_mode(dhcp_client, L_NONE);
2023
2024                         g_free(dhcp_client->assigned_ip);
2025                         dhcp_client->assigned_ip = get_ip(packet.yiaddr);
2026
2027                         /* Address should be set up here */
2028                         if (dhcp_client->lease_available_cb != NULL)
2029                                 dhcp_client->lease_available_cb(dhcp_client,
2030                                         dhcp_client->lease_available_data);
2031
2032                         start_bound(dhcp_client);
2033                 } else if (*message_type == DHCPNAK) {
2034                         dhcp_client->retry_times = 0;
2035
2036                         if (dhcp_client->timeout > 0)
2037                                 g_source_remove(dhcp_client->timeout);
2038
2039                         dhcp_client->timeout = g_timeout_add_seconds_full(
2040                                                         G_PRIORITY_HIGH, 3,
2041                                                         restart_dhcp_timeout,
2042                                                         dhcp_client,
2043                                                         NULL);
2044                 }
2045
2046                 break;
2047         case SOLICITATION:
2048                 if (dhcp_client->type != G_DHCP_IPV6)
2049                         return TRUE;
2050
2051                 if (packet6->message != DHCPV6_REPLY &&
2052                                 packet6->message != DHCPV6_ADVERTISE)
2053                         return TRUE;
2054
2055                 count = 0;
2056                 server_id = dhcpv6_get_option(packet6, pkt_len,
2057                                 G_DHCPV6_SERVERID, &option_len, &count);
2058                 if (server_id == NULL || count != 1 || option_len == 0) {
2059                         /* RFC 3315, 15.10 */
2060                         debug(dhcp_client,
2061                                 "server duid error, discarding msg %p/%d/%d",
2062                                 server_id, option_len, count);
2063                         return TRUE;
2064                 }
2065                 dhcp_client->server_duid = g_try_malloc(option_len);
2066                 if (dhcp_client->server_duid == NULL)
2067                         return TRUE;
2068                 memcpy(dhcp_client->server_duid, server_id, option_len);
2069                 dhcp_client->server_duid_len = option_len;
2070
2071                 if (packet6->message == DHCPV6_REPLY) {
2072                         uint8_t *rapid_commit;
2073                         count = 0;
2074                         option_len = 0;
2075                         rapid_commit = dhcpv6_get_option(packet6, pkt_len,
2076                                                         G_DHCPV6_RAPID_COMMIT,
2077                                                         &option_len, &count);
2078                         if (rapid_commit == NULL || option_len == 0 ||
2079                                                                 count != 1)
2080                                 /* RFC 3315, 17.1.4 */
2081                                 return TRUE;
2082                 }
2083
2084                 switch_listening_mode(dhcp_client, L_NONE);
2085
2086                 if (dhcp_client->status_code == 0)
2087                         get_dhcpv6_request(dhcp_client, packet6, pkt_len,
2088                                         &dhcp_client->status_code);
2089
2090                 if (packet6->message == DHCPV6_ADVERTISE) {
2091                         if (dhcp_client->advertise_cb != NULL)
2092                                 dhcp_client->advertise_cb(dhcp_client,
2093                                                 dhcp_client->advertise_data);
2094                         return TRUE;
2095                 }
2096
2097                 if (dhcp_client->solicitation_cb != NULL) {
2098                         /*
2099                          * The dhcp_client might not be valid after the
2100                          * callback call so just return immediately.
2101                          */
2102                         dhcp_client->solicitation_cb(dhcp_client,
2103                                         dhcp_client->solicitation_data);
2104                         return TRUE;
2105                 }
2106                 break;
2107         case INFORMATION_REQ:
2108         case REQUEST:
2109         case RENEW:
2110         case REBIND:
2111         case RELEASE:
2112                 if (dhcp_client->type != G_DHCP_IPV6)
2113                         return TRUE;
2114
2115                 if (packet6->message != DHCPV6_REPLY)
2116                         return TRUE;
2117
2118                 count = 0;
2119                 option_len = 0;
2120                 server_id = dhcpv6_get_option(packet6, pkt_len,
2121                                 G_DHCPV6_SERVERID, &option_len, &count);
2122                 if (server_id == NULL || count != 1 || option_len == 0 ||
2123                                 (dhcp_client->server_duid_len > 0 &&
2124                                 memcmp(dhcp_client->server_duid, server_id,
2125                                         dhcp_client->server_duid_len) != 0)) {
2126                         /* RFC 3315, 15.10 */
2127                         debug(dhcp_client,
2128                                 "server duid error, discarding msg %p/%d/%d",
2129                                 server_id, option_len, count);
2130                         return TRUE;
2131                 }
2132
2133                 switch_listening_mode(dhcp_client, L_NONE);
2134
2135                 dhcp_client->status_code = 0;
2136                 get_dhcpv6_request(dhcp_client, packet6, pkt_len,
2137                                                 &dhcp_client->status_code);
2138
2139                 if (dhcp_client->information_req_cb != NULL) {
2140                         /*
2141                          * The dhcp_client might not be valid after the
2142                          * callback call so just return immediately.
2143                          */
2144                         dhcp_client->information_req_cb(dhcp_client,
2145                                         dhcp_client->information_req_data);
2146                         return TRUE;
2147                 }
2148                 if (dhcp_client->request_cb != NULL) {
2149                         dhcp_client->request_cb(dhcp_client,
2150                                         dhcp_client->request_data);
2151                         return TRUE;
2152                 }
2153                 if (dhcp_client->renew_cb != NULL) {
2154                         dhcp_client->renew_cb(dhcp_client,
2155                                         dhcp_client->renew_data);
2156                         return TRUE;
2157                 }
2158                 if (dhcp_client->rebind_cb != NULL) {
2159                         dhcp_client->rebind_cb(dhcp_client,
2160                                         dhcp_client->rebind_data);
2161                         return TRUE;
2162                 }
2163                 if (dhcp_client->release_cb != NULL) {
2164                         dhcp_client->release_cb(dhcp_client,
2165                                         dhcp_client->release_data);
2166                         return TRUE;
2167                 }
2168                 break;
2169         default:
2170                 break;
2171         }
2172
2173         debug(dhcp_client, "processed DHCP packet (new state %d)",
2174                                                         dhcp_client->state);
2175
2176         return TRUE;
2177 }
2178
2179 static gboolean discover_timeout(gpointer user_data)
2180 {
2181         GDHCPClient *dhcp_client = user_data;
2182
2183         dhcp_client->retry_times++;
2184
2185         /*
2186          * We do not send the REQUESTED IP option if we are retrying because
2187          * if the server is non-authoritative it will ignore the request if the
2188          * option is present.
2189          */
2190         g_dhcp_client_start(dhcp_client, NULL);
2191
2192         return FALSE;
2193 }
2194
2195 static gboolean ipv4ll_defend_timeout(gpointer dhcp_data)
2196 {
2197         GDHCPClient *dhcp_client = dhcp_data;
2198
2199         debug(dhcp_client, "back to MONITOR mode");
2200
2201         dhcp_client->conflicts = 0;
2202         dhcp_client->state = IPV4LL_MONITOR;
2203
2204         return FALSE;
2205 }
2206
2207 static gboolean ipv4ll_announce_timeout(gpointer dhcp_data)
2208 {
2209         GDHCPClient *dhcp_client = dhcp_data;
2210         uint32_t ip;
2211
2212         debug(dhcp_client, "request timeout (retries %d)",
2213                dhcp_client->retry_times);
2214
2215         if (dhcp_client->retry_times != ANNOUNCE_NUM){
2216                 dhcp_client->retry_times++;
2217                 send_announce_packet(dhcp_client);
2218                 return FALSE;
2219         }
2220
2221         ip = htonl(dhcp_client->requested_ip);
2222         debug(dhcp_client, "switching to monitor mode");
2223         dhcp_client->state = IPV4LL_MONITOR;
2224         dhcp_client->assigned_ip = get_ip(ip);
2225
2226         if (dhcp_client->ipv4ll_available_cb != NULL)
2227                 dhcp_client->ipv4ll_available_cb(dhcp_client,
2228                                         dhcp_client->ipv4ll_available_data);
2229         dhcp_client->conflicts = 0;
2230
2231         return FALSE;
2232 }
2233
2234 static gboolean ipv4ll_probe_timeout(gpointer dhcp_data)
2235 {
2236
2237         GDHCPClient *dhcp_client = dhcp_data;
2238
2239         debug(dhcp_client, "IPV4LL probe timeout (retries %d)",
2240                dhcp_client->retry_times);
2241
2242         if (dhcp_client->retry_times == PROBE_NUM) {
2243                 dhcp_client->state = IPV4LL_ANNOUNCE;
2244                 dhcp_client->retry_times = 0;
2245
2246                 dhcp_client->retry_times++;
2247                 send_announce_packet(dhcp_client);
2248                 return FALSE;
2249         }
2250         dhcp_client->retry_times++;
2251         send_probe_packet(dhcp_client);
2252
2253         return FALSE;
2254 }
2255
2256 int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address)
2257 {
2258         int re;
2259         uint32_t addr;
2260
2261         if (dhcp_client->type == G_DHCP_IPV6) {
2262                 if (dhcp_client->information_req_cb) {
2263                         dhcp_client->state = INFORMATION_REQ;
2264                         re = switch_listening_mode(dhcp_client, L3);
2265                         if (re != 0) {
2266                                 switch_listening_mode(dhcp_client, L_NONE);
2267                                 dhcp_client->state = 0;
2268                                 return re;
2269                         }
2270                         send_information_req(dhcp_client);
2271
2272                 } else if (dhcp_client->solicitation_cb) {
2273                         dhcp_client->state = SOLICITATION;
2274                         re = switch_listening_mode(dhcp_client, L3);
2275                         if (re != 0) {
2276                                 switch_listening_mode(dhcp_client, L_NONE);
2277                                 dhcp_client->state = 0;
2278                                 return re;
2279                         }
2280                         send_solicitation(dhcp_client);
2281
2282                 } else if (dhcp_client->request_cb) {
2283                         dhcp_client->state = REQUEST;
2284                         re = switch_listening_mode(dhcp_client, L3);
2285                         if (re != 0) {
2286                                 switch_listening_mode(dhcp_client, L_NONE);
2287                                 dhcp_client->state = 0;
2288                                 return re;
2289                         }
2290                         send_dhcpv6_request(dhcp_client);
2291
2292                 } else if (dhcp_client->renew_cb) {
2293                         dhcp_client->state = RENEW;
2294                         re = switch_listening_mode(dhcp_client, L3);
2295                         if (re != 0) {
2296                                 switch_listening_mode(dhcp_client, L_NONE);
2297                                 dhcp_client->state = 0;
2298                                 return re;
2299                         }
2300                         send_dhcpv6_renew(dhcp_client);
2301
2302                 } else if (dhcp_client->rebind_cb) {
2303                         dhcp_client->state = REBIND;
2304                         re = switch_listening_mode(dhcp_client, L3);
2305                         if (re != 0) {
2306                                 switch_listening_mode(dhcp_client, L_NONE);
2307                                 dhcp_client->state = 0;
2308                                 return re;
2309                         }
2310                         send_dhcpv6_rebind(dhcp_client);
2311
2312                 } else if (dhcp_client->release_cb) {
2313                         dhcp_client->state = RENEW;
2314                         re = switch_listening_mode(dhcp_client, L3);
2315                         if (re != 0) {
2316                                 switch_listening_mode(dhcp_client, L_NONE);
2317                                 dhcp_client->state = 0;
2318                                 return re;
2319                         }
2320                         send_dhcpv6_release(dhcp_client);
2321                 }
2322
2323                 return 0;
2324         }
2325
2326         if (dhcp_client->retry_times == DISCOVER_RETRIES) {
2327                 ipv4ll_start(dhcp_client);
2328                 return 0;
2329         }
2330
2331         if (dhcp_client->retry_times == 0) {
2332                 g_free(dhcp_client->assigned_ip);
2333                 dhcp_client->assigned_ip = NULL;
2334
2335                 dhcp_client->state = INIT_SELECTING;
2336                 re = switch_listening_mode(dhcp_client, L2);
2337                 if (re != 0)
2338                         return re;
2339
2340                 dhcp_client->xid = rand();
2341                 dhcp_client->start = time(NULL);
2342         }
2343
2344         if (last_address == NULL) {
2345                 addr = 0;
2346         } else {
2347                 addr = inet_addr(last_address);
2348                 if (addr == 0xFFFFFFFF) {
2349                         addr = 0;
2350                 } else {
2351                         g_free(dhcp_client->last_address);
2352                         dhcp_client->last_address = g_strdup(last_address);
2353                 }
2354         }
2355         send_discover(dhcp_client, addr);
2356
2357         dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
2358                                                         DISCOVER_TIMEOUT,
2359                                                         discover_timeout,
2360                                                         dhcp_client,
2361                                                         NULL);
2362         return 0;
2363 }
2364
2365 void g_dhcp_client_stop(GDHCPClient *dhcp_client)
2366 {
2367         switch_listening_mode(dhcp_client, L_NONE);
2368
2369         if (dhcp_client->state == BOUND ||
2370                         dhcp_client->state == RENEWING ||
2371                                 dhcp_client->state == REBINDING)
2372                 send_release(dhcp_client, dhcp_client->server_ip,
2373                                         dhcp_client->requested_ip);
2374
2375         if (dhcp_client->timeout > 0) {
2376                 g_source_remove(dhcp_client->timeout);
2377                 dhcp_client->timeout = 0;
2378         }
2379
2380         if (dhcp_client->listener_watch > 0) {
2381                 g_source_remove(dhcp_client->listener_watch);
2382                 dhcp_client->listener_watch = 0;
2383         }
2384
2385         dhcp_client->listener_channel = NULL;
2386
2387         dhcp_client->retry_times = 0;
2388         dhcp_client->ack_retry_times = 0;
2389
2390         dhcp_client->requested_ip = 0;
2391         dhcp_client->state = RELEASED;
2392         dhcp_client->lease_seconds = 0;
2393 }
2394
2395 GList *g_dhcp_client_get_option(GDHCPClient *dhcp_client,
2396                                         unsigned char option_code)
2397 {
2398         return g_hash_table_lookup(dhcp_client->code_value_hash,
2399                                         GINT_TO_POINTER((int) option_code));
2400 }
2401
2402 void g_dhcp_client_register_event(GDHCPClient *dhcp_client,
2403                                         GDHCPClientEvent event,
2404                                         GDHCPClientEventFunc func,
2405                                                         gpointer data)
2406 {
2407         switch (event) {
2408         case G_DHCP_CLIENT_EVENT_LEASE_AVAILABLE:
2409                 dhcp_client->lease_available_cb = func;
2410                 dhcp_client->lease_available_data = data;
2411                 return;
2412         case G_DHCP_CLIENT_EVENT_IPV4LL_AVAILABLE:
2413                 if (dhcp_client->type == G_DHCP_IPV6)
2414                         return;
2415                 dhcp_client->ipv4ll_available_cb = func;
2416                 dhcp_client->ipv4ll_available_data = data;
2417                 return;
2418         case G_DHCP_CLIENT_EVENT_NO_LEASE:
2419                 dhcp_client->no_lease_cb = func;
2420                 dhcp_client->no_lease_data = data;
2421                 return;
2422         case G_DHCP_CLIENT_EVENT_LEASE_LOST:
2423                 dhcp_client->lease_lost_cb = func;
2424                 dhcp_client->lease_lost_data = data;
2425                 return;
2426         case G_DHCP_CLIENT_EVENT_IPV4LL_LOST:
2427                 if (dhcp_client->type == G_DHCP_IPV6)
2428                         return;
2429                 dhcp_client->ipv4ll_lost_cb = func;
2430                 dhcp_client->ipv4ll_lost_data = data;
2431                 return;
2432         case G_DHCP_CLIENT_EVENT_ADDRESS_CONFLICT:
2433                 dhcp_client->address_conflict_cb = func;
2434                 dhcp_client->address_conflict_data = data;
2435                 return;
2436         case G_DHCP_CLIENT_EVENT_INFORMATION_REQ:
2437                 if (dhcp_client->type == G_DHCP_IPV4)
2438                         return;
2439                 dhcp_client->information_req_cb = func;
2440                 dhcp_client->information_req_data = data;
2441                 return;
2442         case G_DHCP_CLIENT_EVENT_SOLICITATION:
2443                 if (dhcp_client->type == G_DHCP_IPV4)
2444                         return;
2445                 dhcp_client->solicitation_cb = func;
2446                 dhcp_client->solicitation_data = data;
2447                 return;
2448         case G_DHCP_CLIENT_EVENT_ADVERTISE:
2449                 if (dhcp_client->type == G_DHCP_IPV4)
2450                         return;
2451                 dhcp_client->advertise_cb = func;
2452                 dhcp_client->advertise_data = data;
2453                 return;
2454         case G_DHCP_CLIENT_EVENT_REQUEST:
2455                 if (dhcp_client->type == G_DHCP_IPV4)
2456                         return;
2457                 dhcp_client->request_cb = func;
2458                 dhcp_client->request_data = data;
2459                 return;
2460         case G_DHCP_CLIENT_EVENT_RENEW:
2461                 if (dhcp_client->type == G_DHCP_IPV4)
2462                         return;
2463                 dhcp_client->renew_cb = func;
2464                 dhcp_client->renew_data = data;
2465                 return;
2466         case G_DHCP_CLIENT_EVENT_REBIND:
2467                 if (dhcp_client->type == G_DHCP_IPV4)
2468                         return;
2469                 dhcp_client->rebind_cb = func;
2470                 dhcp_client->rebind_data = data;
2471                 return;
2472         case G_DHCP_CLIENT_EVENT_RELEASE:
2473                 if (dhcp_client->type == G_DHCP_IPV4)
2474                         return;
2475                 dhcp_client->release_cb = func;
2476                 dhcp_client->release_data = data;
2477                 return;
2478         }
2479 }
2480
2481 int g_dhcp_client_get_index(GDHCPClient *dhcp_client)
2482 {
2483         return dhcp_client->ifindex;
2484 }
2485
2486 char *g_dhcp_client_get_address(GDHCPClient *dhcp_client)
2487 {
2488         return g_strdup(dhcp_client->assigned_ip);
2489 }
2490
2491 char *g_dhcp_client_get_netmask(GDHCPClient *dhcp_client)
2492 {
2493         GList *option = NULL;
2494
2495         if (dhcp_client->type == G_DHCP_IPV6)
2496                 return NULL;
2497
2498         switch (dhcp_client->state) {
2499         case IPV4LL_DEFEND:
2500         case IPV4LL_MONITOR:
2501                 return g_strdup("255.255.0.0");
2502         case BOUND:
2503         case RENEWING:
2504         case REBINDING:
2505                 option = g_dhcp_client_get_option(dhcp_client, G_DHCP_SUBNET);
2506                 if (option != NULL)
2507                         return g_strdup(option->data);
2508         case INIT_SELECTING:
2509         case REQUESTING:
2510         case RELEASED:
2511         case IPV4LL_PROBE:
2512         case IPV4LL_ANNOUNCE:
2513         case INFORMATION_REQ:
2514         case SOLICITATION:
2515         case REQUEST:
2516         case RENEW:
2517         case REBIND:
2518         case RELEASE:
2519                 break;
2520         }
2521         return NULL;
2522 }
2523
2524 GDHCPClientError g_dhcp_client_set_request(GDHCPClient *dhcp_client,
2525                                                 unsigned int option_code)
2526 {
2527         if (g_list_find(dhcp_client->request_list,
2528                         GINT_TO_POINTER((int) option_code)) == NULL)
2529                 dhcp_client->request_list = g_list_prepend(
2530                                         dhcp_client->request_list,
2531                                         (GINT_TO_POINTER((int) option_code)));
2532
2533         return G_DHCP_CLIENT_ERROR_NONE;
2534 }
2535
2536 void g_dhcp_client_clear_requests(GDHCPClient *dhcp_client)
2537 {
2538         g_list_free(dhcp_client->request_list);
2539         dhcp_client->request_list = NULL;
2540 }
2541
2542 void g_dhcp_client_clear_values(GDHCPClient *dhcp_client)
2543 {
2544         g_hash_table_remove_all(dhcp_client->send_value_hash);
2545 }
2546
2547 static uint8_t *alloc_dhcp_option(int code, const uint8_t *data, unsigned size)
2548 {
2549         uint8_t *storage;
2550
2551         storage = g_try_malloc(size + OPT_DATA);
2552         if (storage == NULL)
2553                 return NULL;
2554
2555         storage[OPT_CODE] = code;
2556         storage[OPT_LEN] = size;
2557         memcpy(&storage[OPT_DATA], data, size);
2558
2559         return storage;
2560 }
2561
2562 static uint8_t *alloc_dhcp_data_option(int code, const uint8_t *data, unsigned size)
2563 {
2564         return alloc_dhcp_option(code, data, MIN(size, 255));
2565 }
2566
2567 static uint8_t *alloc_dhcp_string_option(int code, const char *str)
2568 {
2569         return alloc_dhcp_data_option(code, (const uint8_t *)str, strlen(str));
2570 }
2571
2572 GDHCPClientError g_dhcp_client_set_id(GDHCPClient *dhcp_client)
2573 {
2574         const unsigned maclen = 6;
2575         const unsigned idlen = maclen + 1;
2576         const uint8_t option_code = G_DHCP_CLIENT_ID;
2577         uint8_t idbuf[idlen];
2578         uint8_t *data_option;
2579
2580         idbuf[0] = ARPHRD_ETHER;
2581
2582         memcpy(&idbuf[1], dhcp_client->mac_address, maclen);
2583
2584         data_option = alloc_dhcp_data_option(option_code, idbuf, idlen);
2585         if (data_option == NULL)
2586                 return G_DHCP_CLIENT_ERROR_NOMEM;
2587
2588         g_hash_table_insert(dhcp_client->send_value_hash,
2589                 GINT_TO_POINTER((int) option_code), data_option);
2590
2591         return G_DHCP_CLIENT_ERROR_NONE;
2592 }
2593
2594 /* Now only support send hostname */
2595 GDHCPClientError g_dhcp_client_set_send(GDHCPClient *dhcp_client,
2596                 unsigned char option_code, const char *option_value)
2597 {
2598         uint8_t *binary_option;
2599
2600         if (option_code == G_DHCP_HOST_NAME && option_value != NULL) {
2601                 binary_option = alloc_dhcp_string_option(option_code,
2602                                                         option_value);
2603                 if (binary_option == NULL)
2604                         return G_DHCP_CLIENT_ERROR_NOMEM;
2605
2606                 g_hash_table_insert(dhcp_client->send_value_hash,
2607                         GINT_TO_POINTER((int) option_code), binary_option);
2608         }
2609
2610         return G_DHCP_CLIENT_ERROR_NONE;
2611 }
2612
2613 static uint8_t *alloc_dhcpv6_option(uint16_t code, uint8_t *option,
2614                                 uint16_t len)
2615 {
2616         uint8_t *storage;
2617
2618         storage = g_malloc(2 + 2 + len);
2619         if (storage == NULL)
2620                 return NULL;
2621
2622         storage[0] = code >> 8;
2623         storage[1] = code & 0xff;
2624         storage[2] = len >> 8;
2625         storage[3] = len & 0xff;
2626         memcpy(storage + 2 + 2, option, len);
2627
2628         return storage;
2629 }
2630
2631 void g_dhcpv6_client_set_send(GDHCPClient *dhcp_client,
2632                                         uint16_t option_code,
2633                                         uint8_t *option_value,
2634                                         uint16_t option_len)
2635 {
2636         if (option_value != NULL) {
2637                 uint8_t *binary_option;
2638
2639                 debug(dhcp_client, "setting option %d to %p len %d",
2640                         option_code, option_value, option_len);
2641
2642                 binary_option = alloc_dhcpv6_option(option_code, option_value,
2643                                                 option_len);
2644                 if (binary_option != NULL)
2645                         g_hash_table_insert(dhcp_client->send_value_hash,
2646                                         GINT_TO_POINTER((int) option_code),
2647                                         binary_option);
2648         }
2649 }
2650
2651 void g_dhcpv6_client_reset_renew(GDHCPClient *dhcp_client)
2652 {
2653         if (dhcp_client == NULL || dhcp_client->type == G_DHCP_IPV4)
2654                 return;
2655
2656         dhcp_client->last_renew = time(NULL);
2657 }
2658
2659 void g_dhcpv6_client_reset_rebind(GDHCPClient *dhcp_client)
2660 {
2661         if (dhcp_client == NULL || dhcp_client->type == G_DHCP_IPV4)
2662                 return;
2663
2664         dhcp_client->last_rebind = time(NULL);
2665 }
2666
2667 void g_dhcpv6_client_set_expire(GDHCPClient *dhcp_client, uint32_t timeout)
2668 {
2669         if (dhcp_client == NULL || dhcp_client->type == G_DHCP_IPV4)
2670                 return;
2671
2672         dhcp_client->expire = time(NULL) + timeout;
2673 }
2674
2675 uint16_t g_dhcpv6_client_get_status(GDHCPClient *dhcp_client)
2676 {
2677         if (dhcp_client == NULL || dhcp_client->type == G_DHCP_IPV4)
2678                 return 0;
2679
2680         return dhcp_client->status_code;
2681 }
2682
2683 GDHCPClient *g_dhcp_client_ref(GDHCPClient *dhcp_client)
2684 {
2685         if (dhcp_client == NULL)
2686                 return NULL;
2687
2688         __sync_fetch_and_add(&dhcp_client->ref_count, 1);
2689
2690         return dhcp_client;
2691 }
2692
2693 void g_dhcp_client_unref(GDHCPClient *dhcp_client)
2694 {
2695         if (dhcp_client == NULL)
2696                 return;
2697
2698         if (__sync_fetch_and_sub(&dhcp_client->ref_count, 1) != 1)
2699                 return;
2700
2701         g_dhcp_client_stop(dhcp_client);
2702
2703         g_free(dhcp_client->interface);
2704         g_free(dhcp_client->assigned_ip);
2705         g_free(dhcp_client->last_address);
2706         g_free(dhcp_client->duid);
2707         g_free(dhcp_client->server_duid);
2708
2709         g_list_free(dhcp_client->request_list);
2710         g_list_free(dhcp_client->require_list);
2711
2712         g_hash_table_destroy(dhcp_client->code_value_hash);
2713         g_hash_table_destroy(dhcp_client->send_value_hash);
2714
2715         g_free(dhcp_client);
2716 }
2717
2718 void g_dhcp_client_set_debug(GDHCPClient *dhcp_client,
2719                                 GDHCPDebugFunc func, gpointer user_data)
2720 {
2721         if (dhcp_client == NULL)
2722                 return;
2723
2724         dhcp_client->debug_func = func;
2725         dhcp_client->debug_data = user_data;
2726 }