Add inet helper to retrieve current flags
[platform/upstream/connman.git] / src / ipconfig.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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 <net/if.h>
27 #include <net/if_arp.h>
28
29 #ifndef IFF_LOWER_UP
30 #define IFF_LOWER_UP    0x10000
31 #endif
32
33 #include <gdbus.h>
34
35 #include "connman.h"
36
37 struct connman_ipconfig {
38         gint refcount;
39         int index;
40
41         struct connman_ipconfig *origin;
42
43         const struct connman_ipconfig_ops *ops;
44         void *ops_data;
45
46         enum connman_ipconfig_method method;
47         struct connman_ipaddress *address;
48 };
49
50 struct connman_ipdevice {
51         int index;
52         char *ifname;
53         unsigned short type;
54         unsigned int flags;
55
56         GSList *address_list;
57         char *gateway;
58
59         struct connman_ipconfig *config;
60
61         struct connman_ipconfig_driver *driver;
62         struct connman_ipconfig *driver_config;
63 };
64
65 static GHashTable *ipdevice_hash = NULL;
66 static GList *ipconfig_list = NULL;
67
68 struct connman_ipaddress *connman_ipaddress_alloc(void)
69 {
70         struct connman_ipaddress *ipaddress;
71
72         ipaddress = g_try_new0(struct connman_ipaddress, 1);
73         if (ipaddress == NULL)
74                 return NULL;
75
76         return ipaddress;
77 }
78
79 void connman_ipaddress_free(struct connman_ipaddress *ipaddress)
80 {
81         if (ipaddress == NULL)
82                 return;
83
84         g_free(ipaddress->broadcast);
85         g_free(ipaddress->peer);
86         g_free(ipaddress->local);
87         g_free(ipaddress);
88 }
89
90 void connman_ipaddress_copy(struct connman_ipaddress *ipaddress,
91                                         struct connman_ipaddress *source)
92 {
93         if (ipaddress == NULL || source == NULL)
94                 return;
95
96         ipaddress->prefixlen = source->prefixlen;
97
98         g_free(ipaddress->local);
99         ipaddress->local = g_strdup(source->local);
100
101         g_free(ipaddress->peer);
102         ipaddress->peer = g_strdup(source->peer);
103
104         g_free(ipaddress->broadcast);
105         ipaddress->broadcast = g_strdup(source->broadcast);
106 }
107
108 static void free_address_list(struct connman_ipdevice *ipdevice)
109 {
110         GSList *list;
111
112         for (list = ipdevice->address_list; list; list = list->next) {
113                 struct connman_ipaddress *ipaddress = list->data;
114
115                 connman_ipaddress_free(ipaddress);
116                 list->data = NULL;
117         }
118
119         g_slist_free(ipdevice->address_list);
120         ipdevice->address_list = NULL;
121 }
122
123 static struct connman_ipaddress *find_ipaddress(struct connman_ipdevice *ipdevice,
124                                 unsigned char prefixlen, const char *local)
125 {
126         GSList *list;
127
128         for (list = ipdevice->address_list; list; list = list->next) {
129                 struct connman_ipaddress *ipaddress = list->data;
130
131                 if (g_strcmp0(ipaddress->local, local) == 0 &&
132                                         ipaddress->prefixlen == prefixlen)
133                         return ipaddress;
134         }
135
136         return NULL;
137 }
138
139 static const char *type2str(unsigned short type)
140 {
141         switch (type) {
142         case ARPHRD_ETHER:
143                 return "ETHER";
144         case ARPHRD_LOOPBACK:
145                 return "LOOPBACK";
146         case ARPHRD_PPP:
147                 return "PPP";
148         case ARPHRD_NONE:
149                 return "NONE";
150         case ARPHRD_VOID:
151                 return "VOID";
152         }
153
154         return "";
155 }
156
157 static const char *scope2str(unsigned char scope)
158 {
159         switch (scope) {
160         case 0:
161                 return "UNIVERSE";
162         case 253:
163                 return "LINK";
164         }
165
166         return "";
167 }
168
169 static void free_ipdevice(gpointer data)
170 {
171         struct connman_ipdevice *ipdevice = data;
172
173         connman_info("%s {remove} index %d", ipdevice->ifname,
174                                                         ipdevice->index);
175
176         if (ipdevice->config != NULL)
177                 connman_ipconfig_unref(ipdevice->config);
178
179         free_address_list(ipdevice);
180         g_free(ipdevice->gateway);
181
182         g_free(ipdevice->ifname);
183         g_free(ipdevice);
184 }
185
186 static GSList *driver_list = NULL;
187
188 static gint compare_priority(gconstpointer a, gconstpointer b)
189 {
190         const struct connman_ipconfig_driver *driver1 = a;
191         const struct connman_ipconfig_driver *driver2 = b;
192
193         return driver2->priority - driver1->priority;
194 }
195
196 /**
197  * connman_ipconfig_driver_register:
198  * @driver: IP configuration driver
199  *
200  * Register a new IP configuration driver
201  *
202  * Returns: %0 on success
203  */
204 int connman_ipconfig_driver_register(struct connman_ipconfig_driver *driver)
205 {
206         DBG("driver %p name %s", driver, driver->name);
207
208         driver_list = g_slist_insert_sorted(driver_list, driver,
209                                                         compare_priority);
210
211         return 0;
212 }
213
214 /**
215  * connman_ipconfig_driver_unregister:
216  * @driver: IP configuration driver
217  *
218  * Remove a previously registered IP configuration driver.
219  */
220 void connman_ipconfig_driver_unregister(struct connman_ipconfig_driver *driver)
221 {
222         DBG("driver %p name %s", driver, driver->name);
223
224         driver_list = g_slist_remove(driver_list, driver);
225 }
226
227 static void __connman_ipconfig_lower_up(struct connman_ipdevice *ipdevice)
228 {
229         GSList *list;
230
231         DBG("ipconfig %p", ipdevice->config);
232
233         if (ipdevice->config == NULL)
234                 return;
235
236         switch (ipdevice->config->method) {
237         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
238         case CONNMAN_IPCONFIG_METHOD_IGNORE:
239         case CONNMAN_IPCONFIG_METHOD_STATIC:
240                 return;
241         case CONNMAN_IPCONFIG_METHOD_DHCP:
242                 break;
243         }
244
245         if (ipdevice->driver != NULL)
246                 return;
247
248         ipdevice->driver_config = connman_ipconfig_clone(ipdevice->config);
249         if (ipdevice->driver_config == NULL)
250                 return;
251
252         for (list = driver_list; list; list = list->next) {
253                 struct connman_ipconfig_driver *driver = list->data;
254
255                 if (driver->request(ipdevice->driver_config) == 0) {
256                         ipdevice->driver = driver;
257                         break;
258                 }
259         }
260
261         if (ipdevice->driver == NULL) {
262                 connman_ipconfig_unref(ipdevice->driver_config);
263                 ipdevice->driver_config = NULL;
264         }
265 }
266
267 static void __connman_ipconfig_lower_down(struct connman_ipdevice *ipdevice)
268 {
269         DBG("ipconfig %p", ipdevice->config);
270
271         if (ipdevice->config == NULL)
272                 return;
273
274         if (ipdevice->driver == NULL)
275                 return;
276
277         ipdevice->driver->release(ipdevice->driver_config);
278
279         ipdevice->driver = NULL;
280
281         connman_ipconfig_unref(ipdevice->driver_config);
282         ipdevice->driver_config = NULL;
283
284         connman_inet_clear_address(ipdevice->index);
285 }
286
287 void __connman_ipconfig_newlink(int index, unsigned short type,
288                                                         unsigned int flags)
289 {
290         struct connman_ipdevice *ipdevice;
291         GList *list;
292         GString *str;
293         gboolean up = FALSE, down = FALSE;
294         gboolean lower_up = FALSE, lower_down = FALSE;
295
296         DBG("index %d", index);
297
298         if (type == ARPHRD_LOOPBACK)
299                 return;
300
301         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
302         if (ipdevice != NULL)
303                 goto update;
304
305         ipdevice = g_try_new0(struct connman_ipdevice, 1);
306         if (ipdevice == NULL)
307                 return;
308
309         ipdevice->index = index;
310         ipdevice->ifname = connman_inet_ifname(index);
311         ipdevice->type = type;
312
313         g_hash_table_insert(ipdevice_hash, GINT_TO_POINTER(index), ipdevice);
314
315         connman_info("%s {create} index %d type %d <%s>", ipdevice->ifname,
316                                                 index, type, type2str(type));
317
318 update:
319         if (flags == ipdevice->flags)
320                 return;
321
322         if ((ipdevice->flags & IFF_UP) != (flags & IFF_UP)) {
323                 if (flags & IFF_UP)
324                         up = TRUE;
325                 else
326                         down = TRUE;
327         }
328
329         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) !=
330                                 (flags & (IFF_RUNNING | IFF_LOWER_UP))) {
331                 if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) ==
332                                         (IFF_RUNNING | IFF_LOWER_UP))
333                         lower_up = TRUE;
334                 else if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) == 0)
335                         lower_down = TRUE;
336         }
337
338         connman_inet_clear_address(index);
339
340         ipdevice->flags = flags;
341
342         str = g_string_new(NULL);
343         if (str == NULL)
344                 return;
345
346         if (flags & IFF_UP)
347                 g_string_append(str, "UP");
348         else
349                 g_string_append(str, "DOWN");
350
351         if (flags & IFF_RUNNING)
352                 g_string_append(str, ",RUNNING");
353
354         if (flags & IFF_LOWER_UP)
355                 g_string_append(str, ",LOWER_UP");
356
357         connman_info("%s {update} flags %u <%s>", ipdevice->ifname,
358                                                         flags, str->str);
359
360         g_string_free(str, TRUE);
361
362         for (list = g_list_first(ipconfig_list); list;
363                                                 list = g_list_next(list)) {
364                 struct connman_ipconfig *ipconfig = list->data;
365
366                 if (index != ipconfig->index)
367                         continue;
368
369                 if (up == TRUE && ipconfig->ops->up)
370                         ipconfig->ops->up(ipconfig);
371                 if (lower_up == TRUE && ipconfig->ops->lower_up)
372                         ipconfig->ops->lower_up(ipconfig);
373
374                 if (lower_down == TRUE && ipconfig->ops->lower_down)
375                         ipconfig->ops->lower_down(ipconfig);
376                 if (down == TRUE && ipconfig->ops->down)
377                         ipconfig->ops->down(ipconfig);
378         }
379
380         if (lower_up)
381                 __connman_ipconfig_lower_up(ipdevice);
382         if (lower_down)
383                 __connman_ipconfig_lower_down(ipdevice);
384 }
385
386 void __connman_ipconfig_dellink(int index)
387 {
388         struct connman_ipdevice *ipdevice;
389         GList *list;
390
391         DBG("index %d", index);
392
393         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
394         if (ipdevice == NULL)
395                 return;
396
397         for (list = g_list_first(ipconfig_list); list;
398                                                 list = g_list_next(list)) {
399                 struct connman_ipconfig *ipconfig = list->data;
400
401                 if (index != ipconfig->index)
402                         continue;
403
404                 ipconfig->index = -1;
405
406                 if (ipconfig->ops->lower_down)
407                         ipconfig->ops->lower_down(ipconfig);
408                 if (ipconfig->ops->down)
409                         ipconfig->ops->down(ipconfig);
410         }
411
412         __connman_ipconfig_lower_down(ipdevice);
413
414         g_hash_table_remove(ipdevice_hash, GINT_TO_POINTER(index));
415 }
416
417 void __connman_ipconfig_newaddr(int index, const char *label,
418                                 unsigned char prefixlen, const char *address)
419 {
420         struct connman_ipdevice *ipdevice;
421         struct connman_ipaddress *ipaddress;
422         GList *list;
423
424         DBG("index %d", index);
425
426         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
427         if (ipdevice == NULL)
428                 return;
429
430         ipaddress = connman_ipaddress_alloc();
431         if (ipaddress == NULL)
432                 return;
433
434         ipaddress->prefixlen = prefixlen;
435         ipaddress->local = g_strdup(address);
436
437         ipdevice->address_list = g_slist_append(ipdevice->address_list,
438                                                                 ipaddress);
439
440         connman_info("%s {add} address %s/%u label %s", ipdevice->ifname,
441                                                 address, prefixlen, label);
442
443         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
444                 return;
445
446         if (g_slist_length(ipdevice->address_list) > 1)
447                 return;
448
449         for (list = g_list_first(ipconfig_list); list;
450                                                 list = g_list_next(list)) {
451                 struct connman_ipconfig *ipconfig = list->data;
452
453                 if (index != ipconfig->index)
454                         continue;
455
456                 if (ipconfig->ops->ip_bound)
457                         ipconfig->ops->ip_bound(ipconfig);
458         }
459 }
460
461 void __connman_ipconfig_deladdr(int index, const char *label,
462                                 unsigned char prefixlen, const char *address)
463 {
464         struct connman_ipdevice *ipdevice;
465         struct connman_ipaddress *ipaddress;
466         GList *list;
467
468         DBG("index %d", index);
469
470         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
471         if (ipdevice == NULL)
472                 return;
473
474         ipaddress = find_ipaddress(ipdevice, prefixlen, address);
475         if (ipaddress == NULL)
476                 return;
477
478         ipdevice->address_list = g_slist_remove(ipdevice->address_list,
479                                                                 ipaddress);
480
481         connman_ipaddress_free(ipaddress);
482
483         connman_info("%s {del} address %s/%u label %s", ipdevice->ifname,
484                                                 address, prefixlen, label);
485
486         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
487                 return;
488
489         if (g_slist_length(ipdevice->address_list) > 0)
490                 return;
491
492         for (list = g_list_first(ipconfig_list); list;
493                                                 list = g_list_next(list)) {
494                 struct connman_ipconfig *ipconfig = list->data;
495
496                 if (index != ipconfig->index)
497                         continue;
498
499                 if (ipconfig->ops->ip_release)
500                         ipconfig->ops->ip_release(ipconfig);
501         }
502 }
503
504 void __connman_ipconfig_newroute(int index, unsigned char scope,
505                                         const char *dst, const char *gateway)
506 {
507         struct connman_ipdevice *ipdevice;
508
509         DBG("index %d", index);
510
511         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
512         if (ipdevice == NULL)
513                 return;
514
515         if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
516                 g_free(ipdevice->gateway);
517                 ipdevice->gateway = g_strdup(gateway);
518         }
519
520         connman_info("%s {add} route %s gw %s scope %u <%s>",
521                                         ipdevice->ifname, dst, gateway,
522                                                 scope, scope2str(scope));
523 }
524
525 void __connman_ipconfig_delroute(int index, unsigned char scope,
526                                         const char *dst, const char *gateway)
527 {
528         struct connman_ipdevice *ipdevice;
529
530         DBG("index %d", index);
531
532         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
533         if (ipdevice == NULL)
534                 return;
535
536         if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
537                 g_free(ipdevice->gateway);
538                 ipdevice->gateway = NULL;
539         }
540
541         connman_info("%s {del} route %s gw %s scope %u <%s>",
542                                         ipdevice->ifname, dst, gateway,
543                                                 scope, scope2str(scope));
544 }
545
546 void __connman_ipconfig_foreach(void (*function) (int index, void *user_data),
547                                                         void *user_data)
548 {
549         GList *list, *keys;
550
551         keys = g_hash_table_get_keys(ipdevice_hash);
552         if (keys == NULL)
553                 return;
554
555         for (list = g_list_first(keys); list; list = g_list_next(list)) {
556                 int index = GPOINTER_TO_INT(list->data);
557
558                 function(index, user_data);
559         }
560
561         g_list_free(keys);
562 }
563
564 unsigned short __connman_ipconfig_get_type(int index)
565 {
566         struct connman_ipdevice *ipdevice;
567
568         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
569         if (ipdevice == NULL)
570                 return ARPHRD_VOID;
571
572         return ipdevice->type;
573 }
574
575 unsigned int __connman_ipconfig_get_flags(int index)
576 {
577         struct connman_ipdevice *ipdevice;
578
579         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
580         if (ipdevice == NULL)
581                 return 0;
582
583         return ipdevice->flags;
584 }
585
586 const char *__connman_ipconfig_get_gateway(int index)
587 {
588         struct connman_ipdevice *ipdevice;
589
590         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
591         if (ipdevice == NULL)
592                 return NULL;
593
594         return ipdevice->gateway;
595 }
596
597 /**
598  * connman_ipconfig_create:
599  *
600  * Allocate a new ipconfig structure.
601  *
602  * Returns: a newly-allocated #connman_ipconfig structure
603  */
604 struct connman_ipconfig *connman_ipconfig_create(int index)
605 {
606         struct connman_ipconfig *ipconfig;
607
608         DBG("index %d", index);
609
610         ipconfig = g_try_new0(struct connman_ipconfig, 1);
611         if (ipconfig == NULL)
612                 return NULL;
613
614         ipconfig->refcount = 1;
615
616         ipconfig->index = index;
617
618         ipconfig->address = connman_ipaddress_alloc();
619         if (ipconfig->address == NULL) {
620                 g_free(ipconfig);
621                 return NULL;
622         }
623
624         DBG("ipconfig %p", ipconfig);
625
626         return ipconfig;
627 }
628
629 /**
630  * connman_ipconfig_clone:
631  *
632  * Clone an ipconfig structure and create new reference.
633  *
634  * Returns: a newly-allocated #connman_ipconfig structure
635  */
636 struct connman_ipconfig *connman_ipconfig_clone(struct connman_ipconfig *ipconfig)
637 {
638         struct connman_ipconfig *ipconfig_clone;
639
640         DBG("ipconfig %p", ipconfig);
641
642         ipconfig_clone = g_try_new0(struct connman_ipconfig, 1);
643         if (ipconfig_clone == NULL)
644                 return NULL;
645
646         ipconfig_clone->refcount = 1;
647
648         ipconfig_clone->origin = connman_ipconfig_ref(ipconfig);
649
650         ipconfig_clone->index = -1;
651
652         return ipconfig_clone;
653 }
654
655 /**
656  * connman_ipconfig_ref:
657  * @ipconfig: ipconfig structure
658  *
659  * Increase reference counter of ipconfig
660  */
661 struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig)
662 {
663         g_atomic_int_inc(&ipconfig->refcount);
664
665         return ipconfig;
666 }
667
668 /**
669  * connman_ipconfig_unref:
670  * @ipconfig: ipconfig structure
671  *
672  * Decrease reference counter of ipconfig
673  */
674 void connman_ipconfig_unref(struct connman_ipconfig *ipconfig)
675 {
676         if (g_atomic_int_dec_and_test(&ipconfig->refcount) == TRUE) {
677                 connman_ipconfig_set_ops(ipconfig, NULL);
678
679                 if (ipconfig->origin != NULL) {
680                         connman_ipconfig_unref(ipconfig->origin);
681                         ipconfig->origin = NULL;
682                 }
683
684                 connman_ipaddress_free(ipconfig->address);
685                 g_free(ipconfig);
686         }
687 }
688
689 /**
690  * connman_ipconfig_get_data:
691  * @ipconfig: ipconfig structure
692  *
693  * Get private data pointer
694  */
695 void *connman_ipconfig_get_data(struct connman_ipconfig *ipconfig)
696 {
697         return ipconfig->ops_data;
698 }
699
700 /**
701  * connman_ipconfig_set_data:
702  * @ipconfig: ipconfig structure
703  * @data: data pointer
704  *
705  * Set private data pointer
706  */
707 void connman_ipconfig_set_data(struct connman_ipconfig *ipconfig, void *data)
708 {
709         ipconfig->ops_data = data;
710 }
711
712 /**
713  * connman_ipconfig_get_index:
714  * @ipconfig: ipconfig structure
715  *
716  * Get interface index
717  */
718 int connman_ipconfig_get_index(struct connman_ipconfig *ipconfig)
719 {
720         if (ipconfig->origin != NULL)
721                 return ipconfig->origin->index;
722
723         return ipconfig->index;
724 }
725
726 /**
727  * connman_ipconfig_get_ifname:
728  * @ipconfig: ipconfig structure
729  *
730  * Get interface name
731  */
732 const char *connman_ipconfig_get_ifname(struct connman_ipconfig *ipconfig)
733 {
734         struct connman_ipdevice *ipdevice;
735
736         if (ipconfig->index < 0)
737                 return NULL;
738
739         ipdevice = g_hash_table_lookup(ipdevice_hash,
740                                         GINT_TO_POINTER(ipconfig->index));
741         if (ipdevice == NULL)
742                 return NULL;
743
744         return ipdevice->ifname;
745 }
746
747 /**
748  * connman_ipconfig_set_ops:
749  * @ipconfig: ipconfig structure
750  * @ops: operation callbacks
751  *
752  * Set the operation callbacks
753  */
754 void connman_ipconfig_set_ops(struct connman_ipconfig *ipconfig,
755                                 const struct connman_ipconfig_ops *ops)
756 {
757         if (ipconfig->ops != NULL)
758                 ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
759
760         ipconfig->ops = ops;
761
762         if (ops != NULL)
763                 ipconfig_list = g_list_append(ipconfig_list, ipconfig);
764 }
765
766 /**
767  * connman_ipconfig_set_method:
768  * @ipconfig: ipconfig structure
769  * @method: configuration method
770  *
771  * Set the configuration method
772  */
773 int connman_ipconfig_set_method(struct connman_ipconfig *ipconfig,
774                                         enum connman_ipconfig_method method)
775 {
776         ipconfig->method = method;
777
778         return 0;
779 }
780
781 /**
782  * connman_ipconfig_bind:
783  * @ipconfig: ipconfig structure
784  * @ipaddress: ipaddress structure
785  *
786  * Bind IP address details to configuration
787  */
788 void connman_ipconfig_bind(struct connman_ipconfig *ipconfig,
789                                         struct connman_ipaddress *ipaddress)
790 {
791         struct connman_ipconfig *origin;
792
793         origin = ipconfig->origin ? ipconfig->origin : ipconfig;
794
795         connman_ipaddress_copy(origin->address, ipaddress);
796
797         connman_inet_set_address(origin->index, origin->address);
798 }
799
800 int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
801 {
802         struct connman_ipdevice *ipdevice;
803
804         DBG("ipconfig %p", ipconfig);
805
806         if (ipconfig == NULL || ipconfig->index < 0)
807                 return -ENODEV;
808
809         ipdevice = g_hash_table_lookup(ipdevice_hash,
810                                         GINT_TO_POINTER(ipconfig->index));
811         if (ipdevice == NULL)
812                 return -ENXIO;
813
814         if (ipdevice->config != NULL)
815                 connman_ipconfig_unref(ipdevice->config);
816
817         ipdevice->config = connman_ipconfig_ref(ipconfig);
818
819         return 0;
820 }
821
822 int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
823 {
824         struct connman_ipdevice *ipdevice;
825
826         DBG("ipconfig %p", ipconfig);
827
828         if (ipconfig == NULL || ipconfig->index < 0)
829                 return -ENODEV;
830
831         ipdevice = g_hash_table_lookup(ipdevice_hash,
832                                         GINT_TO_POINTER(ipconfig->index));
833         if (ipdevice == NULL)
834                 return -ENXIO;
835
836         if (ipdevice->config == NULL || ipdevice->config != ipconfig)
837                 return -EINVAL;
838
839         connman_ipconfig_unref(ipdevice->config);
840         ipdevice->config = NULL;
841
842         return 0;
843 }
844
845 const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method)
846 {
847         switch (method) {
848         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
849                 break;
850         case CONNMAN_IPCONFIG_METHOD_IGNORE:
851                 return "ignore";
852         case CONNMAN_IPCONFIG_METHOD_STATIC:
853                 return "static";
854         case CONNMAN_IPCONFIG_METHOD_DHCP:
855                 return "dhcp";
856         }
857
858         return NULL;
859 }
860
861 enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method)
862 {
863         if (g_strcmp0(method, "ignore") == 0)
864                 return CONNMAN_IPCONFIG_METHOD_IGNORE;
865         else if (g_strcmp0(method, "static") == 0)
866                 return CONNMAN_IPCONFIG_METHOD_STATIC;
867         else if (g_strcmp0(method, "dhcp") == 0)
868                 return CONNMAN_IPCONFIG_METHOD_DHCP;
869         else
870                 return CONNMAN_IPCONFIG_METHOD_UNKNOWN;
871 }
872
873 static void append_variant(DBusMessageIter *iter, const char *prefix,
874                                         const char *key, int type, void *val)
875 {
876         char *str;
877
878         if (prefix == NULL) {
879                 connman_dbus_dict_append_variant(iter, key, type, val);
880                 return;
881         }
882
883         str = g_strdup_printf("%s%s", prefix, key);
884         if (str != NULL)
885                 connman_dbus_dict_append_variant(iter, str, type, val);
886
887         g_free(str);
888 }
889
890 void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
891                                 DBusMessageIter *iter, const char *prefix)
892 {
893         const char *str;
894
895         str = __connman_ipconfig_method2string(ipconfig->method);
896         if (str == NULL)
897                 return;
898
899         append_variant(iter, prefix, "Method", DBUS_TYPE_STRING, &str);
900 }
901
902 int __connman_ipconfig_set_ipv4(struct connman_ipconfig *ipconfig,
903                                 const char *key, DBusMessageIter *value)
904 {
905         int type = dbus_message_iter_get_arg_type(value);
906
907         DBG("ipconfig %p key %s type %d", ipconfig, key, type);
908
909         if (g_strcmp0(key, "Method") == 0) {
910                 const char *method;
911
912                 if (type != DBUS_TYPE_STRING)
913                         return -EINVAL;
914
915                 dbus_message_iter_get_basic(value, &method);
916
917                 ipconfig->method = __connman_ipconfig_string2method(method);
918         } else
919                 return -EINVAL;
920
921         return 0;
922 }
923
924 int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
925                 GKeyFile *keyfile, const char *identifier, const char *prefix)
926 {
927         DBG("ipconfig %p identifier %s", ipconfig, identifier);
928
929         return 0;
930 }
931
932 int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
933                 GKeyFile *keyfile, const char *identifier, const char *prefix)
934 {
935         DBG("ipconfig %p identifier %s", ipconfig, identifier);
936
937         return 0;
938 }
939
940 int __connman_ipconfig_init(void)
941 {
942         DBG("");
943
944         ipdevice_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
945                                                         NULL, free_ipdevice);
946
947         return 0;
948 }
949
950 void __connman_ipconfig_cleanup(void)
951 {
952         DBG("");
953
954         g_hash_table_destroy(ipdevice_hash);
955         ipdevice_hash = NULL;
956 }