X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fservice.c;h=ae1f6fd834ab690dd260e5644b48f293e12475bb;hb=72397eb95321ba03392052db5d877ddef79f6d0d;hp=8ea721b5b7b2821cfb746b76dc9ff1269e0a09cc;hpb=d14cf2b39d6e2438f2435cd3c89c3b864cec8734;p=platform%2Fupstream%2Fconnman.git diff --git a/src/service.c b/src/service.c index 8ea721b..ae1f6fd 100644 --- a/src/service.c +++ b/src/service.c @@ -35,40 +35,22 @@ static DBusConnection *connection = NULL; static GSequence *service_list = NULL; static GHashTable *service_hash = NULL; +static GSList *counter_list = NULL; struct connman_stats { connman_bool_t valid; connman_bool_t enabled; - unsigned int rx_packets_update; - unsigned int tx_packets_update; - unsigned int rx_packets_last; - unsigned int tx_packets_last; - unsigned int rx_packets; - unsigned int tx_packets; - unsigned int rx_bytes_update; - unsigned int tx_bytes_update; - unsigned int rx_bytes_last; - unsigned int tx_bytes_last; - unsigned int rx_bytes; - unsigned int tx_bytes; - unsigned int rx_errors_update; - unsigned int tx_errors_update; - unsigned int rx_errors_last; - unsigned int tx_errors_last; - unsigned int rx_errors; - unsigned int tx_errors; - unsigned int rx_dropped_update; - unsigned int tx_dropped_update; - unsigned int rx_dropped_last; - unsigned int tx_dropped_last; - unsigned int rx_dropped; - unsigned int tx_dropped; - unsigned int time_start; - unsigned int time_update; - unsigned int time; + struct connman_stats_data data_last; + struct connman_stats_data data; GTimer *timer; }; +struct connman_stats_counter { + connman_bool_t append_all; + struct connman_stats stats; + struct connman_stats stats_roaming; +}; + struct connman_service { gint refcount; char *identifier; @@ -76,7 +58,8 @@ struct connman_service { enum connman_service_type type; enum connman_service_mode mode; enum connman_service_security security; - enum connman_service_state state; + enum connman_service_state state_ipv4; + enum connman_service_state state_ipv6; enum connman_service_error error; connman_uint8_t strength; connman_bool_t favorite; @@ -90,20 +73,17 @@ struct connman_service { char *name; char *passphrase; char *profile; - char *apn; - char *username; - char *password; - char *mcc; - char *mnc; connman_bool_t roaming; connman_bool_t login_required; - struct connman_ipconfig *ipconfig; + struct connman_ipconfig *ipconfig_ipv4; + struct connman_ipconfig *ipconfig_ipv6; struct connman_network *network; struct connman_provider *provider; char **nameservers; - char *nameserver; + char **nameservers_config; char **domains; char *domainname; + char **timeservers; /* 802.1x settings from the config files */ char *eap; char *identity; @@ -117,6 +97,13 @@ struct connman_service { struct connman_location *location; struct connman_stats stats; struct connman_stats stats_roaming; + GHashTable *counter_table; + enum connman_service_proxy_method proxy; + enum connman_service_proxy_method proxy_config; + char **proxies; + char **excludes; + char *pac; + connman_bool_t wps; }; static void append_path(gpointer value, gpointer user_data) @@ -185,6 +172,8 @@ const char *__connman_service_type2string(enum connman_service_type type) return "gps"; case CONNMAN_SERVICE_TYPE_VPN: return "vpn"; + case CONNMAN_SERVICE_TYPE_GADGET: + return "gadget"; } return NULL; @@ -269,6 +258,12 @@ static const char *error2string(enum connman_service_error error) return "dhcp-failed"; case CONNMAN_SERVICE_ERROR_CONNECT_FAILED: return "connect-failed"; + case CONNMAN_SERVICE_ERROR_LOGIN_FAILED: + return "login-failed"; + case CONNMAN_SERVICE_ERROR_AUTH_FAILED: + return "auth-failed"; + case CONNMAN_SERVICE_ERROR_INVALID_KEY: + return "invalid-key"; } return NULL; @@ -280,16 +275,160 @@ static enum connman_service_error string2error(const char *error) return CONNMAN_SERVICE_ERROR_DHCP_FAILED; else if (g_strcmp0(error, "pin-missing") == 0) return CONNMAN_SERVICE_ERROR_PIN_MISSING; + else if (g_strcmp0(error, "invalid-key") == 0) + return CONNMAN_SERVICE_ERROR_INVALID_KEY; return CONNMAN_SERVICE_ERROR_UNKNOWN; } -static connman_bool_t is_connecting(struct connman_service *service) +static const char *proxymethod2string(enum connman_service_proxy_method method) +{ + switch (method) { + case CONNMAN_SERVICE_PROXY_METHOD_DIRECT: + return "direct"; + case CONNMAN_SERVICE_PROXY_METHOD_MANUAL: + return "manual"; + case CONNMAN_SERVICE_PROXY_METHOD_AUTO: + return "auto"; + case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN: + break; + } + + return NULL; +} + +static enum connman_service_proxy_method string2proxymethod(const char *method) +{ + if (g_strcmp0(method, "direct") == 0) + return CONNMAN_SERVICE_PROXY_METHOD_DIRECT; + else if (g_strcmp0(method, "auto") == 0) + return CONNMAN_SERVICE_PROXY_METHOD_AUTO; + else if (g_strcmp0(method, "manual") == 0) + return CONNMAN_SERVICE_PROXY_METHOD_MANUAL; + else + return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN; +} + +static enum connman_service_state combine_state( + enum connman_service_state state_a, + enum connman_service_state state_b) +{ + enum connman_service_state result; + + if (state_a == state_b) { + result = state_a; + goto done; + } + + if (state_a == CONNMAN_SERVICE_STATE_UNKNOWN) { + result = state_b; + goto done; + } + + if (state_b == CONNMAN_SERVICE_STATE_UNKNOWN) { + result = state_a; + goto done; + } + + if (state_a == CONNMAN_SERVICE_STATE_IDLE) { + result = state_b; + goto done; + } + + if (state_b == CONNMAN_SERVICE_STATE_IDLE) { + result = state_a; + goto done; + } + + if (state_a == CONNMAN_SERVICE_STATE_ASSOCIATION) { + if (state_b == CONNMAN_SERVICE_STATE_CONFIGURATION || + state_b == CONNMAN_SERVICE_STATE_ONLINE || + state_b == CONNMAN_SERVICE_STATE_READY) + result = state_b; + else + result = state_a; + goto done; + } + + if (state_b == CONNMAN_SERVICE_STATE_ASSOCIATION) { + if (state_a == CONNMAN_SERVICE_STATE_CONFIGURATION || + state_a == CONNMAN_SERVICE_STATE_ONLINE || + state_a == CONNMAN_SERVICE_STATE_READY) + result = state_a; + else + result = state_b; + goto done; + } + + if (state_a == CONNMAN_SERVICE_STATE_CONFIGURATION) { + if (state_b == CONNMAN_SERVICE_STATE_ONLINE || + state_b == CONNMAN_SERVICE_STATE_READY) + result = state_b; + else + result = state_a; + goto done; + } + + if (state_b == CONNMAN_SERVICE_STATE_CONFIGURATION) { + if (state_a == CONNMAN_SERVICE_STATE_ONLINE || + state_a == CONNMAN_SERVICE_STATE_READY) + result = state_a; + else + result = state_b; + goto done; + } + + if (state_a == CONNMAN_SERVICE_STATE_READY) { + if (state_b == CONNMAN_SERVICE_STATE_ONLINE) + result = state_b; + else + result = state_a; + goto done; + } + + if (state_b == CONNMAN_SERVICE_STATE_READY) { + if (state_a == CONNMAN_SERVICE_STATE_ONLINE) + result = state_a; + else + result = state_b; + goto done; + } + + if (state_a == CONNMAN_SERVICE_STATE_ONLINE) { + result = state_a; + goto done; + } + + if (state_b == CONNMAN_SERVICE_STATE_ONLINE) { + result = state_b; + goto done; + } + + if (state_a == CONNMAN_SERVICE_STATE_DISCONNECT) { + result = state_b; + goto done; + } + + if (state_b == CONNMAN_SERVICE_STATE_DISCONNECT) { + result = state_a; + goto done; + } + + result = CONNMAN_SERVICE_STATE_FAILURE; + +done: + return result; +} + +static connman_bool_t is_connecting_state(struct connman_service *service, + enum connman_service_state state) { - switch (service->state) { + switch (state) { case CONNMAN_SERVICE_STATE_UNKNOWN: case CONNMAN_SERVICE_STATE_IDLE: case CONNMAN_SERVICE_STATE_FAILURE: + if (service->network != NULL) + return connman_network_get_connecting(service->network); case CONNMAN_SERVICE_STATE_DISCONNECT: case CONNMAN_SERVICE_STATE_READY: case CONNMAN_SERVICE_STATE_ONLINE: @@ -302,9 +441,10 @@ static connman_bool_t is_connecting(struct connman_service *service) return FALSE; } -static connman_bool_t is_connected(const struct connman_service *service) +static connman_bool_t is_connected_state(const struct connman_service *service, + enum connman_service_state state) { - switch (service->state) { + switch (state) { case CONNMAN_SERVICE_STATE_UNKNOWN: case CONNMAN_SERVICE_STATE_IDLE: case CONNMAN_SERVICE_STATE_ASSOCIATION: @@ -320,14 +460,39 @@ static connman_bool_t is_connected(const struct connman_service *service) return FALSE; } +static connman_bool_t is_connecting(struct connman_service *service) +{ + enum connman_service_state state; + + state = combine_state(service->state_ipv4, service->state_ipv6); + + return is_connecting_state(service, state); +} + +static connman_bool_t is_connected(struct connman_service *service) +{ + enum connman_service_state state; + + state = combine_state(service->state_ipv4, service->state_ipv6); + + return is_connected_state(service, state); +} + static void update_nameservers(struct connman_service *service) { - const char *ifname = connman_ipconfig_get_ifname(service->ipconfig); + const char *ifname; + + if (service->ipconfig_ipv4) + ifname = connman_ipconfig_get_ifname(service->ipconfig_ipv4); + else if (service->ipconfig_ipv6) + ifname = connman_ipconfig_get_ifname(service->ipconfig_ipv6); + else + ifname = NULL; if (ifname == NULL) return; - switch (service->state) { + switch (combine_state(service->state_ipv4, service->state_ipv6)) { case CONNMAN_SERVICE_STATE_UNKNOWN: case CONNMAN_SERVICE_STATE_IDLE: case CONNMAN_SERVICE_STATE_ASSOCIATION: @@ -344,59 +509,164 @@ static void update_nameservers(struct connman_service *service) connman_resolver_remove_all(ifname); - if (service->nameservers != NULL) { + if (service->nameservers_config != NULL) { + int i; + + for (i = 0; service->nameservers_config[i] != NULL; i++) { + connman_resolver_append(ifname, NULL, + service->nameservers_config[i]); + } + } else if (service->nameservers != NULL) { int i; - for (i = 0; service->nameservers[i]; i++) + for (i = 0; service->nameservers[i] != NULL; i++) { connman_resolver_append(ifname, NULL, service->nameservers[i]); - } else if (service->nameserver != NULL) - connman_resolver_append(ifname, NULL, service->nameserver); + } + } + + if (service->domains != NULL) { + int i; + + for (i = 0; service->domains[i]; i++) + connman_resolver_append(ifname, service->domains[i], + NULL); + } else if (service->domainname != NULL) + connman_resolver_append(ifname, service->domainname, NULL); connman_resolver_flush(); } -void __connman_service_append_nameserver(struct connman_service *service, +int __connman_service_nameserver_append(struct connman_service *service, const char *nameserver) { - DBG("service %p nameserver %s", service, nameserver); + int len; + + DBG("service %p nameserver %s", service, nameserver); if (nameserver == NULL) - return; + return -EINVAL; + + if (service->nameservers != NULL) { + int i; - g_free(service->nameserver); - service->nameserver = g_strdup(nameserver); + for (i = 0; service->nameservers[i] != NULL; i++) + if (g_strcmp0(service->nameservers[i], nameserver) == 0) + return -EEXIST; + + len = g_strv_length(service->nameservers); + service->nameservers = g_try_renew(char *, service->nameservers, + len + 2); + } else { + len = 0; + service->nameservers = g_try_new0(char *, len + 2); + } + + if (service->nameservers == NULL) + return -ENOMEM; + + service->nameservers[len] = g_strdup(nameserver); + service->nameservers[len + 1] = NULL; update_nameservers(service); + + return 0; } -void __connman_service_remove_nameserver(struct connman_service *service, +int __connman_service_nameserver_remove(struct connman_service *service, const char *nameserver) { + char **servers; + int len, i, j; + DBG("service %p nameserver %s", service, nameserver); if (nameserver == NULL) - return; + return -EINVAL; + + if (service->nameservers == NULL) + return 0; + + len = g_strv_length(service->nameservers); + if (len == 1) { + if (g_strcmp0(service->nameservers[0], nameserver) != 0) + return 0; + + g_strfreev(service->nameservers); + service->nameservers = NULL; + + return 0; + } + + servers = g_try_new0(char *, len - 1); + if (servers == NULL) + return -ENOMEM; + + for (i = 0, j = 0; i < len; i++) { + if (g_strcmp0(service->nameservers[i], nameserver) != 0) { + servers[j] = g_strdup(service->nameservers[i]); + j++; + } + } + servers[len - 2] = NULL; + + g_strfreev(service->nameservers); + service->nameservers = servers; + + update_nameservers(service); - g_free(service->nameserver); - service->nameserver = NULL; + return 0; +} + +void __connman_service_nameserver_clear(struct connman_service *service) +{ + g_strfreev(service->nameservers); + service->nameservers = NULL; update_nameservers(service); } +static void nameserver_add_routes(int index, char **nameservers, + const char *gw) +{ + int i; + + for (i = 0; nameservers[i] != NULL; i++) { + if (connman_inet_compare_subnet(index, nameservers[i])) + continue; + + connman_inet_add_host_route(index, nameservers[i], gw); + } +} + +static void nameserver_del_routes(int index, char **nameservers) +{ + int i; + + for (i = 0; nameservers[i] != NULL; i++) + connman_inet_del_host_route(index, nameservers[i]); +} + void __connman_service_nameserver_add_routes(struct connman_service *service, const char *gw) { - int index; + int index = -1; if (service == NULL) return; - index = connman_network_get_index(service->network); - - if (service->nameservers != NULL) { - int i; + if (service->network != NULL) + index = connman_network_get_index(service->network); + else if (service->provider != NULL) + index = connman_provider_get_index(service->provider); + if (service->nameservers_config != NULL) { + /* + * Configured nameserver takes preference over the + * discoverd nameserver gathered from DHCP, VPN, etc. + */ + nameserver_add_routes(index, service->nameservers_config, gw); + } else if (service->nameservers != NULL) { /* * We add nameservers host routes for nameservers that * are not on our subnet. For those who are, the subnet @@ -404,40 +674,26 @@ void __connman_service_nameserver_add_routes(struct connman_service *service, * tries to reach them. The subnet route is installed * when setting the interface IP address. */ - for (i = 0; service->nameservers[i]; i++) { - if (connman_inet_compare_subnet(index, - service->nameservers[i])) - continue; - - connman_inet_add_host_route(index, - service->nameservers[i], gw); - } - } else if (service->nameserver != NULL) { - if (connman_inet_compare_subnet(index, service->nameserver)) - return; - - connman_inet_add_host_route(index, service->nameserver, gw); + nameserver_add_routes(index, service->nameservers, gw); } } void __connman_service_nameserver_del_routes(struct connman_service *service) { - int index; + int index = -1; if (service == NULL) return; - index = connman_network_get_index(service->network); - - if (service->nameservers != NULL) { - int i; + if (service->network != NULL) + index = connman_network_get_index(service->network); + else if (service->provider != NULL) + index = connman_provider_get_index(service->provider); - for (i = 0; service->nameservers[i]; i++) - connman_inet_del_host_route(index, - service->nameservers[i]); - } else if (service->nameserver != NULL) { - connman_inet_del_host_route(index, service->nameserver); - } + if (service->nameservers_config != NULL) + nameserver_del_routes(index, service->nameservers_config); + else if (service->nameservers != NULL) + nameserver_del_routes(index, service->nameservers); } static struct connman_stats *stats_get(struct connman_service *service) @@ -465,11 +721,9 @@ static void stats_start(struct connman_service *service) return; stats->enabled = TRUE; - stats->time_start = stats->time; + stats->data_last.time = stats->data.time; g_timer_start(stats->timer); - - __connman_counter_add_service(service); } static void stats_stop(struct connman_service *service) @@ -485,106 +739,14 @@ static void stats_stop(struct connman_service *service) if (stats->enabled == FALSE) return; - __connman_counter_remove_service(service); - g_timer_stop(stats->timer); seconds = g_timer_elapsed(stats->timer, NULL); - stats->time = stats->time_start + seconds; + stats->data.time = stats->data_last.time + seconds; stats->enabled = FALSE; } -static int stats_load(struct connman_service *service, GKeyFile *keyfile) -{ - /* home */ - service->stats.rx_packets = g_key_file_get_integer(keyfile, - service->identifier, "Home.rx_packets", NULL); - service->stats.tx_packets = g_key_file_get_integer(keyfile, - service->identifier, "Home.tx_packets", NULL); - service->stats.rx_bytes = g_key_file_get_integer(keyfile, - service->identifier, "Home.rx_bytes", NULL); - service->stats.tx_bytes = g_key_file_get_integer(keyfile, - service->identifier, "Home.tx_bytes", NULL); - service->stats.rx_errors = g_key_file_get_integer(keyfile, - service->identifier, "Home.rx_errors", NULL); - service->stats.tx_errors = g_key_file_get_integer(keyfile, - service->identifier, "Home.tx_errors", NULL); - service->stats.rx_dropped = g_key_file_get_integer(keyfile, - service->identifier, "Home.rx_dropped", NULL); - service->stats.tx_dropped = g_key_file_get_integer(keyfile, - service->identifier, "Home.tx_dropped", NULL); - service->stats.time = g_key_file_get_integer(keyfile, - service->identifier, "Home.time", NULL); - - /* roaming */ - service->stats_roaming.rx_packets = g_key_file_get_integer(keyfile, - service->identifier, "Roaming.rx_packets", NULL); - service->stats_roaming.tx_packets = g_key_file_get_integer(keyfile, - service->identifier, "Roaming.tx_packets", NULL); - service->stats_roaming.rx_bytes = g_key_file_get_integer(keyfile, - service->identifier, "Roaming.rx_bytes", NULL); - service->stats_roaming.tx_bytes = g_key_file_get_integer(keyfile, - service->identifier, "Roaming.tx_bytes", NULL); - service->stats_roaming.rx_errors = g_key_file_get_integer(keyfile, - service->identifier, "Roaming.rx_errors", NULL); - service->stats_roaming.tx_errors = g_key_file_get_integer(keyfile, - service->identifier, "Roaming.tx_errors", NULL); - service->stats_roaming.rx_dropped = g_key_file_get_integer(keyfile, - service->identifier, "Roaming.rx_dropped", NULL); - service->stats_roaming.tx_dropped = g_key_file_get_integer(keyfile, - service->identifier, "Roaming.tx_dropped", NULL); - service->stats_roaming.time = g_key_file_get_integer(keyfile, - service->identifier, "Roaming.time", NULL); - - return 0; -} - -static int stats_save(struct connman_service *service, GKeyFile *keyfile) -{ - /* home */ - g_key_file_set_integer(keyfile, service->identifier, - "Home.rx_packets", service->stats.rx_packets); - g_key_file_set_integer(keyfile, service->identifier, - "Home.tx_packets", service->stats.tx_packets); - g_key_file_set_integer(keyfile, service->identifier, - "Home.rx_bytes", service->stats.rx_bytes); - g_key_file_set_integer(keyfile, service->identifier, - "Home.tx_bytes", service->stats.tx_bytes); - g_key_file_set_integer(keyfile, service->identifier, - "Home.rx_errors", service->stats.rx_errors); - g_key_file_set_integer(keyfile, service->identifier, - "Home.tx_errors", service->stats.tx_errors); - g_key_file_set_integer(keyfile, service->identifier, - "Home.rx_dropped", service->stats.rx_dropped); - g_key_file_set_integer(keyfile, service->identifier, - "Home.tx_dropped", service->stats.tx_dropped); - g_key_file_set_integer(keyfile, service->identifier, - "Home.time", service->stats.time); - - /* roaming */ - g_key_file_set_integer(keyfile, service->identifier, - "Roaming.rx_packets", service->stats_roaming.rx_packets); - g_key_file_set_integer(keyfile, service->identifier, - "Roaming.tx_packets", service->stats_roaming.tx_packets); - g_key_file_set_integer(keyfile, service->identifier, - "Roaming.rx_bytes", service->stats_roaming.rx_bytes); - g_key_file_set_integer(keyfile, service->identifier, - "Roaming.tx_bytes", service->stats_roaming.tx_bytes); - g_key_file_set_integer(keyfile, service->identifier, - "Roaming.rx_errors", service->stats_roaming.rx_errors); - g_key_file_set_integer(keyfile, service->identifier, - "Roaming.tx_errors", service->stats_roaming.tx_errors); - g_key_file_set_integer(keyfile, service->identifier, - "Roaming.rx_dropped", service->stats_roaming.rx_dropped); - g_key_file_set_integer(keyfile, service->identifier, - "Roaming.tx_dropped", service->stats_roaming.tx_dropped); - g_key_file_set_integer(keyfile, service->identifier, - "Roaming.time", service->stats_roaming.time); - - return 0; -} - static void reset_stats(struct connman_service *service) { DBG("service %p", service); @@ -592,52 +754,32 @@ static void reset_stats(struct connman_service *service) /* home */ service->stats.valid = FALSE; - service->stats.rx_packets = 0; - service->stats.tx_packets = 0; - service->stats.rx_bytes = 0; - service->stats.tx_bytes = 0; - service->stats.rx_errors = 0; - service->stats.tx_errors = 0; - service->stats.rx_dropped = 0; - service->stats.tx_dropped = 0; - service->stats.time = 0; - service->stats.time_start = 0; - - service->stats.rx_packets_update = 0; - service->stats.tx_packets_update = 0; - service->stats.rx_bytes_update = 0; - service->stats.tx_bytes_update = 0; - service->stats.rx_errors_update = 0; - service->stats.tx_errors_update = 0; - service->stats.rx_dropped_update = 0; - service->stats.tx_dropped_update = 0; - service->stats.time_update = 0; + service->stats.data.rx_packets = 0; + service->stats.data.tx_packets = 0; + service->stats.data.rx_bytes = 0; + service->stats.data.tx_bytes = 0; + service->stats.data.rx_errors = 0; + service->stats.data.tx_errors = 0; + service->stats.data.rx_dropped = 0; + service->stats.data.tx_dropped = 0; + service->stats.data.time = 0; + service->stats.data_last.time = 0; g_timer_reset(service->stats.timer); /* roaming */ service->stats_roaming.valid = FALSE; - service->stats_roaming.rx_packets = 0; - service->stats_roaming.tx_packets = 0; - service->stats_roaming.rx_bytes = 0; - service->stats_roaming.tx_bytes = 0; - service->stats_roaming.rx_errors = 0; - service->stats_roaming.tx_errors = 0; - service->stats_roaming.rx_dropped = 0; - service->stats_roaming.tx_dropped = 0; - service->stats_roaming.time = 0; - service->stats_roaming.time_start = 0; - - service->stats_roaming.rx_packets_update = 0; - service->stats_roaming.tx_packets_update = 0; - service->stats_roaming.rx_bytes_update = 0; - service->stats_roaming.tx_bytes_update = 0; - service->stats_roaming.rx_errors_update = 0; - service->stats_roaming.tx_errors_update = 0; - service->stats_roaming.rx_dropped_update = 0; - service->stats_roaming.tx_dropped_update = 0; - service->stats_roaming.time_update = 0; + service->stats_roaming.data.rx_packets = 0; + service->stats_roaming.data.tx_packets = 0; + service->stats_roaming.data.rx_bytes = 0; + service->stats_roaming.data.tx_bytes = 0; + service->stats_roaming.data.rx_errors = 0; + service->stats_roaming.data.tx_errors = 0; + service->stats_roaming.data.rx_dropped = 0; + service->stats_roaming.data.tx_dropped = 0; + service->stats_roaming.data.time = 0; + service->stats_roaming.data_last.time = 0; g_timer_reset(service->stats_roaming.timer); } @@ -695,7 +837,8 @@ static void state_changed(struct connman_service *service) { const char *str; - str = state2string(service->state); + str = state2string(combine_state(service->state_ipv4, + service->state_ipv6)); if (str == NULL) return; @@ -767,6 +910,7 @@ static void passphrase_changed(struct connman_service *service) case CONNMAN_SERVICE_TYPE_CELLULAR: case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_VPN: + case CONNMAN_SERVICE_TYPE_GADGET: return; case CONNMAN_SERVICE_TYPE_WIFI: required = FALSE; @@ -805,89 +949,92 @@ static void login_changed(struct connman_service *service) DBUS_TYPE_BOOLEAN, &required); } -static void apn_changed(struct connman_service *service) +static void append_security(DBusMessageIter *iter, void *user_data) { - dbus_bool_t required; - - switch (service->type) { - case CONNMAN_SERVICE_TYPE_UNKNOWN: - case CONNMAN_SERVICE_TYPE_SYSTEM: - case CONNMAN_SERVICE_TYPE_ETHERNET: - case CONNMAN_SERVICE_TYPE_WIMAX: - case CONNMAN_SERVICE_TYPE_BLUETOOTH: - case CONNMAN_SERVICE_TYPE_WIFI: - case CONNMAN_SERVICE_TYPE_GPS: - case CONNMAN_SERVICE_TYPE_VPN: - return; - case CONNMAN_SERVICE_TYPE_CELLULAR: - break; - } + struct connman_service *service = user_data; + const char *str; - required = (service->apn == NULL) ? TRUE : FALSE; + str = security2string(service->security); + if (str != NULL) + dbus_message_iter_append_basic(iter, + DBUS_TYPE_STRING, &str); - connman_dbus_property_changed_basic(service->path, - CONNMAN_SERVICE_INTERFACE, "SetupRequired", - DBUS_TYPE_BOOLEAN, &required); + str = "wps"; + if (service->wps == TRUE) + dbus_message_iter_append_basic(iter, + DBUS_TYPE_STRING, &str); } static void append_ethernet(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; - if (service->ipconfig != NULL) - __connman_ipconfig_append_ethernet(service->ipconfig, iter); + if (service->ipconfig_ipv4 != NULL) + __connman_ipconfig_append_ethernet(service->ipconfig_ipv4, + iter); + else if (service->ipconfig_ipv6 != NULL) + __connman_ipconfig_append_ethernet(service->ipconfig_ipv6, + iter); } static void append_ipv4(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; - if (is_connected(service) == FALSE) + DBG("ipv4 %p state %s", service->ipconfig_ipv4, + state2string(service->state_ipv4)); + + if (is_connected_state(service, service->state_ipv4) == FALSE) return; - if (service->ipconfig != NULL) - __connman_ipconfig_append_ipv4(service->ipconfig, iter); + if (service->ipconfig_ipv4 != NULL) + __connman_ipconfig_append_ipv4(service->ipconfig_ipv4, iter); } static void append_ipv6(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; - struct connman_ipconfig *ipv6config; - - if (is_connected(service) == FALSE) - return; - if (service->ipconfig == NULL) - return; + DBG("ipv6 %p state %s", service->ipconfig_ipv6, + state2string(service->state_ipv6)); - ipv6config = connman_ipconfig_get_ipv6config(service->ipconfig); - if (ipv6config == NULL) + if (is_connected_state(service, service->state_ipv6) == FALSE) return; - __connman_ipconfig_append_ipv6(ipv6config, iter); + if (service->ipconfig_ipv6 != NULL) + __connman_ipconfig_append_ipv6(service->ipconfig_ipv6, iter, + service->ipconfig_ipv4); } static void append_ipv4config(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; - if (service->ipconfig != NULL) - __connman_ipconfig_append_ipv4config(service->ipconfig, iter); + if (service->ipconfig_ipv4 != NULL) + __connman_ipconfig_append_ipv4config(service->ipconfig_ipv4, + iter); } static void append_ipv6config(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; - struct connman_ipconfig *ipv6config; - if (service->ipconfig == NULL) - return; + if (service->ipconfig_ipv6 != NULL) + __connman_ipconfig_append_ipv6config(service->ipconfig_ipv6, + iter); +} - ipv6config = connman_ipconfig_get_ipv6config(service->ipconfig); - if (ipv6config == NULL) - return; +static void append_nameserver(DBusMessageIter *iter, char ***nameservers) +{ + char **servers; + int i; + + servers = *nameservers; - __connman_ipconfig_append_ipv6config(ipv6config, iter); + for (i = 0; servers[i] != NULL; i++) { + dbus_message_iter_append_basic(iter, + DBUS_TYPE_STRING, &servers[i]); + } } static void append_dns(DBusMessageIter *iter, void *user_data) @@ -897,21 +1044,13 @@ static void append_dns(DBusMessageIter *iter, void *user_data) if (is_connected(service) == FALSE) return; - if (service->nameservers != NULL) { - int i; - - for (i = 0; service->nameservers[i]; i++) - dbus_message_iter_append_basic(iter, - DBUS_TYPE_STRING, &service->nameservers[i]); - + if (service->nameservers_config != NULL) { + append_nameserver(iter, &service->nameservers_config); return; - } - - if (service->nameserver == NULL) + } else if (service->nameservers != NULL) { + append_nameserver(iter, &service->nameservers); return; - - dbus_message_iter_append_basic(iter, - DBUS_TYPE_STRING, &service->nameserver); + } } static void append_dnsconfig(DBusMessageIter *iter, void *user_data) @@ -919,19 +1058,22 @@ static void append_dnsconfig(DBusMessageIter *iter, void *user_data) struct connman_service *service = user_data; int i; - if (service->nameservers == NULL) + if (service->nameservers_config == NULL) return; - for (i = 0; service->nameservers[i]; i++) + for (i = 0; service->nameservers_config[i]; i++) { dbus_message_iter_append_basic(iter, - DBUS_TYPE_STRING, &service->nameservers[i]); + DBUS_TYPE_STRING, + &service->nameservers_config[i]); + } } static void append_domain(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; - if (is_connected(service) == FALSE && is_connecting(service) == FALSE) + if (is_connected(service) == FALSE && + is_connecting(service) == FALSE) return; if (service->domainname == NULL) @@ -954,22 +1096,130 @@ static void append_domainconfig(DBusMessageIter *iter, void *user_data) DBUS_TYPE_STRING, &service->domains[i]); } -static void append_proxy(DBusMessageIter *iter, void *user_data) +static void append_proxies(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; + int i; - if (is_connected(service) == FALSE) + if (service->proxies == NULL) return; - if (service->ipconfig != NULL) - __connman_ipconfig_append_proxy(service->ipconfig, iter); + for (i = 0; service->proxies[i]; i++) + dbus_message_iter_append_basic(iter, + DBUS_TYPE_STRING, &service->proxies[i]); } -static void append_provider(DBusMessageIter *iter, void *user_data) +static void append_excludes(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; + int i; - DBG("%p %p", service, service->provider); + if (service->excludes == NULL) + return; + + for (i = 0; service->excludes[i]; i++) + dbus_message_iter_append_basic(iter, + DBUS_TYPE_STRING, &service->excludes[i]); +} + +static void append_proxy(DBusMessageIter *iter, void *user_data) +{ + struct connman_service *service = user_data; + enum connman_service_proxy_method proxy; + const char *pac = NULL; + const char *method = proxymethod2string( + CONNMAN_SERVICE_PROXY_METHOD_DIRECT); + + DBG(""); + + if (is_connected(service) == FALSE) + return; + + proxy = connman_service_get_proxy_method(service); + + switch (proxy) { + case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN: + return; + case CONNMAN_SERVICE_PROXY_METHOD_DIRECT: + goto done; + case CONNMAN_SERVICE_PROXY_METHOD_MANUAL: + connman_dbus_dict_append_array(iter, "Servers", + DBUS_TYPE_STRING, append_proxies, + service); + + connman_dbus_dict_append_array(iter, "Excludes", + DBUS_TYPE_STRING, append_excludes, + service); + break; + case CONNMAN_SERVICE_PROXY_METHOD_AUTO: + /* Maybe DHCP, or WPAD, has provided an url for a pac file */ + if (service->ipconfig_ipv4 != NULL) + pac = __connman_ipconfig_get_proxy_autoconfig( + service->ipconfig_ipv4); + else if (service->ipconfig_ipv6 != NULL) + pac = __connman_ipconfig_get_proxy_autoconfig( + service->ipconfig_ipv6); + + if (service->pac == NULL && pac == NULL) + goto done; + + if (service->pac != NULL) + pac = service->pac; + + connman_dbus_dict_append_basic(iter, "URL", + DBUS_TYPE_STRING, &pac); + break; + } + + method = proxymethod2string(proxy); + +done: + connman_dbus_dict_append_basic(iter, "Method", + DBUS_TYPE_STRING, &method); +} + +static void append_proxyconfig(DBusMessageIter *iter, void *user_data) +{ + struct connman_service *service = user_data; + const char *method; + + if (service->proxy_config == CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN) + return; + + switch (service->proxy_config) { + case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN: + return; + case CONNMAN_SERVICE_PROXY_METHOD_DIRECT: + break; + case CONNMAN_SERVICE_PROXY_METHOD_MANUAL: + if (service->proxies != NULL) + connman_dbus_dict_append_array(iter, "Servers", + DBUS_TYPE_STRING, + append_proxies, service); + + if (service->excludes != NULL) + connman_dbus_dict_append_array(iter, "Excludes", + DBUS_TYPE_STRING, + append_excludes, service); + break; + case CONNMAN_SERVICE_PROXY_METHOD_AUTO: + if (service->pac != NULL) + connman_dbus_dict_append_basic(iter, "URL", + DBUS_TYPE_STRING, &service->pac); + break; + } + + method = proxymethod2string(service->proxy_config); + + connman_dbus_dict_append_basic(iter, "Method", + DBUS_TYPE_STRING, &method); +} + +static void append_provider(DBusMessageIter *iter, void *user_data) +{ + struct connman_service *service = user_data; + + DBG("%p %p", service, service->provider); if (is_connected(service) == FALSE) return; @@ -1047,6 +1297,15 @@ static void proxy_changed(struct connman_service *service) append_proxy, service); } +static void proxy_configuration_changed(struct connman_service *service) +{ + connman_dbus_property_changed_dict(service->path, + CONNMAN_SERVICE_INTERFACE, "Proxy.Configuration", + append_proxyconfig, service); + + proxy_changed(service); +} + static void link_changed(struct connman_service *service) { connman_dbus_property_changed_dict(service->path, @@ -1054,86 +1313,240 @@ static void link_changed(struct connman_service *service) append_ethernet, service); } -static void stats_append(DBusMessageIter *dict, - struct connman_stats *stats, +static void stats_append_counters(DBusMessageIter *dict, + struct connman_stats_data *stats, + struct connman_stats_data *counters, connman_bool_t append_all) { - if (stats->rx_packets_update != stats->rx_packets || append_all) { - stats->rx_packets_update = stats->rx_packets; + if (counters->rx_packets != stats->rx_packets || append_all) { + counters->rx_packets = stats->rx_packets; connman_dbus_dict_append_basic(dict, "RX.Packets", DBUS_TYPE_UINT32, &stats->rx_packets); } - if (stats->tx_packets_update != stats->tx_packets || append_all) { - stats->tx_packets_update = stats->tx_packets; + if (counters->tx_packets != stats->tx_packets || append_all) { + counters->tx_packets = stats->tx_packets; connman_dbus_dict_append_basic(dict, "TX.Packets", DBUS_TYPE_UINT32, &stats->tx_packets); } - if (stats->rx_bytes_update != stats->rx_bytes || append_all) { - stats->rx_bytes_update = stats->rx_bytes; + if (counters->rx_bytes != stats->rx_bytes || append_all) { + counters->rx_bytes = stats->rx_bytes; connman_dbus_dict_append_basic(dict, "RX.Bytes", DBUS_TYPE_UINT32, &stats->rx_bytes); } - if (stats->tx_bytes_update != stats->tx_bytes || append_all) { - stats->tx_bytes_update = stats->tx_bytes; + if (counters->tx_bytes != stats->tx_bytes || append_all) { + counters->tx_bytes = stats->tx_bytes; connman_dbus_dict_append_basic(dict, "TX.Bytes", DBUS_TYPE_UINT32, &stats->tx_bytes); } - if (stats->rx_errors_update != stats->rx_errors || append_all) { - stats->rx_errors_update = stats->rx_errors; + if (counters->rx_errors != stats->rx_errors || append_all) { + counters->rx_errors = stats->rx_errors; connman_dbus_dict_append_basic(dict, "RX.Errors", DBUS_TYPE_UINT32, &stats->rx_errors); } - if (stats->tx_errors_update != stats->tx_errors || append_all) { - stats->tx_errors_update = stats->tx_errors; + if (counters->tx_errors != stats->tx_errors || append_all) { + counters->tx_errors = stats->tx_errors; connman_dbus_dict_append_basic(dict, "TX.Errors", DBUS_TYPE_UINT32, &stats->tx_errors); } - if (stats->rx_dropped_update != stats->rx_dropped || append_all) { - stats->rx_dropped_update = stats->rx_dropped; + if (counters->rx_dropped != stats->rx_dropped || append_all) { + counters->rx_dropped = stats->rx_dropped; connman_dbus_dict_append_basic(dict, "RX.Dropped", DBUS_TYPE_UINT32, &stats->rx_dropped); } - if (stats->tx_dropped_update != stats->tx_dropped || append_all) { - stats->tx_dropped_update = stats->tx_dropped; + if (counters->tx_dropped != stats->tx_dropped || append_all) { + counters->tx_dropped = stats->tx_dropped; connman_dbus_dict_append_basic(dict, "TX.Dropped", DBUS_TYPE_UINT32, &stats->tx_dropped); } - if (stats->time_update != stats->time || append_all) { - stats->time_update = stats->time; + if (counters->time != stats->time || append_all) { + counters->time = stats->time; connman_dbus_dict_append_basic(dict, "Time", DBUS_TYPE_UINT32, &stats->time); } } -void __connman_service_stats_append(struct connman_service *service, - DBusMessage *msg, - connman_bool_t append_all) +static void stats_append(struct connman_service *service, + const char *counter, + struct connman_stats_counter *counters, + connman_bool_t append_all) { DBusMessageIter array, dict; + DBusMessage *msg; + + DBG("service %p counter %s", service, counter); + + msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL); + if (msg == NULL) + return; + + dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, + &service->path, DBUS_TYPE_INVALID); dbus_message_iter_init_append(msg, &array); /* home counter */ connman_dbus_dict_open(&array, &dict); - stats_append(&dict, &service->stats, append_all); + stats_append_counters(&dict, &service->stats.data, + &counters->stats.data, append_all); connman_dbus_dict_close(&array, &dict); /* roaming counter */ connman_dbus_dict_open(&array, &dict); - stats_append(&dict, &service->stats_roaming, append_all); + stats_append_counters(&dict, &service->stats_roaming.data, + &counters->stats_roaming.data, append_all); connman_dbus_dict_close(&array, &dict); + + __connman_counter_send_usage(counter, msg); +} + +static void stats_update(struct connman_service *service, + unsigned int rx_packets, unsigned int tx_packets, + unsigned int rx_bytes, unsigned int tx_bytes, + unsigned int rx_errors, unsigned int tx_errors, + unsigned int rx_dropped, unsigned int tx_dropped) +{ + struct connman_stats *stats = stats_get(service); + struct connman_stats_data *data_last = &stats->data_last; + struct connman_stats_data *data = &stats->data; + unsigned int seconds; + + DBG("service %p", service); + + if (stats->valid == TRUE) { + data->rx_packets += + rx_packets - data_last->rx_packets; + data->tx_packets += + tx_packets - data_last->tx_packets; + data->rx_bytes += + rx_bytes - data_last->rx_bytes; + data->tx_bytes += + tx_bytes - data_last->tx_bytes; + data->rx_errors += + rx_errors - data_last->rx_errors; + data->tx_errors += + tx_errors - data_last->tx_errors; + data->rx_dropped += + rx_dropped - data_last->rx_dropped; + data->tx_dropped += + tx_dropped - data_last->tx_dropped; + } else { + stats->valid = TRUE; + } + + data_last->rx_packets = rx_packets; + data_last->tx_packets = tx_packets; + data_last->rx_bytes = rx_bytes; + data_last->tx_bytes = tx_bytes; + data_last->rx_errors = rx_errors; + data_last->tx_errors = tx_errors; + data_last->rx_dropped = rx_dropped; + data_last->tx_dropped = tx_dropped; + + seconds = g_timer_elapsed(stats->timer, NULL); + stats->data.time = stats->data_last.time + seconds; +} + +void __connman_service_notify(struct connman_service *service, + unsigned int rx_packets, unsigned int tx_packets, + unsigned int rx_bytes, unsigned int tx_bytes, + unsigned int rx_errors, unsigned int tx_errors, + unsigned int rx_dropped, unsigned int tx_dropped) +{ + GHashTableIter iter; + gpointer key, value; + const char *counter; + struct connman_stats_counter *counters; + struct connman_stats_data *data; + int err; + + if (service == NULL) + return; + + if (is_connected(service) == FALSE) + return; + + stats_update(service, + rx_packets, tx_packets, + rx_bytes, tx_bytes, + rx_errors, tx_errors, + rx_dropped, tx_dropped); + + data = &stats_get(service)->data; + err = __connman_stats_update(service, service->roaming, data); + if (err < 0) + connman_error("Failed to store statistics for %s", + service->identifier); + + g_hash_table_iter_init(&iter, service->counter_table); + while (g_hash_table_iter_next(&iter, &key, &value)) { + counter = key; + counters = value; + + stats_append(service, counter, counters, counters->append_all); + counters->append_all = FALSE; + } +} + +int __connman_service_counter_register(const char *counter) +{ + struct connman_service *service; + GSequenceIter *iter; + struct connman_stats_counter *counters; + + DBG("counter %s", counter); + + counter_list = g_slist_append(counter_list, (gpointer)counter); + + iter = g_sequence_get_begin_iter(service_list); + + while (g_sequence_iter_is_end(iter) == FALSE) { + service = g_sequence_get(iter); + + counters = g_try_new0(struct connman_stats_counter, 1); + if (counters == NULL) + return -ENOMEM; + + counters->append_all = TRUE; + + g_hash_table_replace(service->counter_table, (gpointer)counter, + counters); + + iter = g_sequence_iter_next(iter); + } + + return 0; +} + +void __connman_service_counter_unregister(const char *counter) +{ + struct connman_service *service; + GSequenceIter *iter; + + DBG("counter %s", counter); + + iter = g_sequence_get_begin_iter(service_list); + + while (g_sequence_iter_is_end(iter) == FALSE) { + service = g_sequence_get(iter); + + g_hash_table_remove(service->counter_table, counter); + + iter = g_sequence_iter_next(iter); + } + + counter_list = g_slist_remove(counter_list, counter); } static void append_properties(DBusMessageIter *dict, dbus_bool_t limited, @@ -1152,12 +1565,11 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited, connman_dbus_dict_append_basic(dict, "Mode", DBUS_TYPE_STRING, &str); - str = security2string(service->security); - if (str != NULL) - connman_dbus_dict_append_basic(dict, "Security", - DBUS_TYPE_STRING, &str); + connman_dbus_dict_append_array(dict, "Security", + DBUS_TYPE_STRING, append_security, service); - str = state2string(service->state); + str = state2string(combine_state(service->state_ipv4, + service->state_ipv6)); if (str != NULL) connman_dbus_dict_append_basic(dict, "State", DBUS_TYPE_STRING, &str); @@ -1196,36 +1608,13 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited, case CONNMAN_SERVICE_TYPE_SYSTEM: case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_VPN: + case CONNMAN_SERVICE_TYPE_GADGET: break; case CONNMAN_SERVICE_TYPE_CELLULAR: connman_dbus_dict_append_basic(dict, "Roaming", DBUS_TYPE_BOOLEAN, &service->roaming); - if (service->mcc != NULL && service->mnc != NULL) { - connman_dbus_dict_append_basic(dict, "MCC", - DBUS_TYPE_STRING, &service->mcc); - connman_dbus_dict_append_basic(dict, "MNC", - DBUS_TYPE_STRING, &service->mnc); - } - - if (service->apn != NULL) { - connman_dbus_dict_append_basic(dict, "APN", - DBUS_TYPE_STRING, &service->apn); - - if (service->username != NULL) - connman_dbus_dict_append_basic(dict, - "Username", DBUS_TYPE_STRING, - &service->username); - - if (service->password != NULL) - connman_dbus_dict_append_basic(dict, - "Password", DBUS_TYPE_STRING, - &service->password); - - required = FALSE; - } else - required = TRUE; - + required = FALSE; connman_dbus_dict_append_basic(dict, "SetupRequired", DBUS_TYPE_BOOLEAN, &required); connman_dbus_dict_append_dict(dict, "Ethernet", @@ -1255,6 +1644,7 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited, connman_dbus_dict_append_basic(dict, "PassphraseRequired", DBUS_TYPE_BOOLEAN, &required); + /* fall through */ case CONNMAN_SERVICE_TYPE_ETHERNET: case CONNMAN_SERVICE_TYPE_WIMAX: @@ -1264,131 +1654,572 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited, break; } - connman_dbus_dict_append_dict(dict, "IPv4", append_ipv4, service); + connman_dbus_dict_append_dict(dict, "IPv4", append_ipv4, service); + + connman_dbus_dict_append_dict(dict, "IPv4.Configuration", + append_ipv4config, service); + + connman_dbus_dict_append_dict(dict, "IPv6", append_ipv6, service); + + connman_dbus_dict_append_dict(dict, "IPv6.Configuration", + append_ipv6config, service); + + connman_dbus_dict_append_array(dict, "Nameservers", + DBUS_TYPE_STRING, append_dns, service); + + connman_dbus_dict_append_array(dict, "Nameservers.Configuration", + DBUS_TYPE_STRING, append_dnsconfig, service); + + connman_dbus_dict_append_array(dict, "Domains", + DBUS_TYPE_STRING, append_domain, service); + + connman_dbus_dict_append_array(dict, "Domains.Configuration", + DBUS_TYPE_STRING, append_domainconfig, service); + + connman_dbus_dict_append_dict(dict, "Proxy", append_proxy, service); + + connman_dbus_dict_append_dict(dict, "Proxy.Configuration", + append_proxyconfig, service); + + connman_dbus_dict_append_dict(dict, "Provider", + append_provider, service); +} + +static void append_struct(gpointer value, gpointer user_data) +{ + struct connman_service *service = value; + DBusMessageIter *iter = user_data; + DBusMessageIter entry, dict; + + if (service->path == NULL || service->hidden == TRUE) + return; + + dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH, + &service->path); + + connman_dbus_dict_open(&entry, &dict); + append_properties(&dict, TRUE, service); + connman_dbus_dict_close(&entry, &dict); + + dbus_message_iter_close_container(iter, &entry); +} + +void __connman_service_list_struct(DBusMessageIter *iter) +{ + g_sequence_foreach(service_list, append_struct, iter); +} + +int __connman_service_get_index(struct connman_service *service) +{ + if (service == NULL) + return -1; + + if (service->network != NULL) + return connman_network_get_index(service->network); + else if (service->provider != NULL) + return connman_provider_get_index(service->provider); + + return -1; +} + +void __connman_service_set_domainname(struct connman_service *service, + const char *domainname) +{ + if (service == NULL) + return; + + g_free(service->domainname); + service->domainname = g_strdup(domainname); + + domain_changed(service); +} + +const char *connman_service_get_domainname(struct connman_service *service) +{ + if (service == NULL) + return NULL; + + if (service->domains != NULL) + return service->domains[0]; + else + return service->domainname; +} + +char **connman_service_get_nameservers(struct connman_service *service) +{ + if (service == NULL) + return NULL; + + if (service->nameservers_config != NULL) + return service->nameservers_config; + else if (service->nameservers != NULL) + return service->nameservers; + + return NULL; +} + +void connman_service_set_proxy_method(struct connman_service *service, + enum connman_service_proxy_method method) +{ + if (service == NULL) + return; + + service->proxy = method; + + proxy_changed(service); + + if (method != CONNMAN_SERVICE_PROXY_METHOD_AUTO) + __connman_notifier_proxy_changed(service); +} + +enum connman_service_proxy_method connman_service_get_proxy_method( + struct connman_service *service) +{ + if (service == NULL) + return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN; + + if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN) { + if (service->proxy_config == CONNMAN_SERVICE_PROXY_METHOD_AUTO && + service->pac == NULL) + return service->proxy; + + return service->proxy_config; + } + + return service->proxy; +} + +char **connman_service_get_proxy_servers(struct connman_service *service) +{ + return g_strdupv(service->proxies); +} + +char **connman_service_get_proxy_excludes(struct connman_service *service) +{ + return g_strdupv(service->excludes); +} + +const char *connman_service_get_proxy_url(struct connman_service *service) +{ + if (service == NULL) + return NULL; + + return service->pac; +} + +void __connman_service_set_proxy_autoconfig(struct connman_service *service, + const char *url) +{ + if (service == NULL) + return; + + service->proxy = CONNMAN_SERVICE_PROXY_METHOD_AUTO; + + if (service->ipconfig_ipv4) { + if (__connman_ipconfig_set_proxy_autoconfig( + service->ipconfig_ipv4, url) < 0) + return; + } else if (service->ipconfig_ipv6) { + if (__connman_ipconfig_set_proxy_autoconfig( + service->ipconfig_ipv6, url) < 0) + return; + } else + return; + + proxy_changed(service); + + __connman_notifier_proxy_changed(service); +} + +const char *connman_service_get_proxy_autoconfig(struct connman_service *service) +{ + if (service == NULL) + return NULL; + + if (service->ipconfig_ipv4) + return __connman_ipconfig_get_proxy_autoconfig( + service->ipconfig_ipv4); + else if (service->ipconfig_ipv6) + return __connman_ipconfig_get_proxy_autoconfig( + service->ipconfig_ipv6); + return NULL; +} + +static void update_timeservers(struct connman_service *service) +{ + int i; + + if (service->timeservers == NULL) + return; + + switch (combine_state(service->state_ipv4, service->state_ipv6)) { + case CONNMAN_SERVICE_STATE_UNKNOWN: + case CONNMAN_SERVICE_STATE_IDLE: + case CONNMAN_SERVICE_STATE_ASSOCIATION: + case CONNMAN_SERVICE_STATE_CONFIGURATION: + return; + case CONNMAN_SERVICE_STATE_FAILURE: + case CONNMAN_SERVICE_STATE_DISCONNECT: + for (i = 0; service->timeservers[i] != NULL; i++) + connman_timeserver_remove(service->timeservers[i]); + return; + case CONNMAN_SERVICE_STATE_READY: + case CONNMAN_SERVICE_STATE_ONLINE: + break; + } + + for (i = 0; service->timeservers[i] != NULL; i++) + connman_timeserver_append(service->timeservers[i]); +} + +int __connman_service_timeserver_append(struct connman_service *service, + const char *timeserver) +{ + int len; + + DBG("service %p timeserver %s", service, timeserver); + + if (timeserver == NULL) + return -EINVAL; + + if (service->timeservers != NULL) { + int i; + + for (i = 0; service->timeservers[i] != NULL; i++) + if (g_strcmp0(service->timeservers[i], timeserver) == 0) + return -EEXIST; + + len = g_strv_length(service->timeservers); + service->timeservers = g_try_renew(char *, service->timeservers, + len + 2); + } else { + len = 0; + service->timeservers = g_try_new0(char *, len + 2); + } + + if (service->timeservers == NULL) + return -ENOMEM; + + service->timeservers[len] = g_strdup(timeserver); + service->timeservers[len + 1] = NULL; + + update_timeservers(service); + + return 0; +} + +int __connman_service_timeserver_remove(struct connman_service *service, + const char *timeserver) +{ + char **servers; + int len, i, j; + + DBG("service %p timeserver %s", service, timeserver); + + if (timeserver == NULL) + return -EINVAL; + + if (service->timeservers == NULL) + return 0; + + len = g_strv_length(service->timeservers); + if (len == 1) { + if (g_strcmp0(service->timeservers[0], timeserver) != 0) + return 0; + + g_strfreev(service->timeservers); + service->timeservers = NULL; + + return 0; + } + + servers = g_try_new0(char *, len - 1); + if (servers == NULL) + return -ENOMEM; + + for (i = 0, j = 0; i < len; i++) { + if (g_strcmp0(service->timeservers[i], timeserver) != 0) { + servers[j] = g_strdup(service->timeservers[i]); + j++; + } + } + servers[len - 2] = NULL; + + g_strfreev(service->timeservers); + service->timeservers = servers; + + update_timeservers(service); + + return 0; +} + +void __connman_service_set_pac(struct connman_service *service, + const char *pac) +{ + if (pac == NULL) + return; + + g_free(service->pac); + service->pac = g_strdup(pac); +} + +void __connman_service_set_passphrase(struct connman_service *service, + const char* passphrase) +{ + if (service->immutable == TRUE) + return; + + g_free(service->passphrase); + service->passphrase = g_strdup(passphrase); + + passphrase_changed(service); + + if (service->network != NULL) + connman_network_set_string(service->network, + "WiFi.Passphrase", + service->passphrase); + + __connman_storage_save_service(service); +} + +static DBusMessage *get_properties(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + struct connman_service *service = user_data; + DBusMessage *reply; + DBusMessageIter array, dict; + + DBG("service %p", service); + + reply = dbus_message_new_method_return(msg); + if (reply == NULL) + return NULL; + + dbus_message_iter_init_append(reply, &array); + + connman_dbus_dict_open(&array, &dict); + append_properties(&dict, FALSE, service); + connman_dbus_dict_close(&array, &dict); + + return reply; +} + +static int update_proxy_configuration(struct connman_service *service, + DBusMessageIter *array) +{ + DBusMessageIter dict; + enum connman_service_proxy_method method; + GString *servers_str = NULL; + GString *excludes_str = NULL; + const char *url = NULL; + + method = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN; + + dbus_message_iter_recurse(array, &dict); + + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, variant; + const char *key; + int type; + + dbus_message_iter_recurse(&dict, &entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) + goto error; + + dbus_message_iter_get_basic(&entry, &key); + dbus_message_iter_next(&entry); + + if (dbus_message_iter_get_arg_type(&entry) != + DBUS_TYPE_VARIANT) + goto error; + + dbus_message_iter_recurse(&entry, &variant); + type = dbus_message_iter_get_arg_type(&variant); + + if (g_str_equal(key, "Method") == TRUE) { + const char *val; + + if (type != DBUS_TYPE_STRING) + goto error; + + dbus_message_iter_get_basic(&variant, &val); + method = string2proxymethod(val); + } else if (g_str_equal(key, "URL") == TRUE) { + if (type != DBUS_TYPE_STRING) + goto error; + + dbus_message_iter_get_basic(&variant, &url); + } else if (g_str_equal(key, "Servers") == TRUE) { + DBusMessageIter str_array; + + if (type != DBUS_TYPE_ARRAY) + goto error; + + servers_str = g_string_new(NULL); + if (servers_str == NULL) + goto error; - connman_dbus_dict_append_dict(dict, "IPv4.Configuration", - append_ipv4config, service); + dbus_message_iter_recurse(&variant, &str_array); - connman_dbus_dict_append_dict(dict, "IPv6", append_ipv6, service); + while (dbus_message_iter_get_arg_type(&str_array) == + DBUS_TYPE_STRING) { + char *val = NULL; - connman_dbus_dict_append_dict(dict, "IPv6.Configuration", - append_ipv6config, service); + dbus_message_iter_get_basic(&str_array, &val); - connman_dbus_dict_append_array(dict, "Nameservers", - DBUS_TYPE_STRING, append_dns, service); + if (servers_str->len > 0) + g_string_append_printf(servers_str, + " %s", val); + else + g_string_append(servers_str, val); - connman_dbus_dict_append_array(dict, "Nameservers.Configuration", - DBUS_TYPE_STRING, append_dnsconfig, service); + dbus_message_iter_next(&str_array); + } + } else if (g_str_equal(key, "Excludes") == TRUE) { + DBusMessageIter str_array; - connman_dbus_dict_append_array(dict, "Domains", - DBUS_TYPE_STRING, append_domain, service); + if (type != DBUS_TYPE_ARRAY) + goto error; - connman_dbus_dict_append_array(dict, "Domains.Configuration", - DBUS_TYPE_STRING, append_domainconfig, service); + excludes_str = g_string_new(NULL); + if (excludes_str == NULL) + goto error; - connman_dbus_dict_append_dict(dict, "Proxy", append_proxy, service); + dbus_message_iter_recurse(&variant, &str_array); - connman_dbus_dict_append_dict(dict, "Provider", append_provider, service); -} + while (dbus_message_iter_get_arg_type(&str_array) == + DBUS_TYPE_STRING) { + char *val = NULL; -static void append_struct(gpointer value, gpointer user_data) -{ - struct connman_service *service = value; - DBusMessageIter *iter = user_data; - DBusMessageIter entry, dict; + dbus_message_iter_get_basic(&str_array, &val); - if (service->path == NULL || service->hidden == TRUE) - return; + if (excludes_str->len > 0) + g_string_append_printf(excludes_str, + " %s", val); + else + g_string_append(excludes_str, val); - dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &entry); + dbus_message_iter_next(&str_array); + } + } - dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH, - &service->path); + dbus_message_iter_next(&dict); + } - connman_dbus_dict_open(&entry, &dict); - append_properties(&dict, TRUE, service); - connman_dbus_dict_close(&entry, &dict); + switch (method) { + case CONNMAN_SERVICE_PROXY_METHOD_DIRECT: + break; + case CONNMAN_SERVICE_PROXY_METHOD_MANUAL: + if (servers_str == NULL && service->proxies == NULL) + goto error; - dbus_message_iter_close_container(iter, &entry); -} + if (servers_str != NULL) { + g_strfreev(service->proxies); -void __connman_service_list_struct(DBusMessageIter *iter) -{ - g_sequence_foreach(service_list, append_struct, iter); -} + if (servers_str->len > 0) + service->proxies = g_strsplit_set( + servers_str->str, " ", 0); + else + service->proxies = NULL; + } -int __connman_service_get_index(struct connman_service *service) -{ - if (service == NULL) - return -1; + if (excludes_str != NULL) { + g_strfreev(service->excludes); - if (service->network == NULL) - return -1; + if (excludes_str->len > 0) + service->excludes = g_strsplit_set( + excludes_str->str, " ", 0); + else + service->excludes = NULL; + } - return connman_network_get_index(service->network); -} + if (service->proxies == NULL) + method = CONNMAN_SERVICE_PROXY_METHOD_DIRECT; -void __connman_service_set_domainname(struct connman_service *service, - const char *domainname) -{ - if (service == NULL) - return; + break; + case CONNMAN_SERVICE_PROXY_METHOD_AUTO: + g_free(service->pac); - g_free(service->domainname); - service->domainname = g_strdup(domainname); + if (url != NULL && strlen(url) > 0) + service->pac = g_strdup(url); + else + service->pac = NULL; - domain_changed(service); -} + /* if we are connected: + - if service->pac == NULL + - if __connman_ipconfig_get_proxy_autoconfig( + service->ipconfig) == NULL + --> We should start WPAD */ -const char *__connman_service_get_domainname(struct connman_service *service) -{ - if (service == NULL) - return NULL; + break; + case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN: + goto error; + } - return service->domainname; -} + if (servers_str != NULL) + g_string_free(servers_str, TRUE); -const char *__connman_service_get_nameserver(struct connman_service *service) -{ - if (service == NULL) - return NULL; + if (excludes_str != NULL) + g_string_free(excludes_str, TRUE); - return service->nameserver; -} + service->proxy_config = method; -void __connman_service_set_proxy_autoconfig(struct connman_service *service, - const char *url) -{ - if (service == NULL) - return; + return 0; - if (__connman_ipconfig_set_proxy_autoconfig(service->ipconfig, - url) < 0) - return; +error: + if (servers_str != NULL) + g_string_free(servers_str, TRUE); - proxy_changed(service); + if (excludes_str != NULL) + g_string_free(excludes_str, TRUE); + + return -EINVAL; } -static DBusMessage *get_properties(DBusConnection *conn, - DBusMessage *msg, void *user_data) +static int set_ipconfig(struct connman_service *service, + struct connman_ipconfig *ipconfig, + DBusMessageIter *array, + enum connman_service_state state, + enum connman_service_state *new_state) { - struct connman_service *service = user_data; - DBusMessage *reply; - DBusMessageIter array, dict; + enum connman_ipconfig_method old_method; + enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN; + enum connman_ipconfig_type type; + int err; - DBG("service %p", service); + old_method = __connman_ipconfig_get_method(ipconfig); - reply = dbus_message_new_method_return(msg); - if (reply == NULL) - return NULL; + if (is_connecting_state(service, state) || + is_connected_state(service, state)) + __connman_network_clear_ipconfig(service->network, ipconfig); - dbus_message_iter_init_append(reply, &array); + err = __connman_ipconfig_set_config(ipconfig, array); + method = __connman_ipconfig_get_method(ipconfig); + type = __connman_ipconfig_get_config_type(ipconfig); - connman_dbus_dict_open(&array, &dict); - append_properties(&dict, FALSE, service); - connman_dbus_dict_close(&array, &dict); + if (type == CONNMAN_IPCONFIG_TYPE_IPV4) { + if (err == 0 && old_method == CONNMAN_IPCONFIG_METHOD_OFF && + method == CONNMAN_IPCONFIG_METHOD_DHCP) { + *new_state = service->state_ipv4 = + CONNMAN_SERVICE_STATE_CONFIGURATION; + __connman_ipconfig_enable(ipconfig); + } - return reply; + } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) { + if (err == 0 && old_method == CONNMAN_IPCONFIG_METHOD_OFF && + method == CONNMAN_IPCONFIG_METHOD_AUTO) { + *new_state = service->state_ipv6; + __connman_ipconfig_enable(ipconfig); + } + } + + DBG("err %d ipconfig %p type %d method %d state %s", err, ipconfig, + type, method, state2string(*new_state)); + + return err; } static DBusMessage *set_property(DBusConnection *conn, @@ -1410,7 +2241,7 @@ static DBusMessage *set_property(DBusConnection *conn, type = dbus_message_iter_get_arg_type(&value); - if (g_str_has_prefix(name, "AutoConnect") == TRUE) { + if (g_str_equal(name, "AutoConnect") == TRUE) { connman_bool_t autoconnect; if (type != DBUS_TYPE_BOOLEAN) @@ -1440,84 +2271,7 @@ static DBusMessage *set_property(DBusConnection *conn, dbus_message_iter_get_basic(&value, &passphrase); - g_free(service->passphrase); - service->passphrase = g_strdup(passphrase); - - passphrase_changed(service); - - if (service->network != NULL) - connman_network_set_string(service->network, - "WiFi.Passphrase", service->passphrase); - - __connman_storage_save_service(service); - } else if (g_str_equal(name, "APN") == TRUE) { - const char *apn; - - if (type != DBUS_TYPE_STRING) - return __connman_error_invalid_arguments(msg); - - if (service->immutable == TRUE) - return __connman_error_not_supported(msg); - - if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR) - return __connman_error_invalid_service(msg); - - dbus_message_iter_get_basic(&value, &apn); - - g_free(service->apn); - service->apn = g_strdup(apn); - - apn_changed(service); - - if (service->network != NULL) - connman_network_set_string(service->network, - "Cellular.APN", service->apn); - - __connman_storage_save_service(service); - } else if (g_str_equal(name, "Username") == TRUE) { - const char *username; - - if (type != DBUS_TYPE_STRING) - return __connman_error_invalid_arguments(msg); - - if (service->immutable == TRUE) - return __connman_error_not_supported(msg); - - if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR) - return __connman_error_invalid_service(msg); - - dbus_message_iter_get_basic(&value, &username); - - g_free(service->username); - service->username = g_strdup(username); - - if (service->network != NULL) - connman_network_set_string(service->network, - "Cellular.Username", service->username); - - __connman_storage_save_service(service); - } else if (g_str_equal(name, "Password") == TRUE) { - const char *password; - - if (type != DBUS_TYPE_STRING) - return __connman_error_invalid_arguments(msg); - - if (service->immutable == TRUE) - return __connman_error_not_supported(msg); - - if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR) - return __connman_error_invalid_service(msg); - - dbus_message_iter_get_basic(&value, &password); - - g_free(service->password); - service->password = g_strdup(password); - - if (service->network != NULL) - connman_network_set_string(service->network, - "Cellular.Password", service->password); - - __connman_storage_save_service(service); + __connman_service_set_passphrase(service, passphrase); } else if (g_str_equal(name, "Nameservers.Configuration") == TRUE) { DBusMessageIter entry; GString *str; @@ -1532,7 +2286,7 @@ static DBusMessage *set_property(DBusConnection *conn, return __connman_error_invalid_arguments(msg); index = connman_network_get_index(service->network); - gw = __connman_ipconfig_get_gateway(index); + gw = __connman_ipconfig_get_gateway_from_index(index); if (gw && strlen(gw)) __connman_service_nameserver_del_routes(service); @@ -1549,12 +2303,14 @@ static DBusMessage *set_property(DBusConnection *conn, g_string_append(str, val); } - g_strfreev(service->nameservers); + g_strfreev(service->nameservers_config); - if (str->len > 0) - service->nameservers = g_strsplit_set(str->str, " ", 0); - else - service->nameservers = NULL; + if (str->len > 0) { + service->nameservers_config = + g_strsplit_set(str->str, " ", 0); + } else { + service->nameservers_config = NULL; + } g_string_free(str, TRUE); @@ -1597,60 +2353,65 @@ static DBusMessage *set_property(DBusConnection *conn, g_string_free(str, TRUE); - //update_domains(service); + update_nameservers(service); domain_configuration_changed(service); __connman_storage_save_service(service); + } else if (g_str_equal(name, "Proxy.Configuration") == TRUE) { + int err; + + if (type != DBUS_TYPE_ARRAY) + return __connman_error_invalid_arguments(msg); + + err = update_proxy_configuration(service, &value); + + if (err < 0) + return __connman_error_failed(msg, -err); + + proxy_configuration_changed(service); + + __connman_storage_save_service(service); } else if (g_str_equal(name, "IPv4.Configuration") == TRUE || g_str_equal(name, "IPv6.Configuration")) { - enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN; + struct connman_ipconfig *ipv4 = NULL, *ipv6 = NULL; + enum connman_service_state state = + CONNMAN_SERVICE_STATE_UNKNOWN; int err = 0; - struct connman_ipconfig *ipv6config; DBG("%s", name); - ipv6config = connman_ipconfig_get_ipv6config( - service->ipconfig); - if (service->ipconfig == NULL) + if (service->ipconfig_ipv4 == NULL && + service->ipconfig_ipv6 == NULL) return __connman_error_invalid_property(msg); - if (is_connecting(service) || - is_connected(service)) { - __connman_network_clear_ipconfig(service->network, - service->ipconfig); - __connman_network_clear_ipconfig(service->network, - ipv6config); - } - if (g_str_equal(name, "IPv4.Configuration") == TRUE) { - type = CONNMAN_IPCONFIG_TYPE_IPV4; - err = __connman_ipconfig_set_config( - service->ipconfig, type, &value); + ipv4 = service->ipconfig_ipv4; + err = set_ipconfig(service, ipv4, &value, + service->state_ipv4, &state); + } else if (g_str_equal(name, "IPv6.Configuration") == TRUE) { - type = CONNMAN_IPCONFIG_TYPE_IPV6; - err = __connman_ipconfig_set_config( - ipv6config, type, &value); + ipv6 = service->ipconfig_ipv6; + err = set_ipconfig(service, ipv6, &value, + service->state_ipv6, &state); } if (err < 0) { - if (is_connected(service) || - is_connecting(service)) - __connman_network_set_ipconfig( - service->network, - service->ipconfig); + if (is_connected_state(service, state) || + is_connecting_state(service, state)) + __connman_network_set_ipconfig(service->network, + ipv4, ipv6); return __connman_error_failed(msg, -err); } - if (type == CONNMAN_IPCONFIG_TYPE_IPV4) + if (ipv4) ipv4_configuration_changed(service); - else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) + else if (ipv6) ipv6_configuration_changed(service); - if (is_connecting(service) || - is_connected(service)) + if (is_connecting(service) || is_connected(service)) __connman_network_set_ipconfig(service->network, - service->ipconfig); + ipv4, ipv6); __connman_storage_save_service(service); } else @@ -1661,7 +2422,7 @@ static DBusMessage *set_property(DBusConnection *conn, static void set_idle(struct connman_service *service) { - service->state = CONNMAN_SERVICE_STATE_IDLE; + service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE; service->error = CONNMAN_SERVICE_ERROR_UNKNOWN; state_changed(service); } @@ -1709,7 +2470,8 @@ static connman_bool_t is_ignore(struct connman_service *service) if (service->ignore == TRUE) return TRUE; - if (service->state == CONNMAN_SERVICE_STATE_FAILURE) + if (combine_state(service->state_ipv4, service->state_ipv6) == + CONNMAN_SERVICE_STATE_FAILURE) return TRUE; return FALSE; @@ -1740,7 +2502,9 @@ void __connman_service_auto_connect(void) return; if (is_ignore(service) == FALSE && - service->state == CONNMAN_SERVICE_STATE_IDLE) + combine_state(service->state_ipv4, + service->state_ipv6) == + CONNMAN_SERVICE_STATE_IDLE) break; service = NULL; @@ -1774,9 +2538,21 @@ static void reply_pending(struct connman_service *service, int error) error); if (reply != NULL) g_dbus_send_message(connection, reply); - } else - g_dbus_send_reply(connection, service->pending, + } else { + const char *sender; + + sender = dbus_message_get_interface(service->pending); + + DBG("sender %s", sender); + + if (g_strcmp0(sender, CONNMAN_MANAGER_INTERFACE) == 0) + g_dbus_send_reply(connection, service->pending, + DBUS_TYPE_OBJECT_PATH, &service->path, + DBUS_TYPE_INVALID); + else + g_dbus_send_reply(connection, service->pending, DBUS_TYPE_INVALID); + } dbus_message_unref(service->pending); service->pending = NULL; @@ -1795,7 +2571,10 @@ static gboolean connect_timeout(gpointer user_data) if (service->network != NULL) __connman_network_disconnect(service->network); - __connman_ipconfig_disable(service->ipconfig); + __connman_ipconfig_disable(service->ipconfig_ipv4); + __connman_ipconfig_disable(service->ipconfig_ipv6); + + __connman_stats_service_unregister(service); if (service->pending != NULL) { DBusMessage *reply; @@ -1810,7 +2589,11 @@ static gboolean connect_timeout(gpointer user_data) autoconnect = TRUE; __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_FAILURE); + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_IPCONFIG_TYPE_IPV4); + __connman_service_indicate_state(service, + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_IPCONFIG_TYPE_IPV6); if (autoconnect == TRUE && service->userconnect == FALSE) __connman_service_auto_connect(); @@ -1847,6 +2630,20 @@ static connman_bool_t get_reconnect_state(struct connman_service *service) return __connman_device_get_reconnect(device); } +static void request_input_cb (struct connman_service *service, + const char *passphrase, void *user_data) +{ + DBG ("RequestInput return, %p", service); + + if (passphrase == NULL && service->wps == FALSE) + return; + + if (passphrase != NULL) + __connman_service_set_passphrase(service, passphrase); + + __connman_service_connect(service); +} + struct connman_service * __connman_service_connect_type(enum connman_service_type type) { @@ -1896,8 +2693,9 @@ __connman_service_connect_type(enum connman_service_type type) err = __connman_service_connect(service); if (err < 0) { if (err == -ENOKEY) - if (__connman_agent_request_passphrase(service, - NULL, NULL)) + if ( __connman_agent_request_input(service, + request_input_cb, + NULL)) return service; if (err != -EINPROGRESS) @@ -1924,8 +2722,7 @@ static DBusMessage *connect_service(DBusConnection *conn, while (g_sequence_iter_is_end(iter) == FALSE) { struct connman_service *temp = g_sequence_get(iter); - if (service->type == temp->type && - is_connecting(temp) == TRUE) + if (service->type == temp->type && is_connecting(temp) == TRUE) return __connman_error_in_progress(msg); iter = g_sequence_iter_next(iter); @@ -1942,11 +2739,15 @@ static DBusMessage *connect_service(DBusConnection *conn, err = __connman_service_connect(service); if (err < 0) { if (err == -ENOKEY) { - if (__connman_agent_request_passphrase(service, - NULL, NULL) == 0) + if (__connman_agent_request_input(service, + request_input_cb, + NULL) == 0) return NULL; } + if (service->pending == NULL) + return NULL; + if (err != -EINPROGRESS) { dbus_message_unref(service->pending); service->pending = NULL; @@ -1999,7 +2800,8 @@ static DBusMessage *remove_service(DBusConnection *conn, return __connman_error_not_supported(msg); if (service->favorite == FALSE && - service->state != CONNMAN_SERVICE_STATE_FAILURE) + combine_state(service->state_ipv4, service->state_ipv6) != + CONNMAN_SERVICE_STATE_FAILURE) return __connman_error_not_supported(msg); if (service->network != NULL) { @@ -2013,17 +2815,6 @@ static DBusMessage *remove_service(DBusConnection *conn, passphrase_changed(service); - g_free(service->apn); - service->apn = NULL; - - g_free(service->username); - service->username = NULL; - - g_free(service->password); - service->password = NULL; - - apn_changed(service); - set_idle(service); __connman_service_set_favorite(service, FALSE); @@ -2055,7 +2846,8 @@ static DBusMessage *move_service(DBusConnection *conn, DBG("target %s", target->identifier); - if (target->state != service->state) + if (target->state_ipv4 != service->state_ipv4 && + target->state_ipv6 != service->state_ipv6) return __connman_error_invalid_service(msg); g_get_current_time(&service->modified); @@ -2136,30 +2928,35 @@ static void service_free(gpointer user_data) g_free(path); } + g_hash_table_destroy(service->counter_table); + if (service->network != NULL) connman_network_unref(service->network); if (service->provider != NULL) connman_provider_unref(service->provider); - if (service->ipconfig != NULL) { - connman_ipconfig_unref(service->ipconfig); - service->ipconfig = NULL; + if (service->ipconfig_ipv4 != NULL) { + connman_ipconfig_unref(service->ipconfig_ipv4); + service->ipconfig_ipv4 = NULL; + } + + if (service->ipconfig_ipv6 != NULL) { + connman_ipconfig_unref(service->ipconfig_ipv6); + service->ipconfig_ipv6 = NULL; } if (service->location != NULL) connman_location_unref(service->location); g_strfreev(service->nameservers); + g_strfreev(service->nameservers_config); g_strfreev(service->domains); + g_strfreev(service->proxies); + g_strfreev(service->excludes); - g_free(service->nameserver); g_free(service->domainname); - g_free(service->mcc); - g_free(service->mnc); - g_free(service->apn); - g_free(service->username); - g_free(service->password); + g_free(service->pac); g_free(service->profile); g_free(service->name); g_free(service->passphrase); @@ -2227,7 +3024,9 @@ static void service_initialize(struct connman_service *service) service->type = CONNMAN_SERVICE_TYPE_UNKNOWN; service->mode = CONNMAN_SERVICE_MODE_UNKNOWN; service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN; - service->state = CONNMAN_SERVICE_STATE_UNKNOWN; + + service->state_ipv4 = CONNMAN_SERVICE_STATE_UNKNOWN; + service->state_ipv6 = CONNMAN_SERVICE_STATE_UNKNOWN; service->favorite = FALSE; service->immutable = FALSE; @@ -2242,6 +3041,8 @@ static void service_initialize(struct connman_service *service) stats_init(service); service->provider = NULL; + + service->wps = FALSE; } /** @@ -2253,6 +3054,10 @@ static void service_initialize(struct connman_service *service) */ struct connman_service *connman_service_create(void) { + GSList *list; + struct connman_stats_counter *counters; + const char *counter; + struct connman_service *service; service = g_try_new0(struct connman_service, 1); @@ -2261,6 +3066,25 @@ struct connman_service *connman_service_create(void) DBG("service %p", service); + service->counter_table = g_hash_table_new_full(g_str_hash, + g_str_equal, NULL, g_free); + + for (list = counter_list; list; list = list->next) { + counter = list->data; + + counters = g_try_new0(struct connman_stats_counter, 1); + if (counters == NULL) { + g_hash_table_destroy(service->counter_table); + g_free(service); + return NULL; + } + + counters->append_all = TRUE; + + g_hash_table_replace(service->counter_table, (gpointer)counter, + counters); + } + service_initialize(service); service->location = __connman_location_create(service); @@ -2304,12 +3128,21 @@ static gint service_compare(gconstpointer a, gconstpointer b, { struct connman_service *service_a = (void *) a; struct connman_service *service_b = (void *) b; + enum connman_service_state state_a, state_b; - if (service_a->state != service_b->state) { + state_a = combine_state(service_a->state_ipv4, service_a->state_ipv6); + state_b = combine_state(service_b->state_ipv4, service_b->state_ipv6); + + if (state_a != state_b) { if (is_connected(service_a) == TRUE) return -1; if (is_connected(service_b) == TRUE) return 1; + + if (is_connecting(service_a) == TRUE) + return -1; + if (is_connecting(service_b) == TRUE) + return 1; } if (service_a->order > service_b->order) @@ -2331,6 +3164,7 @@ static gint service_compare(gconstpointer a, gconstpointer b, case CONNMAN_SERVICE_TYPE_ETHERNET: case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_VPN: + case CONNMAN_SERVICE_TYPE_GADGET: break; case CONNMAN_SERVICE_TYPE_WIFI: return 1; @@ -2372,7 +3206,14 @@ char *connman_service_get_interface(struct connman_service *service) return NULL; if (service->type == CONNMAN_SERVICE_TYPE_VPN) { - index = connman_ipconfig_get_index(service->ipconfig); + if (service->ipconfig_ipv4) + index = connman_ipconfig_get_index( + service->ipconfig_ipv4); + else if (service->ipconfig_ipv6) + index = connman_ipconfig_get_index( + service->ipconfig_ipv6); + else + return NULL; return connman_inet_ifname(index); } @@ -2400,12 +3241,50 @@ __connman_service_get_network(struct connman_service *service) return service->network; } -struct connman_ipconfig *__connman_service_get_ipconfig(struct connman_service *service) +struct connman_ipconfig * +__connman_service_get_ip4config(struct connman_service *service) +{ + if (service == NULL) + return NULL; + + return service->ipconfig_ipv4; +} + +struct connman_ipconfig * +__connman_service_get_ip6config(struct connman_service *service) { if (service == NULL) return NULL; - return service->ipconfig; + return service->ipconfig_ipv6; +} + +struct connman_ipconfig * +__connman_service_get_ipconfig(struct connman_service *service, int family) +{ + if (family == AF_INET) + return __connman_service_get_ip4config(service); + else if (family == AF_INET6) + return __connman_service_get_ip6config(service); + else + return NULL; + +} + +enum connman_service_security __connman_service_get_security(struct connman_service *service) +{ + if (service == NULL) + return CONNMAN_SERVICE_SECURITY_UNKNOWN; + + return service->security; +} + +connman_bool_t __connman_service_wps_enabled(struct connman_service *service) +{ + if (service == NULL) + return FALSE; + + return service->wps; } /** @@ -2478,30 +3357,73 @@ void __connman_service_set_string(struct connman_service *service, } } +static void service_complete(struct connman_service *service) +{ + reply_pending(service, EIO); + + if (service->userconnect == FALSE) + __connman_service_auto_connect(); + + g_get_current_time(&service->modified); + __connman_storage_save_service(service); +} + +static void report_error_cb(struct connman_service *service, + gboolean retry, void *user_data) +{ + if (retry == TRUE) + __connman_service_connect(service); + else { + service_complete(service); + __connman_profile_changed(FALSE); + __connman_element_request_scan(CONNMAN_ELEMENT_TYPE_UNKNOWN); + } +} + int __connman_service_indicate_state(struct connman_service *service, - enum connman_service_state state) + enum connman_service_state new_state, + enum connman_ipconfig_type type) { + enum connman_service_state service_state, + state = CONNMAN_SERVICE_STATE_IDLE; GSequenceIter *iter; - DBG("service %p state %d", service, state); - if (service == NULL) return -EINVAL; - if (service->state == state) - return -EALREADY; + if (type == CONNMAN_IPCONFIG_TYPE_IPV4) { + if (service->state_ipv4 == new_state) + return -EALREADY; + state = combine_state(new_state, service->state_ipv6); + } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) { + if (service->state_ipv6 == new_state) + return -EALREADY; + state = combine_state(new_state, service->state_ipv4); + } else + return -EINVAL; - if (service->state == CONNMAN_SERVICE_STATE_FAILURE && + service_state = combine_state(service->state_ipv4, + service->state_ipv6); + + DBG("service %p state %s/%s => %s new %s/%d => %s", + service, + state2string(service->state_ipv4), + state2string(service->state_ipv6), + state2string(service_state), + state2string(new_state), + type, + state2string(state)); + + if (service_state == CONNMAN_SERVICE_STATE_FAILURE && state == CONNMAN_SERVICE_STATE_IDLE) return -EINVAL; - if (service->state == CONNMAN_SERVICE_STATE_IDLE && + if (service_state == CONNMAN_SERVICE_STATE_IDLE && state == CONNMAN_SERVICE_STATE_DISCONNECT) return -EINVAL; if (state == CONNMAN_SERVICE_STATE_IDLE && - service->state != CONNMAN_SERVICE_STATE_DISCONNECT) { - service->state = CONNMAN_SERVICE_STATE_DISCONNECT; + service_state != CONNMAN_SERVICE_STATE_DISCONNECT) { state_changed(service); reply_pending(service, ECONNABORTED); @@ -2509,10 +3431,30 @@ int __connman_service_indicate_state(struct connman_service *service, __connman_service_disconnect(service); } - if (state == CONNMAN_SERVICE_STATE_CONFIGURATION) - __connman_ipconfig_enable(service->ipconfig); + if (new_state == CONNMAN_SERVICE_STATE_CONFIGURATION) { + if (__connman_stats_service_register(service) == 0) { + __connman_stats_get(service, FALSE, + &service->stats.data); + __connman_stats_get(service, TRUE, + &service->stats_roaming.data); + } + + if (type == CONNMAN_IPCONFIG_TYPE_IPV4 && + new_state == CONNMAN_SERVICE_STATE_CONFIGURATION) + __connman_ipconfig_enable(service->ipconfig_ipv4); + else if (type == CONNMAN_IPCONFIG_TYPE_IPV6 && + new_state == CONNMAN_SERVICE_STATE_CONFIGURATION) + __connman_ipconfig_enable(service->ipconfig_ipv6); + } + + if (type == CONNMAN_IPCONFIG_TYPE_IPV4) + service->state_ipv4 = new_state; + else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) + service->state_ipv6 = new_state; + + if (state == service_state) + return -EALREADY; - service->state = state; state_changed(service); if (state == CONNMAN_SERVICE_STATE_ONLINE) { @@ -2533,6 +3475,9 @@ int __connman_service_indicate_state(struct connman_service *service, } if (state == CONNMAN_SERVICE_STATE_READY) { + enum connman_service_proxy_method proxy_config; + enum connman_ipconfig_method method; + set_reconnect_state(service, TRUE); __connman_service_set_favorite(service, TRUE); @@ -2546,12 +3491,50 @@ int __connman_service_indicate_state(struct connman_service *service, update_nameservers(service); dns_changed(service); + domain_changed(service); + + proxy_config = service->proxy_config; - __connman_wpad_start(service); + /* + * We start WPAD if we haven't got a PAC URL from DHCP and + * if our proxy manual configuration is either empty or set + * to AUTO with an empty URL. + */ + if (service->proxy == CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN && + (proxy_config == CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN || + (proxy_config == + CONNMAN_SERVICE_PROXY_METHOD_AUTO && + service->pac == NULL))) + if (__connman_wpad_start(service) < 0) { + service->proxy = + CONNMAN_SERVICE_PROXY_METHOD_DIRECT; + + __connman_notifier_proxy_changed(service); + } __connman_notifier_connect(service->type); + if (service->type == CONNMAN_SERVICE_TYPE_WIFI && + connman_network_get_bool(service->network, + "WiFi.UseWPS") == TRUE) { + const char *pass; + + pass = connman_network_get_string(service->network, + "WiFi.Passphrase"); + + __connman_service_set_passphrase(service, pass); + + connman_network_set_bool(service->network, + "WiFi.UseWPS", FALSE); + } + default_changed(); + + method = __connman_ipconfig_get_method(service->ipconfig_ipv6); + if (method == CONNMAN_IPCONFIG_METHOD_OFF) + __connman_ipconfig_disable_ipv6( + service->ipconfig_ipv6); + } else if (state == CONNMAN_SERVICE_STATE_DISCONNECT) { __connman_location_finish(service); @@ -2561,18 +3544,18 @@ int __connman_service_indicate_state(struct connman_service *service, update_nameservers(service); dns_changed(service); + domain_changed(service); __connman_notifier_disconnect(service->type); } if (state == CONNMAN_SERVICE_STATE_FAILURE) { - reply_pending(service, EIO); - - if (service->userconnect == FALSE) - __connman_service_auto_connect(); - - g_get_current_time(&service->modified); - __connman_storage_save_service(service); + if (service->userconnect == TRUE && + __connman_agent_report_error(service, + error2string(service->error), + report_error_cb, NULL) == -EIO) + return 0; + service_complete(service); } else service->error = CONNMAN_SERVICE_ERROR_UNKNOWN; @@ -2582,10 +3565,12 @@ int __connman_service_indicate_state(struct connman_service *service, __connman_profile_changed(FALSE); - if (service->state == CONNMAN_SERVICE_STATE_ONLINE) + service_state = combine_state(service->state_ipv4, + service->state_ipv6); + if (service_state == CONNMAN_SERVICE_STATE_ONLINE) default_changed(); - if (service->state == CONNMAN_SERVICE_STATE_DISCONNECT) { + if (service_state == CONNMAN_SERVICE_STATE_DISCONNECT) { struct connman_service *def_service = get_default(); if (__connman_notifier_count_connected() == 0 && @@ -2594,8 +3579,8 @@ int __connman_service_indicate_state(struct connman_service *service, __connman_provider_disconnect(def_service->provider); } - if (service->state == CONNMAN_SERVICE_STATE_IDLE || - service->state == CONNMAN_SERVICE_STATE_FAILURE) + if (service_state == CONNMAN_SERVICE_STATE_IDLE || + service_state == CONNMAN_SERVICE_STATE_FAILURE) __connman_element_request_scan(CONNMAN_ELEMENT_TYPE_UNKNOWN); return 0; @@ -2611,8 +3596,49 @@ int __connman_service_indicate_error(struct connman_service *service, service->error = error; + if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY) + __connman_service_set_passphrase(service, NULL); + + return __connman_service_indicate_state(service, + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_IPCONFIG_TYPE_IPV4); +} + +int __connman_service_clear_error(struct connman_service *service) +{ + enum connman_service_state state; + + DBG("service %p", service); + + if (service == NULL) + return -EINVAL; + + state = combine_state(service->state_ipv4, service->state_ipv6); + + if (state != CONNMAN_SERVICE_STATE_FAILURE) + return -EINVAL; + + service->state_ipv4 = service->state_ipv6 = + CONNMAN_SERVICE_STATE_UNKNOWN; + service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;; + + if (service->favorite == TRUE) + set_reconnect_state(service, TRUE); + + __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV6); + + /* + * Toggling the IPv6 state to IDLE could trigger the auto connect + * machinery and consequently the IPv4 state. + */ + if (service->state_ipv4 != CONNMAN_SERVICE_STATE_UNKNOWN && + service->state_ipv4 != CONNMAN_SERVICE_STATE_FAILURE) + return 0; + return __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_FAILURE); + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV4); } int __connman_service_indicate_default(struct connman_service *service) @@ -2655,22 +3681,15 @@ static connman_bool_t prepare_network(struct connman_service *service) &ssid_len) == NULL) return FALSE; - connman_network_set_string(service->network, + if (service->passphrase != NULL) + connman_network_set_string(service->network, "WiFi.Passphrase", service->passphrase); break; case CONNMAN_NETWORK_TYPE_ETHERNET: case CONNMAN_NETWORK_TYPE_WIMAX: case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN: case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN: - break; case CONNMAN_NETWORK_TYPE_CELLULAR: - connman_network_set_string(service->network, - "Cellular.APN", service->apn); - - connman_network_set_string(service->network, - "Cellular.Username", service->username); - connman_network_set_string(service->network, - "Cellular.Password", service->password); break; } @@ -2711,31 +3730,21 @@ static void prepare_8021x(struct connman_service *service) service->phase2); } -int __connman_service_connect(struct connman_service *service) +static int service_connect(struct connman_service *service) { int err; - DBG("service %p", service); - - if (is_connected(service) == TRUE) - return -EISCONN; - - if (is_connecting(service) == TRUE) - return -EALREADY; - switch (service->type) { case CONNMAN_SERVICE_TYPE_UNKNOWN: case CONNMAN_SERVICE_TYPE_SYSTEM: case CONNMAN_SERVICE_TYPE_GPS: + case CONNMAN_SERVICE_TYPE_GADGET: return -EINVAL; case CONNMAN_SERVICE_TYPE_ETHERNET: case CONNMAN_SERVICE_TYPE_WIMAX: case CONNMAN_SERVICE_TYPE_BLUETOOTH: - case CONNMAN_SERVICE_TYPE_VPN: - break; case CONNMAN_SERVICE_TYPE_CELLULAR: - if (service->apn == NULL) - return -EINVAL; + case CONNMAN_SERVICE_TYPE_VPN: break; case CONNMAN_SERVICE_TYPE_WIFI: switch (service->security) { @@ -2746,8 +3755,16 @@ int __connman_service_connect(struct connman_service *service) case CONNMAN_SERVICE_SECURITY_PSK: case CONNMAN_SERVICE_SECURITY_WPA: case CONNMAN_SERVICE_SECURITY_RSN: - if (service->passphrase == NULL) - return -ENOKEY; + if (service->passphrase == NULL) { + if (service->network == NULL) + return -EOPNOTSUPP; + + if (service->wps == FALSE || + connman_network_get_bool( + service->network, + "WiFi.UseWPS") == FALSE) + return -ENOKEY; + } break; case CONNMAN_SERVICE_SECURITY_8021X: break; @@ -2772,7 +3789,17 @@ int __connman_service_connect(struct connman_service *service) break; } - __connman_ipconfig_enable(service->ipconfig); + if (__connman_stats_service_register(service) == 0) { + __connman_stats_get(service, FALSE, + &service->stats.data); + __connman_stats_get(service, TRUE, + &service->stats_roaming.data); + } + + if (service->ipconfig_ipv4) + __connman_ipconfig_enable(service->ipconfig_ipv4); + if (service->ipconfig_ipv6) + __connman_ipconfig_enable(service->ipconfig_ipv6); err = __connman_network_connect(service->network); } else if (service->type == CONNMAN_SERVICE_TYPE_VPN && @@ -2783,22 +3810,69 @@ int __connman_service_connect(struct connman_service *service) if (err < 0) { if (err != -EINPROGRESS) { - __connman_ipconfig_disable(service->ipconfig); - return err; + __connman_ipconfig_disable(service->ipconfig_ipv4); + __connman_ipconfig_disable(service->ipconfig_ipv6); + __connman_stats_service_unregister(service); } + } + + return err; +} + + +int __connman_service_connect(struct connman_service *service) +{ + enum connman_service_state state; + int err; + + state = combine_state(service->state_ipv4, service->state_ipv6); + + DBG("service %p state %s", service, state2string(state)); + if (is_connected(service) == TRUE) + return -EISCONN; + + if (is_connecting(service) == TRUE) + return -EALREADY; + + switch (service->type) { + case CONNMAN_SERVICE_TYPE_UNKNOWN: + case CONNMAN_SERVICE_TYPE_SYSTEM: + case CONNMAN_SERVICE_TYPE_GPS: + case CONNMAN_SERVICE_TYPE_GADGET: + return -EINVAL; + default: + err = service_connect(service); + } + + if (err >= 0) + return 0; + + if (err == -EINPROGRESS) { service->timeout = g_timeout_add_seconds(CONNECT_TIMEOUT, connect_timeout, service); return -EINPROGRESS; } - return 0; + if (err == -ENOKEY) + return -ENOKEY; + + if (service->userconnect == TRUE) + reply_pending(service, err); + + __connman_service_indicate_state(service, + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_IPCONFIG_TYPE_IPV4); + __connman_service_indicate_state(service, + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_IPCONFIG_TYPE_IPV6); + + return err; } int __connman_service_disconnect(struct connman_service *service) { - struct connman_ipconfig *ipv6config; int err; DBG("service %p", service); @@ -2811,24 +3885,27 @@ int __connman_service_disconnect(struct connman_service *service) else return -EOPNOTSUPP; - __connman_ipconfig_set_proxy_autoconfig(service->ipconfig, NULL); - - __connman_ipconfig_clear_address(service->ipconfig); + if (err < 0 && err != -EINPROGRESS) + return err; - ipv6config = connman_ipconfig_get_ipv6config(service->ipconfig); + __connman_6to4_remove(service->ipconfig_ipv4); - __connman_ipconfig_clear_address(ipv6config); + if (service->ipconfig_ipv4) + __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv4, + NULL); + else + __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6, + NULL); - __connman_ipconfig_disable(service->ipconfig); + __connman_ipconfig_address_remove(service->ipconfig_ipv4); + __connman_ipconfig_address_remove(service->ipconfig_ipv6); - if (err < 0) { - if (err != -EINPROGRESS) - return err; + __connman_ipconfig_disable(service->ipconfig_ipv4); + __connman_ipconfig_disable(service->ipconfig_ipv6); - return -EINPROGRESS; - } + __connman_stats_service_unregister(service); - return 0; + return err; } /** @@ -2918,8 +3995,6 @@ static struct connman_network *create_hidden_wifi(struct connman_device *device, index = connman_device_get_index(device); connman_network_set_index(network, index); - connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_IP); - if (connman_device_add_network(device, network) < 0) { connman_network_unref(network); return NULL; @@ -2999,11 +4074,11 @@ int __connman_service_create_and_connect(DBusMessage *msg) g_strcmp0(security, "ieee8021x") != 0) return -EINVAL; - device = __connman_element_find_device(CONNMAN_DEVICE_TYPE_WIFI); + device = __connman_element_find_device(CONNMAN_SERVICE_TYPE_WIFI); if (device == NULL) return -EOPNOTSUPP; - ident = __connman_device_get_ident(device); + ident = connman_device_get_ident(device); if (ident == NULL) return -EOPNOTSUPP; @@ -3043,6 +4118,16 @@ done: goto failed; } + if (is_connected(service) == TRUE) { + err = -EISCONN; + goto failed; + } + + if (is_connecting(service) == TRUE) { + err = -EALREADY; + goto failed; + } + set_reconnect_state(service, FALSE); __connman_device_disconnect(device); @@ -3058,9 +4143,7 @@ done: if (err < 0 && err != -EINPROGRESS) goto failed; - g_dbus_send_reply(connection, msg, - DBUS_TYPE_OBJECT_PATH, &service->path, - DBUS_TYPE_INVALID); + service->pending = dbus_message_ref(msg); return 0; @@ -3186,18 +4269,52 @@ static void service_lower_down(struct connman_ipconfig *ipconfig) static void service_ip_bound(struct connman_ipconfig *ipconfig) { struct connman_service *service = connman_ipconfig_get_data(ipconfig); + enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN; + enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN; connman_info("%s ip bound", connman_ipconfig_get_ifname(ipconfig)); + type = __connman_ipconfig_get_config_type(ipconfig); + method = __connman_ipconfig_get_method(ipconfig); + + DBG("service %p ipconfig %p type %d method %d", service, ipconfig, + type, method); + + if (type == CONNMAN_IPCONFIG_TYPE_IPV6 && + method == CONNMAN_IPCONFIG_METHOD_AUTO) + __connman_service_indicate_state(service, + CONNMAN_SERVICE_STATE_READY, + CONNMAN_IPCONFIG_TYPE_IPV6); + settings_changed(service); } static void service_ip_release(struct connman_ipconfig *ipconfig) { struct connman_service *service = connman_ipconfig_get_data(ipconfig); + enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN; + enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN; connman_info("%s ip release", connman_ipconfig_get_ifname(ipconfig)); + type = __connman_ipconfig_get_config_type(ipconfig); + method = __connman_ipconfig_get_method(ipconfig); + + DBG("service %p ipconfig %p type %d method %d", service, ipconfig, + type, method); + + if (type == CONNMAN_IPCONFIG_TYPE_IPV6 && + method == CONNMAN_IPCONFIG_METHOD_OFF) + __connman_service_indicate_state(service, + CONNMAN_SERVICE_STATE_DISCONNECT, + CONNMAN_IPCONFIG_TYPE_IPV6); + + if (type == CONNMAN_IPCONFIG_TYPE_IPV4 && + method == CONNMAN_IPCONFIG_METHOD_OFF) + __connman_service_indicate_state(service, + CONNMAN_SERVICE_STATE_DISCONNECT, + CONNMAN_IPCONFIG_TYPE_IPV4); + settings_changed(service); } @@ -3210,34 +4327,51 @@ static const struct connman_ipconfig_ops service_ops = { .ip_release = service_ip_release, }; -static void setup_ipconfig(struct connman_service *service, int index) +static void setup_ip4config(struct connman_service *service, int index) { if (index < 0) return; - service->ipconfig = connman_ipconfig_create(index); - if (service->ipconfig == NULL) + service->ipconfig_ipv4 = connman_ipconfig_create(index, + CONNMAN_IPCONFIG_TYPE_IPV4); + if (service->ipconfig_ipv4 == NULL) return; - connman_ipconfig_set_method(service->ipconfig, + connman_ipconfig_set_method(service->ipconfig_ipv4, CONNMAN_IPCONFIG_METHOD_DHCP); - connman_ipconfig_set_data(service->ipconfig, service); + connman_ipconfig_set_data(service->ipconfig_ipv4, service); + + connman_ipconfig_set_ops(service->ipconfig_ipv4, &service_ops); +} + +static void setup_ip6config(struct connman_service *service, int index) +{ + if (index < 0) + return; + + service->ipconfig_ipv6 = connman_ipconfig_create(index, + CONNMAN_IPCONFIG_TYPE_IPV6); + if (service->ipconfig_ipv6 == NULL) + return; + + connman_ipconfig_set_data(service->ipconfig_ipv6, service); - connman_ipconfig_set_ops(service->ipconfig, &service_ops); + connman_ipconfig_set_ops(service->ipconfig_ipv6, &service_ops); } -void __connman_service_create_ipconfig(struct connman_service *service, +void __connman_service_create_ip4config(struct connman_service *service, int index) { - struct connman_ipconfig *ipv6config; const char *ident = service->profile; GKeyFile *keyfile; - if (service->ipconfig != NULL) + DBG("ipv4 %p", service->ipconfig_ipv4); + + if (service->ipconfig_ipv4 != NULL) return; - setup_ipconfig(service, index); + setup_ip4config(service, index); if (ident == NULL) return; @@ -3246,14 +4380,36 @@ void __connman_service_create_ipconfig(struct connman_service *service, if (keyfile == NULL) return; + if (service->ipconfig_ipv4) + __connman_ipconfig_load(service->ipconfig_ipv4, keyfile, + service->identifier, "IPv4."); + g_key_file_free(keyfile); +} + +void __connman_service_create_ip6config(struct connman_service *service, + int index) +{ + const char *ident = service->profile; + GKeyFile *keyfile; + + DBG("ipv6 %p", service->ipconfig_ipv6); + + if (service->ipconfig_ipv6 != NULL) + return; + + setup_ip6config(service, index); + + if (ident == NULL) + return; + + keyfile = __connman_storage_open_profile(ident); + if (keyfile == NULL) + return; - ipv6config = connman_ipconfig_get_ipv6config(service->ipconfig); - if (ipv6config != NULL) - __connman_ipconfig_load(ipv6config, keyfile, + if (service->ipconfig_ipv6 != NULL) + __connman_ipconfig_load(service->ipconfig_ipv6, keyfile, service->identifier, "IPv6."); - __connman_ipconfig_load(service->ipconfig, keyfile, - service->identifier, "IPv4."); g_key_file_free(keyfile); } @@ -3297,7 +4453,12 @@ struct connman_service *__connman_service_lookup_from_index(int index) while (g_sequence_iter_is_end(iter) == FALSE) { service = g_sequence_get(iter); - if (connman_ipconfig_get_index(service->ipconfig) == index) + if (connman_ipconfig_get_index(service->ipconfig_ipv4) + == index) + return service; + + if (connman_ipconfig_get_index(service->ipconfig_ipv6) + == index) return service; iter = g_sequence_iter_next(iter); @@ -3306,6 +4467,11 @@ struct connman_service *__connman_service_lookup_from_index(int index) return NULL; } +const char *__connman_service_get_ident(struct connman_service *service) +{ + return service->identifier; +} + const char *__connman_service_get_path(struct connman_service *service) { return service->path; @@ -3454,20 +4620,13 @@ static void update_from_network(struct connman_service *service, str = connman_network_get_string(network, "WiFi.Security"); service->security = convert_wifi_security(str); - str = connman_network_get_string(network, "Cellular.MCC"); - g_free(service->mcc); - service->mcc = g_strdup(str); - - str = connman_network_get_string(network, "Cellular.MNC"); - g_free(service->mnc); - service->mnc = g_strdup(str); - if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) { connman_uint8_t value = connman_network_get_uint8(network, "Cellular.Mode"); service->mode = convert_cellular_mode(value); - } + } else if (service->type == CONNMAN_SERVICE_TYPE_WIFI) + service->wps = connman_network_get_bool(network, "WiFi.WPS"); if (service->strength > strength && service->network != NULL) { connman_network_unref(service->network); @@ -3493,8 +4652,10 @@ static void update_from_network(struct connman_service *service, struct connman_service * __connman_service_create_from_network(struct connman_network *network) { struct connman_service *service; + struct connman_device *device; const char *ident, *group; char *name; + int index; DBG("network %p", network); @@ -3533,6 +4694,7 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne case CONNMAN_SERVICE_TYPE_BLUETOOTH: case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_VPN: + case CONNMAN_SERVICE_TYPE_GADGET: service->autoconnect = FALSE; break; case CONNMAN_SERVICE_TYPE_WIFI: @@ -3541,16 +4703,25 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne break; } - service->state = CONNMAN_SERVICE_STATE_IDLE; + service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE; update_from_network(service, network); - setup_ipconfig(service, connman_network_get_index(network)); + index = connman_network_get_index(network); + + if (service->ipconfig_ipv4 == NULL) + setup_ip4config(service, index); + + if (service->ipconfig_ipv6 == NULL) + setup_ip6config(service, index); service_register(service); - if (service->favorite == TRUE) - __connman_service_auto_connect(); + if (service->favorite == TRUE) { + device = connman_network_get_device(service->network); + if (device && __connman_device_scanning(device) == FALSE) + __connman_service_auto_connect(); + } return service; } @@ -3583,6 +4754,9 @@ void __connman_service_update_from_network(struct connman_network *network) DBUS_TYPE_STRING, &service->name); } + if (service->type == CONNMAN_SERVICE_TYPE_WIFI) + service->wps = connman_network_get_bool(network, "WiFi.WPS"); + strength = connman_network_get_uint8(service->network, "Strength"); if (strength == service->strength) goto roaming; @@ -3670,7 +4844,7 @@ __connman_service_create_from_provider(struct connman_provider *provider) service->provider = connman_provider_ref(provider); service->autoconnect = FALSE; - service->state = CONNMAN_SERVICE_STATE_IDLE; + service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE; str = connman_provider_get_string(provider, "Name"); if (str != NULL) { @@ -3685,73 +4859,33 @@ __connman_service_create_from_provider(struct connman_provider *provider) service->strength = 0; - service->ipconfig = connman_ipconfig_create(index); - if (service->ipconfig == NULL) + if (service->ipconfig_ipv4 == NULL) + service->ipconfig_ipv4 = connman_ipconfig_create(index, + CONNMAN_IPCONFIG_TYPE_IPV4); + if (service->ipconfig_ipv4 == NULL) return service; - connman_ipconfig_set_method(service->ipconfig, + connman_ipconfig_set_method(service->ipconfig_ipv4, CONNMAN_IPCONFIG_METHOD_MANUAL); + connman_ipconfig_set_data(service->ipconfig_ipv4, service); + connman_ipconfig_set_ops(service->ipconfig_ipv4, &service_ops); - connman_ipconfig_set_data(service->ipconfig, service); + if (service->ipconfig_ipv6 == NULL) + service->ipconfig_ipv6 = connman_ipconfig_create(index, + CONNMAN_IPCONFIG_TYPE_IPV6); + if (service->ipconfig_ipv6 == NULL) + return service; - connman_ipconfig_set_ops(service->ipconfig, &service_ops); + connman_ipconfig_set_method(service->ipconfig_ipv6, + CONNMAN_IPCONFIG_METHOD_OFF); + connman_ipconfig_set_data(service->ipconfig_ipv6, service); + connman_ipconfig_set_ops(service->ipconfig_ipv6, &service_ops); service_register(service); return service; } -connman_bool_t __connman_service_stats_update(struct connman_service *service, - unsigned int rx_packets, unsigned int tx_packets, - unsigned int rx_bytes, unsigned int tx_bytes, - unsigned int rx_errors, unsigned int tx_errors, - unsigned int rx_dropped, unsigned int tx_dropped) -{ - unsigned int seconds; - struct connman_stats *stats = stats_get(service); - gboolean valid = stats->valid; - - DBG("service %p", service); - - if (is_connected(service) == FALSE) - return valid; - - if (valid == TRUE) { - stats->rx_packets += - rx_packets - stats->rx_packets_last; - stats->tx_packets += - tx_packets - stats->tx_packets_last; - stats->rx_bytes += - rx_bytes - stats->rx_bytes_last; - stats->tx_bytes += - tx_bytes - stats->tx_bytes_last; - stats->rx_errors += - rx_errors - stats->rx_errors_last; - stats->tx_errors += - tx_errors - stats->tx_errors_last; - stats->rx_dropped += - rx_dropped - stats->rx_dropped_last; - stats->tx_dropped += - tx_dropped - stats->tx_dropped_last; - } else { - stats->valid = TRUE; - } - - stats->rx_packets_last = rx_packets; - stats->tx_packets_last = tx_packets; - stats->rx_bytes_last = rx_bytes; - stats->tx_bytes_last = tx_bytes; - stats->rx_errors_last = rx_errors; - stats->tx_errors_last = tx_errors; - stats->rx_dropped_last = rx_dropped; - stats->tx_dropped_last = tx_dropped; - - seconds = g_timer_elapsed(stats->timer, NULL); - stats->time = stats->time_start + seconds; - - return valid; -} - static int service_load(struct connman_service *service) { const char *ident = service->profile; @@ -3796,6 +4930,7 @@ static int service_load(struct connman_service *service) case CONNMAN_SERVICE_TYPE_ETHERNET: case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_VPN: + case CONNMAN_SERVICE_TYPE_GADGET: break; case CONNMAN_SERVICE_TYPE_WIFI: if (service->name == NULL) { @@ -3850,15 +4985,6 @@ static int service_load(struct connman_service *service) case CONNMAN_SERVICE_TYPE_WIMAX: case CONNMAN_SERVICE_TYPE_BLUETOOTH: case CONNMAN_SERVICE_TYPE_CELLULAR: - service->apn = g_key_file_get_string(keyfile, - service->identifier, "APN", NULL); - - service->username = g_key_file_get_string(keyfile, - service->identifier, "Username", NULL); - - service->password = g_key_file_get_string(keyfile, - service->identifier, "Password", NULL); - service->favorite = g_key_file_get_boolean(keyfile, service->identifier, "Favorite", NULL); @@ -3871,7 +4997,9 @@ static int service_load(struct connman_service *service) str = g_key_file_get_string(keyfile, service->identifier, "Failure", NULL); if (str != NULL) { - service->state = CONNMAN_SERVICE_STATE_FAILURE; + if (service->favorite == FALSE) + service->state_ipv4 = service->state_ipv6 = + CONNMAN_SERVICE_STATE_FAILURE; service->error = string2error(str); } break; @@ -3891,24 +5019,19 @@ static int service_load(struct connman_service *service) service->passphrase = str; } - if (service->ipconfig != NULL) { - struct connman_ipconfig *ipv6config; + if (service->ipconfig_ipv4 != NULL) + __connman_ipconfig_load(service->ipconfig_ipv4, keyfile, + service->identifier, "IPv4."); - ipv6config = connman_ipconfig_get_ipv6config( - service->ipconfig); - if (ipv6config != NULL) - __connman_ipconfig_load(ipv6config, keyfile, + if (service->ipconfig_ipv6 != NULL) + __connman_ipconfig_load(service->ipconfig_ipv6, keyfile, service->identifier, "IPv6."); - __connman_ipconfig_load(service->ipconfig, keyfile, - service->identifier, "IPv4."); - } - - service->nameservers = g_key_file_get_string_list(keyfile, + service->nameservers_config = g_key_file_get_string_list(keyfile, service->identifier, "Nameservers", &length, NULL); - if (service->nameservers != NULL && length == 0) { - g_strfreev(service->nameservers); - service->nameservers = NULL; + if (service->nameservers_config != NULL && length == 0) { + g_strfreev(service->nameservers_config); + service->nameservers_config = NULL; } service->domains = g_key_file_get_string_list(keyfile, @@ -3918,7 +5041,34 @@ static int service_load(struct connman_service *service) service->domains = NULL; } - stats_load(service, keyfile); + str = g_key_file_get_string(keyfile, + service->identifier, "Proxy.Method", NULL); + if (str != NULL) + service->proxy_config = string2proxymethod(str); + + g_free(str); + + service->proxies = g_key_file_get_string_list(keyfile, + service->identifier, "Proxy.Servers", &length, NULL); + if (service->proxies != NULL && length == 0) { + g_strfreev(service->proxies); + service->proxies = NULL; + } + + service->excludes = g_key_file_get_string_list(keyfile, + service->identifier, "Proxy.Excludes", &length, NULL); + if (service->excludes != NULL && length == 0) { + g_strfreev(service->excludes); + service->excludes = NULL; + } + + str = g_key_file_get_string(keyfile, + service->identifier, "Proxy.URL", NULL); + if (str != NULL) { + g_free(service->pac); + service->pac = str; + } + done: g_key_file_free(keyfile); @@ -3932,6 +5082,7 @@ static int service_save(struct connman_service *service) gchar *pathname, *data = NULL; gsize length; gchar *str; + const char *cst_str = NULL; int err = 0; DBG("service %p", service); @@ -3967,6 +5118,7 @@ update: case CONNMAN_SERVICE_TYPE_ETHERNET: case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_VPN: + case CONNMAN_SERVICE_TYPE_GADGET: break; case CONNMAN_SERVICE_TYPE_WIFI: if (service->network) { @@ -4002,18 +5154,6 @@ update: case CONNMAN_SERVICE_TYPE_WIMAX: case CONNMAN_SERVICE_TYPE_BLUETOOTH: case CONNMAN_SERVICE_TYPE_CELLULAR: - if (service->apn != NULL) - g_key_file_set_string(keyfile, service->identifier, - "APN", service->apn); - - if (service->username != NULL) - g_key_file_set_string(keyfile, service->identifier, - "Username", service->username); - - if (service->password != NULL) - g_key_file_set_string(keyfile, service->identifier, - "Password", service->password); - g_key_file_set_boolean(keyfile, service->identifier, "Favorite", service->favorite); @@ -4021,7 +5161,8 @@ update: g_key_file_set_boolean(keyfile, service->identifier, "AutoConnect", service->autoconnect); - if (service->state == CONNMAN_SERVICE_STATE_FAILURE) { + if (service->state_ipv4 == CONNMAN_SERVICE_STATE_FAILURE || + service->state_ipv6 == CONNMAN_SERVICE_STATE_FAILURE) { const char *failure = error2string(service->error); if (failure != NULL) g_key_file_set_string(keyfile, @@ -4048,24 +5189,20 @@ update: g_key_file_remove_key(keyfile, service->identifier, "Passphrase", NULL); - if (service->ipconfig != NULL) { - struct connman_ipconfig *ipv6config; + if (service->ipconfig_ipv4 != NULL) + __connman_ipconfig_save(service->ipconfig_ipv4, keyfile, + service->identifier, "IPv4."); - ipv6config = connman_ipconfig_get_ipv6config(service->ipconfig); - if (ipv6config != NULL) - __connman_ipconfig_save(ipv6config, keyfile, + if (service->ipconfig_ipv6 != NULL) + __connman_ipconfig_save(service->ipconfig_ipv6, keyfile, service->identifier, "IPv6."); - __connman_ipconfig_save(service->ipconfig, keyfile, - service->identifier, "IPv4."); - } - - if (service->nameservers != NULL) { - guint len = g_strv_length(service->nameservers); + if (service->nameservers_config != NULL) { + guint len = g_strv_length(service->nameservers_config); g_key_file_set_string_list(keyfile, service->identifier, "Nameservers", - (const gchar **) service->nameservers, len); + (const gchar **) service->nameservers_config, len); } else g_key_file_remove_key(keyfile, service->identifier, "Nameservers", NULL); @@ -4080,7 +5217,37 @@ update: g_key_file_remove_key(keyfile, service->identifier, "Domains", NULL); - stats_save(service, keyfile); + cst_str = proxymethod2string(service->proxy_config); + if (cst_str != NULL) + g_key_file_set_string(keyfile, service->identifier, + "Proxy.Method", cst_str); + + if (service->proxies != NULL) { + guint len = g_strv_length(service->proxies); + + g_key_file_set_string_list(keyfile, service->identifier, + "Proxy.Servers", + (const gchar **) service->proxies, len); + } else + g_key_file_remove_key(keyfile, service->identifier, + "Proxy.Servers", NULL); + + if (service->excludes != NULL) { + guint len = g_strv_length(service->excludes); + + g_key_file_set_string_list(keyfile, service->identifier, + "Proxy.Excludes", + (const gchar **) service->excludes, len); + } else + g_key_file_remove_key(keyfile, service->identifier, + "Proxy.Excludes", NULL); + + if (service->pac != NULL && strlen(service->pac) > 0) + g_key_file_set_string(keyfile, service->identifier, + "Proxy.URL", service->pac); + else + g_key_file_remove_key(keyfile, service->identifier, + "Proxy.URL", NULL); data = g_key_file_to_data(keyfile, &length, NULL); @@ -4131,6 +5298,9 @@ void __connman_service_cleanup(void) g_hash_table_destroy(service_hash); service_hash = NULL; + g_slist_free(counter_list); + counter_list = NULL; + connman_storage_unregister(&service_storage); dbus_connection_unref(connection);