merge tag upstream/1.38
[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 out:
789         g_free(ifname);
790         return 0;
791 }
792
793 void __connman_ipconfig_deladdr(int index, int family, const char *label,
794                                 unsigned char prefixlen, const char *address)
795 {
796         struct connman_ipdevice *ipdevice;
797         struct connman_ipaddress *ipaddress;
798         enum connman_ipconfig_type type;
799         GList *list;
800         char *ifname;
801
802         DBG("index %d", index);
803
804         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
805         if (!ipdevice)
806                 return;
807
808         ipaddress = find_ipaddress(ipdevice, prefixlen, address);
809         if (!ipaddress)
810                 return;
811
812         if (family == AF_INET)
813                 type = CONNMAN_IPCONFIG_TYPE_IPV4;
814         else if (family == AF_INET6)
815                 type = CONNMAN_IPCONFIG_TYPE_IPV6;
816         else
817                 return;
818
819         ipdevice->address_list = g_slist_remove(ipdevice->address_list,
820                                                                 ipaddress);
821
822         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
823                 __connman_ippool_deladdr(index, address, prefixlen);
824
825         connman_ipaddress_clear(ipaddress);
826         g_free(ipaddress);
827
828         ifname = connman_inet_ifname(index);
829         connman_info("%s {del} address %s/%u label %s", ifname,
830                                                 address, prefixlen, label);
831
832         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
833                 goto out;
834
835         if (g_slist_length(ipdevice->address_list) > 0)
836                 goto out;
837
838         for (list = g_list_first(ipconfig_list); list;
839                                                 list = g_list_next(list)) {
840                 struct connman_ipconfig *ipconfig = list->data;
841
842                 if (index != ipconfig->index)
843                         continue;
844
845                 if (type != ipconfig->type)
846                         continue;
847
848                 if (!ipconfig->ops)
849                         continue;
850
851                 if (ipconfig->ops->ip_release)
852                         ipconfig->ops->ip_release(ipconfig, ifname);
853         }
854
855 out:
856         g_free(ifname);
857 }
858
859 void __connman_ipconfig_newroute(int index, int family, unsigned char scope,
860                                         const char *dst, const char *gateway)
861 {
862         struct connman_ipdevice *ipdevice;
863         char *ifname;
864
865         DBG("index %d", index);
866
867         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
868         if (!ipdevice)
869                 return;
870
871         ifname = connman_inet_ifname(index);
872
873         if (scope == 0 && (g_strcmp0(dst, "0.0.0.0") == 0 ||
874                                                 g_strcmp0(dst, "::") == 0)) {
875                 GList *config_list;
876                 enum connman_ipconfig_type type;
877
878                 if (family == AF_INET6) {
879                         type = CONNMAN_IPCONFIG_TYPE_IPV6;
880                         g_free(ipdevice->ipv6_gateway);
881                         ipdevice->ipv6_gateway = g_strdup(gateway);
882
883                         if (ipdevice->config_ipv6 &&
884                                 ipdevice->config_ipv6->system) {
885                                 g_free(ipdevice->config_ipv6->system->gateway);
886                                 ipdevice->config_ipv6->system->gateway =
887                                         g_strdup(gateway);
888                         }
889                 } else if (family == AF_INET) {
890                         type = CONNMAN_IPCONFIG_TYPE_IPV4;
891                         g_free(ipdevice->ipv4_gateway);
892                         ipdevice->ipv4_gateway = g_strdup(gateway);
893
894                         if (ipdevice->config_ipv4 &&
895                                 ipdevice->config_ipv4->system) {
896                                 g_free(ipdevice->config_ipv4->system->gateway);
897                                 ipdevice->config_ipv4->system->gateway =
898                                         g_strdup(gateway);
899                         }
900                 } else
901                         goto out;
902
903                 for (config_list = g_list_first(ipconfig_list); config_list;
904                                         config_list = g_list_next(config_list)) {
905                         struct connman_ipconfig *ipconfig = config_list->data;
906
907                         if (index != ipconfig->index)
908                                 continue;
909
910                         if (type != ipconfig->type)
911                                 continue;
912
913                         if (!ipconfig->ops)
914                                 continue;
915
916                         if (ipconfig->ops->route_set)
917                                 ipconfig->ops->route_set(ipconfig, ifname);
918                 }
919         }
920
921         connman_info("%s {add} route %s gw %s scope %u <%s>",
922                 ifname, dst, gateway, scope, scope2str(scope));
923
924 out:
925         g_free(ifname);
926 }
927
928 void __connman_ipconfig_delroute(int index, int family, unsigned char scope,
929                                         const char *dst, const char *gateway)
930 {
931         struct connman_ipdevice *ipdevice;
932         char *ifname;
933
934         DBG("index %d", index);
935
936         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
937         if (!ipdevice)
938                 return;
939
940         ifname = connman_inet_ifname(index);
941
942         if (scope == 0 && (g_strcmp0(dst, "0.0.0.0") == 0 ||
943                                                 g_strcmp0(dst, "::") == 0)) {
944                 GList *config_list;
945                 enum connman_ipconfig_type type;
946
947                 if (family == AF_INET6) {
948                         type = CONNMAN_IPCONFIG_TYPE_IPV6;
949                         g_free(ipdevice->ipv6_gateway);
950                         ipdevice->ipv6_gateway = NULL;
951
952                         if (ipdevice->config_ipv6 &&
953                                 ipdevice->config_ipv6->system) {
954                                 g_free(ipdevice->config_ipv6->system->gateway);
955                                 ipdevice->config_ipv6->system->gateway = NULL;
956                         }
957                 } else if (family == AF_INET) {
958                         type = CONNMAN_IPCONFIG_TYPE_IPV4;
959                         g_free(ipdevice->ipv4_gateway);
960                         ipdevice->ipv4_gateway = NULL;
961
962                         if (ipdevice->config_ipv4 &&
963                                 ipdevice->config_ipv4->system) {
964                                 g_free(ipdevice->config_ipv4->system->gateway);
965                                 ipdevice->config_ipv4->system->gateway = NULL;
966                         }
967                 } else
968                         goto out;
969
970                 for (config_list = g_list_first(ipconfig_list); config_list;
971                                         config_list = g_list_next(config_list)) {
972                         struct connman_ipconfig *ipconfig = config_list->data;
973
974                         if (index != ipconfig->index)
975                                 continue;
976
977                         if (type != ipconfig->type)
978                                 continue;
979
980                         if (!ipconfig->ops)
981                                 continue;
982
983                         if (ipconfig->ops->route_unset)
984                                 ipconfig->ops->route_unset(ipconfig, ifname);
985                 }
986         }
987
988         connman_info("%s {del} route %s gw %s scope %u <%s>",
989                 ifname, dst, gateway, scope, scope2str(scope));
990
991 out:
992         g_free(ifname);
993 }
994
995 void __connman_ipconfig_foreach(void (*function) (int index, void *user_data),
996                                                         void *user_data)
997 {
998         GList *list, *keys;
999
1000         keys = g_hash_table_get_keys(ipdevice_hash);
1001         if (!keys)
1002                 return;
1003
1004         for (list = g_list_first(keys); list; list = g_list_next(list)) {
1005                 int index = GPOINTER_TO_INT(list->data);
1006
1007                 function(index, user_data);
1008         }
1009
1010         g_list_free(keys);
1011 }
1012
1013 enum connman_ipconfig_type __connman_ipconfig_get_config_type(
1014                                         struct connman_ipconfig *ipconfig)
1015 {
1016         return ipconfig ? ipconfig->type : CONNMAN_IPCONFIG_TYPE_UNKNOWN;
1017 }
1018
1019 unsigned short __connman_ipconfig_get_type_from_index(int index)
1020 {
1021         struct connman_ipdevice *ipdevice;
1022
1023         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
1024         if (!ipdevice)
1025                 return ARPHRD_VOID;
1026
1027         return ipdevice->type;
1028 }
1029
1030 unsigned int __connman_ipconfig_get_flags_from_index(int index)
1031 {
1032         struct connman_ipdevice *ipdevice;
1033
1034         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
1035         if (!ipdevice)
1036                 return 0;
1037
1038         return ipdevice->flags;
1039 }
1040
1041 const char *__connman_ipconfig_get_gateway_from_index(int index,
1042         enum connman_ipconfig_type type)
1043 {
1044         struct connman_ipdevice *ipdevice;
1045
1046         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
1047         if (!ipdevice)
1048                 return NULL;
1049
1050         if (type != CONNMAN_IPCONFIG_TYPE_IPV6) {
1051                 if (ipdevice->ipv4_gateway)
1052                         return ipdevice->ipv4_gateway;
1053
1054                 if (ipdevice->config_ipv4 &&
1055                                 ipdevice->config_ipv4->address)
1056                         return ipdevice->config_ipv4->address->gateway;
1057         }
1058
1059         if (type != CONNMAN_IPCONFIG_TYPE_IPV4) {
1060                 if (ipdevice->ipv6_gateway)
1061                         return ipdevice->ipv6_gateway;
1062
1063                 if (ipdevice->config_ipv6 &&
1064                                 ipdevice->config_ipv6->address)
1065                         return ipdevice->config_ipv6->address->gateway;
1066         }
1067
1068         return NULL;
1069 }
1070
1071 void __connman_ipconfig_set_index(struct connman_ipconfig *ipconfig, int index)
1072 {
1073         ipconfig->index = index;
1074 }
1075
1076 const char *__connman_ipconfig_get_local(struct connman_ipconfig *ipconfig)
1077 {
1078         if (!ipconfig->address)
1079                 return NULL;
1080
1081         return ipconfig->address->local;
1082 }
1083
1084 void __connman_ipconfig_set_local(struct connman_ipconfig *ipconfig,
1085                                         const char *address)
1086 {
1087         if (!ipconfig->address)
1088                 return;
1089
1090         g_free(ipconfig->address->local);
1091         ipconfig->address->local = g_strdup(address);
1092 }
1093
1094 const char *__connman_ipconfig_get_peer(struct connman_ipconfig *ipconfig)
1095 {
1096         if (!ipconfig->address)
1097                 return NULL;
1098
1099         return ipconfig->address->peer;
1100 }
1101
1102 void __connman_ipconfig_set_peer(struct connman_ipconfig *ipconfig,
1103                                         const char *address)
1104 {
1105         if (!ipconfig->address)
1106                 return;
1107
1108         g_free(ipconfig->address->peer);
1109         ipconfig->address->peer = g_strdup(address);
1110 }
1111
1112 const char *__connman_ipconfig_get_broadcast(struct connman_ipconfig *ipconfig)
1113 {
1114         if (!ipconfig->address)
1115                 return NULL;
1116
1117         return ipconfig->address->broadcast;
1118 }
1119
1120 void __connman_ipconfig_set_broadcast(struct connman_ipconfig *ipconfig,
1121                                         const char *broadcast)
1122 {
1123         if (!ipconfig->address)
1124                 return;
1125
1126         g_free(ipconfig->address->broadcast);
1127         ipconfig->address->broadcast = g_strdup(broadcast);
1128 }
1129
1130 const char *__connman_ipconfig_get_gateway(struct connman_ipconfig *ipconfig)
1131 {
1132         if (!ipconfig->address)
1133                 return NULL;
1134
1135         return ipconfig->address->gateway;
1136 }
1137
1138 void __connman_ipconfig_set_gateway(struct connman_ipconfig *ipconfig,
1139                                         const char *gateway)
1140 {
1141         DBG("");
1142
1143         if (!ipconfig->address)
1144                 return;
1145         g_free(ipconfig->address->gateway);
1146         ipconfig->address->gateway = g_strdup(gateway);
1147 }
1148
1149 #if defined TIZEN_EXT
1150 void __connman_ipconfig_set_dhcp_lease_duration(struct connman_ipconfig *ipconfig,
1151                 int dhcp_lease_duration)
1152 {
1153         ipconfig->dhcp_lease_duration = dhcp_lease_duration;
1154 }
1155 #endif
1156
1157 #if defined TIZEN_EXT
1158 int __connman_ipconfig_gateway_add(struct connman_ipconfig *ipconfig, struct connman_service *service)
1159 #else
1160 int __connman_ipconfig_gateway_add(struct connman_ipconfig *ipconfig)
1161 #endif
1162 {
1163 #if !defined TIZEN_EXT
1164         struct connman_service *service;
1165 #endif
1166
1167         DBG("");
1168
1169         if (!ipconfig->address)
1170                 return -EINVAL;
1171
1172 #if !defined TIZEN_EXT
1173         service = __connman_service_lookup_from_index(ipconfig->index);
1174 #endif
1175         if (!service)
1176                 return -EINVAL;
1177
1178         DBG("type %d gw %s peer %s", ipconfig->type,
1179                 ipconfig->address->gateway, ipconfig->address->peer);
1180
1181         if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6 ||
1182                                 ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4)
1183                 return __connman_connection_gateway_add(service,
1184                                                 ipconfig->address->gateway,
1185                                                 ipconfig->type,
1186                                                 ipconfig->address->peer);
1187
1188         return 0;
1189 }
1190
1191 void __connman_ipconfig_gateway_remove(struct connman_ipconfig *ipconfig)
1192 {
1193         struct connman_service *service;
1194
1195         DBG("");
1196
1197         service = __connman_service_lookup_from_index(ipconfig->index);
1198         if (service)
1199                 __connman_connection_gateway_remove(service, ipconfig->type);
1200 }
1201
1202 unsigned char __connman_ipconfig_get_prefixlen(struct connman_ipconfig *ipconfig)
1203 {
1204         if (!ipconfig->address)
1205                 return 0;
1206
1207         return ipconfig->address->prefixlen;
1208 }
1209
1210 void __connman_ipconfig_set_prefixlen(struct connman_ipconfig *ipconfig,
1211                                         unsigned char prefixlen)
1212 {
1213         if (!ipconfig->address)
1214                 return;
1215
1216         ipconfig->address->prefixlen = prefixlen;
1217 }
1218
1219 static struct connman_ipconfig *create_ipv6config(int index)
1220 {
1221         struct connman_ipconfig *ipv6config;
1222         struct connman_ipdevice *ipdevice;
1223
1224         ipv6config = g_try_new0(struct connman_ipconfig, 1);
1225         if (!ipv6config)
1226                 return NULL;
1227
1228         ipv6config->refcount = 1;
1229
1230         ipv6config->index = index;
1231         ipv6config->type = CONNMAN_IPCONFIG_TYPE_IPV6;
1232
1233         if (!is_ipv6_supported)
1234                 ipv6config->method = CONNMAN_IPCONFIG_METHOD_OFF;
1235         else
1236                 ipv6config->method = CONNMAN_IPCONFIG_METHOD_AUTO;
1237
1238         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
1239         if (ipdevice)
1240 #if !defined TIZEN_EXT
1241                 ipv6config->ipv6_privacy_config = ipdevice->ipv6_privacy;
1242 #else
1243                 ipv6config->ipv6_privacy_config = ipdevice->ipv6_privacy = 2;
1244 #endif
1245
1246         ipv6config->address = connman_ipaddress_alloc(AF_INET6);
1247         if (!ipv6config->address) {
1248                 g_free(ipv6config);
1249                 return NULL;
1250         }
1251
1252         ipv6config->system = connman_ipaddress_alloc(AF_INET6);
1253
1254         DBG("ipconfig %p index %d method %s", ipv6config, index,
1255                 __connman_ipconfig_method2string(ipv6config->method));
1256
1257         return ipv6config;
1258 }
1259
1260 /**
1261  * connman_ipconfig_create:
1262  *
1263  * Allocate a new ipconfig structure.
1264  *
1265  * Returns: a newly-allocated #connman_ipconfig structure
1266  */
1267 struct connman_ipconfig *__connman_ipconfig_create(int index,
1268                                         enum connman_ipconfig_type type)
1269 {
1270         struct connman_ipconfig *ipconfig;
1271
1272         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
1273                 return create_ipv6config(index);
1274
1275         ipconfig = g_try_new0(struct connman_ipconfig, 1);
1276         if (!ipconfig)
1277                 return NULL;
1278
1279         ipconfig->refcount = 1;
1280
1281         ipconfig->index = index;
1282         ipconfig->type = CONNMAN_IPCONFIG_TYPE_IPV4;
1283
1284         ipconfig->address = connman_ipaddress_alloc(AF_INET);
1285         if (!ipconfig->address) {
1286                 g_free(ipconfig);
1287                 return NULL;
1288         }
1289
1290         ipconfig->system = connman_ipaddress_alloc(AF_INET);
1291 #if defined TIZEN_EXT
1292         if (!simplified_log)
1293 #endif
1294         DBG("ipconfig %p index %d", ipconfig, index);
1295
1296         return ipconfig;
1297 }
1298
1299
1300 /**
1301  * connman_ipconfig_ref:
1302  * @ipconfig: ipconfig structure
1303  *
1304  * Increase reference counter of ipconfig
1305  */
1306 struct connman_ipconfig *
1307 __connman_ipconfig_ref_debug(struct connman_ipconfig *ipconfig,
1308                                 const char *file, int line, const char *caller)
1309 {
1310         DBG("%p ref %d by %s:%d:%s()", ipconfig, ipconfig->refcount + 1,
1311                 file, line, caller);
1312
1313         __sync_fetch_and_add(&ipconfig->refcount, 1);
1314
1315         return ipconfig;
1316 }
1317
1318 /**
1319  * connman_ipconfig_unref:
1320  * @ipconfig: ipconfig structure
1321  *
1322  * Decrease reference counter of ipconfig
1323  */
1324 void __connman_ipconfig_unref_debug(struct connman_ipconfig *ipconfig,
1325                                 const char *file, int line, const char *caller)
1326 {
1327         if (!ipconfig)
1328                 return;
1329 #if defined TIZEN_EXT
1330         if (!simplified_log)
1331 #endif
1332         DBG("%p ref %d by %s:%d:%s()", ipconfig, ipconfig->refcount - 1,
1333                 file, line, caller);
1334
1335         if (__sync_fetch_and_sub(&ipconfig->refcount, 1) != 1)
1336                 return;
1337
1338         if (__connman_ipconfig_disable(ipconfig) < 0)
1339                 ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
1340
1341         __connman_ipconfig_set_ops(ipconfig, NULL);
1342
1343         connman_ipaddress_free(ipconfig->system);
1344         connman_ipaddress_free(ipconfig->address);
1345         g_free(ipconfig->last_dhcp_address);
1346         g_strfreev(ipconfig->last_dhcpv6_prefixes);
1347         g_free(ipconfig);
1348 }
1349
1350 /**
1351  * connman_ipconfig_get_data:
1352  * @ipconfig: ipconfig structure
1353  *
1354  * Get private data pointer
1355  */
1356 void *__connman_ipconfig_get_data(struct connman_ipconfig *ipconfig)
1357 {
1358         if (!ipconfig)
1359                 return NULL;
1360
1361         return ipconfig->ops_data;
1362 }
1363
1364 /**
1365  * connman_ipconfig_set_data:
1366  * @ipconfig: ipconfig structure
1367  * @data: data pointer
1368  *
1369  * Set private data pointer
1370  */
1371 void __connman_ipconfig_set_data(struct connman_ipconfig *ipconfig, void *data)
1372 {
1373         ipconfig->ops_data = data;
1374 }
1375
1376 /**
1377  * connman_ipconfig_get_index:
1378  * @ipconfig: ipconfig structure
1379  *
1380  * Get interface index
1381  */
1382 int __connman_ipconfig_get_index(struct connman_ipconfig *ipconfig)
1383 {
1384         if (!ipconfig)
1385                 return -1;
1386
1387         return ipconfig->index;
1388 }
1389
1390 /**
1391  * connman_ipconfig_set_ops:
1392  * @ipconfig: ipconfig structure
1393  * @ops: operation callbacks
1394  *
1395  * Set the operation callbacks
1396  */
1397 void __connman_ipconfig_set_ops(struct connman_ipconfig *ipconfig,
1398                                 const struct connman_ipconfig_ops *ops)
1399 {
1400         ipconfig->ops = ops;
1401 }
1402
1403 /**
1404  * connman_ipconfig_set_method:
1405  * @ipconfig: ipconfig structure
1406  * @method: configuration method
1407  *
1408  * Set the configuration method
1409  */
1410 int __connman_ipconfig_set_method(struct connman_ipconfig *ipconfig,
1411                                         enum connman_ipconfig_method method)
1412 {
1413         ipconfig->method = method;
1414
1415         return 0;
1416 }
1417
1418 enum connman_ipconfig_method __connman_ipconfig_get_method(
1419                                 struct connman_ipconfig *ipconfig)
1420 {
1421         if (!ipconfig)
1422                 return CONNMAN_IPCONFIG_METHOD_UNKNOWN;
1423
1424         return ipconfig->method;
1425 }
1426
1427 int __connman_ipconfig_address_add(struct connman_ipconfig *ipconfig)
1428 {
1429         switch (ipconfig->method) {
1430         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1431         case CONNMAN_IPCONFIG_METHOD_OFF:
1432                 break;
1433         case CONNMAN_IPCONFIG_METHOD_AUTO:
1434         case CONNMAN_IPCONFIG_METHOD_FIXED:
1435         case CONNMAN_IPCONFIG_METHOD_DHCP:
1436         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1437                 if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4)
1438                         return connman_inet_set_address(ipconfig->index,
1439                                                         ipconfig->address);
1440                 else if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
1441                         return connman_inet_set_ipv6_address(
1442                                         ipconfig->index, ipconfig->address);
1443         }
1444
1445         return 0;
1446 }
1447
1448 int __connman_ipconfig_address_remove(struct connman_ipconfig *ipconfig)
1449 {
1450         int err;
1451
1452         if (!ipconfig)
1453                 return 0;
1454
1455         switch (ipconfig->method) {
1456         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1457         case CONNMAN_IPCONFIG_METHOD_OFF:
1458                 break;
1459         case CONNMAN_IPCONFIG_METHOD_AUTO:
1460         case CONNMAN_IPCONFIG_METHOD_DHCP:
1461                 err = __connman_ipconfig_address_unset(ipconfig);
1462                 connman_ipaddress_clear(ipconfig->address);
1463
1464                 return err;
1465         case CONNMAN_IPCONFIG_METHOD_FIXED:
1466         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1467                 return __connman_ipconfig_address_unset(ipconfig);
1468         }
1469
1470         return 0;
1471 }
1472
1473 int __connman_ipconfig_address_unset(struct connman_ipconfig *ipconfig)
1474 {
1475         int err;
1476
1477         if (!ipconfig)
1478                 return 0;
1479
1480 #if defined TIZEN_EXT
1481         DBG("ipconfig method %d type %d", ipconfig->method, ipconfig->type);
1482 #else
1483         DBG("method %d", ipconfig->method);
1484 #endif
1485
1486         switch (ipconfig->method) {
1487         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1488         case CONNMAN_IPCONFIG_METHOD_OFF:
1489                 break;
1490         case CONNMAN_IPCONFIG_METHOD_AUTO:
1491         case CONNMAN_IPCONFIG_METHOD_FIXED:
1492         case CONNMAN_IPCONFIG_METHOD_DHCP:
1493         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1494                 if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4)
1495                         err = connman_inet_clear_address(ipconfig->index,
1496                                                         ipconfig->address);
1497                 else if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
1498                         err = connman_inet_clear_ipv6_address(
1499                                                 ipconfig->index,
1500                                                 ipconfig->address->local,
1501                                                 ipconfig->address->prefixlen);
1502                 else
1503                         err = -EINVAL;
1504
1505                 return err;
1506         }
1507
1508         return 0;
1509 }
1510
1511 int __connman_ipconfig_set_proxy_autoconfig(struct connman_ipconfig *ipconfig,
1512                                                         const char *url)
1513 {
1514         struct connman_ipdevice *ipdevice;
1515
1516         if (!ipconfig || ipconfig->index < 0)
1517                 return -ENODEV;
1518
1519         ipdevice = g_hash_table_lookup(ipdevice_hash,
1520                                         GINT_TO_POINTER(ipconfig->index));
1521         if (!ipdevice)
1522                 return -ENXIO;
1523
1524         g_free(ipdevice->pac);
1525         ipdevice->pac = g_strdup(url);
1526
1527         return 0;
1528 }
1529
1530 const char *__connman_ipconfig_get_proxy_autoconfig(struct connman_ipconfig *ipconfig)
1531 {
1532         struct connman_ipdevice *ipdevice;
1533
1534         if (!ipconfig || ipconfig->index < 0)
1535                 return NULL;
1536
1537         ipdevice = g_hash_table_lookup(ipdevice_hash,
1538                                         GINT_TO_POINTER(ipconfig->index));
1539         if (!ipdevice)
1540                 return NULL;
1541
1542         return ipdevice->pac;
1543 }
1544
1545 void __connman_ipconfig_set_dhcp_address(struct connman_ipconfig *ipconfig,
1546                                         const char *address)
1547 {
1548         if (!ipconfig)
1549                 return;
1550
1551         g_free(ipconfig->last_dhcp_address);
1552         ipconfig->last_dhcp_address = g_strdup(address);
1553 }
1554
1555 char *__connman_ipconfig_get_dhcp_address(struct connman_ipconfig *ipconfig)
1556 {
1557         if (!ipconfig)
1558                 return NULL;
1559
1560         return ipconfig->last_dhcp_address;
1561 }
1562
1563 void __connman_ipconfig_set_dhcpv6_prefixes(struct connman_ipconfig *ipconfig,
1564                                         char **prefixes)
1565 {
1566         if (!ipconfig)
1567                 return;
1568
1569         g_strfreev(ipconfig->last_dhcpv6_prefixes);
1570         ipconfig->last_dhcpv6_prefixes = prefixes;
1571 }
1572
1573 char **__connman_ipconfig_get_dhcpv6_prefixes(struct connman_ipconfig *ipconfig)
1574 {
1575         if (!ipconfig)
1576                 return NULL;
1577
1578         return ipconfig->last_dhcpv6_prefixes;
1579 }
1580
1581 static void disable_ipv6(struct connman_ipconfig *ipconfig)
1582 {
1583         struct connman_ipdevice *ipdevice;
1584         char *ifname;
1585
1586         DBG("");
1587
1588         ipdevice = g_hash_table_lookup(ipdevice_hash,
1589                                         GINT_TO_POINTER(ipconfig->index));
1590         if (!ipdevice)
1591                 return;
1592
1593         ifname = connman_inet_ifname(ipconfig->index);
1594
1595         set_ipv6_state(ifname, false);
1596
1597         g_free(ifname);
1598 }
1599
1600 static void enable_ipv6(struct connman_ipconfig *ipconfig)
1601 {
1602         struct connman_ipdevice *ipdevice;
1603         char *ifname;
1604
1605         DBG("");
1606
1607         ipdevice = g_hash_table_lookup(ipdevice_hash,
1608                                         GINT_TO_POINTER(ipconfig->index));
1609         if (!ipdevice)
1610                 return;
1611
1612         ifname = connman_inet_ifname(ipconfig->index);
1613
1614         if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_AUTO)
1615                 set_ipv6_privacy(ifname, ipconfig->ipv6_privacy_config);
1616
1617         set_ipv6_state(ifname, true);
1618
1619         g_free(ifname);
1620 }
1621
1622 void __connman_ipconfig_enable_ipv6(struct connman_ipconfig *ipconfig)
1623 {
1624         if (!ipconfig || ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
1625                 return;
1626
1627         enable_ipv6(ipconfig);
1628 }
1629
1630 void __connman_ipconfig_disable_ipv6(struct connman_ipconfig *ipconfig)
1631 {
1632         if (!ipconfig || ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
1633                 return;
1634
1635         disable_ipv6(ipconfig);
1636 }
1637
1638 bool __connman_ipconfig_is_usable(struct connman_ipconfig *ipconfig)
1639 {
1640         if (!ipconfig)
1641                 return false;
1642
1643         switch (ipconfig->method) {
1644         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1645         case CONNMAN_IPCONFIG_METHOD_OFF:
1646                 return false;
1647         case CONNMAN_IPCONFIG_METHOD_AUTO:
1648         case CONNMAN_IPCONFIG_METHOD_FIXED:
1649         case CONNMAN_IPCONFIG_METHOD_DHCP:
1650         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1651                 break;
1652         }
1653
1654         return true;
1655 }
1656
1657 int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
1658 {
1659         struct connman_ipdevice *ipdevice;
1660         bool up = false, down = false;
1661         bool lower_up = false, lower_down = false;
1662         enum connman_ipconfig_type type;
1663         char *ifname;
1664
1665         DBG("ipconfig %p", ipconfig);
1666
1667         if (!ipconfig || ipconfig->index < 0)
1668                 return -ENODEV;
1669
1670         ipdevice = g_hash_table_lookup(ipdevice_hash,
1671                                         GINT_TO_POINTER(ipconfig->index));
1672         if (!ipdevice)
1673                 return -ENXIO;
1674
1675         if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4) {
1676                 if (ipdevice->config_ipv4 == ipconfig)
1677                         return -EALREADY;
1678                 type = CONNMAN_IPCONFIG_TYPE_IPV4;
1679         } else if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) {
1680                 if (ipdevice->config_ipv6 == ipconfig)
1681                         return -EALREADY;
1682                 type = CONNMAN_IPCONFIG_TYPE_IPV6;
1683         } else
1684                 return -EINVAL;
1685
1686         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
1687                                         ipdevice->config_ipv4) {
1688                 ipconfig_list = g_list_remove(ipconfig_list,
1689                                                         ipdevice->config_ipv4);
1690
1691                 connman_ipaddress_clear(ipdevice->config_ipv4->system);
1692
1693                 __connman_ipconfig_unref(ipdevice->config_ipv4);
1694         }
1695
1696         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
1697                                         ipdevice->config_ipv6) {
1698                 ipconfig_list = g_list_remove(ipconfig_list,
1699                                                         ipdevice->config_ipv6);
1700
1701                 connman_ipaddress_clear(ipdevice->config_ipv6->system);
1702
1703                 __connman_ipconfig_unref(ipdevice->config_ipv6);
1704         }
1705
1706         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
1707                 ipdevice->config_ipv4 = __connman_ipconfig_ref(ipconfig);
1708         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
1709                 ipdevice->config_ipv6 = __connman_ipconfig_ref(ipconfig);
1710
1711                 enable_ipv6(ipdevice->config_ipv6);
1712         }
1713         ipconfig_list = g_list_append(ipconfig_list, ipconfig);
1714
1715         if (ipdevice->flags & IFF_UP)
1716                 up = true;
1717         else
1718                 down = true;
1719
1720         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) ==
1721                         (IFF_RUNNING | IFF_LOWER_UP))
1722                 lower_up = true;
1723         else if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) == 0)
1724                 lower_down = true;
1725
1726         ifname = connman_inet_ifname(ipconfig->index);
1727
1728         if (up && ipconfig->ops->up)
1729                 ipconfig->ops->up(ipconfig, ifname);
1730         if (lower_up && ipconfig->ops->lower_up)
1731                 ipconfig->ops->lower_up(ipconfig, ifname);
1732
1733         if (lower_down && ipconfig->ops->lower_down)
1734                 ipconfig->ops->lower_down(ipconfig, ifname);
1735         if (down && ipconfig->ops->down)
1736                 ipconfig->ops->down(ipconfig, ifname);
1737
1738         g_free(ifname);
1739
1740         return 0;
1741 }
1742
1743 int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
1744 {
1745         struct connman_ipdevice *ipdevice;
1746 #if defined TIZEN_EXT
1747         if (!simplified_log)
1748 #endif
1749         DBG("ipconfig %p", ipconfig);
1750
1751         if (!ipconfig || ipconfig->index < 0)
1752                 return -ENODEV;
1753
1754         ipdevice = g_hash_table_lookup(ipdevice_hash,
1755                                         GINT_TO_POINTER(ipconfig->index));
1756         if (!ipdevice)
1757                 return -ENXIO;
1758
1759         if (!ipdevice->config_ipv4 && !ipdevice->config_ipv6)
1760                 return -EINVAL;
1761
1762         if (ipdevice->config_ipv4 == ipconfig) {
1763                 ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
1764
1765                 connman_ipaddress_clear(ipdevice->config_ipv4->system);
1766                 __connman_ipconfig_unref(ipdevice->config_ipv4);
1767                 ipdevice->config_ipv4 = NULL;
1768                 return 0;
1769         }
1770
1771         if (ipdevice->config_ipv6 == ipconfig) {
1772                 ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
1773
1774 #if defined TIZEN_EXT
1775                 if (ipdevice->config_ipv6->method ==
1776                                 CONNMAN_IPCONFIG_METHOD_AUTO)
1777                         disable_ipv6(ipdevice->config_ipv6);
1778 #endif
1779                 connman_ipaddress_clear(ipdevice->config_ipv6->system);
1780                 __connman_ipconfig_unref(ipdevice->config_ipv6);
1781                 ipdevice->config_ipv6 = NULL;
1782                 return 0;
1783         }
1784
1785         return -EINVAL;
1786 }
1787
1788 const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method)
1789 {
1790         switch (method) {
1791         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1792                 break;
1793         case CONNMAN_IPCONFIG_METHOD_OFF:
1794                 return "off";
1795         case CONNMAN_IPCONFIG_METHOD_FIXED:
1796                 return "fixed";
1797         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1798                 return "manual";
1799         case CONNMAN_IPCONFIG_METHOD_DHCP:
1800                 return "dhcp";
1801         case CONNMAN_IPCONFIG_METHOD_AUTO:
1802                 return "auto";
1803         }
1804
1805         return NULL;
1806 }
1807
1808 enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method)
1809 {
1810         if (g_strcmp0(method, "off") == 0)
1811                 return CONNMAN_IPCONFIG_METHOD_OFF;
1812         else if (g_strcmp0(method, "fixed") == 0)
1813                 return CONNMAN_IPCONFIG_METHOD_FIXED;
1814         else if (g_strcmp0(method, "manual") == 0)
1815                 return CONNMAN_IPCONFIG_METHOD_MANUAL;
1816         else if (g_strcmp0(method, "dhcp") == 0)
1817                 return CONNMAN_IPCONFIG_METHOD_DHCP;
1818         else if (g_strcmp0(method, "auto") == 0)
1819                 return CONNMAN_IPCONFIG_METHOD_AUTO;
1820         else
1821                 return CONNMAN_IPCONFIG_METHOD_UNKNOWN;
1822 }
1823
1824 static const char *privacy2string(int privacy)
1825 {
1826         if (privacy <= 0)
1827                 return "disabled";
1828         else if (privacy == 1)
1829                 return "enabled";
1830         else
1831                 return "prefered";
1832 }
1833
1834 static int string2privacy(const char *privacy)
1835 {
1836         if (g_strcmp0(privacy, "disabled") == 0)
1837                 return 0;
1838         else if (g_strcmp0(privacy, "enabled") == 0)
1839                 return 1;
1840         else if (g_strcmp0(privacy, "preferred") == 0)
1841                 return 2;
1842         else if (g_strcmp0(privacy, "prefered") == 0)
1843                 return 2;
1844         else
1845                 return 0;
1846 }
1847
1848 int __connman_ipconfig_ipv6_reset_privacy(struct connman_ipconfig *ipconfig)
1849 {
1850         struct connman_ipdevice *ipdevice;
1851         int err;
1852
1853         if (!ipconfig)
1854                 return -EINVAL;
1855
1856         ipdevice = g_hash_table_lookup(ipdevice_hash,
1857                                                 GINT_TO_POINTER(ipconfig->index));
1858         if (!ipdevice)
1859                 return -ENODEV;
1860
1861         err = __connman_ipconfig_ipv6_set_privacy(ipconfig, privacy2string(
1862                                                         ipdevice->ipv6_privacy));
1863
1864         return err;
1865 }
1866
1867 int __connman_ipconfig_ipv6_set_privacy(struct connman_ipconfig *ipconfig,
1868                                         const char *value)
1869 {
1870         int privacy;
1871
1872         if (!ipconfig)
1873                 return -EINVAL;
1874
1875         privacy = string2privacy(value);
1876
1877         ipconfig->ipv6_privacy_config = privacy;
1878
1879         enable_ipv6(ipconfig);
1880
1881         return 0;
1882 }
1883
1884 void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
1885                                                         DBusMessageIter *iter)
1886 {
1887         struct connman_ipaddress *append_addr = NULL;
1888         const char *str;
1889
1890         if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV4)
1891                 return;
1892
1893         str = __connman_ipconfig_method2string(ipconfig->method);
1894         if (!str)
1895                 return;
1896
1897         connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
1898
1899         switch (ipconfig->method) {
1900         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1901         case CONNMAN_IPCONFIG_METHOD_OFF:
1902                 return;
1903
1904         case CONNMAN_IPCONFIG_METHOD_FIXED:
1905                 append_addr = ipconfig->address;
1906                 break;
1907
1908         case CONNMAN_IPCONFIG_METHOD_AUTO:
1909         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1910         case CONNMAN_IPCONFIG_METHOD_DHCP:
1911                 append_addr = ipconfig->system;
1912 #if defined TIZEN_EXT
1913                 /* TIZEN enables get_properties before __connman_ipconfig_newaddr */
1914                 if (append_addr && append_addr->local == NULL)
1915                         append_addr = ipconfig->address;
1916 #endif
1917                 break;
1918         }
1919
1920         if (!append_addr)
1921                 return;
1922
1923         if (append_addr->local) {
1924                 in_addr_t addr;
1925                 struct in_addr netmask;
1926                 char *mask;
1927
1928                 connman_dbus_dict_append_basic(iter, "Address",
1929                                 DBUS_TYPE_STRING, &append_addr->local);
1930
1931                 addr = 0xffffffff << (32 - append_addr->prefixlen);
1932                 netmask.s_addr = htonl(addr);
1933                 mask = inet_ntoa(netmask);
1934                 connman_dbus_dict_append_basic(iter, "Netmask",
1935                                                 DBUS_TYPE_STRING, &mask);
1936         }
1937
1938         if (append_addr->gateway)
1939                 connman_dbus_dict_append_basic(iter, "Gateway",
1940                                 DBUS_TYPE_STRING, &append_addr->gateway);
1941
1942 #if defined TIZEN_EXT
1943         if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_DHCP) {
1944                 char *server_ip;
1945                 server_ip = __connman_dhcp_get_server_address(ipconfig);
1946                 if (server_ip) {
1947                         connman_dbus_dict_append_basic(iter, "DHCPServerIP",
1948                                         DBUS_TYPE_STRING, &server_ip);
1949                         g_free(server_ip);
1950                 }
1951                 connman_dbus_dict_append_basic(iter, "DHCPLeaseDuration",
1952                                 DBUS_TYPE_INT32, &ipconfig->dhcp_lease_duration);
1953         }
1954 #endif
1955 }
1956
1957 void __connman_ipconfig_append_ipv6(struct connman_ipconfig *ipconfig,
1958                                         DBusMessageIter *iter,
1959                                         struct connman_ipconfig *ipconfig_ipv4)
1960 {
1961         struct connman_ipaddress *append_addr = NULL;
1962         const char *str, *privacy;
1963
1964         if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
1965                 return;
1966
1967         str = __connman_ipconfig_method2string(ipconfig->method);
1968         if (!str)
1969                 return;
1970
1971         if (ipconfig_ipv4 &&
1972                         ipconfig->method == CONNMAN_IPCONFIG_METHOD_AUTO) {
1973                 if (__connman_6to4_check(ipconfig_ipv4) == 1)
1974                         str = "6to4";
1975         }
1976
1977         connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
1978
1979         switch (ipconfig->method) {
1980         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1981         case CONNMAN_IPCONFIG_METHOD_OFF:
1982                 return;
1983
1984         case CONNMAN_IPCONFIG_METHOD_FIXED:
1985                 append_addr = ipconfig->address;
1986                 break;
1987
1988         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1989         case CONNMAN_IPCONFIG_METHOD_DHCP:
1990         case CONNMAN_IPCONFIG_METHOD_AUTO:
1991                 append_addr = ipconfig->system;
1992 #if defined TIZEN_EXT
1993                 /* TIZEN enables get_properties before __connman_ipconfig_newaddr */
1994                 if (append_addr && append_addr->local == NULL)
1995                         append_addr = ipconfig->address;
1996 #endif
1997                 break;
1998         }
1999
2000         if (!append_addr)
2001                 return;
2002
2003         if (append_addr->local) {
2004                 connman_dbus_dict_append_basic(iter, "Address",
2005                                 DBUS_TYPE_STRING, &append_addr->local);
2006                 connman_dbus_dict_append_basic(iter, "PrefixLength",
2007                                                 DBUS_TYPE_BYTE,
2008                                                 &append_addr->prefixlen);
2009         }
2010
2011         if (append_addr->gateway)
2012                 connman_dbus_dict_append_basic(iter, "Gateway",
2013                                 DBUS_TYPE_STRING, &append_addr->gateway);
2014
2015         privacy = privacy2string(ipconfig->ipv6_privacy_config);
2016         connman_dbus_dict_append_basic(iter, "Privacy",
2017                                 DBUS_TYPE_STRING, &privacy);
2018 }
2019
2020 void __connman_ipconfig_append_ipv6config(struct connman_ipconfig *ipconfig,
2021                                                         DBusMessageIter *iter)
2022 {
2023         const char *str, *privacy;
2024
2025         str = __connman_ipconfig_method2string(ipconfig->method);
2026         if (!str)
2027                 return;
2028
2029         connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
2030
2031         switch (ipconfig->method) {
2032         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
2033         case CONNMAN_IPCONFIG_METHOD_OFF:
2034         case CONNMAN_IPCONFIG_METHOD_DHCP:
2035                 return;
2036         case CONNMAN_IPCONFIG_METHOD_FIXED:
2037         case CONNMAN_IPCONFIG_METHOD_MANUAL:
2038         case CONNMAN_IPCONFIG_METHOD_AUTO:
2039                 break;
2040         }
2041
2042         if (!ipconfig->address)
2043                 return;
2044
2045         if (ipconfig->address->local) {
2046                 connman_dbus_dict_append_basic(iter, "Address",
2047                                 DBUS_TYPE_STRING, &ipconfig->address->local);
2048                 connman_dbus_dict_append_basic(iter, "PrefixLength",
2049                                                 DBUS_TYPE_BYTE,
2050                                                 &ipconfig->address->prefixlen);
2051         }
2052
2053         if (ipconfig->address->gateway)
2054                 connman_dbus_dict_append_basic(iter, "Gateway",
2055                                 DBUS_TYPE_STRING, &ipconfig->address->gateway);
2056
2057         privacy = privacy2string(ipconfig->ipv6_privacy_config);
2058         connman_dbus_dict_append_basic(iter, "Privacy",
2059                                 DBUS_TYPE_STRING, &privacy);
2060 }
2061
2062 void __connman_ipconfig_append_ipv4config(struct connman_ipconfig *ipconfig,
2063                                                         DBusMessageIter *iter)
2064 {
2065         const char *str;
2066
2067         str = __connman_ipconfig_method2string(ipconfig->method);
2068         if (!str)
2069                 return;
2070
2071         connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
2072
2073         switch (ipconfig->method) {
2074         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
2075         case CONNMAN_IPCONFIG_METHOD_OFF:
2076         case CONNMAN_IPCONFIG_METHOD_DHCP:
2077         case CONNMAN_IPCONFIG_METHOD_AUTO:
2078                 return;
2079         case CONNMAN_IPCONFIG_METHOD_FIXED:
2080         case CONNMAN_IPCONFIG_METHOD_MANUAL:
2081                 break;
2082         }
2083
2084         if (!ipconfig->address)
2085                 return;
2086
2087         if (ipconfig->address->local) {
2088                 in_addr_t addr;
2089                 struct in_addr netmask;
2090                 char *mask;
2091
2092                 connman_dbus_dict_append_basic(iter, "Address",
2093                                 DBUS_TYPE_STRING, &ipconfig->address->local);
2094
2095                 addr = 0xffffffff << (32 - ipconfig->address->prefixlen);
2096                 netmask.s_addr = htonl(addr);
2097                 mask = inet_ntoa(netmask);
2098                 connman_dbus_dict_append_basic(iter, "Netmask",
2099                                                 DBUS_TYPE_STRING, &mask);
2100         }
2101
2102         if (ipconfig->address->gateway)
2103                 connman_dbus_dict_append_basic(iter, "Gateway",
2104                                 DBUS_TYPE_STRING, &ipconfig->address->gateway);
2105 }
2106
2107 int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig,
2108                                                         DBusMessageIter *array)
2109 {
2110         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
2111         const char *address = NULL, *netmask = NULL, *gateway = NULL,
2112                 *privacy_string = NULL;
2113         int prefix_length = 0, privacy = 0;
2114         DBusMessageIter dict;
2115         int type = -1;
2116
2117         if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
2118                 return -EINVAL;
2119
2120         dbus_message_iter_recurse(array, &dict);
2121
2122         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
2123                 DBusMessageIter entry, value;
2124                 const char *key;
2125                 int type;
2126
2127                 dbus_message_iter_recurse(&dict, &entry);
2128
2129                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
2130                         return -EINVAL;
2131
2132                 dbus_message_iter_get_basic(&entry, &key);
2133                 dbus_message_iter_next(&entry);
2134
2135                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
2136                         return -EINVAL;
2137
2138                 dbus_message_iter_recurse(&entry, &value);
2139
2140                 type = dbus_message_iter_get_arg_type(&value);
2141
2142                 if (g_str_equal(key, "Method")) {
2143                         const char *str;
2144
2145                         if (type != DBUS_TYPE_STRING)
2146                                 return -EINVAL;
2147
2148                         dbus_message_iter_get_basic(&value, &str);
2149                         method = __connman_ipconfig_string2method(str);
2150                 } else if (g_str_equal(key, "Address")) {
2151                         if (type != DBUS_TYPE_STRING)
2152                                 return -EINVAL;
2153
2154                         dbus_message_iter_get_basic(&value, &address);
2155                 } else if (g_str_equal(key, "PrefixLength")) {
2156                         if (type != DBUS_TYPE_BYTE)
2157                                 return -EINVAL;
2158
2159                         dbus_message_iter_get_basic(&value, &prefix_length);
2160
2161                         if (prefix_length < 0 || prefix_length > 128)
2162                                 return -EINVAL;
2163                 } else if (g_str_equal(key, "Netmask")) {
2164                         if (type != DBUS_TYPE_STRING)
2165                                 return -EINVAL;
2166
2167                         dbus_message_iter_get_basic(&value, &netmask);
2168                 } else if (g_str_equal(key, "Gateway")) {
2169                         if (type != DBUS_TYPE_STRING)
2170                                 return -EINVAL;
2171
2172                         dbus_message_iter_get_basic(&value, &gateway);
2173                 } else if (g_str_equal(key, "Privacy")) {
2174                         if (type != DBUS_TYPE_STRING)
2175                                 return -EINVAL;
2176
2177                         dbus_message_iter_get_basic(&value, &privacy_string);
2178                         privacy = string2privacy(privacy_string);
2179                 }
2180
2181                 dbus_message_iter_next(&dict);
2182         }
2183
2184         DBG("method %d address %s netmask %s gateway %s prefix_length %d "
2185                 "privacy %s",
2186                 method, address, netmask, gateway, prefix_length,
2187                 privacy_string);
2188
2189         switch (method) {
2190         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
2191         case CONNMAN_IPCONFIG_METHOD_FIXED:
2192                 return -EINVAL;
2193
2194         case CONNMAN_IPCONFIG_METHOD_OFF:
2195                 ipconfig->method = method;
2196 #if defined TIZEN_EXT
2197                 if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
2198                         disable_ipv6(ipconfig);
2199 #endif
2200
2201                 break;
2202
2203         case CONNMAN_IPCONFIG_METHOD_AUTO:
2204                 if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV6)
2205                         return -EOPNOTSUPP;
2206
2207                 ipconfig->method = method;
2208                 if (privacy_string)
2209                         ipconfig->ipv6_privacy_config = privacy;
2210 #if defined TIZEN_EXT
2211                 enable_ipv6(ipconfig);
2212 #endif
2213
2214                 break;
2215
2216         case CONNMAN_IPCONFIG_METHOD_MANUAL:
2217                 switch (ipconfig->type) {
2218                 case CONNMAN_IPCONFIG_TYPE_IPV4:
2219                         type = AF_INET;
2220                         break;
2221                 case CONNMAN_IPCONFIG_TYPE_IPV6:
2222                         type = AF_INET6;
2223                         break;
2224                 case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
2225                 case CONNMAN_IPCONFIG_TYPE_ALL:
2226                         type = -1;
2227                         break;
2228                 }
2229
2230                 if ((address && connman_inet_check_ipaddress(address)
2231                                                 != type) ||
2232                                 (netmask &&
2233                                 connman_inet_check_ipaddress(netmask)
2234                                                 != type) ||
2235                                 (gateway &&
2236                                 connman_inet_check_ipaddress(gateway)
2237                                                 != type))
2238                         return -EINVAL;
2239
2240                 ipconfig->method = method;
2241
2242                 if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4)
2243                         connman_ipaddress_set_ipv4(ipconfig->address,
2244                                                 address, netmask, gateway);
2245                 else
2246                         return connman_ipaddress_set_ipv6(
2247                                         ipconfig->address, address,
2248                                                 prefix_length, gateway);
2249
2250                 break;
2251
2252         case CONNMAN_IPCONFIG_METHOD_DHCP:
2253                 if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV4)
2254                         return -EOPNOTSUPP;
2255
2256                 ipconfig->method = method;
2257                 break;
2258         }
2259
2260         return 0;
2261 }
2262
2263 void __connman_ipconfig_append_ethernet(struct connman_ipconfig *ipconfig,
2264                                                         DBusMessageIter *iter)
2265 {
2266         struct connman_ipdevice *ipdevice;
2267         const char *method = "auto";
2268
2269         connman_dbus_dict_append_basic(iter, "Method",
2270                                                 DBUS_TYPE_STRING, &method);
2271
2272         ipdevice = g_hash_table_lookup(ipdevice_hash,
2273                                         GINT_TO_POINTER(ipconfig->index));
2274         if (!ipdevice)
2275                 return;
2276
2277         if (ipconfig->index >= 0) {
2278                 char *ifname = connman_inet_ifname(ipconfig->index);
2279                 if (ifname) {
2280                         connman_dbus_dict_append_basic(iter, "Interface",
2281                                                 DBUS_TYPE_STRING, &ifname);
2282                         g_free(ifname);
2283                 }
2284         }
2285
2286         if (ipdevice->address)
2287                 connman_dbus_dict_append_basic(iter, "Address",
2288                                         DBUS_TYPE_STRING, &ipdevice->address);
2289
2290         if (ipdevice->mtu > 0)
2291                 connman_dbus_dict_append_basic(iter, "MTU",
2292                                         DBUS_TYPE_UINT16, &ipdevice->mtu);
2293 }
2294
2295 void __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
2296                 GKeyFile *keyfile, const char *identifier, const char *prefix)
2297 {
2298         char *method;
2299         char *str;
2300         struct ipconfig_store is = { .file = keyfile,
2301                                      .group = identifier,
2302                                      .prefix = prefix };
2303
2304         DBG("ipconfig %p identifier %s", ipconfig, identifier);
2305
2306         method = store_get_str(&is, "method");
2307         if (!method) {
2308                 switch (ipconfig->type) {
2309                 case CONNMAN_IPCONFIG_TYPE_IPV4:
2310                         ipconfig->method = CONNMAN_IPCONFIG_METHOD_DHCP;
2311                         break;
2312
2313                 case CONNMAN_IPCONFIG_TYPE_IPV6:
2314                         ipconfig->method = CONNMAN_IPCONFIG_METHOD_AUTO;
2315                         break;
2316
2317                 case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
2318                 case CONNMAN_IPCONFIG_TYPE_ALL:
2319                         ipconfig->method = CONNMAN_IPCONFIG_METHOD_OFF;
2320                         break;
2321                 }
2322         } else {
2323                 ipconfig->method = __connman_ipconfig_string2method(method);
2324                 g_free(method);
2325         }
2326
2327         if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_UNKNOWN)
2328                 ipconfig->method = CONNMAN_IPCONFIG_METHOD_OFF;
2329
2330         if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) {
2331                 if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_AUTO ||
2332                                 ipconfig->method == CONNMAN_IPCONFIG_METHOD_MANUAL) {
2333                         char *privacy;
2334
2335                         privacy = store_get_str(&is, "privacy");
2336                         ipconfig->ipv6_privacy_config = string2privacy(privacy);
2337                         g_free(privacy);
2338                 }
2339
2340                 g_strfreev(ipconfig->last_dhcpv6_prefixes);
2341                 ipconfig->last_dhcpv6_prefixes =
2342                         store_get_strs(&is, "DHCP.LastPrefixes");
2343         }
2344
2345
2346         switch (ipconfig->method) {
2347         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
2348         case CONNMAN_IPCONFIG_METHOD_OFF:
2349                 break;
2350
2351         case CONNMAN_IPCONFIG_METHOD_FIXED:
2352         case CONNMAN_IPCONFIG_METHOD_MANUAL:
2353                 ipconfig->address->prefixlen =
2354                         store_get_int(&is, "netmask_prefixlen");
2355
2356                 g_free(ipconfig->address->local);
2357                 ipconfig->address->local =
2358                         store_get_str(&is, "local_address");
2359
2360                 g_free(ipconfig->address->peer);
2361                 ipconfig->address->peer =
2362                         store_get_str(&is, "peer_address");
2363
2364                 g_free(ipconfig->address->broadcast);
2365                 ipconfig->address->broadcast =
2366                         store_get_str(&is, "broadcast_address");
2367
2368                 g_free(ipconfig->address->gateway);
2369                 ipconfig->address->gateway =
2370                         store_get_str(&is, "gateway");
2371                 break;
2372
2373         case CONNMAN_IPCONFIG_METHOD_AUTO:
2374                 if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV4)
2375                         break;
2376
2377                 /*
2378                  * If the last used method for IPv4 was AUTO then we
2379                  * try first DHCP. We will try also to use the last
2380                  * used DHCP address, if exits.
2381                  */
2382                 __connman_ipconfig_set_method(ipconfig,
2383                                         CONNMAN_IPCONFIG_METHOD_DHCP);
2384                 /* fall through */
2385
2386         case CONNMAN_IPCONFIG_METHOD_DHCP:
2387                 str = store_get_str(&is, "DHCP.LastAddress");
2388                 if (str) {
2389                         g_free(ipconfig->last_dhcp_address);
2390                         ipconfig->last_dhcp_address = str;
2391                 }
2392
2393                 break;
2394         }
2395 }
2396
2397 void __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
2398                 GKeyFile *keyfile, const char *identifier, const char *prefix)
2399 {
2400         const char *method;
2401         struct ipconfig_store is = { .file = keyfile,
2402                                      .group = identifier,
2403                                      .prefix = prefix };
2404
2405         method = __connman_ipconfig_method2string(ipconfig->method);
2406         DBG("ipconfig %p identifier %s method %s", ipconfig, identifier,
2407                                                                 method);
2408         store_set_str(&is, "method", method);
2409
2410         if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) {
2411                 store_set_str(&is, "privacy",
2412                                 privacy2string(ipconfig->ipv6_privacy_config));
2413
2414                 store_set_str(&is, "DHCP.LastAddress",
2415                                 ipconfig->last_dhcp_address);
2416
2417                 store_set_strs(&is, "DHCP.LastPrefixes",
2418                                 ipconfig->last_dhcpv6_prefixes);
2419         }
2420
2421         switch (ipconfig->method) {
2422         case CONNMAN_IPCONFIG_METHOD_FIXED:
2423         case CONNMAN_IPCONFIG_METHOD_MANUAL:
2424                 break;
2425
2426         case CONNMAN_IPCONFIG_METHOD_DHCP:
2427                 store_set_str(&is, "DHCP.LastAddress",
2428                                 ipconfig->last_dhcp_address);
2429                 /* fall through */
2430
2431         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
2432         case CONNMAN_IPCONFIG_METHOD_OFF:
2433         case CONNMAN_IPCONFIG_METHOD_AUTO:
2434                 return;
2435         }
2436
2437         store_set_int(&is, "netmask_prefixlen", ipconfig->address->prefixlen);
2438         store_set_str(&is, "local_address", ipconfig->address->local);
2439         store_set_str(&is, "peer_address", ipconfig->address->peer);
2440         store_set_str(&is, "broadcast_address", ipconfig->address->broadcast);
2441         store_set_str(&is, "gateway", ipconfig->address->gateway);
2442 }
2443
2444 int __connman_ipconfig_init(void)
2445 {
2446         DBG("");
2447
2448         ipdevice_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
2449                                                         NULL, free_ipdevice);
2450
2451         is_ipv6_supported = connman_inet_is_ipv6_supported();
2452
2453         return 0;
2454 }
2455
2456 void __connman_ipconfig_cleanup(void)
2457 {
2458         DBG("");
2459
2460         g_hash_table_destroy(ipdevice_hash);
2461         ipdevice_hash = NULL;
2462 }