summaryrefslogtreecommitdiff
path: root/clients
diff options
context:
space:
mode:
authorJiří Klimeš <jklimes@redhat.com>2015-11-10 09:30:39 +0100
committerJiří Klimeš <jklimes@redhat.com>2015-11-10 09:30:39 +0100
commit2b4b78eba1b7ecb5eff7074e08f26b1ec8306e68 (patch)
treed998d823e054a0c71e8a0b1bd17662cb29a96a41 /clients
parentcfa4195e0c972a8ceb2fc9cc5920139ab14b0661 (diff)
parentfe5927ae488742d524b6ae496a0152f6b58c70f6 (diff)
downloadNetworkManager-2b4b78eba1b7ecb5eff7074e08f26b1ec8306e68.tar.gz
merge: add 'nmcli device wifi hotspot' command (bgo #756081)
Synopsis: nmcli device wifi hotspot [ifname <ifname>] [con-name <name>] [ssid <SSID>] [band a|bg] [channel <channel>] [password <password>] [--show-password] https://bugzilla.gnome.org/show_bug.cgi?id=756081
Diffstat (limited to 'clients')
-rw-r--r--clients/cli/common.c23
-rw-r--r--clients/cli/common.h3
-rw-r--r--clients/cli/connections.c30
-rw-r--r--clients/cli/devices.c379
-rw-r--r--clients/cli/nmcli-completion14
5 files changed, 416 insertions, 33 deletions
diff --git a/clients/cli/common.c b/clients/cli/common.c
index b988679ff9..8317764e3a 100644
--- a/clients/cli/common.c
+++ b/clients/cli/common.c
@@ -1011,6 +1011,29 @@ nmc_secrets_requested (NMSecretAgentSimple *agent,
}
}
+char *
+nmc_unique_connection_name (const GPtrArray *connections, const char *try_name)
+{
+ NMConnection *connection;
+ const char *name;
+ char *new_name;
+ unsigned int num = 1;
+ int i = 0;
+
+ new_name = g_strdup (try_name);
+ while (i < connections->len) {
+ connection = NM_CONNECTION (connections->pdata[i]);
+
+ name = nm_connection_get_id (connection);
+ if (g_strcmp0 (new_name, name) == 0) {
+ g_free (new_name);
+ new_name = g_strdup_printf ("%s-%d", try_name, num++);
+ i = 0;
+ } else
+ i++;
+ }
+ return new_name;
+}
/**
* nmc_cleanup_readline:
diff --git a/clients/cli/common.h b/clients/cli/common.h
index bb3f44e851..c7acb653da 100644
--- a/clients/cli/common.h
+++ b/clients/cli/common.h
@@ -57,6 +57,9 @@ void nmc_secrets_requested (NMSecretAgentSimple *agent,
GPtrArray *secrets,
gpointer user_data);
+char *nmc_unique_connection_name (const GPtrArray *connections,
+ const char *try_name);
+
void nmc_cleanup_readline (void);
char *nmc_readline (const char *prompt_fmt, ...) G_GNUC_PRINTF (1, 2);
char *nmc_rl_gen_func_basic (const char *text, int state, const char **words);
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index 94d0ff73c2..cb95694b07 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -5810,30 +5810,6 @@ cleanup_bridge_slave:
return TRUE;
}
-static char *
-unique_connection_name (const GPtrArray *connections, const char *try_name)
-{
- NMConnection *connection;
- const char *name;
- char *new_name;
- unsigned int num = 1;
- int i = 0;
-
- new_name = g_strdup (try_name);
- while (i < connections->len) {
- connection = NM_CONNECTION (connections->pdata[i]);
-
- name = nm_connection_get_id (connection);
- if (g_strcmp0 (new_name, name) == 0) {
- g_free (new_name);
- new_name = g_strdup_printf ("%s-%d", try_name, num++);
- i = 0;
- } else
- i++;
- }
- return new_name;
-}
-
typedef struct {
NmCli *nmc;
char *con_name;
@@ -6180,7 +6156,7 @@ do_connection_add (NmCli *nmc, int argc, char **argv)
char *try_name = ifname ?
g_strdup_printf ("%s-%s", get_name_alias (setting_name, nmc_valid_connection_types), ifname)
: g_strdup (get_name_alias (setting_name, nmc_valid_connection_types));
- default_name = unique_connection_name (nmc->connections, try_name);
+ default_name = nmc_unique_connection_name (nmc->connections, try_name);
g_free (try_name);
}
@@ -9015,8 +8991,8 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
if (con_name)
default_name = g_strdup (con_name);
else
- default_name = unique_connection_name (nmc->connections,
- get_name_alias (connection_type, nmc_valid_connection_types));
+ default_name = nmc_unique_connection_name (nmc->connections,
+ get_name_alias (connection_type, nmc_valid_connection_types));
g_object_set (s_con,
NM_SETTING_CONNECTION_ID, default_name,
diff --git a/clients/cli/devices.c b/clients/cli/devices.c
index 5dce08c220..0c38419234 100644
--- a/clients/cli/devices.c
+++ b/clients/cli/devices.c
@@ -267,6 +267,8 @@ usage (void)
" wifi [list [ifname <ifname>] [bssid <BSSID>]]\n\n"
" wifi connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [ifname <ifname>]\n"
" [bssid <BSSID>] [name <name>] [private yes|no] [hidden yes|no]\n\n"
+ " wifi hotspot [ifname <ifname>] [con-name <name>] [ssid <SSID>] [band a|bg] [channel <channel>]\n\n"
+ " [password <password>] [--show-password]\n\n"
" wifi rescan [ifname <ifname>] [[ssid <SSID to scan>] ...]\n\n"
));
}
@@ -371,6 +373,21 @@ usage_device_wifi (void)
"only open, WEP and WPA-PSK networks are supported at the moment. It is also\n"
"assumed that IP configuration is obtained via DHCP.\n"
"\n"
+ "ARGUMENTS := wifi hotspot [ifname <ifname>] [con-name <name>] [ssid <SSID>]\n"
+ " [band a|bg] [channel <channel>] [password <password>]\n"
+ " [--show-password]\n"
+ "\n"
+ "Create a Wi-Fi hotspot. Use 'connection down' or 'device disconnect'\n"
+ "to stop the hotspot.\n"
+ "Parameters of the hotspot can be influenced by the optional parameters:\n"
+ "ifname - Wi-Fi device to use\n"
+ "con-name - name of the created hotspot connection profile\n"
+ "ssid - SSID of the hotspot\n"
+ "band - Wi-Fi band to use\n"
+ "channel - Wi-Fi channel to use\n"
+ "password - password to use for the hotspot\n"
+ "--show-password - tell nmcli to print password to stdout\n"
+ "\n"
"ARGUMENTS := rescan [ifname <ifname>] [[ssid <SSID to scan>] ...]\n"
"\n"
"Request that NetworkManager immediately re-scan for available access points.\n"
@@ -1349,6 +1366,7 @@ connected_state_cb (NMDevice *device, NMActiveConnection *active)
typedef struct {
NmCli *nmc;
NMDevice *device;
+ gboolean hotspot;
} AddAndActivateInfo;
static void
@@ -1366,8 +1384,12 @@ add_and_activate_cb (GObject *client,
active = nm_client_add_and_activate_connection_finish (NM_CLIENT (client), result, &error);
if (error) {
- g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: %s"),
- error->message);
+ if (info->hotspot)
+ g_string_printf (nmc->return_text, _("Error: Failed to setup a Wi-Fi hotspot: %s"),
+ error->message);
+ else
+ g_string_printf (nmc->return_text, _("Error: Failed to add/activate new connection: %s"),
+ error->message);
g_error_free (error);
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
quit ();
@@ -1375,7 +1397,10 @@ add_and_activate_cb (GObject *client,
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"));
+ 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 ();
@@ -1386,8 +1411,12 @@ add_and_activate_cb (GObject *client,
if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
if (nmc->print_output == NMC_PRINT_PRETTY)
nmc_terminal_erase_line ();
- g_print (_("Connection with UUID '%s' created and activated on device '%s'\n"),
- nm_active_connection_get_uuid (active), nm_device_get_iface (device));
+ 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);
quit ();
@@ -1566,6 +1595,7 @@ do_device_connect (NmCli *nmc, int argc, char **argv)
info = g_malloc0 (sizeof (AddAndActivateInfo));
info->nmc = nmc;
info->device = device;
+ info->hotspot = FALSE;
nm_client_activate_connection_async (nmc->client,
NULL, /* let NM find a connection automatically */
@@ -2659,6 +2689,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
info = g_malloc0 (sizeof (AddAndActivateInfo));
info->nmc = nmc;
info->device = device;
+ info->hotspot = FALSE;
nm_client_add_and_activate_connection_async (nmc->client,
connection,
@@ -2679,6 +2710,342 @@ error:
return nmc->return_value;
}
+static GBytes *
+generate_ssid_for_hotspot (const char *ssid)
+{
+ GBytes *ssid_bytes;
+ char *hotspot_ssid = NULL;
+
+ if (!ssid) {
+ hotspot_ssid = g_strdup_printf ("Hotspot-%s", g_get_host_name ());
+ if (strlen (hotspot_ssid) > 32)
+ hotspot_ssid[32] = '\0';
+ ssid = hotspot_ssid;
+ }
+ ssid_bytes = g_bytes_new (ssid, strlen (ssid));
+ g_free (hotspot_ssid);
+ return ssid_bytes;
+}
+
+#define WPA_PASSKEY_SIZE 8
+static void
+generate_wpa_key (char *key, size_t len)
+{
+ guint i;
+
+ g_return_if_fail (key);
+ g_return_if_fail (len > WPA_PASSKEY_SIZE);
+
+ /* generate a 8-chars ASCII WPA key */
+ for (i = 0; i < WPA_PASSKEY_SIZE; i++) {
+ int c;
+ c = g_random_int_range (33, 126);
+ /* too many non alphanumeric characters are hard to remember for humans */
+ while (!g_ascii_isalnum (c))
+ c = g_random_int_range (33, 126);
+
+ key[i] = (gchar) c;
+ }
+ key[WPA_PASSKEY_SIZE] = '\0';
+}
+
+static void
+generate_wep_key (char *key, size_t len)
+{
+ int i;
+ const char *hexdigits = "0123456789abcdef";
+
+ g_return_if_fail (key);
+ g_return_if_fail (len > 10);
+
+ /* generate a 10-digit hex WEP key */
+ for (i = 0; i < 10; i++) {
+ int digit;
+ digit = g_random_int_range (0, 16);
+ key[i] = hexdigits[digit];
+ }
+ key[10] = '\0';
+}
+
+static gboolean
+set_wireless_security_for_hotspot (NMSettingWirelessSecurity *s_wsec,
+ const char *wifi_mode,
+ NMDeviceWifiCapabilities caps,
+ const char *password,
+ gboolean show_password,
+ GError **error)
+{
+ char generated_key[11];
+ const char *key;
+ const char *key_mgmt;
+
+ if (g_strcmp0 (wifi_mode, NM_SETTING_WIRELESS_MODE_AP) == 0) {
+ if (caps & NM_WIFI_DEVICE_CAP_RSN) {
+ nm_setting_wireless_security_add_proto (s_wsec, "rsn");
+ nm_setting_wireless_security_add_pairwise (s_wsec, "ccmp");
+ nm_setting_wireless_security_add_group (s_wsec, "ccmp");
+ key_mgmt = "wpa-psk";
+ } else if (caps & NM_WIFI_DEVICE_CAP_WPA) {
+ nm_setting_wireless_security_add_proto (s_wsec, "wpa");
+ nm_setting_wireless_security_add_pairwise (s_wsec, "tkip");
+ nm_setting_wireless_security_add_group (s_wsec, "tkip");
+ key_mgmt = "wpa-psk";
+ } else
+ key_mgmt = "none";
+ } else
+ key_mgmt = "none";
+
+ if (g_strcmp0 (key_mgmt, "wpa-psk") == 0) {
+ /* use WPA */
+ if (password) {
+ if (!nm_utils_wpa_psk_valid (password)) {
+ g_set_error (error, NMCLI_ERROR, 0, _("'%s' is not valid WPA PSK"), password);
+ return FALSE;
+ }
+ key = password;
+ } else {
+ generate_wpa_key (generated_key, sizeof (generated_key));
+ key = generated_key;
+ }
+ g_object_set (s_wsec,
+ NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, key_mgmt,
+ NM_SETTING_WIRELESS_SECURITY_PSK, key,
+ NULL);
+ } else {
+ /* use WEP */
+ if (password) {
+ if (!nm_utils_wep_key_valid (password, NM_WEP_KEY_TYPE_KEY)) {
+ g_set_error (error, NMCLI_ERROR, 0,
+ _("'%s' is not valid WEP key (it should be 5 or 13 ASCII chars)"),
+ password);
+ return FALSE;
+ }
+ key = password;
+ } else {
+ generate_wep_key (generated_key, sizeof (generated_key));
+ key = generated_key;
+ }
+ g_object_set (s_wsec,
+ NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, key_mgmt,
+ NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, key,
+ NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_KEY,
+ NULL);
+ }
+ if (show_password)
+ g_print (_("Hotspot password: %s\n"), key);
+
+ return TRUE;
+}
+
+static NMCResultCode
+do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
+{
+ AddAndActivateInfo *info;
+ const char *ifname = NULL;
+ const char *con_name = NULL;
+ char *default_name = NULL;
+ const char *ssid = NULL;
+ const char *wifi_mode;
+ const char *band = NULL;
+ const char *channel = NULL;
+ unsigned long channel_int;
+ const char *password = NULL;
+ gboolean show_password = FALSE;
+ NMDevice *device = NULL;
+ int devices_idx;
+ const GPtrArray *devices;
+ NMDeviceWifiCapabilities caps;
+ NMConnection *connection = NULL;
+ NMSettingConnection *s_con;
+ NMSettingWireless *s_wifi;
+ NMSettingWirelessSecurity *s_wsec;
+ NMSettingIPConfig *s_ip4, *s_ip6;
+ GBytes *ssid_bytes;
+ GError *error = NULL;
+
+ /* Set default timeout waiting for operation completion. */
+ if (nmc->timeout == -1)
+ nmc->timeout = 60;
+
+ while (argc > 0) {
+ if (strcmp (*argv, "ifname") == 0) {
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
+ nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ goto error;
+ }
+ ifname = *argv;
+ } else if (strcmp (*argv, "con-name") == 0) {
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
+ nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ goto error;
+ }
+ con_name = *argv;
+ } else if (strcmp (*argv, "ssid") == 0) {
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
+ nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ goto error;
+ }
+ ssid = *argv;
+ if (strlen (ssid) > 32) {
+ g_string_printf (nmc->return_text, _("Error: ssid is too long."));
+ nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ goto error;
+ }
+ } else if (strcmp (*argv, "band") == 0) {
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
+ nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ goto error;
+ }
+ band = *argv;
+ if (strcmp (band, "a") && strcmp (band, "bg")) {
+ g_string_printf (nmc->return_text, _("Error: band argument value '%s' is invalid; use 'a' or 'bg'."),
+ band);
+ nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ goto error;
+ }
+ } else if (strcmp (*argv, "channel") == 0) {
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
+ nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ goto error;
+ }
+ channel = *argv;
+ } else if (strcmp (*argv, "password") == 0) {
+ if (next_arg (&argc, &argv) != 0) {
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
+ nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ goto error;
+ }
+ password = *argv;
+ } else if (nmc_arg_is_option (*argv, "show-password")) {
+ show_password = TRUE;
+ } else {
+ g_string_printf (nmc->return_text, _("Error: Unknown parameter %s."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ goto error;
+ }
+
+ argc--;
+ argv++;
+ }
+
+ /* Verify band and channel parameters */
+ if (!channel) {
+ if (g_strcmp0 (band, "bg") == 0)
+ channel = "1";
+ if (g_strcmp0 (band, "a") == 0)
+ channel = "7";
+ }
+ if (channel) {
+ if (!band) {
+ g_string_printf (nmc->return_text, _("Error: channel requires band too."));
+ nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ goto error;
+ }
+ if ( !nmc_string_to_uint (channel, TRUE, 1, 5825, &channel_int)
+ || !nm_utils_wifi_is_channel_valid (channel_int, band)) {
+ g_string_printf (nmc->return_text, _("Error: channel '%s' not valid for band '%s'."),
+ channel, band);
+ nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ goto error;
+ }
+ }
+
+ /* Find Wi-Fi device. When no ifname is provided, the first Wi-Fi is used. */
+ devices = nm_client_get_devices (nmc->client);
+ devices_idx = 0;
+ device = find_wifi_device_by_iface (devices, ifname, &devices_idx);
+
+ if (!device) {
+ if (ifname)
+ g_string_printf (nmc->return_text, _("Error: Device '%s' is not a Wi-Fi device."), ifname);
+ else
+ g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found."));
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ /* Check device supported mode */
+ caps = nm_device_wifi_get_capabilities (NM_DEVICE_WIFI (device));
+ if (caps & NM_WIFI_DEVICE_CAP_AP)
+ wifi_mode = NM_SETTING_WIRELESS_MODE_AP;
+ else if (caps & NM_WIFI_DEVICE_CAP_ADHOC)
+ wifi_mode = NM_SETTING_WIRELESS_MODE_ADHOC;
+ else {
+ g_string_printf (nmc->return_text, _("Error: Device '%s' supports neither AP nor Ad-Hoc mode."),
+ nm_device_get_iface (device));
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ goto error;
+ }
+
+ /* Create a connection with appropriate parameters */
+ connection = nm_simple_connection_new ();
+ s_con = (NMSettingConnection *) nm_setting_connection_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_con));
+ if (!con_name)
+ con_name = default_name = nmc_unique_connection_name (nm_client_get_connections (nmc->client), "Hotspot");
+ g_object_set (s_con,
+ NM_SETTING_CONNECTION_ID, con_name,
+ NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
+ NULL);
+ g_free (default_name);
+
+ s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_wifi));
+ ssid_bytes = generate_ssid_for_hotspot (ssid);
+ g_object_set (s_wifi, NM_SETTING_WIRELESS_MODE, wifi_mode,
+ NM_SETTING_WIRELESS_SSID, ssid_bytes,
+ NULL);
+ g_bytes_unref (ssid_bytes);
+ if (channel)
+ g_object_set (s_wifi,
+ NM_SETTING_WIRELESS_CHANNEL, (guint32) channel_int,
+ NM_SETTING_WIRELESS_BAND, band,
+ NULL);
+
+ s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_wsec));
+ if (!set_wireless_security_for_hotspot (s_wsec, wifi_mode, caps, password, show_password, &error)) {
+ g_object_unref (connection);
+ g_string_printf (nmc->return_text, _("Error: Invalid 'password': %s."), error->message);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ g_clear_error (&error);
+ goto error;
+ }
+
+ s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+ g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_SHARED, NULL);
+
+ s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_ip6));
+ g_object_set (s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL);
+
+ /* Activate the connection now */
+ nmc->nowait_flag = (nmc->timeout == 0);
+ nmc->should_wait = TRUE;
+
+ info = g_malloc0 (sizeof (AddAndActivateInfo));
+ info->nmc = nmc;
+ info->device = device;
+ info->hotspot = TRUE;
+
+ nm_client_add_and_activate_connection_async (nmc->client,
+ connection,
+ device,
+ NULL,
+ NULL,
+ add_and_activate_cb,
+ info);
+
+error:
+ return nmc->return_value;
+}
+
static void
request_rescan_cb (GObject *object, GAsyncResult *result, gpointer user_data)
{
@@ -2791,6 +3158,8 @@ do_device_wifi (NmCli *nmc, int argc, char **argv)
nmc->return_value = do_device_wifi_list (nmc, argc-1, argv+1);
} else if (matches (*argv, "connect") == 0) {
nmc->return_value = do_device_wifi_connect_network (nmc, argc-1, argv+1);
+ } else if (matches (*argv, "hotspot") == 0) {
+ nmc->return_value = do_device_wifi_hotspot (nmc, argc-1, argv+1);
} else if (matches (*argv, "rescan") == 0) {
nmc->return_value = do_device_wifi_rescan (nmc, argc-1, argv+1);
} else {
diff --git a/clients/cli/nmcli-completion b/clients/cli/nmcli-completion
index 6d9b6ae1cb..02364c65cd 100644
--- a/clients/cli/nmcli-completion
+++ b/clients/cli/nmcli-completion
@@ -512,6 +512,7 @@ _nmcli_compl_ARGS()
save| \
hidden| \
private)
+ show-password)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "yes no"
return 0
@@ -589,6 +590,12 @@ _nmcli_compl_ARGS()
return 0
fi
;;
+ band)
+ if [[ "${#words[@]}" -eq 2 ]]; then
+ _nmcli_list "a bg"
+ return 0
+ fi
+ ;;
*)
return 1
;;
@@ -1317,7 +1324,7 @@ _nmcli()
;;
w|wi|wif|wifi)
if [[ ${#words[@]} -eq 3 ]]; then
- _nmcli_compl_COMMAND "${words[2]}" list connect rescan
+ _nmcli_compl_COMMAND "${words[2]}" list connect hotspot rescan
else
case "${words[2]}" in
l|li|lis|list)
@@ -1338,6 +1345,11 @@ _nmcli()
_nmcli_compl_ARGS
fi
;;
+ h|ho|hot|hots|hotsp|hotspo|hotspot)
+ _nmcli_array_delete_at words 0 2
+ OPTIONS=(ifname con-name ssid band channel password show-password)
+ _nmcli_compl_ARGS
+ ;;
r|re|res|resc|resca|rescan)
_nmcli_array_delete_at words 0 2
OPTIONS_REPEATABLE=(ssid)