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