From e425c22615000881b6be9037b895e65a2e096063 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 23 Aug 2009 13:16:13 -0700 Subject: [PATCH] Add support for cloning IP configurations --- include/ipconfig.h | 1 + src/connman.h | 3 ++ src/device.c | 41 ----------------- src/ipconfig.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++------- src/service.c | 74 ++++++++++++++++++++++++++++++- 5 files changed, 188 insertions(+), 57 deletions(-) diff --git a/include/ipconfig.h b/include/ipconfig.h index 76d0b28..8888d09 100644 --- a/include/ipconfig.h +++ b/include/ipconfig.h @@ -69,6 +69,7 @@ struct connman_ipconfig_ops { }; struct connman_ipconfig *connman_ipconfig_create(int index); +struct connman_ipconfig *connman_ipconfig_clone(struct connman_ipconfig *ipconfig); struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig); void connman_ipconfig_unref(struct connman_ipconfig *ipconfig); diff --git a/src/connman.h b/src/connman.h index 5ea9ea4..8392201 100644 --- a/src/connman.h +++ b/src/connman.h @@ -112,6 +112,9 @@ unsigned short __connman_ipconfig_get_type(int index); unsigned int __connman_ipconfig_get_flags(int index); const char *__connman_ipconfig_get_gateway(int index); +int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig); +int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig); + const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method); enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method); diff --git a/src/device.c b/src/device.c index 1f0e20a..2745893 100644 --- a/src/device.c +++ b/src/device.c @@ -1019,45 +1019,6 @@ const char *connman_device_get_path(struct connman_device *device) return device->element.path; } -static void device_up(struct connman_ipconfig *ipconfig) -{ - connman_info("%s up", connman_ipconfig_get_ifname(ipconfig)); -} - -static void device_down(struct connman_ipconfig *ipconfig) -{ - connman_info("%s down", connman_ipconfig_get_ifname(ipconfig)); -} - -static void device_lower_up(struct connman_ipconfig *ipconfig) -{ - connman_info("%s lower up", connman_ipconfig_get_ifname(ipconfig)); -} - -static void device_lower_down(struct connman_ipconfig *ipconfig) -{ - connman_info("%s lower down", connman_ipconfig_get_ifname(ipconfig)); -} - -static void device_ip_bound(struct connman_ipconfig *ipconfig) -{ - connman_info("%s ip bound", connman_ipconfig_get_ifname(ipconfig)); -} - -static void device_ip_release(struct connman_ipconfig *ipconfig) -{ - connman_info("%s ip release", connman_ipconfig_get_ifname(ipconfig)); -} - -static const struct connman_ipconfig_ops device_ops = { - .up = device_up, - .down = device_down, - .lower_up = device_lower_up, - .lower_down = device_lower_down, - .ip_bound = device_ip_bound, - .ip_release = device_ip_release, -}; - /** * connman_device_set_index: * @device: device structure @@ -1077,8 +1038,6 @@ void connman_device_set_index(struct connman_device *device, int index) } device->ipconfig = connman_ipconfig_create(index); - - connman_ipconfig_set_ops(device->ipconfig, &device_ops); } /** diff --git a/src/ipconfig.c b/src/ipconfig.c index 2e68a65..2f5d521 100644 --- a/src/ipconfig.c +++ b/src/ipconfig.c @@ -38,6 +38,8 @@ struct connman_ipconfig { gint refcount; int index; + struct connman_ipconfig *origin; + const struct connman_ipconfig_ops *ops; void *ops_data; @@ -55,7 +57,9 @@ struct connman_ipdevice { char *gateway; struct connman_ipconfig *config; + struct connman_ipconfig_driver *driver; + struct connman_ipconfig *driver_config; }; static GHashTable *ipdevice_hash = NULL; @@ -74,6 +78,9 @@ struct connman_ipaddress *connman_ipaddress_alloc(void) void connman_ipaddress_free(struct connman_ipaddress *ipaddress) { + if (ipaddress == NULL) + return; + g_free(ipaddress->broadcast); g_free(ipaddress->peer); g_free(ipaddress->local); @@ -83,6 +90,9 @@ void connman_ipaddress_free(struct connman_ipaddress *ipaddress) void connman_ipaddress_copy(struct connman_ipaddress *ipaddress, struct connman_ipaddress *source) { + if (ipaddress == NULL || source == NULL) + return; + ipaddress->prefixlen = source->prefixlen; g_free(ipaddress->local); @@ -235,14 +245,23 @@ static void __connman_ipconfig_lower_up(struct connman_ipdevice *ipdevice) if (ipdevice->driver != NULL) return; + ipdevice->driver_config = connman_ipconfig_clone(ipdevice->config); + if (ipdevice->driver_config == NULL) + return; + for (list = driver_list; list; list = list->next) { struct connman_ipconfig_driver *driver = list->data; - if (driver->request(ipdevice->config) == 0) { + if (driver->request(ipdevice->driver_config) == 0) { ipdevice->driver = driver; break; } } + + if (ipdevice->driver == NULL) { + connman_ipconfig_unref(ipdevice->driver_config); + ipdevice->driver_config = NULL; + } } static void __connman_ipconfig_lower_down(struct connman_ipdevice *ipdevice) @@ -255,7 +274,12 @@ static void __connman_ipconfig_lower_down(struct connman_ipdevice *ipdevice) if (ipdevice->driver == NULL) return; - ipdevice->driver->release(ipdevice->config); + ipdevice->driver->release(ipdevice->driver_config); + + ipdevice->driver = NULL; + + connman_ipconfig_unref(ipdevice->driver_config); + ipdevice->driver_config = NULL; connman_inet_clear_address(ipdevice->index); } @@ -283,17 +307,6 @@ void __connman_ipconfig_newlink(int index, unsigned short type, ipdevice->ifname = connman_inet_ifname(index); ipdevice->type = type; - ipdevice->config = connman_ipconfig_create(index); - if (ipdevice->config == NULL) { - g_free(ipdevice->ifname); - g_free(ipdevice); - return; - } - - if (type == ARPHRD_ETHER) - connman_ipconfig_set_method(ipdevice->config, - CONNMAN_IPCONFIG_METHOD_IGNORE); - g_hash_table_insert(ipdevice_hash, GINT_TO_POINTER(index), ipdevice); connman_info("%s {create} index %d type %d <%s>", ipdevice->ifname, @@ -611,6 +624,32 @@ struct connman_ipconfig *connman_ipconfig_create(int index) } /** + * connman_ipconfig_clone: + * + * Clone an ipconfig structure and create new reference. + * + * Returns: a newly-allocated #connman_ipconfig structure + */ +struct connman_ipconfig *connman_ipconfig_clone(struct connman_ipconfig *ipconfig) +{ + struct connman_ipconfig *ipconfig_clone; + + DBG("ipconfig %p", ipconfig); + + ipconfig_clone = g_try_new0(struct connman_ipconfig, 1); + if (ipconfig_clone == NULL) + return NULL; + + ipconfig_clone->refcount = 1; + + ipconfig_clone->origin = connman_ipconfig_ref(ipconfig); + + ipconfig_clone->index = -1; + + return ipconfig_clone; +} + +/** * connman_ipconfig_ref: * @ipconfig: ipconfig structure * @@ -634,6 +673,11 @@ void connman_ipconfig_unref(struct connman_ipconfig *ipconfig) if (g_atomic_int_dec_and_test(&ipconfig->refcount) == TRUE) { connman_ipconfig_set_ops(ipconfig, NULL); + if (ipconfig->origin != NULL) { + connman_ipconfig_unref(ipconfig->origin); + ipconfig->origin = NULL; + } + connman_ipaddress_free(ipconfig->address); g_free(ipconfig); } @@ -670,6 +714,9 @@ void connman_ipconfig_set_data(struct connman_ipconfig *ipconfig, void *data) */ int connman_ipconfig_get_index(struct connman_ipconfig *ipconfig) { + if (ipconfig->origin != NULL) + return ipconfig->origin->index; + return ipconfig->index; } @@ -738,9 +785,58 @@ int connman_ipconfig_set_method(struct connman_ipconfig *ipconfig, void connman_ipconfig_bind(struct connman_ipconfig *ipconfig, struct connman_ipaddress *ipaddress) { - connman_ipaddress_copy(ipconfig->address, ipaddress); + struct connman_ipconfig *origin; - connman_inet_set_address(ipconfig->index, ipconfig->address); + origin = ipconfig->origin ? ipconfig->origin : ipconfig; + + connman_ipaddress_copy(origin->address, ipaddress); + + connman_inet_set_address(origin->index, origin->address); +} + +int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig) +{ + struct connman_ipdevice *ipdevice; + + DBG("ipconfig %p", ipconfig); + + if (ipconfig == NULL || ipconfig->index < 0) + return -ENODEV; + + ipdevice = g_hash_table_lookup(ipdevice_hash, + GINT_TO_POINTER(ipconfig->index)); + if (ipdevice == NULL) + return -ENXIO; + + if (ipdevice->config != NULL) + connman_ipconfig_unref(ipdevice->config); + + ipdevice->config = connman_ipconfig_ref(ipconfig); + + return 0; +} + +int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig) +{ + struct connman_ipdevice *ipdevice; + + DBG("ipconfig %p", ipconfig); + + if (ipconfig == NULL || ipconfig->index < 0) + return -ENODEV; + + ipdevice = g_hash_table_lookup(ipdevice_hash, + GINT_TO_POINTER(ipconfig->index)); + if (ipdevice == NULL) + return -ENXIO; + + if (ipdevice->config == NULL || ipdevice->config != ipconfig) + return -EINVAL; + + connman_ipconfig_unref(ipdevice->config); + ipdevice->config = NULL; + + return 0; } const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method) diff --git a/src/service.c b/src/service.c index 7287c0d..df49a21 100644 --- a/src/service.c +++ b/src/service.c @@ -703,6 +703,8 @@ static gboolean connect_timeout(gpointer user_data) else if (service->device != NULL) __connman_device_disconnect(service->device); + __connman_ipconfig_disable(service->ipconfig); + if (service->pending != NULL) { DBusMessage *reply; @@ -1283,18 +1285,24 @@ int __connman_service_connect(struct connman_service *service) if (prepare_network(service) == FALSE) return -EINVAL; + __connman_ipconfig_enable(service->ipconfig); + err = __connman_network_connect(service->network); } else if (service->device != NULL) { if (service->favorite == FALSE) return -ENOLINK; + __connman_ipconfig_enable(service->ipconfig); + err = __connman_device_connect(service->device); } else return -EOPNOTSUPP; if (err < 0) { - if (err != -EINPROGRESS) + if (err != -EINPROGRESS) { + __connman_ipconfig_disable(service->ipconfig); return err; + } service->timeout = g_timeout_add_seconds(45, connect_timeout, service); @@ -1322,6 +1330,8 @@ int __connman_service_disconnect(struct connman_service *service) } else return -EOPNOTSUPP; + __connman_ipconfig_disable(service->ipconfig); + if (err < 0) { if (err != -EINPROGRESS) return err; @@ -1608,6 +1618,64 @@ static int service_register(struct connman_service *service) return 0; } +static void service_up(struct connman_ipconfig *ipconfig) +{ + connman_info("%s up", connman_ipconfig_get_ifname(ipconfig)); +} + +static void service_down(struct connman_ipconfig *ipconfig) +{ + connman_info("%s down", connman_ipconfig_get_ifname(ipconfig)); +} + +static void service_lower_up(struct connman_ipconfig *ipconfig) +{ + connman_info("%s lower up", connman_ipconfig_get_ifname(ipconfig)); +} + +static void service_lower_down(struct connman_ipconfig *ipconfig) +{ + connman_info("%s lower down", connman_ipconfig_get_ifname(ipconfig)); +} + +static void service_ip_bound(struct connman_ipconfig *ipconfig) +{ + connman_info("%s ip bound", connman_ipconfig_get_ifname(ipconfig)); +} + +static void service_ip_release(struct connman_ipconfig *ipconfig) +{ + connman_info("%s ip release", connman_ipconfig_get_ifname(ipconfig)); +} + +static const struct connman_ipconfig_ops service_ops = { + .up = service_up, + .down = service_down, + .lower_up = service_lower_up, + .lower_down = service_lower_down, + .ip_bound = service_ip_bound, + .ip_release = service_ip_release, +}; + +static void setup_ipconfig(struct connman_service *service, int index) +{ + if (index < 0) + return; + + service->ipconfig = connman_ipconfig_create(index); + if (service->ipconfig == NULL) + return; + + connman_ipconfig_set_method(service->ipconfig, + CONNMAN_IPCONFIG_METHOD_DHCP); + + __connman_storage_load_service(service); + + connman_ipconfig_set_data(service->ipconfig, service); + + connman_ipconfig_set_ops(service->ipconfig, &service_ops); +} + /** * __connman_service_lookup_from_device: * @device: device structure @@ -1667,6 +1735,8 @@ struct connman_service *__connman_service_create_from_device(struct connman_devi service->device = device; + setup_ipconfig(service, connman_device_get_index(device)); + service_register(service); __connman_profile_changed(TRUE); @@ -1903,6 +1973,8 @@ struct connman_service *__connman_service_create_from_network(struct connman_net update_from_network(service, network); + setup_ipconfig(service, connman_network_get_index(network)); + service_register(service); __connman_profile_changed(TRUE); -- 2.7.4