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