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