stats: Avoid double-frees on a failed mapping
[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 } ClientState;
73
74 struct _GDHCPClient {
75         gint ref_count;
76         GDHCPType type;
77         ClientState state;
78         int ifindex;
79         char *interface;
80         uint8_t mac_address[6];
81         uint32_t xid;
82         uint32_t server_ip;
83         uint32_t requested_ip;
84         char *assigned_ip;
85         uint32_t lease_seconds;
86         ListenMode listen_mode;
87         int listener_sockfd;
88         uint8_t retry_times;
89         uint8_t ack_retry_times;
90         uint8_t conflicts;
91         guint timeout;
92         guint listener_watch;
93         GIOChannel *listener_channel;
94         GList *require_list;
95         GList *request_list;
96         GHashTable *code_value_hash;
97         GHashTable *send_value_hash;
98         GDHCPClientEventFunc lease_available_cb;
99         gpointer lease_available_data;
100         GDHCPClientEventFunc ipv4ll_available_cb;
101         gpointer ipv4ll_available_data;
102         GDHCPClientEventFunc no_lease_cb;
103         gpointer no_lease_data;
104         GDHCPClientEventFunc lease_lost_cb;
105         gpointer lease_lost_data;
106         GDHCPClientEventFunc ipv4ll_lost_cb;
107         gpointer ipv4ll_lost_data;
108         GDHCPClientEventFunc address_conflict_cb;
109         gpointer address_conflict_data;
110         GDHCPDebugFunc debug_func;
111         gpointer debug_data;
112 };
113
114 static inline void debug(GDHCPClient *client, const char *format, ...)
115 {
116         char str[256];
117         va_list ap;
118
119         if (client->debug_func == NULL)
120                 return;
121
122         va_start(ap, format);
123
124         if (vsnprintf(str, sizeof(str), format, ap) > 0)
125                 client->debug_func(str, client->debug_data);
126
127         va_end(ap);
128 }
129
130 /* Initialize the packet with the proper defaults */
131 static void init_packet(GDHCPClient *dhcp_client,
132                 struct dhcp_packet *packet, char type)
133 {
134         dhcp_init_header(packet, type);
135
136         memcpy(packet->chaddr, dhcp_client->mac_address, 6);
137 }
138
139 static void add_request_options(GDHCPClient *dhcp_client,
140                                 struct dhcp_packet *packet)
141 {
142         int len = 0;
143         GList *list;
144         uint8_t code;
145         int end = dhcp_end_option(packet->options);
146
147         for (list = dhcp_client->request_list; list; list = list->next) {
148                 code = (uint8_t) GPOINTER_TO_INT(list->data);
149
150                 packet->options[end + OPT_DATA + len] = code;
151                 len++;
152         }
153
154         if (len) {
155                 packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
156                 packet->options[end + OPT_LEN] = len;
157                 packet->options[end + OPT_DATA + len] = DHCP_END;
158         }
159 }
160
161 static void add_binary_option(gpointer key, gpointer value, gpointer user_data)
162 {
163         uint8_t *option = value;
164         struct dhcp_packet *packet = user_data;
165
166         dhcp_add_binary_option(packet, option);
167 }
168
169 static void add_send_options(GDHCPClient *dhcp_client,
170                                 struct dhcp_packet *packet)
171 {
172         g_hash_table_foreach(dhcp_client->send_value_hash,
173                                 add_binary_option, packet);
174 }
175
176 static int send_discover(GDHCPClient *dhcp_client, uint32_t requested)
177 {
178         struct dhcp_packet packet;
179
180         debug(dhcp_client, "sending DHCP discover request");
181
182         init_packet(dhcp_client, &packet, DHCPDISCOVER);
183
184         packet.xid = dhcp_client->xid;
185
186         if (requested)
187                 dhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
188
189         /* Explicitly saying that we want RFC-compliant packets helps
190          * some buggy DHCP servers to NOT send bigger packets */
191         dhcp_add_simple_option(&packet, DHCP_MAX_SIZE, htons(576));
192
193         add_request_options(dhcp_client, &packet);
194
195         add_send_options(dhcp_client, &packet);
196
197         return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
198                                         INADDR_BROADCAST, SERVER_PORT,
199                                         MAC_BCAST_ADDR, dhcp_client->ifindex);
200 }
201
202 static int send_select(GDHCPClient *dhcp_client)
203 {
204         struct dhcp_packet packet;
205         struct in_addr addr;
206
207         debug(dhcp_client, "sending DHCP select request");
208
209         init_packet(dhcp_client, &packet, DHCPREQUEST);
210
211         packet.xid = dhcp_client->xid;
212
213         dhcp_add_simple_option(&packet, DHCP_REQUESTED_IP,
214                                         dhcp_client->requested_ip);
215         dhcp_add_simple_option(&packet, DHCP_SERVER_ID, dhcp_client->server_ip);
216
217         add_request_options(dhcp_client, &packet);
218
219         add_send_options(dhcp_client, &packet);
220
221         addr.s_addr = dhcp_client->requested_ip;
222
223         return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
224                                         INADDR_BROADCAST, SERVER_PORT,
225                                         MAC_BCAST_ADDR, dhcp_client->ifindex);
226 }
227
228 static int send_renew(GDHCPClient *dhcp_client)
229 {
230         struct dhcp_packet packet;
231
232         debug(dhcp_client, "sending DHCP renew request");
233
234         init_packet(dhcp_client , &packet, DHCPREQUEST);
235         packet.xid = dhcp_client->xid;
236         packet.ciaddr = dhcp_client->requested_ip;
237
238         add_request_options(dhcp_client, &packet);
239
240         add_send_options(dhcp_client, &packet);
241
242         return dhcp_send_kernel_packet(&packet,
243                 dhcp_client->requested_ip, CLIENT_PORT,
244                 dhcp_client->server_ip, SERVER_PORT);
245 }
246
247 static int send_rebound(GDHCPClient *dhcp_client)
248 {
249         struct dhcp_packet packet;
250
251         debug(dhcp_client, "sending DHCP rebound request");
252
253         init_packet(dhcp_client , &packet, DHCPREQUEST);
254         packet.xid = dhcp_client->xid;
255         packet.ciaddr = dhcp_client->requested_ip;
256
257         add_request_options(dhcp_client, &packet);
258
259         add_send_options(dhcp_client, &packet);
260
261         return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
262                                         INADDR_BROADCAST, SERVER_PORT,
263                                         MAC_BCAST_ADDR, dhcp_client->ifindex);
264 }
265
266 static int send_release(GDHCPClient *dhcp_client,
267                         uint32_t server, uint32_t ciaddr)
268 {
269         struct dhcp_packet packet;
270
271         debug(dhcp_client, "sending DHCP release request");
272
273         init_packet(dhcp_client, &packet, DHCPRELEASE);
274         packet.xid = rand();
275         packet.ciaddr = ciaddr;
276
277         dhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
278
279         return dhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT,
280                                                 server, SERVER_PORT);
281 }
282
283 static gboolean ipv4ll_probe_timeout(gpointer dhcp_data);
284 static int switch_listening_mode(GDHCPClient *dhcp_client,
285                                         ListenMode listen_mode);
286
287 static gboolean send_probe_packet(gpointer dhcp_data)
288 {
289         GDHCPClient *dhcp_client;
290         guint timeout;
291
292         dhcp_client = dhcp_data;
293         /* if requested_ip is not valid, pick a new address*/
294         if (dhcp_client->requested_ip == 0) {
295                 debug(dhcp_client, "pick a new random address");
296                 dhcp_client->requested_ip = ipv4ll_random_ip(0);
297         }
298
299         debug(dhcp_client, "sending IPV4LL probe request");
300
301         if (dhcp_client->retry_times == 1) {
302                 dhcp_client->state = IPV4LL_PROBE;
303                 switch_listening_mode(dhcp_client, L_ARP);
304         }
305         ipv4ll_send_arp_packet(dhcp_client->mac_address, 0,
306                         dhcp_client->requested_ip, dhcp_client->ifindex);
307
308         if (dhcp_client->retry_times < PROBE_NUM) {
309                 /*add a random timeout in range of PROBE_MIN to PROBE_MAX*/
310                 timeout = ipv4ll_random_delay_ms(PROBE_MAX-PROBE_MIN);
311                 timeout += PROBE_MIN*1000;
312         } else
313                 timeout = (ANNOUNCE_WAIT * 1000);
314
315         dhcp_client->timeout = g_timeout_add_full(G_PRIORITY_HIGH,
316                                                  timeout,
317                                                  ipv4ll_probe_timeout,
318                                                  dhcp_client,
319                                                  NULL);
320         return FALSE;
321 }
322
323 static gboolean ipv4ll_announce_timeout(gpointer dhcp_data);
324 static gboolean ipv4ll_defend_timeout(gpointer dhcp_data);
325
326 static gboolean send_announce_packet(gpointer dhcp_data)
327 {
328         GDHCPClient *dhcp_client;
329
330         dhcp_client = dhcp_data;
331
332         debug(dhcp_client, "sending IPV4LL announce request");
333
334         ipv4ll_send_arp_packet(dhcp_client->mac_address,
335                                 dhcp_client->requested_ip,
336                                 dhcp_client->requested_ip,
337                                 dhcp_client->ifindex);
338
339         if (dhcp_client->timeout > 0)
340                 g_source_remove(dhcp_client->timeout);
341         dhcp_client->timeout = 0;
342
343         if (dhcp_client->state == IPV4LL_DEFEND) {
344                 dhcp_client->timeout =
345                         g_timeout_add_seconds_full(G_PRIORITY_HIGH,
346                                                 DEFEND_INTERVAL,
347                                                 ipv4ll_defend_timeout,
348                                                 dhcp_client,
349                                                 NULL);
350                 return TRUE;
351         } else
352                 dhcp_client->timeout =
353                         g_timeout_add_seconds_full(G_PRIORITY_HIGH,
354                                                 ANNOUNCE_INTERVAL,
355                                                 ipv4ll_announce_timeout,
356                                                 dhcp_client,
357                                                 NULL);
358         return TRUE;
359 }
360
361 static void get_interface_mac_address(int index, uint8_t *mac_address)
362 {
363         struct ifreq ifr;
364         int sk, err;
365
366         sk = socket(PF_INET, SOCK_DGRAM, 0);
367         if (sk < 0) {
368                 perror("Open socket error");
369                 return;
370         }
371
372         memset(&ifr, 0, sizeof(ifr));
373         ifr.ifr_ifindex = index;
374
375         err = ioctl(sk, SIOCGIFNAME, &ifr);
376         if (err < 0) {
377                 perror("Get interface name error");
378                 goto done;
379         }
380
381         err = ioctl(sk, SIOCGIFHWADDR, &ifr);
382         if (err < 0) {
383                 perror("Get mac address error");
384                 goto done;
385         }
386
387         memcpy(mac_address, ifr.ifr_hwaddr.sa_data, 6);
388
389 done:
390         close(sk);
391 }
392
393 static void remove_value(gpointer data, gpointer user_data)
394 {
395         char *value = data;
396         g_free(value);
397 }
398
399 static void remove_option_value(gpointer data)
400 {
401         GList *option_value = data;
402
403         g_list_foreach(option_value, remove_value, NULL);
404 }
405
406 GDHCPClient *g_dhcp_client_new(GDHCPType type,
407                         int ifindex, GDHCPClientError *error)
408 {
409         GDHCPClient *dhcp_client;
410
411         if (ifindex < 0) {
412                 *error = G_DHCP_CLIENT_ERROR_INVALID_INDEX;
413                 return NULL;
414         }
415
416         dhcp_client = g_try_new0(GDHCPClient, 1);
417         if (dhcp_client == NULL) {
418                 *error = G_DHCP_CLIENT_ERROR_NOMEM;
419                 return NULL;
420         }
421
422         dhcp_client->interface = get_interface_name(ifindex);
423         if (dhcp_client->interface == NULL) {
424                 *error = G_DHCP_CLIENT_ERROR_INTERFACE_UNAVAILABLE;
425                 goto error;
426         }
427
428         if (interface_is_up(ifindex) == FALSE) {
429                 *error = G_DHCP_CLIENT_ERROR_INTERFACE_DOWN;
430                 goto error;
431         }
432
433         get_interface_mac_address(ifindex, dhcp_client->mac_address);
434
435         dhcp_client->listener_sockfd = -1;
436         dhcp_client->listener_channel = NULL;
437         dhcp_client->listen_mode = L_NONE;
438         dhcp_client->ref_count = 1;
439         dhcp_client->type = type;
440         dhcp_client->ifindex = ifindex;
441         dhcp_client->lease_available_cb = NULL;
442         dhcp_client->ipv4ll_available_cb = NULL;
443         dhcp_client->no_lease_cb = NULL;
444         dhcp_client->lease_lost_cb = NULL;
445         dhcp_client->ipv4ll_lost_cb = NULL;
446         dhcp_client->address_conflict_cb = NULL;
447         dhcp_client->listener_watch = 0;
448         dhcp_client->retry_times = 0;
449         dhcp_client->ack_retry_times = 0;
450         dhcp_client->code_value_hash = g_hash_table_new_full(g_direct_hash,
451                                 g_direct_equal, NULL, remove_option_value);
452         dhcp_client->send_value_hash = g_hash_table_new_full(g_direct_hash,
453                                 g_direct_equal, NULL, g_free);
454         dhcp_client->request_list = NULL;
455         dhcp_client->require_list = NULL;
456
457         *error = G_DHCP_CLIENT_ERROR_NONE;
458
459         return dhcp_client;
460
461 error:
462         g_free(dhcp_client->interface);
463         g_free(dhcp_client);
464         return NULL;
465 }
466
467 #define SERVER_AND_CLIENT_PORTS  ((67 << 16) + 68)
468
469 static int dhcp_l2_socket(int ifindex)
470 {
471         int fd;
472         struct sockaddr_ll sock;
473
474         /*
475          * Comment:
476          *
477          *      I've selected not to see LL header, so BPF doesn't see it, too.
478          *      The filter may also pass non-IP and non-ARP packets, but we do
479          *      a more complete check when receiving the message in userspace.
480          *
481          * and filter shamelessly stolen from:
482          *
483          *      http://www.flamewarmaster.de/software/dhcpclient/
484          *
485          * There are a few other interesting ideas on that page (look under
486          * "Motivation").  Use of netlink events is most interesting.  Think
487          * of various network servers listening for events and reconfiguring.
488          * That would obsolete sending HUP signals and/or make use of restarts.
489          *
490          * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
491          * License: GPL v2.
492          *
493          * TODO: make conditional?
494          */
495         static const struct sock_filter filter_instr[] = {
496                 /* check for udp */
497                 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
498                 /* L5, L1, is UDP? */
499                 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 2, 0),
500                 /* ugly check for arp on ethernet-like and IPv4 */
501                 BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2), /* L1: */
502                 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x08000604, 3, 4),/* L3, L4 */
503                 /* skip IP header */
504                 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), /* L5: */
505                 /* check udp source and destination ports */
506                 BPF_STMT(BPF_LD|BPF_W|BPF_IND, 0),
507                 /* L3, L4 */
508                 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_AND_CLIENT_PORTS, 0, 1),
509                 /* returns */
510                 BPF_STMT(BPF_RET|BPF_K, 0x0fffffff), /* L3: pass */
511                 BPF_STMT(BPF_RET|BPF_K, 0), /* L4: reject */
512         };
513
514         static const struct sock_fprog filter_prog = {
515                 .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
516                 /* casting const away: */
517                 .filter = (struct sock_filter *) filter_instr,
518         };
519
520         fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
521         if (fd < 0)
522                 return fd;
523
524         if (SERVER_PORT == 67 && CLIENT_PORT == 68)
525                 /* Use only if standard ports are in use */
526                 setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
527                                                         sizeof(filter_prog));
528
529         memset(&sock, 0, sizeof(sock));
530         sock.sll_family = AF_PACKET;
531         sock.sll_protocol = htons(ETH_P_IP);
532         sock.sll_ifindex = ifindex;
533
534         if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) != 0) {
535                 close(fd);
536                 return -errno;
537         }
538
539         return fd;
540 }
541
542 static gboolean sanity_check(struct ip_udp_dhcp_packet *packet, int bytes)
543 {
544         if (packet->ip.protocol != IPPROTO_UDP)
545                 return FALSE;
546
547         if (packet->ip.version != IPVERSION)
548                 return FALSE;
549
550         if (packet->ip.ihl != sizeof(packet->ip) >> 2)
551                 return FALSE;
552
553         if (packet->udp.dest != htons(CLIENT_PORT))
554                 return FALSE;
555
556         if (ntohs(packet->udp.len) != (uint16_t)(bytes - sizeof(packet->ip)))
557                 return FALSE;
558
559         return TRUE;
560 }
561
562 static int dhcp_recv_l2_packet(struct dhcp_packet *dhcp_pkt, int fd)
563 {
564         int bytes;
565         struct ip_udp_dhcp_packet packet;
566         uint16_t check;
567
568         memset(&packet, 0, sizeof(packet));
569
570         bytes = read(fd, &packet, sizeof(packet));
571         if (bytes < 0)
572                 return -1;
573
574         if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp)))
575                 return -1;
576
577         if (bytes < ntohs(packet.ip.tot_len))
578                 /* packet is bigger than sizeof(packet), we did partial read */
579                 return -1;
580
581         /* ignore any extra garbage bytes */
582         bytes = ntohs(packet.ip.tot_len);
583
584         if (sanity_check(&packet, bytes) == FALSE)
585                 return -1;
586
587         check = packet.ip.check;
588         packet.ip.check = 0;
589         if (check != dhcp_checksum(&packet.ip, sizeof(packet.ip)))
590                 return -1;
591
592         /* verify UDP checksum. IP header has to be modified for this */
593         memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
594         /* ip.xx fields which are not memset: protocol, check, saddr, daddr */
595         packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
596         check = packet.udp.check;
597         packet.udp.check = 0;
598         if (check && check != dhcp_checksum(&packet, bytes))
599                 return -1;
600
601         memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) +
602                                                         sizeof(packet.udp)));
603
604         if (dhcp_pkt->cookie != htonl(DHCP_MAGIC))
605                 return -1;
606
607         return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
608 }
609
610 static void ipv4ll_start(GDHCPClient *dhcp_client)
611 {
612         guint timeout;
613         int seed;
614
615         if (dhcp_client->timeout > 0) {
616                 g_source_remove(dhcp_client->timeout);
617                 dhcp_client->timeout = 0;
618         }
619
620         switch_listening_mode(dhcp_client, L_NONE);
621         dhcp_client->type = G_DHCP_IPV4LL;
622         dhcp_client->retry_times = 0;
623         dhcp_client->requested_ip = 0;
624
625         /*try to start with a based mac address ip*/
626         seed = (dhcp_client->mac_address[4] << 8 | dhcp_client->mac_address[4]);
627         dhcp_client->requested_ip = ipv4ll_random_ip(seed);
628
629         /*first wait a random delay to avoid storm of arp request on boot*/
630         timeout = ipv4ll_random_delay_ms(PROBE_WAIT);
631
632         dhcp_client->retry_times++;
633         dhcp_client->timeout = g_timeout_add_full(G_PRIORITY_HIGH,
634                                                 timeout,
635                                                 send_probe_packet,
636                                                 dhcp_client,
637                                                 NULL);
638 }
639
640 static void ipv4ll_stop(GDHCPClient *dhcp_client)
641 {
642
643         switch_listening_mode(dhcp_client, L_NONE);
644
645         if (dhcp_client->timeout > 0)
646                 g_source_remove(dhcp_client->timeout);
647
648         if (dhcp_client->listener_watch > 0) {
649                 g_source_remove(dhcp_client->listener_watch);
650                 dhcp_client->listener_watch = 0;
651         }
652
653         dhcp_client->state = IPV4LL_PROBE;
654         dhcp_client->retry_times = 0;
655         dhcp_client->requested_ip = 0;
656
657         g_free(dhcp_client->assigned_ip);
658         dhcp_client->assigned_ip = NULL;
659 }
660
661 static int ipv4ll_recv_arp_packet(GDHCPClient *dhcp_client)
662 {
663         int bytes;
664         struct ether_arp arp;
665         uint32_t ip_requested;
666         int source_conflict;
667         int target_conflict;
668
669         memset(&arp, 0, sizeof(arp));
670         bytes = 0;
671         bytes = read(dhcp_client->listener_sockfd, &arp, sizeof(arp));
672         if (bytes < 0)
673                 return bytes;
674
675         if (arp.arp_op != htons(ARPOP_REPLY) &&
676                         arp.arp_op != htons(ARPOP_REQUEST))
677                 return -EINVAL;
678
679         ip_requested = ntohl(dhcp_client->requested_ip);
680         source_conflict = !memcmp(arp.arp_spa, &ip_requested,
681                                                 sizeof(ip_requested));
682
683         target_conflict = !memcmp(arp.arp_tpa, &ip_requested,
684                                 sizeof(ip_requested));
685
686         if (!source_conflict && !target_conflict)
687                 return 0;
688
689         dhcp_client->conflicts++;
690
691         debug(dhcp_client, "IPV4LL conflict detected");
692
693         if (dhcp_client->state == IPV4LL_MONITOR) {
694                 if (!source_conflict)
695                         return 0;
696                 dhcp_client->state = IPV4LL_DEFEND;
697                 debug(dhcp_client, "DEFEND mode conflicts : %d",
698                         dhcp_client->conflicts);
699                 /*Try to defend with a single announce*/
700                 send_announce_packet(dhcp_client);
701                 return 0;
702         }
703
704         if (dhcp_client->state == IPV4LL_DEFEND) {
705                 if (!source_conflict)
706                         return 0;
707                 else if (dhcp_client->ipv4ll_lost_cb != NULL)
708                         dhcp_client->ipv4ll_lost_cb(dhcp_client,
709                                                 dhcp_client->ipv4ll_lost_data);
710         }
711
712         ipv4ll_stop(dhcp_client);
713
714         if (dhcp_client->conflicts < MAX_CONFLICTS) {
715                 /*restart whole state machine*/
716                 dhcp_client->retry_times++;
717                 dhcp_client->timeout =
718                         g_timeout_add_full(G_PRIORITY_HIGH,
719                                         ipv4ll_random_delay_ms(PROBE_WAIT),
720                                         send_probe_packet,
721                                         dhcp_client,
722                                         NULL);
723         }
724         /* Here we got a lot of conflicts, RFC3927 states that we have
725          * to wait RATE_LIMIT_INTERVAL before retrying,
726          * but we just report failure.
727          */
728         else if (dhcp_client->no_lease_cb != NULL)
729                         dhcp_client->no_lease_cb(dhcp_client,
730                                                 dhcp_client->no_lease_data);
731
732         return 0;
733 }
734
735 static gboolean check_package_owner(GDHCPClient *dhcp_client,
736                                         struct dhcp_packet *packet)
737 {
738         if (packet->xid != dhcp_client->xid)
739                 return FALSE;
740
741         if (packet->hlen != 6)
742                 return FALSE;
743
744         if (memcmp(packet->chaddr, dhcp_client->mac_address, 6))
745                 return FALSE;
746
747         return TRUE;
748 }
749
750 static void start_request(GDHCPClient *dhcp_client);
751
752 static gboolean request_timeout(gpointer user_data)
753 {
754         GDHCPClient *dhcp_client = user_data;
755
756         debug(dhcp_client, "request timeout (retries %d)",
757                                         dhcp_client->retry_times);
758
759         dhcp_client->retry_times++;
760
761         start_request(dhcp_client);
762
763         return FALSE;
764 }
765
766 static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
767                                                         gpointer user_data);
768
769 static int switch_listening_mode(GDHCPClient *dhcp_client,
770                                         ListenMode listen_mode)
771 {
772         GIOChannel *listener_channel;
773         int listener_sockfd;
774
775         debug(dhcp_client, "switch listening mode (%d ==> %d)",
776                                 dhcp_client->listen_mode, listen_mode);
777
778         if (dhcp_client->listen_mode == listen_mode)
779                 return 0;
780
781         if (dhcp_client->listen_mode != L_NONE) {
782                 g_source_remove(dhcp_client->listener_watch);
783                 dhcp_client->listener_channel = NULL;
784                 dhcp_client->listen_mode = L_NONE;
785                 dhcp_client->listener_sockfd = -1;
786                 dhcp_client->listener_watch = 0;
787         }
788
789         if (listen_mode == L_NONE)
790                 return 0;
791
792         if (listen_mode == L2)
793                 listener_sockfd = dhcp_l2_socket(dhcp_client->ifindex);
794         else if (listen_mode == L3)
795                 listener_sockfd = dhcp_l3_socket(CLIENT_PORT,
796                                                 dhcp_client->interface);
797         else if (listen_mode == L_ARP)
798                 listener_sockfd = ipv4ll_arp_socket(dhcp_client->ifindex);
799         else
800                 return -EIO;
801
802         if (listener_sockfd < 0)
803                 return -EIO;
804
805         listener_channel = g_io_channel_unix_new(listener_sockfd);
806         if (listener_channel == NULL) {
807                 /* Failed to create listener channel */
808                 close(listener_sockfd);
809                 return -EIO;
810         }
811
812         dhcp_client->listen_mode = listen_mode;
813         dhcp_client->listener_sockfd = listener_sockfd;
814         dhcp_client->listener_channel = listener_channel;
815
816         g_io_channel_set_close_on_unref(listener_channel, TRUE);
817         dhcp_client->listener_watch =
818                         g_io_add_watch_full(listener_channel, G_PRIORITY_HIGH,
819                                 G_IO_IN | G_IO_NVAL | G_IO_ERR | G_IO_HUP,
820                                                 listener_event, dhcp_client,
821                                                                 NULL);
822         g_io_channel_unref(dhcp_client->listener_channel);
823
824         return 0;
825 }
826
827 static void start_request(GDHCPClient *dhcp_client)
828 {
829         debug(dhcp_client, "start request (retries %d)",
830                                         dhcp_client->retry_times);
831
832         if (dhcp_client->retry_times == REQUEST_RETRIES) {
833                 dhcp_client->state = INIT_SELECTING;
834                 ipv4ll_start(dhcp_client);
835
836                 return;
837         }
838
839         if (dhcp_client->retry_times == 0) {
840                 dhcp_client->state = REQUESTING;
841                 switch_listening_mode(dhcp_client, L2);
842         }
843
844         send_select(dhcp_client);
845
846         dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
847                                                         REQUEST_TIMEOUT,
848                                                         request_timeout,
849                                                         dhcp_client,
850                                                         NULL);
851 }
852
853 static uint32_t get_lease(struct dhcp_packet *packet)
854 {
855         uint8_t *option_u8;
856         uint32_t lease_seconds;
857
858         option_u8 = dhcp_get_option(packet, DHCP_LEASE_TIME);
859         if (option_u8 == NULL)
860                 return 3600;
861
862         lease_seconds = dhcp_get_unaligned((uint32_t *) option_u8);
863         lease_seconds = ntohl(lease_seconds);
864         /* paranoia: must not be prone to overflows */
865         lease_seconds &= 0x0fffffff;
866         if (lease_seconds < 10)
867                 lease_seconds = 10;
868
869         return lease_seconds;
870 }
871
872 static void restart_dhcp(GDHCPClient *dhcp_client, int retry_times)
873 {
874         debug(dhcp_client, "restart DHCP (retries %d)", retry_times);
875
876         if (dhcp_client->timeout > 0) {
877                 g_source_remove(dhcp_client->timeout);
878                 dhcp_client->timeout = 0;
879         }
880
881         dhcp_client->retry_times = retry_times;
882         dhcp_client->requested_ip = 0;
883         switch_listening_mode(dhcp_client, L2);
884
885         g_dhcp_client_start(dhcp_client);
886 }
887
888 static gboolean start_rebound_timeout(gpointer user_data)
889 {
890         GDHCPClient *dhcp_client = user_data;
891
892         debug(dhcp_client, "start rebound timeout");
893
894         switch_listening_mode(dhcp_client, L2);
895
896         dhcp_client->lease_seconds >>= 1;
897
898         /* We need to have enough time to receive ACK package*/
899         if (dhcp_client->lease_seconds <= 6) {
900
901                 /* ip need to be cleared */
902                 if (dhcp_client->lease_lost_cb != NULL)
903                         dhcp_client->lease_lost_cb(dhcp_client,
904                                         dhcp_client->lease_lost_data);
905
906                 restart_dhcp(dhcp_client, 0);
907         } else {
908                 send_rebound(dhcp_client);
909
910                 dhcp_client->timeout =
911                                 g_timeout_add_seconds_full(G_PRIORITY_HIGH,
912                                                 dhcp_client->lease_seconds >> 1,
913                                                         start_rebound_timeout,
914                                                                 dhcp_client,
915                                                                 NULL);
916         }
917
918         return FALSE;
919 }
920
921 static void start_rebound(GDHCPClient *dhcp_client)
922 {
923         debug(dhcp_client, "start rebound");
924
925         dhcp_client->state = REBINDING;
926
927         dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
928                                                 dhcp_client->lease_seconds >> 1,
929                                                         start_rebound_timeout,
930                                                                 dhcp_client,
931                                                                 NULL);
932 }
933
934 static gboolean start_renew_timeout(gpointer user_data)
935 {
936         GDHCPClient *dhcp_client = user_data;
937
938         debug(dhcp_client, "start renew timeout");
939
940         dhcp_client->state = RENEWING;
941
942         dhcp_client->lease_seconds >>= 1;
943
944         switch_listening_mode(dhcp_client, L3);
945         if (dhcp_client->lease_seconds <= 60)
946                 start_rebound(dhcp_client);
947         else {
948                 send_renew(dhcp_client);
949
950                 dhcp_client->timeout =
951                                 g_timeout_add_seconds_full(G_PRIORITY_HIGH,
952                                                 dhcp_client->lease_seconds >> 1,
953                                                         start_renew_timeout,
954                                                                 dhcp_client,
955                                                                 NULL);
956         }
957
958         return FALSE;
959 }
960
961 static void start_bound(GDHCPClient *dhcp_client)
962 {
963         debug(dhcp_client, "start bound");
964
965         dhcp_client->state = BOUND;
966
967         dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
968                                         dhcp_client->lease_seconds >> 1,
969                                         start_renew_timeout, dhcp_client,
970                                                         NULL);
971 }
972
973 static gboolean restart_dhcp_timeout(gpointer user_data)
974 {
975         GDHCPClient *dhcp_client = user_data;
976
977         debug(dhcp_client, "restart DHCP timeout");
978
979         dhcp_client->ack_retry_times++;
980
981         restart_dhcp(dhcp_client, dhcp_client->ack_retry_times);
982
983         return FALSE;
984 }
985
986 static char *get_ip(uint32_t ip)
987 {
988         struct in_addr addr;
989
990         addr.s_addr = ip;
991
992         return g_strdup(inet_ntoa(addr));
993 }
994
995 /* get a rough idea of how long an option will be */
996 static const uint8_t len_of_option_as_string[] = {
997         [OPTION_IP] = sizeof("255.255.255.255 "),
998         [OPTION_STRING] = 1,
999         [OPTION_U8] = sizeof("255 "),
1000         [OPTION_U16] = sizeof("65535 "),
1001         [OPTION_U32] = sizeof("4294967295 "),
1002 };
1003
1004 static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
1005 {
1006         return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
1007 }
1008
1009 /* Create "opt_value1 option_value2 ..." string */
1010 static char *malloc_option_value_string(uint8_t *option, GDHCPOptionType type)
1011 {
1012         unsigned upper_length;
1013         int len, optlen;
1014         char *dest, *ret;
1015
1016         len = option[OPT_LEN - OPT_DATA];
1017         type &= OPTION_TYPE_MASK;
1018         optlen = dhcp_option_lengths[type];
1019         if (optlen == 0)
1020                 return NULL;
1021         upper_length = len_of_option_as_string[type] *
1022                         ((unsigned)len / (unsigned)optlen);
1023         dest = ret = malloc(upper_length + 1);
1024         if (ret == NULL)
1025                 return NULL;
1026
1027         while (len >= optlen) {
1028                 switch (type) {
1029                 case OPTION_IP:
1030                         dest += sprint_nip(dest, "", option);
1031                         break;
1032                 case OPTION_U16: {
1033                         uint16_t val_u16 = dhcp_get_unaligned(
1034                                                 (uint16_t *) option);
1035                         dest += sprintf(dest, "%u", ntohs(val_u16));
1036                         break;
1037                 }
1038                 case OPTION_U32: {
1039                         uint32_t val_u32 = dhcp_get_unaligned(
1040                                                 (uint32_t *) option);
1041                         dest += sprintf(dest, type == OPTION_U32 ? "%lu" :
1042                                         "%ld", (unsigned long) ntohl(val_u32));
1043                         break;
1044                 }
1045                 case OPTION_STRING:
1046                         memcpy(dest, option, len);
1047                         dest[len] = '\0';
1048                         return ret;
1049                 default:
1050                         break;
1051                 }
1052                 option += optlen;
1053                 len -= optlen;
1054                 if (len <= 0)
1055                         break;
1056                 *dest++ = ' ';
1057                 *dest = '\0';
1058         }
1059
1060         return ret;
1061 }
1062
1063 static GList *get_option_value_list(char *value, GDHCPOptionType type)
1064 {
1065         char *pos = value;
1066         GList *list = NULL;
1067
1068         if (pos == NULL)
1069                 return NULL;
1070
1071         if (type == OPTION_STRING)
1072                 return g_list_append(list, g_strdup(value));
1073
1074         while ((pos = strchr(pos, ' ')) != NULL) {
1075                 *pos = '\0';
1076
1077                 list = g_list_append(list, g_strdup(value));
1078
1079                 value = ++pos;
1080         }
1081
1082         list = g_list_append(list, g_strdup(value));
1083
1084         return list;
1085 }
1086
1087 static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet)
1088 {
1089         GDHCPOptionType type;
1090         GList *list, *value_list;
1091         char *option_value;
1092         uint8_t *option;
1093         uint8_t code;
1094
1095         for (list = dhcp_client->request_list; list; list = list->next) {
1096                 code = (uint8_t) GPOINTER_TO_INT(list->data);
1097
1098                 option = dhcp_get_option(packet, code);
1099                 if (option == NULL) {
1100                         g_hash_table_remove(dhcp_client->code_value_hash,
1101                                                 GINT_TO_POINTER((int) code));
1102                         continue;
1103                 }
1104
1105                 type =  dhcp_get_code_type(code);
1106
1107                 option_value = malloc_option_value_string(option, type);
1108                 if (option_value == NULL)
1109                         g_hash_table_remove(dhcp_client->code_value_hash,
1110                                                 GINT_TO_POINTER((int) code));
1111
1112                 value_list = get_option_value_list(option_value, type);
1113
1114                 g_free(option_value);
1115
1116                 if (value_list == NULL)
1117                         g_hash_table_remove(dhcp_client->code_value_hash,
1118                                                 GINT_TO_POINTER((int) code));
1119                 else
1120                         g_hash_table_insert(dhcp_client->code_value_hash,
1121                                 GINT_TO_POINTER((int) code), value_list);
1122         }
1123 }
1124
1125 static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
1126                                                         gpointer user_data)
1127 {
1128         GDHCPClient *dhcp_client = user_data;
1129         struct dhcp_packet packet;
1130         uint8_t *message_type, *option_u8;
1131         int re;
1132
1133         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
1134                 dhcp_client->listener_watch = 0;
1135                 return FALSE;
1136         }
1137
1138         if (dhcp_client->listen_mode == L_NONE)
1139                 return FALSE;
1140
1141         if (dhcp_client->listen_mode == L2)
1142                 re = dhcp_recv_l2_packet(&packet, dhcp_client->listener_sockfd);
1143         else if (dhcp_client->listen_mode == L3)
1144                 re = dhcp_recv_l3_packet(&packet, dhcp_client->listener_sockfd);
1145         else if (dhcp_client->listen_mode == L_ARP) {
1146                 re = ipv4ll_recv_arp_packet(dhcp_client);
1147                 return TRUE;
1148         }
1149         else
1150                 re = -EIO;
1151
1152         if (re < 0)
1153                 return TRUE;
1154
1155         if (check_package_owner(dhcp_client, &packet) == FALSE)
1156                 return TRUE;
1157
1158         message_type = dhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
1159         if (message_type == NULL)
1160                 /* No message type option, ignore package */
1161                 return TRUE;
1162
1163         debug(dhcp_client, "received DHCP packet (current state %d)",
1164                                                         dhcp_client->state);
1165
1166         switch (dhcp_client->state) {
1167         case INIT_SELECTING:
1168                 if (*message_type != DHCPOFFER)
1169                         return TRUE;
1170
1171                 g_source_remove(dhcp_client->timeout);
1172                 dhcp_client->timeout = 0;
1173                 dhcp_client->retry_times = 0;
1174
1175                 option_u8 = dhcp_get_option(&packet, DHCP_SERVER_ID);
1176                 dhcp_client->server_ip =
1177                                 dhcp_get_unaligned((uint32_t *) option_u8);
1178                 dhcp_client->requested_ip = packet.yiaddr;
1179
1180                 dhcp_client->state = REQUESTING;
1181
1182                 start_request(dhcp_client);
1183
1184                 return TRUE;
1185         case REQUESTING:
1186         case RENEWING:
1187         case REBINDING:
1188                 if (*message_type == DHCPACK) {
1189                         dhcp_client->retry_times = 0;
1190
1191                         if (dhcp_client->timeout > 0)
1192                                 g_source_remove(dhcp_client->timeout);
1193                         dhcp_client->timeout = 0;
1194
1195                         dhcp_client->lease_seconds = get_lease(&packet);
1196
1197                         get_request(dhcp_client, &packet);
1198
1199                         switch_listening_mode(dhcp_client, L_NONE);
1200
1201                         g_free(dhcp_client->assigned_ip);
1202                         dhcp_client->assigned_ip = get_ip(packet.yiaddr);
1203
1204                         /* Address should be set up here */
1205                         if (dhcp_client->lease_available_cb != NULL)
1206                                 dhcp_client->lease_available_cb(dhcp_client,
1207                                         dhcp_client->lease_available_data);
1208
1209                         start_bound(dhcp_client);
1210                 } else if (*message_type == DHCPNAK) {
1211                         dhcp_client->retry_times = 0;
1212
1213                         if (dhcp_client->timeout > 0)
1214                                 g_source_remove(dhcp_client->timeout);
1215
1216                         dhcp_client->timeout = g_timeout_add_seconds_full(
1217                                                         G_PRIORITY_HIGH, 3,
1218                                                         restart_dhcp_timeout,
1219                                                         dhcp_client,
1220                                                         NULL);
1221                 }
1222
1223                 break;
1224         default:
1225                 break;
1226         }
1227
1228         debug(dhcp_client, "processed DHCP packet (new state %d)",
1229                                                         dhcp_client->state);
1230
1231         return TRUE;
1232 }
1233
1234 static gboolean discover_timeout(gpointer user_data)
1235 {
1236         GDHCPClient *dhcp_client = user_data;
1237
1238         dhcp_client->retry_times++;
1239
1240         g_dhcp_client_start(dhcp_client);
1241
1242         return FALSE;
1243 }
1244
1245 static gboolean ipv4ll_defend_timeout(gpointer dhcp_data)
1246 {
1247         GDHCPClient *dhcp_client = dhcp_data;
1248
1249         debug(dhcp_client, "back to MONITOR mode");
1250
1251         dhcp_client->conflicts = 0;
1252         dhcp_client->state = IPV4LL_MONITOR;
1253
1254         return FALSE;
1255 }
1256
1257 static gboolean ipv4ll_announce_timeout(gpointer dhcp_data)
1258 {
1259         GDHCPClient *dhcp_client = dhcp_data;
1260         uint32_t ip;
1261
1262         debug(dhcp_client, "request timeout (retries %d)",
1263                dhcp_client->retry_times);
1264
1265         if (dhcp_client->retry_times != ANNOUNCE_NUM){
1266                 dhcp_client->retry_times++;
1267                 send_announce_packet(dhcp_client);
1268                 return FALSE;
1269         }
1270
1271         ip = htonl(dhcp_client->requested_ip);
1272         debug(dhcp_client, "switching to monitor mode");
1273         dhcp_client->state = IPV4LL_MONITOR;
1274         dhcp_client->assigned_ip = get_ip(ip);
1275
1276         if (dhcp_client->ipv4ll_available_cb != NULL)
1277                 dhcp_client->ipv4ll_available_cb(dhcp_client,
1278                                         dhcp_client->ipv4ll_available_data);
1279         dhcp_client->conflicts = 0;
1280
1281         return FALSE;
1282 }
1283
1284 static gboolean ipv4ll_probe_timeout(gpointer dhcp_data)
1285 {
1286
1287         GDHCPClient *dhcp_client = dhcp_data;
1288
1289         debug(dhcp_client, "IPV4LL probe timeout (retries %d)",
1290                dhcp_client->retry_times);
1291
1292         if (dhcp_client->retry_times == PROBE_NUM) {
1293                 dhcp_client->state = IPV4LL_ANNOUNCE;
1294                 dhcp_client->retry_times = 0;
1295
1296                 dhcp_client->retry_times++;
1297                 send_announce_packet(dhcp_client);
1298                 return FALSE;
1299         }
1300         dhcp_client->retry_times++;
1301         send_probe_packet(dhcp_client);
1302
1303         return FALSE;
1304 }
1305
1306 int g_dhcp_client_start(GDHCPClient *dhcp_client)
1307 {
1308         int re;
1309
1310         if (dhcp_client->retry_times == DISCOVER_RETRIES) {
1311                 ipv4ll_start(dhcp_client);
1312                 return 0;
1313         }
1314
1315         if (dhcp_client->retry_times == 0) {
1316                 g_free(dhcp_client->assigned_ip);
1317                 dhcp_client->assigned_ip = NULL;
1318
1319                 dhcp_client->state = INIT_SELECTING;
1320                 re = switch_listening_mode(dhcp_client, L2);
1321                 if (re != 0)
1322                         return re;
1323
1324                 dhcp_client->xid = rand();
1325         }
1326
1327         send_discover(dhcp_client, 0);
1328
1329         dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
1330                                                         DISCOVER_TIMEOUT,
1331                                                         discover_timeout,
1332                                                         dhcp_client,
1333                                                         NULL);
1334         return 0;
1335 }
1336
1337 void g_dhcp_client_stop(GDHCPClient *dhcp_client)
1338 {
1339         switch_listening_mode(dhcp_client, L_NONE);
1340
1341         if (dhcp_client->state == BOUND ||
1342                         dhcp_client->state == RENEWING ||
1343                                 dhcp_client->state == REBINDING)
1344                 send_release(dhcp_client, dhcp_client->server_ip,
1345                                         dhcp_client->requested_ip);
1346
1347         if (dhcp_client->timeout > 0) {
1348                 g_source_remove(dhcp_client->timeout);
1349                 dhcp_client->timeout = 0;
1350         }
1351
1352         if (dhcp_client->listener_watch > 0) {
1353                 g_source_remove(dhcp_client->listener_watch);
1354                 dhcp_client->listener_watch = 0;
1355         }
1356
1357         dhcp_client->listener_channel = NULL;
1358
1359         dhcp_client->retry_times = 0;
1360         dhcp_client->ack_retry_times = 0;
1361
1362         dhcp_client->requested_ip = 0;
1363         dhcp_client->state = RELEASED;
1364         dhcp_client->lease_seconds = 0;
1365 }
1366
1367 GList *g_dhcp_client_get_option(GDHCPClient *dhcp_client,
1368                                         unsigned char option_code)
1369 {
1370         return g_hash_table_lookup(dhcp_client->code_value_hash,
1371                                         GINT_TO_POINTER((int) option_code));
1372 }
1373
1374 void g_dhcp_client_register_event(GDHCPClient *dhcp_client,
1375                                         GDHCPClientEvent event,
1376                                         GDHCPClientEventFunc func,
1377                                                         gpointer data)
1378 {
1379         switch (event) {
1380         case G_DHCP_CLIENT_EVENT_LEASE_AVAILABLE:
1381                 dhcp_client->lease_available_cb = func;
1382                 dhcp_client->lease_available_data = data;
1383                 return;
1384         case G_DHCP_CLIENT_EVENT_IPV4LL_AVAILABLE:
1385                 dhcp_client->ipv4ll_available_cb = func;
1386                 dhcp_client->ipv4ll_available_data = data;
1387                 return;
1388         case G_DHCP_CLIENT_EVENT_NO_LEASE:
1389                 dhcp_client->no_lease_cb = func;
1390                 dhcp_client->no_lease_data = data;
1391                 return;
1392         case G_DHCP_CLIENT_EVENT_LEASE_LOST:
1393                 dhcp_client->lease_lost_cb = func;
1394                 dhcp_client->lease_lost_data = data;
1395                 return;
1396         case G_DHCP_CLIENT_EVENT_IPV4LL_LOST:
1397                 dhcp_client->ipv4ll_lost_cb = func;
1398                 dhcp_client->ipv4ll_lost_data = data;
1399                 return;
1400         case G_DHCP_CLIENT_EVENT_ADDRESS_CONFLICT:
1401                 dhcp_client->address_conflict_cb = func;
1402                 dhcp_client->address_conflict_data = data;
1403                 return;
1404         }
1405 }
1406
1407 int g_dhcp_client_get_index(GDHCPClient *dhcp_client)
1408 {
1409         return dhcp_client->ifindex;
1410 }
1411
1412 char *g_dhcp_client_get_address(GDHCPClient *dhcp_client)
1413 {
1414         return g_strdup(dhcp_client->assigned_ip);
1415 }
1416
1417 char *g_dhcp_client_get_netmask(GDHCPClient *dhcp_client)
1418 {
1419         GList *option = NULL;
1420
1421         switch (dhcp_client->state) {
1422         case IPV4LL_DEFEND:
1423         case IPV4LL_MONITOR:
1424                 return g_strdup("255.255.0.0");
1425         case BOUND:
1426         case RENEWING:
1427         case REBINDING:
1428                 option = g_dhcp_client_get_option(dhcp_client, G_DHCP_SUBNET);
1429                 if (option != NULL)
1430                         return g_strdup(option->data);
1431         case INIT_SELECTING:
1432         case REQUESTING:
1433         case RELEASED:
1434         case IPV4LL_PROBE:
1435         case IPV4LL_ANNOUNCE:
1436                 break;
1437         }
1438         return NULL;
1439 }
1440
1441 GDHCPClientError g_dhcp_client_set_request(GDHCPClient *dhcp_client,
1442                                                 unsigned char option_code)
1443 {
1444         if (g_list_find(dhcp_client->request_list,
1445                         GINT_TO_POINTER((int) option_code)) == NULL)
1446                 dhcp_client->request_list = g_list_prepend(
1447                                         dhcp_client->request_list,
1448                                         (GINT_TO_POINTER((int) option_code)));
1449
1450         return G_DHCP_CLIENT_ERROR_NONE;
1451 }
1452
1453 static uint8_t *alloc_dhcp_option(int code, const char *str, int extra)
1454 {
1455         uint8_t *storage;
1456         int len = strnlen(str, 255);
1457
1458         storage = malloc(len + extra + OPT_DATA);
1459         storage[OPT_CODE] = code;
1460         storage[OPT_LEN] = len + extra;
1461         memcpy(storage + extra + OPT_DATA, str, len);
1462
1463         return storage;
1464 }
1465
1466 /* Now only support send hostname */
1467 GDHCPClientError g_dhcp_client_set_send(GDHCPClient *dhcp_client,
1468                 unsigned char option_code, const char *option_value)
1469 {
1470         uint8_t *binary_option;
1471
1472         if (option_code == G_DHCP_HOST_NAME && option_value != NULL) {
1473                 binary_option = alloc_dhcp_option(option_code,
1474                                                         option_value, 0);
1475
1476                 g_hash_table_insert(dhcp_client->send_value_hash,
1477                         GINT_TO_POINTER((int) option_code), binary_option);
1478         }
1479
1480         return G_DHCP_CLIENT_ERROR_NONE;
1481 }
1482
1483 GDHCPClient *g_dhcp_client_ref(GDHCPClient *dhcp_client)
1484 {
1485         if (dhcp_client == NULL)
1486                 return NULL;
1487
1488         g_atomic_int_inc(&dhcp_client->ref_count);
1489
1490         return dhcp_client;
1491 }
1492
1493 void g_dhcp_client_unref(GDHCPClient *dhcp_client)
1494 {
1495         if (dhcp_client == NULL)
1496                 return;
1497
1498         if (g_atomic_int_dec_and_test(&dhcp_client->ref_count) == FALSE)
1499                 return;
1500
1501         g_dhcp_client_stop(dhcp_client);
1502
1503         g_free(dhcp_client->interface);
1504         g_free(dhcp_client->assigned_ip);
1505
1506         g_list_free(dhcp_client->request_list);
1507         g_list_free(dhcp_client->require_list);
1508
1509         g_hash_table_destroy(dhcp_client->code_value_hash);
1510         g_hash_table_destroy(dhcp_client->send_value_hash);
1511
1512         g_free(dhcp_client);
1513 }
1514
1515 void g_dhcp_client_set_debug(GDHCPClient *dhcp_client,
1516                                 GDHCPDebugFunc func, gpointer user_data)
1517 {
1518         if (dhcp_client == NULL)
1519                 return;
1520
1521         dhcp_client->debug_func = func;
1522         dhcp_client->debug_data = user_data;
1523 }