summary refs log tree commit diff
path: root/cli/src/devices.c
diff options
context:
space:
mode:
Diffstat (limited to 'cli/src/devices.c')
-rw-r--r--cli/src/devices.c723
1 files changed, 497 insertions, 226 deletions
diff --git a/cli/src/devices.c b/cli/src/devices.c
index 0b1b6d6e..6b9367b4 100644
--- a/cli/src/devices.c
+++ b/cli/src/devices.c
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <netinet/ether.h>
 
 #include <glib.h>
 #include <glib/gi18n.h>
@@ -30,6 +31,7 @@
 #include <nm-client.h>
 #include <nm-device.h>
 #include <nm-device-ethernet.h>
+#include <nm-device-adsl.h>
 #include <nm-device-wifi.h>
 #include <nm-device-modem.h>
 #include <nm-device-bt.h>
@@ -46,6 +48,7 @@
 #include <nm-vpn-connection.h>
 #include <nm-setting-connection.h>
 #include <nm-setting-wired.h>
+#include <nm-setting-adsl.h>
 #include <nm-setting-pppoe.h>
 #include <nm-setting-wireless.h>
 #include <nm-setting-gsm.h>
@@ -105,17 +108,20 @@ static NmcOutputField nmc_fields_dev_list_general[] = {
 	{"VENDOR",            N_("VENDOR"),            20, NULL, 0},  /* 3 */
 	{"PRODUCT",           N_("PRODUCT"),           50, NULL, 0},  /* 4 */
 	{"DRIVER",            N_("DRIVER"),             9, NULL, 0},  /* 5 */
-	{"HWADDR",            N_("HWADDR"),            19, NULL, 0},  /* 6 */
-	{"STATE",             N_("STATE"),             14, NULL, 0},  /* 7 */
-	{"REASON",            N_("REASON"),            25, NULL, 0},  /* 8 */
-	{"UDI",               N_("UDI"),               64, NULL, 0},  /* 9 */
-	{"IP-IFACE",          N_("IP-IFACE"),          10, NULL, 0},  /* 10 */
-	{"NM-MANAGED",        N_("NM-MANAGED"),        15, NULL, 0},  /* 11 */
-	{"FIRMWARE-MISSING",  N_("FIRMWARE-MISSING"),  18, NULL, 0},  /* 12 */
-	{"CONNECTION",        N_("CONNECTION"),        51, NULL, 0},  /* 13 */
+	{"DRIVER-VERSION",    N_("DRIVER-VERSION"),    18, NULL, 0},  /* 6 */
+	{"FIRMWARE-VERSION",  N_("FIRMWARE-VERSION"),  18, NULL, 0},  /* 7 */
+	{"HWADDR",            N_("HWADDR"),            19, NULL, 0},  /* 8 */
+	{"STATE",             N_("STATE"),             14, NULL, 0},  /* 9 */
+	{"REASON",            N_("REASON"),            25, NULL, 0},  /* 10 */
+	{"UDI",               N_("UDI"),               64, NULL, 0},  /* 11 */
+	{"IP-IFACE",          N_("IP-IFACE"),          10, NULL, 0},  /* 12 */
+	{"NM-MANAGED",        N_("NM-MANAGED"),        15, NULL, 0},  /* 13 */
+	{"AUTOCONNECT",       N_("AUTOCONNECT"),       15, NULL, 0},  /* 14 */
+	{"FIRMWARE-MISSING",  N_("FIRMWARE-MISSING"),  18, NULL, 0},  /* 15 */
+	{"CONNECTION",        N_("CONNECTION"),        51, NULL, 0},  /* 16 */
 	{NULL, NULL, 0, NULL, 0}
 };
-#define NMC_FIELDS_DEV_LIST_GENERAL_ALL     "NAME,DEVICE,TYPE,VENDOR,PRODUCT,DRIVER,HWADDR,STATE,REASON,UDI,IP-IFACE,NM-MANAGED,FIRMWARE-MISSING,CONNECTION"
+#define NMC_FIELDS_DEV_LIST_GENERAL_ALL     "NAME,DEVICE,TYPE,VENDOR,PRODUCT,DRIVER,DRIVER-VERSION,FIRMWARE-VERSION,HWADDR,STATE,REASON,UDI,IP-IFACE,NM-MANAGED,AUTOCONNECT,FIRMWARE-MISSING,CONNECTION"
 #define NMC_FIELDS_DEV_LIST_GENERAL_COMMON  "NAME,DEVICE,TYPE,VENDOR,PRODUCT,DRIVER,HWADDR,STATE"
 
 /* Available fields for 'dev list' - CAPABILITIES part */
@@ -208,6 +214,8 @@ static NmcOutputField nmc_fields_dev_wimax_list[] = {
 /* glib main loop variable - defined in nmcli.c */
 extern GMainLoop *loop;
 
+static guint progress_id = 0;  /* ID of event source for displaying progress */
+
 static void
 usage (void)
 {
@@ -222,6 +230,8 @@ usage (void)
 	         "  list [iface <iface>]\n"
 	         "  disconnect iface <iface> [--nowait] [--timeout <timeout>]\n"
 	         "  wifi [list [iface <iface>] [bssid <BSSID>]]\n"
+	         "  wifi connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [iface <iface>] [bssid <BSSID>] [name <name>]\n"
+	         "               [--private] [--nowait] [--timeout <timeout>]\n"
 #if WITH_WIMAX
 	         "  wimax [list [iface <iface>] [nsp <name>]]\n\n"
 #endif
@@ -232,201 +242,12 @@ usage (void)
 static void
 quit (void)
 {
-	g_main_loop_quit (loop);  /* quit main loop */
-}
-
-static const char *
-device_state_to_string (NMDeviceState state)
-{
-	switch (state) {
-	case NM_DEVICE_STATE_UNMANAGED:
-		return _("unmanaged");
-	case NM_DEVICE_STATE_UNAVAILABLE:
-		return _("unavailable");
-	case NM_DEVICE_STATE_DISCONNECTED:
-		return _("disconnected");
-	case NM_DEVICE_STATE_PREPARE:
-		return _("connecting (prepare)");
-	case NM_DEVICE_STATE_CONFIG:
-		return _("connecting (configuring)");
-	case NM_DEVICE_STATE_NEED_AUTH:
-		return _("connecting (need authentication)");
-	case NM_DEVICE_STATE_IP_CONFIG:
-		return _("connecting (getting IP configuration)");
-	case NM_DEVICE_STATE_IP_CHECK:
-		return _("connecting (checking IP connectivity)");
-	case NM_DEVICE_STATE_SECONDARIES:
-		return _("connecting (starting secondary connections)");
-	case NM_DEVICE_STATE_ACTIVATED:
-		return _("connected");
-	case NM_DEVICE_STATE_DEACTIVATING:
-		return _("deactivating");
-	case NM_DEVICE_STATE_FAILED:
-		return _("connection failed");
-	default:
-		return _("unknown");
+	if (progress_id) {
+		g_source_remove (progress_id);
+		nmc_terminal_erase_line ();
 	}
-}
-
-static const char *
-device_reason_to_string (NMDeviceStateReason reason)
-{
-	switch (reason) {
-	case NM_DEVICE_STATE_REASON_NONE:
-		return _("No reason given");
-
-	case NM_DEVICE_STATE_REASON_UNKNOWN:
-		return _("Unknown error");
-
-	case NM_DEVICE_STATE_REASON_NOW_MANAGED:
-		return _("Device is now managed");
-
-	case NM_DEVICE_STATE_REASON_NOW_UNMANAGED:
-		return _("Device is now unmanaged");
-
-	case NM_DEVICE_STATE_REASON_CONFIG_FAILED:
-		return _("The device could not be readied for configuration");
-
-	case NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE:
-		return _("IP configuration could not be reserved (no available address, timeout, etc)");
-
-	case NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED:
-		return _("The IP configuration is no longer valid");
-
-	case NM_DEVICE_STATE_REASON_NO_SECRETS:
-		return _("Secrets were required, but not provided");
-
-	case NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT:
-		return _("802.1X supplicant disconnected");
-
-	case NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED:
-		return _("802.1X supplicant configuration failed");
-
-	case NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED:
-		return _("802.1X supplicant failed");
-
-	case NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT:
-		return _("802.1X supplicant took too long to authenticate");
-
-	case NM_DEVICE_STATE_REASON_PPP_START_FAILED:
-		return _("PPP service failed to start");
-
-	case NM_DEVICE_STATE_REASON_PPP_DISCONNECT:
-		return _("PPP service disconnected");
-
-	case NM_DEVICE_STATE_REASON_PPP_FAILED:
-		return _("PPP failed");
-
-	case NM_DEVICE_STATE_REASON_DHCP_START_FAILED:
-		return _("DHCP client failed to start");
-
-	case NM_DEVICE_STATE_REASON_DHCP_ERROR:
-		return _("DHCP client error");
-
-	case NM_DEVICE_STATE_REASON_DHCP_FAILED:
-		return _("DHCP client failed");
-
-	case NM_DEVICE_STATE_REASON_SHARED_START_FAILED:
-		return _("Shared connection service failed to start");
-
-	case NM_DEVICE_STATE_REASON_SHARED_FAILED:
-		return _("Shared connection service failed");
-
-	case NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED:
-		return _("AutoIP service failed to start");
-
-	case NM_DEVICE_STATE_REASON_AUTOIP_ERROR:
-		return _("AutoIP service error");
-
-	case NM_DEVICE_STATE_REASON_AUTOIP_FAILED:
-		return _("AutoIP service failed");
-
-	case NM_DEVICE_STATE_REASON_MODEM_BUSY:
-		return _("The line is busy");
-
-	case NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE:
-		return _("No dial tone");
-
-	case NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER:
-		return _("No carrier could be established");
 
-	case NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT:
-		return _("The dialing request timed out");
-
-	case NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED:
-		return _("The dialing attempt failed");
-
-	case NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED:
-		return _("Modem initialization failed");
-
-	case NM_DEVICE_STATE_REASON_GSM_APN_FAILED:
-		return _("Failed to select the specified APN");
-
-	case NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING:
-		return _("Not searching for networks");
-
-	case NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED:
-		return _("Network registration denied");
-
-	case NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT:
-		return _("Network registration timed out");
-
-	case NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED:
-		return _("Failed to register with the requested network");
-
-	case NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED:
-		return _("PIN check failed");
-
-	case NM_DEVICE_STATE_REASON_FIRMWARE_MISSING:
-		return _("Necessary firmware for the device may be missing");
-
-	case NM_DEVICE_STATE_REASON_REMOVED:
-		return _("The device was removed");
-
-	case NM_DEVICE_STATE_REASON_SLEEPING:
-		return _("NetworkManager went to sleep");
-
-	case NM_DEVICE_STATE_REASON_CONNECTION_REMOVED:
-		return _("The device's active connection disappeared");
-
-	case NM_DEVICE_STATE_REASON_USER_REQUESTED:
-		return _("Device disconnected by user or client");
-
-	case NM_DEVICE_STATE_REASON_CARRIER:
-		return _("Carrier/link changed");
-
-	case NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED:
-		return _("The device's existing connection was assumed");
-
-	case NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE:
-		return _("The supplicant is now available");
-
-	case NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND:
-		return _("The modem could not be found");
-
-	case NM_DEVICE_STATE_REASON_BT_FAILED:
-		return _("The Bluetooth connection failed or timed out");
-
-	case NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED:
-		return _("GSM Modem's SIM card not inserted");
-
-	case NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED:
-		return _("GSM Modem's SIM PIN required");
-
-	case NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED:
-		return _("GSM Modem's SIM PUK required");
-
-	case NM_DEVICE_STATE_REASON_GSM_SIM_WRONG:
-		return _("GSM Modem's SIM wrong");
-
-	case NM_DEVICE_STATE_REASON_INFINIBAND_MODE:
-		return _("InfiniBand device does not support connected mode");
-
-        case NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED:
-		return _("A dependency of the connection failed");
-	default:
-		return _("Unknown");
-	}
+	g_main_loop_quit (loop);  /* quit main loop */
 }
 
 /* Convert device type to string. Use setting names strings to match with
@@ -440,6 +261,8 @@ device_type_to_string (NMDevice *device)
 	switch (nm_device_get_device_type (device)) {
 	case NM_DEVICE_TYPE_ETHERNET:
 		return NM_SETTING_WIRED_SETTING_NAME;
+	case NM_DEVICE_TYPE_ADSL:
+		return NM_SETTING_ADSL_SETTING_NAME;
 	case NM_DEVICE_TYPE_WIFI:
 		return NM_SETTING_WIRELESS_SETTING_NAME;
 	case NM_DEVICE_TYPE_MODEM:
@@ -505,7 +328,7 @@ ap_wpa_rsn_flags_to_string (NM80211ApSecurityFlags flags)
 
 	i = 0;
 	while (flags_str[i])
-		 g_free (flags_str[i++]);
+		g_free (flags_str[i++]);
 
 	return ret_str;
 }
@@ -745,8 +568,8 @@ show_device_info (gpointer data, gpointer user_data)
 			else if (NM_IS_DEVICE_VLAN (device))
 				hwaddr = nm_device_vlan_get_hw_address (NM_DEVICE_VLAN (device));
 
-			state_str = g_strdup_printf ("%d (%s)", state, device_state_to_string (state));
-			reason_str = g_strdup_printf ("%d (%s)", reason, device_reason_to_string (reason));
+			state_str = g_strdup_printf ("%d (%s)", state, nmc_device_state_to_string (state));
+			reason_str = g_strdup_printf ("%d (%s)", reason, nmc_device_reason_to_string (reason));
 
 			nmc->allowed_fields[0].value = nmc_fields_dev_list_sections[0].name;  /* "GENERAL"*/
 			nmc->allowed_fields[1].value = nm_device_get_iface (device);
@@ -754,14 +577,17 @@ show_device_info (gpointer data, gpointer user_data)
 			nmc->allowed_fields[3].value = nm_device_get_vendor (device);
 			nmc->allowed_fields[4].value = nm_device_get_product (device);
 			nmc->allowed_fields[5].value = nm_device_get_driver (device) ? nm_device_get_driver (device) : _("(unknown)");
-			nmc->allowed_fields[6].value = hwaddr ? hwaddr : _("(unknown)");
-			nmc->allowed_fields[7].value = state_str;
-			nmc->allowed_fields[8].value = reason_str;
-			nmc->allowed_fields[9].value = nm_device_get_udi (device);
-			nmc->allowed_fields[10].value = nm_device_get_ip_iface (device);
-			nmc->allowed_fields[11].value = nm_device_get_managed (device) ? _("yes") : _("no");
-			nmc->allowed_fields[12].value = nm_device_get_firmware_missing (device) ? _("yes") : _("no");
-			nmc->allowed_fields[13].value = (acon = nm_device_get_active_connection (device)) ?
+			nmc->allowed_fields[6].value = nm_device_get_driver_version (device);
+			nmc->allowed_fields[7].value = nm_device_get_firmware_version (device);
+			nmc->allowed_fields[8].value = hwaddr ? hwaddr : _("(unknown)");
+			nmc->allowed_fields[9].value = state_str;
+			nmc->allowed_fields[10].value = reason_str;
+			nmc->allowed_fields[11].value = nm_device_get_udi (device);
+			nmc->allowed_fields[12].value = nm_device_get_ip_iface (device);
+			nmc->allowed_fields[13].value = nm_device_get_managed (device) ? _("yes") : _("no");
+			nmc->allowed_fields[14].value = nm_device_get_autoconnect (device) ? _("yes") : _("no");
+			nmc->allowed_fields[15].value = nm_device_get_firmware_missing (device) ? _("yes") : _("no");
+			nmc->allowed_fields[16].value = (acon = nm_device_get_active_connection (device)) ?
 			                                   nm_object_get_path (NM_OBJECT (acon)) : _("not connected");
 
 			nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX;
@@ -975,7 +801,7 @@ show_device_status (NMDevice *device, NmCli *nmc)
 {
 	nmc->allowed_fields[0].value = nm_device_get_iface (device);
 	nmc->allowed_fields[1].value = device_type_to_string (device);
-	nmc->allowed_fields[2].value = device_state_to_string (nm_device_get_state (device));
+	nmc->allowed_fields[2].value = nmc_device_state_to_string (nm_device_get_state (device));
 	nmc->allowed_fields[3].value = nm_object_get_path (NM_OBJECT (device));
 
 	nmc->print_fields.flags &= ~NMC_PF_FLAG_MAIN_HEADER_ADD & ~NMC_PF_FLAG_MAIN_HEADER_ONLY & ~NMC_PF_FLAG_FIELD_NAMES; /* Clear header flags */
@@ -1110,7 +936,7 @@ do_devices_list (NmCli *nmc, int argc, char **argv)
 				device = candidate;
 		}
 		if (!device) {
-		 	g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), iface);
+			g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), iface);
 			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 			goto error;
 		}
@@ -1151,6 +977,16 @@ timeout_cb (gpointer user_data)
 	return FALSE;
 }
 
+static gboolean
+progress_cb (gpointer user_data)
+{
+	NMDevice *device = (NMDevice *) user_data;
+
+	nmc_terminal_show_progress (device ? nmc_device_state_to_string (nm_device_get_state (device)) : "");
+
+	return TRUE;
+}
+
 static void
 disconnect_device_cb (NMDevice *device, GError *error, gpointer user_data)
 {
@@ -1166,10 +1002,13 @@ disconnect_device_cb (NMDevice *device, GError *error, gpointer user_data)
 		quit ();
 	} else {
 		state = nm_device_get_state (device);
-		printf (_("Device state: %d (%s)\n"), state, device_state_to_string (state));
 
 		if (nmc->nowait_flag || state == NM_DEVICE_STATE_DISCONNECTED) {
 			/* Don't want to wait or device already disconnected */
+			if (state == NM_DEVICE_STATE_DISCONNECTED && nmc->print_output == NMC_PRINT_PRETTY) {
+				nmc_terminal_erase_line ();
+				printf (_("Device '%s' has been disconnected.\n"), nm_device_get_iface (device));
+			}
 			quit ();
 		} else {
 			g_signal_connect (device, "notify::state", G_CALLBACK (device_state_cb), nmc);
@@ -1273,6 +1112,10 @@ do_device_disconnect (NmCli *nmc, int argc, char **argv)
 	nmc->should_wait = TRUE;
 	nm_device_disconnect (device, disconnect_device_cb, nmc);
 
+	/* Start progress indication */
+	if (nmc->print_output == NMC_PRINT_PRETTY)
+		progress_id = g_timeout_add (120, progress_cb, device);
+
 error:
 	return nmc->return_value;
 }
@@ -1399,7 +1242,7 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 		}
 
 		if (!device) {
-		 	g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), iface);
+			g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), iface);
 			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 			goto error;
 		}
@@ -1419,7 +1262,7 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 					g_free (bssid_up);
 				}
 				if (!ap) {
-				 	g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."), bssid_user);
+					g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."), bssid_user);
 					nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 					goto error;
 				}
@@ -1436,7 +1279,7 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 				show_acces_point_info (device, nmc);
 			}
 		} else {
-		 	g_string_printf (nmc->return_text, _("Error: Device '%s' is not a WiFi device."), iface);
+			g_string_printf (nmc->return_text, _("Error: Device '%s' is not a WiFi device."), iface);
 			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 			goto error;
 		}
@@ -1473,7 +1316,7 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 				}
 			}
 			if (!ap) {
-			 	g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."), bssid_user);
+				g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."), bssid_user);
 				nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 				goto error;
 			}
@@ -1490,6 +1333,433 @@ error:
 	return nmc->return_value;
 }
 
+static void
+monitor_device_state_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
+{
+	NmCli *nmc = (NmCli *) user_data;
+	NMDeviceState state;
+	NMDeviceStateReason reason;
+
+	state = nm_device_get_state_reason (device, &reason);
+
+	if (state == NM_DEVICE_STATE_ACTIVATED) {
+		if (nmc->print_output == NMC_PRINT_PRETTY) {
+			NMActiveConnection *active = nm_device_get_active_connection (device);
+
+			nmc_terminal_erase_line ();
+			printf (_("Connection with UUID '%s' created and activated on device '%s'\n"),
+			        nm_active_connection_get_uuid (active), nm_device_get_iface (device));
+		}
+		quit ();
+	} else if (state == NM_DEVICE_STATE_FAILED) {
+		g_string_printf (nmc->return_text, _("Error: Connection activation failed: (%d) %s."),
+		                 reason, nmc_device_reason_to_string (reason));
+		nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
+		quit ();
+	}
+}
+
+typedef struct {
+	NmCli *nmc;
+	NMDevice *device;
+} AddAndActivateInfo;
+
+static void
+add_and_activate_cb (NMClient *client,
+                     NMActiveConnection *active,
+                     const char *connection_path,
+                     GError *error,
+                     gpointer user_data)
+{
+	AddAndActivateInfo *info = (AddAndActivateInfo *) user_data;
+	NmCli *nmc = info->nmc;
+	NMDevice *device = info->device;
+	NMActiveConnectionState state;
+
+        if (error) {
+		g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: (%d) %s"),
+		                 error->code, error->message);
+		nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
+		quit ();
+	} else {
+		state = nm_active_connection_get_state (active);
+
+		if (state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
+			g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: Unknown error"));
+			nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
+			quit ();
+		}
+
+		if (nmc->nowait_flag || state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
+			/* User doesn't want to wait or already activated */
+			if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED && nmc->print_output == NMC_PRINT_PRETTY) {
+				printf (_("Connection with UUID '%s' created and activated on device '%s'\n"),
+				        nm_active_connection_get_uuid (active), nm_device_get_iface (device));
+			}
+			quit ();
+		} else {
+			g_signal_connect (device, "notify::state", G_CALLBACK (monitor_device_state_cb), nmc);
+			g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);  /* Exit if timeout expires */
+
+			if (nmc->print_output == NMC_PRINT_PRETTY)
+				progress_id = g_timeout_add (120, progress_cb, device);
+		}
+	}
+
+	g_free (info);
+}
+
+/*
+ * Find a Wi-Fi device with 'iface' in 'devices' array. If 'iface' is NULL,
+ * the first Wi-Fi device is returned. 'idx' parameter is updated to the point
+ * where the function finished so that the function can be called repeatedly
+ * to get next matching device.
+ * Returns: found device or NULL
+ */
+static NMDevice *
+find_wifi_device_by_iface (const GPtrArray *devices, const char *iface, int *idx)
+{
+	NMDevice *device = NULL;
+	int i;
+
+	for (i = *idx; devices && (i < devices->len); i++) {
+		NMDevice *candidate = g_ptr_array_index (devices, i);
+		const char *dev_iface = nm_device_get_iface (candidate);
+
+		if (!NM_IS_DEVICE_WIFI (candidate))
+			continue;
+
+		if (iface) {
+			/* If a iface was specified then use it. */
+			if (strcmp (dev_iface, iface) == 0) {
+				device = candidate;
+				break;
+			}
+		} else {
+			/* Else return the first Wi-Fi device. */
+			device = candidate;
+			break;
+		}
+	}
+
+	*idx = i + 1;
+	return device;
+}
+
+/*
+ * Find AP on 'device' according to 'bssid' or 'ssid' parameter.
+ * Returns: found AP or NULL
+ */
+static NMAccessPoint *
+find_ap_on_device (NMDevice *device, GByteArray *bssid, const char *ssid)
+{
+	const GPtrArray *aps;
+	NMAccessPoint *ap = NULL;
+	int i;
+
+	g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
+	g_return_val_if_fail ((bssid && !ssid) || (!bssid && ssid), NULL);
+
+	aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device));
+	for (i = 0; aps && (i < aps->len); i++) {
+		NMAccessPoint *candidate_ap = g_ptr_array_index (aps, i);
+
+		if (ssid) {
+			/* Parameter is SSID */
+			const GByteArray *candidate_ssid = nm_access_point_get_ssid (candidate_ap);
+			char *ssid_tmp = nm_utils_ssid_to_utf8 (candidate_ssid);
+
+			/* Compare SSIDs */
+			if (strcmp (ssid, ssid_tmp) == 0) {
+				ap = candidate_ap;
+				g_free (ssid_tmp);
+				break;
+			}
+			g_free (ssid_tmp);
+		} else if (bssid) {
+			/* Parameter is BSSID */
+			const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap);
+			char *bssid_up = nm_utils_hwaddr_ntoa (bssid->data, ARPHRD_ETHER);
+
+			/* Compare BSSIDs */
+			if (strcmp (bssid_up, candidate_bssid) == 0) {
+				ap = candidate_ap;
+				g_free (bssid_up);
+				break;
+			}
+			g_free (bssid_up);
+		}
+	}
+
+	return ap;
+}
+
+static NMCResultCode
+do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
+{
+	NMDevice *device = NULL;
+	NMAccessPoint *ap = NULL;
+	NMConnection *connection = NULL;
+	NMSettingConnection *s_con;
+	NMSettingWireless *s_wifi;
+	NMSettingWirelessSecurity *s_wsec;
+	AddAndActivateInfo *info;
+	const char *param_user = NULL;
+	const char *iface = NULL;
+	const char *bssid = NULL;
+	const char *password = NULL;
+	const char *con_name = NULL;
+	gboolean private = FALSE;
+	gboolean wait = TRUE;
+	gboolean wep_passphrase = FALSE;
+	GByteArray *bssid1_arr = NULL;
+	GByteArray *bssid2_arr = NULL;
+	const GPtrArray *devices;
+	int devices_idx;
+	GError *error = NULL;
+
+	/* Default timeout for waiting for operation completion */
+	nmc->timeout = 90;
+
+	/* Get the first compulsory argument (SSID or BSSID) */
+	if (argc > 0) {
+		param_user = *argv;
+		bssid1_arr = nm_utils_hwaddr_atoba (param_user, ARPHRD_ETHER);
+
+		argc--;
+		argv++;
+	} else {
+		g_string_printf (nmc->return_text, _("Error: SSID or BSSID are missing."));
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		goto error;
+	}
+
+	/* Get the rest of the parameters */
+	while (argc > 0) {
+		if (strcmp (*argv, "iface") == 0) {
+			if (next_arg (&argc, &argv) != 0) {
+				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				goto error;
+			}
+			iface = *argv;
+		} else if (strcmp (*argv, "bssid") == 0) {
+			if (next_arg (&argc, &argv) != 0) {
+				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				goto error;
+			}
+			bssid = *argv;
+			bssid2_arr = nm_utils_hwaddr_atoba (bssid, ARPHRD_ETHER);
+			if (!bssid2_arr) {
+				g_string_printf (nmc->return_text, _("Error: bssid argument value '%s' is not a valid BSSID."),
+				                 bssid);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				goto error;
+			}
+		} else if (strcmp (*argv, "password") == 0) {
+			if (next_arg (&argc, &argv) != 0) {
+				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				goto error;
+			}
+			password = *argv;
+		} else if (strcmp (*argv, "wep-key-type") == 0) {
+			if (next_arg (&argc, &argv) != 0) {
+				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				goto error;
+			}
+			if (strcmp (*argv, "key") == 0)
+				wep_passphrase = FALSE;
+			else if (strcmp (*argv, "phrase") == 0)
+				wep_passphrase = TRUE;
+			else {
+				g_string_printf (nmc->return_text,
+				                 _("Error: wep-key-type argument value '%s' is invalid, use 'key' or 'phrase'."),
+				                 *argv);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				goto error;
+			}
+		} else if (strcmp (*argv, "name") == 0) {
+			if (next_arg (&argc, &argv) != 0) {
+				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				goto error;
+			}
+			con_name = *argv;
+		} else if (strcmp (*argv, "--private") == 0) {
+			private = TRUE;
+		} else if (strcmp (*argv, "--nowait") == 0) {
+			wait = FALSE;
+		} else if (strcmp (*argv, "--timeout") == 0) {
+			if (next_arg (&argc, &argv) != 0) {
+				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *argv);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				goto error;
+			}
+
+			errno = 0;
+			nmc->timeout = strtol (*argv, NULL, 10);
+			if (errno || nmc->timeout < 0) {
+				g_string_printf (nmc->return_text, _("Error: timeout value '%s' is not valid."), *argv);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				goto error;
+			}
+		} else {
+			fprintf (stderr, _("Unknown parameter: %s\n"), *argv);
+		}
+
+		argc--;
+		argv++;
+	}
+
+	/* Verify SSID/BSSID parameters */
+	if (bssid1_arr && bssid2_arr && memcmp (bssid1_arr->data, bssid2_arr->data, ETH_ALEN)) {
+		g_string_printf (nmc->return_text, _("Error: BSSID to connect to (%s) differs from bssid argument (%s)."),
+		                 param_user, bssid);
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		goto error;
+	}
+	if (!bssid1_arr && strlen (param_user) > 32) {
+		g_string_printf (nmc->return_text, _("Error: Parameter '%s' is neither SSID nor BSSID."), param_user);
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		goto error;
+	}
+
+	if (!nmc_is_nm_running (nmc, &error)) {
+		if (error) {
+			g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), error->message);
+			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+			g_error_free (error);
+		} else {
+			g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+			nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+		}
+		goto error;
+	}
+
+	if (!nmc_versions_match (nmc))
+		goto error;
+
+	nmc->get_client (nmc);
+	devices = nm_client_get_devices (nmc->client);
+
+	/* Find a device to activate the connection on */
+	devices_idx = 0;
+	device = find_wifi_device_by_iface (devices, iface, &devices_idx);
+
+	if (!device) {
+		if (iface)
+			g_string_printf (nmc->return_text, _("Error: Device '%s' is not a Wi-Fi device."), iface);
+		else
+			g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found."));
+		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+		goto error;
+	}
+
+	/* Find an AP to connect to */
+	ap = find_ap_on_device (device, bssid1_arr, bssid1_arr ? NULL : param_user);
+	if (!ap && !iface) {
+		/* AP not found. iface was not specified, so try finding the AP on another device. */
+		while ((device = find_wifi_device_by_iface (devices, NULL, &devices_idx)) != NULL) {
+			ap = find_ap_on_device (device, bssid1_arr, bssid1_arr ? NULL : param_user);
+			if (ap)
+				break;
+		}
+	}
+
+	if (!ap) {
+		if (!bssid1_arr)
+			g_string_printf (nmc->return_text, _("Error: No network with SSID '%s' found."), param_user);
+		else
+			g_string_printf (nmc->return_text, _("Error: No access point with BSSID '%s' found."), param_user);
+		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+		goto error;
+	}
+
+	/* If there are some connection data from user, create a connection and
+	 * fill them into proper settings. */
+	if (con_name || private || bssid2_arr || password)
+		connection = nm_connection_new ();
+
+	if (con_name || private) {
+		s_con =  (NMSettingConnection *) nm_setting_connection_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+		/* Set user provided connection name */
+		if (con_name)
+			g_object_set (s_con, NM_SETTING_CONNECTION_ID, con_name, NULL);
+
+		/* Connection will only be visible to this user when '--private' is specified */
+		if (private)
+			nm_setting_connection_add_permission (s_con, "user", g_get_user_name (), NULL);
+	}
+	if (bssid2_arr) {
+		s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+
+		/* 'bssid' parameter is used to restrict the conenction only to the BSSID */
+		g_object_set (s_wifi, NM_SETTING_WIRELESS_BSSID, bssid2_arr, NULL);
+	}
+	if (password) {
+		NM80211ApFlags flags = nm_access_point_get_flags (ap);
+		NM80211ApSecurityFlags wpa_flags = nm_access_point_get_wpa_flags (ap);
+		NM80211ApSecurityFlags rsn_flags = nm_access_point_get_rsn_flags (ap);
+
+		s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+		nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+
+		/* Set password for WEP or WPA-PSK. */
+		if (flags & NM_802_11_AP_FLAGS_PRIVACY) {
+			if (wpa_flags == NM_802_11_AP_SEC_NONE && rsn_flags == NM_802_11_AP_SEC_NONE) {
+				/* WEP */
+				nm_setting_wireless_security_set_wep_key (s_wsec, 0, password);
+				g_object_set (G_OBJECT (s_wsec),
+				              NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
+				              wep_passphrase ? NM_WEP_KEY_TYPE_PASSPHRASE: NM_WEP_KEY_TYPE_KEY,
+				              NULL);
+			} else if (   !(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
+				   && !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
+				/* WPA PSK */
+				g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_PSK, password, NULL);
+			}
+		}
+		// FIXME: WPA-Enterprise is not supported yet.
+		// We are not able to determine and fill all the parameters for
+		// 802.1X authentication automatically without user providing
+		// the data. Adding nmcli options for the 8021x setting would
+		// clutter the command. However, that could be solved later by
+		// implementing add/edit connections support for nmcli.
+	}
+
+	/* nowait_flag indicates user input. should_wait says whether quit in start().
+	 * We have to delay exit after add_and_activate_cb() is called, even if
+	 * the user doesn't want to wait, in order to give NM time to check our
+	 * permissions. */
+	nmc->nowait_flag = !wait;
+	nmc->should_wait = TRUE;
+
+	info = g_malloc0 (sizeof (AddAndActivateInfo));
+	info->nmc = nmc;
+	info->device = device;
+
+	nm_client_add_and_activate_connection (nmc->client,
+	                                       connection,
+	                                       device,
+	                                       nm_object_get_path (NM_OBJECT (ap)),
+	                                       add_and_activate_cb,
+	                                       info);
+
+error:
+	if (bssid1_arr)
+		g_byte_array_free (bssid1_arr, TRUE);
+	if (bssid2_arr)
+		g_byte_array_free (bssid2_arr, TRUE);
+
+	return nmc->return_value;
+}
+
 static NMCResultCode
 do_device_wifi (NmCli *nmc, int argc, char **argv)
 {
@@ -1498,8 +1768,9 @@ do_device_wifi (NmCli *nmc, int argc, char **argv)
 	else if (argc > 0) {
 		if (matches (*argv, "list") == 0) {
 			nmc->return_value = do_device_wifi_list (nmc, argc-1, argv+1);
-		}
-		else {
+		} else if (matches (*argv, "connect") == 0) {
+			nmc->return_value = do_device_wifi_connect_network (nmc, argc-1, argv+1);
+		} else {
 			g_string_printf (nmc->return_text, _("Error: 'dev wifi' command '%s' is not valid."), *argv);
 			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 		}
@@ -1618,7 +1889,7 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv)
 		}
 
 		if (!device) {
-		 	g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), iface);
+			g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), iface);
 			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 			goto error;
 		}
@@ -1638,7 +1909,7 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv)
 					g_free (nsp_up);
 				}
 				if (!nsp) {
-				 	g_string_printf (nmc->return_text, _("Error: NSP with name '%s' not found."), nsp_user);
+					g_string_printf (nmc->return_text, _("Error: NSP with name '%s' not found."), nsp_user);
 					nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 					goto error;
 				}
@@ -1649,7 +1920,7 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv)
 				show_nsp_info (device, nmc);
 			}
 		} else {
-		 	g_string_printf (nmc->return_text, _("Error: Device '%s' is not a WiMAX device."), iface);
+			g_string_printf (nmc->return_text, _("Error: Device '%s' is not a WiMAX device."), iface);
 			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 			goto error;
 		}
@@ -1680,7 +1951,7 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv)
 				}
 			}
 			if (!nsp) {
-			 	g_string_printf (nmc->return_text, _("Error: Access point with nsp '%s' not found."), nsp_user);
+				g_string_printf (nmc->return_text, _("Error: Access point with nsp '%s' not found."), nsp_user);
 				nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 				goto error;
 			}