5 * Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
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.
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.
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
27 #include <net/if_arp.h>
30 #define IFF_LOWER_UP 0x10000
37 struct connman_ipconfig {
41 struct connman_ipconfig *origin;
43 const struct connman_ipconfig_ops *ops;
46 enum connman_ipconfig_method method;
47 struct connman_ipaddress *address;
48 struct connman_ipaddress *system;
54 struct connman_ipdevice {
63 struct connman_ipconfig *config;
65 struct connman_ipconfig_driver *driver;
66 struct connman_ipconfig *driver_config;
69 static GHashTable *ipdevice_hash = NULL;
70 static GList *ipconfig_list = NULL;
72 struct connman_ipaddress *connman_ipaddress_alloc(void)
74 struct connman_ipaddress *ipaddress;
76 ipaddress = g_try_new0(struct connman_ipaddress, 1);
77 if (ipaddress == NULL)
83 void connman_ipaddress_free(struct connman_ipaddress *ipaddress)
85 if (ipaddress == NULL)
88 g_free(ipaddress->broadcast);
89 g_free(ipaddress->peer);
90 g_free(ipaddress->local);
94 void connman_ipaddress_clear(struct connman_ipaddress *ipaddress)
96 if (ipaddress == NULL)
99 ipaddress->prefixlen = 0;
101 g_free(ipaddress->local);
102 ipaddress->local = NULL;
104 g_free(ipaddress->peer);
105 ipaddress->peer = NULL;
107 g_free(ipaddress->broadcast);
108 ipaddress->broadcast = NULL;
111 void connman_ipaddress_copy(struct connman_ipaddress *ipaddress,
112 struct connman_ipaddress *source)
114 if (ipaddress == NULL || source == NULL)
117 ipaddress->prefixlen = source->prefixlen;
119 g_free(ipaddress->local);
120 ipaddress->local = g_strdup(source->local);
122 g_free(ipaddress->peer);
123 ipaddress->peer = g_strdup(source->peer);
125 g_free(ipaddress->broadcast);
126 ipaddress->broadcast = g_strdup(source->broadcast);
129 static void free_address_list(struct connman_ipdevice *ipdevice)
133 for (list = ipdevice->address_list; list; list = list->next) {
134 struct connman_ipaddress *ipaddress = list->data;
136 connman_ipaddress_free(ipaddress);
140 g_slist_free(ipdevice->address_list);
141 ipdevice->address_list = NULL;
144 static struct connman_ipaddress *find_ipaddress(struct connman_ipdevice *ipdevice,
145 unsigned char prefixlen, const char *local)
149 for (list = ipdevice->address_list; list; list = list->next) {
150 struct connman_ipaddress *ipaddress = list->data;
152 if (g_strcmp0(ipaddress->local, local) == 0 &&
153 ipaddress->prefixlen == prefixlen)
160 static const char *type2str(unsigned short type)
165 case ARPHRD_LOOPBACK:
178 static const char *scope2str(unsigned char scope)
190 static void free_ipdevice(gpointer data)
192 struct connman_ipdevice *ipdevice = data;
194 connman_info("%s {remove} index %d", ipdevice->ifname,
197 if (ipdevice->config != NULL)
198 connman_ipconfig_unref(ipdevice->config);
200 free_address_list(ipdevice);
201 g_free(ipdevice->gateway);
203 g_free(ipdevice->ifname);
207 static GSList *driver_list = NULL;
209 static gint compare_priority(gconstpointer a, gconstpointer b)
211 const struct connman_ipconfig_driver *driver1 = a;
212 const struct connman_ipconfig_driver *driver2 = b;
214 return driver2->priority - driver1->priority;
218 * connman_ipconfig_driver_register:
219 * @driver: IP configuration driver
221 * Register a new IP configuration driver
223 * Returns: %0 on success
225 int connman_ipconfig_driver_register(struct connman_ipconfig_driver *driver)
227 DBG("driver %p name %s", driver, driver->name);
229 driver_list = g_slist_insert_sorted(driver_list, driver,
236 * connman_ipconfig_driver_unregister:
237 * @driver: IP configuration driver
239 * Remove a previously registered IP configuration driver.
241 void connman_ipconfig_driver_unregister(struct connman_ipconfig_driver *driver)
243 DBG("driver %p name %s", driver, driver->name);
245 driver_list = g_slist_remove(driver_list, driver);
248 static void __connman_ipconfig_lower_up(struct connman_ipdevice *ipdevice)
252 DBG("ipconfig %p", ipdevice->config);
254 if (ipdevice->config == NULL)
257 switch (ipdevice->config->method) {
258 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
259 case CONNMAN_IPCONFIG_METHOD_IGNORE:
260 case CONNMAN_IPCONFIG_METHOD_STATIC:
262 case CONNMAN_IPCONFIG_METHOD_DHCP:
266 if (ipdevice->driver != NULL)
269 ipdevice->driver_config = connman_ipconfig_clone(ipdevice->config);
270 if (ipdevice->driver_config == NULL)
273 for (list = driver_list; list; list = list->next) {
274 struct connman_ipconfig_driver *driver = list->data;
276 if (driver->request(ipdevice->driver_config) == 0) {
277 ipdevice->driver = driver;
282 if (ipdevice->driver == NULL) {
283 connman_ipconfig_unref(ipdevice->driver_config);
284 ipdevice->driver_config = NULL;
288 static void __connman_ipconfig_lower_down(struct connman_ipdevice *ipdevice)
290 DBG("ipconfig %p", ipdevice->config);
292 if (ipdevice->config == NULL)
295 if (ipdevice->driver == NULL)
298 ipdevice->driver->release(ipdevice->driver_config);
300 ipdevice->driver = NULL;
302 connman_ipconfig_unref(ipdevice->driver_config);
303 ipdevice->driver_config = NULL;
305 connman_inet_clear_address(ipdevice->index);
308 void __connman_ipconfig_newlink(int index, unsigned short type,
309 unsigned int flags, const char *address,
312 struct connman_ipdevice *ipdevice;
315 gboolean up = FALSE, down = FALSE;
316 gboolean lower_up = FALSE, lower_down = FALSE;
319 DBG("index %d", index);
321 if (type == ARPHRD_LOOPBACK)
324 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
325 if (ipdevice != NULL)
328 ifname = connman_inet_ifname(index);
330 if (__connman_element_device_isfiltered(ifname) == TRUE) {
331 connman_info("Ignoring interface %s (filtered)", ifname);
336 ipdevice = g_try_new0(struct connman_ipdevice, 1);
337 if (ipdevice == NULL) {
342 ipdevice->index = index;
343 ipdevice->ifname = ifname;
344 ipdevice->type = type;
346 g_hash_table_insert(ipdevice_hash, GINT_TO_POINTER(index), ipdevice);
348 connman_info("%s {create} index %d type %d <%s>", ipdevice->ifname,
349 index, type, type2str(type));
352 if (ipdevice->config != NULL) {
353 g_free(ipdevice->config->eth);
354 ipdevice->config->eth = g_strdup(address);
355 ipdevice->config->mtu = mtu;
358 if (flags == ipdevice->flags)
361 if ((ipdevice->flags & IFF_UP) != (flags & IFF_UP)) {
368 if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) !=
369 (flags & (IFF_RUNNING | IFF_LOWER_UP))) {
370 if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) ==
371 (IFF_RUNNING | IFF_LOWER_UP))
373 else if ((flags & (IFF_RUNNING | IFF_LOWER_UP)) == 0)
377 ipdevice->flags = flags;
379 str = g_string_new(NULL);
384 g_string_append(str, "UP");
386 g_string_append(str, "DOWN");
388 if (flags & IFF_RUNNING)
389 g_string_append(str, ",RUNNING");
391 if (flags & IFF_LOWER_UP)
392 g_string_append(str, ",LOWER_UP");
394 connman_info("%s {update} flags %u <%s>", ipdevice->ifname,
397 g_string_free(str, TRUE);
399 for (list = g_list_first(ipconfig_list); list;
400 list = g_list_next(list)) {
401 struct connman_ipconfig *ipconfig = list->data;
403 if (index != ipconfig->index)
406 if (up == TRUE && ipconfig->ops->up)
407 ipconfig->ops->up(ipconfig);
408 if (lower_up == TRUE && ipconfig->ops->lower_up)
409 ipconfig->ops->lower_up(ipconfig);
411 if (lower_down == TRUE && ipconfig->ops->lower_down)
412 ipconfig->ops->lower_down(ipconfig);
413 if (down == TRUE && ipconfig->ops->down)
414 ipconfig->ops->down(ipconfig);
418 __connman_ipconfig_lower_up(ipdevice);
420 __connman_ipconfig_lower_down(ipdevice);
423 void __connman_ipconfig_dellink(int index)
425 struct connman_ipdevice *ipdevice;
428 DBG("index %d", index);
430 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
431 if (ipdevice == NULL)
434 for (list = g_list_first(ipconfig_list); list;
435 list = g_list_next(list)) {
436 struct connman_ipconfig *ipconfig = list->data;
438 if (index != ipconfig->index)
441 ipconfig->index = -1;
443 if (ipconfig->ops->lower_down)
444 ipconfig->ops->lower_down(ipconfig);
445 if (ipconfig->ops->down)
446 ipconfig->ops->down(ipconfig);
449 __connman_ipconfig_lower_down(ipdevice);
451 g_hash_table_remove(ipdevice_hash, GINT_TO_POINTER(index));
454 void __connman_ipconfig_newaddr(int index, const char *label,
455 unsigned char prefixlen, const char *address)
457 struct connman_ipdevice *ipdevice;
458 struct connman_ipaddress *ipaddress;
461 DBG("index %d", index);
463 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
464 if (ipdevice == NULL)
467 ipaddress = connman_ipaddress_alloc();
468 if (ipaddress == NULL)
471 ipaddress->prefixlen = prefixlen;
472 ipaddress->local = g_strdup(address);
474 ipdevice->address_list = g_slist_append(ipdevice->address_list,
477 connman_info("%s {add} address %s/%u label %s", ipdevice->ifname,
478 address, prefixlen, label);
480 if (ipdevice->config != NULL)
481 connman_ipaddress_copy(ipdevice->config->system, ipaddress);
483 if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
486 if (g_slist_length(ipdevice->address_list) > 1)
489 for (list = g_list_first(ipconfig_list); list;
490 list = g_list_next(list)) {
491 struct connman_ipconfig *ipconfig = list->data;
493 if (index != ipconfig->index)
496 if (ipconfig->ops->ip_bound)
497 ipconfig->ops->ip_bound(ipconfig);
501 void __connman_ipconfig_deladdr(int index, const char *label,
502 unsigned char prefixlen, const char *address)
504 struct connman_ipdevice *ipdevice;
505 struct connman_ipaddress *ipaddress;
508 DBG("index %d", index);
510 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
511 if (ipdevice == NULL)
514 ipaddress = find_ipaddress(ipdevice, prefixlen, address);
515 if (ipaddress == NULL)
518 ipdevice->address_list = g_slist_remove(ipdevice->address_list,
521 connman_ipaddress_free(ipaddress);
523 connman_info("%s {del} address %s/%u label %s", ipdevice->ifname,
524 address, prefixlen, label);
526 if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
529 if (g_slist_length(ipdevice->address_list) > 0)
532 for (list = g_list_first(ipconfig_list); list;
533 list = g_list_next(list)) {
534 struct connman_ipconfig *ipconfig = list->data;
536 if (index != ipconfig->index)
539 if (ipconfig->ops->ip_release)
540 ipconfig->ops->ip_release(ipconfig);
544 void __connman_ipconfig_newroute(int index, unsigned char scope,
545 const char *dst, const char *gateway)
547 struct connman_ipdevice *ipdevice;
549 DBG("index %d", index);
551 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
552 if (ipdevice == NULL)
555 if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
556 g_free(ipdevice->gateway);
557 ipdevice->gateway = g_strdup(gateway);
560 connman_info("%s {add} route %s gw %s scope %u <%s>",
561 ipdevice->ifname, dst, gateway,
562 scope, scope2str(scope));
565 void __connman_ipconfig_delroute(int index, unsigned char scope,
566 const char *dst, const char *gateway)
568 struct connman_ipdevice *ipdevice;
570 DBG("index %d", index);
572 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
573 if (ipdevice == NULL)
576 if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
577 g_free(ipdevice->gateway);
578 ipdevice->gateway = NULL;
581 connman_info("%s {del} route %s gw %s scope %u <%s>",
582 ipdevice->ifname, dst, gateway,
583 scope, scope2str(scope));
586 void __connman_ipconfig_foreach(void (*function) (int index, void *user_data),
591 keys = g_hash_table_get_keys(ipdevice_hash);
595 for (list = g_list_first(keys); list; list = g_list_next(list)) {
596 int index = GPOINTER_TO_INT(list->data);
598 function(index, user_data);
604 unsigned short __connman_ipconfig_get_type(int index)
606 struct connman_ipdevice *ipdevice;
608 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
609 if (ipdevice == NULL)
612 return ipdevice->type;
615 unsigned int __connman_ipconfig_get_flags(int index)
617 struct connman_ipdevice *ipdevice;
619 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
620 if (ipdevice == NULL)
623 return ipdevice->flags;
626 const char *__connman_ipconfig_get_gateway(int index)
628 struct connman_ipdevice *ipdevice;
630 ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
631 if (ipdevice == NULL)
634 return ipdevice->gateway;
638 * connman_ipconfig_create:
640 * Allocate a new ipconfig structure.
642 * Returns: a newly-allocated #connman_ipconfig structure
644 struct connman_ipconfig *connman_ipconfig_create(int index)
646 struct connman_ipconfig *ipconfig;
648 DBG("index %d", index);
650 ipconfig = g_try_new0(struct connman_ipconfig, 1);
651 if (ipconfig == NULL)
654 ipconfig->refcount = 1;
656 ipconfig->index = index;
658 ipconfig->address = connman_ipaddress_alloc();
659 if (ipconfig->address == NULL) {
664 ipconfig->system = connman_ipaddress_alloc();
666 DBG("ipconfig %p", ipconfig);
672 * connman_ipconfig_clone:
674 * Clone an ipconfig structure and create new reference.
676 * Returns: a newly-allocated #connman_ipconfig structure
678 struct connman_ipconfig *connman_ipconfig_clone(struct connman_ipconfig *ipconfig)
680 struct connman_ipconfig *ipconfig_clone;
682 DBG("ipconfig %p", ipconfig);
684 ipconfig_clone = g_try_new0(struct connman_ipconfig, 1);
685 if (ipconfig_clone == NULL)
688 ipconfig_clone->refcount = 1;
690 ipconfig_clone->origin = connman_ipconfig_ref(ipconfig);
692 ipconfig_clone->index = -1;
694 return ipconfig_clone;
698 * connman_ipconfig_ref:
699 * @ipconfig: ipconfig structure
701 * Increase reference counter of ipconfig
703 struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig)
705 g_atomic_int_inc(&ipconfig->refcount);
711 * connman_ipconfig_unref:
712 * @ipconfig: ipconfig structure
714 * Decrease reference counter of ipconfig
716 void connman_ipconfig_unref(struct connman_ipconfig *ipconfig)
718 if (g_atomic_int_dec_and_test(&ipconfig->refcount) == TRUE) {
719 connman_ipconfig_set_ops(ipconfig, NULL);
721 if (ipconfig->origin != NULL) {
722 connman_ipconfig_unref(ipconfig->origin);
723 ipconfig->origin = NULL;
726 connman_ipaddress_free(ipconfig->system);
727 connman_ipaddress_free(ipconfig->address);
728 g_free(ipconfig->eth);
734 * connman_ipconfig_get_data:
735 * @ipconfig: ipconfig structure
737 * Get private data pointer
739 void *connman_ipconfig_get_data(struct connman_ipconfig *ipconfig)
741 return ipconfig->ops_data;
745 * connman_ipconfig_set_data:
746 * @ipconfig: ipconfig structure
747 * @data: data pointer
749 * Set private data pointer
751 void connman_ipconfig_set_data(struct connman_ipconfig *ipconfig, void *data)
753 ipconfig->ops_data = data;
757 * connman_ipconfig_get_index:
758 * @ipconfig: ipconfig structure
760 * Get interface index
762 int connman_ipconfig_get_index(struct connman_ipconfig *ipconfig)
764 if (ipconfig->origin != NULL)
765 return ipconfig->origin->index;
767 return ipconfig->index;
771 * connman_ipconfig_get_ifname:
772 * @ipconfig: ipconfig structure
776 const char *connman_ipconfig_get_ifname(struct connman_ipconfig *ipconfig)
778 struct connman_ipdevice *ipdevice;
780 if (ipconfig->index < 0)
783 ipdevice = g_hash_table_lookup(ipdevice_hash,
784 GINT_TO_POINTER(ipconfig->index));
785 if (ipdevice == NULL)
788 return ipdevice->ifname;
792 * connman_ipconfig_set_ops:
793 * @ipconfig: ipconfig structure
794 * @ops: operation callbacks
796 * Set the operation callbacks
798 void connman_ipconfig_set_ops(struct connman_ipconfig *ipconfig,
799 const struct connman_ipconfig_ops *ops)
801 if (ipconfig->ops != NULL)
802 ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
807 ipconfig_list = g_list_append(ipconfig_list, ipconfig);
811 * connman_ipconfig_set_method:
812 * @ipconfig: ipconfig structure
813 * @method: configuration method
815 * Set the configuration method
817 int connman_ipconfig_set_method(struct connman_ipconfig *ipconfig,
818 enum connman_ipconfig_method method)
820 ipconfig->method = method;
826 * connman_ipconfig_bind:
827 * @ipconfig: ipconfig structure
828 * @ipaddress: ipaddress structure
830 * Bind IP address details to configuration
832 void connman_ipconfig_bind(struct connman_ipconfig *ipconfig,
833 struct connman_ipaddress *ipaddress)
835 struct connman_ipconfig *origin;
837 origin = ipconfig->origin ? ipconfig->origin : ipconfig;
839 connman_ipaddress_copy(origin->address, ipaddress);
841 connman_inet_set_address(origin->index, origin->address);
844 int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
846 struct connman_ipdevice *ipdevice;
848 DBG("ipconfig %p", ipconfig);
850 if (ipconfig == NULL || ipconfig->index < 0)
853 ipdevice = g_hash_table_lookup(ipdevice_hash,
854 GINT_TO_POINTER(ipconfig->index));
855 if (ipdevice == NULL)
858 if (ipdevice->config != NULL) {
859 connman_ipaddress_clear(ipdevice->config->system);
861 connman_ipconfig_unref(ipdevice->config);
864 ipdevice->config = connman_ipconfig_ref(ipconfig);
869 int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
871 struct connman_ipdevice *ipdevice;
873 DBG("ipconfig %p", ipconfig);
875 if (ipconfig == NULL || ipconfig->index < 0)
878 ipdevice = g_hash_table_lookup(ipdevice_hash,
879 GINT_TO_POINTER(ipconfig->index));
880 if (ipdevice == NULL)
883 if (ipdevice->config == NULL || ipdevice->config != ipconfig)
886 connman_ipaddress_clear(ipdevice->config->system);
888 connman_ipconfig_unref(ipdevice->config);
889 ipdevice->config = NULL;
894 const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method)
897 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
899 case CONNMAN_IPCONFIG_METHOD_IGNORE:
901 case CONNMAN_IPCONFIG_METHOD_STATIC:
903 case CONNMAN_IPCONFIG_METHOD_DHCP:
910 enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method)
912 if (g_strcmp0(method, "ignore") == 0)
913 return CONNMAN_IPCONFIG_METHOD_IGNORE;
914 else if (g_strcmp0(method, "static") == 0)
915 return CONNMAN_IPCONFIG_METHOD_STATIC;
916 else if (g_strcmp0(method, "dhcp") == 0)
917 return CONNMAN_IPCONFIG_METHOD_DHCP;
919 return CONNMAN_IPCONFIG_METHOD_UNKNOWN;
922 void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
923 DBusMessageIter *iter)
927 str = __connman_ipconfig_method2string(ipconfig->method);
931 connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
933 if (ipconfig->system == NULL)
936 if (ipconfig->system->local != NULL) {
938 struct in_addr netmask;
941 connman_dbus_dict_append_basic(iter, "Address",
942 DBUS_TYPE_STRING, &ipconfig->system->local);
944 addr = 0xffffffff << (32 - ipconfig->system->prefixlen);
945 netmask.s_addr = htonl(addr);
946 mask = inet_ntoa(netmask);
947 connman_dbus_dict_append_basic(iter, "Netmask",
948 DBUS_TYPE_STRING, &mask);
952 int __connman_ipconfig_set_ipv4(struct connman_ipconfig *ipconfig,
953 const char *key, DBusMessageIter *value)
955 int type = dbus_message_iter_get_arg_type(value);
957 DBG("ipconfig %p key %s type %d", ipconfig, key, type);
959 if (g_strcmp0(key, "Method") == 0) {
962 if (type != DBUS_TYPE_STRING)
965 dbus_message_iter_get_basic(value, &method);
967 ipconfig->method = __connman_ipconfig_string2method(method);
974 int __connman_ipconfig_append_ethernet(struct connman_ipconfig *ipconfig,
975 DBusMessageIter *iter)
977 const char *method = "auto";
979 connman_dbus_dict_append_basic(iter, "Method",
980 DBUS_TYPE_STRING, &method);
982 if (ipconfig->eth != NULL)
983 connman_dbus_dict_append_basic(iter, "Address",
984 DBUS_TYPE_STRING, &ipconfig->eth);
986 if (ipconfig->mtu > 0)
987 connman_dbus_dict_append_basic(iter, "MTU",
988 DBUS_TYPE_UINT16, &ipconfig->mtu);
993 int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
994 GKeyFile *keyfile, const char *identifier, const char *prefix)
996 DBG("ipconfig %p identifier %s", ipconfig, identifier);
1001 int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
1002 GKeyFile *keyfile, const char *identifier, const char *prefix)
1004 DBG("ipconfig %p identifier %s", ipconfig, identifier);
1009 int __connman_ipconfig_init(void)
1013 ipdevice_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1014 NULL, free_ipdevice);
1019 void __connman_ipconfig_cleanup(void)
1023 g_hash_table_destroy(ipdevice_hash);
1024 ipdevice_hash = NULL;