#include <netdb.h>
#include <gdbus.h>
#include <ctype.h>
+#include <stdint.h>
#include <connman/storage.h>
#include <connman/setting.h>
+#include <connman/agent.h>
#include "connman.h"
enum connman_service_state state_ipv4;
enum connman_service_state state_ipv6;
enum connman_service_error error;
- connman_uint8_t strength;
+ uint8_t strength;
connman_bool_t favorite;
connman_bool_t immutable;
connman_bool_t hidden;
char *config_entry;
};
+static connman_bool_t allow_property_changed(struct connman_service *service);
+
+static struct connman_ipconfig *create_ip4config(struct connman_service *service,
+ int index, enum connman_ipconfig_method method);
+static struct connman_ipconfig *create_ip6config(struct connman_service *service,
+ int index);
+
+
struct find_data {
const char *path;
struct connman_service *service;
return "ethernet";
case CONNMAN_SERVICE_TYPE_WIFI:
return "wifi";
- case CONNMAN_SERVICE_TYPE_WIMAX:
- return "wimax";
case CONNMAN_SERVICE_TYPE_BLUETOOTH:
return "bluetooth";
case CONNMAN_SERVICE_TYPE_CELLULAR:
return CONNMAN_SERVICE_TYPE_CELLULAR;
if (strcmp(str, "bluetooth") == 0)
return CONNMAN_SERVICE_TYPE_BLUETOOTH;
- if (strcmp(str, "wimax") == 0)
- return CONNMAN_SERVICE_TYPE_WIMAX;
if (strcmp(str, "vpn") == 0)
return CONNMAN_SERVICE_TYPE_VPN;
if (strcmp(str, "gps") == 0)
}
/* fall through */
- case CONNMAN_SERVICE_TYPE_WIMAX:
case CONNMAN_SERVICE_TYPE_BLUETOOTH:
case CONNMAN_SERVICE_TYPE_CELLULAR:
service->favorite = g_key_file_get_boolean(keyfile,
}
/* fall through */
- case CONNMAN_SERVICE_TYPE_WIMAX:
case CONNMAN_SERVICE_TYPE_BLUETOOTH:
case CONNMAN_SERVICE_TYPE_CELLULAR:
g_key_file_set_boolean(keyfile, service->identifier,
return is_connected_state(service, service->state);
}
-static const char *nameserver_get_ifname(struct connman_service *service)
+static int nameserver_get_index(struct connman_service *service)
{
- const char *ifname;
+ int index;
- 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;
+ index = __connman_service_get_index(service);
- if (ifname == NULL)
- return NULL;
+ if (index < 0)
+ return -1;
switch (combine_state(service->state_ipv4, service->state_ipv6)) {
case CONNMAN_SERVICE_STATE_UNKNOWN:
case CONNMAN_SERVICE_STATE_CONFIGURATION:
case CONNMAN_SERVICE_STATE_FAILURE:
case CONNMAN_SERVICE_STATE_DISCONNECT:
- return NULL;
+ return -1;
case CONNMAN_SERVICE_STATE_READY:
case CONNMAN_SERVICE_STATE_ONLINE:
break;
}
- return ifname;
+ return index;
}
static void remove_nameservers(struct connman_service *service,
- const char* interface, char **ns)
+ int index, char **ns)
{
- const char *ifname = interface;
int i;
if (ns == NULL)
return;
- if (interface == NULL)
- ifname = nameserver_get_ifname(service);
+ if (index < 0)
+ index = nameserver_get_index(service);
- if (ifname == NULL)
+ if (index < 0)
return;
for (i = 0; ns[i] != NULL; i++)
- connman_resolver_remove(ifname, NULL, ns[i]);
+ connman_resolver_remove(index, NULL, ns[i]);
}
static void remove_searchdomains(struct connman_service *service,
- const char *interface, char **sd)
+ int index, char **sd)
{
- const char *ifname = interface;
int i;
if (sd == NULL)
return;
- if (interface == NULL)
- ifname = nameserver_get_ifname(service);
+ if (index < 0)
+ index = nameserver_get_index(service);
- if (ifname == NULL)
+ if (index < 0)
return;
for (i = 0; sd[i] != NULL; i++)
- connman_resolver_remove(ifname, sd[i], NULL);
+ connman_resolver_remove(index, sd[i], NULL);
}
static void update_nameservers(struct connman_service *service)
{
- 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;
+ int index;
- if (ifname == NULL)
+ index = __connman_service_get_index(service);
+ if (index < 0)
return;
switch (combine_state(service->state_ipv4, service->state_ipv6)) {
return;
case CONNMAN_SERVICE_STATE_FAILURE:
case CONNMAN_SERVICE_STATE_DISCONNECT:
- connman_resolver_remove_all(ifname);
+ connman_resolver_remove_all(index);
return;
case CONNMAN_SERVICE_STATE_READY:
case CONNMAN_SERVICE_STATE_ONLINE:
if (service->nameservers_config != NULL) {
int i;
- remove_nameservers(service, ifname, service->nameservers);
+ remove_nameservers(service, index, service->nameservers);
i = g_strv_length(service->nameservers_config);
while (i != 0) {
i--;
- connman_resolver_append(ifname, NULL,
+ connman_resolver_append(index, NULL,
service->nameservers_config[i]);
}
} else if (service->nameservers != NULL) {
i = g_strv_length(service->nameservers);
while (i != 0) {
i--;
- connman_resolver_append(ifname, NULL,
+ connman_resolver_append(index, NULL,
service->nameservers[i]);
}
}
int i;
searchdomains[0] = service->domainname;
- remove_searchdomains(service, ifname, searchdomains);
+ remove_searchdomains(service, index, searchdomains);
i = g_strv_length(service->domains);
while (i != 0) {
i--;
- connman_resolver_append(ifname, service->domains[i],
+ connman_resolver_append(index, service->domains[i],
NULL);
}
} else if (service->domainname != NULL)
- connman_resolver_append(ifname, service->domainname, NULL);
+ connman_resolver_append(index, service->domainname, NULL);
connman_resolver_flush();
}
if (str == NULL)
return;
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_basic(service->path,
CONNMAN_SERVICE_INTERFACE, "State",
DBUS_TYPE_STRING, &str);
if (service->strength == 0)
return;
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_basic(service->path,
CONNMAN_SERVICE_INTERFACE, "Strength",
DBUS_TYPE_BYTE, &service->strength);
if (service->path == NULL)
return;
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_basic(service->path,
CONNMAN_SERVICE_INTERFACE, "Favorite",
DBUS_TYPE_BOOLEAN, &service->favorite);
if (service->path == NULL)
return;
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_basic(service->path,
CONNMAN_SERVICE_INTERFACE, "Immutable",
DBUS_TYPE_BOOLEAN, &service->immutable);
if (service->path == NULL)
return;
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_basic(service->path,
CONNMAN_SERVICE_INTERFACE, "Roaming",
DBUS_TYPE_BOOLEAN, &service->roaming);
if (service->path == NULL)
return;
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_basic(service->path,
CONNMAN_SERVICE_INTERFACE, "AutoConnect",
DBUS_TYPE_BOOLEAN, &service->autoconnect);
static void settings_changed(struct connman_service *service,
struct connman_ipconfig *ipconfig)
{
- connman_dbus_property_changed_dict(service->path,
- CONNMAN_SERVICE_INTERFACE, "IPv4",
- append_ipv4, service);
+ enum connman_ipconfig_type type;
- connman_dbus_property_changed_dict(service->path,
+ if (allow_property_changed(service) == FALSE)
+ return;
+
+ type = __connman_ipconfig_get_config_type(ipconfig);
+
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+ connman_dbus_property_changed_dict(service->path,
+ CONNMAN_SERVICE_INTERFACE, "IPv4",
+ append_ipv4, service);
+ else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
+ connman_dbus_property_changed_dict(service->path,
CONNMAN_SERVICE_INTERFACE, "IPv6",
- append_ipv6, service);
+ append_ipv6, service);
__connman_notifier_ipconfig_changed(service, ipconfig);
}
static void ipv4_configuration_changed(struct connman_service *service)
{
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_dict(service->path,
CONNMAN_SERVICE_INTERFACE,
"IPv4.Configuration",
static void ipv6_configuration_changed(struct connman_service *service)
{
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_dict(service->path,
CONNMAN_SERVICE_INTERFACE,
"IPv6.Configuration",
static void dns_changed(struct connman_service *service)
{
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_array(service->path,
CONNMAN_SERVICE_INTERFACE, "Nameservers",
DBUS_TYPE_STRING, append_dns, service);
static void dns_configuration_changed(struct connman_service *service)
{
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_array(service->path,
CONNMAN_SERVICE_INTERFACE,
"Nameservers.Configuration",
static void domain_changed(struct connman_service *service)
{
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_array(service->path,
CONNMAN_SERVICE_INTERFACE, "Domains",
DBUS_TYPE_STRING, append_domain, service);
static void domain_configuration_changed(struct connman_service *service)
{
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_array(service->path,
CONNMAN_SERVICE_INTERFACE,
"Domains.Configuration",
static void proxy_changed(struct connman_service *service)
{
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_dict(service->path,
CONNMAN_SERVICE_INTERFACE, "Proxy",
append_proxy, service);
static void proxy_configuration_changed(struct connman_service *service)
{
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_dict(service->path,
CONNMAN_SERVICE_INTERFACE, "Proxy.Configuration",
append_proxyconfig, service);
static void timeservers_configuration_changed(struct connman_service *service)
{
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_array(service->path,
CONNMAN_SERVICE_INTERFACE,
"Timeservers.Configuration",
static void link_changed(struct connman_service *service)
{
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_dict(service->path,
CONNMAN_SERVICE_INTERFACE, "Ethernet",
append_ethernet, service);
DBG("counter %s", counter);
- counter_list = g_slist_append(counter_list, (gpointer)counter);
+ counter_list = g_slist_prepend(counter_list, (gpointer)counter);
iter = g_sequence_get_begin_iter(service_list);
break;
case CONNMAN_SERVICE_TYPE_WIFI:
case CONNMAN_SERVICE_TYPE_ETHERNET:
- case CONNMAN_SERVICE_TYPE_WIMAX:
case CONNMAN_SERVICE_TYPE_BLUETOOTH:
connman_dbus_dict_append_dict(dict, "Ethernet",
append_ethernet, service);
return NULL;
}
+void __connman_service_set_timeservers(struct connman_service *service,
+ char **timeservers)
+{
+ int i;
+
+ if (service == NULL)
+ return;
+
+ g_strfreev(service->timeservers);
+ service->timeservers = NULL;
+
+ for (i = 0; timeservers != NULL && timeservers[i] != NULL; i++)
+ __connman_service_timeserver_append(service, timeservers[i]);
+}
+
int __connman_service_timeserver_append(struct connman_service *service,
const char *timeserver)
{
if (service == NULL)
return;
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_array(service->path,
CONNMAN_SERVICE_INTERFACE, "Timeservers",
DBUS_TYPE_STRING, append_ts, ts_list);
return -EINVAL;
}
-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)
+int __connman_service_reset_ipconfig(struct connman_service *service,
+ enum connman_ipconfig_type type, DBusMessageIter *array,
+ enum connman_service_state *new_state)
{
- enum connman_ipconfig_method old_method;
- enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
- enum connman_ipconfig_type type;
- int err;
+ struct connman_ipconfig *ipconfig, *new_ipconfig;
+ enum connman_ipconfig_method old_method, new_method;
+ enum connman_service_state state;
+ int err = 0, index;
- if (ipconfig == NULL)
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
+ ipconfig = service->ipconfig_ipv4;
+ state = service->state_ipv4;
+ new_method = CONNMAN_IPCONFIG_METHOD_DHCP;
+ } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
+ ipconfig = service->ipconfig_ipv6;
+ state = service->state_ipv6;
+ new_method = CONNMAN_IPCONFIG_METHOD_AUTO;
+ } else
return -EINVAL;
+ if (ipconfig == NULL)
+ return -ENXIO;
+
old_method = __connman_ipconfig_get_method(ipconfig);
+ index = __connman_ipconfig_get_index(ipconfig);
+
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+ new_ipconfig = create_ip4config(service, index,
+ CONNMAN_IPCONFIG_METHOD_UNKNOWN);
+ else
+ new_ipconfig = create_ip6config(service, index);
+
+ if (array != NULL) {
+ err = __connman_ipconfig_set_config(new_ipconfig, array);
+ if (err < 0) {
+ __connman_ipconfig_unref(new_ipconfig);
+ return err;
+ }
+
+ new_method = __connman_ipconfig_get_method(new_ipconfig);
+ }
if (is_connecting_state(service, state) ||
is_connected_state(service, state))
__connman_network_clear_ipconfig(service->network, ipconfig);
-
- err = __connman_ipconfig_set_config(ipconfig, array);
- method = __connman_ipconfig_get_method(ipconfig);
- type = __connman_ipconfig_get_config_type(ipconfig);
+ __connman_ipconfig_unref(ipconfig);
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_ipconfig_enable(ipconfig);
- __connman_service_auto_connect();
- }
-
+ service->ipconfig_ipv4 = new_ipconfig;
} else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
- if (err == 0 && old_method == CONNMAN_IPCONFIG_METHOD_OFF &&
- method == CONNMAN_IPCONFIG_METHOD_AUTO) {
+ service->ipconfig_ipv6 = new_ipconfig;
+ }
+
+ __connman_ipconfig_enable(new_ipconfig);
+
+ if (new_state != NULL && new_method != old_method) {
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+ *new_state = service->state_ipv4;
+ else
*new_state = service->state_ipv6;
- __connman_ipconfig_enable(ipconfig);
- __connman_service_auto_connect();
- }
+ __connman_service_auto_connect();
}
- DBG("err %d ipconfig %p type %d method %d state %s", err, ipconfig,
- type, method, state2string(*new_state));
+ DBG("err %d ipconfig %p type %d method %d state %s", err,
+ new_ipconfig, type, new_method,
+ new_state == NULL ? "-" : state2string(*new_state));
return err;
}
autoconnect_changed(service);
+ if (autoconnect == TRUE)
+ __connman_service_auto_connect();
+
service_save(service);
} else if (g_str_equal(name, "Nameservers.Configuration") == TRUE) {
DBusMessageIter entry;
int index;
const char *gw;
+ if (service->immutable == TRUE)
+ return __connman_error_not_supported(msg);
+
if (type != DBUS_TYPE_ARRAY)
return __connman_error_invalid_arguments(msg);
if (str == NULL)
return __connman_error_invalid_arguments(msg);
- index = connman_network_get_index(service->network);
+ if (service->type == CONNMAN_SERVICE_TYPE_VPN)
+ index = connman_provider_get_index(service->provider);
+ else
+ index = connman_network_get_index(service->network);
gw = __connman_ipconfig_get_gateway_from_index(index,
CONNMAN_IPCONFIG_TYPE_ALL);
}
}
- remove_nameservers(service, NULL, service->nameservers_config);
+ remove_nameservers(service, -1, service->nameservers_config);
g_strfreev(service->nameservers_config);
if (str->len > 0) {
update_nameservers(service);
dns_configuration_changed(service);
+ if (__connman_service_is_connected_state(service,
+ CONNMAN_IPCONFIG_TYPE_IPV4))
+ __connman_wispr_start(service,
+ CONNMAN_IPCONFIG_TYPE_IPV4);
+
+ if (__connman_service_is_connected_state(service,
+ CONNMAN_IPCONFIG_TYPE_IPV6))
+ __connman_wispr_start(service,
+ CONNMAN_IPCONFIG_TYPE_IPV6);
+
service_save(service);
} else if (g_str_equal(name, "Timeservers.Configuration") == TRUE) {
DBusMessageIter entry;
GSList *list = NULL;
int count = 0;
+ if (service->immutable == TRUE)
+ return __connman_error_not_supported(msg);
+
if (type != DBUS_TYPE_ARRAY)
return __connman_error_invalid_arguments(msg);
service_save(service);
timeservers_configuration_changed(service);
- __connman_timeserver_sync(service);
+ if (service == __connman_service_get_default())
+ __connman_timeserver_sync(service);
+
} else if (g_str_equal(name, "Domains.Configuration") == TRUE) {
DBusMessageIter entry;
GString *str;
+ if (service->immutable == TRUE)
+ return __connman_error_not_supported(msg);
+
if (type != DBUS_TYPE_ARRAY)
return __connman_error_invalid_arguments(msg);
g_string_append(str, val);
}
- remove_searchdomains(service, NULL, service->domains);
+ remove_searchdomains(service, -1, service->domains);
g_strfreev(service->domains);
if (str->len > 0)
update_nameservers(service);
domain_configuration_changed(service);
+ domain_changed(service);
service_save(service);
} else if (g_str_equal(name, "Proxy.Configuration") == TRUE) {
int err;
+ if (service->immutable == TRUE)
+ return __connman_error_not_supported(msg);
+
if (type != DBUS_TYPE_ARRAY)
return __connman_error_invalid_arguments(msg);
} else if (g_str_equal(name, "IPv4.Configuration") == TRUE ||
g_str_equal(name, "IPv6.Configuration")) {
- struct connman_ipconfig *ipv4 = NULL, *ipv6 = NULL;
enum connman_service_state state =
CONNMAN_SERVICE_STATE_UNKNOWN;
+ enum connman_ipconfig_type type =
+ CONNMAN_IPCONFIG_TYPE_UNKNOWN;
int err = 0;
+ if (service->immutable == TRUE)
+ return __connman_error_not_supported(msg);
+
DBG("%s", name);
if (service->ipconfig_ipv4 == NULL &&
service->ipconfig_ipv6 == NULL)
return __connman_error_invalid_property(msg);
- if (g_str_equal(name, "IPv4.Configuration") == TRUE) {
- ipv4 = service->ipconfig_ipv4;
- err = set_ipconfig(service, ipv4, &value,
- service->state_ipv4, &state);
+ if (g_str_equal(name, "IPv4.Configuration") == TRUE)
+ type = CONNMAN_IPCONFIG_TYPE_IPV4;
+ else
+ type = CONNMAN_IPCONFIG_TYPE_IPV6;
- } else if (g_str_equal(name, "IPv6.Configuration") == TRUE) {
- ipv6 = service->ipconfig_ipv6;
- err = set_ipconfig(service, ipv6, &value,
- service->state_ipv6, &state);
- }
+ err = __connman_service_reset_ipconfig(service, type, &value,
+ &state);
if (err < 0) {
if (is_connected_state(service, state) ||
is_connecting_state(service, state))
__connman_network_set_ipconfig(service->network,
- ipv4, ipv6);
+ service->ipconfig_ipv4,
+ service->ipconfig_ipv6);
return __connman_error_failed(msg, -err);
}
- if (ipv4)
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
ipv4_configuration_changed(service);
- else if (ipv6)
+ else
ipv6_configuration_changed(service);
if (is_connecting(service) || is_connected(service))
__connman_network_set_ipconfig(service->network,
- ipv4, ipv6);
+ service->ipconfig_ipv4,
+ service->ipconfig_ipv6);
service_save(service);
} else
if (str == NULL)
str = "";
+ if (allow_property_changed(service) == FALSE)
+ return;
+
connman_dbus_property_changed_basic(service->path,
CONNMAN_SERVICE_INTERFACE, "Error",
DBUS_TYPE_STRING, &str);
}
}
-static GSequence* preferred_tech_list_get(GSequence *list)
+static GSequence* preferred_tech_list_get(void)
{
unsigned int *tech_array;
struct preferred_tech_data tech_data;
if (tech_array == NULL)
return NULL;
+ if (connman_setting_get_bool("SingleConnectedTechnology") == TRUE) {
+ GSequenceIter *iter = g_sequence_get_begin_iter(service_list);
+ while (g_sequence_iter_is_end(iter) == FALSE) {
+ struct connman_service *service;
+
+ service = g_sequence_get(iter);
+
+ if (is_connected(service) == FALSE)
+ break;
+
+ if (service->userconnect == TRUE) {
+ DBG("service %p name %s is user connected",
+ service, service->name);
+ return NULL;
+ }
+
+ iter = g_sequence_iter_next(iter);
+ }
+ }
+
tech_data.preferred_list = g_sequence_new(NULL);
for (i = 0; tech_array[i] != 0; i += 1) {
return FALSE;
}
- if (is_connected(service) == TRUE) {
- if (preferred == TRUE && service->state !=
- CONNMAN_SERVICE_STATE_ONLINE)
- goto next_service;
+ if (is_connected(service) == TRUE)
return TRUE;
- }
if (is_ignore(service) == FALSE && service->state ==
CONNMAN_SERVICE_STATE_IDLE)
DBG("");
- preferred_tech = preferred_tech_list_get(service_list);
+ preferred_tech = preferred_tech_list_get();
if (preferred_tech != NULL)
iter = g_sequence_get_begin_iter(preferred_tech);
if (service->network != NULL)
__connman_network_disconnect(service->network);
else if (service->provider != NULL)
- __connman_provider_disconnect(service->provider);
+ connman_provider_disconnect(service->provider);
__connman_ipconfig_disable(service->ipconfig_ipv4);
__connman_ipconfig_disable(service->ipconfig_ipv6);
return __connman_device_get_reconnect(device);
}
+static connman_bool_t is_interface_available(struct connman_service *service,
+ struct connman_service *other_service)
+{
+ unsigned int index = 0, other_index = 0;
+
+ if (service->ipconfig_ipv4 != NULL)
+ index = __connman_ipconfig_get_index(service->ipconfig_ipv4);
+ else if (service->ipconfig_ipv6 != NULL)
+ index = __connman_ipconfig_get_index(service->ipconfig_ipv6);
+
+ if (other_service->ipconfig_ipv4 != NULL)
+ other_index = __connman_ipconfig_get_index(
+ other_service->ipconfig_ipv4);
+ else if (other_service->ipconfig_ipv6 != NULL)
+ 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)
{
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)
- return __connman_error_in_progress(msg);
+ /*
+ * We should allow connection if there are available
+ * interfaces for a given technology type (like having
+ * more than one wifi card).
+ */
+ if (service->type == temp->type &&
+ is_connecting(temp) == TRUE &&
+ is_interface_available(service,
+ temp) == FALSE) {
+ if (temp->pending != NULL)
+ __connman_service_return_error(temp,
+ ECONNABORTED,
+ NULL);
+
+ err = __connman_service_disconnect(temp);
+ if (err < 0 && err != -EINPROGRESS)
+ return __connman_error_in_progress(msg);
+ else {
+ set_idle(temp);
+ break;
+ }
+ }
iter = g_sequence_iter_next(iter);
}
if (err < 0) {
if (err != -EINPROGRESS)
return __connman_error_failed(msg, -err);
-
- return NULL;
}
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
return;
if (def_service == service &&
- def_service->state == CONNMAN_SERVICE_STATE_ONLINE)
+ def_service->state == CONNMAN_SERVICE_STATE_ONLINE) {
def_service->state = CONNMAN_SERVICE_STATE_READY;
+ __connman_notifier_leave_online(def_service->type);
+ }
}
static void switch_default_service(struct connman_service *default_service,
DBG("");
+ services_notify->id = 0;
+
signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
CONNMAN_MANAGER_INTERFACE, "ServicesChanged");
if (signal == NULL)
g_hash_table_remove_all(services_notify->remove);
g_hash_table_remove_all(services_notify->add);
- services_notify->id = 0;
return FALSE;
}
service_schedule_changed();
}
+static connman_bool_t allow_property_changed(struct connman_service *service)
+{
+ if (g_hash_table_lookup_extended(services_notify->add, service->path,
+ NULL, NULL) == TRUE) {
+ DBG("no property updates for service %p", service);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static const GDBusMethodTable service_methods[] = {
{ GDBUS_DEPRECATED_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
__connman_notifier_service_remove(service);
service_schedule_removed(service);
+ __connman_wispr_stop(service);
stats_stop(service);
service->path = NULL;
break;
case CONNMAN_SERVICE_TYPE_WIFI:
return 1;
- case CONNMAN_SERVICE_TYPE_WIMAX:
case CONNMAN_SERVICE_TYPE_BLUETOOTH:
case CONNMAN_SERVICE_TYPE_CELLULAR:
return -1;
{
if (service->hidden == TRUE)
return -EOPNOTSUPP;
+
+ if (service->immutable == immutable)
+ return 0;
+
service->immutable = immutable;
immutable_changed(service);
return 0;
}
+int __connman_service_set_ignore(struct connman_service *service,
+ connman_bool_t ignore)
+{
+ if (service == NULL)
+ return -EINVAL;
+
+ service->ignore = ignore;
+
+ return 0;
+}
+
void __connman_service_set_string(struct connman_service *service,
const char *key, const char *value)
{
service->userconnect = userconnect;
}
+void __connman_service_set_search_domains(struct connman_service *service,
+ char **domains)
+{
+ int index;
+
+ index = __connman_service_get_index(service);
+ if (index < 0)
+ return;
+
+ if (service->domains != NULL) {
+ remove_searchdomains(service, index, service->domains);
+ g_strfreev(service->domains);
+
+ service->domains = g_strdupv(domains);
+
+ update_nameservers(service);
+ }
+}
+
static void service_complete(struct connman_service *service)
{
reply_pending(service, EIO);
service_save(service);
}
-static void report_error_cb(struct connman_service *service,
- gboolean retry, void *user_data)
+static void report_error_cb(void *user_context, gboolean retry,
+ void *user_data)
{
+ struct connman_service *service = user_context;
+
if (retry == TRUE)
__connman_service_connect(service);
else {
done:
if (err >= 0) {
+ /* We forget any previous error. */
+ set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
+
__connman_service_connect(service);
/* Never cache agent provided credentials */
} else if (err == -ENOKEY) {
__connman_service_indicate_error(service,
CONNMAN_SERVICE_ERROR_INVALID_KEY);
- __connman_agent_report_error(service,
- error2string(service->error),
- report_error_cb, NULL);
} else {
/* It is not relevant to stay on Failure state
* when failing is due to wrong user input */
return -EALREADY;
if (new_service->type == tech_array[i]) {
- switch_default_service(new_service,
- default_service);
+ switch_default_service(default_service,
+ new_service);
+ __connman_connection_update_gateway();
return 0;
}
}
- return -EAGAIN;
}
return -EALREADY;
}
+static void single_connected_tech(struct connman_service *allowed)
+{
+ GSList *services = NULL;
+ GSequenceIter *iter;
+ GSList *list;
+
+ iter = g_sequence_get_begin_iter(service_list);
+
+ while (g_sequence_iter_is_end(iter) == FALSE) {
+ struct connman_service *service = g_sequence_get(iter);
+
+ if (service != allowed && is_connected(service))
+ services = g_slist_prepend(services, service);
+
+ iter = g_sequence_iter_next(iter);
+ }
+
+ DBG("keeping %p %s", allowed, allowed->path);
+
+ for (list = services; list != NULL; list = list->next) {
+ struct connman_service *service = list->data;
+
+ DBG("disconnecting %p %s", service, service->path);
+ __connman_service_disconnect(service);
+ }
+
+ g_slist_free(services);
+}
+
static int service_indicate_state(struct connman_service *service)
{
enum connman_service_state old_state, new_state;
service, new_state);
if (result == -EALREADY)
return result;
- if (result == -EAGAIN)
- __connman_service_auto_connect();
}
if (old_state == CONNMAN_SERVICE_STATE_ONLINE)
reply_pending(service, 0);
- service->userconnect = FALSE;
-
g_get_current_time(&service->modified);
service_save(service);
dns_changed(service);
domain_changed(service);
- __connman_notifier_connect(service->type);
+ if (old_state != CONNMAN_SERVICE_STATE_ONLINE)
+ __connman_notifier_connect(service->type);
if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
connman_network_get_bool(service->network,
__connman_ipconfig_disable_ipv6(
service->ipconfig_ipv6);
+ if (connman_setting_get_bool("SingleConnectedTechnology")
+ == TRUE)
+ single_connected_tech(service);
+
} else if (new_state == CONNMAN_SERVICE_STATE_DISCONNECT) {
def_service = __connman_service_get_default();
if (__connman_notifier_is_connected() == FALSE &&
def_service != NULL &&
def_service->provider != NULL)
- __connman_provider_disconnect(def_service->provider);
+ connman_provider_disconnect(def_service->provider);
default_changed();
if (new_state == CONNMAN_SERVICE_STATE_FAILURE) {
if (service->userconnect == TRUE &&
- __connman_agent_report_error(service,
+ connman_agent_report_error(service, service->path,
error2string(service->error),
report_error_cb, NULL) == -EINPROGRESS)
return 0;
"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:
case CONNMAN_NETWORK_TYPE_CELLULAR:
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_CELLULAR:
case CONNMAN_SERVICE_TYPE_VPN:
__connman_network_disconnect(service->network);
else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
service->provider != NULL)
- __connman_provider_disconnect(service->provider);
+ connman_provider_disconnect(service->provider);
if (service->userconnect == TRUE) {
if (err == -ENOKEY || err == -EPERM) {
DBG("service %p", service);
+ service->userconnect = FALSE;
+
+ connman_agent_cancel(service);
+
if (service->network != NULL) {
err = __connman_network_disconnect(service->network);
} else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
service->provider != NULL)
- err = __connman_provider_disconnect(service->provider);
+ err = connman_provider_disconnect(service->provider);
else
return -EOPNOTSUPP;
NULL);
__connman_ipconfig_address_remove(service->ipconfig_ipv4);
+ settings_changed(service, service->ipconfig_ipv4);
+
__connman_ipconfig_address_remove(service->ipconfig_ipv6);
+ settings_changed(service, service->ipconfig_ipv6);
__connman_ipconfig_disable(service->ipconfig_ipv4);
__connman_ipconfig_disable(service->ipconfig_ipv6);
.route_unset = service_route_changed,
};
-static void setup_ip4config(struct connman_service *service, int index,
- enum connman_ipconfig_method method)
+static struct connman_ipconfig *create_ip4config(struct connman_service *service,
+ int index, enum connman_ipconfig_method method)
{
- service->ipconfig_ipv4 = __connman_ipconfig_create(index,
+ struct connman_ipconfig *ipconfig_ipv4;
+
+ ipconfig_ipv4 = __connman_ipconfig_create(index,
CONNMAN_IPCONFIG_TYPE_IPV4);
- if (service->ipconfig_ipv4 == NULL)
- return;
+ if (ipconfig_ipv4 == NULL)
+ return NULL;
+
+ __connman_ipconfig_set_method(ipconfig_ipv4, method);
- __connman_ipconfig_set_method(service->ipconfig_ipv4, method);
+ __connman_ipconfig_set_data(ipconfig_ipv4, service);
- __connman_ipconfig_set_data(service->ipconfig_ipv4, service);
+ __connman_ipconfig_set_ops(ipconfig_ipv4, &service_ops);
- __connman_ipconfig_set_ops(service->ipconfig_ipv4, &service_ops);
+ return ipconfig_ipv4;
}
-static void setup_ip6config(struct connman_service *service, int index)
+static struct connman_ipconfig *create_ip6config(struct connman_service *service,
+ int index)
{
- service->ipconfig_ipv6 = __connman_ipconfig_create(index,
+ struct connman_ipconfig *ipconfig_ipv6;
+
+ ipconfig_ipv6 = __connman_ipconfig_create(index,
CONNMAN_IPCONFIG_TYPE_IPV6);
- if (service->ipconfig_ipv6 == NULL)
- return;
+ if (ipconfig_ipv6 == NULL)
+ return NULL;
- __connman_ipconfig_set_data(service->ipconfig_ipv6, service);
+ __connman_ipconfig_set_data(ipconfig_ipv6, service);
- __connman_ipconfig_set_ops(service->ipconfig_ipv6, &service_ops);
+ __connman_ipconfig_set_ops(ipconfig_ipv6, &service_ops);
+
+ return ipconfig_ipv6;
}
void __connman_service_read_ip4config(struct connman_service *service)
if (service->ipconfig_ipv4 != NULL)
return;
- setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_DHCP);
+ service->ipconfig_ipv4 = create_ip4config(service, index,
+ CONNMAN_IPCONFIG_METHOD_DHCP);
__connman_service_read_ip4config(service);
}
if (service->ipconfig_ipv6 != NULL)
return;
- setup_ip6config(service, index);
+ service->ipconfig_ipv6 = create_ip6config(service, index);
__connman_service_read_ip6config(service);
}
return CONNMAN_SERVICE_TYPE_ETHERNET;
case CONNMAN_NETWORK_TYPE_WIFI:
return CONNMAN_SERVICE_TYPE_WIFI;
- case CONNMAN_NETWORK_TYPE_WIMAX:
- return CONNMAN_SERVICE_TYPE_WIMAX;
case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
return CONNMAN_SERVICE_TYPE_BLUETOOTH;
static void update_from_network(struct connman_service *service,
struct connman_network *network)
{
- connman_uint8_t strength = service->strength;
+ uint8_t strength = service->strength;
GSequenceIter *iter;
const char *str;
switch (service->type) {
case CONNMAN_SERVICE_TYPE_UNKNOWN:
case CONNMAN_SERVICE_TYPE_SYSTEM:
- case CONNMAN_SERVICE_TYPE_WIMAX:
case CONNMAN_SERVICE_TYPE_BLUETOOTH:
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_VPN:
index = connman_network_get_index(network);
if (service->ipconfig_ipv4 == NULL)
- setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_DHCP);
+ service->ipconfig_ipv4 = create_ip4config(service, index,
+ CONNMAN_IPCONFIG_METHOD_DHCP);
if (service->ipconfig_ipv6 == NULL)
- setup_ip6config(service, index);
+ service->ipconfig_ipv6 = create_ip6config(service, index);
service_register(service);
{
connman_bool_t need_sort = FALSE;
struct connman_service *service;
- connman_uint8_t strength;
+ uint8_t strength;
connman_bool_t roaming;
GSequenceIter *iter;
const char *name;
if (g_strcmp0(service->name, name) != 0) {
g_free(service->name);
service->name = g_strdup(name);
- connman_dbus_property_changed_basic(service->path,
- CONNMAN_SERVICE_INTERFACE, "Name",
- DBUS_TYPE_STRING, &service->name);
+
+ if (allow_property_changed(service) == TRUE)
+ connman_dbus_property_changed_basic(service->path,
+ CONNMAN_SERVICE_INTERFACE, "Name",
+ DBUS_TYPE_STRING, &service->name);
}
if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
service->strength = 0;
if (service->ipconfig_ipv4 == NULL)
- setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_MANUAL);
+ service->ipconfig_ipv4 = create_ip4config(service, index,
+ CONNMAN_IPCONFIG_METHOD_MANUAL);
if (service->ipconfig_ipv6 == NULL)
- setup_ip6config(service, index);
+ service->ipconfig_ipv6 = create_ip6config(service, index);
service_register(service);
g_strfreev(services);
}
+static int agent_probe(struct connman_agent *agent)
+{
+ DBG("agent %p", agent);
+ return 0;
+}
+
+static void agent_remove(struct connman_agent *agent)
+{
+ DBG("agent %p", agent);
+}
+
+static void *agent_context_ref(void *context)
+{
+ struct connman_service *service = context;
+
+ return (void *)connman_service_ref(service);
+}
+
+static void agent_context_unref(void *context)
+{
+ struct connman_service *service = context;
+
+ connman_service_unref(service);
+}
+
+static struct connman_agent_driver agent_driver = {
+ .name = "service",
+ .interface = CONNMAN_AGENT_INTERFACE,
+ .probe = agent_probe,
+ .remove = agent_remove,
+ .context_ref = agent_context_ref,
+ .context_unref = agent_context_unref,
+};
+
int __connman_service_init(void)
{
+ int err;
+
DBG("");
+ err = connman_agent_driver_register(&agent_driver);
+ if (err < 0) {
+ connman_error("Cannot register agent driver for %s",
+ agent_driver.name);
+ return err;
+ }
+
connection = connman_dbus_get_connection();
service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
}
g_free(services_notify);
+ connman_agent_driver_unregister(&agent_driver);
+
dbus_connection_unref(connection);
}