Lubomir Rintel
2019-01-04 18:26:41 +01:00
2 changed files with 152 additions and 105 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
@@ -1849,47 +1849,29 @@ add_and_activate_cb (GObject *client,
AddAndActivateInfo *info = (AddAndActivateInfo *) user_data; AddAndActivateInfo *info = (AddAndActivateInfo *) user_data;
NmCli *nmc = info->nmc; NmCli *nmc = info->nmc;
NMDevice *device = info->device; NMDevice *device = info->device;
NMActiveConnectionState state;
NMActiveConnection *active; NMActiveConnection *active;
GError *error = NULL; GError *error = NULL;
active = nm_client_add_and_activate_connection_finish (NM_CLIENT (client), result, &error); if (info->create)
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 ();
} else { } else {
state = nm_active_connection_get_state (active); if (nmc->nowait_flag) {
if (state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
if (info->hotspot)
g_string_printf (nmc->return_text, _("Error: Failed to setup a Wi-Fi hotspot"));
else
g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: Unknown error"));
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
g_object_unref (active);
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) {
if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY)
nmc_terminal_erase_line ();
if (!info->hotspot)
g_print (_("Connection with UUID '%s' created and activated on device '%s'\n"),
nm_active_connection_get_uuid (active), nm_device_get_iface (device));
else
g_print (_("Hotspot '%s' activated on device '%s'\n"),
nm_active_connection_get_id (active), nm_device_get_iface (device));
}
g_object_unref (active); g_object_unref (active);
quit (); quit ();
} else { } else {
@@ -1897,6 +1879,8 @@ add_and_activate_cb (GObject *client,
g_signal_connect (device, "notify::state", G_CALLBACK (device_state_cb), active); g_signal_connect (device, "notify::state", G_CALLBACK (device_state_cb), active);
g_signal_connect (active, "notify::state", G_CALLBACK (active_state_cb), device); g_signal_connect (active, "notify::state", G_CALLBACK (active_state_cb), device);
connected_state_cb (device, active);
g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc); /* Exit if timeout expires */ g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc); /* Exit if timeout expires */
if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY)
@@ -1940,13 +1924,13 @@ connect_device_cb (GObject *client, GAsyncResult *result, gpointer user_data)
GError *error = NULL; GError *error = NULL;
const GPtrArray *devices; const GPtrArray *devices;
NMDevice *device; NMDevice *device;
NMDeviceState state;
active = nm_client_activate_connection_finish (NM_CLIENT (client), result, &error); active = nm_client_activate_connection_finish (NM_CLIENT (client), result, &error);
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;
} }
@@ -1969,14 +1953,8 @@ connect_device_cb (GObject *client, GAsyncResult *result, gpointer user_data)
} }
device = g_ptr_array_index (devices, 0); device = g_ptr_array_index (devices, 0);
state = nm_device_get_state (device);
if (nmc->nowait_flag || state == NM_DEVICE_STATE_ACTIVATED) { if (nmc->nowait_flag) {
/* Don't want to wait or device already activated */
if (state == NM_DEVICE_STATE_ACTIVATED && nmc->nmc_config.print_output == NMC_PRINT_PRETTY) {
nmc_terminal_erase_line ();
g_print (_("Device '%s' has been connected.\n"), nm_device_get_iface (device));
}
g_object_unref (active); g_object_unref (active);
quit (); quit ();
} else { } else {
@@ -1990,6 +1968,9 @@ connect_device_cb (GObject *client, GAsyncResult *result, gpointer user_data)
g_object_ref (device); g_object_ref (device);
g_signal_connect (device, "notify::state", G_CALLBACK (device_state_cb), active); g_signal_connect (device, "notify::state", G_CALLBACK (device_state_cb), active);
g_signal_connect (active, "notify::state", G_CALLBACK (active_state_cb), device); g_signal_connect (active, "notify::state", G_CALLBACK (active_state_cb), device);
connected_state_cb (device, active);
/* Start timer not to loop forever if "notify::state" signal is not issued */ /* Start timer not to loop forever if "notify::state" signal is not issued */
g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc); g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
} }
@@ -2687,7 +2668,7 @@ find_wifi_device_by_iface (NMDevice **devices, const char *iface, int *idx)
} }
/* /*
* Find AP on 'device' according to 'bssid' or 'ssid' parameter. * Find AP on 'device' according to 'bssid' and 'ssid' parameters.
* Returns: found AP or NULL * Returns: found AP or NULL
*/ */
static NMAccessPoint * static NMAccessPoint *
@@ -2704,17 +2685,17 @@ find_ap_on_device (NMDevice *device, const char *bssid, const char *ssid, gboole
NMAccessPoint *candidate_ap = g_ptr_array_index (aps, i); NMAccessPoint *candidate_ap = g_ptr_array_index (aps, i);
if (bssid) { if (bssid) {
/* Parameter is BSSID */
const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap); const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap);
if (!candidate_bssid)
continue;
/* Compare BSSIDs */ /* Compare BSSIDs */
if (complete) { if (complete) {
if (g_str_has_prefix (candidate_bssid, bssid)) if (g_str_has_prefix (candidate_bssid, bssid))
g_print ("%s\n", candidate_bssid); g_print ("%s\n", candidate_bssid);
} else if (strcmp (bssid, candidate_bssid) == 0) { } else if (strcmp (bssid, candidate_bssid) != 0)
ap = candidate_ap; continue;
break;
}
} }
if (ssid) { if (ssid) {
@@ -2733,13 +2714,18 @@ find_ap_on_device (NMDevice *device, const char *bssid, const char *ssid, gboole
if (complete) { if (complete) {
if (g_str_has_prefix (ssid_tmp, ssid)) if (g_str_has_prefix (ssid_tmp, ssid))
g_print ("%s\n", ssid_tmp); g_print ("%s\n", ssid_tmp);
} else if (strcmp (ssid, ssid_tmp) == 0) { } else if (strcmp (ssid, ssid_tmp) != 0) {
ap = candidate_ap;
g_free (ssid_tmp); g_free (ssid_tmp);
break; continue;
} }
g_free (ssid_tmp); g_free (ssid_tmp);
} }
if (complete)
continue;
ap = candidate_ap;
break;
} }
return ap; return ap;
@@ -3143,7 +3129,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;
@@ -3159,6 +3144,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)
@@ -3363,14 +3352,14 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
} }
/* Find an AP to connect to */ /* Find an AP to connect to */
ap = find_ap_on_device (device, bssid1_arr ? param_user : NULL, ap = find_ap_on_device (device, bssid1_arr ? param_user : bssid,
bssid1_arr ? NULL : param_user, FALSE); bssid1_arr ? NULL : param_user, FALSE);
if (!ap && !ifname) { if (!ap && !ifname) {
NMDevice *dev; NMDevice *dev;
/* AP not found, ifname was not specified, so try finding the AP on another device. */ /* AP not found, ifname was not specified, so try finding the AP on another device. */
while ((dev = find_wifi_device_by_iface (devices, NULL, &devices_idx)) != NULL) { while ((dev = find_wifi_device_by_iface (devices, NULL, &devices_idx)) != NULL) {
ap = find_ap_on_device (dev, bssid1_arr ? param_user : NULL, ap = find_ap_on_device (dev, bssid1_arr ? param_user : bssid,
bssid1_arr ? NULL : param_user, FALSE); bssid1_arr ? NULL : param_user, FALSE);
if (ap) { if (ap) {
device = dev; device = dev;
@@ -3388,45 +3377,75 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
goto finish; goto finish;
} }
/* If there are some connection data from user, create a connection and avail_cons = nm_device_get_available_connections (device);
* fill them into proper settings. */ for (i = 0; i < avail_cons->len; i++) {
if (con_name || private || bssid2_arr || password || hidden) NMRemoteConnection *avail_con = g_ptr_array_index (avail_cons, i);
connection = nm_simple_connection_new (); const char *id = nm_connection_get_id (NM_CONNECTION (avail_con));
if (con_name || private) { if (con_name) {
s_con = (NMSettingConnection *) nm_setting_connection_new (); if (!id || strcmp (id, con_name))
nm_connection_add_setting (connection, NM_SETTING (s_con)); continue;
/* Set user provided connection name */ name_match = TRUE;
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 (nm_access_point_connection_valid (ap, NM_CONNECTION (avail_con))) {
if (private) /* ap has been checked against bssid1, bssid2 and the ssid
nm_setting_connection_add_permission (s_con, "user", g_get_user_name (), NULL); * and now avail_con has been checked against ap.
*/
connection = NM_CONNECTION (avail_con);
existing_con = TRUE;
break;
}
} }
if (bssid2_arr || hidden) {
s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
nm_connection_add_setting (connection, NM_SETTING (s_wifi));
/* 'bssid' parameter is used to restrict the connection only to the BSSID */ if (name_match && !existing_con) {
if (bssid2_arr) g_string_printf (nmc->return_text, _("Error: Connection '%s' exists but properties don't match."), con_name);
g_object_set (s_wifi, NM_SETTING_WIRELESS_BSSID, bssid2_arr, NULL); nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
goto finish;
}
/* 'hidden' parameter is used to indicate that SSID is not broadcasted */ if (!existing_con) {
if (hidden) { /* If there are some connection data from user, create a connection and
GBytes *ssid = g_bytes_new (param_user, strlen (param_user)); * fill them into proper settings. */
if (con_name || private || bssid2_arr || password || hidden)
connection = nm_simple_connection_new ();
g_object_set (s_wifi, if (con_name || private) {
NM_SETTING_WIRELESS_SSID, ssid, s_con = (NMSettingConnection *) nm_setting_connection_new ();
NM_SETTING_WIRELESS_HIDDEN, hidden, nm_connection_add_setting (connection, NM_SETTING (s_con));
NULL);
g_bytes_unref (ssid);
/* Warn when the provided AP identifier looks like BSSID instead of SSID */ /* Set user provided connection name */
if (bssid1_arr) if (con_name)
g_printerr (_("Warning: '%s' should be SSID for hidden APs; but it looks like a BSSID.\n"), g_object_set (s_con, NM_SETTING_CONNECTION_ID, con_name, NULL);
param_user);
/* 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 || hidden) {
s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
nm_connection_add_setting (connection, NM_SETTING (s_wifi));
/* 'bssid' parameter is used to restrict the connection only to the BSSID */
if (bssid2_arr)
g_object_set (s_wifi, NM_SETTING_WIRELESS_BSSID, bssid2_arr, NULL);
/* 'hidden' parameter is used to indicate that SSID is not broadcasted */
if (hidden) {
GBytes *ssid = g_bytes_new (param_user, strlen (param_user));
g_object_set (s_wifi,
NM_SETTING_WIRELESS_SSID, ssid,
NM_SETTING_WIRELESS_HIDDEN, hidden,
NULL);
g_bytes_unref (ssid);
/* Warn when the provided AP identifier looks like BSSID instead of SSID */
if (bssid1_arr)
g_printerr (_("Warning: '%s' should be SSID for hidden APs; but it looks like a BSSID.\n"),
param_user);
}
} }
} }
@@ -3439,8 +3458,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: "));
@@ -3449,8 +3485,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 ();
s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new (); if (!s_wsec) {
nm_connection_add_setting (connection, NM_SETTING (s_wsec)); s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
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 */
@@ -3466,7 +3504,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
@@ -3484,14 +3522,24 @@ 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;
nm_client_add_and_activate_connection_async (nmc->client, if (existing_con) {
connection, nm_client_activate_connection_async (nmc->client,
device, connection,
nm_object_get_path (NM_OBJECT (ap)), device,
NULL, nm_object_get_path (NM_OBJECT (ap)),
add_and_activate_cb, NULL,
info); add_and_activate_cb,
info);
} else {
nm_client_add_and_activate_connection_async (nmc->client,
connection,
device,
nm_object_get_path (NM_OBJECT (ap)),
NULL,
add_and_activate_cb,
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>