service: Update Domains property when Domains.Configuration changes
[platform/upstream/connman.git] / src / service.c
index 890a313..af8bfce 100644 (file)
 #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"
 
@@ -71,7 +73,7 @@ struct connman_service {
        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;
@@ -124,6 +126,14 @@ struct connman_service {
        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;
@@ -163,8 +173,6 @@ const char *__connman_service_type2string(enum connman_service_type type)
                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:
@@ -195,8 +203,6 @@ enum connman_service_type __connman_service_string2type(const char *str)
                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)
@@ -394,7 +400,6 @@ static int service_load(struct connman_service *service)
                }
                /* 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,
@@ -566,7 +571,6 @@ static int service_save(struct connman_service *service)
                }
                /* 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,
@@ -858,19 +862,14 @@ static connman_bool_t is_connected(struct connman_service *service)
        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:
@@ -879,65 +878,57 @@ static const char *nameserver_get_ifname(struct connman_service *service)
        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)) {
@@ -948,7 +939,7 @@ static void update_nameservers(struct connman_service *service)
                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:
@@ -958,12 +949,12 @@ static void update_nameservers(struct connman_service *service)
        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) {
@@ -972,7 +963,7 @@ static void update_nameservers(struct connman_service *service)
                i = g_strv_length(service->nameservers);
                while (i != 0) {
                        i--;
-                       connman_resolver_append(ifname, NULL,
+                       connman_resolver_append(index, NULL,
                                        service->nameservers[i]);
                }
        }
@@ -982,16 +973,16 @@ static void update_nameservers(struct connman_service *service)
                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();
 }
@@ -1366,6 +1357,9 @@ static void state_changed(struct connman_service *service)
        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);
@@ -1376,6 +1370,9 @@ static void strength_changed(struct connman_service *service)
        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);
@@ -1386,6 +1383,9 @@ static void favorite_changed(struct connman_service *service)
        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);
@@ -1396,6 +1396,9 @@ static void immutable_changed(struct connman_service *service)
        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);
@@ -1406,6 +1409,9 @@ static void roaming_changed(struct connman_service *service)
        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);
@@ -1416,6 +1422,9 @@ static void autoconnect_changed(struct connman_service *service)
        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);
@@ -1749,19 +1758,30 @@ static void append_provider(DBusMessageIter *iter, void *user_data)
 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",
@@ -1771,6 +1791,9 @@ static void ipv4_configuration_changed(struct connman_service *service)
 
 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",
@@ -1780,6 +1803,9 @@ static void ipv6_configuration_changed(struct connman_service *service)
 
 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);
@@ -1787,6 +1813,9 @@ static void dns_changed(struct connman_service *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",
@@ -1797,6 +1826,9 @@ static void dns_configuration_changed(struct connman_service *service)
 
 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);
@@ -1804,6 +1836,9 @@ static void domain_changed(struct connman_service *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",
@@ -1812,6 +1847,9 @@ static void domain_configuration_changed(struct connman_service *service)
 
 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);
@@ -1819,6 +1857,9 @@ static void proxy_changed(struct connman_service *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);
@@ -1828,6 +1869,9 @@ static void proxy_configuration_changed(struct connman_service *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",
@@ -1837,6 +1881,9 @@ static void timeservers_configuration_changed(struct connman_service *service)
 
 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);
@@ -2036,7 +2083,7 @@ int __connman_service_counter_register(const char *counter)
 
        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);
 
@@ -2192,7 +2239,6 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
                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);
@@ -2481,6 +2527,21 @@ const char *connman_service_get_proxy_autoconfig(struct connman_service *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)
 {
@@ -2574,6 +2635,9 @@ void __connman_service_timeserver_changed(struct connman_service *service,
        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);
@@ -2917,49 +2981,72 @@ error:
        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;
 }
@@ -3008,6 +3095,9 @@ static DBusMessage *set_property(DBusConnection *conn,
 
                autoconnect_changed(service);
 
+               if (autoconnect == TRUE)
+                       __connman_service_auto_connect();
+
                service_save(service);
        } else if (g_str_equal(name, "Nameservers.Configuration") == TRUE) {
                DBusMessageIter entry;
@@ -3015,6 +3105,9 @@ static DBusMessage *set_property(DBusConnection *conn,
                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);
 
@@ -3022,7 +3115,10 @@ static DBusMessage *set_property(DBusConnection *conn,
                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);
 
@@ -3044,7 +3140,7 @@ static DBusMessage *set_property(DBusConnection *conn,
                        }
                }
 
-               remove_nameservers(service, NULL, service->nameservers_config);
+               remove_nameservers(service, -1, service->nameservers_config);
                g_strfreev(service->nameservers_config);
 
                if (str->len > 0) {
@@ -3062,12 +3158,25 @@ static DBusMessage *set_property(DBusConnection *conn,
                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);
 
@@ -3104,11 +3213,16 @@ static DBusMessage *set_property(DBusConnection *conn,
                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);
 
@@ -3128,7 +3242,7 @@ static DBusMessage *set_property(DBusConnection *conn,
                                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)
@@ -3140,11 +3254,15 @@ static DBusMessage *set_property(DBusConnection *conn,
 
                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);
 
@@ -3161,44 +3279,47 @@ static DBusMessage *set_property(DBusConnection *conn,
        } 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
@@ -3225,6 +3346,9 @@ static void set_error(struct connman_service *service,
        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);
@@ -3308,7 +3432,7 @@ static void preferred_tech_add_by_type(gpointer data, gpointer user_data)
        }
 }
 
-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;
@@ -3318,6 +3442,26 @@ static GSequence* preferred_tech_list_get(GSequence *list)
        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) {
@@ -3349,12 +3493,8 @@ static connman_bool_t auto_connect_service(GSequenceIter* iter,
                        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)
@@ -3387,7 +3527,7 @@ static gboolean run_auto_connect(gpointer data)
 
        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);
 
@@ -3547,7 +3687,7 @@ static gboolean connect_timeout(gpointer user_data)
        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);
@@ -3608,6 +3748,29 @@ static connman_bool_t get_reconnect_state(struct connman_service *service)
        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)
 {
@@ -3625,8 +3788,28 @@ 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)
-                       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);
        }
@@ -3675,8 +3858,6 @@ static DBusMessage *disconnect_service(DBusConnection *conn,
        if (err < 0) {
                if (err != -EINPROGRESS)
                        return __connman_error_failed(msg, -err);
-
-               return NULL;
        }
 
        return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
@@ -3779,8 +3960,10 @@ static void apply_relevant_default_downgrade(struct connman_service *service)
                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,
@@ -3978,6 +4161,8 @@ static gboolean service_send_changed(gpointer data)
 
        DBG("");
 
+       services_notify->id = 0;
+
        signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
                        CONNMAN_MANAGER_INTERFACE, "ServicesChanged");
        if (signal == NULL)
@@ -4000,7 +4185,6 @@ static gboolean service_send_changed(gpointer data)
        g_hash_table_remove_all(services_notify->remove);
        g_hash_table_remove_all(services_notify->add);
 
-       services_notify->id = 0;
        return FALSE;
 }
 
@@ -4038,6 +4222,17 @@ static void service_schedule_removed(struct connman_service *service)
        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}" }),
@@ -4083,6 +4278,7 @@ static void service_free(gpointer user_data)
        __connman_notifier_service_remove(service);
        service_schedule_removed(service);
 
+       __connman_wispr_stop(service);
        stats_stop(service);
 
        service->path = NULL;
@@ -4350,7 +4546,6 @@ static gint service_compare(gconstpointer a, gconstpointer b,
                        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;
@@ -4566,6 +4761,10 @@ int __connman_service_set_immutable(struct connman_service *service,
 {
        if (service->hidden == TRUE)
                return -EOPNOTSUPP;
+
+       if (service->immutable == immutable)
+               return 0;
+
        service->immutable = immutable;
 
        immutable_changed(service);
@@ -4573,6 +4772,17 @@ int __connman_service_set_immutable(struct connman_service *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)
 {
@@ -4612,6 +4822,25 @@ void __connman_service_set_userconnect(struct connman_service *service,
                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);
@@ -4623,9 +4852,11 @@ static void service_complete(struct connman_service *service)
        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 {
@@ -4759,6 +4990,9 @@ static void request_input_cb (struct connman_service *service,
 
  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 */
@@ -4767,9 +5001,6 @@ static void request_input_cb (struct connman_service *service,
        } 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 */
@@ -4833,17 +5064,46 @@ static int service_update_preferred_order(struct connman_service *default_servic
                                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;
@@ -4874,8 +5134,6 @@ static int service_indicate_state(struct connman_service *service)
                                service, new_state);
                if (result == -EALREADY)
                        return result;
-               if (result == -EAGAIN)
-                       __connman_service_auto_connect();
        }
 
        if (old_state == CONNMAN_SERVICE_STATE_ONLINE)
@@ -4939,8 +5197,6 @@ static int service_indicate_state(struct connman_service *service)
 
                reply_pending(service, 0);
 
-               service->userconnect = FALSE;
-
                g_get_current_time(&service->modified);
                service_save(service);
 
@@ -4948,7 +5204,8 @@ static int service_indicate_state(struct connman_service *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,
@@ -4971,13 +5228,17 @@ static int service_indicate_state(struct connman_service *service)
                        __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();
 
@@ -5001,7 +5262,7 @@ static int service_indicate_state(struct connman_service *service)
 
        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;
@@ -5346,7 +5607,6 @@ static connman_bool_t prepare_network(struct connman_service *service)
                                "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:
@@ -5404,7 +5664,6 @@ static int service_connect(struct connman_service *service)
        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:
@@ -5548,7 +5807,7 @@ int __connman_service_connect(struct connman_service *service)
                __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) {
@@ -5584,11 +5843,15 @@ int __connman_service_disconnect(struct connman_service *service)
 
        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;
 
@@ -5605,7 +5868,10 @@ int __connman_service_disconnect(struct connman_service *service)
                                                        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);
@@ -5906,31 +6172,40 @@ static const struct connman_ipconfig_ops service_ops = {
        .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)
@@ -5958,7 +6233,8 @@ void connman_service_create_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);
 }
 
@@ -5987,7 +6263,7 @@ void connman_service_create_ip6config(struct connman_service *service,
        if (service->ipconfig_ipv6 != NULL)
                return;
 
-       setup_ip6config(service, index);
+       service->ipconfig_ipv6 = create_ip6config(service, index);
 
        __connman_service_read_ip6config(service);
 }
@@ -6115,8 +6391,6 @@ static enum connman_service_type convert_network_type(struct connman_network *ne
                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;
@@ -6150,7 +6424,7 @@ static enum connman_service_security convert_wifi_security(const char *security)
 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;
 
@@ -6267,7 +6541,6 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne
        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:
@@ -6288,10 +6561,11 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne
        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);
 
@@ -6311,7 +6585,7 @@ void __connman_service_update_from_network(struct connman_network *network)
 {
        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;
@@ -6330,9 +6604,11 @@ void __connman_service_update_from_network(struct connman_network *network)
        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)
@@ -6441,10 +6717,11 @@ __connman_service_create_from_provider(struct connman_provider *provider)
        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);
 
@@ -6514,10 +6791,53 @@ static void remove_unprovisioned_services()
        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,
@@ -6564,5 +6884,7 @@ void __connman_service_cleanup(void)
        }
        g_free(services_notify);
 
+       connman_agent_driver_unregister(&agent_driver);
+
        dbus_connection_unref(connection);
 }