service: Connecting hidden network waits until connected
authorJukka Rissanen <jukka.rissanen@linux.intel.com>
Fri, 15 Jun 2012 13:00:21 +0000 (16:00 +0300)
committerPatrik Flykt <patrik.flykt@linux.intel.com>
Mon, 18 Jun 2012 07:57:08 +0000 (10:57 +0300)
If the user is connecting to hidden network, then we delay the
return of the reply to caller until the real service has connected.

This way the user connect to hidden and non-hidden networks works
the same way from caller point of view.

include/device.h
include/network.h
plugins/wifi.c
src/connman.h
src/device.c
src/network.c
src/service.c

index 1141620..f787cf4 100644 (file)
@@ -120,7 +120,8 @@ struct connman_device_driver {
        int (*scan_fast) (struct connman_device *device);
        int (*scan_hidden)(struct connman_device *device,
                        const char *ssid, unsigned int ssid_len,
-                       const char *identity, const char* passphrase);
+                       const char *identity, const char* passphrase,
+                       void *user_data);
 };
 
 int connman_device_driver_register(struct connman_device_driver *driver);
index 12b0621..3945a54 100644 (file)
@@ -102,8 +102,9 @@ connman_bool_t connman_network_get_connected(struct connman_network *network);
 
 connman_bool_t connman_network_get_associating(struct connman_network *network);
 
+void connman_network_clear_hidden(void *user_data);
 int connman_network_connect_hidden(struct connman_network *network,
-                               char *identity, char* passphrase);
+                       char *identity, char* passphrase, void *user_data);
 
 void connman_network_set_ipv4_method(struct connman_network *network,
                                        enum connman_ipconfig_method method);
index 3cd2be2..3f9afad 100644 (file)
@@ -68,6 +68,7 @@ struct hidden_params {
        unsigned int ssid_len;
        char *identity;
        char *passphrase;
+       gpointer user_data;
 };
 
 /**
@@ -664,6 +665,7 @@ static void scan_callback(int result, GSupplicantInterface *interface,
        DBG("result %d", result);
 
        if (wifi != NULL && wifi->hidden != NULL) {
+               connman_network_clear_hidden(wifi->hidden->user_data);
                hidden_free(wifi->hidden);
                wifi->hidden = NULL;
        }
@@ -865,7 +867,8 @@ static int wifi_scan_fast(struct connman_device *device)
  */
 static int wifi_scan_hidden(struct connman_device *device,
                const char *ssid, unsigned int ssid_len,
-               const char *identity, const char* passphrase)
+               const char *identity, const char* passphrase,
+               gpointer user_data)
 {
        struct wifi_data *wifi = connman_device_get_data(device);
        GSupplicantScanParams *scan_params = NULL;
@@ -911,6 +914,7 @@ static int wifi_scan_hidden(struct connman_device *device,
        hidden->ssid_len = ssid_len;
        hidden->identity = g_strdup(identity);
        hidden->passphrase = g_strdup(passphrase);
+       hidden->user_data = user_data;
        wifi->hidden = hidden;
 
        connman_device_ref(device);
@@ -1572,7 +1576,9 @@ static void network_added(GSupplicantNetwork *supplicant_network)
                                                ssid_len) == 0) {
                        connman_network_connect_hidden(network,
                                        wifi->hidden->identity,
-                                       wifi->hidden->passphrase);
+                                       wifi->hidden->passphrase,
+                                       wifi->hidden->user_data);
+                       wifi->hidden->user_data = NULL;
                        hidden_free(wifi->hidden);
                        wifi->hidden = NULL;
                }
index db3934d..0418a7e 100644 (file)
@@ -470,7 +470,8 @@ struct connman_device *__connman_device_find_device(enum connman_service_type ty
 int __connman_device_request_scan(enum connman_service_type type);
 int __connman_device_request_hidden_scan(struct connman_device *device,
                                const char *ssid, unsigned int ssid_len,
-                               const char *identity, const char *passphrase);
+                               const char *identity, const char *passphrase,
+                               gpointer user_data);
 
 connman_bool_t __connman_device_isfiltered(const char *devname);
 
index e433991..3af3680 100644 (file)
@@ -1102,7 +1102,8 @@ int __connman_device_request_scan(enum connman_service_type type)
 
 int __connman_device_request_hidden_scan(struct connman_device *device,
                                const char *ssid, unsigned int ssid_len,
-                               const char *identity, const char *passphrase)
+                               const char *identity, const char *passphrase,
+                               void *user_data)
 {
        DBG("device %p", device);
 
@@ -1114,7 +1115,7 @@ int __connman_device_request_hidden_scan(struct connman_device *device,
                return -EALREADY;
 
        return device->driver->scan_hidden(device, ssid, ssid_len,
-                                       identity, passphrase);
+                                       identity, passphrase, user_data);
 }
 
 connman_bool_t __connman_device_isfiltered(const char *devname)
index 6fe1d9c..bf01767 100644 (file)
@@ -1455,17 +1455,36 @@ connman_bool_t connman_network_get_associating(struct connman_network *network)
        return network->associating;
 }
 
+void connman_network_clear_hidden(void *user_data)
+{
+       if (user_data == NULL)
+               return;
+
+       DBG("user_data %p", user_data);
+
+       /*
+        * Hidden service does not have a connect timeout so
+        * we do not need to remove it. We can just return
+        * error to the caller telling that we could not find
+        * any network that we could connect to.
+        */
+       __connman_service_reply_dbus_pending(user_data, EIO);
+}
+
 int connman_network_connect_hidden(struct connman_network *network,
-                               char *identity, char* passphrase)
+                       char *identity, char* passphrase, void *user_data)
 {
        int err = 0;
        struct connman_service *service;
 
-       DBG("");
-
        service = __connman_service_lookup_from_network(network);
-       if (service == NULL)
-               return -EINVAL;
+
+       DBG("network %p service %p user_data %p", network, service, user_data);
+
+       if (service == NULL) {
+               err = -EINVAL;
+               goto out;
+       }
 
        if (identity != NULL)
                __connman_service_set_agent_identity(service, identity);
@@ -1476,12 +1495,17 @@ int connman_network_connect_hidden(struct connman_network *network,
        if (err == -ENOKEY) {
                __connman_service_indicate_error(service,
                                        CONNMAN_SERVICE_ERROR_INVALID_KEY);
-               return err;
+               goto out;
        } else {
                __connman_service_set_hidden(service);
                __connman_service_set_userconnect(service, TRUE);
+               __connman_service_set_hidden_data(service, user_data);
                return __connman_service_connect(service);
        }
+
+out:
+       __connman_service_return_error(service, -err, user_data);
+       return err;
 }
 
 /**
index a3a0160..72f5af4 100644 (file)
@@ -4631,15 +4631,27 @@ static void request_input_cb (struct connman_service *service,
                if (g_strcmp0(error,
                                "net.connman.Agent.Error.Canceled") == 0) {
                        err = -EINVAL;
+
+                       if (service->hidden == TRUE)
+                               __connman_service_return_error(service,
+                                                       ECANCELED, user_data);
                        goto done;
+               } else {
+                       if (service->hidden == TRUE)
+                               __connman_service_return_error(service,
+                                                       ETIMEDOUT, user_data);
                }
        }
 
        if (service->hidden == TRUE && name_len > 0 && name_len <= 32) {
                device = connman_network_get_device(service->network);
-               __connman_device_request_hidden_scan(device,
+               err = __connman_device_request_hidden_scan(device,
                                                name, name_len,
-                                               identity, passphrase);
+                                               identity, passphrase,
+                                               user_data);
+               if (err < 0)
+                       __connman_service_return_error(service, -err,
+                                                       user_data);
        }
 
        if (values_received == FALSE || service->hidden == TRUE) {
@@ -4682,6 +4694,17 @@ static void request_input_cb (struct connman_service *service,
                 * when failing is due to wrong user input */
                service->state = CONNMAN_SERVICE_STATE_IDLE;
 
+               if (service->hidden == FALSE) {
+                       /*
+                        * If there was a real error when requesting
+                        * hidden scan, then that error is returned already
+                        * to the user somewhere above so do not try to
+                        * do this again.
+                        */
+                       __connman_service_return_error(service, -err,
+                                                       user_data);
+               }
+
                service_complete(service);
                __connman_connection_update_gateway();
        }
@@ -5443,8 +5466,25 @@ int __connman_service_connect(struct connman_service *service)
 
        if (service->userconnect == TRUE) {
                if (err == -ENOKEY || err == -EPERM) {
-                       return __connman_agent_request_passphrase_input(service,
-                                       request_input_cb, NULL);
+                       DBusMessage *pending = NULL;
+
+                       /*
+                        * We steal the reply here. The idea is that the
+                        * connecting client will see the connection status
+                        * after the real hidden network is connected or
+                        * connection failed.
+                        */
+                       if (service->hidden == TRUE) {
+                               pending = service->pending;
+                               service->pending = NULL;
+                       }
+
+                       err = __connman_agent_request_passphrase_input(service,
+                                       request_input_cb, pending);
+                       if (service->hidden == TRUE && err != -EINPROGRESS)
+                               service->pending = pending;
+
+                       return err;
                }
                reply_pending(service, -err);
        }