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