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