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