};
struct connman_service {
- gint refcount;
- gint session_usage_count;
+ int refcount;
+ int session_usage_count;
char *identifier;
char *path;
enum connman_service_type type;
struct connman_provider *provider;
char **nameservers;
char **nameservers_config;
+ char **nameservers_auto;
char **domains;
char *domainname;
char **timeservers;
service->state_ipv4 = service->state_ipv6 =
CONNMAN_SERVICE_STATE_FAILURE;
service->error = string2error(str);
+ g_free(str);
}
break;
}
break;
}
- connman_resolver_remove_all(ifname);
-
if (service->nameservers_config != NULL) {
int i;
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;
}
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;
}
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);
}
}
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;
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;
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;
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);
*/
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);
}
}
{
DBG("%p", service);
- g_atomic_int_inc(&service->refcount);
+ __sync_fetch_and_add(&service->refcount, 1);
return service;
}
return -EALREADY;
service->favorite = favorite;
+ service->order = __connman_service_get_order(service);
favorite_changed(service);
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;
if (__connman_wpad_start(service) < 0) {
service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
__connman_notifier_proxy_changed(service);
+ goto done;
}
return;
__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)
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:
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;
int __connman_service_disconnect_all(void)
{
GSequenceIter *iter;
+ GSList *services = NULL, *list;
DBG("");
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;
}
{
GHashTableIter iter;
gpointer key, value;
+ struct connman_device *device;
+ const char *ifname;
g_hash_table_iter_init(&iter, service_hash);
*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;
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;
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);
goto failed;
}
- service->network_created = TRUE;
+ service->network_created = network_created;
if (is_connected(service) == TRUE) {
err = -EISCONN;
if (service->ipconfig_ipv4 == NULL)
return;
- keyfile = __connman_storage_load_global();
+ keyfile = connman_storage_load_service(service->identifier);
if (keyfile == NULL)
return;
if (service == NULL)
return;
+ __connman_connection_gateway_remove(service,
+ CONNMAN_IPCONFIG_TYPE_ALL);
+
__connman_service_put(service);
}