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