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