char *identifier;
struct connman_device *device;
struct connman_network *network;
+ struct connman_network *pending_network;
GSupplicantInterface *interface;
connman_bool_t connected;
+ connman_bool_t disconnecting;
int index;
unsigned flags;
unsigned int watch;
return -ENOMEM;
wifi->connected = FALSE;
+ wifi->disconnecting = FALSE;
connman_device_set_data(device, wifi);
wifi->device = connman_device_ref(device);
DBG("device %p", device);
+ if (wifi->pending_network != NULL) {
+ connman_network_unref(wifi->pending_network);
+ wifi->pending_network = NULL;
+ }
+
connman_device_set_data(device, NULL);
connman_device_unref(wifi->device);
connman_rtnl_remove_watch(wifi->watch);
DBG("device %p", device);
wifi->connected = FALSE;
+ wifi->disconnecting = FALSE;
+
+ if (wifi->pending_network != NULL) {
+ connman_network_unref(wifi->pending_network);
+ wifi->pending_network = NULL;
+ }
return g_supplicant_interface_remove(wifi->interface,
interface_remove_callback,
connman_error("%s", __func__);
}
-static void disconnect_callback(int result, GSupplicantInterface *interface,
- void *user_data)
-{
- struct wifi_data *wifi = user_data;
-
- if (result < 0) {
- connman_error("%s", __func__);
- return;
- }
-
- connman_network_unref(wifi->network);
-
- wifi->network = NULL;
-}
-
-
static GSupplicantSecurity network_security(const char *security)
{
if (g_str_equal(security, "none") == TRUE)
ssid_init(&ssid, network);
- wifi->network = connman_network_ref(network);
+ if (wifi->disconnecting == TRUE)
+ wifi->pending_network = connman_network_ref(network);
+ else {
+ wifi->network = connman_network_ref(network);
- return g_supplicant_interface_connect(interface, &ssid,
+ return g_supplicant_interface_connect(interface, &ssid,
connect_callback, NULL);
+ }
+
+ return -EINPROGRESS;
+}
+
+static void disconnect_callback(int result, GSupplicantInterface *interface,
+ void *user_data)
+{
+ struct wifi_data *wifi = user_data;
+
+ if (wifi->network != NULL) {
+ /*
+ * if result < 0 supplican return an error because
+ * the network is not current.
+ * we wont receive G_SUPPLICANT_STATE_DISCONNECTED since it
+ * failed, call connman_network_set_connected to report
+ * disconnect is completed.
+ */
+ if (result < 0)
+ connman_network_set_connected(wifi->network, FALSE);
+
+ connman_network_unref(wifi->network);
+ }
+
+ wifi->network = NULL;
+
+ wifi->disconnecting = FALSE;
+
+ if (wifi->pending_network != NULL) {
+ network_connect(wifi->pending_network);
+ connman_network_unref(wifi->pending_network);
+ wifi->pending_network = NULL;
+ }
+
}
static int network_disconnect(struct connman_network *network)
{
struct connman_device *device = connman_network_get_device(network);
struct wifi_data *wifi;
+ int err;
DBG("network %p", network);
connman_network_set_associating(network, FALSE);
- return g_supplicant_interface_disconnect(wifi->interface,
+ if (wifi->disconnecting == TRUE)
+ return -EALREADY;
+
+ wifi->disconnecting = TRUE;
+
+ err = g_supplicant_interface_disconnect(wifi->interface,
disconnect_callback, wifi);
+ if (err < 0)
+ wifi->disconnecting = FALSE;
+
+ return err;
}
static struct connman_network_driver network_driver = {