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