Remove non-essential logs
[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 #if defined TIZEN_EXT
1446         DBG("ipconfig method %d type %d", ipconfig->method, ipconfig->type);
1447 #else
1448         DBG("method %d", ipconfig->method);
1449 #endif
1450
1451         switch (ipconfig->method) {
1452         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1453         case CONNMAN_IPCONFIG_METHOD_OFF:
1454                 break;
1455         case CONNMAN_IPCONFIG_METHOD_AUTO:
1456         case CONNMAN_IPCONFIG_METHOD_FIXED:
1457         case CONNMAN_IPCONFIG_METHOD_DHCP:
1458         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1459                 if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4)
1460                         err = connman_inet_clear_address(ipconfig->index,
1461                                                         ipconfig->address);
1462                 else if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
1463                         err = connman_inet_clear_ipv6_address(
1464                                                 ipconfig->index,
1465                                                 ipconfig->address->local,
1466                                                 ipconfig->address->prefixlen);
1467                 else
1468                         err = -EINVAL;
1469
1470                 return err;
1471         }
1472
1473         return 0;
1474 }
1475
1476 int __connman_ipconfig_set_proxy_autoconfig(struct connman_ipconfig *ipconfig,
1477                                                         const char *url)
1478 {
1479         struct connman_ipdevice *ipdevice;
1480
1481         DBG("ipconfig %p", ipconfig);
1482
1483         if (!ipconfig || ipconfig->index < 0)
1484                 return -ENODEV;
1485
1486         ipdevice = g_hash_table_lookup(ipdevice_hash,
1487                                         GINT_TO_POINTER(ipconfig->index));
1488         if (!ipdevice)
1489                 return -ENXIO;
1490
1491         g_free(ipdevice->pac);
1492         ipdevice->pac = g_strdup(url);
1493
1494         return 0;
1495 }
1496
1497 const char *__connman_ipconfig_get_proxy_autoconfig(struct connman_ipconfig *ipconfig)
1498 {
1499         struct connman_ipdevice *ipdevice;
1500
1501         DBG("ipconfig %p", ipconfig);
1502
1503         if (!ipconfig || ipconfig->index < 0)
1504                 return NULL;
1505
1506         ipdevice = g_hash_table_lookup(ipdevice_hash,
1507                                         GINT_TO_POINTER(ipconfig->index));
1508         if (!ipdevice)
1509                 return NULL;
1510
1511         return ipdevice->pac;
1512 }
1513
1514 void __connman_ipconfig_set_dhcp_address(struct connman_ipconfig *ipconfig,
1515                                         const char *address)
1516 {
1517         if (!ipconfig)
1518                 return;
1519
1520         g_free(ipconfig->last_dhcp_address);
1521         ipconfig->last_dhcp_address = g_strdup(address);
1522 }
1523
1524 char *__connman_ipconfig_get_dhcp_address(struct connman_ipconfig *ipconfig)
1525 {
1526         if (!ipconfig)
1527                 return NULL;
1528
1529         return ipconfig->last_dhcp_address;
1530 }
1531
1532 void __connman_ipconfig_set_dhcpv6_prefixes(struct connman_ipconfig *ipconfig,
1533                                         char **prefixes)
1534 {
1535         if (!ipconfig)
1536                 return;
1537
1538         g_strfreev(ipconfig->last_dhcpv6_prefixes);
1539         ipconfig->last_dhcpv6_prefixes = prefixes;
1540 }
1541
1542 char **__connman_ipconfig_get_dhcpv6_prefixes(struct connman_ipconfig *ipconfig)
1543 {
1544         if (!ipconfig)
1545                 return NULL;
1546
1547         return ipconfig->last_dhcpv6_prefixes;
1548 }
1549
1550 static void disable_ipv6(struct connman_ipconfig *ipconfig)
1551 {
1552         struct connman_ipdevice *ipdevice;
1553         char *ifname;
1554
1555         DBG("");
1556
1557         ipdevice = g_hash_table_lookup(ipdevice_hash,
1558                                         GINT_TO_POINTER(ipconfig->index));
1559         if (!ipdevice)
1560                 return;
1561
1562         ifname = connman_inet_ifname(ipconfig->index);
1563
1564         set_ipv6_state(ifname, false);
1565
1566         g_free(ifname);
1567 }
1568
1569 static void enable_ipv6(struct connman_ipconfig *ipconfig)
1570 {
1571         struct connman_ipdevice *ipdevice;
1572         char *ifname;
1573
1574         DBG("");
1575
1576         ipdevice = g_hash_table_lookup(ipdevice_hash,
1577                                         GINT_TO_POINTER(ipconfig->index));
1578         if (!ipdevice)
1579                 return;
1580
1581         ifname = connman_inet_ifname(ipconfig->index);
1582
1583         if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_AUTO)
1584                 set_ipv6_privacy(ifname, ipconfig->ipv6_privacy_config);
1585
1586         set_ipv6_state(ifname, true);
1587
1588         g_free(ifname);
1589 }
1590
1591 void __connman_ipconfig_enable_ipv6(struct connman_ipconfig *ipconfig)
1592 {
1593         if (!ipconfig || ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
1594                 return;
1595
1596         enable_ipv6(ipconfig);
1597 }
1598
1599 void __connman_ipconfig_disable_ipv6(struct connman_ipconfig *ipconfig)
1600 {
1601         if (!ipconfig || ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
1602                 return;
1603
1604         disable_ipv6(ipconfig);
1605 }
1606
1607 bool __connman_ipconfig_is_usable(struct connman_ipconfig *ipconfig)
1608 {
1609         if (!ipconfig)
1610                 return false;
1611
1612         switch (ipconfig->method) {
1613         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1614         case CONNMAN_IPCONFIG_METHOD_OFF:
1615                 return false;
1616         case CONNMAN_IPCONFIG_METHOD_AUTO:
1617         case CONNMAN_IPCONFIG_METHOD_FIXED:
1618         case CONNMAN_IPCONFIG_METHOD_DHCP:
1619         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1620                 break;
1621         }
1622
1623         return true;
1624 }
1625
1626 int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
1627 {
1628         struct connman_ipdevice *ipdevice;
1629         bool up = false, down = false;
1630         bool lower_up = false, lower_down = false;
1631         enum connman_ipconfig_type type;
1632         char *ifname;
1633
1634         DBG("ipconfig %p", ipconfig);
1635
1636         if (!ipconfig || ipconfig->index < 0)
1637                 return -ENODEV;
1638
1639         ipdevice = g_hash_table_lookup(ipdevice_hash,
1640                                         GINT_TO_POINTER(ipconfig->index));
1641         if (!ipdevice)
1642                 return -ENXIO;
1643
1644         if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4) {
1645                 if (ipdevice->config_ipv4 == ipconfig)
1646                         return -EALREADY;
1647                 type = CONNMAN_IPCONFIG_TYPE_IPV4;
1648         } else if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) {
1649                 if (ipdevice->config_ipv6 == ipconfig)
1650                         return -EALREADY;
1651                 type = CONNMAN_IPCONFIG_TYPE_IPV6;
1652         } else
1653                 return -EINVAL;
1654
1655         ipconfig->enabled = true;
1656
1657         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
1658                                         ipdevice->config_ipv4) {
1659                 ipconfig_list = g_list_remove(ipconfig_list,
1660                                                         ipdevice->config_ipv4);
1661
1662                 connman_ipaddress_clear(ipdevice->config_ipv4->system);
1663
1664                 __connman_ipconfig_unref(ipdevice->config_ipv4);
1665         }
1666
1667         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
1668                                         ipdevice->config_ipv6) {
1669                 ipconfig_list = g_list_remove(ipconfig_list,
1670                                                         ipdevice->config_ipv6);
1671
1672                 connman_ipaddress_clear(ipdevice->config_ipv6->system);
1673
1674                 __connman_ipconfig_unref(ipdevice->config_ipv6);
1675         }
1676
1677         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
1678                 ipdevice->config_ipv4 = __connman_ipconfig_ref(ipconfig);
1679         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
1680                 ipdevice->config_ipv6 = __connman_ipconfig_ref(ipconfig);
1681
1682                 enable_ipv6(ipdevice->config_ipv6);
1683         }
1684         ipconfig_list = g_list_append(ipconfig_list, ipconfig);
1685
1686         if (ipdevice->flags & IFF_UP)
1687                 up = true;
1688         else
1689                 down = true;
1690
1691         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) ==
1692                         (IFF_RUNNING | IFF_LOWER_UP))
1693                 lower_up = true;
1694         else if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) == 0)
1695                 lower_down = true;
1696
1697         ifname = connman_inet_ifname(ipconfig->index);
1698
1699         if (up && ipconfig->ops->up)
1700                 ipconfig->ops->up(ipconfig, ifname);
1701         if (lower_up && ipconfig->ops->lower_up)
1702                 ipconfig->ops->lower_up(ipconfig, ifname);
1703
1704         if (lower_down && ipconfig->ops->lower_down)
1705                 ipconfig->ops->lower_down(ipconfig, ifname);
1706         if (down && ipconfig->ops->down)
1707                 ipconfig->ops->down(ipconfig, ifname);
1708
1709         g_free(ifname);
1710
1711         return 0;
1712 }
1713
1714 int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
1715 {
1716         struct connman_ipdevice *ipdevice;
1717
1718         DBG("ipconfig %p", ipconfig);
1719
1720         if (!ipconfig || ipconfig->index < 0)
1721                 return -ENODEV;
1722
1723         ipdevice = g_hash_table_lookup(ipdevice_hash,
1724                                         GINT_TO_POINTER(ipconfig->index));
1725         if (!ipdevice)
1726                 return -ENXIO;
1727
1728         if (!ipdevice->config_ipv4 && !ipdevice->config_ipv6)
1729                 return -EINVAL;
1730
1731         ipconfig->enabled = false;
1732
1733         if (ipdevice->config_ipv4 == ipconfig) {
1734                 ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
1735
1736                 connman_ipaddress_clear(ipdevice->config_ipv4->system);
1737                 __connman_ipconfig_unref(ipdevice->config_ipv4);
1738                 ipdevice->config_ipv4 = NULL;
1739                 return 0;
1740         }
1741
1742         if (ipdevice->config_ipv6 == ipconfig) {
1743                 ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
1744
1745 #if defined TIZEN_EXT
1746                 if (ipdevice->config_ipv6->method ==
1747                                 CONNMAN_IPCONFIG_METHOD_AUTO)
1748                         disable_ipv6(ipdevice->config_ipv6);
1749 #endif
1750                 connman_ipaddress_clear(ipdevice->config_ipv6->system);
1751                 __connman_ipconfig_unref(ipdevice->config_ipv6);
1752                 ipdevice->config_ipv6 = NULL;
1753                 return 0;
1754         }
1755
1756         return -EINVAL;
1757 }
1758
1759 const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method)
1760 {
1761         switch (method) {
1762         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1763                 break;
1764         case CONNMAN_IPCONFIG_METHOD_OFF:
1765                 return "off";
1766         case CONNMAN_IPCONFIG_METHOD_FIXED:
1767                 return "fixed";
1768         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1769                 return "manual";
1770         case CONNMAN_IPCONFIG_METHOD_DHCP:
1771                 return "dhcp";
1772         case CONNMAN_IPCONFIG_METHOD_AUTO:
1773                 return "auto";
1774         }
1775
1776         return NULL;
1777 }
1778
1779 enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method)
1780 {
1781         if (g_strcmp0(method, "off") == 0)
1782                 return CONNMAN_IPCONFIG_METHOD_OFF;
1783         else if (g_strcmp0(method, "fixed") == 0)
1784                 return CONNMAN_IPCONFIG_METHOD_FIXED;
1785         else if (g_strcmp0(method, "manual") == 0)
1786                 return CONNMAN_IPCONFIG_METHOD_MANUAL;
1787         else if (g_strcmp0(method, "dhcp") == 0)
1788                 return CONNMAN_IPCONFIG_METHOD_DHCP;
1789         else if (g_strcmp0(method, "auto") == 0)
1790                 return CONNMAN_IPCONFIG_METHOD_AUTO;
1791         else
1792                 return CONNMAN_IPCONFIG_METHOD_UNKNOWN;
1793 }
1794
1795 static const char *privacy2string(int privacy)
1796 {
1797         if (privacy <= 0)
1798                 return "disabled";
1799         else if (privacy == 1)
1800                 return "enabled";
1801         else
1802                 return "prefered";
1803 }
1804
1805 static int string2privacy(const char *privacy)
1806 {
1807         if (g_strcmp0(privacy, "disabled") == 0)
1808                 return 0;
1809         else if (g_strcmp0(privacy, "enabled") == 0)
1810                 return 1;
1811         else if (g_strcmp0(privacy, "preferred") == 0)
1812                 return 2;
1813         else if (g_strcmp0(privacy, "prefered") == 0)
1814                 return 2;
1815         else
1816                 return 0;
1817 }
1818
1819 int __connman_ipconfig_ipv6_reset_privacy(struct connman_ipconfig *ipconfig)
1820 {
1821         struct connman_ipdevice *ipdevice;
1822         int err;
1823
1824         if (!ipconfig)
1825                 return -EINVAL;
1826
1827         ipdevice = g_hash_table_lookup(ipdevice_hash,
1828                                                 GINT_TO_POINTER(ipconfig->index));
1829         if (!ipdevice)
1830                 return -ENODEV;
1831
1832         err = __connman_ipconfig_ipv6_set_privacy(ipconfig, privacy2string(
1833                                                         ipdevice->ipv6_privacy));
1834
1835         return err;
1836 }
1837
1838 int __connman_ipconfig_ipv6_set_privacy(struct connman_ipconfig *ipconfig,
1839                                         const char *value)
1840 {
1841         int privacy;
1842
1843         if (!ipconfig)
1844                 return -EINVAL;
1845
1846         DBG("ipconfig %p privacy %s", ipconfig, value);
1847
1848         privacy = string2privacy(value);
1849
1850         ipconfig->ipv6_privacy_config = privacy;
1851
1852         enable_ipv6(ipconfig);
1853
1854         return 0;
1855 }
1856
1857 void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
1858                                                         DBusMessageIter *iter)
1859 {
1860         struct connman_ipaddress *append_addr = NULL;
1861         const char *str;
1862 #if defined TIZEN_EXT
1863         DBG("");
1864 #endif
1865
1866         if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV4)
1867                 return;
1868
1869         str = __connman_ipconfig_method2string(ipconfig->method);
1870         if (!str)
1871                 return;
1872
1873         connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
1874
1875         switch (ipconfig->method) {
1876         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1877         case CONNMAN_IPCONFIG_METHOD_OFF:
1878         case CONNMAN_IPCONFIG_METHOD_AUTO:
1879                 return;
1880
1881         case CONNMAN_IPCONFIG_METHOD_FIXED:
1882                 append_addr = ipconfig->address;
1883                 break;
1884
1885         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1886         case CONNMAN_IPCONFIG_METHOD_DHCP:
1887                 append_addr = ipconfig->system;
1888 #if defined TIZEN_EXT
1889                 /* TIZEN enables get_properties before __connman_ipconfig_newaddr */
1890                 if (append_addr && append_addr->local == NULL)
1891                         append_addr = ipconfig->address;
1892 #endif
1893                 break;
1894         }
1895
1896         if (!append_addr)
1897                 return;
1898
1899         if (append_addr->local) {
1900                 in_addr_t addr;
1901                 struct in_addr netmask;
1902                 char *mask;
1903
1904                 connman_dbus_dict_append_basic(iter, "Address",
1905                                 DBUS_TYPE_STRING, &append_addr->local);
1906
1907                 addr = 0xffffffff << (32 - append_addr->prefixlen);
1908                 netmask.s_addr = htonl(addr);
1909                 mask = inet_ntoa(netmask);
1910                 connman_dbus_dict_append_basic(iter, "Netmask",
1911                                                 DBUS_TYPE_STRING, &mask);
1912         }
1913
1914         if (append_addr->gateway)
1915                 connman_dbus_dict_append_basic(iter, "Gateway",
1916                                 DBUS_TYPE_STRING, &append_addr->gateway);
1917
1918 #if defined TIZEN_EXT
1919         if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_DHCP) {
1920                 char *server_ip;
1921                 server_ip = __connman_dhcp_get_server_address(ipconfig);
1922                 if (server_ip) {
1923                         connman_dbus_dict_append_basic(iter, "DHCPServerIP",
1924                                         DBUS_TYPE_STRING, &server_ip);
1925                         g_free(server_ip);
1926                 }
1927                 connman_dbus_dict_append_basic(iter, "DHCPLeaseDuration",
1928                                 DBUS_TYPE_INT32, &ipconfig->dhcp_lease_duration);
1929         }
1930 #endif
1931 }
1932
1933 void __connman_ipconfig_append_ipv6(struct connman_ipconfig *ipconfig,
1934                                         DBusMessageIter *iter,
1935                                         struct connman_ipconfig *ipconfig_ipv4)
1936 {
1937         struct connman_ipaddress *append_addr = NULL;
1938         const char *str, *privacy;
1939 #if defined TIZEN_EXT
1940         DBG("");
1941 #endif
1942
1943         if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
1944                 return;
1945
1946         str = __connman_ipconfig_method2string(ipconfig->method);
1947         if (!str)
1948                 return;
1949
1950         if (ipconfig_ipv4 &&
1951                         ipconfig->method == CONNMAN_IPCONFIG_METHOD_AUTO) {
1952                 if (__connman_6to4_check(ipconfig_ipv4) == 1)
1953                         str = "6to4";
1954         }
1955
1956         connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
1957
1958         switch (ipconfig->method) {
1959         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1960         case CONNMAN_IPCONFIG_METHOD_OFF:
1961                 return;
1962
1963         case CONNMAN_IPCONFIG_METHOD_FIXED:
1964                 append_addr = ipconfig->address;
1965                 break;
1966
1967         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1968         case CONNMAN_IPCONFIG_METHOD_DHCP:
1969         case CONNMAN_IPCONFIG_METHOD_AUTO:
1970                 append_addr = ipconfig->system;
1971 #if defined TIZEN_EXT
1972                 /* TIZEN enables get_properties before __connman_ipconfig_newaddr */
1973                 if (append_addr && append_addr->local == NULL)
1974                         append_addr = ipconfig->address;
1975 #endif
1976                 break;
1977         }
1978
1979         if (!append_addr)
1980                 return;
1981
1982         if (append_addr->local) {
1983                 connman_dbus_dict_append_basic(iter, "Address",
1984                                 DBUS_TYPE_STRING, &append_addr->local);
1985                 connman_dbus_dict_append_basic(iter, "PrefixLength",
1986                                                 DBUS_TYPE_BYTE,
1987                                                 &append_addr->prefixlen);
1988         }
1989
1990         if (append_addr->gateway)
1991                 connman_dbus_dict_append_basic(iter, "Gateway",
1992                                 DBUS_TYPE_STRING, &append_addr->gateway);
1993
1994         privacy = privacy2string(ipconfig->ipv6_privacy_config);
1995         connman_dbus_dict_append_basic(iter, "Privacy",
1996                                 DBUS_TYPE_STRING, &privacy);
1997 }
1998
1999 void __connman_ipconfig_append_ipv6config(struct connman_ipconfig *ipconfig,
2000                                                         DBusMessageIter *iter)
2001 {
2002         const char *str, *privacy;
2003 #if !defined TIZEN_EXT
2004         DBG("");
2005 #endif
2006
2007         str = __connman_ipconfig_method2string(ipconfig->method);
2008         if (!str)
2009                 return;
2010
2011         connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
2012
2013         switch (ipconfig->method) {
2014         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
2015         case CONNMAN_IPCONFIG_METHOD_OFF:
2016         case CONNMAN_IPCONFIG_METHOD_DHCP:
2017                 return;
2018         case CONNMAN_IPCONFIG_METHOD_FIXED:
2019         case CONNMAN_IPCONFIG_METHOD_MANUAL:
2020         case CONNMAN_IPCONFIG_METHOD_AUTO:
2021                 break;
2022         }
2023
2024         if (!ipconfig->address)
2025                 return;
2026
2027         if (ipconfig->address->local) {
2028                 connman_dbus_dict_append_basic(iter, "Address",
2029                                 DBUS_TYPE_STRING, &ipconfig->address->local);
2030                 connman_dbus_dict_append_basic(iter, "PrefixLength",
2031                                                 DBUS_TYPE_BYTE,
2032                                                 &ipconfig->address->prefixlen);
2033         }
2034
2035         if (ipconfig->address->gateway)
2036                 connman_dbus_dict_append_basic(iter, "Gateway",
2037                                 DBUS_TYPE_STRING, &ipconfig->address->gateway);
2038
2039         privacy = privacy2string(ipconfig->ipv6_privacy_config);
2040         connman_dbus_dict_append_basic(iter, "Privacy",
2041                                 DBUS_TYPE_STRING, &privacy);
2042 }
2043
2044 void __connman_ipconfig_append_ipv4config(struct connman_ipconfig *ipconfig,
2045                                                         DBusMessageIter *iter)
2046 {
2047         const char *str;
2048 #if !defined TIZEN_EXT
2049         DBG("");
2050 #endif
2051
2052         str = __connman_ipconfig_method2string(ipconfig->method);
2053         if (!str)
2054                 return;
2055
2056         connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
2057
2058         switch (ipconfig->method) {
2059         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
2060         case CONNMAN_IPCONFIG_METHOD_OFF:
2061         case CONNMAN_IPCONFIG_METHOD_DHCP:
2062         case CONNMAN_IPCONFIG_METHOD_AUTO:
2063                 return;
2064         case CONNMAN_IPCONFIG_METHOD_FIXED:
2065         case CONNMAN_IPCONFIG_METHOD_MANUAL:
2066                 break;
2067         }
2068
2069         if (!ipconfig->address)
2070                 return;
2071
2072         if (ipconfig->address->local) {
2073                 in_addr_t addr;
2074                 struct in_addr netmask;
2075                 char *mask;
2076
2077                 connman_dbus_dict_append_basic(iter, "Address",
2078                                 DBUS_TYPE_STRING, &ipconfig->address->local);
2079
2080                 addr = 0xffffffff << (32 - ipconfig->address->prefixlen);
2081                 netmask.s_addr = htonl(addr);
2082                 mask = inet_ntoa(netmask);
2083                 connman_dbus_dict_append_basic(iter, "Netmask",
2084                                                 DBUS_TYPE_STRING, &mask);
2085         }
2086
2087         if (ipconfig->address->gateway)
2088                 connman_dbus_dict_append_basic(iter, "Gateway",
2089                                 DBUS_TYPE_STRING, &ipconfig->address->gateway);
2090 }
2091
2092 int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig,
2093                                                         DBusMessageIter *array)
2094 {
2095         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
2096         const char *address = NULL, *netmask = NULL, *gateway = NULL,
2097                 *privacy_string = NULL;
2098         int prefix_length = 0, privacy = 0;
2099         DBusMessageIter dict;
2100         int type = -1;
2101
2102         DBG("ipconfig %p", ipconfig);
2103
2104         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
2105                 return -EINVAL;
2106
2107         dbus_message_iter_recurse(array, &dict);
2108
2109         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
2110                 DBusMessageIter entry, value;
2111                 const char *key;
2112                 int type;
2113
2114                 dbus_message_iter_recurse(&dict, &entry);
2115
2116                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
2117                         return -EINVAL;
2118
2119                 dbus_message_iter_get_basic(&entry, &key);
2120                 dbus_message_iter_next(&entry);
2121
2122                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
2123                         return -EINVAL;
2124
2125                 dbus_message_iter_recurse(&entry, &value);
2126
2127                 type = dbus_message_iter_get_arg_type(&value);
2128
2129                 if (g_str_equal(key, "Method")) {
2130                         const char *str;
2131
2132                         if (type != DBUS_TYPE_STRING)
2133                                 return -EINVAL;
2134
2135                         dbus_message_iter_get_basic(&value, &str);
2136                         method = __connman_ipconfig_string2method(str);
2137                 } else if (g_str_equal(key, "Address")) {
2138                         if (type != DBUS_TYPE_STRING)
2139                                 return -EINVAL;
2140
2141                         dbus_message_iter_get_basic(&value, &address);
2142                 } else if (g_str_equal(key, "PrefixLength")) {
2143                         if (type != DBUS_TYPE_BYTE)
2144                                 return -EINVAL;
2145
2146                         dbus_message_iter_get_basic(&value, &prefix_length);
2147
2148                         if (prefix_length < 0 || prefix_length > 128)
2149                                 return -EINVAL;
2150                 } else if (g_str_equal(key, "Netmask")) {
2151                         if (type != DBUS_TYPE_STRING)
2152                                 return -EINVAL;
2153
2154                         dbus_message_iter_get_basic(&value, &netmask);
2155                 } else if (g_str_equal(key, "Gateway")) {
2156                         if (type != DBUS_TYPE_STRING)
2157                                 return -EINVAL;
2158
2159                         dbus_message_iter_get_basic(&value, &gateway);
2160                 } else if (g_str_equal(key, "Privacy")) {
2161                         if (type != DBUS_TYPE_STRING)
2162                                 return -EINVAL;
2163
2164                         dbus_message_iter_get_basic(&value, &privacy_string);
2165                         privacy = string2privacy(privacy_string);
2166                 }
2167
2168                 dbus_message_iter_next(&dict);
2169         }
2170
2171         DBG("method %d address %s netmask %s gateway %s prefix_length %d "
2172                 "privacy %s",
2173                 method, address, netmask, gateway, prefix_length,
2174                 privacy_string);
2175
2176         switch (method) {
2177         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
2178         case CONNMAN_IPCONFIG_METHOD_FIXED:
2179                 return -EINVAL;
2180
2181         case CONNMAN_IPCONFIG_METHOD_OFF:
2182                 ipconfig->method = method;
2183 #if defined TIZEN_EXT
2184                 if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
2185                         disable_ipv6(ipconfig);
2186 #endif
2187                 break;
2188
2189         case CONNMAN_IPCONFIG_METHOD_AUTO:
2190                 if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
2191                         return -EOPNOTSUPP;
2192
2193                 ipconfig->method = method;
2194                 if (privacy_string)
2195                         ipconfig->ipv6_privacy_config = privacy;
2196 #if defined TIZEN_EXT
2197                 enable_ipv6(ipconfig);
2198 #endif
2199                 break;
2200
2201         case CONNMAN_IPCONFIG_METHOD_MANUAL:
2202                 switch (ipconfig->type) {
2203                 case CONNMAN_IPCONFIG_TYPE_IPV4:
2204                         type = AF_INET;
2205                         break;
2206                 case CONNMAN_IPCONFIG_TYPE_IPV6:
2207                         type = AF_INET6;
2208                         break;
2209                 case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
2210                 case CONNMAN_IPCONFIG_TYPE_ALL:
2211                         type = -1;
2212                         break;
2213                 }
2214
2215                 if ((address && connman_inet_check_ipaddress(address)
2216                                                 != type) ||
2217                                 (netmask &&
2218                                 connman_inet_check_ipaddress(netmask)
2219                                                 != type) ||
2220                                 (gateway &&
2221                                 connman_inet_check_ipaddress(gateway)
2222                                                 != type))
2223                         return -EINVAL;
2224
2225                 ipconfig->method = method;
2226
2227                 if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4)
2228                         connman_ipaddress_set_ipv4(ipconfig->address,
2229                                                 address, netmask, gateway);
2230                 else
2231                         return connman_ipaddress_set_ipv6(
2232                                         ipconfig->address, address,
2233                                                 prefix_length, gateway);
2234
2235                 break;
2236
2237         case CONNMAN_IPCONFIG_METHOD_DHCP:
2238                 if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV4)
2239                         return -EOPNOTSUPP;
2240
2241                 ipconfig->method = method;
2242                 break;
2243         }
2244
2245         return 0;
2246 }
2247
2248 void __connman_ipconfig_append_ethernet(struct connman_ipconfig *ipconfig,
2249                                                         DBusMessageIter *iter)
2250 {
2251         struct connman_ipdevice *ipdevice;
2252         const char *method = "auto";
2253
2254         connman_dbus_dict_append_basic(iter, "Method",
2255                                                 DBUS_TYPE_STRING, &method);
2256
2257         ipdevice = g_hash_table_lookup(ipdevice_hash,
2258                                         GINT_TO_POINTER(ipconfig->index));
2259         if (!ipdevice)
2260                 return;
2261
2262         if (ipconfig->index >= 0) {
2263                 char *ifname = connman_inet_ifname(ipconfig->index);
2264                 if (ifname) {
2265                         connman_dbus_dict_append_basic(iter, "Interface",
2266                                                 DBUS_TYPE_STRING, &ifname);
2267                         g_free(ifname);
2268                 }
2269         }
2270
2271         if (ipdevice->address)
2272                 connman_dbus_dict_append_basic(iter, "Address",
2273                                         DBUS_TYPE_STRING, &ipdevice->address);
2274
2275         if (ipdevice->mtu > 0)
2276                 connman_dbus_dict_append_basic(iter, "MTU",
2277                                         DBUS_TYPE_UINT16, &ipdevice->mtu);
2278 }
2279
2280 int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
2281                 GKeyFile *keyfile, const char *identifier, const char *prefix)
2282 {
2283         char *method;
2284         char *key;
2285         char *str;
2286
2287         DBG("ipconfig %p identifier %s", ipconfig, identifier);
2288
2289         key = g_strdup_printf("%smethod", prefix);
2290         method = g_key_file_get_string(keyfile, identifier, key, NULL);
2291         if (!method) {
2292                 switch (ipconfig->type) {
2293                 case CONNMAN_IPCONFIG_TYPE_IPV4:
2294                         ipconfig->method = CONNMAN_IPCONFIG_METHOD_DHCP;
2295                         break;
2296                 case CONNMAN_IPCONFIG_TYPE_IPV6:
2297                         ipconfig->method = CONNMAN_IPCONFIG_METHOD_AUTO;
2298                         break;
2299                 case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
2300                 case CONNMAN_IPCONFIG_TYPE_ALL:
2301                         ipconfig->method = CONNMAN_IPCONFIG_METHOD_OFF;
2302                         break;
2303                 }
2304         } else
2305                 ipconfig->method = __connman_ipconfig_string2method(method);
2306
2307         if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_UNKNOWN)
2308                 ipconfig->method = CONNMAN_IPCONFIG_METHOD_OFF;
2309
2310         if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) {
2311                 gsize length;
2312                 char *pprefix;
2313
2314                 if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_AUTO ||
2315                         ipconfig->method == CONNMAN_IPCONFIG_METHOD_MANUAL) {
2316                         char *privacy;
2317
2318                         pprefix = g_strdup_printf("%sprivacy", prefix);
2319                         privacy = g_key_file_get_string(keyfile, identifier,
2320                                                         pprefix, NULL);
2321                         ipconfig->ipv6_privacy_config = string2privacy(privacy);
2322                         g_free(pprefix);
2323                         g_free(privacy);
2324                 }
2325
2326                 pprefix = g_strdup_printf("%sDHCP.LastPrefixes", prefix);
2327                 ipconfig->last_dhcpv6_prefixes =
2328                         g_key_file_get_string_list(keyfile, identifier, pprefix,
2329                                                 &length, NULL);
2330                 if (ipconfig->last_dhcpv6_prefixes && length == 0) {
2331                         g_free(ipconfig->last_dhcpv6_prefixes);
2332                         ipconfig->last_dhcpv6_prefixes = NULL;
2333                 }
2334                 g_free(pprefix);
2335         }
2336
2337         g_free(method);
2338         g_free(key);
2339
2340         switch (ipconfig->method) {
2341         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
2342         case CONNMAN_IPCONFIG_METHOD_OFF:
2343                 break;
2344
2345         case CONNMAN_IPCONFIG_METHOD_FIXED:
2346         case CONNMAN_IPCONFIG_METHOD_MANUAL:
2347
2348                 key = g_strdup_printf("%snetmask_prefixlen", prefix);
2349                 ipconfig->address->prefixlen = g_key_file_get_integer(
2350                                 keyfile, identifier, key, NULL);
2351                 g_free(key);
2352
2353                 key = g_strdup_printf("%slocal_address", prefix);
2354                 g_free(ipconfig->address->local);
2355                 ipconfig->address->local = g_key_file_get_string(
2356                         keyfile, identifier, key, NULL);
2357                 g_free(key);
2358
2359                 key = g_strdup_printf("%speer_address", prefix);
2360                 g_free(ipconfig->address->peer);
2361                 ipconfig->address->peer = g_key_file_get_string(
2362                                 keyfile, identifier, key, NULL);
2363                 g_free(key);
2364
2365                 key = g_strdup_printf("%sbroadcast_address", prefix);
2366                 g_free(ipconfig->address->broadcast);
2367                 ipconfig->address->broadcast = g_key_file_get_string(
2368                                 keyfile, identifier, key, NULL);
2369                 g_free(key);
2370
2371                 key = g_strdup_printf("%sgateway", prefix);
2372                 g_free(ipconfig->address->gateway);
2373                 ipconfig->address->gateway = g_key_file_get_string(
2374                                 keyfile, identifier, key, NULL);
2375                 g_free(key);
2376                 break;
2377
2378         case CONNMAN_IPCONFIG_METHOD_DHCP:
2379
2380                 key = g_strdup_printf("%sDHCP.LastAddress", prefix);
2381                 str = g_key_file_get_string(keyfile, identifier, key, NULL);
2382                 if (str) {
2383                         g_free(ipconfig->last_dhcp_address);
2384                         ipconfig->last_dhcp_address = str;
2385                 }
2386                 g_free(key);
2387
2388                 break;
2389
2390         case CONNMAN_IPCONFIG_METHOD_AUTO:
2391                 break;
2392         }
2393
2394         return 0;
2395 }
2396
2397 int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
2398                 GKeyFile *keyfile, const char *identifier, const char *prefix)
2399 {
2400         const char *method;
2401         char *key;
2402
2403         method = __connman_ipconfig_method2string(ipconfig->method);
2404
2405         DBG("ipconfig %p identifier %s method %s", ipconfig, identifier,
2406                                                                 method);
2407         if (method) {
2408                 key = g_strdup_printf("%smethod", prefix);
2409                 g_key_file_set_string(keyfile, identifier, key, method);
2410                 g_free(key);
2411         }
2412
2413         if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) {
2414                 const char *privacy;
2415                 privacy = privacy2string(ipconfig->ipv6_privacy_config);
2416                 key = g_strdup_printf("%sprivacy", prefix);
2417                 g_key_file_set_string(keyfile, identifier, key, privacy);
2418                 g_free(key);
2419
2420                 key = g_strdup_printf("%sDHCP.LastAddress", prefix);
2421                 if (ipconfig->last_dhcp_address &&
2422                                 strlen(ipconfig->last_dhcp_address) > 0)
2423                         g_key_file_set_string(keyfile, identifier, key,
2424                                         ipconfig->last_dhcp_address);
2425                 else
2426                         g_key_file_remove_key(keyfile, identifier, key, NULL);
2427                 g_free(key);
2428
2429                 key = g_strdup_printf("%sDHCP.LastPrefixes", prefix);
2430                 if (ipconfig->last_dhcpv6_prefixes &&
2431                                 ipconfig->last_dhcpv6_prefixes[0]) {
2432                         guint len =
2433                                 g_strv_length(ipconfig->last_dhcpv6_prefixes);
2434
2435                         g_key_file_set_string_list(keyfile, identifier, key,
2436                                 (const gchar **)ipconfig->last_dhcpv6_prefixes,
2437                                                 len);
2438                 } else
2439                         g_key_file_remove_key(keyfile, identifier, key, NULL);
2440                 g_free(key);
2441         }
2442
2443         switch (ipconfig->method) {
2444         case CONNMAN_IPCONFIG_METHOD_FIXED:
2445         case CONNMAN_IPCONFIG_METHOD_MANUAL:
2446                 break;
2447         case CONNMAN_IPCONFIG_METHOD_DHCP:
2448                 key = g_strdup_printf("%sDHCP.LastAddress", prefix);
2449                 if (ipconfig->last_dhcp_address &&
2450                                 strlen(ipconfig->last_dhcp_address) > 0)
2451                         g_key_file_set_string(keyfile, identifier, key,
2452                                         ipconfig->last_dhcp_address);
2453                 else
2454                         g_key_file_remove_key(keyfile, identifier, key, NULL);
2455                 g_free(key);
2456                 /* fall through */
2457         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
2458         case CONNMAN_IPCONFIG_METHOD_OFF:
2459         case CONNMAN_IPCONFIG_METHOD_AUTO:
2460                 return 0;
2461         }
2462
2463         key = g_strdup_printf("%snetmask_prefixlen", prefix);
2464         if (ipconfig->address->prefixlen != 0)
2465                 g_key_file_set_integer(keyfile, identifier,
2466                                 key, ipconfig->address->prefixlen);
2467         g_free(key);
2468
2469         key = g_strdup_printf("%slocal_address", prefix);
2470         if (ipconfig->address->local)
2471                 g_key_file_set_string(keyfile, identifier,
2472                                 key, ipconfig->address->local);
2473         g_free(key);
2474
2475         key = g_strdup_printf("%speer_address", prefix);
2476         if (ipconfig->address->peer)
2477                 g_key_file_set_string(keyfile, identifier,
2478                                 key, ipconfig->address->peer);
2479         g_free(key);
2480
2481         key = g_strdup_printf("%sbroadcast_address", prefix);
2482         if (ipconfig->address->broadcast)
2483                 g_key_file_set_string(keyfile, identifier,
2484                         key, ipconfig->address->broadcast);
2485         g_free(key);
2486
2487         key = g_strdup_printf("%sgateway", prefix);
2488         if (ipconfig->address->gateway)
2489                 g_key_file_set_string(keyfile, identifier,
2490                         key, ipconfig->address->gateway);
2491         g_free(key);
2492
2493         return 0;
2494 }
2495
2496 int __connman_ipconfig_init(void)
2497 {
2498         DBG("");
2499
2500         ipdevice_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
2501                                                         NULL, free_ipdevice);
2502
2503         is_ipv6_supported = connman_inet_is_ipv6_supported();
2504
2505         return 0;
2506 }
2507
2508 void __connman_ipconfig_cleanup(void)
2509 {
2510         DBG("");
2511
2512         g_hash_table_destroy(ipdevice_hash);
2513         ipdevice_hash = NULL;
2514 }