diff options
author | Zhang zhengguang <zhengguang.zhang@intel.com> | 2014-10-29 11:03:47 +0800 |
---|---|---|
committer | Zhang zhengguang <zhengguang.zhang@intel.com> | 2014-10-29 11:03:47 +0800 |
commit | bcae74da8fa2958b3fec9153fc33e41f0e0317bf (patch) | |
tree | 06a00f6457307467fee4f6580dce4a1a857751c1 /src/service.c | |
parent | 1b9d0a62f59bb48c8deb2f0b98d9acdffdd9abe7 (diff) | |
download | connman-bcae74da8fa2958b3fec9153fc33e41f0e0317bf.tar.gz connman-bcae74da8fa2958b3fec9153fc33e41f0e0317bf.tar.bz2 connman-bcae74da8fa2958b3fec9153fc33e41f0e0317bf.zip |
Imported Upstream version 1.26upstream/1.26
Diffstat (limited to 'src/service.c')
-rw-r--r-- | src/service.c | 417 |
1 files changed, 188 insertions, 229 deletions
diff --git a/src/service.c b/src/service.c index cbca669e..87a2f2cd 100644 --- a/src/service.c +++ b/src/service.c @@ -234,6 +234,23 @@ enum connman_service_type __connman_service_string2type(const char *str) return CONNMAN_SERVICE_TYPE_UNKNOWN; } +enum connman_service_security __connman_service_string2security(const char *str) +{ + if (!str) + return CONNMAN_SERVICE_SECURITY_UNKNOWN; + + if (!strcmp(str, "psk")) + return CONNMAN_SERVICE_SECURITY_PSK; + if (!strcmp(str, "ieee8021x")) + return CONNMAN_SERVICE_SECURITY_8021X; + if (!strcmp(str, "none")) + return CONNMAN_SERVICE_SECURITY_NONE; + if (!strcmp(str, "wep")) + return CONNMAN_SERVICE_SECURITY_WEP; + + return CONNMAN_SERVICE_SECURITY_UNKNOWN; +} + static const char *security2string(enum connman_service_security security) { switch (security) { @@ -302,18 +319,6 @@ static const char *error2string(enum connman_service_error error) return NULL; } -static enum connman_service_error string2error(const char *error) -{ - if (g_strcmp0(error, "dhcp-failed") == 0) - 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 const char *proxymethod2string(enum connman_service_proxy_method method) { switch (method) { @@ -480,15 +485,6 @@ static int service_load(struct connman_service *service) service->favorite = g_key_file_get_boolean(keyfile, service->identifier, "Favorite", NULL); - str = g_key_file_get_string(keyfile, - service->identifier, "Failure", NULL); - if (str) { - if (!service->favorite) - service->state_ipv4 = service->state_ipv6 = - CONNMAN_SERVICE_STATE_FAILURE; - service->error = string2error(str); - g_free(str); - } /* fall through */ case CONNMAN_SERVICE_TYPE_ETHERNET: @@ -655,17 +651,9 @@ static int service_save(struct connman_service *service) g_key_file_set_boolean(keyfile, service->identifier, "Favorite", service->favorite); - if (service->state_ipv4 == CONNMAN_SERVICE_STATE_FAILURE || - service->state_ipv6 == CONNMAN_SERVICE_STATE_FAILURE) { - const char *failure = error2string(service->error); - if (failure) - g_key_file_set_string(keyfile, - service->identifier, - "Failure", failure); - } else { - g_key_file_remove_key(keyfile, service->identifier, - "Failure", NULL); - } + g_key_file_remove_key(keyfile, service->identifier, + "Failure", NULL); + /* fall through */ case CONNMAN_SERVICE_TYPE_ETHERNET: @@ -2804,30 +2792,29 @@ void __connman_service_set_agent_identity(struct connman_service *service, service->agent_identity); } -static int check_passphrase(struct connman_service *service, - enum connman_service_security security, - const char *passphrase) +static int check_passphrase(enum connman_service_security security, + const char *passphrase) { guint i; gsize length; - if (!passphrase) { - /* - * This will prevent __connman_service_set_passphrase() to - * wipe the passphrase out in case of -ENOKEY error for a - * favorite service. */ - if (service->favorite) - return 1; - else - return 0; - } + if (!passphrase) + return 0; length = strlen(passphrase); switch (security) { - case CONNMAN_SERVICE_SECURITY_PSK: + case CONNMAN_SERVICE_SECURITY_UNKNOWN: + case CONNMAN_SERVICE_SECURITY_NONE: case CONNMAN_SERVICE_SECURITY_WPA: case CONNMAN_SERVICE_SECURITY_RSN: + + DBG("service security '%s' (%d) not handled", + security2string(security), security); + + return -EOPNOTSUPP; + + case CONNMAN_SERVICE_SECURITY_PSK: /* A raw key is always 64 bytes length, * its content is in hex representation. * A PSK key must be between [8..63]. @@ -2852,8 +2839,7 @@ static int check_passphrase(struct connman_service *service, } else if (length != 5 && length != 13) return -ENOKEY; break; - case CONNMAN_SERVICE_SECURITY_UNKNOWN: - case CONNMAN_SERVICE_SECURITY_NONE: + case CONNMAN_SERVICE_SECURITY_8021X: break; } @@ -2864,25 +2850,29 @@ static int check_passphrase(struct connman_service *service, int __connman_service_set_passphrase(struct connman_service *service, const char *passphrase) { - int err = 0; + int err; - if (service->immutable || service->hidden) + if (service->hidden) + return -EINVAL; + + if (service->immutable && + service->security != CONNMAN_SERVICE_SECURITY_8021X) return -EINVAL; - err = check_passphrase(service, service->security, passphrase); + err = check_passphrase(service->security, passphrase); - if (err == 0) { - g_free(service->passphrase); - service->passphrase = g_strdup(passphrase); + if (err < 0) + return err; - if (service->network) - connman_network_set_string(service->network, - "WiFi.Passphrase", - service->passphrase); - service_save(service); - } + g_free(service->passphrase); + service->passphrase = g_strdup(passphrase); - return err; + if (service->network) + connman_network_set_string(service->network, "WiFi.Passphrase", + service->passphrase); + service_save(service); + + return 0; } const char *__connman_service_get_passphrase(struct connman_service *service) @@ -2893,6 +2883,16 @@ const char *__connman_service_get_passphrase(struct connman_service *service) return service->passphrase; } +static void clear_passphrase(struct connman_service *service) +{ + g_free(service->passphrase); + service->passphrase = NULL; + + if (service->network) + connman_network_set_string(service->network, "WiFi.Passphrase", + service->passphrase); +} + static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg, void *user_data) { @@ -3133,6 +3133,7 @@ int __connman_service_reset_ipconfig(struct connman_service *service, if (is_connecting_state(service, state) || is_connected_state(service, state)) __connman_network_clear_ipconfig(service->network, ipconfig); + __connman_ipconfig_unref(ipconfig); if (type == CONNMAN_IPCONFIG_TYPE_IPV4) @@ -3140,13 +3141,16 @@ int __connman_service_reset_ipconfig(struct connman_service *service, else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) service->ipconfig_ipv6 = new_ipconfig; - __connman_ipconfig_enable(new_ipconfig); + if (is_connecting_state(service, state) || + is_connected_state(service, state)) + __connman_ipconfig_enable(new_ipconfig); if (new_state && new_method != old_method) { if (type == CONNMAN_IPCONFIG_TYPE_IPV4) *new_state = service->state_ipv4; else *new_state = service->state_ipv6; + __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO); } @@ -3800,50 +3804,17 @@ static void remove_timeout(struct connman_service *service) } } -void __connman_service_reply_dbus_pending(DBusMessage *pending, int error, - const char *path) -{ - if (pending) { - if (error > 0) { - DBusMessage *reply; - - reply = __connman_error_failed(pending, error); - if (reply) - g_dbus_send_message(connection, reply); - } else { - const char *sender; - - sender = dbus_message_get_interface(pending); - if (!path) - path = dbus_message_get_path(pending); - - DBG("sender %s path %s", sender, path); - - if (g_strcmp0(sender, CONNMAN_MANAGER_INTERFACE) == 0) - g_dbus_send_reply(connection, pending, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID); - else - g_dbus_send_reply(connection, pending, - DBUS_TYPE_INVALID); - } - - dbus_message_unref(pending); - } -} - static void reply_pending(struct connman_service *service, int error) { remove_timeout(service); if (service->pending) { - __connman_service_reply_dbus_pending(service->pending, error, - NULL); + connman_dbus_reply_pending(service->pending, error, NULL); service->pending = NULL; } if (service->provider_pending) { - __connman_service_reply_dbus_pending(service->provider_pending, + connman_dbus_reply_pending(service->provider_pending, error, service->path); service->provider_pending = NULL; } @@ -3955,34 +3926,11 @@ static gboolean connect_timeout(gpointer user_data) return FALSE; } -static bool is_interface_available(struct connman_service *service, - struct connman_service *other_service) -{ - unsigned int index = 0, other_index = 0; - - 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); - - if (other_service->ipconfig_ipv4) - other_index = __connman_ipconfig_get_index( - other_service->ipconfig_ipv4); - else if (other_service->ipconfig_ipv6) - other_index = __connman_ipconfig_get_index( - other_service->ipconfig_ipv6); - - if (index > 0 && other_index != index) - return true; - - return false; -} - static DBusMessage *connect_service(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct connman_service *service = user_data; - int err = 0; + int index, err = 0; GList *list; DBG("service %p", service); @@ -3990,27 +3938,27 @@ static DBusMessage *connect_service(DBusConnection *conn, if (service->pending) return __connman_error_in_progress(msg); + index = __connman_service_get_index(service); + for (list = service_list; list; list = list->next) { struct connman_service *temp = list->data; - /* - * We should allow connection if there are available - * interfaces for a given technology type (like having - * more than one wifi card). - */ if (!is_connecting(temp) && !is_connected(temp)) break; + if (service == temp) + continue; + if (service->type != temp->type) continue; - if(!is_interface_available(service, temp)) { - if (__connman_service_disconnect(temp) == -EINPROGRESS) - err = -EINPROGRESS; - } + if (__connman_service_get_index(temp) == index && + __connman_service_disconnect(temp) == -EINPROGRESS) + err = -EINPROGRESS; + } if (err == -EINPROGRESS) - return __connman_error_in_progress(msg); + return __connman_error_operation_timeout(msg); service->ignore = false; @@ -4022,8 +3970,10 @@ static DBusMessage *connect_service(DBusConnection *conn, if (err == -EINPROGRESS) return NULL; - dbus_message_unref(service->pending); - service->pending = NULL; + if (service->pending) { + dbus_message_unref(service->pending); + service->pending = NULL; + } if (err < 0) return __connman_error_failed(msg, -err); @@ -4042,10 +3992,8 @@ static DBusMessage *disconnect_service(DBusConnection *conn, service->ignore = true; err = __connman_service_disconnect(service); - if (err < 0) { - if (err != -EINPROGRESS) - return __connman_error_failed(msg, -err); - } + if (err < 0 && err != -EINPROGRESS) + return __connman_error_failed(msg, -err); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } @@ -4082,6 +4030,8 @@ bool __connman_service_remove(struct connman_service *service) __connman_service_set_favorite(service, false); + __connman_ipconfig_ipv6_reset_privacy(service->ipconfig_ipv6); + service_save(service); return true; @@ -4397,13 +4347,13 @@ static void service_schedule_added(struct connman_service *service) static void service_schedule_removed(struct connman_service *service) { - DBG("service %p %s", service, service->path); - if (!service || !service->path) { DBG("service %p or path is NULL", service); return; } + DBG("service %p %s", service, service->path); + g_hash_table_remove(services_notify->add, service->path); g_hash_table_replace(services_notify->remove, g_strdup(service->path), NULL); @@ -5003,10 +4953,8 @@ void __connman_service_set_string(struct connman_service *service, } else if (g_str_equal(key, "Phase2")) { g_free(service->phase2); service->phase2 = g_strdup(value); - } else if (g_str_equal(key, "Passphrase")) { - g_free(service->passphrase); - service->passphrase = g_strdup(value); - } + } else if (g_str_equal(key, "Passphrase")) + __connman_service_set_passphrase(service, value); } void __connman_service_set_search_domains(struct connman_service *service, @@ -5062,38 +5010,13 @@ static void report_error_cb(void *user_context, bool retry, else { /* It is not relevant to stay on Failure state * when failing is due to wrong user input */ - service->state = CONNMAN_SERVICE_STATE_IDLE; + __connman_service_clear_error(service); service_complete(service); __connman_connection_update_gateway(); } } -int __connman_service_add_passphrase(struct connman_service *service, - const gchar *passphrase) -{ - int err = 0; - - switch (service->security) { - case CONNMAN_SERVICE_SECURITY_WEP: - case CONNMAN_SERVICE_SECURITY_PSK: - case CONNMAN_SERVICE_SECURITY_8021X: - err = __connman_service_set_passphrase(service, passphrase); - break; - - case CONNMAN_SERVICE_SECURITY_UNKNOWN: - case CONNMAN_SERVICE_SECURITY_NONE: - case CONNMAN_SERVICE_SECURITY_WPA: - case CONNMAN_SERVICE_SECURITY_RSN: - DBG("service security '%s' (%d) not handled", - security2string(service->security), - service->security); - break; - } - - return err; -} - static int check_wpspin(struct connman_service *service, const char *wpspin) { int length; @@ -5187,7 +5110,7 @@ static void request_input_cb(struct connman_service *service, __connman_service_set_agent_identity(service, identity); if (passphrase) - err = __connman_service_add_passphrase(service, passphrase); + err = __connman_service_set_passphrase(service, passphrase); done: if (err >= 0) { @@ -5311,6 +5234,7 @@ static int service_indicate_state(struct connman_service *service) { enum connman_service_state old_state, new_state; struct connman_service *def_service; + enum connman_ipconfig_method method; int result; if (!service) @@ -5344,13 +5268,22 @@ static int service_indicate_state(struct connman_service *service) service->state = new_state; state_changed(service); - if (new_state == CONNMAN_SERVICE_STATE_IDLE && - old_state != CONNMAN_SERVICE_STATE_DISCONNECT) { + switch(new_state) { + case CONNMAN_SERVICE_STATE_UNKNOWN: - __connman_service_disconnect(service); - } + break; + + case CONNMAN_SERVICE_STATE_IDLE: + if (old_state != CONNMAN_SERVICE_STATE_DISCONNECT) + __connman_service_disconnect(service); + + break; + + case CONNMAN_SERVICE_STATE_ASSOCIATION: - if (new_state == CONNMAN_SERVICE_STATE_CONFIGURATION) { + break; + + case CONNMAN_SERVICE_STATE_CONFIGURATION: if (!service->new_service && __connman_stats_service_register(service) == 0) { /* @@ -5362,11 +5295,10 @@ static int service_indicate_state(struct connman_service *service) __connman_stats_get(service, true, &service->stats_roaming.data); } - } - if (new_state == CONNMAN_SERVICE_STATE_READY) { - enum connman_ipconfig_method method; + break; + case CONNMAN_SERVICE_STATE_READY: if (service->new_service && __connman_stats_service_register(service) == 0) { /* @@ -5426,7 +5358,16 @@ static int service_indicate_state(struct connman_service *service) else if (service->type != CONNMAN_SERVICE_TYPE_VPN) vpn_auto_connect(); - } else if (new_state == CONNMAN_SERVICE_STATE_DISCONNECT) { + break; + + case CONNMAN_SERVICE_STATE_ONLINE: + + break; + + case CONNMAN_SERVICE_STATE_DISCONNECT: + + reply_pending(service, ECONNABORTED); + def_service = __connman_service_get_default(); if (!__connman_notifier_is_connected() && @@ -5452,9 +5393,9 @@ static int service_indicate_state(struct connman_service *service) downgrade_connected_services(); __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO); - } + break; - if (new_state == CONNMAN_SERVICE_STATE_FAILURE) { + case CONNMAN_SERVICE_STATE_FAILURE: if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER && connman_agent_report_error(service, service->path, @@ -5464,7 +5405,11 @@ static int service_indicate_state(struct connman_service *service) NULL) == -EINPROGRESS) return 0; service_complete(service); - } else + + break; + } + + if (new_state != CONNMAN_SERVICE_STATE_FAILURE) set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN); service_list_sort(); @@ -5502,7 +5447,7 @@ int __connman_service_indicate_error(struct connman_service *service, */ if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY || service->security == CONNMAN_SERVICE_SECURITY_8021X) - __connman_service_set_passphrase(service, NULL); + clear_passphrase(service); __connman_service_set_agent_identity(service, NULL); @@ -5517,6 +5462,8 @@ int __connman_service_indicate_error(struct connman_service *service, int __connman_service_clear_error(struct connman_service *service) { + DBusMessage *pending, *provider_pending; + DBG("service %p", service); if (!service) @@ -5525,25 +5472,23 @@ int __connman_service_clear_error(struct connman_service *service) if (service->state != CONNMAN_SERVICE_STATE_FAILURE) return -EINVAL; - service->state_ipv4 = service->state_ipv6 = - CONNMAN_SERVICE_STATE_UNKNOWN; - set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN); + pending = service->pending; + service->pending = NULL; + provider_pending = service->provider_pending; + service->provider_pending = NULL; __connman_service_ipconfig_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; + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV6); - return __connman_service_ipconfig_indicate_state(service, + __connman_service_ipconfig_indicate_state(service, CONNMAN_SERVICE_STATE_IDLE, CONNMAN_IPCONFIG_TYPE_IPV4); + + service->pending = pending; + service->provider_pending = provider_pending; + + return 0; } int __connman_service_indicate_default(struct connman_service *service) @@ -5708,38 +5653,45 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service, enum connman_ipconfig_type type) { struct connman_ipconfig *ipconfig = NULL; - enum connman_service_state old_state; + enum connman_service_state *old_state; enum connman_ipconfig_method method; if (!service) return -EINVAL; - if (type == CONNMAN_IPCONFIG_TYPE_IPV4) { - old_state = service->state_ipv4; + switch (type) { + case CONNMAN_IPCONFIG_TYPE_UNKNOWN: + return -EINVAL; + + case CONNMAN_IPCONFIG_TYPE_IPV4: + old_state = &service->state_ipv4; ipconfig = service->ipconfig_ipv4; - } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) { - old_state = service->state_ipv6; + + break; + + case CONNMAN_IPCONFIG_TYPE_IPV6: + old_state = &service->state_ipv6; ipconfig = service->ipconfig_ipv6; + + break; } if (!ipconfig) return -EINVAL; /* Any change? */ - if (old_state == new_state) + if (*old_state == new_state) return -EALREADY; - DBG("service %p (%s) state %d (%s) type %d (%s)", + DBG("service %p (%s) old state %d (%s) new state %d (%s) type %d (%s)", service, service ? service->identifier : NULL, + *old_state, state2string(*old_state), new_state, state2string(new_state), type, __connman_ipconfig_type2string(type)); switch (new_state) { case CONNMAN_SERVICE_STATE_UNKNOWN: case CONNMAN_SERVICE_STATE_IDLE: - if (service->state == CONNMAN_SERVICE_STATE_FAILURE) - return -EINVAL; - break; case CONNMAN_SERVICE_STATE_ASSOCIATION: break; case CONNMAN_SERVICE_STATE_CONFIGURATION: @@ -5772,25 +5724,23 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service, the state to IDLE so that it will not affect the combined state in the future. */ - if (type == CONNMAN_IPCONFIG_TYPE_IPV4) { - method = __connman_ipconfig_get_method(service->ipconfig_ipv4); - - if (method == CONNMAN_IPCONFIG_METHOD_OFF || - method == CONNMAN_IPCONFIG_METHOD_UNKNOWN) - new_state = CONNMAN_SERVICE_STATE_IDLE; - - service->state_ipv4 = new_state; - - } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) { - method = __connman_ipconfig_get_method(service->ipconfig_ipv6); + method = __connman_ipconfig_get_method(ipconfig); + switch (method) { + case CONNMAN_IPCONFIG_METHOD_UNKNOWN: + case CONNMAN_IPCONFIG_METHOD_OFF: + new_state = CONNMAN_SERVICE_STATE_IDLE; + break; - if (method == CONNMAN_IPCONFIG_METHOD_OFF || - method == CONNMAN_IPCONFIG_METHOD_UNKNOWN) - new_state = CONNMAN_SERVICE_STATE_IDLE; + case CONNMAN_IPCONFIG_METHOD_FIXED: + case CONNMAN_IPCONFIG_METHOD_MANUAL: + case CONNMAN_IPCONFIG_METHOD_DHCP: + case CONNMAN_IPCONFIG_METHOD_AUTO: + break; - service->state_ipv6 = new_state; } + *old_state = new_state; + update_nameservers(service); return service_indicate_state(service); @@ -5896,10 +5846,9 @@ static int service_connect(struct connman_service *service) if (!service->wps || !connman_network_get_bool(service->network, "WiFi.UseWPS")) return -ENOKEY; - } else if (service->error == - CONNMAN_SERVICE_ERROR_INVALID_KEY) - return -ENOKEY; + } break; + case CONNMAN_SERVICE_SECURITY_8021X: if (!service->eap) return -EINVAL; @@ -5995,13 +5944,23 @@ int __connman_service_connect(struct connman_service *service, case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_P2P: return -EINVAL; - default: - if (!is_ipconfig_usable(service)) - return -ENOLINK; - err = service_connect(service); + case CONNMAN_SERVICE_TYPE_ETHERNET: + case CONNMAN_SERVICE_TYPE_GADGET: + case CONNMAN_SERVICE_TYPE_BLUETOOTH: + case CONNMAN_SERVICE_TYPE_CELLULAR: + case CONNMAN_SERVICE_TYPE_VPN: + case CONNMAN_SERVICE_TYPE_WIFI: + break; } + if (!is_ipconfig_usable(service)) + return -ENOLINK; + + __connman_service_clear_error(service); + + err = service_connect(service); + service->connect_reason = reason; if (err >= 0) { set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN); |