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