ipconfig: Support IPv6 privacy extension for autoconf addresses
[framework/connectivity/connman.git] / src / ipconfig.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-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 #include <stdio.h>
27 #include <net/if.h>
28 #include <net/if_arp.h>
29 #include <linux/if_link.h>
30 #include <string.h>
31 #include <stdlib.h>
32
33 #ifndef IFF_LOWER_UP
34 #define IFF_LOWER_UP    0x10000
35 #endif
36
37 #include <gdbus.h>
38
39 #include "connman.h"
40
41 struct connman_ipconfig {
42         gint refcount;
43         int index;
44         enum connman_ipconfig_type type;
45
46         struct connman_ipconfig *origin;
47
48         const struct connman_ipconfig_ops *ops;
49         void *ops_data;
50
51         enum connman_ipconfig_method method;
52         struct connman_ipaddress *address;
53         struct connman_ipaddress *system;
54
55         int ipv6_privacy_config;
56 };
57
58 struct connman_ipdevice {
59         int index;
60         char *ifname;
61         unsigned short type;
62         unsigned int flags;
63         char *address;
64         uint16_t mtu;
65         uint32_t rx_packets;
66         uint32_t tx_packets;
67         uint32_t rx_bytes;
68         uint32_t tx_bytes;
69         uint32_t rx_errors;
70         uint32_t tx_errors;
71         uint32_t rx_dropped;
72         uint32_t tx_dropped;
73
74         GSList *address_list;
75         char *ipv4_gateway;
76         char *ipv6_gateway;
77
78         char *pac;
79
80         struct connman_ipconfig *config_ipv4;
81         struct connman_ipconfig *config_ipv6;
82
83         gboolean ipv6_enabled;
84         int ipv6_privacy;
85 };
86
87 static GHashTable *ipdevice_hash = NULL;
88 static GList *ipconfig_list = NULL;
89
90 struct connman_ipaddress *connman_ipaddress_alloc(int family)
91 {
92         struct connman_ipaddress *ipaddress;
93
94         ipaddress = g_try_new0(struct connman_ipaddress, 1);
95         if (ipaddress == NULL)
96                 return NULL;
97
98         ipaddress->family = family;
99         ipaddress->prefixlen = 0;
100         ipaddress->local = NULL;
101         ipaddress->peer = NULL;
102         ipaddress->broadcast = NULL;
103         ipaddress->gateway = NULL;
104
105         return ipaddress;
106 }
107
108 void connman_ipaddress_free(struct connman_ipaddress *ipaddress)
109 {
110         if (ipaddress == NULL)
111                 return;
112
113         g_free(ipaddress->broadcast);
114         g_free(ipaddress->peer);
115         g_free(ipaddress->local);
116         g_free(ipaddress->gateway);
117         g_free(ipaddress);
118 }
119
120 unsigned char __connman_ipconfig_netmask_prefix_len(const char *netmask)
121 {
122         unsigned char bits;
123         in_addr_t mask;
124         in_addr_t host;
125
126         if (netmask == NULL)
127                 return 32;
128
129         mask = inet_network(netmask);
130         host = ~mask;
131
132         /* a valid netmask must be 2^n - 1 */
133         if ((host & (host + 1)) != 0)
134                 return -1;
135
136         bits = 0;
137         for (; mask; mask <<= 1)
138                 ++bits;
139
140         return bits;
141 }
142
143 static gboolean check_ipv6_address(const char *address)
144 {
145         unsigned char buf[sizeof(struct in6_addr)];
146         int err;
147
148         err = inet_pton(AF_INET6, address, buf);
149         if (err > 0)
150                 return TRUE;
151
152         return FALSE;
153 }
154
155 int connman_ipaddress_set_ipv6(struct connman_ipaddress *ipaddress,
156                                 const char *address, const char *gateway,
157                                                 unsigned char prefix_length)
158 {
159         if (ipaddress == NULL)
160                 return -EINVAL;
161
162         if (check_ipv6_address(address) == FALSE)
163                 return -EINVAL;
164
165         if (check_ipv6_address(gateway) == FALSE)
166                 return -EINVAL;
167
168         DBG("prefix_len %d address %s gateway %s",
169                         prefix_length, address, gateway);
170
171         ipaddress->prefixlen = prefix_length;
172
173         g_free(ipaddress->local);
174         ipaddress->local = g_strdup(address);
175
176         g_free(ipaddress->gateway);
177         ipaddress->gateway = g_strdup(gateway);
178
179         return 0;
180 }
181
182 void connman_ipaddress_set_ipv4(struct connman_ipaddress *ipaddress,
183                 const char *address, const char *netmask, const char *gateway)
184 {
185         if (ipaddress == NULL)
186                 return;
187
188         ipaddress->prefixlen = __connman_ipconfig_netmask_prefix_len(netmask);
189
190         g_free(ipaddress->local);
191         ipaddress->local = g_strdup(address);
192
193         g_free(ipaddress->gateway);
194         ipaddress->gateway = g_strdup(gateway);
195 }
196
197 void connman_ipaddress_clear(struct connman_ipaddress *ipaddress)
198 {
199         if (ipaddress == NULL)
200                 return;
201
202         ipaddress->prefixlen = 0;
203
204         g_free(ipaddress->local);
205         ipaddress->local = NULL;
206
207         g_free(ipaddress->peer);
208         ipaddress->peer = NULL;
209
210         g_free(ipaddress->broadcast);
211         ipaddress->broadcast = NULL;
212
213         g_free(ipaddress->gateway);
214         ipaddress->gateway = NULL;
215 }
216
217 void connman_ipaddress_copy(struct connman_ipaddress *ipaddress,
218                                         struct connman_ipaddress *source)
219 {
220         if (ipaddress == NULL || source == NULL)
221                 return;
222
223         ipaddress->family = source->family;
224         ipaddress->prefixlen = source->prefixlen;
225
226         g_free(ipaddress->local);
227         ipaddress->local = g_strdup(source->local);
228
229         g_free(ipaddress->peer);
230         ipaddress->peer = g_strdup(source->peer);
231
232         g_free(ipaddress->broadcast);
233         ipaddress->broadcast = g_strdup(source->broadcast);
234
235         g_free(ipaddress->gateway);
236         ipaddress->gateway = g_strdup(source->gateway);
237 }
238
239 static void free_address_list(struct connman_ipdevice *ipdevice)
240 {
241         GSList *list;
242
243         for (list = ipdevice->address_list; list; list = list->next) {
244                 struct connman_ipaddress *ipaddress = list->data;
245
246                 connman_ipaddress_free(ipaddress);
247                 list->data = NULL;
248         }
249
250         g_slist_free(ipdevice->address_list);
251         ipdevice->address_list = NULL;
252 }
253
254 static struct connman_ipaddress *find_ipaddress(struct connman_ipdevice *ipdevice,
255                                 unsigned char prefixlen, const char *local)
256 {
257         GSList *list;
258
259         for (list = ipdevice->address_list; list; list = list->next) {
260                 struct connman_ipaddress *ipaddress = list->data;
261
262                 if (g_strcmp0(ipaddress->local, local) == 0 &&
263                                         ipaddress->prefixlen == prefixlen)
264                         return ipaddress;
265         }
266
267         return NULL;
268 }
269
270 static const char *type2str(unsigned short type)
271 {
272         switch (type) {
273         case ARPHRD_ETHER:
274                 return "ETHER";
275         case ARPHRD_LOOPBACK:
276                 return "LOOPBACK";
277         case ARPHRD_PPP:
278                 return "PPP";
279         case ARPHRD_NONE:
280                 return "NONE";
281         case ARPHRD_VOID:
282                 return "VOID";
283         }
284
285         return "";
286 }
287
288 static const char *scope2str(unsigned char scope)
289 {
290         switch (scope) {
291         case 0:
292                 return "UNIVERSE";
293         case 253:
294                 return "LINK";
295         }
296
297         return "";
298 }
299
300 static gboolean get_ipv6_state(gchar *ifname)
301 {
302         int disabled;
303         gchar *path;
304         FILE *f;
305         gboolean enabled = FALSE;
306
307         if (ifname == NULL)
308                 path = g_strdup("/proc/sys/net/ipv6/conf/all/disable_ipv6");
309         else
310                 path = g_strdup_printf(
311                         "/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifname);
312
313         if (path == NULL)
314                 return enabled;
315
316         f = fopen(path, "r");
317
318         g_free(path);
319
320         if (f != NULL) {
321                 if (fscanf(f, "%d", &disabled) > 0)
322                         enabled = !disabled;
323                 fclose(f);
324         }
325
326         return enabled;
327 }
328
329 static void set_ipv6_state(gchar *ifname, gboolean enable)
330 {
331         gchar *path;
332         FILE *f;
333
334         if (ifname == NULL)
335                 path = g_strdup("/proc/sys/net/ipv6/conf/all/disable_ipv6");
336         else
337                 path = g_strdup_printf(
338                         "/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifname);
339
340         if (path == NULL)
341                 return;
342
343         f = fopen(path, "r+");
344
345         g_free(path);
346
347         if (f == NULL)
348                 return;
349
350         if (enable == FALSE)
351                 fprintf(f, "1");
352         else
353                 fprintf(f, "0");
354
355         fclose(f);
356 }
357
358 static int get_ipv6_privacy(gchar *ifname)
359 {
360         gchar *path;
361         FILE *f;
362         int value;
363
364         if (ifname == NULL)
365                 return 0;
366
367         path = g_strdup_printf("/proc/sys/net/ipv6/conf/%s/use_tempaddr",
368                                                                 ifname);
369
370         if (path == NULL)
371                 return 0;
372
373         f = fopen(path, "r");
374
375         g_free(path);
376
377         if (f == NULL)
378                 return 0;
379
380         if (fscanf(f, "%d", &value) <= 0)
381                 value = 0;
382
383         fclose(f);
384
385         return value;
386 }
387
388 /* Enable the IPv6 privacy extension for stateless address autoconfiguration.
389  * The privacy extension is described in RFC 3041 and RFC 4941
390  */
391 static void set_ipv6_privacy(gchar *ifname, int value)
392 {
393         gchar *path;
394         FILE *f;
395
396         if (ifname == NULL)
397                 return;
398
399         path = g_strdup_printf("/proc/sys/net/ipv6/conf/%s/use_tempaddr",
400                                                                 ifname);
401
402         if (path == NULL)
403                 return;
404
405         if (value < 0)
406                 value = 0;
407
408         f = fopen(path, "r+");
409
410         g_free(path);
411
412         if (f == NULL)
413                 return;
414
415         fprintf(f, "%d", value);
416         fclose(f);
417 }
418
419 static void free_ipdevice(gpointer data)
420 {
421         struct connman_ipdevice *ipdevice = data;
422
423         connman_info("%s {remove} index %d", ipdevice->ifname,
424                                                         ipdevice->index);
425
426         if (ipdevice->config_ipv4 != NULL) {
427                 connman_ipconfig_unref(ipdevice->config_ipv4);
428                 ipdevice->config_ipv4 = NULL;
429         }
430
431         if (ipdevice->config_ipv6 != NULL) {
432                 connman_ipconfig_unref(ipdevice->config_ipv6);
433                 ipdevice->config_ipv6 = NULL;
434         }
435
436         free_address_list(ipdevice);
437         g_free(ipdevice->ipv4_gateway);
438         g_free(ipdevice->ipv6_gateway);
439         g_free(ipdevice->pac);
440
441         g_free(ipdevice->address);
442
443         set_ipv6_state(ipdevice->ifname, ipdevice->ipv6_enabled);
444         set_ipv6_privacy(ipdevice->ifname, ipdevice->ipv6_privacy);
445
446         g_free(ipdevice->ifname);
447         g_free(ipdevice);
448 }
449
450 static void __connman_ipconfig_lower_up(struct connman_ipdevice *ipdevice)
451 {
452         DBG("ipconfig ipv4 %p ipv6 %p", ipdevice->config_ipv4,
453                                         ipdevice->config_ipv6);
454 }
455
456 static void __connman_ipconfig_lower_down(struct connman_ipdevice *ipdevice)
457 {
458         DBG("ipconfig ipv4 %p ipv6 %p", ipdevice->config_ipv4,
459                                         ipdevice->config_ipv6);
460
461         if (ipdevice->config_ipv4)
462                 connman_inet_clear_address(ipdevice->index,
463                                         ipdevice->config_ipv4->address);
464
465         if (ipdevice->config_ipv6)
466                 connman_inet_clear_ipv6_address(ipdevice->index,
467                                 ipdevice->config_ipv6->address->local,
468                                 ipdevice->config_ipv6->address->prefixlen);
469 }
470
471 static void update_stats(struct connman_ipdevice *ipdevice,
472                                                 struct rtnl_link_stats *stats)
473 {
474         struct connman_service *service;
475
476         if (stats->rx_packets == 0 && stats->tx_packets == 0)
477                 return;
478
479         connman_info("%s {RX} %u packets %u bytes", ipdevice->ifname,
480                                         stats->rx_packets, stats->rx_bytes);
481         connman_info("%s {TX} %u packets %u bytes", ipdevice->ifname,
482                                         stats->tx_packets, stats->tx_bytes);
483
484         if (ipdevice->config_ipv4 == NULL && ipdevice->config_ipv6 == NULL)
485                 return;
486
487         if (ipdevice->config_ipv4)
488                 service = connman_ipconfig_get_data(ipdevice->config_ipv4);
489         else if (ipdevice->config_ipv6)
490                 service = connman_ipconfig_get_data(ipdevice->config_ipv6);
491         else
492                 return;
493
494         if (service == NULL)
495                 return;
496
497         ipdevice->rx_packets = stats->rx_packets;
498         ipdevice->tx_packets = stats->tx_packets;
499         ipdevice->rx_bytes = stats->rx_bytes;
500         ipdevice->tx_bytes = stats->tx_bytes;
501         ipdevice->rx_errors = stats->rx_errors;
502         ipdevice->tx_errors = stats->tx_errors;
503         ipdevice->rx_dropped = stats->rx_dropped;
504         ipdevice->tx_dropped = stats->tx_dropped;
505
506         __connman_service_notify(service,
507                                 ipdevice->rx_packets, ipdevice->tx_packets,
508                                 ipdevice->rx_bytes, ipdevice->tx_bytes,
509                                 ipdevice->rx_errors, ipdevice->tx_errors,
510                                 ipdevice->rx_dropped, ipdevice->tx_dropped);
511 }
512
513 void __connman_ipconfig_newlink(int index, unsigned short type,
514                                 unsigned int flags, const char *address,
515                                                         unsigned short mtu,
516                                                 struct rtnl_link_stats *stats)
517 {
518         struct connman_ipdevice *ipdevice;
519         GList *list;
520         GString *str;
521         gboolean up = FALSE, down = FALSE;
522         gboolean lower_up = FALSE, lower_down = FALSE;
523
524         DBG("index %d", index);
525
526         if (type == ARPHRD_LOOPBACK)
527                 return;
528
529         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
530         if (ipdevice != NULL)
531                 goto update;
532
533         ipdevice = g_try_new0(struct connman_ipdevice, 1);
534         if (ipdevice == NULL)
535                 return;
536
537         ipdevice->index = index;
538         ipdevice->ifname = connman_inet_ifname(index);
539         ipdevice->type = type;
540
541         ipdevice->ipv6_enabled = get_ipv6_state(ipdevice->ifname);
542         ipdevice->ipv6_privacy = get_ipv6_privacy(ipdevice->ifname);
543
544         ipdevice->address = g_strdup(address);
545
546         g_hash_table_insert(ipdevice_hash, GINT_TO_POINTER(index), ipdevice);
547
548         connman_info("%s {create} index %d type %d <%s>", ipdevice->ifname,
549                                                 index, type, type2str(type));
550
551 update:
552         ipdevice->mtu = mtu;
553
554         update_stats(ipdevice, stats);
555
556         if (flags == ipdevice->flags)
557                 return;
558
559         if ((ipdevice->flags & IFF_UP) != (flags & IFF_UP)) {
560                 if (flags & IFF_UP)
561                         up = TRUE;
562                 else
563                         down = TRUE;
564         }
565
566         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) !=
567                                 (flags & (IFF_RUNNING | IFF_LOWER_UP))) {
568                 if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) ==
569                                         (IFF_RUNNING | IFF_LOWER_UP))
570                         lower_up = TRUE;
571                 else if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) == 0)
572                         lower_down = TRUE;
573         }
574
575         ipdevice->flags = flags;
576
577         str = g_string_new(NULL);
578         if (str == NULL)
579                 return;
580
581         if (flags & IFF_UP)
582                 g_string_append(str, "UP");
583         else
584                 g_string_append(str, "DOWN");
585
586         if (flags & IFF_RUNNING)
587                 g_string_append(str, ",RUNNING");
588
589         if (flags & IFF_LOWER_UP)
590                 g_string_append(str, ",LOWER_UP");
591
592         connman_info("%s {update} flags %u <%s>", ipdevice->ifname,
593                                                         flags, str->str);
594
595         g_string_free(str, TRUE);
596
597         for (list = g_list_first(ipconfig_list); list;
598                                                 list = g_list_next(list)) {
599                 struct connman_ipconfig *ipconfig = list->data;
600
601                 if (index != ipconfig->index)
602                         continue;
603
604                 if (ipconfig->ops == NULL)
605                         continue;
606
607                 if (up == TRUE && ipconfig->ops->up)
608                         ipconfig->ops->up(ipconfig);
609                 if (lower_up == TRUE && ipconfig->ops->lower_up)
610                         ipconfig->ops->lower_up(ipconfig);
611
612                 if (lower_down == TRUE && ipconfig->ops->lower_down)
613                         ipconfig->ops->lower_down(ipconfig);
614                 if (down == TRUE && ipconfig->ops->down)
615                         ipconfig->ops->down(ipconfig);
616         }
617
618         if (lower_up)
619                 __connman_ipconfig_lower_up(ipdevice);
620         if (lower_down)
621                 __connman_ipconfig_lower_down(ipdevice);
622 }
623
624 void __connman_ipconfig_dellink(int index, struct rtnl_link_stats *stats)
625 {
626         struct connman_ipdevice *ipdevice;
627         GList *list;
628
629         DBG("index %d", index);
630
631         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
632         if (ipdevice == NULL)
633                 return;
634
635         update_stats(ipdevice, stats);
636
637         for (list = g_list_first(ipconfig_list); list;
638                                                 list = g_list_next(list)) {
639                 struct connman_ipconfig *ipconfig = list->data;
640
641                 if (index != ipconfig->index)
642                         continue;
643
644                 ipconfig->index = -1;
645
646                 if (ipconfig->ops == NULL)
647                         continue;
648
649                 if (ipconfig->ops->lower_down)
650                         ipconfig->ops->lower_down(ipconfig);
651                 if (ipconfig->ops->down)
652                         ipconfig->ops->down(ipconfig);
653         }
654
655         __connman_ipconfig_lower_down(ipdevice);
656
657         g_hash_table_remove(ipdevice_hash, GINT_TO_POINTER(index));
658 }
659
660 static inline gint check_duplicate_address(gconstpointer a, gconstpointer b)
661 {
662         const struct connman_ipaddress *addr1 = a;
663         const struct connman_ipaddress *addr2 = b;
664
665         if (addr1->prefixlen != addr2->prefixlen)
666                 return addr2->prefixlen - addr1->prefixlen;
667
668         return g_strcmp0(addr1->local, addr2->local);
669 }
670
671 void __connman_ipconfig_newaddr(int index, int family, const char *label,
672                                 unsigned char prefixlen, const char *address)
673 {
674         struct connman_ipdevice *ipdevice;
675         struct connman_ipaddress *ipaddress;
676         GList *list;
677
678         DBG("index %d", index);
679
680         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
681         if (ipdevice == NULL)
682                 return;
683
684         ipaddress = connman_ipaddress_alloc(family);
685         if (ipaddress == NULL)
686                 return;
687
688         ipaddress->prefixlen = prefixlen;
689         ipaddress->local = g_strdup(address);
690
691         if (g_slist_find_custom(ipdevice->address_list, ipaddress,
692                                         check_duplicate_address)) {
693                 connman_ipaddress_free(ipaddress);
694                 return;
695         }
696
697         ipdevice->address_list = g_slist_append(ipdevice->address_list,
698                                                                 ipaddress);
699
700         connman_info("%s {add} address %s/%u label %s family %d",
701                 ipdevice->ifname, address, prefixlen, label, family);
702
703         if (ipdevice->config_ipv4 != NULL && family == AF_INET)
704                 connman_ipaddress_copy(ipdevice->config_ipv4->system,
705                                         ipaddress);
706
707         else if (ipdevice->config_ipv6 != NULL && family == AF_INET6)
708                 connman_ipaddress_copy(ipdevice->config_ipv6->system,
709                                         ipaddress);
710         else
711                 return;
712
713         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
714                 return;
715
716         for (list = g_list_first(ipconfig_list); list;
717                                                 list = g_list_next(list)) {
718                 struct connman_ipconfig *ipconfig = list->data;
719
720                 if (index != ipconfig->index)
721                         continue;
722
723                 if (ipconfig->ops == NULL)
724                         continue;
725
726                 if (ipconfig->ops->ip_bound)
727                         ipconfig->ops->ip_bound(ipconfig);
728         }
729 }
730
731 void __connman_ipconfig_deladdr(int index, int family, const char *label,
732                                 unsigned char prefixlen, const char *address)
733 {
734         struct connman_ipdevice *ipdevice;
735         struct connman_ipaddress *ipaddress;
736         GList *list;
737
738         DBG("index %d", index);
739
740         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
741         if (ipdevice == NULL)
742                 return;
743
744         ipaddress = find_ipaddress(ipdevice, prefixlen, address);
745         if (ipaddress == NULL)
746                 return;
747
748         ipdevice->address_list = g_slist_remove(ipdevice->address_list,
749                                                                 ipaddress);
750
751         connman_ipaddress_clear(ipaddress);
752         g_free(ipaddress);
753
754         connman_info("%s {del} address %s/%u label %s", ipdevice->ifname,
755                                                 address, prefixlen, label);
756
757         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
758                 return;
759
760         if (g_slist_length(ipdevice->address_list) > 0)
761                 return;
762
763         for (list = g_list_first(ipconfig_list); list;
764                                                 list = g_list_next(list)) {
765                 struct connman_ipconfig *ipconfig = list->data;
766
767                 if (index != ipconfig->index)
768                         continue;
769
770                 if (ipconfig->ops == NULL)
771                         continue;
772
773                 if (ipconfig->ops->ip_release)
774                         ipconfig->ops->ip_release(ipconfig);
775         }
776 }
777
778 void __connman_ipconfig_newroute(int index, int family, unsigned char scope,
779                                         const char *dst, const char *gateway)
780 {
781         struct connman_ipdevice *ipdevice;
782
783         DBG("index %d", index);
784
785         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
786         if (ipdevice == NULL)
787                 return;
788
789         if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
790                 GSList *list;
791                 GList *config_list;
792
793                 if (family == AF_INET6) {
794                         g_free(ipdevice->ipv6_gateway);
795                         ipdevice->ipv6_gateway = g_strdup(gateway);
796
797                         if (ipdevice->config_ipv6 != NULL &&
798                                 ipdevice->config_ipv6->system != NULL) {
799                                 g_free(ipdevice->config_ipv6->system->gateway);
800                                 ipdevice->config_ipv6->system->gateway =
801                                         g_strdup(gateway);
802                         }
803                 } else {
804                         g_free(ipdevice->ipv4_gateway);
805                         ipdevice->ipv4_gateway = g_strdup(gateway);
806
807                         if (ipdevice->config_ipv4 != NULL &&
808                                 ipdevice->config_ipv4->system != NULL) {
809                                 g_free(ipdevice->config_ipv4->system->gateway);
810                                 ipdevice->config_ipv4->system->gateway =
811                                         g_strdup(gateway);
812                         }
813                 }
814
815                 for (list = ipdevice->address_list; list; list = list->next) {
816                         struct connman_ipaddress *ipaddress = list->data;
817
818                         g_free(ipaddress->gateway);
819                         ipaddress->gateway = g_strdup(gateway);
820                 }
821
822                 for (config_list = g_list_first(ipconfig_list); config_list;
823                                         config_list = g_list_next(config_list)) {
824                         struct connman_ipconfig *ipconfig = config_list->data;
825
826                         if (index != ipconfig->index)
827                                 continue;
828
829                         if (ipconfig->ops == NULL)
830                                 continue;
831
832                         if (ipconfig->ops->ip_bound)
833                                 ipconfig->ops->ip_bound(ipconfig);
834                 }
835         }
836
837         connman_info("%s {add} route %s gw %s scope %u <%s>",
838                                         ipdevice->ifname, dst, gateway,
839                                                 scope, scope2str(scope));
840 }
841
842 void __connman_ipconfig_delroute(int index, int family, unsigned char scope,
843                                         const char *dst, const char *gateway)
844 {
845         struct connman_ipdevice *ipdevice;
846
847         DBG("index %d", index);
848
849         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
850         if (ipdevice == NULL)
851                 return;
852
853         if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
854                 GSList *list;
855                 GList *config_list;
856
857                 if (family == AF_INET6) {
858                         g_free(ipdevice->ipv6_gateway);
859                         ipdevice->ipv6_gateway = NULL;
860
861                         if (ipdevice->config_ipv6 != NULL &&
862                                 ipdevice->config_ipv6->system != NULL) {
863                                 g_free(ipdevice->config_ipv6->system->gateway);
864                                 ipdevice->config_ipv6->system->gateway = NULL;
865                         }
866                 } else {
867                         g_free(ipdevice->ipv4_gateway);
868                         ipdevice->ipv4_gateway = NULL;
869
870                         if (ipdevice->config_ipv4 != NULL &&
871                                 ipdevice->config_ipv4->system != NULL) {
872                                 g_free(ipdevice->config_ipv4->system->gateway);
873                                 ipdevice->config_ipv4->system->gateway = NULL;
874                         }
875                 }
876
877                 for (list = ipdevice->address_list; list; list = list->next) {
878                         struct connman_ipaddress *ipaddress = list->data;
879
880                         g_free(ipaddress->gateway);
881                         ipaddress->gateway = NULL;
882                 }
883
884                 for (config_list = g_list_first(ipconfig_list); config_list;
885                                         config_list = g_list_next(config_list)) {
886                         struct connman_ipconfig *ipconfig = config_list->data;
887
888                         if (index != ipconfig->index)
889                                 continue;
890
891                         if (ipconfig->ops == NULL)
892                                 continue;
893
894                         if (ipconfig->ops->ip_release)
895                                 ipconfig->ops->ip_release(ipconfig);
896                 }
897         }
898
899         connman_info("%s {del} route %s gw %s scope %u <%s>",
900                                         ipdevice->ifname, dst, gateway,
901                                                 scope, scope2str(scope));
902 }
903
904 void __connman_ipconfig_foreach(void (*function) (int index, void *user_data),
905                                                         void *user_data)
906 {
907         GList *list, *keys;
908
909         keys = g_hash_table_get_keys(ipdevice_hash);
910         if (keys == NULL)
911                 return;
912
913         for (list = g_list_first(keys); list; list = g_list_next(list)) {
914                 int index = GPOINTER_TO_INT(list->data);
915
916                 function(index, user_data);
917         }
918
919         g_list_free(keys);
920 }
921
922 enum connman_ipconfig_type __connman_ipconfig_get_config_type(
923                                         struct connman_ipconfig *ipconfig)
924 {
925         return ipconfig ? ipconfig->type : CONNMAN_IPCONFIG_TYPE_UNKNOWN;
926 }
927
928 unsigned short __connman_ipconfig_get_type_from_index(int index)
929 {
930         struct connman_ipdevice *ipdevice;
931
932         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
933         if (ipdevice == NULL)
934                 return ARPHRD_VOID;
935
936         return ipdevice->type;
937 }
938
939 unsigned int __connman_ipconfig_get_flags_from_index(int index)
940 {
941         struct connman_ipdevice *ipdevice;
942
943         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
944         if (ipdevice == NULL)
945                 return 0;
946
947         return ipdevice->flags;
948 }
949
950 const char *__connman_ipconfig_get_gateway_from_index(int index)
951 {
952         struct connman_ipdevice *ipdevice;
953
954         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
955         if (ipdevice == NULL)
956                 return NULL;
957
958         if (ipdevice->ipv4_gateway != NULL)
959                 return ipdevice->ipv4_gateway;
960
961         if (ipdevice->config_ipv4 != NULL &&
962                         ipdevice->config_ipv4->address != NULL)
963                 return ipdevice->config_ipv4->address->gateway;
964
965         if (ipdevice->ipv6_gateway != NULL)
966                 return ipdevice->ipv6_gateway;
967
968         if (ipdevice->config_ipv6 != NULL &&
969                         ipdevice->config_ipv6->address != NULL)
970                 return ipdevice->config_ipv6->address->gateway;
971
972         return NULL;
973 }
974
975 void __connman_ipconfig_set_index(struct connman_ipconfig *ipconfig, int index)
976 {
977         ipconfig->index = index;
978 }
979
980 const char *__connman_ipconfig_get_local(struct connman_ipconfig *ipconfig)
981 {
982         if (ipconfig->address == NULL)
983                 return NULL;
984
985         return ipconfig->address->local;
986 }
987
988 void __connman_ipconfig_set_local(struct connman_ipconfig *ipconfig, const char *address)
989 {
990         if (ipconfig->address == NULL)
991                 return;
992
993         g_free(ipconfig->address->local);
994         ipconfig->address->local = g_strdup(address);
995 }
996
997 const char *__connman_ipconfig_get_peer(struct connman_ipconfig *ipconfig)
998 {
999         if (ipconfig->address == NULL)
1000                 return NULL;
1001
1002         return ipconfig->address->peer;
1003 }
1004
1005 void __connman_ipconfig_set_peer(struct connman_ipconfig *ipconfig, const char *address)
1006 {
1007         if (ipconfig->address == NULL)
1008                 return;
1009
1010         g_free(ipconfig->address->peer);
1011         ipconfig->address->peer = g_strdup(address);
1012 }
1013
1014 const char *__connman_ipconfig_get_broadcast(struct connman_ipconfig *ipconfig)
1015 {
1016         if (ipconfig->address == NULL)
1017                 return NULL;
1018
1019         return ipconfig->address->broadcast;
1020 }
1021
1022 void __connman_ipconfig_set_broadcast(struct connman_ipconfig *ipconfig, const char *broadcast)
1023 {
1024         if (ipconfig->address == NULL)
1025                 return;
1026
1027         g_free(ipconfig->address->broadcast);
1028         ipconfig->address->broadcast = g_strdup(broadcast);
1029 }
1030
1031 const char *__connman_ipconfig_get_gateway(struct connman_ipconfig *ipconfig)
1032 {
1033         if (ipconfig->address == NULL)
1034                 return NULL;
1035
1036         return ipconfig->address->gateway;
1037 }
1038
1039 void __connman_ipconfig_set_gateway(struct connman_ipconfig *ipconfig, const char *gateway)
1040 {
1041         struct connman_service *service;
1042
1043         if (ipconfig->address == NULL)
1044                 return;
1045
1046         service = __connman_service_lookup_from_index(ipconfig->index);
1047         if (service != NULL)
1048                 __connman_connection_gateway_remove(service);
1049
1050         g_free(ipconfig->address->gateway);
1051         ipconfig->address->gateway = g_strdup(gateway);
1052
1053         if (service != NULL && ipconfig->address->gateway != NULL) {
1054                 if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) {
1055                         __connman_connection_gateway_add(service,
1056                                                 NULL,
1057                                                 ipconfig->address->gateway,
1058                                                 ipconfig->address->peer);
1059                 } else if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4) {
1060                         __connman_connection_gateway_add(service,
1061                                                 ipconfig->address->gateway,
1062                                                 NULL,
1063                                                 ipconfig->address->peer);
1064                 }
1065         }
1066 }
1067
1068 unsigned char __connman_ipconfig_get_prefixlen(struct connman_ipconfig *ipconfig)
1069 {
1070         if (ipconfig->address == NULL)
1071                 return 0;
1072
1073         return ipconfig->address->prefixlen;
1074 }
1075
1076 void __connman_ipconfig_set_prefixlen(struct connman_ipconfig *ipconfig, unsigned char prefixlen)
1077 {
1078         if (ipconfig->address == NULL)
1079                 return;
1080
1081         ipconfig->address->prefixlen = prefixlen;
1082 }
1083
1084 static struct connman_ipconfig *create_ipv6config(int index)
1085 {
1086         struct connman_ipconfig *ipv6config;
1087
1088         DBG("index %d", index);
1089
1090         ipv6config = g_try_new0(struct connman_ipconfig, 1);
1091         if (ipv6config == NULL)
1092                 return NULL;
1093
1094         ipv6config->refcount = 1;
1095
1096         ipv6config->index = index;
1097         ipv6config->type = CONNMAN_IPCONFIG_TYPE_IPV6;
1098         ipv6config->method = CONNMAN_IPCONFIG_METHOD_AUTO;
1099         ipv6config->ipv6_privacy_config = 0;
1100
1101         ipv6config->address = connman_ipaddress_alloc(AF_INET6);
1102         if (ipv6config->address == NULL) {
1103                 g_free(ipv6config);
1104                 return NULL;
1105         }
1106
1107         ipv6config->system = connman_ipaddress_alloc(AF_INET6);
1108
1109         DBG("ipconfig %p", ipv6config);
1110
1111         return ipv6config;
1112 }
1113
1114 /**
1115  * connman_ipconfig_create:
1116  *
1117  * Allocate a new ipconfig structure.
1118  *
1119  * Returns: a newly-allocated #connman_ipconfig structure
1120  */
1121 struct connman_ipconfig *connman_ipconfig_create(int index,
1122                                         enum connman_ipconfig_type type)
1123 {
1124         struct connman_ipconfig *ipconfig;
1125
1126         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
1127                 return create_ipv6config(index);
1128
1129         DBG("index %d", index);
1130
1131         ipconfig = g_try_new0(struct connman_ipconfig, 1);
1132         if (ipconfig == NULL)
1133                 return NULL;
1134
1135         ipconfig->refcount = 1;
1136
1137         ipconfig->index = index;
1138         ipconfig->type = CONNMAN_IPCONFIG_TYPE_IPV4;
1139
1140         ipconfig->address = connman_ipaddress_alloc(AF_INET);
1141         if (ipconfig->address == NULL) {
1142                 g_free(ipconfig);
1143                 return NULL;
1144         }
1145
1146         ipconfig->system = connman_ipaddress_alloc(AF_INET);
1147
1148         DBG("ipconfig %p", ipconfig);
1149
1150         return ipconfig;
1151 }
1152
1153
1154 /**
1155  * connman_ipconfig_ref:
1156  * @ipconfig: ipconfig structure
1157  *
1158  * Increase reference counter of ipconfig
1159  */
1160 struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig)
1161 {
1162         DBG("ipconfig %p refcount %d", ipconfig,
1163                                 g_atomic_int_get(&ipconfig->refcount) + 1);
1164
1165         g_atomic_int_inc(&ipconfig->refcount);
1166
1167         return ipconfig;
1168 }
1169
1170 /**
1171  * connman_ipconfig_unref:
1172  * @ipconfig: ipconfig structure
1173  *
1174  * Decrease reference counter of ipconfig
1175  */
1176 void connman_ipconfig_unref(struct connman_ipconfig *ipconfig)
1177 {
1178         if (ipconfig == NULL)
1179                 return;
1180
1181         DBG("ipconfig %p refcount %d", ipconfig,
1182                         g_atomic_int_get(&ipconfig->refcount) - 1);
1183
1184         if (g_atomic_int_dec_and_test(&ipconfig->refcount) == TRUE) {
1185                 __connman_ipconfig_disable(ipconfig);
1186
1187                 connman_ipconfig_set_ops(ipconfig, NULL);
1188
1189                 if (ipconfig->origin != NULL) {
1190                         connman_ipconfig_unref(ipconfig->origin);
1191                         ipconfig->origin = NULL;
1192                 }
1193
1194                 connman_ipaddress_free(ipconfig->system);
1195                 connman_ipaddress_free(ipconfig->address);
1196                 g_free(ipconfig);
1197         }
1198 }
1199
1200 /**
1201  * connman_ipconfig_get_data:
1202  * @ipconfig: ipconfig structure
1203  *
1204  * Get private data pointer
1205  */
1206 void *connman_ipconfig_get_data(struct connman_ipconfig *ipconfig)
1207 {
1208         if (ipconfig == NULL)
1209                 return NULL;
1210
1211         return ipconfig->ops_data;
1212 }
1213
1214 /**
1215  * connman_ipconfig_set_data:
1216  * @ipconfig: ipconfig structure
1217  * @data: data pointer
1218  *
1219  * Set private data pointer
1220  */
1221 void connman_ipconfig_set_data(struct connman_ipconfig *ipconfig, void *data)
1222 {
1223         ipconfig->ops_data = data;
1224 }
1225
1226 /**
1227  * connman_ipconfig_get_index:
1228  * @ipconfig: ipconfig structure
1229  *
1230  * Get interface index
1231  */
1232 int connman_ipconfig_get_index(struct connman_ipconfig *ipconfig)
1233 {
1234         if (ipconfig == NULL)
1235                 return -1;
1236
1237         if (ipconfig->origin != NULL)
1238                 return ipconfig->origin->index;
1239
1240         return ipconfig->index;
1241 }
1242
1243 /**
1244  * connman_ipconfig_get_ifname:
1245  * @ipconfig: ipconfig structure
1246  *
1247  * Get interface name
1248  */
1249 const char *connman_ipconfig_get_ifname(struct connman_ipconfig *ipconfig)
1250 {
1251         struct connman_ipdevice *ipdevice;
1252
1253         if (ipconfig == NULL)
1254                 return NULL;
1255
1256         if (ipconfig->index < 0)
1257                 return NULL;
1258
1259         ipdevice = g_hash_table_lookup(ipdevice_hash,
1260                                         GINT_TO_POINTER(ipconfig->index));
1261         if (ipdevice == NULL)
1262                 return NULL;
1263
1264         return ipdevice->ifname;
1265 }
1266
1267 /**
1268  * connman_ipconfig_set_ops:
1269  * @ipconfig: ipconfig structure
1270  * @ops: operation callbacks
1271  *
1272  * Set the operation callbacks
1273  */
1274 void connman_ipconfig_set_ops(struct connman_ipconfig *ipconfig,
1275                                 const struct connman_ipconfig_ops *ops)
1276 {
1277         ipconfig->ops = ops;
1278 }
1279
1280 /**
1281  * connman_ipconfig_set_method:
1282  * @ipconfig: ipconfig structure
1283  * @method: configuration method
1284  *
1285  * Set the configuration method
1286  */
1287 int connman_ipconfig_set_method(struct connman_ipconfig *ipconfig,
1288                                         enum connman_ipconfig_method method)
1289 {
1290         ipconfig->method = method;
1291
1292         return 0;
1293 }
1294
1295 enum connman_ipconfig_method __connman_ipconfig_get_method(struct connman_ipconfig *ipconfig)
1296 {
1297         if (ipconfig == NULL)
1298                 return CONNMAN_IPCONFIG_METHOD_UNKNOWN;
1299
1300         return ipconfig->method;
1301 }
1302
1303 /**
1304  * connman_ipconfig_bind:
1305  * @ipconfig: ipconfig structure
1306  * @ipaddress: ipaddress structure
1307  *
1308  * Bind IP address details to configuration
1309  */
1310 void connman_ipconfig_bind(struct connman_ipconfig *ipconfig,
1311                                         struct connman_ipaddress *ipaddress)
1312 {
1313         struct connman_ipconfig *origin;
1314
1315         origin = ipconfig->origin ? ipconfig->origin : ipconfig;
1316
1317         connman_ipaddress_copy(origin->address, ipaddress);
1318
1319         connman_inet_set_address(origin->index, origin->address);
1320 }
1321
1322 void __connman_ipconfig_set_element_ipv6_gateway(
1323                         struct connman_ipconfig *ipconfig,
1324                                 struct connman_element *element)
1325 {
1326         if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
1327                 element->ipv6.gateway = ipconfig->address->gateway;
1328 }
1329
1330 int __connman_ipconfig_set_address(struct connman_ipconfig *ipconfig)
1331 {
1332         DBG("");
1333
1334         switch (ipconfig->method) {
1335         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1336         case CONNMAN_IPCONFIG_METHOD_OFF:
1337         case CONNMAN_IPCONFIG_METHOD_FIXED:
1338         case CONNMAN_IPCONFIG_METHOD_DHCP:
1339         case CONNMAN_IPCONFIG_METHOD_AUTO:
1340                 break;
1341         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1342                 if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4)
1343                         return connman_inet_set_address(ipconfig->index,
1344                                                         ipconfig->address);
1345                 else if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
1346                         return connman_inet_set_ipv6_address(
1347                                         ipconfig->index, ipconfig->address);
1348         }
1349
1350         return 0;
1351 }
1352
1353 int __connman_ipconfig_clear_address(struct connman_ipconfig *ipconfig)
1354 {
1355         DBG("");
1356
1357         if (ipconfig == NULL)
1358                 return 0;
1359
1360         DBG("method %d", ipconfig->method);
1361
1362         switch (ipconfig->method) {
1363         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1364         case CONNMAN_IPCONFIG_METHOD_OFF:
1365         case CONNMAN_IPCONFIG_METHOD_FIXED:
1366         case CONNMAN_IPCONFIG_METHOD_DHCP:
1367         case CONNMAN_IPCONFIG_METHOD_AUTO:
1368                 break;
1369         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1370                 if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4)
1371                         return connman_inet_clear_address(ipconfig->index,
1372                                                         ipconfig->address);
1373                 else if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
1374                         return connman_inet_clear_ipv6_address(
1375                                                 ipconfig->index,
1376                                                 ipconfig->address->local,
1377                                                 ipconfig->address->prefixlen);
1378         }
1379
1380         return 0;
1381 }
1382
1383 int __connman_ipconfig_set_proxy_autoconfig(struct connman_ipconfig *ipconfig,
1384                                                         const char *url)
1385 {
1386         struct connman_ipdevice *ipdevice;
1387
1388         DBG("ipconfig %p", ipconfig);
1389
1390         if (ipconfig == NULL || ipconfig->index < 0)
1391                 return -ENODEV;
1392
1393         ipdevice = g_hash_table_lookup(ipdevice_hash,
1394                                         GINT_TO_POINTER(ipconfig->index));
1395         if (ipdevice == NULL)
1396                 return -ENXIO;
1397
1398         g_free(ipdevice->pac);
1399         ipdevice->pac = g_strdup(url);
1400
1401         return 0;
1402 }
1403
1404 const char *__connman_ipconfig_get_proxy_autoconfig(struct connman_ipconfig *ipconfig)
1405 {
1406         struct connman_ipdevice *ipdevice;
1407
1408         DBG("ipconfig %p", ipconfig);
1409
1410         if (ipconfig == NULL || ipconfig->index < 0)
1411                 return NULL;
1412
1413         ipdevice = g_hash_table_lookup(ipdevice_hash,
1414                                         GINT_TO_POINTER(ipconfig->index));
1415         if (ipdevice == NULL)
1416                 return NULL;
1417
1418         return ipdevice->pac;
1419 }
1420
1421 static void disable_ipv6(struct connman_ipconfig *ipconfig)
1422 {
1423         struct connman_ipdevice *ipdevice;
1424
1425         DBG("");
1426
1427         ipdevice = g_hash_table_lookup(ipdevice_hash,
1428                                         GINT_TO_POINTER(ipconfig->index));
1429         if (ipdevice == NULL)
1430                 return;
1431
1432         set_ipv6_state(ipdevice->ifname, FALSE);
1433 }
1434
1435 static void enable_ipv6(struct connman_ipconfig *ipconfig)
1436 {
1437         struct connman_ipdevice *ipdevice;
1438
1439         DBG("");
1440
1441         ipdevice = g_hash_table_lookup(ipdevice_hash,
1442                                         GINT_TO_POINTER(ipconfig->index));
1443         if (ipdevice == NULL)
1444                 return;
1445
1446         if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_AUTO)
1447                 set_ipv6_privacy(ipdevice->ifname,
1448                                 ipconfig->ipv6_privacy_config);
1449
1450         set_ipv6_state(ipdevice->ifname, TRUE);
1451 }
1452
1453 void __connman_ipconfig_disable_ipv6(struct connman_ipconfig *ipconfig)
1454 {
1455         if (ipconfig == NULL || ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
1456                 return;
1457
1458         disable_ipv6(ipconfig);
1459 }
1460
1461 int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
1462 {
1463         struct connman_ipdevice *ipdevice;
1464         gboolean up = FALSE, down = FALSE;
1465         gboolean lower_up = FALSE, lower_down = FALSE;
1466         enum connman_ipconfig_type type;
1467
1468         DBG("ipconfig %p", ipconfig);
1469
1470         if (ipconfig == NULL || ipconfig->index < 0)
1471                 return -ENODEV;
1472
1473         ipdevice = g_hash_table_lookup(ipdevice_hash,
1474                                         GINT_TO_POINTER(ipconfig->index));
1475         if (ipdevice == NULL)
1476                 return -ENXIO;
1477
1478         if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4) {
1479                 if (ipdevice->config_ipv4 == ipconfig)
1480                         return -EALREADY;
1481                 type = CONNMAN_IPCONFIG_TYPE_IPV4;
1482         } else if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) {
1483                 if (ipdevice->config_ipv6 == ipconfig)
1484                         return -EALREADY;
1485                 type = CONNMAN_IPCONFIG_TYPE_IPV6;
1486                 enable_ipv6(ipconfig);
1487         } else
1488                 return -EINVAL;
1489
1490         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
1491                                         ipdevice->config_ipv4 != NULL) {
1492                 ipconfig_list = g_list_remove(ipconfig_list,
1493                                                         ipdevice->config_ipv4);
1494
1495                 connman_ipaddress_clear(ipdevice->config_ipv4->system);
1496
1497                 connman_ipconfig_unref(ipdevice->config_ipv4);
1498         }
1499
1500         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
1501                                         ipdevice->config_ipv6 != NULL) {
1502                 ipconfig_list = g_list_remove(ipconfig_list,
1503                                                         ipdevice->config_ipv6);
1504
1505                 connman_ipaddress_clear(ipdevice->config_ipv6->system);
1506
1507                 connman_ipconfig_unref(ipdevice->config_ipv6);
1508         }
1509
1510         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
1511                 ipdevice->config_ipv4 = connman_ipconfig_ref(ipconfig);
1512         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
1513                 ipdevice->config_ipv6 = connman_ipconfig_ref(ipconfig);
1514
1515         ipconfig_list = g_list_append(ipconfig_list, ipconfig);
1516
1517         if (ipdevice->flags & IFF_UP)
1518                 up = TRUE;
1519         else
1520                 down = TRUE;
1521
1522         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) ==
1523                         (IFF_RUNNING | IFF_LOWER_UP))
1524                 lower_up = TRUE;
1525         else if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) == 0)
1526                 lower_down = TRUE;
1527
1528         if (up == TRUE && ipconfig->ops->up)
1529                 ipconfig->ops->up(ipconfig);
1530         if (lower_up == TRUE && ipconfig->ops->lower_up)
1531                 ipconfig->ops->lower_up(ipconfig);
1532
1533         if (lower_down == TRUE && ipconfig->ops->lower_down)
1534                 ipconfig->ops->lower_down(ipconfig);
1535         if (down == TRUE && ipconfig->ops->down)
1536                 ipconfig->ops->down(ipconfig);
1537
1538         return 0;
1539 }
1540
1541 int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
1542 {
1543         struct connman_ipdevice *ipdevice;
1544
1545         DBG("ipconfig %p", ipconfig);
1546
1547         if (ipconfig == NULL || ipconfig->index < 0)
1548                 return -ENODEV;
1549
1550         ipdevice = g_hash_table_lookup(ipdevice_hash,
1551                                         GINT_TO_POINTER(ipconfig->index));
1552         if (ipdevice == NULL)
1553                 return -ENXIO;
1554
1555         if (ipdevice->config_ipv4 == NULL && ipdevice->config_ipv6 == NULL)
1556                 return -EINVAL;
1557
1558         if (ipdevice->config_ipv4 == ipconfig) {
1559                 ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
1560
1561                 connman_ipaddress_clear(ipdevice->config_ipv4->system);
1562                 connman_ipconfig_unref(ipdevice->config_ipv4);
1563                 ipdevice->config_ipv4 = NULL;
1564                 return 0;
1565         }
1566
1567         if (ipdevice->config_ipv6 == ipconfig) {
1568                 ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
1569
1570                 if (ipdevice->config_ipv6->method ==
1571                                                 CONNMAN_IPCONFIG_METHOD_AUTO)
1572                         disable_ipv6(ipdevice->config_ipv6);
1573
1574                 connman_ipaddress_clear(ipdevice->config_ipv6->system);
1575                 connman_ipconfig_unref(ipdevice->config_ipv6);
1576                 ipdevice->config_ipv6 = NULL;
1577                 return 0;
1578         }
1579
1580         return -EINVAL;
1581 }
1582
1583 const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method)
1584 {
1585         switch (method) {
1586         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1587                 break;
1588         case CONNMAN_IPCONFIG_METHOD_OFF:
1589                 return "off";
1590         case CONNMAN_IPCONFIG_METHOD_FIXED:
1591                 return "fixed";
1592         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1593                 return "manual";
1594         case CONNMAN_IPCONFIG_METHOD_DHCP:
1595                 return "dhcp";
1596         case CONNMAN_IPCONFIG_METHOD_AUTO:
1597                 return "auto";
1598         }
1599
1600         return NULL;
1601 }
1602
1603 enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method)
1604 {
1605         if (g_strcmp0(method, "off") == 0)
1606                 return CONNMAN_IPCONFIG_METHOD_OFF;
1607         else if (g_strcmp0(method, "fixed") == 0)
1608                 return CONNMAN_IPCONFIG_METHOD_FIXED;
1609         else if (g_strcmp0(method, "manual") == 0)
1610                 return CONNMAN_IPCONFIG_METHOD_MANUAL;
1611         else if (g_strcmp0(method, "dhcp") == 0)
1612                 return CONNMAN_IPCONFIG_METHOD_DHCP;
1613         else if (g_strcmp0(method, "auto") == 0)
1614                 return CONNMAN_IPCONFIG_METHOD_AUTO;
1615         else
1616                 return CONNMAN_IPCONFIG_METHOD_UNKNOWN;
1617 }
1618
1619 static const char *privacy2string(int privacy)
1620 {
1621         if (privacy <= 0)
1622                 return "disabled";
1623         else if (privacy == 1)
1624                 return "enabled";
1625         else if (privacy > 1)
1626                 return "prefered";
1627
1628         return "disabled";
1629 }
1630
1631 static int string2privacy(const char *privacy)
1632 {
1633         if (g_strcmp0(privacy, "disabled") == 0)
1634                 return 0;
1635         else if (g_strcmp0(privacy, "enabled") == 0)
1636                 return 1;
1637         else if (g_strcmp0(privacy, "prefered") == 0)
1638                 return 2;
1639         else
1640                 return 0;
1641 }
1642
1643 void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
1644                                                         DBusMessageIter *iter)
1645 {
1646         const char *str;
1647
1648         DBG("");
1649
1650         if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV4)
1651                 return;
1652
1653         str = __connman_ipconfig_method2string(ipconfig->method);
1654         if (str == NULL)
1655                 return;
1656
1657         connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
1658
1659         if (ipconfig->system == NULL)
1660                 return;
1661
1662         if (ipconfig->system->local != NULL) {
1663                 in_addr_t addr;
1664                 struct in_addr netmask;
1665                 char *mask;
1666
1667                 connman_dbus_dict_append_basic(iter, "Address",
1668                                 DBUS_TYPE_STRING, &ipconfig->system->local);
1669
1670                 addr = 0xffffffff << (32 - ipconfig->system->prefixlen);
1671                 netmask.s_addr = htonl(addr);
1672                 mask = inet_ntoa(netmask);
1673                 connman_dbus_dict_append_basic(iter, "Netmask",
1674                                                 DBUS_TYPE_STRING, &mask);
1675         }
1676
1677         if (ipconfig->system->gateway != NULL)
1678                 connman_dbus_dict_append_basic(iter, "Gateway",
1679                                 DBUS_TYPE_STRING, &ipconfig->system->gateway);
1680 }
1681
1682 void __connman_ipconfig_append_ipv6(struct connman_ipconfig *ipconfig,
1683                                                         DBusMessageIter *iter)
1684 {
1685         const char *str, *privacy;
1686
1687         DBG("");
1688
1689         if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
1690                 return;
1691
1692         str = __connman_ipconfig_method2string(ipconfig->method);
1693         if (str == NULL)
1694                 return;
1695
1696         connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
1697
1698         if (ipconfig->system == NULL)
1699                 return;
1700
1701         if (ipconfig->system->local != NULL) {
1702                 connman_dbus_dict_append_basic(iter, "Address",
1703                                 DBUS_TYPE_STRING, &ipconfig->system->local);
1704                 connman_dbus_dict_append_basic(iter, "PrefixLength",
1705                                                 DBUS_TYPE_BYTE,
1706                                                 &ipconfig->system->prefixlen);
1707         }
1708
1709         if (ipconfig->system->gateway != NULL)
1710                 connman_dbus_dict_append_basic(iter, "Gateway",
1711                                 DBUS_TYPE_STRING, &ipconfig->system->gateway);
1712
1713         privacy = privacy2string(ipconfig->ipv6_privacy_config);
1714         connman_dbus_dict_append_basic(iter, "Privacy",
1715                                 DBUS_TYPE_STRING, &privacy);
1716 }
1717
1718 void __connman_ipconfig_append_ipv6config(struct connman_ipconfig *ipconfig,
1719                                                         DBusMessageIter *iter)
1720 {
1721         const char *str, *privacy;
1722
1723         DBG("");
1724
1725         str = __connman_ipconfig_method2string(ipconfig->method);
1726         if (str == NULL)
1727                 return;
1728
1729         connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
1730
1731         switch (ipconfig->method) {
1732         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1733         case CONNMAN_IPCONFIG_METHOD_OFF:
1734         case CONNMAN_IPCONFIG_METHOD_DHCP:
1735                 return;
1736         case CONNMAN_IPCONFIG_METHOD_FIXED:
1737         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1738         case CONNMAN_IPCONFIG_METHOD_AUTO:
1739                 break;
1740         }
1741
1742         if (ipconfig->address == NULL)
1743                 return;
1744
1745         if (ipconfig->address->local != NULL) {
1746                 connman_dbus_dict_append_basic(iter, "Address",
1747                                 DBUS_TYPE_STRING, &ipconfig->address->local);
1748                 connman_dbus_dict_append_basic(iter, "PrefixLength",
1749                                                 DBUS_TYPE_BYTE,
1750                                                 &ipconfig->address->prefixlen);
1751         }
1752
1753         if (ipconfig->address->gateway != NULL)
1754                 connman_dbus_dict_append_basic(iter, "Gateway",
1755                                 DBUS_TYPE_STRING, &ipconfig->address->gateway);
1756
1757         privacy = privacy2string(ipconfig->ipv6_privacy_config);
1758         connman_dbus_dict_append_basic(iter, "Privacy",
1759                                 DBUS_TYPE_STRING, &privacy);
1760 }
1761
1762 void __connman_ipconfig_append_ipv4config(struct connman_ipconfig *ipconfig,
1763                                                         DBusMessageIter *iter)
1764 {
1765         const char *str;
1766
1767         DBG("");
1768
1769         str = __connman_ipconfig_method2string(ipconfig->method);
1770         if (str == NULL)
1771                 return;
1772
1773         connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
1774
1775         switch (ipconfig->method) {
1776         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1777         case CONNMAN_IPCONFIG_METHOD_OFF:
1778         case CONNMAN_IPCONFIG_METHOD_FIXED:
1779         case CONNMAN_IPCONFIG_METHOD_DHCP:
1780         case CONNMAN_IPCONFIG_METHOD_AUTO:
1781                 return;
1782         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1783                 break;
1784         }
1785
1786         if (ipconfig->address == NULL)
1787                 return;
1788
1789         if (ipconfig->address->local != NULL) {
1790                 in_addr_t addr;
1791                 struct in_addr netmask;
1792                 char *mask;
1793
1794                 connman_dbus_dict_append_basic(iter, "Address",
1795                                 DBUS_TYPE_STRING, &ipconfig->address->local);
1796
1797                 addr = 0xffffffff << (32 - ipconfig->address->prefixlen);
1798                 netmask.s_addr = htonl(addr);
1799                 mask = inet_ntoa(netmask);
1800                 connman_dbus_dict_append_basic(iter, "Netmask",
1801                                                 DBUS_TYPE_STRING, &mask);
1802         }
1803
1804         if (ipconfig->address->gateway != NULL)
1805                 connman_dbus_dict_append_basic(iter, "Gateway",
1806                                 DBUS_TYPE_STRING, &ipconfig->address->gateway);
1807 }
1808
1809 int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig,
1810                                                         DBusMessageIter *array)
1811 {
1812         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
1813         const char *address = NULL, *netmask = NULL, *gateway = NULL,
1814                 *prefix_length_string = NULL, *privacy_string = NULL;
1815         int prefix_length = 0, privacy = 0;
1816         DBusMessageIter dict;
1817
1818         DBG("ipconfig %p", ipconfig);
1819
1820         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
1821                 return -EINVAL;
1822
1823         dbus_message_iter_recurse(array, &dict);
1824
1825         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1826                 DBusMessageIter entry;
1827                 const char *key;
1828                 int type;
1829
1830                 dbus_message_iter_recurse(&dict, &entry);
1831
1832                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
1833                         return -EINVAL;
1834
1835                 dbus_message_iter_get_basic(&entry, &key);
1836                 dbus_message_iter_next(&entry);
1837
1838                 type = dbus_message_iter_get_arg_type(&entry);
1839
1840                 if (g_str_equal(key, "Method") == TRUE) {
1841                         const char *str;
1842
1843                         if (type != DBUS_TYPE_STRING)
1844                                 return -EINVAL;
1845
1846                         dbus_message_iter_get_basic(&entry, &str);
1847                         method = __connman_ipconfig_string2method(str);
1848                 } else if (g_str_equal(key, "Address") == TRUE) {
1849                         if (type != DBUS_TYPE_STRING)
1850                                 return -EINVAL;
1851
1852                         dbus_message_iter_get_basic(&entry, &address);
1853                 } else if (g_str_equal(key, "PrefixLength") == TRUE) {
1854                         if (type != DBUS_TYPE_STRING)
1855                                 return -EINVAL;
1856
1857                         dbus_message_iter_get_basic(&entry,
1858                                                         &prefix_length_string);
1859
1860                         prefix_length = atoi(prefix_length_string);
1861                         if (prefix_length < 0 || prefix_length > 128)
1862                                 return -EINVAL;
1863
1864                 } else if (g_str_equal(key, "Netmask") == TRUE) {
1865                         if (type != DBUS_TYPE_STRING)
1866                                 return -EINVAL;
1867
1868                         dbus_message_iter_get_basic(&entry, &netmask);
1869                 } else if (g_str_equal(key, "Gateway") == TRUE) {
1870                         if (type != DBUS_TYPE_STRING)
1871                                 return -EINVAL;
1872
1873                         dbus_message_iter_get_basic(&entry, &gateway);
1874                 } else if (g_str_equal(key, "Privacy") == TRUE) {
1875                         if (type != DBUS_TYPE_STRING)
1876                                 return -EINVAL;
1877
1878                         dbus_message_iter_get_basic(&entry, &privacy_string);
1879                         privacy = string2privacy(privacy_string);
1880                 }
1881                 dbus_message_iter_next(&dict);
1882         }
1883
1884         DBG("method %d address %s netmask %s gateway %s prefix_length %d "
1885                 "privacy %s",
1886                 method, address, netmask, gateway, prefix_length,
1887                 privacy_string);
1888
1889         switch (method) {
1890         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1891         case CONNMAN_IPCONFIG_METHOD_FIXED:
1892                 return -EINVAL;
1893
1894         case CONNMAN_IPCONFIG_METHOD_OFF:
1895                 ipconfig->method = method;
1896                 if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
1897                         disable_ipv6(ipconfig);
1898                 break;
1899
1900         case CONNMAN_IPCONFIG_METHOD_AUTO:
1901                 if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
1902                         return -EINVAL;
1903
1904                 ipconfig->method = method;
1905                 if (privacy_string != NULL)
1906                         ipconfig->ipv6_privacy_config = privacy;
1907                 enable_ipv6(ipconfig);
1908                 break;
1909
1910         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1911                 if (address == NULL)
1912                         return -EINVAL;
1913
1914                 ipconfig->method = method;
1915
1916                 if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4)
1917                         connman_ipaddress_set_ipv4(ipconfig->address,
1918                                                 address, netmask, gateway);
1919                 else
1920                         return connman_ipaddress_set_ipv6(
1921                                         ipconfig->address, address,
1922                                                 gateway, prefix_length);
1923                 break;
1924
1925         case CONNMAN_IPCONFIG_METHOD_DHCP:
1926                 if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
1927                         return -EOPNOTSUPP;
1928
1929                 ipconfig->method = method;
1930                 break;
1931         }
1932
1933         return 0;
1934 }
1935
1936 void __connman_ipconfig_append_ethernet(struct connman_ipconfig *ipconfig,
1937                                                         DBusMessageIter *iter)
1938 {
1939         struct connman_ipdevice *ipdevice;
1940         const char *method = "auto";
1941
1942         connman_dbus_dict_append_basic(iter, "Method",
1943                                                 DBUS_TYPE_STRING, &method);
1944
1945         ipdevice = g_hash_table_lookup(ipdevice_hash,
1946                                         GINT_TO_POINTER(ipconfig->index));
1947         if (ipdevice == NULL)
1948                 return;
1949
1950         if (ipdevice->ifname != NULL)
1951                 connman_dbus_dict_append_basic(iter, "Interface",
1952                                         DBUS_TYPE_STRING, &ipdevice->ifname);
1953
1954         if (ipdevice->address != NULL)
1955                 connman_dbus_dict_append_basic(iter, "Address",
1956                                         DBUS_TYPE_STRING, &ipdevice->address);
1957
1958         if (ipdevice->mtu > 0)
1959                 connman_dbus_dict_append_basic(iter, "MTU",
1960                                         DBUS_TYPE_UINT16, &ipdevice->mtu);
1961 }
1962
1963 int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
1964                 GKeyFile *keyfile, const char *identifier, const char *prefix)
1965 {
1966         char *method;
1967         char *key;
1968
1969         DBG("ipconfig %p identifier %s", ipconfig, identifier);
1970
1971         key = g_strdup_printf("%smethod", prefix);
1972         method = g_key_file_get_string(keyfile, identifier, key, NULL);
1973         if (method == NULL) {
1974                 if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4)
1975                         ipconfig->method = CONNMAN_IPCONFIG_METHOD_DHCP;
1976                 else
1977                         ipconfig->method = CONNMAN_IPCONFIG_METHOD_OFF;
1978         } else
1979                 ipconfig->method = __connman_ipconfig_string2method(method);
1980
1981         if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_UNKNOWN)
1982                 ipconfig->method = CONNMAN_IPCONFIG_METHOD_OFF;
1983
1984         if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) {
1985                 if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_AUTO ||
1986                         ipconfig->method == CONNMAN_IPCONFIG_METHOD_MANUAL) {
1987                         char *privacy;
1988                         char *pprefix = g_strdup_printf("%sprivacy", prefix);
1989                         privacy = g_key_file_get_string(keyfile, identifier,
1990                                                         pprefix, NULL);
1991                         ipconfig->ipv6_privacy_config = string2privacy(privacy);
1992                         g_free(pprefix);
1993                         g_free(privacy);
1994
1995                         __connman_ipconfig_enable(ipconfig);
1996                         enable_ipv6(ipconfig);
1997                 }
1998         }
1999
2000         g_free(method);
2001         g_free(key);
2002
2003         key = g_strdup_printf("%snetmask_prefixlen", prefix);
2004         ipconfig->address->prefixlen = g_key_file_get_integer(
2005                                 keyfile, identifier, key, NULL);
2006         g_free(key);
2007
2008         key = g_strdup_printf("%slocal_address", prefix);
2009         ipconfig->address->local = g_key_file_get_string(
2010                         keyfile, identifier, key, NULL);
2011         g_free(key);
2012
2013         key = g_strdup_printf("%speer_address", prefix);
2014         ipconfig->address->peer = g_key_file_get_string(
2015                                 keyfile, identifier, key, NULL);
2016         g_free(key);
2017
2018         key = g_strdup_printf("%sbroadcast_address", prefix);
2019         ipconfig->address->broadcast = g_key_file_get_string(
2020                                 keyfile, identifier, key, NULL);
2021         g_free(key);
2022
2023         key = g_strdup_printf("%sgateway", prefix);
2024         ipconfig->address->gateway = g_key_file_get_string(
2025                                 keyfile, identifier, key, NULL);
2026         g_free(key);
2027
2028         return 0;
2029 }
2030
2031 int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
2032                 GKeyFile *keyfile, const char *identifier, const char *prefix)
2033 {
2034         const char *method;
2035         char *key;
2036
2037         DBG("ipconfig %p identifier %s", ipconfig, identifier);
2038
2039         method = __connman_ipconfig_method2string(ipconfig->method);
2040
2041         key = g_strdup_printf("%smethod", prefix);
2042         g_key_file_set_string(keyfile, identifier, key, method);
2043         g_free(key);
2044
2045         key = g_strdup_printf("%snetmask_prefixlen", prefix);
2046         g_key_file_set_integer(keyfile, identifier,
2047                         key, ipconfig->address->prefixlen);
2048         g_free(key);
2049
2050         key = g_strdup_printf("%slocal_address", prefix);
2051         if (ipconfig->address->local != NULL)
2052                 g_key_file_set_string(keyfile, identifier,
2053                                 key, ipconfig->address->local);
2054         g_free(key);
2055
2056         key = g_strdup_printf("%speer_address", prefix);
2057         if (ipconfig->address->peer != NULL)
2058                 g_key_file_set_string(keyfile, identifier,
2059                                 key, ipconfig->address->peer);
2060         g_free(key);
2061
2062         key = g_strdup_printf("%sbroadcast_address", prefix);
2063         if (ipconfig->address->broadcast != NULL)
2064                 g_key_file_set_string(keyfile, identifier,
2065                         key, ipconfig->address->broadcast);
2066         g_free(key);
2067
2068         key = g_strdup_printf("%sgateway", prefix);
2069         if (ipconfig->address->gateway != NULL)
2070                 g_key_file_set_string(keyfile, identifier,
2071                         key, ipconfig->address->gateway);
2072         g_free(key);
2073
2074         if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) {
2075                 const char *privacy;
2076                 privacy = privacy2string(ipconfig->ipv6_privacy_config);
2077                 key = g_strdup_printf("%sprivacy", prefix);
2078                 g_key_file_set_string(keyfile, identifier, key, privacy);
2079                 g_free(key);
2080         }
2081
2082         return 0;
2083 }
2084
2085 int __connman_ipconfig_init(void)
2086 {
2087         DBG("");
2088
2089         ipdevice_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
2090                                                         NULL, free_ipdevice);
2091
2092         return 0;
2093 }
2094
2095 void __connman_ipconfig_cleanup(void)
2096 {
2097         DBG("");
2098
2099         g_hash_table_destroy(ipdevice_hash);
2100         ipdevice_hash = NULL;
2101 }