Add support for cloning IP configurations
[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         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
299         if (ipdevice != NULL)
300                 goto update;
301
302         ipdevice = g_try_new0(struct connman_ipdevice, 1);
303         if (ipdevice == NULL)
304                 return;
305
306         ipdevice->index = index;
307         ipdevice->ifname = connman_inet_ifname(index);
308         ipdevice->type = type;
309
310         g_hash_table_insert(ipdevice_hash, GINT_TO_POINTER(index), ipdevice);
311
312         connman_info("%s {create} index %d type %d <%s>", ipdevice->ifname,
313                                                 index, type, type2str(type));
314
315 update:
316         if (flags == ipdevice->flags)
317                 return;
318
319         if ((ipdevice->flags & IFF_UP) != (flags & IFF_UP)) {
320                 if (flags & IFF_UP)
321                         up = TRUE;
322                 else
323                         down = TRUE;
324         }
325
326         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) !=
327                                 (flags & (IFF_RUNNING | IFF_LOWER_UP))) {
328                 if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) ==
329                                         (IFF_RUNNING | IFF_LOWER_UP))
330                         lower_up = TRUE;
331                 else if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) == 0)
332                         lower_down = TRUE;
333         }
334
335         connman_inet_clear_address(index);
336
337         ipdevice->flags = flags;
338
339         str = g_string_new(NULL);
340         if (str == NULL)
341                 return;
342
343         if (flags & IFF_UP)
344                 g_string_append(str, "UP");
345         else
346                 g_string_append(str, "DOWN");
347
348         if (flags & IFF_RUNNING)
349                 g_string_append(str, ",RUNNING");
350
351         if (flags & IFF_LOWER_UP)
352                 g_string_append(str, ",LOWER_UP");
353
354         connman_info("%s {update} flags %u <%s>", ipdevice->ifname,
355                                                         flags, str->str);
356
357         g_string_free(str, TRUE);
358
359         for (list = g_list_first(ipconfig_list); list;
360                                                 list = g_list_next(list)) {
361                 struct connman_ipconfig *ipconfig = list->data;
362
363                 if (index != ipconfig->index)
364                         continue;
365
366                 if (up == TRUE && ipconfig->ops->up)
367                         ipconfig->ops->up(ipconfig);
368                 if (lower_up == TRUE && ipconfig->ops->lower_up)
369                         ipconfig->ops->lower_up(ipconfig);
370
371                 if (lower_down == TRUE && ipconfig->ops->lower_down)
372                         ipconfig->ops->lower_down(ipconfig);
373                 if (down == TRUE && ipconfig->ops->down)
374                         ipconfig->ops->down(ipconfig);
375         }
376
377         if (lower_up)
378                 __connman_ipconfig_lower_up(ipdevice);
379         if (lower_down)
380                 __connman_ipconfig_lower_down(ipdevice);
381 }
382
383 void __connman_ipconfig_dellink(int index)
384 {
385         struct connman_ipdevice *ipdevice;
386         GList *list;
387
388         DBG("index %d", index);
389
390         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
391         if (ipdevice == NULL)
392                 return;
393
394         for (list = g_list_first(ipconfig_list); list;
395                                                 list = g_list_next(list)) {
396                 struct connman_ipconfig *ipconfig = list->data;
397
398                 if (index != ipconfig->index)
399                         continue;
400
401                 ipconfig->index = -1;
402
403                 if (ipconfig->ops->lower_down)
404                         ipconfig->ops->lower_down(ipconfig);
405                 if (ipconfig->ops->down)
406                         ipconfig->ops->down(ipconfig);
407         }
408
409         __connman_ipconfig_lower_down(ipdevice);
410
411         g_hash_table_remove(ipdevice_hash, GINT_TO_POINTER(index));
412 }
413
414 void __connman_ipconfig_newaddr(int index, const char *label,
415                                 unsigned char prefixlen, const char *address)
416 {
417         struct connman_ipdevice *ipdevice;
418         struct connman_ipaddress *ipaddress;
419         GList *list;
420
421         DBG("index %d", index);
422
423         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
424         if (ipdevice == NULL)
425                 return;
426
427         ipaddress = connman_ipaddress_alloc();
428         if (ipaddress == NULL)
429                 return;
430
431         ipaddress->prefixlen = prefixlen;
432         ipaddress->local = g_strdup(address);
433
434         ipdevice->address_list = g_slist_append(ipdevice->address_list,
435                                                                 ipaddress);
436
437         connman_info("%s {add} address %s/%u label %s", ipdevice->ifname,
438                                                 address, prefixlen, label);
439
440         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
441                 return;
442
443         if (g_slist_length(ipdevice->address_list) > 1)
444                 return;
445
446         for (list = g_list_first(ipconfig_list); list;
447                                                 list = g_list_next(list)) {
448                 struct connman_ipconfig *ipconfig = list->data;
449
450                 if (index != ipconfig->index)
451                         continue;
452
453                 if (ipconfig->ops->ip_bound)
454                         ipconfig->ops->ip_bound(ipconfig);
455         }
456 }
457
458 void __connman_ipconfig_deladdr(int index, const char *label,
459                                 unsigned char prefixlen, const char *address)
460 {
461         struct connman_ipdevice *ipdevice;
462         struct connman_ipaddress *ipaddress;
463         GList *list;
464
465         DBG("index %d", index);
466
467         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
468         if (ipdevice == NULL)
469                 return;
470
471         ipaddress = find_ipaddress(ipdevice, prefixlen, address);
472         if (ipaddress == NULL)
473                 return;
474
475         ipdevice->address_list = g_slist_remove(ipdevice->address_list,
476                                                                 ipaddress);
477
478         connman_ipaddress_free(ipaddress);
479
480         connman_info("%s {del} address %s/%u label %s", ipdevice->ifname,
481                                                 address, prefixlen, label);
482
483         if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
484                 return;
485
486         if (g_slist_length(ipdevice->address_list) > 0)
487                 return;
488
489         for (list = g_list_first(ipconfig_list); list;
490                                                 list = g_list_next(list)) {
491                 struct connman_ipconfig *ipconfig = list->data;
492
493                 if (index != ipconfig->index)
494                         continue;
495
496                 if (ipconfig->ops->ip_release)
497                         ipconfig->ops->ip_release(ipconfig);
498         }
499 }
500
501 void __connman_ipconfig_newroute(int index, unsigned char scope,
502                                         const char *dst, const char *gateway)
503 {
504         struct connman_ipdevice *ipdevice;
505
506         DBG("index %d", index);
507
508         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
509         if (ipdevice == NULL)
510                 return;
511
512         if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
513                 g_free(ipdevice->gateway);
514                 ipdevice->gateway = g_strdup(gateway);
515         }
516
517         connman_info("%s {add} route %s gw %s scope %u <%s>",
518                                         ipdevice->ifname, dst, gateway,
519                                                 scope, scope2str(scope));
520 }
521
522 void __connman_ipconfig_delroute(int index, unsigned char scope,
523                                         const char *dst, const char *gateway)
524 {
525         struct connman_ipdevice *ipdevice;
526
527         DBG("index %d", index);
528
529         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
530         if (ipdevice == NULL)
531                 return;
532
533         if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
534                 g_free(ipdevice->gateway);
535                 ipdevice->gateway = NULL;
536         }
537
538         connman_info("%s {del} route %s gw %s scope %u <%s>",
539                                         ipdevice->ifname, dst, gateway,
540                                                 scope, scope2str(scope));
541 }
542
543 void __connman_ipconfig_foreach(void (*function) (int index, void *user_data),
544                                                         void *user_data)
545 {
546         GList *list, *keys;
547
548         keys = g_hash_table_get_keys(ipdevice_hash);
549         if (keys == NULL)
550                 return;
551
552         for (list = g_list_first(keys); list; list = g_list_next(list)) {
553                 int index = GPOINTER_TO_INT(list->data);
554
555                 function(index, user_data);
556         }
557
558         g_list_free(keys);
559 }
560
561 unsigned short __connman_ipconfig_get_type(int index)
562 {
563         struct connman_ipdevice *ipdevice;
564
565         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
566         if (ipdevice == NULL)
567                 return ARPHRD_VOID;
568
569         return ipdevice->type;
570 }
571
572 unsigned int __connman_ipconfig_get_flags(int index)
573 {
574         struct connman_ipdevice *ipdevice;
575
576         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
577         if (ipdevice == NULL)
578                 return 0;
579
580         return ipdevice->flags;
581 }
582
583 const char *__connman_ipconfig_get_gateway(int index)
584 {
585         struct connman_ipdevice *ipdevice;
586
587         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
588         if (ipdevice == NULL)
589                 return NULL;
590
591         return ipdevice->gateway;
592 }
593
594 /**
595  * connman_ipconfig_create:
596  *
597  * Allocate a new ipconfig structure.
598  *
599  * Returns: a newly-allocated #connman_ipconfig structure
600  */
601 struct connman_ipconfig *connman_ipconfig_create(int index)
602 {
603         struct connman_ipconfig *ipconfig;
604
605         DBG("index %d", index);
606
607         ipconfig = g_try_new0(struct connman_ipconfig, 1);
608         if (ipconfig == NULL)
609                 return NULL;
610
611         ipconfig->refcount = 1;
612
613         ipconfig->index = index;
614
615         ipconfig->address = connman_ipaddress_alloc();
616         if (ipconfig->address == NULL) {
617                 g_free(ipconfig);
618                 return NULL;
619         }
620
621         DBG("ipconfig %p", ipconfig);
622
623         return ipconfig;
624 }
625
626 /**
627  * connman_ipconfig_clone:
628  *
629  * Clone an ipconfig structure and create new reference.
630  *
631  * Returns: a newly-allocated #connman_ipconfig structure
632  */
633 struct connman_ipconfig *connman_ipconfig_clone(struct connman_ipconfig *ipconfig)
634 {
635         struct connman_ipconfig *ipconfig_clone;
636
637         DBG("ipconfig %p", ipconfig);
638
639         ipconfig_clone = g_try_new0(struct connman_ipconfig, 1);
640         if (ipconfig_clone == NULL)
641                 return NULL;
642
643         ipconfig_clone->refcount = 1;
644
645         ipconfig_clone->origin = connman_ipconfig_ref(ipconfig);
646
647         ipconfig_clone->index = -1;
648
649         return ipconfig_clone;
650 }
651
652 /**
653  * connman_ipconfig_ref:
654  * @ipconfig: ipconfig structure
655  *
656  * Increase reference counter of ipconfig
657  */
658 struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig)
659 {
660         g_atomic_int_inc(&ipconfig->refcount);
661
662         return ipconfig;
663 }
664
665 /**
666  * connman_ipconfig_unref:
667  * @ipconfig: ipconfig structure
668  *
669  * Decrease reference counter of ipconfig
670  */
671 void connman_ipconfig_unref(struct connman_ipconfig *ipconfig)
672 {
673         if (g_atomic_int_dec_and_test(&ipconfig->refcount) == TRUE) {
674                 connman_ipconfig_set_ops(ipconfig, NULL);
675
676                 if (ipconfig->origin != NULL) {
677                         connman_ipconfig_unref(ipconfig->origin);
678                         ipconfig->origin = NULL;
679                 }
680
681                 connman_ipaddress_free(ipconfig->address);
682                 g_free(ipconfig);
683         }
684 }
685
686 /**
687  * connman_ipconfig_get_data:
688  * @ipconfig: ipconfig structure
689  *
690  * Get private data pointer
691  */
692 void *connman_ipconfig_get_data(struct connman_ipconfig *ipconfig)
693 {
694         return ipconfig->ops_data;
695 }
696
697 /**
698  * connman_ipconfig_set_data:
699  * @ipconfig: ipconfig structure
700  * @data: data pointer
701  *
702  * Set private data pointer
703  */
704 void connman_ipconfig_set_data(struct connman_ipconfig *ipconfig, void *data)
705 {
706         ipconfig->ops_data = data;
707 }
708
709 /**
710  * connman_ipconfig_get_index:
711  * @ipconfig: ipconfig structure
712  *
713  * Get interface index
714  */
715 int connman_ipconfig_get_index(struct connman_ipconfig *ipconfig)
716 {
717         if (ipconfig->origin != NULL)
718                 return ipconfig->origin->index;
719
720         return ipconfig->index;
721 }
722
723 /**
724  * connman_ipconfig_get_ifname:
725  * @ipconfig: ipconfig structure
726  *
727  * Get interface name
728  */
729 const char *connman_ipconfig_get_ifname(struct connman_ipconfig *ipconfig)
730 {
731         struct connman_ipdevice *ipdevice;
732
733         if (ipconfig->index < 0)
734                 return NULL;
735
736         ipdevice = g_hash_table_lookup(ipdevice_hash,
737                                         GINT_TO_POINTER(ipconfig->index));
738         if (ipdevice == NULL)
739                 return NULL;
740
741         return ipdevice->ifname;
742 }
743
744 /**
745  * connman_ipconfig_set_ops:
746  * @ipconfig: ipconfig structure
747  * @ops: operation callbacks
748  *
749  * Set the operation callbacks
750  */
751 void connman_ipconfig_set_ops(struct connman_ipconfig *ipconfig,
752                                 const struct connman_ipconfig_ops *ops)
753 {
754         if (ipconfig->ops != NULL)
755                 ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
756
757         ipconfig->ops = ops;
758
759         if (ops != NULL)
760                 ipconfig_list = g_list_append(ipconfig_list, ipconfig);
761 }
762
763 /**
764  * connman_ipconfig_set_method:
765  * @ipconfig: ipconfig structure
766  * @method: configuration method
767  *
768  * Set the configuration method
769  */
770 int connman_ipconfig_set_method(struct connman_ipconfig *ipconfig,
771                                         enum connman_ipconfig_method method)
772 {
773         ipconfig->method = method;
774
775         return 0;
776 }
777
778 /**
779  * connman_ipconfig_bind:
780  * @ipconfig: ipconfig structure
781  * @ipaddress: ipaddress structure
782  *
783  * Bind IP address details to configuration
784  */
785 void connman_ipconfig_bind(struct connman_ipconfig *ipconfig,
786                                         struct connman_ipaddress *ipaddress)
787 {
788         struct connman_ipconfig *origin;
789
790         origin = ipconfig->origin ? ipconfig->origin : ipconfig;
791
792         connman_ipaddress_copy(origin->address, ipaddress);
793
794         connman_inet_set_address(origin->index, origin->address);
795 }
796
797 int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
798 {
799         struct connman_ipdevice *ipdevice;
800
801         DBG("ipconfig %p", ipconfig);
802
803         if (ipconfig == NULL || ipconfig->index < 0)
804                 return -ENODEV;
805
806         ipdevice = g_hash_table_lookup(ipdevice_hash,
807                                         GINT_TO_POINTER(ipconfig->index));
808         if (ipdevice == NULL)
809                 return -ENXIO;
810
811         if (ipdevice->config != NULL)
812                 connman_ipconfig_unref(ipdevice->config);
813
814         ipdevice->config = connman_ipconfig_ref(ipconfig);
815
816         return 0;
817 }
818
819 int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
820 {
821         struct connman_ipdevice *ipdevice;
822
823         DBG("ipconfig %p", ipconfig);
824
825         if (ipconfig == NULL || ipconfig->index < 0)
826                 return -ENODEV;
827
828         ipdevice = g_hash_table_lookup(ipdevice_hash,
829                                         GINT_TO_POINTER(ipconfig->index));
830         if (ipdevice == NULL)
831                 return -ENXIO;
832
833         if (ipdevice->config == NULL || ipdevice->config != ipconfig)
834                 return -EINVAL;
835
836         connman_ipconfig_unref(ipdevice->config);
837         ipdevice->config = NULL;
838
839         return 0;
840 }
841
842 const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method)
843 {
844         switch (method) {
845         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
846                 break;
847         case CONNMAN_IPCONFIG_METHOD_IGNORE:
848                 return "ignore";
849         case CONNMAN_IPCONFIG_METHOD_STATIC:
850                 return "static";
851         case CONNMAN_IPCONFIG_METHOD_DHCP:
852                 return "dhcp";
853         }
854
855         return NULL;
856 }
857
858 enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method)
859 {
860         if (g_strcmp0(method, "ignore") == 0)
861                 return CONNMAN_IPCONFIG_METHOD_IGNORE;
862         else if (g_strcmp0(method, "static") == 0)
863                 return CONNMAN_IPCONFIG_METHOD_STATIC;
864         else if (g_strcmp0(method, "dhcp") == 0)
865                 return CONNMAN_IPCONFIG_METHOD_DHCP;
866         else
867                 return CONNMAN_IPCONFIG_METHOD_UNKNOWN;
868 }
869
870 static void append_variant(DBusMessageIter *iter, const char *prefix,
871                                         const char *key, int type, void *val)
872 {
873         char *str;
874
875         if (prefix == NULL) {
876                 connman_dbus_dict_append_variant(iter, key, type, val);
877                 return;
878         }
879
880         str = g_strdup_printf("%s%s", prefix, key);
881         if (str != NULL)
882                 connman_dbus_dict_append_variant(iter, str, type, val);
883
884         g_free(str);
885 }
886
887 void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
888                                 DBusMessageIter *iter, const char *prefix)
889 {
890         const char *str;
891
892         str = __connman_ipconfig_method2string(ipconfig->method);
893         if (str == NULL)
894                 return;
895
896         append_variant(iter, prefix, "Method", DBUS_TYPE_STRING, &str);
897 }
898
899 int __connman_ipconfig_set_ipv4(struct connman_ipconfig *ipconfig,
900                                 const char *key, DBusMessageIter *value)
901 {
902         int type = dbus_message_iter_get_arg_type(value);
903
904         DBG("ipconfig %p key %s type %d", ipconfig, key, type);
905
906         if (g_strcmp0(key, "Method") == 0) {
907                 const char *method;
908
909                 if (type != DBUS_TYPE_STRING)
910                         return -EINVAL;
911
912                 dbus_message_iter_get_basic(value, &method);
913
914                 ipconfig->method = __connman_ipconfig_string2method(method);
915         } else
916                 return -EINVAL;
917
918         return 0;
919 }
920
921 int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
922                 GKeyFile *keyfile, const char *identifier, const char *prefix)
923 {
924         DBG("ipconfig %p identifier %s", ipconfig, identifier);
925
926         return 0;
927 }
928
929 int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
930                 GKeyFile *keyfile, const char *identifier, const char *prefix)
931 {
932         DBG("ipconfig %p identifier %s", ipconfig, identifier);
933
934         return 0;
935 }
936
937 int __connman_ipconfig_init(void)
938 {
939         DBG("");
940
941         ipdevice_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
942                                                         NULL, free_ipdevice);
943
944         return 0;
945 }
946
947 void __connman_ipconfig_cleanup(void)
948 {
949         DBG("");
950
951         g_hash_table_destroy(ipdevice_hash);
952         ipdevice_hash = NULL;
953 }