provider: Set nameservers if we receive them from vpnd
[platform/upstream/connman.git] / plugins / vpn.c
index ff4d725..d33d7c1 100644 (file)
@@ -81,6 +81,7 @@ struct connection_data {
        char **host_ip;
        char *domain;
        char **nameservers;
+       gboolean immutable;
 
        GHashTable *server_routes;
        GHashTable *user_routes;
@@ -251,6 +252,8 @@ static void set_provider_state(struct connection_data *data)
        enum connman_provider_state state = CONNMAN_PROVIDER_STATE_UNKNOWN;
        int err = 0;
 
+       DBG("provider %p new state %s", data->provider, data->state);
+
        if (g_str_equal(data->state, "ready") == TRUE) {
                state = CONNMAN_PROVIDER_STATE_READY;
                goto set;
@@ -300,6 +303,7 @@ static int create_provider(struct connection_data *data, void *user_data)
 
        err = connman_provider_create_service(data->provider);
        if (err == 0) {
+               connman_provider_set_immutable(data->provider, data->immutable);
                if (g_str_equal(data->state, "ready") == TRUE) {
                        connman_provider_set_index(data->provider,
                                                        data->index);
@@ -449,6 +453,16 @@ static int extract_nameservers(DBusMessageIter *array,
        return 0;
 }
 
+static int errorstr2val(const char *error) {
+       if (g_strcmp0(error, CONNMAN_ERROR_INTERFACE ".InProgress") == 0)
+               return -EINPROGRESS;
+
+       if (g_strcmp0(error, CONNMAN_ERROR_INTERFACE ".AlreadyConnected") == 0)
+               return -EISCONN;
+
+       return -ECONNREFUSED;
+}
+
 static void connect_reply(DBusPendingCall *call, void *user_data)
 {
        DBusMessage *reply;
@@ -466,15 +480,15 @@ static void connect_reply(DBusPendingCall *call, void *user_data)
        dbus_error_init(&error);
 
        if (dbus_set_error_from_message(&error, reply) == TRUE) {
-               if (dbus_error_has_name(&error, CONNMAN_ERROR_INTERFACE
-                                               ".InProgress") == FALSE) {
+               int err = errorstr2val(error.name);
+               if (err != -EINPROGRESS) {
                        connman_error("Connect reply: %s (%s)", error.message,
                                                                error.name);
                        dbus_error_free(&error);
 
+                       DBG("data %p cb_data %p", data, cb_data);
                        if (cb_data != NULL) {
-                               cb_data->callback(cb_data->message,
-                                               ECONNREFUSED, NULL);
+                               cb_data->callback(cb_data->message, err, NULL);
                                free_config_cb_data(cb_data);
                                data->cb_data = NULL;
                        }
@@ -503,6 +517,8 @@ static int connect_provider(struct connection_data *data, void *user_data)
 
        DBG("data %p user %p path %s", data, cb_data, data->path);
 
+       data->connect_pending = FALSE;
+
        message = dbus_message_new_method_call(VPN_SERVICE, data->path,
                                        VPN_CONNECTION_INTERFACE,
                                        VPN_CONNECT);
@@ -587,6 +603,8 @@ static void add_connection(const char *path, DBusMessageIter *properties,
                } else if (g_str_equal(key, "Type") == TRUE) {
                        dbus_message_iter_get_basic(&value, &str);
                        data->type = g_strdup(str);
+               } else if (g_str_equal(key, "Immutable") == TRUE) {
+                       dbus_message_iter_get_basic(&value, &data->immutable);
                } else if (g_str_equal(key, "Host") == TRUE) {
                        dbus_message_iter_get_basic(&value, &str);
                        data->host = g_strdup(str);
@@ -597,6 +615,10 @@ static void add_connection(const char *path, DBusMessageIter *properties,
                        extract_nameservers(&value, data);
                } else if (g_str_equal(key, "Index") == TRUE) {
                        dbus_message_iter_get_basic(&value, &data->index);
+               } else if (g_str_equal(key, "ServerRoutes") == TRUE) {
+                       /* Ignored */
+               } else if (g_str_equal(key, "UserRoutes") == TRUE) {
+                       /* Ignored */
                } else {
                        if (dbus_message_iter_get_arg_type(&value) ==
                                                        DBUS_TYPE_STRING) {
@@ -621,6 +643,10 @@ static void add_connection(const char *path, DBusMessageIter *properties,
 
        resolv_host_addr(data);
 
+       if (data->nameservers != NULL)
+               connman_provider_set_nameservers(data->provider,
+                                               data->nameservers);
+
        if (data->connect_pending == TRUE)
                connect_provider(data, data->cb_data);
 
@@ -774,6 +800,14 @@ static int provider_remove(struct connman_provider *provider)
 
        DBG("provider %p data %p", provider, data);
 
+       if (data == NULL) {
+               /*
+                * This means the provider is already removed,
+                * just ignore the dbus in this case.
+                */
+               return -EALREADY;
+       }
+
        /*
         * When provider.c:provider_remove() calls this function,
         * it will remove the provider itself after the call.
@@ -1233,8 +1267,8 @@ static int create_configuration(DBusMessage *msg, connection_ready_cb callback)
 
        data = g_hash_table_lookup(vpn_connections, ident);
        if (data != NULL) {
-               if (data->call != NULL) {
-                       connman_error("Dbus call already pending");
+               if (data->call != NULL || data->cb_data != NULL) {
+                       DBG("create configuration call already pending");
                        err = -EINPROGRESS;
                        goto done;
                }
@@ -1264,6 +1298,18 @@ static int create_configuration(DBusMessage *msg, connection_ready_cb callback)
        dbus_message_set_sender(new_msg, me);
        dbus_message_set_member(new_msg, "Create");
 
+       user_data = g_try_new0(struct config_create_data, 1);
+       if (user_data == NULL) {
+               err = -ENOMEM;
+               goto done;
+       }
+
+       user_data->callback = callback;
+       user_data->message = dbus_message_ref(msg);
+       user_data->path = NULL;
+
+       DBG("cb %p msg %p", user_data, msg);
+
        result = dbus_connection_send_with_reply(connection, new_msg,
                                                &call, DBUS_TIMEOUT);
        if (result == FALSE || call == NULL) {
@@ -1271,20 +1317,6 @@ static int create_configuration(DBusMessage *msg, connection_ready_cb callback)
                goto done;
        }
 
-       if (data->cb_data == NULL) {
-               user_data = g_try_new(struct config_create_data, 1);
-               if (user_data != NULL) {
-                       user_data->callback = callback;
-                       user_data->message = dbus_message_ref(msg);
-                       user_data->path = NULL;
-
-                       DBG("cb %p msg %p", user_data, msg);
-               }
-       } else {
-               DBG("Configuration callback data already pending, "
-                       "discarding new data.");
-       }
-
        dbus_pending_call_set_notify(call, configuration_create_reply,
                                                        user_data, NULL);
        data->call = call;
@@ -1420,7 +1452,9 @@ static void destroy_provider(struct connection_data *data)
        if (data->call != NULL)
                dbus_pending_call_cancel(data->call);
 
-       connman_provider_put(data->provider);
+       connman_provider_set_data(data->provider, NULL);
+
+       connman_provider_remove(data->provider);
 
        data->provider = NULL;
 }
@@ -1478,6 +1512,7 @@ static gboolean connection_removed(DBusConnection *conn, DBusMessage *message,
 {
        const char *path;
        const char *signature = DBUS_TYPE_OBJECT_PATH_AS_STRING;
+       struct connection_data *data;
 
        if (dbus_message_has_signature(message, signature) == FALSE) {
                connman_error("vpn removed signature \"%s\" does not match "
@@ -1488,7 +1523,11 @@ static gboolean connection_removed(DBusConnection *conn, DBusMessage *message,
 
        dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
                                DBUS_TYPE_INVALID);
-       remove_connection(conn, path);
+
+       data = g_hash_table_lookup(vpn_connections, get_ident(path));
+       if (data != NULL)
+               remove_connection(conn, path);
+
        return TRUE;
 }
 
@@ -1721,7 +1760,10 @@ static gboolean property_changed(DBusConnection *conn,
                        set_routes(data->provider,
                                                CONNMAN_PROVIDER_ROUTE_USER);
        } else if (g_str_equal(key, "Nameservers") == TRUE) {
-               extract_nameservers(&value, data);
+               if (extract_nameservers(&value, data) == 0 &&
+                                               data->nameservers != NULL)
+                       connman_provider_set_nameservers(data->provider,
+                                                       data->nameservers);
        }
 
        if (ip_set == TRUE && err == 0) {