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