Hi, On Thu, 2012-10-04 at 12:56 +0300, Jukka Rissanen wrote: > --- > include/provider.h | 10 ++ > plugins/vpn.c | 292 +++++++++++++++++++++++++++++++++++++++++++- > src/provider.c | 42 +------ > vpn/vpn-provider.c | 352 > ++++++++++++++++++++++++++++++++++++++--------------- > 4 files changed, 556 insertions(+), 140 deletions(-) > > diff --git a/include/provider.h b/include/provider.h > index b663f37..548bd61 100644 > --- a/include/provider.h > +++ b/include/provider.h > @@ -56,6 +56,13 @@ enum connman_provider_error { > CONNMAN_PROVIDER_ERROR_AUTH_FAILED = 3, > }; > > +enum connman_provider_route_type { > + CONNMAN_PROVIDER_ROUTE_UNKNOWN = 0, > + CONNMAN_PROVIDER_ROUTE_ALL = 0, > + CONNMAN_PROVIDER_ROUTE_USER = 1, > + CONNMAN_PROVIDER_ROUTE_SERVER = 2, > +}; > + > struct connman_provider; > struct connman_ipaddress; > > @@ -119,6 +126,9 @@ struct connman_provider_driver { > const char * (*get_property) (struct connman_provider *provider, > const char *key); > int (*create) (DBusMessage *msg); > + int (*set_routes) (struct connman_provider *provider, > + enum connman_provider_route_type type); > + connman_bool_t (*check_routes) (struct connman_provider *provider); > }; > > int connman_provider_driver_register(struct connman_provider_driver *driver); > diff --git a/plugins/vpn.c b/plugins/vpn.c > index 5059952..aff821b 100644 > --- a/plugins/vpn.c > +++ b/plugins/vpn.c > @@ -39,6 +39,7 @@ > #include <connman/provider.h> > #include <connman/ipaddress.h> > #include <connman/vpn-dbus.h> > +#include <connman/inet.h> > > #define DBUS_TIMEOUT 10000 > > @@ -51,6 +52,13 @@ static guint added_watch; > static guint removed_watch; > static guint property_watch; > > +struct vpn_route { > + int family; > + char *host; > + char *netmask; > + char *gateway; > +}; > + > struct connection_data { > char *path; > struct connman_provider *provider; > @@ -64,6 +72,8 @@ struct connection_data { > char *domain; > char **nameservers; > > + GHashTable *server_routes; > + GHashTable *user_routes; > GHashTable *setting_strings; > > struct connman_ipaddress *ip; > @@ -197,6 +207,16 @@ out: > return err; > } > > +static void destroy_route(gpointer user_data) > +{ > + struct vpn_route *route = user_data; > + > + g_free(route->host); > + g_free(route->netmask); > + g_free(route->gateway); > + g_free(route); > +} > + > static struct connection_data *create_connection_data(const char *path) > { > struct connection_data *data; > @@ -213,6 +233,11 @@ static struct connection_data > *create_connection_data(const char *path) > data->setting_strings = g_hash_table_new_full(g_str_hash, > g_str_equal, g_free, g_free); > > + data->server_routes = g_hash_table_new_full(g_direct_hash, > + g_str_equal, g_free, destroy_route); > + data->user_routes = g_hash_table_new_full(g_str_hash, > + g_str_equal, g_free, destroy_route); > + > return data; > } > > @@ -887,6 +912,74 @@ done: > return err; > } > > +static void set_route(struct connection_data *data, struct vpn_route *route) > +{ > + if (route->family == AF_INET6) { > + unsigned char prefix_len = atoi(route->netmask); > + > + connman_inet_add_ipv6_network_route(data->index, route->host, > + route->gateway, > + prefix_len); > + } else { > + connman_inet_add_network_route(data->index, route->host, > + route->gateway, > + route->netmask); > + } > +} > + > +static int set_routes(struct connman_provider *provider, > + enum connman_provider_route_type type) > +{ > + struct connection_data *data; > + GHashTableIter iter; > + gpointer value, key; > + > + DBG("provider %p", provider); > + > + data = connman_provider_get_data(provider); > + if (data == NULL) > + return -EINVAL; > + > + if (type == CONNMAN_PROVIDER_ROUTE_ALL || > + type == CONNMAN_PROVIDER_ROUTE_USER) { > + g_hash_table_iter_init(&iter, data->user_routes); > + > + while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) > + set_route(data, value); > + } > + > + if (type == CONNMAN_PROVIDER_ROUTE_ALL || > + type == CONNMAN_PROVIDER_ROUTE_SERVER) { > + g_hash_table_iter_init(&iter, data->server_routes); > + > + while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) > + set_route(data, value); > + } > + > + return 0; > +} > + > +static connman_bool_t check_routes(struct connman_provider *provider) > +{ > + struct connection_data *data; > + > + DBG("provider %p", provider); > + > + data = connman_provider_get_data(provider); > + if (data == NULL) > + return FALSE; > + > + if (data->user_routes != NULL && > + g_hash_table_size(data->user_routes) > 0) > + return TRUE; > + > + if (data->server_routes != NULL && > + g_hash_table_size(data->server_routes) > 0) > + return TRUE; > + > + return FALSE; > +} > + > static struct connman_provider_driver provider_driver = { > .name = "VPN", > .type = CONNMAN_PROVIDER_TYPE_VPN, > @@ -897,6 +990,8 @@ static struct connman_provider_driver provider_driver = { > .set_property = set_string, > .get_property = get_string, > .create = create_configuration, > + .set_routes = set_routes, > + .check_routes = check_routes, > }; > > static void destroy_provider(struct connection_data *data) > @@ -930,6 +1025,8 @@ static void connection_destroy(gpointer hash_data) > g_free(data->name); > g_free(data->host); > g_free(data->domain); > + g_hash_table_destroy(data->server_routes); > + g_hash_table_destroy(data->user_routes); > g_strfreev(data->nameservers); > g_hash_table_destroy(data->setting_strings); > > @@ -1018,6 +1115,195 @@ static gboolean connection_added(DBusConnection > *conn, DBusMessage *message, > return TRUE; > } > > +static int save_route(GHashTable *routes, int family, const char *network, > + const char *netmask, const char *gateway) > +{ > + struct vpn_route *route; > + char *key = g_strdup_printf("%d/%s/%s", family, network, netmask); > + > + DBG("family %d network %s netmask %s", family, network, netmask); > + > + route = g_hash_table_lookup(routes, key); > + if (route == NULL) { > + route = g_try_new0(struct vpn_route, 1); > + if (route == NULL) { > + connman_error("out of memory"); > + return -ENOMEM; > + } > + > + route->family = family; > + route->host = g_strdup(network); > + route->netmask = g_strdup(netmask); > + route->gateway = g_strdup(gateway); > + > + g_hash_table_replace(routes, key, route); > + } else > + g_free(key); > + > + return 0; > +} > + > +static void server_route_changed(DBusMessageIter *array, > + struct connection_data *data) > +{ > + DBusMessageIter dict; > + int family = AF_INET; > + char *host = NULL, *netmask = NULL, *gateway = NULL; > + > + if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) { > + DBG("Expecting array, ignoring routes."); > + return; > + } > + > + dbus_message_iter_recurse(array, &dict); > + > + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { > + DBusMessageIter entry, value; > + const char *key; > + > + dbus_message_iter_recurse(&dict, &entry); > + dbus_message_iter_get_basic(&entry, &key); > + > + dbus_message_iter_next(&entry); > + dbus_message_iter_recurse(&entry, &value); > + > + if (g_str_equal(key, "ProtocolFamily") == TRUE) { > + int pf; > + dbus_message_iter_get_basic(&value, &pf); > + switch (pf) { > + case 4: > + family = AF_INET; > + break; > + case 6: > + family = AF_INET6; > + break; > + } > + DBG("family %d", family); > + } else if (g_str_equal(key, "Netmask") == TRUE) { > + dbus_message_iter_get_basic(&value, &netmask); > + DBG("netmask %s", netmask); > + } else if (g_str_equal(key, "Host") == TRUE) { > + dbus_message_iter_get_basic(&value, &host); > + DBG("host %s", host); > + } else if (g_str_equal(key, "Gateway") == TRUE) { > + dbus_message_iter_get_basic(&value, &gateway); > + DBG("gateway %s", gateway); > + } > + > + dbus_message_iter_next(&dict); > + } > + > + if (netmask == NULL || host == NULL || gateway == NULL) { > + DBG("Value missing."); > + return; > + } > + > + save_route(data->server_routes, family, host, netmask, gateway); > +} > + > +static int parse_user_route(const char *route, int *user_family, > + char **user_network, char **user_netmask) > +{ > + char *network, *netmask; > + char **elems; > + int family = PF_UNSPEC; > + > + if (route == NULL) > + return -EINVAL; > + > + elems = g_strsplit(route, "/", 0); > + if (elems == NULL) > + return -EINVAL; > + > + network = elems[0]; > + if (network == NULL || *network == '\0') { > + DBG("no network/netmask set"); > + g_strfreev(elems); > + return -EINVAL; > + } > + > + netmask = elems[1]; > + if (netmask != NULL && *netmask == '\0') { > + DBG("no netmask set"); > + g_strfreev(elems); > + return -EINVAL; > + } > + > + if (g_strrstr(network, ":") != NULL) > + family = AF_INET6; > + else if (g_strrstr(network, ".") != NULL) { > + family = AF_INET; > + > + if (g_strrstr(netmask, ".") == NULL) { > + /* We have netmask length */ > + in_addr_t addr; > + struct in_addr netmask_in; > + unsigned char prefix_len = 32; > + > + if (netmask != NULL) > + prefix_len = atoi(netmask);
If netmask is some text string, prefix_len will be 0 and incorrect? > + > + addr = 0xffffffff << (32 - prefix_len); > + netmask_in.s_addr = htonl(addr); > + netmask = inet_ntoa(netmask_in); > + > + DBG("network %s netmask %s", network, netmask); > + } > + } > + > + if (user_family != NULL) > + *user_family = family; > + > + if (user_network != NULL) > + *user_network = network; > + > + if (user_netmask != NULL) > + *user_netmask = netmask; 'network' and 'netmask' now point into elems[] which is freed below? > + > + g_strfreev(elems); > + > + return 0; > +} > + > +static void add_user_route(GHashTable *user_routes, const char *route) > +{ > + char *network, *netmask; > + int family, err; > + > + err = parse_user_route(route, &family, &network, &netmask); > + if (err < 0) > + return; > + > + save_route(user_routes, family, network, netmask, NULL); > +} > + > +static int user_routes_changed(DBusMessageIter *array, > + struct connection_data *data) > +{ > + GHashTable *user_routes; > + DBusMessageIter entry; > + > + dbus_message_iter_recurse(array, &entry); > + > + user_routes = g_hash_table_new_full(g_str_hash, g_str_equal, > + g_free, destroy_route); > + > + while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) { > + const char *route; > + > + dbus_message_iter_get_basic(&entry, &route); > + > + add_user_route(user_routes, route); > + > + dbus_message_iter_next(&entry); > + } > + > + g_hash_table_destroy(data->user_routes); > + data->user_routes = user_routes; > + > + return 0; > +} > + > static gboolean property_changed(DBusConnection *conn, > DBusMessage *message, > void *user_data) > @@ -1074,10 +1360,10 @@ static gboolean property_changed(DBusConnection *conn, > } else if (g_str_equal(key, "IPv6") == TRUE) { > err = extract_ip(&value, AF_INET6, data); > ip_set = TRUE; > - } else if (g_str_equal(key, "ServerRoutes") == TRUE) { > - /* XXX: TBD */ > + } else if (g_str_equal(key, "ServerRoute") == TRUE) { > + server_route_changed(&value, data); > } else if (g_str_equal(key, "UserRoutes") == TRUE) { > - /* XXX: TBD */ > + user_routes_changed(&value, data); > } else if (g_str_equal(key, "Nameservers") == TRUE) { > extract_nameservers(&value, data); > } > diff --git a/src/provider.c b/src/provider.c > index 64a871b..cd11db9 100644 > --- a/src/provider.c > +++ b/src/provider.c > @@ -38,25 +38,14 @@ static GHashTable *provider_hash = NULL; > > static GSList *driver_list = NULL; > > -struct connman_route { > - int family; > - char *host; > - char *netmask; > - char *gateway; > -}; > - > struct connman_provider { > int refcount; > struct connman_service *vpn_service; > int index; > char *identifier; > int family; > - GHashTable *routes; > struct connman_provider_driver *driver; > void *driver_data; > - GHashTable *user_routes; > - gchar **user_networks; > - gsize num_user_networks; > }; > > void __connman_provider_append_properties(struct connman_provider *provider, > @@ -109,9 +98,6 @@ static void provider_destruct(struct connman_provider > *provider) > DBG("provider %p", provider); > > g_free(provider->identifier); > - g_strfreev(provider->user_networks); > - g_hash_table_destroy(provider->routes); > - g_hash_table_destroy(provider->user_routes); > g_free(provider); > } > > @@ -248,6 +234,10 @@ static int set_connected(struct connman_provider > *provider, > provider_indicate_state(provider, > CONNMAN_SERVICE_STATE_READY); > > + if (provider->driver != NULL && provider->driver->set_routes) > + provider->driver->set_routes(provider, > + CONNMAN_PROVIDER_ROUTE_ALL); > + > } else { > if (ipconfig != NULL) { > provider_indicate_state(provider, > @@ -396,13 +386,8 @@ __connman_provider_check_routes(struct connman_provider > *provider) > if (provider == NULL) > return FALSE; > > - if (provider->user_routes != NULL && > - g_hash_table_size(provider->user_routes) > 0) > - return TRUE; > - > - if (provider->routes != NULL && > - g_hash_table_size(provider->routes) > 0) > - return TRUE; > + if (provider->driver != NULL && provider->driver->check_routes) > + return provider->driver->check_routes(provider); > > return FALSE; > } > @@ -601,27 +586,12 @@ static void provider_offline_mode(connman_bool_t > enabled) > > } > > -static void destroy_route(gpointer user_data) > -{ > - struct connman_route *route = user_data; > - > - g_free(route->host); > - g_free(route->netmask); > - g_free(route->gateway); > - g_free(route); > -} > - > static void provider_initialize(struct connman_provider *provider) > { > DBG("provider %p", provider); > > provider->index = 0; > provider->identifier = NULL; > - provider->user_networks = NULL; > - provider->routes = g_hash_table_new_full(g_direct_hash, g_direct_equal, > - NULL, destroy_route); > - provider->user_routes = g_hash_table_new_full(g_str_hash, g_str_equal, > - g_free, destroy_route); > } > > static struct connman_provider *provider_new(void) > diff --git a/vpn/vpn-provider.c b/vpn/vpn-provider.c > index a5cff3b..7ca3f5d 100644 > --- a/vpn/vpn-provider.c > +++ b/vpn/vpn-provider.c > @@ -75,24 +75,271 @@ struct vpn_provider { > char **nameservers; > }; > > +static void append_routes(DBusMessageIter *iter, char **routes) > +{ > + int i; > + > + DBG("%p", routes); > + > + for (i = 0; routes[i] != NULL; i++) { > + DBG("routes[%d] %s", i, routes[i]); > + dbus_message_iter_append_basic(iter, > + DBUS_TYPE_STRING, &routes[i]); > + } > +} > + > +static void append_user_routes(DBusMessageIter *iter, void *user_data) > +{ > + struct vpn_provider *provider = user_data; > + > + if (provider->user_networks != NULL && > + provider->num_user_networks > 0) { > + append_routes(iter, provider->user_networks); > + } > +} > + > +static void append_server_route(DBusMessageIter *iter, void *user_data) > +{ > + struct vpn_route *route = user_data; > + int family = 0; > + > + if (route->family == AF_INET) > + family = 4; > + else if (route->family == AF_INET6) > + family = 6; > + > + if (family != 0) > + connman_dbus_dict_append_basic(iter, "ProtocolFamily", > + DBUS_TYPE_INT32, &family); > + > + if (route->host != NULL) > + connman_dbus_dict_append_basic(iter, "Host", > + DBUS_TYPE_STRING, &route->host); > + > + if (route->netmask != NULL) > + connman_dbus_dict_append_basic(iter, "Netmask", > + DBUS_TYPE_STRING, &route->netmask); > + > + if (route->gateway != NULL) > + connman_dbus_dict_append_basic(iter, "Gateway", > + DBUS_TYPE_STRING, &route->gateway); > +} > + > +static void send_server_routes(struct vpn_provider *provider, void > *user_data) > +{ > + GHashTableIter hash; > + gpointer value, key; > + > + if (user_data != NULL) { > + connman_dbus_property_changed_dict(provider->path, > + VPN_CONNECTION_INTERFACE, > + "ServerRoute", > + append_server_route, > + user_data); > + return; > + } > + > + g_hash_table_iter_init(&hash, provider->routes); > + > + while (g_hash_table_iter_next(&hash, &key, &value) == TRUE) > + connman_dbus_property_changed_dict(provider->path, > + VPN_CONNECTION_INTERFACE, > + "ServerRoute", > + append_server_route, > + value); > +} > + > +static int provider_property_changed(struct vpn_provider *provider, > + const char *name, void *user_data) > +{ > + DBG("provider %p name %s", provider, name); > + > + if (g_str_equal(name, "UserRoutes") == TRUE) > + connman_dbus_property_changed_array(provider->path, > + VPN_CONNECTION_INTERFACE, > + name, > + DBUS_TYPE_STRING, > + append_user_routes, > + provider); > + else if (g_str_equal(name, "ServerRoute") == TRUE) > + send_server_routes(provider, user_data); > + > + return 0; > +} > + > +static char **get_user_networks(DBusMessageIter *array, int *count) > +{ > + DBusMessageIter entry; > + char **networks = NULL; > + GSList *list = NULL, *l; > + int len; > + > + dbus_message_iter_recurse(array, &entry); > + > + while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) { > + const char *val; > + dbus_message_iter_get_basic(&entry, &val); > + > + list = g_slist_prepend(list, g_strdup(val)); > + dbus_message_iter_next(&entry); > + } > + > + len = g_slist_length(list); > + if (len == 0) > + goto out; > + > + networks = g_try_new(char *, len + 1); > + if (networks == NULL) > + goto out; > + > + *count = len; > + networks[len] = 0; > + > + for (l = list; l != NULL; l = g_slist_next(l)) > + networks[--len] = l->data; > + > +out: > + g_slist_free(list); > + > + return networks; > +} > + > +static void set_user_networks(struct vpn_provider *provider, > + char **networks) > +{ > + int i = 0; > + > + while (networks[i] != NULL) { > + char **elems = g_strsplit(networks[i], "/", 0); > + char *network, *netmask; > + int family = PF_UNSPEC, ret; > + > + if (elems == NULL) > + break; > + > + network = elems[0]; > + if (network == NULL || *network == '\0') { > + DBG("no network/netmask set"); > + g_strfreev(elems); > + break; > + } > + > + netmask = elems[1]; > + if (netmask != NULL && *netmask == '\0') { > + DBG("no netmask set"); > + g_strfreev(elems); > + break; > + } > + > + if (g_strrstr(network, ":") != NULL) > + family = AF_INET6; > + else if (g_strrstr(network, ".") != NULL) { > + family = AF_INET; > + > + if (g_strrstr(netmask, ".") == NULL) { > + /* We have netmask length */ > + in_addr_t addr; > + struct in_addr netmask_in; > + unsigned char prefix_len = 32; > + > + if (netmask != NULL) > + prefix_len = atoi(netmask); atoi() again. > + > + addr = 0xffffffff << (32 - prefix_len); > + netmask_in.s_addr = htonl(addr); > + netmask = inet_ntoa(netmask_in); > + > + DBG("network %s netmask %s", network, netmask); > + } > + } > + > + ret = __vpn_provider_append_user_route(provider, > + family, network, netmask); > + g_strfreev(elems); > + > + if (ret != 0) > + break; > + > + i++; > + } > +} > + > +static void del_routes(struct vpn_provider *provider) > +{ > + g_hash_table_remove_all(provider->user_routes); > + g_strfreev(provider->user_networks); > + provider->user_networks = NULL; > + provider->num_user_networks = 0; > +} > + > static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg, > void *data) > { > + struct vpn_provider *provider = data; > + DBusMessageIter iter, value; > + const char *name; > + int type; > + > DBG("conn %p", conn); > > - // XXX: > + if (dbus_message_iter_init(msg, &iter) == FALSE) > + return __connman_error_invalid_arguments(msg); > > - return NULL; > + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) > + return __connman_error_invalid_arguments(msg); > + > + dbus_message_iter_get_basic(&iter, &name); > + dbus_message_iter_next(&iter); > + > + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) > + return __connman_error_invalid_arguments(msg); > + > + dbus_message_iter_recurse(&iter, &value); > + > + type = dbus_message_iter_get_arg_type(&value); > + > + if (g_str_equal(name, "UserRoutes") == TRUE) { > + char **networks; > + int count = 0; > + > + if (type != DBUS_TYPE_ARRAY) > + return __connman_error_invalid_arguments(msg); > + > + networks = get_user_networks(&value, &count); > + if (networks != NULL) { > + g_strfreev(provider->user_networks); > + provider->user_networks = networks; > + provider->num_user_networks = count; > + set_user_networks(provider, provider->user_networks); > + > + provider_property_changed(provider, name, NULL); > + } > + } else > + return __connman_error_invalid_property(msg); > + > + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); > } > > static DBusMessage *clear_property(DBusConnection *conn, DBusMessage *msg, > void *data) > { > + struct vpn_provider *provider = data; > + const char *name; > + > DBG("conn %p", conn); > > - // XXX: > + dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name, > + DBUS_TYPE_INVALID); > > - return NULL; > + if (g_str_equal(name, "UserRoutes") == TRUE) { > + del_routes(provider); > + > + provider_property_changed(provider, name, NULL); > + } else { > + return __connman_error_invalid_property(msg); > + } > + > + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); > } > > static DBusMessage *do_connect(DBusConnection *conn, DBusMessage *msg, > @@ -231,66 +478,6 @@ int __vpn_provider_append_user_route(struct vpn_provider > *provider, > return 0; > } > > -static void set_user_networks(struct vpn_provider *provider, > - char **networks) > -{ > - int i = 0; > - > - while (networks[i] != NULL) { > - char **elems = g_strsplit(networks[i], "/", 0); > - char *network, *netmask; > - int family = PF_UNSPEC, ret; > - > - if (elems == NULL) > - break; > - > - network = elems[0]; > - if (network == NULL || *network == '\0') { > - DBG("no network/netmask set"); > - g_strfreev(elems); > - break; > - } > - > - netmask = elems[1]; > - if (netmask != NULL && *netmask == '\0') { > - DBG("no netmask set"); > - g_strfreev(elems); > - break; > - } > - > - if (g_strrstr(network, ":") != NULL) > - family = AF_INET6; > - else if (g_strrstr(network, ".") != NULL) { > - family = AF_INET; > - > - if (g_strrstr(netmask, ".") == NULL) { > - /* We have netmask length */ > - in_addr_t addr; > - struct in_addr netmask_in; > - unsigned char prefix_len = 32; > - > - if (netmask != NULL) > - prefix_len = atoi(netmask); > - > - addr = 0xffffffff << (32 - prefix_len); > - netmask_in.s_addr = htonl(addr); > - netmask = inet_ntoa(netmask_in); > - > - DBG("network %s netmask %s", network, netmask); > - } > - } > - > - ret = __vpn_provider_append_user_route(provider, > - family, network, netmask); > - g_strfreev(elems); > - > - if (ret != 0) > - break; > - > - i++; > - } > -} > - > static int provider_load_from_keyfile(struct vpn_provider *provider, > GKeyFile *keyfile) > { > @@ -1102,43 +1289,6 @@ static void provider_create_all_from_type(const char > *provider_type) > g_strfreev(providers); > } > > -static char **get_user_networks(DBusMessageIter *array, int *count) > -{ > - DBusMessageIter entry; > - char **networks = NULL; > - GSList *list = NULL, *l; > - int len; > - > - dbus_message_iter_recurse(array, &entry); > - > - while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) { > - const char *val; > - dbus_message_iter_get_basic(&entry, &val); > - > - list = g_slist_prepend(list, g_strdup(val)); > - dbus_message_iter_next(&entry); > - } > - > - len = g_slist_length(list); > - if (len == 0) > - goto out; > - > - networks = g_try_new(char *, len + 1); > - if (networks == NULL) > - goto out; > - > - *count = len; > - networks[len] = 0; > - > - for (l = list; l != NULL; l = g_slist_next(l)) > - networks[--len] = l->data; > - > -out: > - g_slist_free(list); > - > - return networks; > -} > - > int __vpn_provider_create_and_connect(DBusMessage *msg) > { > struct vpn_provider *provider; _______________________________________________ connman mailing list connman@connman.net http://lists.connman.net/listinfo/connman