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