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