cli: reuse connections in nmcli dev wifi con

Try to locate an existing connection before creating a new one when
handling "nmcli device wifi connect".  This allows WPA-Enterprise
networks to be activated this way, consistent with the comment that this
command is equivalent to clicking on an SSID in a GUI client.
This commit is contained in:
Andrew Zaborowski
2018-06-12 06:52:01 +02:00
committed by Andrew Zaborowski
parent 0c70a9ef6d
commit 3593237527
2 changed files with 139 additions and 65 deletions

View File

@@ -847,14 +847,13 @@ usage_device_wifi (void)
"ARGUMENTS := connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [ifname <ifname>]\n" "ARGUMENTS := connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [ifname <ifname>]\n"
" [bssid <BSSID>] [name <name>] [private yes|no] [hidden yes|no]\n" " [bssid <BSSID>] [name <name>] [private yes|no] [hidden yes|no]\n"
"\n" "\n"
"Connect to a Wi-Fi network specified by SSID or BSSID. The command creates\n" "Connect to a Wi-Fi network specified by SSID or BSSID. The command finds a\n"
"a new connection and then activates it on a device. This is a command-line\n" "matching connection or creates one and then activates it on a device. This\n"
"counterpart of clicking an SSID in a GUI client. The command always creates\n" "is a command-line counterpart of clicking an SSID in a GUI client. If a\n"
"a new connection and thus it is mainly useful for connecting to new Wi-Fi\n" "connection for the network already exists, it is possible to bring up the\n"
"networks. If a connection for the network already exists, it is better to\n" "existing profile as follows: nmcli con up id <name>. Note that only open,\n"
"bring up the existing profile as follows: nmcli con up id <name>. Note that\n" "WEP and WPA-PSK networks are supported if no previous connection exists.\n"
"only open, WEP and WPA-PSK networks are supported at the moment. It is also\n" "It is also assumed that IP configuration is obtained via DHCP.\n"
"assumed that IP configuration is obtained via DHCP.\n"
"\n" "\n"
"ARGUMENTS := hotspot [ifname <ifname>] [con-name <name>] [ssid <SSID>]\n" "ARGUMENTS := hotspot [ifname <ifname>] [con-name <name>] [ssid <SSID>]\n"
" [band a|bg] [channel <channel>] [password <password>]\n" " [band a|bg] [channel <channel>] [password <password>]\n"
@@ -1839,6 +1838,7 @@ typedef struct {
NmCli *nmc; NmCli *nmc;
NMDevice *device; NMDevice *device;
gboolean hotspot; gboolean hotspot;
gboolean create;
} AddAndActivateInfo; } AddAndActivateInfo;
static void static void
@@ -1853,15 +1853,21 @@ add_and_activate_cb (GObject *client,
NMActiveConnection *active; NMActiveConnection *active;
GError *error = NULL; GError *error = NULL;
if (info->create)
active = nm_client_add_and_activate_connection_finish (NM_CLIENT (client), result, &error); active = nm_client_add_and_activate_connection_finish (NM_CLIENT (client), result, &error);
else
active = nm_client_activate_connection_finish (NM_CLIENT (client), result, &error);
if (error) { if (error) {
if (info->hotspot) if (info->hotspot)
g_string_printf (nmc->return_text, _("Error: Failed to setup a Wi-Fi hotspot: %s"), g_string_printf (nmc->return_text, _("Error: Failed to setup a Wi-Fi hotspot: %s"),
error->message); error->message);
else else if (info->create)
g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: %s"), g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: %s"),
error->message); error->message);
else
g_string_printf (nmc->return_text, _("Error: Failed to activate connection: %s"),
error->message);
g_error_free (error); g_error_free (error);
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION; nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
quit (); quit ();
@@ -1871,8 +1877,10 @@ add_and_activate_cb (GObject *client,
if (state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) { if (state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
if (info->hotspot) if (info->hotspot)
g_string_printf (nmc->return_text, _("Error: Failed to setup a Wi-Fi hotspot")); g_string_printf (nmc->return_text, _("Error: Failed to setup a Wi-Fi hotspot"));
else else if (info->create)
g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: Unknown error")); g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: Unknown error"));
else
g_string_printf (nmc->return_text, _("Error: Failed to activate connection: Unknown error"));
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION; nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
g_object_unref (active); g_object_unref (active);
quit (); quit ();
@@ -1883,12 +1891,16 @@ add_and_activate_cb (GObject *client,
if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY)
nmc_terminal_erase_line (); nmc_terminal_erase_line ();
if (!info->hotspot) if (info->hotspot)
g_print (_("Hotspot '%s' activated on device '%s'\n"),
nm_active_connection_get_id (active), nm_device_get_iface (device));
else if (info->create)
g_print (_("Connection with UUID '%s' created and activated on device '%s'\n"), g_print (_("Connection with UUID '%s' created and activated on device '%s'\n"),
nm_active_connection_get_uuid (active), nm_device_get_iface (device)); nm_active_connection_get_uuid (active), nm_device_get_iface (device));
else else
g_print (_("Hotspot '%s' activated on device '%s'\n"), g_print (_("Connection with ID '%s', UUID '%s' activated on device '%s'\n"),
nm_active_connection_get_id (active), nm_device_get_iface (device)); nm_active_connection_get_id (active), nm_active_connection_get_uuid (active),
nm_device_get_iface (device));
} }
g_object_unref (active); g_object_unref (active);
quit (); quit ();
@@ -1947,6 +1959,7 @@ connect_device_cb (GObject *client, GAsyncResult *result, gpointer user_data)
if (error) { if (error) {
/* If no connection existed for the device, create one and activate it */ /* If no connection existed for the device, create one and activate it */
if (g_error_matches (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION)) { if (g_error_matches (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION)) {
info->create = TRUE;
create_connect_connection_for_device (info); create_connect_connection_for_device (info);
return; return;
} }
@@ -3139,7 +3152,6 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
NMConnection *connection = NULL; NMConnection *connection = NULL;
NMSettingConnection *s_con; NMSettingConnection *s_con;
NMSettingWireless *s_wifi; NMSettingWireless *s_wifi;
NMSettingWirelessSecurity *s_wsec;
AddAndActivateInfo *info; AddAndActivateInfo *info;
const char *param_user = NULL; const char *param_user = NULL;
const char *ifname = NULL; const char *ifname = NULL;
@@ -3155,6 +3167,10 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
int devices_idx; int devices_idx;
char *ssid_ask = NULL; char *ssid_ask = NULL;
char *passwd_ask = NULL; char *passwd_ask = NULL;
const GPtrArray *avail_cons;
gboolean name_match = FALSE;
gboolean existing_con = FALSE;
int i;
/* Set default timeout waiting for operation completion. */ /* Set default timeout waiting for operation completion. */
if (nmc->timeout == -1) if (nmc->timeout == -1)
@@ -3384,6 +3400,35 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
goto finish; goto finish;
} }
avail_cons = nm_device_get_available_connections (device);
for (i = 0; i < avail_cons->len; i++) {
NMRemoteConnection *avail_con = g_ptr_array_index (avail_cons, i);
const char *id = nm_connection_get_id (NM_CONNECTION (avail_con));
if (con_name) {
if (!id || strcmp (id, con_name))
continue;
name_match = TRUE;
}
if (nm_access_point_connection_valid (ap, NM_CONNECTION (avail_con))) {
/* ap has been checked against bssid1, bssid2 and the ssid
* and now avail_con has been checked against ap.
*/
connection = NM_CONNECTION (avail_con);
existing_con = TRUE;
break;
}
}
if (name_match && !existing_con) {
g_string_printf (nmc->return_text, _("Error: Connection '%s' exists but properties don't match."), con_name);
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
goto finish;
}
if (!existing_con) {
/* If there are some connection data from user, create a connection and /* If there are some connection data from user, create a connection and
* fill them into proper settings. */ * fill them into proper settings. */
if (con_name || private || bssid2_arr || password || hidden) if (con_name || private || bssid2_arr || password || hidden)
@@ -3425,6 +3470,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
param_user); param_user);
} }
} }
}
/* handle password */ /* handle password */
ap_flags = nm_access_point_get_flags (ap); ap_flags = nm_access_point_get_flags (ap);
@@ -3435,8 +3481,25 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
if ( (ap_flags & NM_802_11_AP_FLAGS_PRIVACY) if ( (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
|| ap_wpa_flags != NM_802_11_AP_SEC_NONE || ap_wpa_flags != NM_802_11_AP_SEC_NONE
|| ap_rsn_flags != NM_802_11_AP_SEC_NONE) { || ap_rsn_flags != NM_802_11_AP_SEC_NONE) {
const char *con_password = NULL;
NMSettingWirelessSecurity *s_wsec = NULL;
if (connection) {
s_wsec = nm_connection_get_setting_wireless_security (connection);
if (s_wsec) {
if (ap_wpa_flags == NM_802_11_AP_SEC_NONE && ap_rsn_flags == NM_802_11_AP_SEC_NONE) {
/* WEP */
con_password = nm_setting_wireless_security_get_wep_key (s_wsec, 0);
} else if ( (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
|| (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) {
/* WPA PSK */
con_password = nm_setting_wireless_security_get_psk (s_wsec);
}
}
}
/* Ask for missing password when one is expected and '--ask' is used */ /* Ask for missing password when one is expected and '--ask' is used */
if (!password && nmc->ask) { if (!password && !con_password && nmc->ask) {
password = passwd_ask = nmc_readline_echo (&nmc->nmc_config, password = passwd_ask = nmc_readline_echo (&nmc->nmc_config,
nmc->nmc_config.show_secrets, nmc->nmc_config.show_secrets,
_("Password: ")); _("Password: "));
@@ -3445,8 +3508,10 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
if (password) { if (password) {
if (!connection) if (!connection)
connection = nm_simple_connection_new (); connection = nm_simple_connection_new ();
if (!s_wsec) {
s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new (); s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
nm_connection_add_setting (connection, NM_SETTING (s_wsec)); nm_connection_add_setting (connection, NM_SETTING (s_wsec));
}
if (ap_wpa_flags == NM_802_11_AP_SEC_NONE && ap_rsn_flags == NM_802_11_AP_SEC_NONE) { if (ap_wpa_flags == NM_802_11_AP_SEC_NONE && ap_rsn_flags == NM_802_11_AP_SEC_NONE) {
/* WEP */ /* WEP */
@@ -3462,7 +3527,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
} }
} }
} }
// FIXME: WPA-Enterprise is not supported yet. // FIXME: Creating WPA-Enterprise connections is not supported yet.
// We are not able to determine and fill all the parameters for // We are not able to determine and fill all the parameters for
// 802.1X authentication automatically without user providing // 802.1X authentication automatically without user providing
// the data. Adding nmcli options for the 8021x setting would // the data. Adding nmcli options for the 8021x setting would
@@ -3480,7 +3545,16 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
info->nmc = nmc; info->nmc = nmc;
info->device = device; info->device = device;
info->hotspot = FALSE; info->hotspot = FALSE;
info->create = !existing_con;
if (existing_con) {
nm_client_activate_connection_async (nmc->client,
connection,
device,
nm_object_get_path (NM_OBJECT (ap)),
NULL,
add_and_activate_cb,
info);
} else {
nm_client_add_and_activate_connection_async (nmc->client, nm_client_add_and_activate_connection_async (nmc->client,
connection, connection,
device, device,
@@ -3488,6 +3562,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
NULL, NULL,
add_and_activate_cb, add_and_activate_cb,
info); info);
}
finish: finish:
if (bssid1_arr) if (bssid1_arr)

View File

@@ -1445,14 +1445,13 @@
<listitem> <listitem>
<para>Connect to a Wi-Fi network specified by SSID or BSSID. The command <para>Connect to a Wi-Fi network specified by SSID or BSSID. The command
creates a new connection and then activates it on a device. This is a finds a matching connnection or creates one and then activates it on a device.
command-line counterpart of clicking an SSID in a GUI client. The command This is a command-line counterpart of clicking an SSID in a GUI client. If
always creates a new connection and thus it is mainly useful for connecting to a connection for the network already exists, it is possible to bring up
new Wi-Fi networks. If a connection for the network already exists, it is (activate) the existing profile as follows:
better to bring up (activate) the existing connection as follows:
<command>nmcli con up id <replaceable>name</replaceable></command>. Note that <command>nmcli con up id <replaceable>name</replaceable></command>. Note that
only open, WEP and WPA-PSK networks are supported at the moment. It is also only open, WEP and WPA-PSK networks are supported if no previous connection
supposed that IP configuration is obtained via DHCP.</para> exists. It is also assumed that IP configuration is obtained via DHCP.</para>
<para>If <option>--wait</option> option is not specified, the default timeout will be 90 <para>If <option>--wait</option> option is not specified, the default timeout will be 90
seconds.</para> seconds.</para>