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