X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fservice.c;h=bb01e6ffb2e9a7b982eb681b935d82daf0ce9e44;hb=012bd3d307134928123b1479591bf754fe8713d3;hp=a6c764caac890a016314b7d96847413b88495806;hpb=f5af5715d88a0525e6bc6323d196bd78680e67d1;p=framework%2Fconnectivity%2Fconnman.git diff --git a/src/service.c b/src/service.c index a6c764c..bb01e6f 100644 --- a/src/service.c +++ b/src/service.c @@ -56,8 +56,8 @@ struct connman_stats_counter { }; struct connman_service { - gint refcount; - gint session_usage_count; + int refcount; + int session_usage_count; char *identifier; char *path; enum connman_service_type type; @@ -87,6 +87,7 @@ struct connman_service { struct connman_provider *provider; char **nameservers; char **nameservers_config; + char **nameservers_auto; char **domains; char *domainname; char **timeservers; @@ -391,6 +392,7 @@ static int service_load(struct connman_service *service) service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_FAILURE; service->error = string2error(str); + g_free(str); } break; } @@ -835,8 +837,6 @@ static void update_nameservers(struct connman_service *service) break; } - connman_resolver_remove_all(ifname); - if (service->nameservers_config != NULL) { int i; @@ -865,63 +865,95 @@ static void update_nameservers(struct connman_service *service) connman_resolver_flush(); } +/* + * The is_auto variable is set to true when IPv6 autoconf nameservers are + * inserted to resolver via netlink message (see rtnl.c:rtnl_newnduseropt() + * for details) and not through service.c + */ int __connman_service_nameserver_append(struct connman_service *service, - const char *nameserver) + const char *nameserver, gboolean is_auto) { - int len; + char **nameservers; + int len, i; - DBG("service %p nameserver %s", service, nameserver); + DBG("service %p nameserver %s auto %d", service, nameserver, is_auto); if (nameserver == NULL) return -EINVAL; - if (service->nameservers != NULL) { - int i; + if (is_auto == TRUE) + nameservers = service->nameservers_auto; + else + nameservers = service->nameservers; - for (i = 0; service->nameservers[i] != NULL; i++) - if (g_strcmp0(service->nameservers[i], nameserver) == 0) - return -EEXIST; + for (i = 0; nameservers != NULL && nameservers[i] != NULL; i++) + if (g_strcmp0(nameservers[i], nameserver) == 0) + return -EEXIST; - len = g_strv_length(service->nameservers); - service->nameservers = g_try_renew(char *, service->nameservers, - len + 2); + if (nameservers != NULL) { + len = g_strv_length(nameservers); + nameservers = g_try_renew(char *, nameservers, len + 2); } else { len = 0; - service->nameservers = g_try_new0(char *, len + 2); + nameservers = g_try_new0(char *, len + 2); } - if (service->nameservers == NULL) + if (nameservers == NULL) return -ENOMEM; - service->nameservers[len] = g_strdup(nameserver); - service->nameservers[len + 1] = NULL; + nameservers[len] = g_strdup(nameserver); + if (nameservers[len] == NULL) + return -ENOMEM; - update_nameservers(service); + nameservers[len + 1] = NULL; + + if (is_auto == TRUE) { + service->nameservers_auto = nameservers; + } else { + service->nameservers = nameservers; + update_nameservers(service); + } return 0; } int __connman_service_nameserver_remove(struct connman_service *service, - const char *nameserver) + const char *nameserver, gboolean is_auto) { - char **servers; + char **servers, **nameservers; + gboolean found = FALSE; int len, i, j; - DBG("service %p nameserver %s", service, nameserver); + DBG("service %p nameserver %s auto %d", service, nameserver, is_auto); if (nameserver == NULL) return -EINVAL; - if (service->nameservers == NULL) + if (is_auto == TRUE) + nameservers = service->nameservers_auto; + else + nameservers = service->nameservers; + + if (nameservers == NULL) return 0; - len = g_strv_length(service->nameservers); - if (len == 1) { - if (g_strcmp0(service->nameservers[0], nameserver) != 0) - return 0; + for (i = 0; nameservers != NULL && nameservers[i] != NULL; i++) + if (g_strcmp0(nameservers[i], nameserver) == 0) { + found = TRUE; + break; + } + + if (found == FALSE) + return 0; - g_strfreev(service->nameservers); - service->nameservers = NULL; + len = g_strv_length(nameservers); + + if (len == 1) { + g_strfreev(nameservers); + if (is_auto == TRUE) + service->nameservers_auto = NULL; + else + service->nameservers = NULL; return 0; } @@ -931,17 +963,24 @@ int __connman_service_nameserver_remove(struct connman_service *service, 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]); + if (g_strcmp0(nameservers[i], nameserver) != 0) { + servers[j] = g_strdup(nameservers[i]); + if (servers[j] == NULL) + return -ENOMEM; j++; } } servers[len - 1] = NULL; - g_strfreev(service->nameservers); - service->nameservers = servers; + g_strfreev(nameservers); + nameservers = servers; - update_nameservers(service); + if (is_auto == TRUE) { + service->nameservers_auto = nameservers; + } else { + service->nameservers = nameservers; + update_nameservers(service); + } return 0; } @@ -1421,9 +1460,12 @@ static void append_dns(DBusMessageIter *iter, void *user_data) if (service->nameservers_config != NULL) { append_nameserver(iter, &service->nameservers_config); return; - } else if (service->nameservers != NULL) { - append_nameserver(iter, &service->nameservers); - return; + } else { + if (service->nameservers != NULL) + append_nameserver(iter, &service->nameservers); + + if (service->nameservers_auto != NULL) + append_nameserver(iter, &service->nameservers_auto); } } @@ -1985,17 +2027,17 @@ GSequence *__connman_service_get_list(struct connman_session *session, void __connman_service_session_inc(struct connman_service *service) { DBG("service %p ref count %d", service, - g_atomic_int_get(&service->session_usage_count) + 1); + service->session_usage_count + 1); - g_atomic_int_inc(&service->session_usage_count); + __sync_fetch_and_add(&service->session_usage_count, 1); } connman_bool_t __connman_service_session_dec(struct connman_service *service) { DBG("service %p ref count %d", service, - g_atomic_int_get(&service->session_usage_count) - 1); + service->session_usage_count - 1); - if (g_atomic_int_dec_and_test(&service->session_usage_count) == FALSE) + if (__sync_fetch_and_sub(&service->session_usage_count, 1) != 1) return FALSE; return TRUE; @@ -2060,9 +2102,6 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited, connman_dbus_dict_append_basic(dict, "Roaming", DBUS_TYPE_BOOLEAN, &service->roaming); - required = FALSE; - connman_dbus_dict_append_basic(dict, "SetupRequired", - DBUS_TYPE_BOOLEAN, &required); connman_dbus_dict_append_dict(dict, "Ethernet", append_ethernet, service); break; @@ -3213,11 +3252,9 @@ static DBusMessage *remove_service(DBusConnection *conn, CONNMAN_SERVICE_STATE_FAILURE) return __connman_error_not_supported(msg); - if (service->network != NULL) { - set_reconnect_state(service, FALSE); + set_reconnect_state(service, FALSE); - __connman_network_disconnect(service->network); - } + __connman_service_disconnect(service); g_free(service->passphrase); service->passphrase = NULL; @@ -3426,6 +3463,7 @@ static void service_free(gpointer user_data) g_strfreev(service->nameservers); g_strfreev(service->nameservers_config); + g_strfreev(service->nameservers_auto); g_strfreev(service->domains); g_strfreev(service->proxies); g_strfreev(service->excludes); @@ -3461,20 +3499,22 @@ static void service_free(gpointer user_data) */ void __connman_service_put(struct connman_service *service) { + GSequenceIter *iter; + DBG("service %p", service); - if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) { - GSequenceIter *iter; + if (__sync_fetch_and_sub(&service->refcount, 1) != 1) + return; - iter = g_hash_table_lookup(service_hash, service->identifier); - if (iter != NULL) { - reply_pending(service, ECONNABORTED); + iter = g_hash_table_lookup(service_hash, service->identifier); + if (iter != NULL) { + reply_pending(service, ECONNABORTED); - __connman_service_disconnect(service); + __connman_service_disconnect(service); - g_sequence_remove(iter); - } else - service_free(service); + g_sequence_remove(iter); + } else { + service_free(service); } } @@ -3579,7 +3619,7 @@ struct connman_service *connman_service_ref(struct connman_service *service) { DBG("%p", service); - g_atomic_int_inc(&service->refcount); + __sync_fetch_and_add(&service->refcount, 1); return service; } @@ -3799,6 +3839,7 @@ int __connman_service_set_favorite(struct connman_service *service, return -EALREADY; service->favorite = favorite; + service->order = __connman_service_get_order(service); favorite_changed(service); @@ -4129,6 +4170,9 @@ enum connman_service_state __connman_service_ipconfig_get_state( struct connman_service *service, enum connman_ipconfig_type type) { + if (service == NULL) + return CONNMAN_SERVICE_STATE_UNKNOWN; + if (type == CONNMAN_IPCONFIG_TYPE_IPV4) return service->state_ipv4; @@ -4157,6 +4201,7 @@ static void check_proxy_setup(struct connman_service *service) if (__connman_wpad_start(service) < 0) { service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT; __connman_notifier_proxy_changed(service); + goto done; } return; @@ -4165,6 +4210,59 @@ done: __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4); } +/* + * How many networks are connected at the same time. If more than 1, + * then set the rp_filter setting properly (loose mode routing) so that network + * connectivity works ok. This is only done for IPv4 networks as IPv6 + * does not have rp_filter knob. + */ +static int connected_networks_count; +static int original_rp_filter; + +static void service_rp_filter(struct connman_service *service, + gboolean connected) +{ + enum connman_ipconfig_method method; + + method = __connman_ipconfig_get_method(service->ipconfig_ipv4); + + switch (method) { + case CONNMAN_IPCONFIG_METHOD_UNKNOWN: + case CONNMAN_IPCONFIG_METHOD_OFF: + case CONNMAN_IPCONFIG_METHOD_AUTO: + return; + case CONNMAN_IPCONFIG_METHOD_FIXED: + case CONNMAN_IPCONFIG_METHOD_MANUAL: + case CONNMAN_IPCONFIG_METHOD_DHCP: + break; + } + + if (connected == TRUE) { + if (connected_networks_count == 1) { + int filter_value; + filter_value = __connman_ipconfig_set_rp_filter(); + if (filter_value < 0) + return; + + original_rp_filter = filter_value; + } + connected_networks_count++; + + } else { + if (connected_networks_count == 2) + __connman_ipconfig_unset_rp_filter(original_rp_filter); + + connected_networks_count--; + if (connected_networks_count < 0) + connected_networks_count = 0; + } + + DBG("%s %s ipconfig %p method %d count %d filter %d", + connected ? "connected" : "disconnected", service->identifier, + service->ipconfig_ipv4, method, + connected_networks_count, original_rp_filter); +} + int __connman_service_ipconfig_indicate_state(struct connman_service *service, enum connman_service_state new_state, enum connman_ipconfig_type type) @@ -4210,9 +4308,10 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service, case CONNMAN_SERVICE_STATE_READY: update_nameservers(service); - if (type == CONNMAN_IPCONFIG_TYPE_IPV4) + if (type == CONNMAN_IPCONFIG_TYPE_IPV4) { check_proxy_setup(service); - else + service_rp_filter(service, TRUE); + } else __connman_wispr_start(service, type); break; case CONNMAN_SERVICE_STATE_ONLINE: @@ -4220,6 +4319,10 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service, case CONNMAN_SERVICE_STATE_DISCONNECT: if (service->state == CONNMAN_SERVICE_STATE_IDLE) return -EINVAL; + + if (type == CONNMAN_IPCONFIG_TYPE_IPV4) + service_rp_filter(service, FALSE); + break; case CONNMAN_SERVICE_STATE_FAILURE: break; @@ -4547,6 +4650,7 @@ int __connman_service_disconnect(struct connman_service *service) int __connman_service_disconnect_all(void) { GSequenceIter *iter; + GSList *services = NULL, *list; DBG(""); @@ -4555,15 +4659,23 @@ int __connman_service_disconnect_all(void) while (g_sequence_iter_is_end(iter) == FALSE) { struct connman_service *service = g_sequence_get(iter); + services = g_slist_prepend(services, service); + + iter = g_sequence_iter_next(iter); + } + + for (list = services; list != NULL; list = list->next) { + struct connman_service *service = list->data; + service->ignore = TRUE; set_reconnect_state(service, FALSE); __connman_service_disconnect(service); - - iter = g_sequence_iter_next(iter); } + g_slist_free(list); + return 0; } @@ -4579,6 +4691,8 @@ int __connman_service_lookup(const char *pattern, const char **path) { GHashTableIter iter; gpointer key, value; + struct connman_device *device; + const char *ifname; g_hash_table_iter_init(&iter, service_hash); @@ -4591,6 +4705,20 @@ int __connman_service_lookup(const char *pattern, const char **path) *path = (const char *) service->path; return 0; } + + if (service->network == NULL) + continue; + + device = connman_network_get_device(service->network); + if (device == NULL) + continue; + + ifname = connman_device_get_string(device, "Interface"); + if (ifname != NULL && g_strcmp0(ifname, pattern) == 0) { + *path = (const char *) service->path; + return 0; + } + } return -ENXIO; @@ -4674,6 +4802,7 @@ int __connman_service_create_and_connect(DBusMessage *msg) DBusMessageIter iter, array; const char *mode = "managed", *security = "none", *group_security; const char *type = NULL, *ssid = NULL, *passphrase = NULL; + connman_bool_t network_created = FALSE; unsigned int ssid_len = 0; const char *ident; char *name, *group; @@ -4758,16 +4887,17 @@ int __connman_service_create_and_connect(DBusMessage *msg) service = lookup_by_identifier(name); - if (service != NULL) - goto done; - - network = create_hidden_wifi(device, ssid, mode, security, group); - if (network != NULL) - connman_network_set_group(network, group); + if (service == NULL) { + network = create_hidden_wifi(device, ssid, + mode, security, group); + if (network != NULL) { + connman_network_set_group(network, group); + network_created = TRUE; + } - service = lookup_by_identifier(name); + service = lookup_by_identifier(name); + } -done: g_free(name); g_free(group); @@ -4776,7 +4906,7 @@ done: goto failed; } - service->network_created = TRUE; + service->network_created = network_created; if (is_connected(service) == TRUE) { err = -EISCONN; @@ -5097,7 +5227,7 @@ void __connman_service_read_ip4config(struct connman_service *service) if (service->ipconfig_ipv4 == NULL) return; - keyfile = __connman_storage_load_global(); + keyfile = connman_storage_load_service(service->identifier); if (keyfile == NULL) return; @@ -5501,6 +5631,9 @@ void __connman_service_remove_from_network(struct connman_network *network) if (service == NULL) return; + __connman_connection_gateway_remove(service, + CONNMAN_IPCONFIG_TYPE_ALL); + __connman_service_put(service); }