summary refs log tree commit diff
path: root/clients
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2020-04-11 21:28:04 +0200
committerMichael Biebl <biebl@debian.org>2020-04-11 21:28:04 +0200
commit1e5977b62f896e844b548c3007ace9e1dfa7f9ed (patch)
tree7a7416ed410e72b6200f3d860fd315ec11cc106b /clients
parentb012fa6e1d808e0736c009799c62d835cbfcc1dd (diff)
New upstream version 1.23.90 upstream/1.23.90
Diffstat (limited to 'clients')
-rw-r--r--clients/cli/agent.c96
-rw-r--r--clients/cli/agent.h13
-rw-r--r--clients/cli/common.c77
-rw-r--r--clients/cli/common.h10
-rw-r--r--clients/cli/connections.c508
-rw-r--r--clients/cli/connections.h13
-rw-r--r--clients/cli/devices.c784
-rw-r--r--clients/cli/devices.h2
-rw-r--r--clients/cli/general.c532
-rw-r--r--clients/cli/general.h17
-rw-r--r--clients/cli/meson.build33
-rw-r--r--clients/cli/nmcli.c120
-rw-r--r--clients/cli/nmcli.h35
-rw-r--r--clients/cli/polkit-agent.c97
-rw-r--r--clients/cli/settings.c6
-rw-r--r--clients/cli/utils.c77
-rw-r--r--clients/cli/utils.h8
-rw-r--r--clients/cloud-setup/main.c86
-rw-r--r--clients/cloud-setup/meson.build15
-rw-r--r--clients/cloud-setup/nm-cloud-setup-utils.c12
-rw-r--r--clients/cloud-setup/nm-http-client.c13
-rw-r--r--clients/cloud-setup/nmcs-provider-ec2.c8
-rw-r--r--clients/common/meson.build5
-rw-r--r--clients/common/nm-client-utils.c1
-rw-r--r--clients/common/nm-meta-setting-desc.c229
-rw-r--r--clients/common/nm-polkit-listener.c1090
-rw-r--r--clients/common/nm-polkit-listener.h121
-rw-r--r--clients/common/nm-secret-agent-simple.c2
-rw-r--r--clients/common/nm-vpn-helpers.c28
-rw-r--r--clients/common/settings-docs.h21
-rw-r--r--clients/common/settings-docs.h.in21
-rw-r--r--clients/common/tests/meson.build2
-rw-r--r--clients/common/tests/test-clients-common.c13
-rw-r--r--clients/common/tests/wg-test0.conf2
-rw-r--r--clients/meson.build13
-rw-r--r--clients/nm-online.c22
-rw-r--r--clients/tests/test-client.check-on-disk/test_001.expected1016
-rwxr-xr-xclients/tests/test-client.py49
-rw-r--r--clients/tui/meson.build3
-rw-r--r--clients/tui/newt/meson.build2
-rw-r--r--clients/tui/newt/nmt-newt-form.c24
-rw-r--r--clients/tui/newt/nmt-newt-grid.c8
-rw-r--r--clients/tui/nm-editor-bindings.c15
-rw-r--r--clients/tui/nm-editor-utils.c19
-rw-r--r--clients/tui/nmt-connect-connection-list.c2
-rw-r--r--clients/tui/nmt-device-entry.c2
-rw-r--r--clients/tui/nmt-editor-grid.c2
-rw-r--r--clients/tui/nmt-page-team-port.c2
-rw-r--r--clients/tui/nmt-page-team.c2
-rw-r--r--clients/tui/nmt-page-wifi.c1
-rw-r--r--clients/tui/nmt-password-dialog.c4
-rw-r--r--clients/tui/nmt-route-entry.c2
-rw-r--r--clients/tui/nmtui.c9
53 files changed, 3072 insertions, 2222 deletions
diff --git a/clients/cli/agent.c b/clients/cli/agent.c
index f4057df9..f3707db7 100644
--- a/clients/cli/agent.c
+++ b/clients/cli/agent.c
@@ -5,8 +5,6 @@
 
 #include "nm-default.h"
 
-#include "agent.h"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <readline/readline.h>
@@ -16,6 +14,7 @@
 #include "utils.h"
 #include "nm-secret-agent-simple.h"
 #include "polkit-agent.h"
+#include "nm-polkit-listener.h"
 
 static void
 usage (void)
@@ -122,12 +121,12 @@ secrets_requested (NMSecretAgentSimple *agent,
 	                                 success ? secrets : NULL);
 }
 
-static NMCResultCode
-do_agent_secret (NmCli *nmc, int argc, char **argv)
+static void
+do_agent_secret (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	next_arg (nmc, &argc, &argv, NULL);
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	/* Create secret agent */
 	nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-agent");
@@ -145,76 +144,93 @@ do_agent_secret (NmCli *nmc, int argc, char **argv)
 		g_string_printf (nmc->return_text, _("Error: secret agent initialization failed"));
 		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 	}
+}
 
-	return nmc->return_value;
+static void
+polkit_registered (gpointer instance,
+                   gpointer user_data)
+{
+	g_print (_("nmcli successfully registered as a polkit agent.\n"));
+}
+
+static void
+polkit_error (gpointer instance,
+              const char *error,
+              gpointer user_data)
+{
+	g_main_loop_quit (loop);
 }
 
-static NMCResultCode
-do_agent_polkit (NmCli *nmc, int argc, char **argv)
+static void
+do_agent_polkit (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
-	GError *error = NULL;
+	gs_free_error GError *error = NULL;
 
 	next_arg (nmc, &argc, &argv, NULL);
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
-	/* Initialize polkit agent */
 	if (!nmc_polkit_agent_init (nmc, TRUE, &error)) {
 		g_dbus_error_strip_remote_error (error);
-		g_string_printf (nmc->return_text, _("Error: polkit agent initialization failed: %s"),
+		g_string_printf (nmc->return_text,
+		                 _("Error: polkit agent initialization failed: %s"),
 		                 error->message);
 		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-		g_error_free (error);
 	} else {
 		/* We keep running */
 		nmc->should_wait++;
-
-		g_print (_("nmcli successfully registered as a polkit agent.\n"));
+		g_signal_connect (nmc->pk_listener,
+		                  NM_POLKIT_LISTENER_SIGNAL_ERROR,
+		                  G_CALLBACK (polkit_error),
+		                  NULL);
+		g_signal_connect (nmc->pk_listener,
+		                  NM_POLKIT_LISTENER_SIGNAL_REGISTERED,
+		                  G_CALLBACK (polkit_registered),
+		                  NULL);
+
+		/* keep running */
+		nmc->should_wait++;
 	}
-
-	return nmc->return_value;
 }
 
-static NMCResultCode
-do_agent_all (NmCli *nmc, int argc, char **argv)
+static void
+do_agent_all (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
-	NMCResultCode secret_res;
+	NMCResultCode r;
 
 	next_arg (nmc, &argc, &argv, NULL);
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	/* Run both secret and polkit agent */
-	secret_res = do_agent_secret (nmc, argc, argv);
-	if (secret_res != NMC_RESULT_SUCCESS) {
+	do_agent_secret (cmd, nmc, argc, argv);
+	r = nmc->return_value;
+	if (r != NMC_RESULT_SUCCESS) {
 		g_printerr ("%s\n", nmc->return_text->str);
 		g_string_truncate (nmc->return_text, 0);
+		nmc->return_value = NMC_RESULT_SUCCESS;
 	}
 
-	nmc->return_value = do_agent_polkit (nmc, argc, argv);
+	do_agent_polkit (cmd, nmc, argc, argv);
 	if (nmc->return_value != NMC_RESULT_SUCCESS) {
 		g_printerr ("%s\n", nmc->return_text->str);
 		g_string_truncate (nmc->return_text, 0);
 	}
 
-	if (nmc->return_value == NMC_RESULT_SUCCESS && secret_res != NMC_RESULT_SUCCESS)
-		nmc->return_value = secret_res;
-
-	return nmc->return_value;
+	if (r != NMC_RESULT_SUCCESS)
+		nmc->return_value = r;
 }
 
-static const NMCCommand agent_cmds[] = {
-	{ "secret",  do_agent_secret,  usage_agent_secret,  TRUE,   TRUE },
-	{ "polkit",  do_agent_polkit,  usage_agent_polkit,  TRUE,   TRUE },
-	{ "all",     do_agent_all,     usage_agent_all,     TRUE,   TRUE },
-	{ NULL,      do_agent_all,     usage,               TRUE,   TRUE },
-};
-
-NMCResultCode
-do_agent (NmCli *nmc, int argc, char **argv)
+void
+nmc_command_func_agent (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
-	next_arg (nmc, &argc, &argv, NULL);
-	nmc_do_cmd (nmc, agent_cmds, *argv, argc, argv);
+	static const NMCCommand cmds[] = {
+		{ "secret", do_agent_secret, usage_agent_secret, TRUE, TRUE },
+		{ "polkit", do_agent_polkit, usage_agent_polkit, TRUE, TRUE },
+		{ "all",    do_agent_all,    usage_agent_all,    TRUE, TRUE },
+		{ NULL,     do_agent_all,    usage,              TRUE, TRUE },
+	};
 
-	return nmc->return_value;
+	next_arg (nmc, &argc, &argv, NULL);
+	nmc_do_cmd (nmc, cmds, *argv, argc, argv);
 }
diff --git a/clients/cli/agent.h b/clients/cli/agent.h
deleted file mode 100644
index aad56bba..00000000
--- a/clients/cli/agent.h
+++ /dev/null
@@ -1,13 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2014 Red Hat, Inc.
- */
-
-#ifndef __NMC_AGENT_H__
-#define __NMC_AGENT_H__
-
-#include "nmcli.h"
-
-NMCResultCode do_agent (NmCli *nmc, int argc, char **argv);
-
-#endif /* __NMC_AGENT_H__ */
diff --git a/clients/cli/common.c b/clients/cli/common.c
index 04ccf8dc..93defe65 100644
--- a/clients/cli/common.c
+++ b/clients/cli/common.c
@@ -13,8 +13,11 @@
 #include <readline/readline.h>
 #include <readline/history.h>
 
+#include "nm-libnm-aux/nm-libnm-aux.h"
+
 #include "nm-vpn-helpers.h"
 #include "nm-client-utils.h"
+#include "nm-glib-aux/nm-secret-utils.h"
 
 #include "utils.h"
 
@@ -730,7 +733,7 @@ get_secrets_from_user (const NmcConfig *nmc_config,
 		/* No password provided, cancel the secrets. */
 		if (!pwd)
 			return FALSE;
-		g_free (secret->value);
+		nm_free_secret (secret->value);
 		secret->value = pwd;
 	}
 	return TRUE;
@@ -861,7 +864,9 @@ readline_cb (char *line)
 }
 
 static gboolean
-stdin_ready_cb (GIOChannel * io, GIOCondition condition, gpointer data)
+stdin_ready_cb (int fd,
+                GIOCondition condition,
+                gpointer data)
 {
 	rl_callback_read_char ();
 	return TRUE;
@@ -871,14 +876,17 @@ static char *
 nmc_readline_helper (const NmcConfig *nmc_config,
                      const char *prompt)
 {
-	GIOChannel *io = NULL;
-	guint io_watch_id;
+	GSource *io_source;
 
 	nmc_set_in_readline (TRUE);
 
-	io = g_io_channel_unix_new (STDIN_FILENO);
-	io_watch_id = g_io_add_watch (io, G_IO_IN, stdin_ready_cb, NULL);
-	g_io_channel_unref (io);
+	io_source = nm_g_unix_fd_source_new (STDIN_FILENO,
+	                                     G_IO_IN,
+	                                     G_PRIORITY_DEFAULT,
+	                                     stdin_ready_cb,
+	                                     NULL,
+	                                     NULL);
+	g_source_attach (io_source, NULL);
 
 read_again:
 	rl_string = NULL;
@@ -927,7 +935,8 @@ read_again:
 		rl_string = NULL;
 	}
 
-	g_source_remove (io_watch_id);
+	nm_clear_g_source_inst (&io_source);
+
 	nmc_set_in_readline (FALSE);
 
 	return rl_string;
@@ -1003,7 +1012,7 @@ nmc_readline_echo (const NmcConfig *nmc_config,
 	va_list args;
 	gs_free char *prompt = NULL;
 	char *str;
-	HISTORY_STATE *saved_history;
+	nm_auto_free HISTORY_STATE *saved_history = NULL;
 	HISTORY_STATE passwd_history = { 0, };
 
 	va_start (args, prompt_fmt);
@@ -1016,6 +1025,10 @@ nmc_readline_echo (const NmcConfig *nmc_config,
 	if (!echo_on) {
 		saved_history = history_get_history_state ();
 		history_set_history_state (&passwd_history);
+		/* stifling history is important as it tells readline to
+		 * not store anything, otherwise sensitive data could be
+		 * leaked */
+		stifle_history (0);
 		rl_redisplay_function = nmc_secret_redisplay;
 	}
 
@@ -1105,7 +1118,7 @@ nmc_rl_gen_func_ifnames (const char *text, int state)
 	const char **ifnames;
 	char *ret;
 
-	devices = nm_client_get_devices (nm_cli.client);
+	devices = nm_client_get_devices (nm_cli_global_readline->client);
 	if (devices->len == 0)
 		return NULL;
 
@@ -1206,7 +1219,7 @@ typedef struct {
 } CmdCall;
 
 static void
-call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, char **argv);
+call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, const char *const*argv);
 
 static void
 got_client (GObject *source_object, GAsyncResult *res, gpointer user_data)
@@ -1216,25 +1229,31 @@ got_client (GObject *source_object, GAsyncResult *res, gpointer user_data)
 	CmdCall *call = user_data;
 	NmCli *nmc;
 
+	nm_assert (NM_IS_CLIENT (source_object));
+
 	task = g_steal_pointer (&call->task);
 	nmc = g_task_get_task_data (task);
 
 	nmc->should_wait--;
-	nmc->client = nm_client_new_finish (res, &error);
 
-	if (!nmc->client) {
+	if (!g_async_initable_init_finish (G_ASYNC_INITABLE (source_object),
+	                                   res,
+	                                   &error)) {
+		g_object_unref (source_object);
 		g_task_return_new_error (task, NMCLI_ERROR, NMC_RESULT_ERROR_UNKNOWN,
 		                         _("Error: Could not create NMClient object: %s."),
 		                         error->message);
 	} else {
-		call_cmd (nmc, g_steal_pointer (&task), call->cmd, call->argc, call->argv);
+		nmc->client = NM_CLIENT (source_object);
+		call_cmd (nmc, g_steal_pointer (&task), call->cmd, call->argc, (const char *const*) call->argv);
 	}
 
-	g_slice_free (CmdCall, call);
+	g_strfreev (call->argv);
+	nm_g_slice_free (call);
 }
 
 static void
-call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, char **argv)
+call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, const char *const*argv)
 {
 	CmdCall *call;
 
@@ -1245,7 +1264,7 @@ call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, char **argv)
 			g_task_return_new_error (task, NMCLI_ERROR, NMC_RESULT_ERROR_NM_NOT_RUNNING,
 			                         _("Error: NetworkManager is not running."));
 		} else {
-			nmc->return_value = cmd->func (nmc, argc, argv);
+			cmd->func (cmd, nmc, argc, argv);
 			g_task_return_boolean (task, TRUE);
 		}
 
@@ -1254,12 +1273,18 @@ call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, char **argv)
 		nm_assert (nmc->client == NULL);
 
 		nmc->should_wait++;
-		call = g_slice_new0 (CmdCall);
-		call->cmd = cmd;
-		call->argc = argc;
-		call->argv = argv;
-		call->task = task;
-		nm_client_new_async (NULL, got_client, call);
+		call = g_slice_new (CmdCall);
+		*call = (CmdCall) {
+			.cmd  = cmd,
+			.argc = argc,
+			.argv = nm_utils_strv_dup ((char **) argv, argc, TRUE),
+			.task = task,
+		};
+		nmc_client_new_async (NULL,
+		                      got_client,
+		                      call,
+		                      NM_CLIENT_INSTANCE_FLAGS, (guint) NM_CLIENT_INSTANCE_FLAGS_NO_AUTO_FETCH_PERMISSIONS,
+		                      NULL);
 	}
 }
 
@@ -1291,7 +1316,7 @@ nmc_complete_help (const char *prefix)
  * no callback to free the memory in (for simplicity).
  */
 void
-nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char **argv)
+nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, const char *const*argv)
 {
 	const NMCCommand *c;
 	gs_unref_object GTask *task = NULL;
@@ -1327,7 +1352,7 @@ nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char
 			c->usage ();
 			g_task_return_boolean (task, TRUE);
 		} else {
-			call_cmd (nmc, g_steal_pointer (&task), c, argc, argv);
+			call_cmd (nmc, g_steal_pointer (&task), c, argc, (const char *const*) argv);
 		}
 	} else if (cmd) {
 		/* Not a known command. */
@@ -1340,7 +1365,7 @@ nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char
 		}
 	} else if (c->func) {
 		/* No command, run the default handler. */
-		call_cmd (nmc, g_steal_pointer (&task), c, argc, argv);
+		call_cmd (nmc, g_steal_pointer (&task), c, argc, (const char *const*) argv);
 	} else {
 		/* No command and no default handler. */
 		g_task_return_new_error (task, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
diff --git a/clients/cli/common.h b/clients/cli/common.h
index f8fad8c6..243a2098 100644
--- a/clients/cli/common.h
+++ b/clients/cli/common.h
@@ -62,15 +62,7 @@ int nmc_rl_set_deftext (void);
 
 char *nmc_parse_lldp_capabilities (guint value);
 
-typedef struct {
-	const char *cmd;
-	NMCResultCode (*func) (NmCli *nmc, int argc, char **argv);
-	void (*usage) (void);
-	gboolean needs_client;
-	gboolean needs_nm_running;
-} NMCCommand;
-
-void nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char **argv);
+void nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, const char *const*argv);
 
 void nmc_complete_strv (const char *prefix, gssize nargs, const char *const*args);
 
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index e13ae9ac..0e4a95e6 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -62,7 +62,8 @@ typedef struct _OptionInfo {
 
 /*****************************************************************************/
 
-NM_UTILS_LOOKUP_STR_DEFINE_STATIC (active_connection_state_to_string, NMActiveConnectionState,
+static
+NM_UTILS_LOOKUP_STR_DEFINE (active_connection_state_to_string, NMActiveConnectionState,
 	NM_UTILS_LOOKUP_DEFAULT (N_("unknown")),
 	NM_UTILS_LOOKUP_ITEM (NM_ACTIVE_CONNECTION_STATE_ACTIVATING,   N_("activating")),
 	NM_UTILS_LOOKUP_ITEM (NM_ACTIVE_CONNECTION_STATE_ACTIVATED,    N_("activated")),
@@ -71,7 +72,8 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (active_connection_state_to_string, NMActiveCo
 	NM_UTILS_LOOKUP_ITEM_IGNORE (NM_ACTIVE_CONNECTION_STATE_UNKNOWN),
 )
 
-NM_UTILS_LOOKUP_STR_DEFINE_STATIC (vpn_connection_state_to_string, NMVpnConnectionState,
+static
+NM_UTILS_LOOKUP_STR_DEFINE (vpn_connection_state_to_string, NMVpnConnectionState,
 	NM_UTILS_LOOKUP_DEFAULT (N_("unknown")),
 	NM_UTILS_LOOKUP_ITEM (NM_VPN_CONNECTION_STATE_PREPARE,       N_("VPN connecting (prepare)")),
 	NM_UTILS_LOOKUP_ITEM (NM_VPN_CONNECTION_STATE_NEED_AUTH,     N_("VPN connecting (need authentication)")),
@@ -421,7 +423,7 @@ _metagen_con_show_row_data_init_primary_active (MetagenConShowRowData *row_data)
 		g_object_unref (row_data->primary_active);
 		row_data->primary_active = g_object_ref (best_ac);
 	}
-	g_clear_pointer (&row_data->all_active, g_ptr_array_unref);
+	nm_clear_pointer (&row_data->all_active, g_ptr_array_unref);
 }
 
 static void
@@ -434,7 +436,7 @@ _metagen_con_show_row_data_destroy (gpointer data)
 
 	g_clear_object (&row_data->connection);
 	g_clear_object (&row_data->primary_active);
-	g_clear_pointer (&row_data->all_active, g_ptr_array_unref);
+	nm_clear_pointer (&row_data->all_active, g_ptr_array_unref);
 	g_slice_free (MetagenConShowRowData, row_data);
 }
 
@@ -855,6 +857,7 @@ const NmcMetaGenericInfo *const metagen_con_active_vpn[_NMC_GENERIC_INFO_TYPE_CO
                                          NM_SETTING_MACSEC_SETTING_NAME"," \
                                          NM_SETTING_MACVLAN_SETTING_NAME"," \
                                          NM_SETTING_VXLAN_SETTING_NAME"," \
+                                         NM_SETTING_VRF_SETTING_NAME"," \
                                          NM_SETTING_WPAN_SETTING_NAME","\
                                          NM_SETTING_6LOWPAN_SETTING_NAME","\
                                          NM_SETTING_WIREGUARD_SETTING_NAME","\
@@ -1111,6 +1114,10 @@ usage_connection_modify (void)
 	              "The '+' sign allows appending items instead of overwriting the whole value.\n"
 	              "The '-' sign allows removing selected items instead of the whole value.\n"
 	              "\n"
+	              "ARGUMENTS := remove <setting>\n"
+	              "\n"
+	              "Remove a setting from the connection profile.\n"
+	              "\n"
 	              "Examples:\n"
 	              "nmcli con mod home-wifi wifi.ssid rakosnicek\n"
 	              "nmcli con mod em1-1 ipv4.method manual ipv4.addr \"192.168.1.2/24, 10.10.1.5/8\"\n"
@@ -1118,7 +1125,8 @@ usage_connection_modify (void)
 	              "nmcli con mod em1-1 -ipv4.dns 1\n"
 	              "nmcli con mod em1-1 -ipv6.addr \"abbe::cafe/56\"\n"
 	              "nmcli con mod bond0 +bond.options mii=500\n"
-	              "nmcli con mod bond0 -bond.options downdelay\n\n"));
+	              "nmcli con mod bond0 -bond.options downdelay\n"
+	              "nmcli con mod em1-1 remove sriov\n\n"));
 }
 
 static void
@@ -1348,9 +1356,9 @@ nmc_connection_profile_details (NMConnection *connection, NmCli *nmc)
 	const char *base_hdr = _("Connection profile details");
 	gboolean was_output = FALSE;
 
-	if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
+	if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0)
 		fields_str = fields_common;
-	else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
+	else if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "all") == 0)
 		fields_str = fields_all;
 	else
 		fields_str = nmc->required_fields;
@@ -1380,9 +1388,13 @@ nmc_connection_profile_details (NMConnection *connection, NmCli *nmc)
 		for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++)
 			row[i].info = (const NMMetaAbstractInfo *) &nm_meta_setting_infos_editor[i];
 
-		print_required_fields (&nmc->nmc_config, NMC_OF_FLAG_MAIN_HEADER_ONLY,
-		                       out_indices, header_name,
-		                       0, row);
+		print_required_fields (&nmc->nmc_config,
+		                       &nmc->pager_data,
+		                       NMC_OF_FLAG_MAIN_HEADER_ONLY,
+		                       out_indices,
+		                       header_name,
+		                       0,
+		                       row);
 	}
 
 	/* Loop through the required settings and print them. */
@@ -1436,8 +1448,8 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc)
 	const char *base_hdr = _("Activate connection details");
 	gboolean was_output = FALSE;
 
-	if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) {
-	} else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) {
+	if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) {
+	} else if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "all") == 0) {
 	} else
 		fields_str = nmc->required_fields;
 
@@ -1465,9 +1477,13 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc)
 		for (i = 0; nmc_fields_con_active_details_groups[i]; i++)
 			row[i].info = (const NMMetaAbstractInfo *) nmc_fields_con_active_details_groups[i];
 
-		print_required_fields (&nmc->nmc_config, NMC_OF_FLAG_MAIN_HEADER_ONLY,
-		                       out_indices, header_name,
-		                       0, row);
+		print_required_fields (&nmc->nmc_config,
+		                       &nmc->pager_data,
+		                       NMC_OF_FLAG_MAIN_HEADER_ONLY,
+		                       out_indices,
+		                       header_name,
+		                       0,
+		                       row);
 	}
 
 	/* Loop through the groups and print them. */
@@ -1500,7 +1516,7 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc)
 		}
 
 		/* IP4 */
-		if (strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name,  nmc_fields_con_active_details_groups[1]->name) == 0) {
+		if (g_ascii_strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name,  nmc_fields_con_active_details_groups[1]->name) == 0) {
 			gboolean b1 = FALSE;
 			NMIPConfig *cfg4 = nm_active_connection_get_ip4_config (acon);
 
@@ -1509,7 +1525,7 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc)
 		}
 
 		/* DHCP4 */
-		if (strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name,  nmc_fields_con_active_details_groups[2]->name) == 0) {
+		if (g_ascii_strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name,  nmc_fields_con_active_details_groups[2]->name) == 0) {
 			gboolean b1 = FALSE;
 			NMDhcpConfig *dhcp4 = nm_active_connection_get_dhcp4_config (acon);
 
@@ -1518,7 +1534,7 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc)
 		}
 
 		/* IP6 */
-		if (strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name,  nmc_fields_con_active_details_groups[3]->name) == 0) {
+		if (g_ascii_strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name,  nmc_fields_con_active_details_groups[3]->name) == 0) {
 			gboolean b1 = FALSE;
 			NMIPConfig *cfg6 = nm_active_connection_get_ip6_config (acon);
 
@@ -1527,7 +1543,7 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc)
 		}
 
 		/* DHCP6 */
-		if (strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name,  nmc_fields_con_active_details_groups[4]->name) == 0) {
+		if (g_ascii_strcasecmp (nmc_fields_con_active_details_groups[group_idx]->name,  nmc_fields_con_active_details_groups[4]->name) == 0) {
 			gboolean b1 = FALSE;
 			NMDhcpConfig *dhcp6 = nm_active_connection_get_dhcp6_config (acon);
 
@@ -1594,13 +1610,13 @@ split_required_fields_for_con_show (const char *input,
 		if (dot)
 			*dot = '\0';
 
-		is_all = !dot && strcasecmp (s_mutable, "all") == 0;
-		is_common = !dot && strcasecmp (s_mutable, "common") == 0;
+		is_all = !dot && g_ascii_strcasecmp (s_mutable, "all") == 0;
+		is_common = !dot && g_ascii_strcasecmp (s_mutable, "common") == 0;
 
 		found = FALSE;
 		for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) {
 			if (   is_all || is_common
-			    || !strcasecmp (s_mutable, nm_meta_setting_infos[i].setting_name)) {
+			    || !g_ascii_strcasecmp (s_mutable, nm_meta_setting_infos[i].setting_name)) {
 				if (dot)
 					*dot = '.';
 				g_string_append (str1, s_mutable);
@@ -1614,7 +1630,7 @@ split_required_fields_for_con_show (const char *input,
 
 		for (i = 0; nmc_fields_con_active_details_groups[i]; i++) {
 			if (   is_all || is_common
-			    || !strcasecmp (s_mutable, nmc_fields_con_active_details_groups[i]->name)) {
+			    || !g_ascii_strcasecmp (s_mutable, nmc_fields_con_active_details_groups[i]->name)) {
 				if (dot)
 					*dot = '.';
 				g_string_append (str2, s_mutable);
@@ -1626,9 +1642,9 @@ split_required_fields_for_con_show (const char *input,
 		if (!found) {
 			if (dot)
 				*dot = '.';
-			if (!strcasecmp (s_mutable, CON_SHOW_DETAIL_GROUP_PROFILE))
+			if (!g_ascii_strcasecmp (s_mutable, CON_SHOW_DETAIL_GROUP_PROFILE))
 				group_profile = TRUE;
-			else if (!strcasecmp (s_mutable, CON_SHOW_DETAIL_GROUP_ACTIVE))
+			else if (!g_ascii_strcasecmp (s_mutable, CON_SHOW_DETAIL_GROUP_ACTIVE))
 				group_active = TRUE;
 			else {
 				gs_free char *allowed1 = nm_meta_abstract_infos_get_names_str ((const NMMetaAbstractInfo *const*) nm_meta_setting_infos_editor_p (), NULL);
@@ -1960,7 +1976,7 @@ parse_preferred_connection_order (const char *order, GError **error)
 static NMConnection *
 get_connection (NmCli *nmc,
                 int *argc,
-                char ***argv,
+                const char *const**argv,
                 const char **out_selector,
                 const char **out_value,
                 GPtrArray **out_result,
@@ -2011,8 +2027,8 @@ get_connection (NmCli *nmc,
 	return connection;
 }
 
-static NMCResultCode
-do_connections_show (NmCli *nmc, int argc, char **argv)
+static void
+do_connections_show (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	gs_free_error GError *err = NULL;
 	gs_free char *profile_flds = NULL;
@@ -2055,9 +2071,9 @@ do_connections_show (NmCli *nmc, int argc, char **argv)
 		if (nmc->complete)
 			goto finish;
 
-		if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
+		if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0)
 			fields_str = NMC_FIELDS_CON_SHOW_COMMON;
-		else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) {
+		else if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "all") == 0) {
 		} else
 			fields_str = nmc->required_fields;
 
@@ -2085,7 +2101,7 @@ do_connections_show (NmCli *nmc, int argc, char **argv)
 			}
 		}
 
-		nm_cli_spawn_pager (nmc);
+		nm_cli_spawn_pager (&nmc->nmc_config, &nmc->pager_data);
 
 		items = con_show_get_items (nmc, active_only, show_active_fields, order);
 		g_ptr_array_add (items, NULL);
@@ -2118,7 +2134,7 @@ do_connections_show (NmCli *nmc, int argc, char **argv)
 		 * option after the connection ids */
 		if (!nmc->nmc_config.show_secrets && !nmc->complete) {
 			int argc_cp = argc;
-			char **argv_cp = argv;
+			const char *const*argv_cp = argv;
 
 			do {
 				if (NM_IN_STRSET (*argv_cp, "id", "uuid", "path", "filename", "apath")) {
@@ -2268,7 +2284,6 @@ finish:
 		g_string_printf (nmc->return_text, _("Error: %s."), err->message);
 		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 	}
-	return nmc->return_value;
 }
 
 static NMActiveConnection *
@@ -2838,8 +2853,8 @@ nmc_activate_connection (NmCli *nmc,
 	return TRUE;
 }
 
-static NMCResultCode
-do_connection_up (NmCli *nmc, int argc, char **argv)
+static void
+do_connection_up (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	NMConnection *connection = NULL;
 	const char *ifname = NULL;
@@ -2847,9 +2862,9 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 	const char *nsp = NULL;
 	const char *pwds = NULL;
 	gs_free_error GError *error = NULL;
-	char **arg_arr = NULL;
+	gs_strfreev char **arg_arr = NULL;
 	int arg_num;
-	char ***argv_ptr;
+	const char *const**argv_ptr;
 	int *argc_ptr;
 
 	/*
@@ -2872,7 +2887,7 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 		line = nmc_readline (&nmc->nmc_config,
 		                     PROMPT_CONNECTION);
 		nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
-		argv_ptr = &arg_arr;
+		argv_ptr = (const char *const**) &arg_arr;
 		argc_ptr = &arg_num;
 	}
 
@@ -2880,7 +2895,8 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 		connection = get_connection (nmc, argc_ptr, argv_ptr, NULL, NULL, NULL, &error);
 		if (!connection) {
 			g_string_printf (nmc->return_text, _("Error: %s."), error->message);
-			return error->code;
+			nmc->return_value = error->code;
+			return;
 		}
 	}
 
@@ -2893,7 +2909,8 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 
 			ifname = *argv;
@@ -2905,7 +2922,8 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 
 			ap = *argv;
@@ -2917,7 +2935,8 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 
 			if (argc == 1 && nmc->complete)
@@ -2927,14 +2946,15 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 		}
 		else if (!nmc->complete) {
 			g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
-			return NMC_RESULT_ERROR_USER_INPUT;
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			return;
 		}
 
 		next_arg (nmc, &argc, &argv, NULL);
 	}
 
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	/* Use nowait_flag instead of should_wait because exiting has to be postponed till
 	 * active_connection_state_cb() is called. That gives NM time to check our permissions
@@ -2947,14 +2967,13 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
 		g_string_printf (nmc->return_text, _("Error: %s."),
 		                 error->message);
 		nmc->should_wait--;
-		return error->code;
+		nmc->return_value = error->code;
+		return;
 	}
 
 	/* Start progress indication */
 	if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY)
 		progress_id = g_timeout_add (120, progress_cb, _("preparing"));
-
-	return nmc->return_value;
 }
 
 /*****************************************************************************/
@@ -3096,14 +3115,14 @@ connection_op_timeout_cb (gpointer user_data)
 	return G_SOURCE_REMOVE;
 }
 
-static NMCResultCode
-do_connection_down (NmCli *nmc, int argc, char **argv)
+static void
+do_connection_down (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	NMActiveConnection *active;
 	ConnectionCbInfo *info = NULL;
 	const GPtrArray *active_cons;
 	gs_strfreev char **arg_arr = NULL;
-	char **arg_ptr;
+	const char *const*arg_ptr;
 	int arg_num;
 	guint i;
 	gs_unref_ptrarray GPtrArray *found_active_cons = NULL;
@@ -3125,11 +3144,12 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
 			line = nmc_readline (&nmc->nmc_config,
 			                     PROMPT_ACTIVE_CONNECTIONS);
 			nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
-			arg_ptr = arg_arr;
+			arg_ptr = (const char *const*) arg_arr;
 		}
 		if (arg_num == 0) {
 			g_string_printf (nmc->return_text, _("Error: No connection specified."));
-			return NMC_RESULT_ERROR_USER_INPUT;
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			return;
 		}
 	}
 
@@ -3147,7 +3167,8 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
 			arg_ptr++;
 			if (!arg_num) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector);
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 		}
 
@@ -3168,12 +3189,13 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
 
 	if (!found_active_cons) {
 		g_string_printf (nmc->return_text, _("Error: no active connection provided."));
-		return NMC_RESULT_ERROR_NOT_FOUND;
+		nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+		return;
 	}
 	nm_assert (found_active_cons->len > 0);
 
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	if (nmc->timeout > 0) {
 		nmc->should_wait++;
@@ -3210,8 +3232,6 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
 			}
 		}
 	}
-
-	return nmc->return_value;
 }
 
 /*****************************************************************************/
@@ -3699,7 +3719,7 @@ prompt_yes_no (gboolean default_yes, char *delim)
 }
 
 static NMSetting *
-is_setting_valid (NMConnection *connection, const NMMetaSettingValidPartItem *const*valid_settings_main, const NMMetaSettingValidPartItem *const*valid_settings_slave, char *setting)
+is_setting_valid (NMConnection *connection, const NMMetaSettingValidPartItem *const*valid_settings_main, const NMMetaSettingValidPartItem *const*valid_settings_slave, const char *setting)
 {
 	const char *setting_name;
 
@@ -3834,7 +3854,7 @@ _meta_abstract_complete (const NMMetaAbstractInfo *abstract_info, const char *te
 
 	values = nm_meta_abstract_info_complete (abstract_info,
 	                                         nmc_meta_environment,
-	                                         nmc_meta_environment_arg,
+	                                         (gpointer) nmc_meta_environment_arg,
 	                                         &ctx,
 	                                         text,
 	                                         NULL,
@@ -4634,7 +4654,7 @@ complete_option (NmCli *nmc, const NMMetaAbstractInfo *abstract_info, const char
 
 	values = nm_meta_abstract_info_complete (abstract_info,
 	                                         nmc_meta_environment,
-	                                         nmc_meta_environment_arg,
+	                                         (gpointer) nmc_meta_environment_arg,
 	                                         &ctx,
 	                                         prefix,
 	                                         &complete_filename,
@@ -4659,6 +4679,27 @@ complete_option (NmCli *nmc, const NMMetaAbstractInfo *abstract_info, const char
 }
 
 static void
+complete_existing_setting (NmCli *nmc, NMConnection *connection, const char *prefix)
+{
+	gs_free NMSetting **settings = NULL;
+	const NMMetaSettingInfoEditor *editor;
+	guint i;
+
+	settings = nm_connection_get_settings (connection, NULL);
+	for (i = 0; settings && settings[i]; i++) {
+		editor = nm_meta_setting_info_editor_find_by_setting (settings[i]);
+
+		if (!prefix || g_str_has_prefix (editor->general->setting_name, prefix))
+			g_print ("%s\n", editor->general->setting_name);
+
+		if (editor->alias) {
+			if (!prefix || g_str_has_prefix (editor->alias, prefix))
+				g_print ("%s\n", editor->alias);
+		}
+	}
+}
+
+static void
 complete_property (NmCli *nmc, const char *setting_name, const char *property, const char *prefix, NMConnection *connection)
 {
 	const NMMetaPropertyInfo *property_info;
@@ -4671,7 +4712,25 @@ complete_property (NmCli *nmc, const char *setting_name, const char *property, c
 /*****************************************************************************/
 
 static gboolean
-get_value (const char **value, int *argc, char ***argv, const char *option, GError **error)
+connection_remove_setting (NMConnection *connection, NMSetting *setting, GError **error)
+{
+	gboolean mandatory;
+
+	g_return_val_if_fail (setting, FALSE);
+
+	mandatory = is_setting_mandatory (connection, setting);
+	if (!mandatory) {
+		nm_connection_remove_setting (connection, G_OBJECT_TYPE (setting));
+		return TRUE;
+	}
+	g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+	             _("Error: setting '%s' is mandatory and cannot be removed."),
+	             nm_setting_get_name (setting));
+	return FALSE;
+}
+
+static gboolean
+get_value (const char **value, int *argc, const char *const**argv, const char *option, GError **error)
 {
 	if (!**argv) {
 		g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -4691,11 +4750,12 @@ get_value (const char **value, int *argc, char ***argv, const char *option, GErr
 }
 
 gboolean
-nmc_read_connection_properties (NmCli *nmc,
-                                NMConnection *connection,
-                                int *argc,
-                                char ***argv,
-                                GError **error)
+nmc_process_connection_properties (NmCli *nmc,
+                                   NMConnection *connection,
+                                   int *argc,
+                                   const char *const**argv,
+                                   gboolean allow_setting_removal,
+                                   GError **error)
 {
 	/* First check if we have a slave-type, as this would mean we will not
 	 * have ip properties but possibly others, slave-type specific.
@@ -4729,7 +4789,53 @@ nmc_read_connection_properties (NmCli *nmc,
 		default:  modifier = NM_META_ACCESSOR_MODIFIER_SET; option = option_orig;     break;
 		}
 
-		if ((tmp = strchr (option, '.'))) {
+		if (   allow_setting_removal
+		    && modifier == NM_META_ACCESSOR_MODIFIER_SET
+		    && nm_streq (option, "remove")) {
+			NMSetting *ss;
+			const char *setting_name;
+
+			(*argc)--;
+			(*argv)++;
+
+			if (*argc == 1 && nmc->complete) {
+				complete_existing_setting (nmc, connection, value);
+				return TRUE;
+			}
+
+			if (!*argc) {
+				g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+				                     _("Error: missing setting."));
+				return FALSE;
+			}
+
+			setting_name = **argv;
+			(*argc)--;
+			(*argv)++;
+
+			ss = is_setting_valid (connection,
+			                       type_settings,
+			                       slv_settings,
+			                       setting_name);
+			if (!ss) {
+				if (check_valid_name (setting_name,
+				                      type_settings,
+				                      slv_settings,
+				                      NULL)) {
+					g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+					             _("Setting '%s' is not present in the connection."),
+					             setting_name);
+				} else {
+					g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
+					             _("Error: invalid setting argument '%s'."),
+					             setting_name);
+				}
+				return FALSE;
+			}
+
+			if (!connection_remove_setting (connection, ss, error))
+				return FALSE;
+		} else if ((tmp = strchr (option, '.'))) {
 			gs_free char *option_sett = g_strndup (option, tmp - option);
 			const char *option_prop = &tmp[1];
 			const char *option_sett_expanded;
@@ -4823,8 +4929,12 @@ nmc_read_connection_properties (NmCli *nmc,
 			}
 
 			if (!chosen) {
-				if (*argc == 1 && nmc->complete)
+				if (*argc == 1 && nmc->complete) {
+					if (   allow_setting_removal
+					    && g_str_has_prefix ("remove", option))
+						g_print ("remove\n");
 					complete_property_name (nmc, connection, modifier, option, NULL);
+				}
 				g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
 				             _("Error: invalid <setting>.<property> '%s'."), option);
 				return FALSE;
@@ -4844,7 +4954,6 @@ nmc_read_connection_properties (NmCli *nmc,
 			if (!set_option (nmc, connection, chosen, value, error))
 				return FALSE;
 		}
-
 	} while (*argc);
 
 	return TRUE;
@@ -5243,8 +5352,8 @@ again:
 	return TRUE;
 }
 
-static NMCResultCode
-do_connection_add (NmCli *nmc, int argc, char **argv)
+static void
+do_connection_add (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	gs_unref_object NMConnection *connection = NULL;
 	NMSettingConnection *s_con;
@@ -5267,7 +5376,7 @@ do_connection_add (NmCli *nmc, int argc, char **argv)
 read_properties:
 	g_clear_error (&error);
 	/* Get the arguments from the command line if any */
-	if (argc && !nmc_read_connection_properties (nmc, connection, &argc, &argv, &error)) {
+	if (argc && !nmc_process_connection_properties (nmc, connection, &argc, &argv, FALSE, &error)) {
 		if (g_strcmp0 (*argv, "--") == 0 && !seen_dash_dash) {
 			/* This is for compatibility with older nmcli that required
 			 * options and properties to be separated with "--" */
@@ -5401,7 +5510,6 @@ read_properties:
 
 finish:
 	reset_options ();
-	return nmc->return_value;
 }
 
 /*****************************************************************************/
@@ -5730,7 +5838,7 @@ gen_vpn_uuids (const char *text, int state)
 	const char **uuids;
 	char *ret;
 
-	connections = nm_client_get_connections (nm_cli.client);
+	connections = nm_client_get_connections (nm_cli_global_readline->client);
 	if (connections->len < 1)
 		return NULL;
 
@@ -5747,7 +5855,7 @@ gen_vpn_ids (const char *text, int state)
 	const char **ids;
 	char *ret;
 
-	connections = nm_client_get_connections (nm_cli.client);
+	connections = nm_client_get_connections (nm_cli_global_readline->client);
 	if (connections->len < 1)
 		return NULL;
 
@@ -6878,23 +6986,6 @@ print_setting_description (NMSetting *setting)
 	g_strfreev (all_props);
 }
 
-static gboolean
-connection_remove_setting (NMConnection *connection, NMSetting *setting)
-{
-	gboolean mandatory;
-
-	g_return_val_if_fail (setting, FALSE);
-
-	mandatory = is_setting_mandatory (connection, setting);
-	if (!mandatory) {
-		nm_connection_remove_setting (connection, G_OBJECT_TYPE (setting));
-		return TRUE;
-	}
-	g_print (_("Error: setting '%s' is mandatory and cannot be removed.\n"),
-	         nm_setting_get_name (setting));
-	return FALSE;
-}
-
 static void
 editor_show_status_line (NMConnection *connection, gboolean dirty, gboolean temp)
 {
@@ -7632,8 +7723,12 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 					ss = menu_ctx.curr_setting;
 
 				if (descr_all) {
+					gs_free_error GError *local = NULL;
+
 					/* Remove setting from the connection */
-					connection_remove_setting (connection, ss);
+					if (!connection_remove_setting (connection, ss, &local))
+						g_print ("%s\n", local->message);
+
 					if (ss == menu_ctx.curr_setting) {
 						/* If we removed the setting we are in, go up */
 						menu_switch_to_level0 (&nmc->nmc_config, &menu_ctx, BASE_PROMPT);
@@ -7664,8 +7759,11 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 						                          valid_settings_slave,
 						                          cmd_arg_p);
 						if (s_tmp) {
+							gs_free_error GError *local = NULL;
+
 							/* Remove setting from the connection */
-							connection_remove_setting (connection, s_tmp);
+							if (!connection_remove_setting (connection, s_tmp, &local))
+								g_print ("%s\n", local->message);
 
 							/* coverity[copy_paste_error] - suppress Coverity COPY_PASTE_ERROR defect */
 							if (ss == menu_ctx.curr_setting) {
@@ -7919,7 +8017,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 					connection_changed = FALSE;
 				}
 
-				source = g_timeout_source_new (10 * NM_UTILS_MSEC_PER_SECOND);
+				source = g_timeout_source_new (10 * NM_UTILS_MSEC_PER_SEC);
 				g_source_set_callback (source, editor_save_timeout, &timeout, NULL);
 				g_source_attach (source, g_main_loop_get_context (loop));
 
@@ -8259,8 +8357,8 @@ nmc_complete_connection_type (const char *prefix)
 	}
 }
 
-static NMCResultCode
-do_connection_edit (NmCli *nmc, int argc, char **argv)
+static void
+do_connection_edit (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	const GPtrArray *connections;
 	gs_unref_object NMConnection *connection = NULL;
@@ -8295,7 +8393,8 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
 	else {
 		if (!nmc_parse_args (exp_args, TRUE, &argc, &argv, &error)) {
 			g_string_assign (nmc->return_text, error->message);
-			return error->code;
+			nmc->return_value = error->code;
+			return;
 		}
 	}
 
@@ -8325,7 +8424,8 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
 		} else {
 			g_string_printf (nmc->return_text,
 			                 _("Error: only one of 'id', 'filename', uuid, or 'path' can be provided."));
-			return NMC_RESULT_ERROR_USER_INPUT;
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			return;
 		}
 	}
 
@@ -8335,11 +8435,12 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
 
 		found_con = nmc_find_connection (connections, selector, con, NULL, nmc->complete);
 		if (nmc->complete)
-			return nmc->return_value;
+			return;
 
 		if (!found_con) {
 			g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), con);
-			return NMC_RESULT_ERROR_NOT_FOUND;
+			nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+			return;
 		}
 
 		/* Duplicate the connection and use that so that we need not
@@ -8374,7 +8475,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
 		if (nmc->complete) {
 			if (type && argc == 0)
 				nmc_complete_connection_type (type);
-			return nmc->return_value;
+			return;
 		}
 
 		connection_type = check_valid_name_toplevel (type, &slave_type, &err1);
@@ -8450,7 +8551,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
 	nm_clear_g_free (&nmc_tab_completion.con_type);
 	nmc_tab_completion.connection = NULL;
 
-	return nmc->return_value;
+	return;
 }
 
 static void
@@ -8478,10 +8579,8 @@ modify_connection_cb (GObject *connection,
 	quit ();
 }
 
-static NMCResultCode
-do_connection_modify (NmCli *nmc,
-                      int argc,
-                      char **argv)
+static void
+do_connection_modify (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	NMConnection *connection = NULL;
 	NMRemoteConnection *rc = NULL;
@@ -8496,7 +8595,8 @@ do_connection_modify (NmCli *nmc,
 	connection = get_connection (nmc, &argc, &argv, NULL, NULL, NULL, &error);
 	if (!connection) {
 		g_string_printf (nmc->return_text, _("Error: %s."), error->message);
-		return error->code;
+		nmc->return_value = error->code;
+		return;
 	}
 
 	rc = nm_client_get_connection_by_uuid (nmc->client,
@@ -8504,21 +8604,21 @@ do_connection_modify (NmCli *nmc,
 	if (!rc) {
 		g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."),
 		                 nm_connection_get_uuid (connection));
-		return NMC_RESULT_ERROR_NOT_FOUND;
+		nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+		return;
 	}
 
-	if (!nmc_read_connection_properties (nmc, NM_CONNECTION (rc), &argc, &argv, &error)) {
+	if (!nmc_process_connection_properties (nmc, NM_CONNECTION (rc), &argc, &argv, TRUE, &error)) {
 		g_string_assign (nmc->return_text, error->message);
-		return error->code;
+		nmc->return_value = error->code;
+		return;
 	}
 
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	update_connection (rc, temporary, modify_connection_cb, nmc);
 	nmc->should_wait++;
-
-	return nmc->return_value;
 }
 
 static void
@@ -8548,8 +8648,8 @@ clone_connection_cb (GObject *client,
 	quit ();
 }
 
-static NMCResultCode
-do_connection_clone (NmCli *nmc, int argc, char **argv)
+static void
+do_connection_clone (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	NMConnection *connection = NULL;
 	gs_unref_object NMConnection *new_connection = NULL;
@@ -8557,9 +8657,9 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
 	gs_free char *new_name_free = NULL;
 	gs_free char *uuid = NULL;
 	gboolean temporary = FALSE;
-	char **arg_arr = NULL;
+	gs_strfreev char **arg_arr = NULL;
 	int arg_num;
-	char ***argv_ptr;
+	const char *const**argv_ptr;
 	int *argc_ptr;
 	GError *error = NULL;
 
@@ -8580,18 +8680,19 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
 		line = nmc_readline (&nmc->nmc_config,
 		                     PROMPT_CONNECTION);
 		nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
-		argv_ptr = &arg_arr;
+		argv_ptr = (const char *const**) &arg_arr;
 		argc_ptr = &arg_num;
 	}
 
 	connection = get_connection (nmc, argc_ptr, argv_ptr, NULL, NULL, NULL, &error);
 	if (!connection) {
 		g_string_printf (nmc->return_text, _("Error: %s."), error->message);
-		return error->code;
+		nmc->return_value = error->code;
+		return;
 	}
 
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	if (argv[0])
 		new_name = *argv;
@@ -8600,12 +8701,14 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
 		                                         _("New connection name: "));
 	} else {
 		g_string_printf (nmc->return_text, _("Error: <new name> argument is missing."));
-		return NMC_RESULT_ERROR_USER_INPUT;
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return;
 	}
 
 	if (next_arg (nmc->ask ? NULL : nmc, argc_ptr, argv_ptr, NULL) == 0) {
 		g_string_printf (nmc->return_text, _("Error: unknown extra argument: '%s'."), *argv);
-		return NMC_RESULT_ERROR_USER_INPUT;
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return;
 	}
 
 	new_connection = nm_simple_connection_new_clone (connection);
@@ -8624,8 +8727,6 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
 	                clone_connection_cb,
 	                _add_connection_info_new (nmc, connection, new_connection));
 	nmc->should_wait++;
-
-	return nmc->return_value;
 }
 
 static void
@@ -8649,13 +8750,13 @@ delete_cb (GObject *con, GAsyncResult *result, gpointer user_data)
 	}
 }
 
-static NMCResultCode
-do_connection_delete (NmCli *nmc, int argc, char **argv)
+static void
+do_connection_delete (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	NMConnection *connection;
 	ConnectionCbInfo *info = NULL;
 	gs_strfreev char **arg_arr = NULL;
-	char **arg_ptr;
+	const char *const*arg_ptr;
 	guint i;
 	int arg_num;
 	nm_auto_free_gstring GString *invalid_cons = NULL;
@@ -8679,7 +8780,7 @@ do_connection_delete (NmCli *nmc, int argc, char **argv)
 			line = nmc_readline (&nmc->nmc_config,
 			                     PROMPT_CONNECTIONS);
 			nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
-			arg_ptr = arg_arr;
+			arg_ptr = (const char *const*) arg_arr;
 		}
 		if (arg_num == 0) {
 			g_string_printf (nmc->return_text, _("Error: No connection specified."));
@@ -8750,7 +8851,6 @@ finish:
 		                 invalid_cons->str);
 		nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
 	}
-	return nmc->return_value;
 }
 
 static void
@@ -8795,8 +8895,8 @@ connection_removed (NMClient *client, NMRemoteConnection *con, NmCli *nmc)
 	connection_unwatch (nmc, connection);
 }
 
-static NMCResultCode
-do_connection_monitor (NmCli *nmc, int argc, char **argv)
+static void
+do_connection_monitor (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	GError *error = NULL;
 	guint i;
@@ -8817,7 +8917,8 @@ do_connection_monitor (NmCli *nmc, int argc, char **argv)
 				if (!nmc->complete)
 					g_printerr (_("Error: %s.\n"), error->message);
 				g_string_printf (nmc->return_text, _("Error: not all connections found."));
-				return error->code;
+				nmc->return_value = error->code;
+				return;
 			}
 
 			if (nmc->complete)
@@ -8828,7 +8929,7 @@ do_connection_monitor (NmCli *nmc, int argc, char **argv)
 	}
 
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	for (i = 0; i < connections->len; i++)
 		connection_watch (nmc, connections->pdata[i]);
@@ -8840,19 +8941,17 @@ do_connection_monitor (NmCli *nmc, int argc, char **argv)
 	}
 
 	g_signal_connect (nmc->client, NM_CLIENT_CONNECTION_REMOVED, G_CALLBACK (connection_removed), nmc);
-
-	return NMC_RESULT_SUCCESS;
 }
 
-static NMCResultCode
-do_connection_reload (NmCli *nmc, int argc, char **argv)
+static void
+do_connection_reload (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	gs_unref_variant GVariant *result = NULL;
 	gs_free_error GError *error = NULL;
 
 	next_arg (nmc, &argc, &argv, NULL);
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	result = nmc_dbus_call_sync (nmc,
 	                             "/org/freedesktop/NetworkManager/Settings",
@@ -8866,33 +8965,31 @@ do_connection_reload (NmCli *nmc, int argc, char **argv)
 		                 nmc_error_get_simple_message (error));
 		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 	}
-
-	return nmc->return_value;
 }
 
-static NMCResultCode
-do_connection_load (NmCli *nmc, int argc, char **argv)
+static void
+do_connection_load (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	GError *error = NULL;
-	char **filenames, **failures = NULL;
+	gs_free const char **filenames = NULL;
+	gs_strfreev char **failures = NULL;
 	int i;
 
 	next_arg (nmc, &argc, &argv, NULL);
 	if (argc == 0) {
 		g_string_printf (nmc->return_text, _("Error: No connection specified."));
-		return NMC_RESULT_ERROR_USER_INPUT;
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return;
 	}
 
-	if (nmc->complete)
-		return NMC_RESULT_COMPLETE_FILE;
+	if (nmc->complete) {
+		nmc->return_value = NMC_RESULT_COMPLETE_FILE;
+		return;
+	}
 
-	filenames = g_new (char *, argc + 1);
-	for (i = 0; i < argc; i++)
-		filenames[i] = argv[i];
-	filenames[i] = NULL;
+	filenames = (const char **) nm_utils_strv_dup ((char **) argv, argc, FALSE);
 
-	nm_client_load_connections (nmc->client, filenames, &failures, NULL, &error);
-	g_free (filenames);
+	nm_client_load_connections (nmc->client, (char **) filenames, &failures, NULL, &error);
 	if (error) {
 		g_string_printf (nmc->return_text, _("Error: failed to load connection: %s."),
 		                 nmc_error_get_simple_message (error));
@@ -8903,16 +9000,13 @@ do_connection_load (NmCli *nmc, int argc, char **argv)
 	if (failures) {
 		for (i = 0; failures[i]; i++)
 			g_printerr (_("Could not load file '%s'\n"), failures[i]);
-		g_strfreev (failures);
 	}
-
-	return nmc->return_value;
 }
 
 #define PROMPT_IMPORT_FILE N_("File to import: ")
 
-static NMCResultCode
-do_connection_import (NmCli *nmc, int argc, char **argv)
+static void
+do_connection_import (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	gs_free_error GError *error = NULL;
 	const char *type = NULL, *filename = NULL;
@@ -8943,7 +9037,8 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 			filename = nm_strstrip (filename_ask);
 		} else {
 			g_string_printf (nmc->return_text, _("Error: No arguments provided."));
-			return NMC_RESULT_ERROR_USER_INPUT;
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			return;
 		}
 	}
 
@@ -8959,7 +9054,8 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 
 			if (   argc == 1
@@ -8980,7 +9076,8 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			if (argc == 1 && nmc->complete)
 				nmc->return_value = NMC_RESULT_COMPLETE_FILE;
@@ -8990,22 +9087,25 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 				g_printerr (_("Warning: 'file' already specified, ignoring extra one.\n"));
 		} else {
 			g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
-			return NMC_RESULT_ERROR_USER_INPUT;
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			return;
 		}
 
 		next_arg (nmc, &argc, &argv, NULL);
 	}
 
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	if (!type) {
 		g_string_printf (nmc->return_text, _("Error: 'type' argument is required."));
-		return NMC_RESULT_ERROR_USER_INPUT;
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return;
 	}
 	if (!filename) {
 		g_string_printf (nmc->return_text, _("Error: 'file' argument is required."));
-		return NMC_RESULT_ERROR_USER_INPUT;
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return;
 	}
 
 	if (nm_streq (type, "wireguard"))
@@ -9014,7 +9114,8 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 		service_type = nm_vpn_plugin_info_list_find_service_type (nm_vpn_get_plugin_infos (), type);
 		if (!service_type) {
 			g_string_printf (nmc->return_text, _("Error: failed to find VPN plugin for %s."), type);
-			return NMC_RESULT_ERROR_UNKNOWN;
+			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+			return;
 		}
 
 		/* Import VPN configuration */
@@ -9022,7 +9123,8 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 		if (!plugin) {
 			g_string_printf (nmc->return_text, _("Error: failed to load VPN plugin: %s."),
 			                 error->message);
-			return NMC_RESULT_ERROR_UNKNOWN;
+			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+			return;
 		}
 
 		connection = nm_vpn_editor_plugin_import (plugin, filename, &error);
@@ -9031,7 +9133,8 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 	if (!connection) {
 		g_string_printf (nmc->return_text, _("Error: failed to import '%s': %s."),
 		                 filename, error->message);
-		return NMC_RESULT_ERROR_UNKNOWN;
+		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+		return;
 	}
 
 	add_connection (nmc->client,
@@ -9040,12 +9143,10 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
 	                add_connection_cb,
 	                _add_connection_info_new (nmc, NULL, connection));
 	nmc->should_wait++;
-
-	return nmc->return_value;
 }
 
-static NMCResultCode
-do_connection_export (NmCli *nmc, int argc, char **argv)
+static void
+do_connection_export (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	NMConnection *connection = NULL;
 	const char *out_name = NULL;
@@ -9055,9 +9156,9 @@ do_connection_export (NmCli *nmc, int argc, char **argv)
 	NMVpnEditorPlugin *plugin;
 	gs_free_error GError *error = NULL;
 	char tmpfile[] = "/tmp/nmcli-export-temp-XXXXXX";
-	char **arg_arr = NULL;
+	gs_strfreev char **arg_arr = NULL;
 	int arg_num;
-	char ***argv_ptr;
+	const char *const**argv_ptr;
 	int *argc_ptr;
 
 	next_arg (nmc, &argc, &argv, NULL);
@@ -9073,7 +9174,7 @@ do_connection_export (NmCli *nmc, int argc, char **argv)
 		line = nmc_readline (&nmc->nmc_config,
 		                     PROMPT_VPN_CONNECTION);
 		nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
-		argv_ptr = &arg_arr;
+		argv_ptr = (const char *const**) &arg_arr;
 		argc_ptr = &arg_num;
 	}
 
@@ -9085,7 +9186,7 @@ do_connection_export (NmCli *nmc, int argc, char **argv)
 	}
 
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	out_name = *argv;
 
@@ -9155,7 +9256,6 @@ do_connection_export (NmCli *nmc, int argc, char **argv)
 finish:
 	if (!out_name && path)
 		unlink (path);
-	return nmc->return_value;
 }
 
 static char *
@@ -9166,7 +9266,7 @@ gen_func_connection_names (const char *text, int state)
 	const char **connection_names;
 	char *ret;
 
-	connections = nm_client_get_connections (nm_cli.client);
+	connections = nm_client_get_connections (nm_cli_global_readline->client);
 	if (connections->len == 0)
 		return NULL;
 
@@ -9189,10 +9289,10 @@ gen_func_active_connection_names (const char *text, int state)
 	const char **connections;
 	char *ret;
 
-	if (!nm_cli.client)
+	if (!nm_cli_global_readline->client)
 		return NULL;
 
-	acs = nm_client_get_active_connections (nm_cli.client);
+	acs = nm_client_get_active_connections (nm_cli_global_readline->client);
 	if (!acs || acs->len == 0)
 		return NULL;
 
@@ -9243,46 +9343,42 @@ nmcli_con_tab_completion (const char *text, int start, int end)
 	if (generator_func)
 		match_array = rl_completion_matches (text, generator_func);
 
-	g_clear_pointer (&nmc_tab_completion.words, g_strfreev);
+	nm_clear_pointer (&nmc_tab_completion.words, g_strfreev);
 	return match_array;
 }
 
-static const NMCCommand connection_cmds[] = {
-	{ "show",     do_connections_show,      usage_connection_show,     TRUE,   TRUE },
-	{ "up",       do_connection_up,         usage_connection_up,       TRUE,   TRUE },
-	{ "down",     do_connection_down,       usage_connection_down,     TRUE,   TRUE },
-	{ "add",      do_connection_add,        usage_connection_add,      TRUE,   TRUE },
-	{ "edit",     do_connection_edit,       usage_connection_edit,     TRUE,   TRUE },
-	{ "delete",   do_connection_delete,     usage_connection_delete,   TRUE,   TRUE },
-	{ "reload",   do_connection_reload,     usage_connection_reload,   FALSE,  FALSE },
-	{ "load",     do_connection_load,       usage_connection_load,     TRUE,   TRUE },
-	{ "modify",   do_connection_modify,     usage_connection_modify,   TRUE,   TRUE },
-	{ "clone",    do_connection_clone,      usage_connection_clone,    TRUE,   TRUE },
-	{ "import",   do_connection_import,     usage_connection_import,   TRUE,   TRUE },
-	{ "export",   do_connection_export,     usage_connection_export,   TRUE,   TRUE },
-	{ "monitor",  do_connection_monitor,    usage_connection_monitor,  TRUE,   TRUE },
-	{ NULL,       do_connections_show,      usage,                     TRUE,   TRUE },
-};
+void
+nmc_command_func_connection (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
+{
+	static const NMCCommand cmds[] = {
+		{ "show",   do_connections_show,   usage_connection_show,    TRUE,  TRUE  },
+		{ "up",     do_connection_up,      usage_connection_up,      TRUE,  TRUE  },
+		{ "down",   do_connection_down,    usage_connection_down,    TRUE,  TRUE  },
+		{ "add",    do_connection_add,     usage_connection_add,     TRUE,  TRUE  },
+		{ "edit",   do_connection_edit,    usage_connection_edit,    TRUE,  TRUE  },
+		{ "delete", do_connection_delete,  usage_connection_delete,  TRUE,  TRUE  },
+		{ "reload", do_connection_reload,  usage_connection_reload,  FALSE, FALSE },
+		{ "load",   do_connection_load,    usage_connection_load,    TRUE,  TRUE  },
+		{ "modify", do_connection_modify,  usage_connection_modify,  TRUE,  TRUE  },
+		{ "clone",  do_connection_clone,   usage_connection_clone,   TRUE,  TRUE  },
+		{ "import", do_connection_import,  usage_connection_import,  TRUE,  TRUE  },
+		{ "export", do_connection_export,  usage_connection_export,  TRUE,  TRUE  },
+		{ "monitor",do_connection_monitor, usage_connection_monitor, TRUE,  TRUE  },
+		{ NULL,     do_connections_show,   usage,                    TRUE,  TRUE  },
+	};
 
-/* Entry point function for connections-related commands: 'nmcli connection' */
-NMCResultCode
-do_connections (NmCli *nmc, int argc, char **argv)
-{
 	next_arg (nmc, &argc, &argv, NULL);
 
-	/* Register polkit agent */
 	nmc_start_polkit_agent_start_try (nmc);
 
 	/* Set completion function for 'nmcli con' */
 	rl_attempted_completion_function = nmcli_con_tab_completion;
 
-	nmc_do_cmd (nmc, connection_cmds, *argv, argc, argv);
-
-	return nmc->return_value;
+	nmc_do_cmd (nmc, cmds, *argv, argc, argv);
 }
 
 void
 monitor_connections (NmCli *nmc)
 {
-	do_connection_monitor (nmc, 0, NULL);
+	do_connection_monitor (NULL, nmc, 0, NULL);
 }
diff --git a/clients/cli/connections.h b/clients/cli/connections.h
index 7fa9d448..79359a1f 100644
--- a/clients/cli/connections.h
+++ b/clients/cli/connections.h
@@ -8,16 +8,15 @@
 
 #include "nmcli.h"
 
-NMCResultCode do_connections (NmCli *nmc, int argc, char **argv);
-
 void monitor_connections (NmCli *nmc);
 
 gboolean
-nmc_read_connection_properties (NmCli *nmc,
-                                NMConnection *connection,
-                                int *argc,
-                                char ***argv,
-                                GError **error);
+nmc_process_connection_properties (NmCli *nmc,
+                                   NMConnection *connection,
+                                   int *argc,
+                                   const char *const**argv,
+                                   gboolean allow_remove_setting,
+                                   GError **error);
 
 NMMetaColor nmc_active_connection_state_to_color (NMActiveConnectionState state);
 
diff --git a/clients/cli/devices.c b/clients/cli/devices.c
index c99efd0d..4ea4e772 100644
--- a/clients/cli/devices.c
+++ b/clients/cli/devices.c
@@ -11,13 +11,13 @@
 #include <stdlib.h>
 #include <readline/readline.h>
 
-#include "nm-secret-agent-simple.h"
+#include "nm-glib-aux/nm-secret-utils.h"
+#include "common.h"
+#include "connections.h"
 #include "nm-client-utils.h"
-
+#include "nm-secret-agent-simple.h"
 #include "polkit-agent.h"
 #include "utils.h"
-#include "common.h"
-#include "connections.h"
 
 /* define some prompts */
 #define PROMPT_INTERFACE  _("Interface: ")
@@ -26,9 +26,9 @@
 /*****************************************************************************/
 
 static char *
-ap_wpa_rsn_flags_to_string (NM80211ApSecurityFlags flags)
+ap_wpa_rsn_flags_to_string (NM80211ApSecurityFlags flags, NMMetaAccessorGetType get_type)
 {
-	char *flags_str[13];
+	char *flags_str[16];
 	int i = 0;
 
 	if (flags & NM_802_11_AP_SEC_PAIR_WEP40)
@@ -53,13 +53,19 @@ ap_wpa_rsn_flags_to_string (NM80211ApSecurityFlags flags)
 		flags_str[i++] = "802.1X";
 	if (flags & NM_802_11_AP_SEC_KEY_MGMT_SAE)
 		flags_str[i++] = "sae";
+	if (flags & NM_802_11_AP_SEC_KEY_MGMT_OWE)
+		flags_str[i++] = "owe";
+
 	/* Make sure you grow flags_str when adding items here. */
+	nm_assert (i < G_N_ELEMENTS (flags_str));
 
-	if (i == 0)
-		flags_str[i++] = _("(none)");
+	if (i == 0) {
+		if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY)
+			return g_strdup (_("(none)"));
+		return g_strdup ("(none)");
+	}
 
 	flags_str[i] = NULL;
-
 	return g_strjoinv (" ", flags_str);
 }
 
@@ -990,11 +996,11 @@ nmc_complete_device (NMClient *client, const char *prefix, gboolean wifi_only)
 }
 
 static GSList *
-get_device_list (NmCli *nmc, int argc, char **argv)
+get_device_list (NmCli *nmc, int argc, const char *const*argv)
 {
 	int arg_num = argc;
-	char **arg_arr = NULL;
-	char **arg_ptr = argv;
+	gs_strfreev char **arg_arr = NULL;
+	const char *const*arg_ptr = argv;
 	NMDevice **devices;
 	GSList *queue = NULL;
 	NMDevice *device;
@@ -1007,7 +1013,7 @@ get_device_list (NmCli *nmc, int argc, char **argv)
 			line = nmc_readline (&nmc->nmc_config,
 			                     PROMPT_INTERFACES);
 			nmc_string_to_arg_array (line, NULL, FALSE, &arg_arr, &arg_num);
-			arg_ptr = arg_arr;
+			arg_ptr = (const char *const*) arg_arr;
 		}
 		if (arg_num == 0) {
 			g_string_printf (nmc->return_text, _("Error: No interface specified."));
@@ -1053,7 +1059,7 @@ error:
 }
 
 static NMDevice *
-get_device (NmCli *nmc, int *argc, char ***argv, GError **error)
+get_device (NmCli *nmc, int *argc, const char *const**argv, GError **error)
 {
 	gs_free NMDevice **devices = NULL;
 	gs_free char *ifname_ask = NULL;
@@ -1098,30 +1104,30 @@ compare_aps (gconstpointer a, gconstpointer b, gpointer user_data)
 {
 	NMAccessPoint *apa = *(NMAccessPoint **)a;
 	NMAccessPoint *apb = *(NMAccessPoint **)b;
-	int cmp;
 
-	cmp = nm_access_point_get_strength (apb) - nm_access_point_get_strength (apa);
-	if (cmp != 0)
-		return cmp;
+	NM_CMP_DIRECT (nm_access_point_get_strength (apb), nm_access_point_get_strength (apa));
+	NM_CMP_DIRECT (nm_access_point_get_frequency (apa), nm_access_point_get_frequency (apb));
+	NM_CMP_DIRECT (nm_access_point_get_max_bitrate (apb), nm_access_point_get_max_bitrate (apa));
 
-	cmp = nm_access_point_get_frequency (apa) - nm_access_point_get_frequency (apb);
-	if (cmp != 0)
-		return cmp;
+	/* as fallback, just give it some stable order and use the D-Bus path (literally). */
+	NM_CMP_DIRECT_STRCMP0 (nm_object_get_path (NM_OBJECT (apa)),
+	                       nm_object_get_path (NM_OBJECT (apb)));
 
-	return nm_access_point_get_max_bitrate (apb) - nm_access_point_get_max_bitrate (apa);
+	return 0;
 }
 
 static GPtrArray *
 sort_access_points (const GPtrArray *aps)
 {
 	GPtrArray *sorted;
-	int i;
+	guint i;
 
 	g_return_val_if_fail (aps, NULL);
 
 	sorted = g_ptr_array_sized_new (aps->len);
+	g_ptr_array_set_free_func (sorted, nm_g_object_unref);
 	for (i = 0; i < aps->len; i++)
-		g_ptr_array_add (sorted, aps->pdata[i]);
+		g_ptr_array_add (sorted, g_object_ref (aps->pdata[i]));
 	g_ptr_array_sort_with_data (sorted, compare_aps, NULL);
 	return sorted;
 }
@@ -1186,8 +1192,8 @@ fill_output_access_point (gpointer data, gpointer user_data)
 	freq_str = g_strdup_printf (_("%u MHz"), freq);
 	bitrate_str = g_strdup_printf (_("%u Mbit/s"), bitrate/1000);
 	strength_str = g_strdup_printf ("%u", strength);
-	wpa_flags_str = ap_wpa_rsn_flags_to_string (wpa_flags);
-	rsn_flags_str = ap_wpa_rsn_flags_to_string (rsn_flags);
+	wpa_flags_str = ap_wpa_rsn_flags_to_string (wpa_flags, NM_META_ACCESSOR_GET_TYPE_PRETTY);
+	rsn_flags_str = ap_wpa_rsn_flags_to_string (rsn_flags, NM_META_ACCESSOR_GET_TYPE_PRETTY);
 	sig_bars = nmc_wifi_strength_bars (strength);
 
 	security_str = g_string_new (NULL);
@@ -1207,6 +1213,9 @@ fill_output_access_point (gpointer data, gpointer user_data)
 	if (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE) {
 		g_string_append (security_str, "WPA3 ");
 	}
+	if (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_OWE) {
+		g_string_append (security_str, "OWE ");
+	}
 	if (   (wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
 	    || (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
 		g_string_append   (security_str, "802.1X ");
@@ -1331,7 +1340,7 @@ print_bond_bridge_info (NMDevice *device,
 	g_ptr_array_add (out.output_data, arr);
 
 	print_data_prepare_width (out.output_data);
-	print_data (&nmc->nmc_config, out_indices, NULL, 0, &out);
+	print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, NULL, 0, &out);
 
 	g_string_free (slaves_str, FALSE);
 
@@ -1401,7 +1410,7 @@ print_team_info (NMDevice *device,
 	g_ptr_array_add (out.output_data, arr);
 
 	print_data_prepare_width (out.output_data);
-	print_data (&nmc->nmc_config, out_indices, NULL, 0, &out);
+	print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, NULL, 0, &out);
 
 	g_string_free (slaves_str, FALSE);
 
@@ -1424,9 +1433,9 @@ show_device_info (NMDevice *device, NmCli *nmc)
 	const char *base_hdr = _("Device details");
 	GPtrArray *fields_in_section = NULL;
 
-	if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
+	if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0)
 		fields_str = NMC_FIELDS_DEV_SHOW_SECTIONS_COMMON;
-	else if (strcasecmp (nmc->required_fields, "all") == 0) {
+	else if (g_ascii_strcasecmp (nmc->required_fields, "all") == 0) {
 	} else
 		fields_str = nmc->required_fields;
 
@@ -1456,9 +1465,13 @@ show_device_info (NMDevice *device, NmCli *nmc)
 		for (i = 0; i < G_N_ELEMENTS (metagen_device_detail_general); i++)
 			row[i].info = (const NMMetaAbstractInfo *) &metagen_device_detail_general[i];
 
-		print_required_fields (&nmc->nmc_config, NMC_OF_FLAG_MAIN_HEADER_ONLY,
-		                       out_indices, header_name,
-		                       0, row);
+		print_required_fields (&nmc->nmc_config,
+		                       &nmc->pager_data,
+		                       NMC_OF_FLAG_MAIN_HEADER_ONLY,
+		                       out_indices,
+		                       header_name,
+		                       0,
+		                       row);
 	}
 
 	/* Loop through the required sections and print them. */
@@ -1537,10 +1550,9 @@ show_device_info (NMDevice *device, NmCli *nmc)
 		if ((NM_IS_DEVICE_WIFI (device))) {
 			NMAccessPoint *active_ap = NULL;
 			const char *active_bssid = NULL;
-			GPtrArray *aps;
 
 			/* section AP */
-			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[4]->name)) {
+			if (!g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[4]->name)) {
 				NMC_OUTPUT_DATA_DEFINE_SCOPED (out);
 
 				if (state == NM_DEVICE_STATE_ACTIVATED) {
@@ -1555,6 +1567,7 @@ show_device_info (NMDevice *device, NmCli *nmc)
 				g_ptr_array_add (out.output_data, arr);
 
 				{
+					gs_unref_ptrarray GPtrArray *aps = NULL;
 					APInfo info = {
 						.nmc = nmc,
 						.index = 1,
@@ -1566,11 +1579,10 @@ show_device_info (NMDevice *device, NmCli *nmc)
 
 					aps = sort_access_points (nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device)));
 					g_ptr_array_foreach (aps, fill_output_access_point, &info);
-					g_ptr_array_free (aps, FALSE);
 				}
 
 				print_data_prepare_width (out.output_data);
-				print_data (&nmc->nmc_config, out_indices, NULL, 0, &out);
+				print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, NULL, 0, &out);
 				was_output = TRUE;
 			}
 		}
@@ -1598,42 +1610,42 @@ show_device_info (NMDevice *device, NmCli *nmc)
 		dhcp6 = nm_device_get_dhcp6_config (device);
 
 		/* IP4 */
-		if (cfg4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[8]->name))
+		if (cfg4 && !g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[8]->name))
 			was_output = print_ip_config (cfg4, AF_INET, &nmc->nmc_config, section_fld);
 
 		/* DHCP4 */
-		if (dhcp4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[9]->name))
+		if (dhcp4 && !g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[9]->name))
 			was_output = print_dhcp_config (dhcp4, AF_INET, &nmc->nmc_config, section_fld);
 
 		/* IP6 */
-		if (cfg6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[10]->name))
+		if (cfg6 && !g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[10]->name))
 			was_output = print_ip_config (cfg6, AF_INET6, &nmc->nmc_config, section_fld);
 
 		/* DHCP6 */
-		if (dhcp6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[11]->name))
+		if (dhcp6 && !g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[11]->name))
 			was_output = print_dhcp_config (dhcp6, AF_INET6, &nmc->nmc_config, section_fld);
 
 		/* Bond specific information */
 		if (NM_IS_DEVICE_BOND (device)) {
-			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[12]->name))
+			if (!g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[12]->name))
 				was_output = print_bond_bridge_info (device, nmc, nmc_fields_dev_show_sections[12]->name, section_fld);
 		}
 
 		/* Team specific information */
 		if (NM_IS_DEVICE_TEAM (device)) {
-			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[13]->name))
+			if (!g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[13]->name))
 				was_output = print_team_info (device, nmc, nmc_fields_dev_show_sections[13]->name, section_fld);
 		}
 
 		/* Bridge specific information */
 		if (NM_IS_DEVICE_BRIDGE (device)) {
-			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[14]->name))
+			if (!g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[14]->name))
 				was_output = print_bond_bridge_info (device, nmc, nmc_fields_dev_show_sections[14]->name, section_fld);
 		}
 
 		/* VLAN-specific information */
 		if ((NM_IS_DEVICE_VLAN (device))) {
-			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[15]->name)) {
+			if (!g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[15]->name)) {
 				char * vlan_id_str = g_strdup_printf ("%u", nm_device_vlan_get_vlan_id (NM_DEVICE_VLAN (device)));
 				NMDevice *parent = nm_device_vlan_get_parent (NM_DEVICE_VLAN (device));
 				NMC_OUTPUT_DATA_DEFINE_SCOPED (out);
@@ -1651,14 +1663,14 @@ show_device_info (NMDevice *device, NmCli *nmc)
 				g_ptr_array_add (out.output_data, arr);
 
 				print_data_prepare_width (out.output_data);
-				print_data (&nmc->nmc_config, out_indices, NULL, 0, &out);
+				print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, NULL, 0, &out);
 
 				was_output = TRUE;
 			}
 		}
 
 		if (NM_IS_DEVICE_BT (device)) {
-			if (!strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[16]->name)) {
+			if (!g_ascii_strcasecmp (nmc_fields_dev_show_sections[section_idx]->name, nmc_fields_dev_show_sections[16]->name)) {
 				NMC_OUTPUT_DATA_DEFINE_SCOPED (out);
 
 				tmpl = (const NMMetaAbstractInfo *const*) nmc_fields_dev_show_bluetooth;
@@ -1673,7 +1685,7 @@ show_device_info (NMDevice *device, NmCli *nmc)
 				g_ptr_array_add (out.output_data, arr);
 
 				print_data_prepare_width (out.output_data);
-				print_data (&nmc->nmc_config, out_indices, NULL, 0, &out);
+				print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, NULL, 0, &out);
 				was_output = TRUE;
 			}
 		}
@@ -1716,8 +1728,8 @@ nmc_device_state_to_color (NMDeviceState state)
 	return NM_META_COLOR_DEVICE_UNKNOWN;
 }
 
-static NMCResultCode
-do_devices_status (NmCli *nmc, int argc, char **argv)
+static void
+do_devices_status (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	GError *error = NULL;
 	gs_free NMDevice **devices = NULL;
@@ -1726,16 +1738,17 @@ do_devices_status (NmCli *nmc, int argc, char **argv)
 	next_arg (nmc, &argc, &argv, NULL);
 
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	if (argc) {
 		g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
-		return NMC_RESULT_ERROR_USER_INPUT;
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return;
 	}
 
-	if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
+	if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0)
 		fields_str = "DEVICE,TYPE,STATE,CONNECTION";
-	else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) {
+	else if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "all") == 0) {
 	} else
 		fields_str = nmc->required_fields;
 
@@ -1750,14 +1763,13 @@ do_devices_status (NmCli *nmc, int argc, char **argv)
 	                &error)) {
 		g_string_printf (nmc->return_text, _("Error: 'device status': %s"), error->message);
 		g_error_free (error);
-		return NMC_RESULT_ERROR_USER_INPUT;
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return;
 	}
-
-	return NMC_RESULT_SUCCESS;
 }
 
-static NMCResultCode
-do_device_show (NmCli *nmc, int argc, char **argv)
+static void
+do_device_show (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	gs_free_error GError *error = NULL;
 
@@ -1771,16 +1783,18 @@ do_device_show (NmCli *nmc, int argc, char **argv)
 		device = get_device (nmc, &argc, &argv, &error);
 		if (!device) {
 			g_string_printf (nmc->return_text, _("Error: %s."), error->message);
-			return error->code;
+			nmc->return_value = error->code;
+			return;
 		}
 
 		if (argc) {
 			g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
-			return NMC_RESULT_ERROR_USER_INPUT;
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			return;
 		}
 
 		if (nmc->complete)
-			return nmc->return_value;
+			return;
 
 		show_device_info (device, nmc);
 	} else {
@@ -1800,8 +1814,6 @@ do_device_show (NmCli *nmc, int argc, char **argv)
 
 		g_free (devices);
 	}
-
-	return nmc->return_value;
 }
 
 static gboolean
@@ -2024,8 +2036,8 @@ connect_device_cb (GObject *client, GAsyncResult *result, gpointer user_data)
 	g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
 }
 
-static NMCResultCode
-do_device_connect (NmCli *nmc, int argc, char **argv)
+static void
+do_device_connect (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	NMDevice *device = NULL;
 	AddAndActivateInfo *info;
@@ -2039,16 +2051,18 @@ do_device_connect (NmCli *nmc, int argc, char **argv)
 	device = get_device (nmc, &argc, &argv, &error);
 	if (!device) {
 		g_string_printf (nmc->return_text, _("Error: %s."), error->message);
-		return error->code;
+		nmc->return_value = error->code;
+		return;
 	}
 
 	if (*argv) {
 		g_string_printf (nmc->return_text, _("Error: extra argument not allowed: '%s'."), *argv);
-		return NMC_RESULT_ERROR_USER_INPUT;
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return;
 	}
 
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	/*
 	 * Use nowait_flag instead of should_wait, because exiting has to be postponed
@@ -2079,8 +2093,6 @@ do_device_connect (NmCli *nmc, int argc, char **argv)
 	/* Start progress indication */
 	if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY)
 		progress_id = g_timeout_add (120, progress_cb, device);
-
-	return nmc->return_value;
 }
 
 typedef struct {
@@ -2194,8 +2206,8 @@ reapply_device_cb (GObject *object, GAsyncResult *result, gpointer user_data)
 	}
 }
 
-static NMCResultCode
-do_device_reapply (NmCli *nmc, int argc, char **argv)
+static void
+do_device_reapply (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	NMDevice *device;
 	DeviceCbInfo *info = NULL;
@@ -2209,16 +2221,18 @@ do_device_reapply (NmCli *nmc, int argc, char **argv)
 	device = get_device (nmc, &argc, &argv, &error);
 	if (!device) {
 		g_string_printf (nmc->return_text, _("Error: %s."), error->message);
-		return error->code;
+		nmc->return_value = error->code;
+		return;
 	}
 
 	if (argc) {
 		g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
-		return NMC_RESULT_ERROR_USER_INPUT;
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return;
 	}
 
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	nmc->nowait_flag = (nmc->timeout == 0);
 	nmc->should_wait++;
@@ -2229,8 +2243,6 @@ do_device_reapply (NmCli *nmc, int argc, char **argv)
 
 	/* Now reapply the connection to the device */
 	nm_device_reapply_async (device, NULL, 0, 0, NULL, reapply_device_cb, info);
-
-	return nmc->return_value;
 }
 
 typedef struct {
@@ -2276,6 +2288,8 @@ modify_get_applied_cb (GObject *object,
 	gs_free_error GError *error = NULL;
 	NMConnection *connection;
 	guint64 version_id;
+	int argc;
+	const char *const*argv;
 
 	connection = nm_device_get_applied_connection_finish (device,
 	                                                      result,
@@ -2292,7 +2306,10 @@ modify_get_applied_cb (GObject *object,
 		return;
 	}
 
-	if (!nmc_read_connection_properties (info->nmc, connection, &info->argc, &info->argv, &error)) {
+	argc = info->argc;
+	argv = (const char *const*) info->argv;
+
+	if (!nmc_process_connection_properties (info->nmc, connection, &argc, &argv, TRUE, &error)) {
 		g_string_assign (nmc->return_text, error->message);
 		nmc->return_value = error->code;
 		g_slice_free (ModifyInfo, info);
@@ -2306,8 +2323,8 @@ modify_get_applied_cb (GObject *object,
 		nm_device_reapply_async (device, connection, version_id, 0, NULL, modify_reapply_cb, info);
 }
 
-static NMCResultCode
-do_device_modify (NmCli *nmc, int argc, char **argv)
+static void
+do_device_modify (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	NMDevice *device = NULL;
 	ModifyInfo *info = NULL;
@@ -2317,7 +2334,8 @@ do_device_modify (NmCli *nmc, int argc, char **argv)
 	device = get_device (nmc, &argc, &argv, &error);
 	if (!device) {
 		g_string_printf (nmc->return_text, _("Error: %s."), error->message);
-		return error->code;
+		nmc->return_value = error->code;
+		return;
 	}
 
 	if (nmc->timeout == -1)
@@ -2329,11 +2347,9 @@ do_device_modify (NmCli *nmc, int argc, char **argv)
 	info = g_slice_new0 (ModifyInfo);
 	info->nmc = nmc;
 	info->argc = argc;
-	info->argv = argv;
+	info->argv = nm_utils_strv_dup ((char **) argv, argc, TRUE);
 
 	nm_device_get_applied_connection_async (device, 0, NULL, modify_get_applied_cb, info);
-
-	return nmc->return_value;
 }
 
 static void
@@ -2373,8 +2389,8 @@ disconnect_device_cb (GObject *object, GAsyncResult *result, gpointer user_data)
 	}
 }
 
-static NMCResultCode
-do_devices_disconnect (NmCli *nmc, int argc, char **argv)
+static void
+do_devices_disconnect (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	NMDevice *device;
 	DeviceCbInfo *info = NULL;
@@ -2387,7 +2403,7 @@ do_devices_disconnect (NmCli *nmc, int argc, char **argv)
 	next_arg (nmc, &argc, &argv, NULL);
 	queue = get_device_list (nmc, argc, argv);
 	if (!queue)
-		return nmc->return_value;
+		return;
 	if (nmc->complete)
 		goto out;
 	queue = g_slist_reverse (queue);
@@ -2418,7 +2434,6 @@ do_devices_disconnect (NmCli *nmc, int argc, char **argv)
 
 out:
 	g_slist_free (queue);
-	return nmc->return_value;
 }
 
 static void
@@ -2445,8 +2460,8 @@ delete_device_cb (GObject *object, GAsyncResult *result, gpointer user_data)
 	}
 }
 
-static NMCResultCode
-do_devices_delete (NmCli *nmc, int argc, char **argv)
+static void
+do_devices_delete (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	NMDevice *device;
 	DeviceCbInfo *info = NULL;
@@ -2459,7 +2474,7 @@ do_devices_delete (NmCli *nmc, int argc, char **argv)
 	next_arg (nmc, &argc, &argv, NULL);
 	queue = get_device_list (nmc, argc, argv);
 	if (!queue)
-		return nmc->return_value;
+		return;
 	if (nmc->complete)
 		goto out;
 	queue = g_slist_reverse (queue);
@@ -2483,11 +2498,10 @@ do_devices_delete (NmCli *nmc, int argc, char **argv)
 
 out:
 	g_slist_free (queue);
-	return nmc->return_value;
 }
 
-static NMCResultCode
-do_device_set (NmCli *nmc, int argc, char **argv)
+static void
+do_device_set (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 #define DEV_SET_AUTOCONNECT 0
 #define DEV_SET_MANAGED     1
@@ -2509,12 +2523,14 @@ do_device_set (NmCli *nmc, int argc, char **argv)
 	device = get_device (nmc, &argc, &argv, &error);
 	if (!device) {
 		g_string_printf (nmc->return_text, _("Error: %s."), error->message);
-		return error->code;
+		nmc->return_value = error->code;
+		return;
 	}
 
 	if (!argc) {
 		g_string_printf (nmc->return_text, _("Error: No property specified."));
-		return NMC_RESULT_ERROR_USER_INPUT;
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return;
 	}
 
 	i = 0;
@@ -2529,14 +2545,16 @@ do_device_set (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			if (argc == 1 && nmc->complete)
 				nmc_complete_bool (*argv);
 			if (!nmc_string_to_bool (*argv, &flag, &error)) {
 				g_string_printf (nmc->return_text, _("Error: 'managed': %s."),
 				                 error->message);
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			values[DEV_SET_MANAGED].idx = ++i;
 			values[DEV_SET_MANAGED].value = flag;
@@ -2546,26 +2564,29 @@ do_device_set (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			if (argc == 1 && nmc->complete)
 				nmc_complete_bool (*argv);
 			if (!nmc_string_to_bool (*argv, &flag, &error)) {
 				g_string_printf (nmc->return_text, _("Error: 'autoconnect': %s."),
 				                 error->message);
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			values[DEV_SET_AUTOCONNECT].idx = ++i;
 			values[DEV_SET_AUTOCONNECT].value = flag;
 		}
 		else {
 			g_string_printf (nmc->return_text, _("Error: property '%s' is not known."), *argv);
-			return NMC_RESULT_ERROR_USER_INPUT;
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			return;
 		}
 	} while (next_arg (nmc, &argc, &argv, NULL) == 0);
 
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	/* when multiple properties are specified, set them in the order as they
 	 * are specified on the command line. */
@@ -2579,8 +2600,6 @@ do_device_set (NmCli *nmc, int argc, char **argv)
 		nm_device_set_autoconnect (device, values[DEV_SET_AUTOCONNECT].value);
 	if (values[DEV_SET_MANAGED].idx >= 0)
 		nm_device_set_managed (device, values[DEV_SET_MANAGED].value);
-
-	return nmc->return_value;
 }
 
 static void
@@ -2645,11 +2664,11 @@ device_removed (NMClient *client, NMDevice *device, NmCli *nmc)
 	device_unwatch (nmc, device);
 }
 
-static NMCResultCode
-do_devices_monitor (NmCli *nmc, int argc, char **argv)
+static void
+do_devices_monitor (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	next_arg (nmc, &argc, &argv, NULL);
 	if (argc == 0) {
@@ -2674,7 +2693,6 @@ do_devices_monitor (NmCli *nmc, int argc, char **argv)
 	}
 
 	g_signal_connect (nmc->client, NM_CLIENT_DEVICE_REMOVED, G_CALLBACK (device_removed), nmc);
-	return nmc->return_value;
 }
 
 /*
@@ -2779,7 +2797,6 @@ show_access_point_info (NMDeviceWifi *wifi, NmCli *nmc, NmcOutputData *out)
 {
 	NMAccessPoint *active_ap = NULL;
 	const char *active_bssid = NULL;
-	GPtrArray *aps;
 	NmcOutputField *arr;
 
 	if (nm_device_get_state (NM_DEVICE (wifi)) == NM_DEVICE_STATE_ACTIVATED) {
@@ -2792,6 +2809,7 @@ show_access_point_info (NMDeviceWifi *wifi, NmCli *nmc, NmcOutputData *out)
 	g_ptr_array_add (out->output_data, arr);
 
 	{
+		gs_unref_ptrarray GPtrArray *aps = NULL;
 		APInfo info = {
 			.nmc = nmc,
 			.index = 1,
@@ -2803,7 +2821,6 @@ show_access_point_info (NMDeviceWifi *wifi, NmCli *nmc, NmcOutputData *out)
 
 		aps = sort_access_points (nm_device_wifi_get_access_points (wifi));
 		g_ptr_array_foreach (aps, fill_output_access_point, &info);
-		g_ptr_array_free (aps, TRUE);
 	}
 
 	print_data_prepare_width (out->output_data);
@@ -2814,7 +2831,8 @@ wifi_print_aps (NMDeviceWifi *wifi,
                 NmCli *nmc,
                 GArray *_out_indices,
                 const NMMetaAbstractInfo *const*tmpl,
-                const char *bssid_user)
+                const char *bssid_user,
+                gboolean *bssid_found)
 {
 	NMAccessPoint *ap = NULL;
 	const GPtrArray *aps;
@@ -2838,14 +2856,13 @@ wifi_print_aps (NMDeviceWifi *wifi,
 		/* Specific AP requested - list only that */
 		aps = nm_device_wifi_get_access_points (wifi);
 		for (i = 0; i < aps->len; i++) {
-			char *bssid_up;
 			NMAccessPoint *candidate_ap = g_ptr_array_index (aps, i);
-			const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap);
 
-			bssid_up = g_ascii_strup (bssid_user, -1);
-			if (!strcmp (bssid_up, candidate_bssid))
+			if (nm_utils_hwaddr_matches (bssid_user,
+			                             -1,
+			                             nm_access_point_get_bssid (candidate_ap),
+			                             -1))
 				ap = candidate_ap;
-			g_free (bssid_up);
 		}
 		if (ap) {
 			/* Add headers (field names) */
@@ -2863,25 +2880,38 @@ wifi_print_aps (NMDeviceWifi *wifi,
 			fill_output_access_point (ap, info);
 
 			print_data_prepare_width (out.output_data);
-			print_data (&nmc->nmc_config, out_indices, header_name, 0, &out);
+			print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, header_name, 0, &out);
 			g_free (info);
 
-			nmc->return_value = NMC_RESULT_SUCCESS;
+			*bssid_found = TRUE;
 			empty_line = TRUE;
 		}
 	} else {
 		show_access_point_info (wifi, nmc, &out);
-		print_data (&nmc->nmc_config, out_indices, header_name, 0, &out);
+		print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, header_name, 0, &out);
 		empty_line = TRUE;
 	}
 }
 
+static gint64
+_device_wifi_get_last_scan (NMDeviceWifi *wifi)
+{
+	gint64 timestamp;
+
+	timestamp = nm_device_wifi_get_last_scan (wifi);
+	if (timestamp == -1)
+		return G_MININT64;
+	return timestamp;
+}
+
 typedef struct {
 	NmCli *nmc;
 	NMDevice **devices;
 	const NMMetaAbstractInfo *const *tmpl;
-	const char *bssid_user;
+	char *bssid_user;
 	GArray *out_indices;
+	gint64 rescan_cutoff_msec;
+	guint pending;
 } ScanInfo;
 
 typedef struct {
@@ -2893,79 +2923,94 @@ typedef struct {
 } WifiListData;
 
 static void
-wifi_list_finish (WifiListData *data)
+wifi_list_finish (WifiListData *wifi_list_data,
+                  gboolean force_finished)
 {
-	ScanInfo *info = data->scan_info;
-	NmCli *nmc = info->nmc;
+	ScanInfo *scan_info = wifi_list_data->scan_info;
+	NmCli *nmc = scan_info->nmc;
+	gboolean bssid_found = FALSE;
 	guint i;
 
-	if (--info->nmc->should_wait == 0) {
-		for (i = 0; info->devices[i]; i++) {
-			wifi_print_aps (NM_DEVICE_WIFI (info->devices[i]),
-			                info->nmc,
-			                info->out_indices,
-			                info->tmpl,
-			                info->bssid_user);
-		}
-		if (nmc->return_value == NMC_RESULT_ERROR_NOT_FOUND) {
-			g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."),
-			                 data->scan_info->bssid_user);
-		}
-		g_main_loop_quit (loop);
+	if (   !force_finished
+	    && scan_info->rescan_cutoff_msec > _device_wifi_get_last_scan (wifi_list_data->wifi)) {
+		/* wait longer... */
+		return;
+	}
+
+	nm_clear_g_signal_handler (wifi_list_data->wifi, &wifi_list_data->last_scan_id);
+	nm_clear_g_source (&wifi_list_data->timeout_id);
+	nm_clear_g_cancellable (&wifi_list_data->scan_cancellable);
+	nm_g_slice_free (wifi_list_data);
+
+	if (--scan_info->pending > 0)
+		return;
+
+	for (i = 0; scan_info->devices[i]; i++) {
+		wifi_print_aps (NM_DEVICE_WIFI (scan_info->devices[i]),
+		                nmc,
+		                scan_info->out_indices,
+		                scan_info->tmpl,
+		                scan_info->bssid_user,
+		                &bssid_found);
 	}
 
-	g_signal_handler_disconnect (data->wifi, data->last_scan_id);
-	nm_clear_g_source (&data->timeout_id);
-	nm_clear_g_cancellable (&data->scan_cancellable);
-	g_slice_free (WifiListData, data);
-
-	if (info->nmc->should_wait == 0) {
-		for (i = 0; info->devices[i]; i++)
-			g_object_unref (info->devices[i]);
-		g_free (info->devices);
-		g_array_unref (info->out_indices);
-		g_free (info);
+	if (   scan_info->bssid_user
+	    && !bssid_found) {
+		nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+		g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."),
+		                 scan_info->bssid_user);
 	}
+
+	for (i = 0; scan_info->devices[i]; i++)
+		g_object_unref (scan_info->devices[i]);
+	g_free (scan_info->devices);
+	g_array_unref (scan_info->out_indices);
+	g_free (scan_info->bssid_user);
+	nm_g_slice_free (scan_info);
+
+	nmc->should_wait--;
+	g_main_loop_quit (loop);
 }
 
 static void
 wifi_last_scan_updated (GObject *gobject, GParamSpec *pspec, gpointer user_data)
 {
-	WifiListData *data = user_data;
-
-	wifi_list_finish (data);
+	wifi_list_finish (user_data, FALSE);
 }
 
 static void
 wifi_list_rescan_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
 {
 	NMDeviceWifi *wifi = NM_DEVICE_WIFI (source_object);
-	WifiListData *data = user_data;
 	gs_free_error GError *error = NULL;
+	WifiListData *wifi_list_data;
+	gboolean force_finished;
 
-	if (!nm_device_wifi_request_scan_finish (wifi, res, &error)) {
-		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
-			return;
+	nm_device_wifi_request_scan_finish (wifi, res, &error);
+	if (nm_utils_error_is_cancelled (error))
+		return;
 
-		if (g_error_matches (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ALLOWED)) {
-			/* This likely means that scanning is already in progress. There's
-			 * a good chance we'll get updated results soon; wait for them. */
-			return;
-		}
+	if (g_error_matches (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ALLOWED)) {
+		/* This likely means that scanning is already in progress. There's
+		 * a good chance we'll get updated results soon; wait for them. */
+		force_finished = FALSE;
+	} else if (error)
+		force_finished = TRUE;
+	else
+		force_finished = FALSE;
 
-		/* Scanning could not be initiated for unknown reason,
-		 * no point in waiting for results. */
-		wifi_list_finish (data);
-	}
+	wifi_list_data = user_data;
+	g_clear_object (&wifi_list_data->scan_cancellable);
+	wifi_list_finish (wifi_list_data, force_finished);
 }
 
 static gboolean
 wifi_list_scan_timeout (gpointer user_data)
 {
-	WifiListData *data = user_data;
-
-	wifi_list_finish (data);
+	WifiListData *wifi_list_data = user_data;
 
+	wifi_list_data->timeout_id = 0;
+	wifi_list_finish (user_data, TRUE);
 	return G_SOURCE_REMOVE;
 }
 
@@ -2989,8 +3034,8 @@ nmc_complete_bssid (NMClient *client, const char *ifname, const char *bssid_pref
 	complete_aps (devices, ifname, bssid_prefix, NULL);
 }
 
-static NMCResultCode
-do_device_wifi_list (NmCli *nmc, int argc, char **argv)
+static void
+do_device_wifi_list (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	GError *error = NULL;
 	NMDevice *device = NULL;
@@ -3002,10 +3047,10 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 	const NMMetaAbstractInfo *const*tmpl;
 	gs_unref_array GArray *out_indices = NULL;
 	int option;
-	guint64 rescan_cutoff;
-	NMDeviceWifi *wifi;
+	gint64 rescan_cutoff_msec;
 	ScanInfo *scan_info = NULL;
-	WifiListData *data;
+	gboolean ifname_handled;
+	NMDevice *ifname_handled_candidate;
 	guint i, j;
 
 	devices = nmc_get_devices_sorted (nmc->client);
@@ -3017,7 +3062,8 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			ifname = *argv;
 			if (argc == 1 && nmc->complete)
@@ -3029,20 +3075,20 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			bssid_user = *argv;
 			if (argc == 1 && nmc->complete)
 				complete_aps (devices, NULL, bssid_user, NULL);
-			/* We'll switch this to NMC_RESULT_SUCCESS if we find an access point. */
-			nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
 			break;
 		case 4: /* --rescan */
 			argc--;
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			rescan = *argv;
 			if (argc == 1 && nmc->complete)
@@ -3054,9 +3100,12 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 		}
 	}
 
-	if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
+	if (nmc->complete)
+		return;
+
+	if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0)
 		fields_str = NMC_FIELDS_DEV_WIFI_LIST_COMMON;
-	else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) {
+	else if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "all") == 0) {
 	} else
 		fields_str = nmc->required_fields;
 
@@ -3066,101 +3115,134 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 	if (error) {
 		g_string_printf (nmc->return_text, _("Error: 'device wifi': %s"), error->message);
 		g_error_free (error);
-		return NMC_RESULT_ERROR_USER_INPUT;
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return;
 	}
 
-	if (nmc->complete)
-		return nmc->return_value;
-
 	if (argc) {
 		g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
-		return NMC_RESULT_ERROR_USER_INPUT;
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return;
 	}
 
-	if (rescan == NULL || strcmp (rescan, "auto") == 0) {
-		rescan_cutoff = NM_MAX (nm_utils_get_timestamp_msec () - 30 * NM_UTILS_MSEC_PER_SECOND, 0);
-	} else if (strcmp (rescan, "no") == 0) {
-		rescan_cutoff = 0;
-	} else if (strcmp (rescan, "yes") == 0) {
-		rescan_cutoff = -1;
-	} else {
+	if (NM_IN_STRSET (rescan, NULL, "auto"))
+		rescan_cutoff_msec = nm_utils_get_timestamp_msec () - (30 * NM_UTILS_MSEC_PER_SEC);
+	else if (nm_streq (rescan, "no"))
+		rescan_cutoff_msec = G_MININT64;
+	else if (nm_streq (rescan, "yes"))
+		rescan_cutoff_msec = nm_utils_get_timestamp_msec ();
+	else {
 		g_string_printf (nmc->return_text, _("Error: invalid rescan argument: '%s' not among [auto, no, yes]"), rescan);
-		return NMC_RESULT_ERROR_USER_INPUT;
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return;
 	}
 
-	if (ifname) {
-		device = find_wifi_device_by_iface (devices, ifname, NULL);
-		if (!device) {
-			g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname);
-			return NMC_RESULT_ERROR_NOT_FOUND;
+	ifname_handled = (ifname == NULL);
+	ifname_handled_candidate = NULL;
+
+	j = 0;
+	for (i = 0; devices[i]; i++) {
+		const char *dev_iface;
+
+		device = devices[i];
+		dev_iface = nm_device_get_iface (device);
+
+		if (ifname) {
+			if (!nm_streq0 (ifname, dev_iface))
+				continue;
+			if (!NM_IS_DEVICE_WIFI (device)) {
+				if (   nm_device_get_device_type (device) == NM_DEVICE_TYPE_GENERIC
+				    && nm_streq0 (nm_device_get_type_description (device), "wifi"))
+					ifname_handled_candidate = device;
+				else if (!ifname_handled_candidate)
+					ifname_handled_candidate = device;
+				continue;
+			}
+			ifname_handled = TRUE;
+		} else {
+			if (!NM_IS_DEVICE_WIFI (device))
+				continue;
 		}
 
-		if (NM_IS_DEVICE_WIFI (device)) {
-			devices[0] = device;
-			devices[1] = NULL;
+		devices[j++] = device;
+	}
+	devices[j] = NULL;
+
+	if (!ifname_handled) {
+		if (!ifname_handled_candidate) {
+			g_string_printf (nmc->return_text,
+			                 _("Error: Device '%s' not found."),
+			                 ifname);
+		} else if (   nm_device_get_device_type (ifname_handled_candidate) == NM_DEVICE_TYPE_GENERIC
+		           && nm_streq0 (nm_device_get_type_description (ifname_handled_candidate), "wifi")) {
+			g_string_printf (nmc->return_text,
+			                 _("Error: Device '%s' was not recognized as a Wi-Fi device, check NetworkManager Wi-Fi plugin."),
+			                 ifname);
 		} else {
-			if (   nm_device_get_device_type (device) == NM_DEVICE_TYPE_GENERIC
-			    && g_strcmp0 (nm_device_get_type_description (device), "wifi") == 0) {
-				g_string_printf (nmc->return_text,
-				                 _("Error: Device '%s' was not recognized as a Wi-Fi device, check NetworkManager Wi-Fi plugin."),
-				                 ifname);
-			} else {
-				g_string_printf (nmc->return_text,
-				                 _("Error: Device '%s' is not a Wi-Fi device."),
-				                 ifname);
-			}
-			return NMC_RESULT_ERROR_UNKNOWN;
+			g_string_printf (nmc->return_text,
+			                 _("Error: Device '%s' is not a Wi-Fi device."),
+			                 ifname);
 		}
+		nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+		return;
 	}
 
-	/* Filter out non-wifi devices */
-	for (i = 0, j = 0; devices[i]; i++) {
-		if (NM_IS_DEVICE_WIFI (devices[i]))
-			devices[j++] = devices[i];
+	if (!devices[0]) {
+		if (bssid_user) {
+			nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+			g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."),
+			                 bssid_user);
+			nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+		}
+		return;
 	}
-	devices[j] = NULL;
 
-	/* Start a new scan for devices that need it */
-	for (i = 0; devices[i]; i++) {
-		wifi = (NMDeviceWifi *) devices[i];
-		g_object_ref (wifi);
+	scan_info = g_slice_new (ScanInfo);
+	*scan_info = (ScanInfo) {
+		.out_indices        = g_array_ref (out_indices),
+		.tmpl               = tmpl,
+		.bssid_user         = g_strdup (bssid_user),
+		.nmc                = nmc,
+		.rescan_cutoff_msec = rescan_cutoff_msec,
+	};
 
-		if (   rescan_cutoff == 0
-		    || (rescan_cutoff > 0 && nm_device_wifi_get_last_scan (wifi) >= rescan_cutoff))
-			continue;
+	for (i = 0; devices[i]; i++)
+		g_object_ref (devices[i]);
 
-		if (!scan_info) {
-			scan_info = g_new0 (ScanInfo, 1);
-			scan_info->out_indices = g_array_ref (out_indices);
-			scan_info->tmpl = tmpl;
-			scan_info->bssid_user = bssid_user;
-			scan_info->nmc = nmc;
-		}
+	for (i = 0; devices[i]; i++) {
+		NMDeviceWifi *wifi = NM_DEVICE_WIFI (devices[i]);
+		WifiListData *wifi_list_data;
+		int timeout_msec;
 
-		nmc->should_wait++;
-		data = g_slice_new0 (WifiListData);
-		data->wifi = wifi;
-		data->scan_info = scan_info;
-		data->last_scan_id = g_signal_connect (wifi, "notify::" NM_DEVICE_WIFI_LAST_SCAN,
-		                                       G_CALLBACK (wifi_last_scan_updated), data);
-		data->scan_cancellable = g_cancellable_new ();
-		data->timeout_id = g_timeout_add_seconds (15, wifi_list_scan_timeout, data);
-		nm_device_wifi_request_scan_async (wifi, data->scan_cancellable, wifi_list_rescan_cb, data);
-	}
+		if (rescan_cutoff_msec <= _device_wifi_get_last_scan (wifi))
+			timeout_msec = 0;
+		else
+			timeout_msec = 15000;
+
+		wifi_list_data = g_slice_new (WifiListData);
+		*wifi_list_data = (WifiListData) {
+			.wifi             = wifi,
+			.scan_info        = scan_info,
+			.timeout_id       = g_timeout_add (timeout_msec,
+			                                   wifi_list_scan_timeout,
+			                                   wifi_list_data),
+		};
 
-	if (scan_info) {
-		scan_info->devices = g_steal_pointer (&devices);
-	} else {
-		/* Print results right away if no scan is pending */
-		for (i = 0; devices[i]; i++) {
-			wifi_print_aps (NM_DEVICE_WIFI (devices[i]),
-			                nmc, out_indices,
-			                tmpl, bssid_user);
-			g_object_unref (devices[i]);
+		scan_info->pending++;
+
+		if (timeout_msec > 0) {
+			wifi_list_data->last_scan_id = g_signal_connect (wifi,
+			                                                 "notify::" NM_DEVICE_WIFI_LAST_SCAN,
+			                                                 G_CALLBACK (wifi_last_scan_updated),
+			                                                 wifi_list_data),
+			wifi_list_data->scan_cancellable = g_cancellable_new (),
+			nm_device_wifi_request_scan_async (wifi, wifi_list_data->scan_cancellable, wifi_list_rescan_cb, wifi_list_data);
 		}
 	}
 
-	return nmc->return_value;
+	scan_info->devices = g_steal_pointer (&devices);
+
+	nmc->should_wait++;
 }
 
 static void
@@ -3224,8 +3306,8 @@ save_and_activate_connection (NmCli *nmc,
 	}
 }
 
-static NMCResultCode
-do_device_wifi_connect (NmCli *nmc, int argc, char **argv)
+static void
+do_device_wifi_connect (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	NMDevice *device = NULL;
 	NMAccessPoint *ap = NULL;
@@ -3561,8 +3643,8 @@ do_device_wifi_connect (NmCli *nmc, int argc, char **argv)
 
 	/* Set password for WEP or WPA-PSK. */
 	if (   (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
-	    || ap_wpa_flags != NM_802_11_AP_SEC_NONE
-	    || ap_rsn_flags != NM_802_11_AP_SEC_NONE) {
+	    || (ap_wpa_flags != NM_802_11_AP_SEC_NONE && !(ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_OWE))
+	    || (ap_rsn_flags != NM_802_11_AP_SEC_NONE && !(ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_OWE))) {
 		const char *con_password = NULL;
 		NMSettingWirelessSecurity *s_wsec = NULL;
 
@@ -3634,9 +3716,7 @@ finish:
 	if (bssid2_arr)
 		g_byte_array_free (bssid2_arr, TRUE);
 	g_free (ssid_ask);
-	g_free (passwd_ask);
-
-	return nmc->return_value;
+	nm_free_secret (passwd_ask);
 }
 
 static GBytes *
@@ -3865,8 +3945,8 @@ create_hotspot_conn (const GPtrArray *connections,
 	return connection;
 }
 
-static NMCResultCode
-do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
+static void
+do_device_wifi_hotspot (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	const char *ifname = NULL;
 	const char *con_name = NULL;
@@ -3903,7 +3983,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			ifname = *argv;
 			if (argc == 1 && nmc->complete)
@@ -3913,7 +3994,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			con_name = *argv;
 		} else if (strcmp (*argv, "ssid") == 0) {
@@ -3921,11 +4003,13 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			if (strlen (*argv) > 32) {
 				g_string_printf (nmc->return_text, _("Error: ssid is too long."));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			ssid_bytes = g_bytes_new (*argv, strlen (*argv));
 		} else if (strcmp (*argv, "band") == 0) {
@@ -3933,7 +4017,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			band = *argv;
 			if (argc == 1 && nmc->complete)
@@ -3941,14 +4026,16 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **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);
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 		} else if (strcmp (*argv, "channel") == 0) {
 			argc--;
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			channel = *argv;
 		} else if (strcmp (*argv, "password") == 0) {
@@ -3956,7 +4043,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			password = *argv;
 		/* --show-password is deprecated in favour of global --show-secrets option */
@@ -3965,7 +4053,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 			show_password = TRUE;
 		} else {
 			g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
-			return NMC_RESULT_ERROR_USER_INPUT;
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			return;
 		}
 
 		next_arg (nmc, &argc, &argv, NULL);
@@ -3973,7 +4062,7 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 	show_password = nmc->nmc_config.show_secrets || show_password;
 
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	/* Verify band and channel parameters */
 	if (!channel) {
@@ -3987,13 +4076,15 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 
 		if (!band) {
 			g_string_printf (nmc->return_text, _("Error: channel requires band too."));
-			return NMC_RESULT_ERROR_USER_INPUT;
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			return;
 		}
 		if (   !nmc_string_to_uint (channel, TRUE, 1, 5825, &value)
 		    || !nm_utils_wifi_is_channel_valid (value, band)) {
 			g_string_printf (nmc->return_text, _("Error: channel '%s' not valid for band '%s'."),
 			                 channel, band);
-			return NMC_RESULT_ERROR_USER_INPUT;
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			return;
 		}
 
 		channel_int = value;
@@ -4006,7 +4097,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 			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."));
-		return NMC_RESULT_ERROR_UNKNOWN;
+		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+		return;
 	}
 
 	/* Check device supported mode */
@@ -4018,7 +4110,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 	else {
 		g_string_printf (nmc->return_text, _("Error: Device '%s' supports neither AP nor Ad-Hoc mode."),
 		                 nm_device_get_iface (device));
-		return NMC_RESULT_ERROR_UNKNOWN;
+		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+		return;
 	}
 
 	connections = nm_client_get_connections (nmc->client);
@@ -4034,13 +4127,14 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 
 	if (password || !NM_IS_REMOTE_CONNECTION (connection)) {
 		s_wsec = nm_connection_get_setting_wireless_security (connection);
-		g_return_val_if_fail (s_wsec, NMC_RESULT_ERROR_UNKNOWN);
+		g_return_if_fail (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);
 			g_clear_error (&error);
-			return NMC_RESULT_ERROR_UNKNOWN;
+			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+			return;
 		}
 	}
 
@@ -4049,8 +4143,6 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv)
 	nmc->should_wait++;
 
 	save_and_activate_connection (nmc, device, connection, TRUE, NULL);
-
-	return nmc->return_value;
 }
 
 static void
@@ -4068,16 +4160,15 @@ request_rescan_cb (GObject *object, GAsyncResult *result, gpointer user_data)
 	quit ();
 }
 
-static NMCResultCode
-do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
+static void
+do_device_wifi_rescan (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	NMDevice *device;
 	const char *ifname = NULL;
-	GPtrArray *ssids;
+	gs_unref_ptrarray GPtrArray *ssids = NULL;
 	gs_free NMDevice **devices = NULL;
 	GVariantBuilder builder, array_builder;
 	GVariant *options;
-	const char *ssid;
 	int i;
 
 	ssids = g_ptr_array_new ();
@@ -4093,14 +4184,14 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
 			if (ifname) {
 				g_string_printf (nmc->return_text, _("Error: '%s' cannot repeat."), *(argv-1));
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				goto finish;
+				return;
 			}
 			argc--;
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				goto finish;
+				return;
 			}
 			ifname = *argv;
 			if (argc == 1 && nmc->complete)
@@ -4111,20 +4202,20 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
 				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-				goto finish;
+				return;
 			}
-			g_ptr_array_add (ssids, *argv);
+			g_ptr_array_add (ssids, (gpointer) *argv);
 		} else if (!nmc->complete) {
 			g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
 			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-			goto finish;
+			return;
 		}
 
 		next_arg (nmc, &argc, &argv, NULL);
 	}
 
 	if (nmc->complete)
-		goto finish;
+		return;
 
 	/* Find Wi-Fi device to scan on. When no ifname is provided, the first Wi-Fi is used. */
 	device = find_wifi_device_by_iface (devices, ifname, NULL);
@@ -4135,7 +4226,7 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
 		else
 			g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found."));
 		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-		goto finish;
+		return;
 	}
 
 	if (ssids->len) {
@@ -4143,7 +4234,8 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
 		g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aay"));
 
 		for (i = 0; i < ssids->len; i++) {
-			ssid = g_ptr_array_index (ssids, i);
+			const char *ssid = g_ptr_array_index (ssids, i);
+
 			g_variant_builder_add (&array_builder, "@ay",
 			                       g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, ssid, strlen (ssid), 1));
 		}
@@ -4158,9 +4250,6 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
 		                                   NULL, request_rescan_cb, nmc);
 
 	nmc->should_wait++;
-finish:
-	g_ptr_array_free (ssids, FALSE);
-	return nmc->return_value;
 }
 
 static void
@@ -4234,6 +4323,9 @@ print_wifi_connection (const NmcConfig *nmc_config, NMConnection *connection)
 	           || strcmp (key_mgmt, "sae") == 0) {
 		type = "WPA";
 		g_print ("%s: WPA\n", _("Security"));
+	} else if (   strcmp (key_mgmt, "owe") == 0) {
+		type = "nopass";
+		g_print ("%s: OWE\n", _("Security"));
 	}
 
 	if (psk)
@@ -4296,8 +4388,8 @@ wifi_show_device (const NmcConfig *nmc_config, NMDevice *device, GError **error)
 	return TRUE;
 }
 
-static NMCResultCode
-do_device_wifi_show_password (NmCli *nmc, int argc, char **argv)
+static void
+do_device_wifi_show_password (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	const char *ifname = NULL;
 	gs_free NMDevice **devices = NULL;
@@ -4317,7 +4409,8 @@ do_device_wifi_show_password (NmCli *nmc, int argc, char **argv)
 				g_string_printf (nmc->return_text,
 				                 _("Error: '%s' cannot repeat."),
 				                 *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			argc--;
 			argv++;
@@ -4325,7 +4418,8 @@ do_device_wifi_show_password (NmCli *nmc, int argc, char **argv)
 				g_string_printf (nmc->return_text,
 				                 _("Error: %s argument is missing."),
 				                 *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 			ifname = *argv;
 			if (argc == 1 && nmc->complete)
@@ -4334,14 +4428,15 @@ do_device_wifi_show_password (NmCli *nmc, int argc, char **argv)
 			g_string_printf (nmc->return_text,
 			                 _("Error: invalid extra argument '%s'."),
 			                 *argv);
-			return NMC_RESULT_ERROR_USER_INPUT;
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			return;
 		}
 
 		next_arg (nmc, &argc, &argv, NULL);
 	}
 
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	for (i = 0; devices[i]; i++) {
 		if (ifname && g_strcmp0 (nm_device_get_iface (devices[i]), ifname) != 0)
@@ -4353,7 +4448,8 @@ do_device_wifi_show_password (NmCli *nmc, int argc, char **argv)
 			if (ifname) {
 				g_string_printf (nmc->return_text,
 				                 _("%s"), error->message);
-				return NMC_RESULT_ERROR_UNKNOWN;
+				nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+				return;
 			}
 			g_clear_error (&error);
 		}
@@ -4365,10 +4461,9 @@ do_device_wifi_show_password (NmCli *nmc, int argc, char **argv)
 	if (!found) {
 		g_string_printf (nmc->return_text,
 		                 _("Error: No Wi-Fi device found."));
-		return NMC_RESULT_ERROR_UNKNOWN;
+		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+		return;
 	}
-
-	return nmc->return_value;
 }
 
 static NMCCommand device_wifi_cmds[] = {
@@ -4380,13 +4475,11 @@ static NMCCommand device_wifi_cmds[] = {
 	{ NULL,             do_device_wifi_list,           NULL,  TRUE,  TRUE },
 };
 
-static NMCResultCode
-do_device_wifi (NmCli *nmc, int argc, char **argv)
+static void
+do_device_wifi (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	next_arg (nmc, &argc, &argv, NULL);
 	nmc_do_cmd (nmc, device_wifi_cmds, *argv, argc, argv);
-
-	return nmc->return_value;
 }
 
 static int
@@ -4469,13 +4562,13 @@ show_device_lldp_list (NMDevice *device, NmCli *nmc, const char *fields_str, int
 	}
 
 	print_data_prepare_width (out.output_data);
-	print_data (&nmc->nmc_config, out_indices, header_name, 0, &out);
+	print_data (&nmc->nmc_config, &nmc->pager_data, out_indices, header_name, 0, &out);
 
 	return neighbors->len;
 }
 
-static NMCResultCode
-do_device_lldp_list (NmCli *nmc, int argc, char **argv)
+static void
+do_device_lldp_list (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	NMDevice *device = NULL;
 	gs_free_error GError *error = NULL;
@@ -4493,25 +4586,28 @@ do_device_lldp_list (NmCli *nmc, int argc, char **argv)
 			argv++;
 			if (!argc) {
 				g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 
 			device = get_device (nmc, &argc, &argv, &error);
 			if (!device) {
 				g_string_printf (nmc->return_text, _("Error: %s."), error->message);
-				return error->code;
+				nmc->return_value = error->code;
+				return;
 			}
 		} else {
 			g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
-			return NMC_RESULT_ERROR_USER_INPUT;
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			return;
 		}
 
 		next_arg (nmc, &argc, &argv, NULL);
 	}
 
-	if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
+	if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0)
 		fields_str = NMC_FIELDS_DEV_LLDP_LIST_COMMON;
-	else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) {
+	else if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "all") == 0) {
 	} else
 		fields_str = nmc->required_fields;
 
@@ -4519,25 +4615,22 @@ do_device_lldp_list (NmCli *nmc, int argc, char **argv)
 
 	if (error) {
 		g_string_printf (nmc->return_text, _("Error: 'device lldp list': %s"), error->message);
-		return NMC_RESULT_ERROR_USER_INPUT;
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return;
 	}
 
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	if (device) {
 		show_device_lldp_list (device, nmc, fields_str, &counter);
 	} else {
-		NMDevice **devices = nmc_get_devices_sorted (nmc->client);
-		int i;
+		gs_free NMDevice **devices = nmc_get_devices_sorted (nmc->client);
+		guint i;
 
 		for (i = 0; devices[i]; i++)
 			show_device_lldp_list (devices[i], nmc, fields_str, &counter);
-
-		g_free (devices);
 	}
-
-	return nmc->return_value;
 }
 
 static NMCCommand device_lldp_cmds[] = {
@@ -4545,16 +4638,14 @@ static NMCCommand device_lldp_cmds[] = {
 	{ NULL,    do_device_lldp_list,  NULL,             TRUE,   TRUE },
 };
 
-static NMCResultCode
-do_device_lldp (NmCli *nmc, int argc, char **argv)
+static void
+do_device_lldp (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	if (!nmc->mode_specified)
 		nmc->nmc_config_mutable.multiline_output = TRUE;  /* multiline mode is default for 'device lldp' */
 
 	next_arg (nmc, &argc, &argv, NULL);
 	nmc_do_cmd (nmc, device_lldp_cmds, *argv, argc, argv);
-
-	return nmc->return_value;
 }
 
 static gboolean
@@ -4599,38 +4690,35 @@ nmcli_device_tab_completion (const char *text, int start, int end)
 	return match_array;
 }
 
-static const NMCCommand device_cmds[] = {
-	{ "status",      do_devices_status,      usage_device_status,      TRUE,   TRUE },
-	{ "show",        do_device_show,         usage_device_show,        TRUE,   TRUE },
-	{ "connect",     do_device_connect,      usage_device_connect,     TRUE,   TRUE },
-	{ "reapply",     do_device_reapply,      usage_device_reapply,     TRUE,   TRUE },
-	{ "disconnect",  do_devices_disconnect,  usage_device_disconnect,  TRUE,   TRUE },
-	{ "delete",      do_devices_delete,      usage_device_delete,      TRUE,   TRUE },
-	{ "set",         do_device_set,          usage_device_set,         TRUE,   TRUE },
-	{ "monitor",     do_devices_monitor,     usage_device_monitor,     TRUE,   TRUE },
-	{ "wifi",        do_device_wifi,         usage_device_wifi,        FALSE,  FALSE },
-	{ "lldp",        do_device_lldp,         usage_device_lldp,        FALSE,  FALSE },
-	{ "modify",      do_device_modify,       usage_device_modify,      TRUE,   TRUE },
-	{ NULL,          do_devices_status,      usage,                    TRUE,   TRUE },
-};
-
-NMCResultCode
-do_devices (NmCli *nmc, int argc, char **argv)
+void
+nmc_command_func_device (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
+	static const NMCCommand cmds[] = {
+		{ "status",     do_devices_status,     usage_device_status,     TRUE,  TRUE  },
+		{ "show",       do_device_show,        usage_device_show,       TRUE,  TRUE  },
+		{ "connect",    do_device_connect,     usage_device_connect,    TRUE,  TRUE  },
+		{ "reapply",    do_device_reapply,     usage_device_reapply,    TRUE,  TRUE  },
+		{ "disconnect", do_devices_disconnect, usage_device_disconnect, TRUE,  TRUE  },
+		{ "delete",     do_devices_delete,     usage_device_delete,     TRUE,  TRUE  },
+		{ "set",        do_device_set,         usage_device_set,        TRUE,  TRUE  },
+		{ "monitor",    do_devices_monitor,    usage_device_monitor,    TRUE,  TRUE  },
+		{ "wifi",       do_device_wifi,        usage_device_wifi,       FALSE, FALSE },
+		{ "lldp",       do_device_lldp,        usage_device_lldp,       FALSE, FALSE },
+		{ "modify",     do_device_modify,      usage_device_modify,     TRUE,  TRUE  },
+		{ NULL,         do_devices_status,     usage,                   TRUE,  TRUE  },
+	};
+
 	next_arg (nmc, &argc, &argv, NULL);
 
-	/* Register polkit agent */
 	nmc_start_polkit_agent_start_try (nmc);
 
 	rl_attempted_completion_function = (rl_completion_func_t *) nmcli_device_tab_completion;
 
-	nmc_do_cmd (nmc, device_cmds, *argv, argc, argv);
-
-	return nmc->return_value;
+	nmc_do_cmd (nmc, cmds, *argv, argc, argv);
 }
 
 void
 monitor_devices (NmCli *nmc)
 {
-	do_devices_monitor (nmc, 0, NULL);
+	do_devices_monitor (NULL, nmc, 0, NULL);
 }
diff --git a/clients/cli/devices.h b/clients/cli/devices.h
index 055d56e7..8b7aa901 100644
--- a/clients/cli/devices.h
+++ b/clients/cli/devices.h
@@ -8,8 +8,6 @@
 
 #include "nmcli.h"
 
-NMCResultCode do_devices (NmCli *nmc, int argc, char **argv);
-
 void nmc_complete_device (NMClient *client, const char *prefix, gboolean wifi_only);
 
 void nmc_complete_bssid (NMClient *client, const char *ifname, const char *bssid_prefix);
diff --git a/clients/cli/general.c b/clients/cli/general.c
index 123cc5b4..747203bb 100644
--- a/clients/cli/general.c
+++ b/clients/cli/general.c
@@ -5,8 +5,6 @@
 
 #include "nm-default.h"
 
-#include "general.h"
-
 #include <stdlib.h>
 
 #include "nm-libnm-core-intern/nm-common-macros.h"
@@ -22,7 +20,14 @@
 
 /*****************************************************************************/
 
-NM_UTILS_LOOKUP_STR_DEFINE_STATIC (nm_state_to_string, NMState,
+static void permission_changed (GObject *gobject,
+                                GParamSpec *pspec,
+                                NmCli *nmc);
+
+/*****************************************************************************/
+
+static
+NM_UTILS_LOOKUP_STR_DEFINE (nm_state_to_string, NMState,
 	NM_UTILS_LOOKUP_DEFAULT (N_("unknown")),
 	NM_UTILS_LOOKUP_ITEM (NM_STATE_ASLEEP,           N_("asleep")),
 	NM_UTILS_LOOKUP_ITEM (NM_STATE_CONNECTING,       N_("connecting")),
@@ -77,47 +82,12 @@ connectivity_to_color (NMConnectivityState connectivity)
 static const char *
 permission_to_string (NMClientPermission perm)
 {
-	switch (perm) {
-	case NM_CLIENT_PERMISSION_ENABLE_DISABLE_NETWORK:
-		return NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK;
-	case NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIFI:
-		return NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI;
-	case NM_CLIENT_PERMISSION_ENABLE_DISABLE_WWAN:
-		return NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN;
-	case NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIMAX:
-		return NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX;
-	case NM_CLIENT_PERMISSION_SLEEP_WAKE:
-		return NM_AUTH_PERMISSION_SLEEP_WAKE;
-	case NM_CLIENT_PERMISSION_NETWORK_CONTROL:
-		return NM_AUTH_PERMISSION_NETWORK_CONTROL;
-	case NM_CLIENT_PERMISSION_WIFI_SHARE_PROTECTED:
-		return NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED;
-	case NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN:
-		return NM_AUTH_PERMISSION_WIFI_SHARE_OPEN;
-	case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM:
-		return NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM;
-	case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_OWN:
-		return NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN;
-	case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_HOSTNAME:
-		return NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME;
-	case NM_CLIENT_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS:
-		return NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS;
-	case NM_CLIENT_PERMISSION_RELOAD:
-		return NM_AUTH_PERMISSION_RELOAD;
-	case NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK:
-		return NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK;
-	case NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS:
-		return NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS;
-	case NM_CLIENT_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK:
-		return NM_AUTH_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK;
-	case NM_CLIENT_PERMISSION_WIFI_SCAN:
-		return NM_AUTH_PERMISSION_WIFI_SCAN;
-	default:
-		return _("unknown");
-	}
+	return    nm_auth_permission_to_string (perm)
+	       ?: _("unknown");
 }
 
-NM_UTILS_LOOKUP_STR_DEFINE_STATIC (permission_result_to_string, NMClientPermissionResult,
+static
+NM_UTILS_LOOKUP_STR_DEFINE (permission_result_to_string, NMClientPermissionResult,
 	NM_UTILS_LOOKUP_DEFAULT (N_("unknown")),
 	NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_YES,  N_("yes")),
 	NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_NO,   N_("no")),
@@ -125,7 +95,8 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (permission_result_to_string, NMClientPermissi
 	NM_UTILS_LOOKUP_ITEM_IGNORE (NM_CLIENT_PERMISSION_RESULT_UNKNOWN),
 );
 
-_NM_UTILS_LOOKUP_DEFINE (static, permission_result_to_color, NMClientPermissionResult, NMMetaColor,
+static
+NM_UTILS_LOOKUP_DEFINE (permission_result_to_color, NMClientPermissionResult, NMMetaColor,
 	NM_UTILS_LOOKUP_DEFAULT (NM_META_COLOR_PERMISSION_UNKNOWN),
 	NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_YES,  NM_META_COLOR_PERMISSION_YES),
 	NM_UTILS_LOOKUP_ITEM (NM_CLIENT_PERMISSION_RESULT_NO,   NM_META_COLOR_PERMISSION_NO),
@@ -497,9 +468,9 @@ show_nm_status (NmCli *nmc, const char *pretty_header_name, const char *print_fl
 	const char *fields_all =    print_flds ?: NMC_FIELDS_NM_STATUS_ALL;
 	const char *fields_common = print_flds ?: NMC_FIELDS_NM_STATUS_COMMON;
 
-	if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
+	if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0)
 		fields_str = fields_common;
-	else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
+	else if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "all") == 0)
 		fields_str = fields_all;
 	else
 		fields_str = nmc->required_fields;
@@ -518,15 +489,14 @@ show_nm_status (NmCli *nmc, const char *pretty_header_name, const char *print_fl
 	return TRUE;
 }
 
-static NMCResultCode
-do_general_status (NmCli *nmc, int argc, char **argv)
+static void
+do_general_status (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	next_arg (nmc, &argc, &argv, NULL);
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	show_nm_status (nmc, NULL, NULL);
-	return nmc->return_value;
 }
 
 static gboolean
@@ -534,32 +504,56 @@ timeout_cb (gpointer user_data)
 {
 	NmCli *nmc = (NmCli *) user_data;
 
+	g_signal_handlers_disconnect_by_func (nmc->client,
+	                                      G_CALLBACK (permission_changed),
+	                                      nmc);
+
 	g_string_printf (nmc->return_text, _("Error: Timeout %d sec expired."), nmc->timeout);
 	nmc->return_value = NMC_RESULT_ERROR_TIMEOUT_EXPIRED;
 	quit ();
 	return FALSE;
 }
 
-static int
+static void
 print_permissions (void *user_data)
 {
 	NmCli *nmc = user_data;
 	gs_free_error GError *error = NULL;
 	const char *fields_str = NULL;
-	NMClientPermission perm;
-	guint i;
-	gpointer permissions[NM_CLIENT_PERMISSION_LAST + 1];
+	gpointer permissions[G_N_ELEMENTS (nm_auth_permission_sorted) + 1];
+	gboolean is_running;
+	int i;
+
+	is_running = nm_client_get_nm_running (nmc->client);
+
+	if (   is_running
+	    && nm_client_get_permissions_state (nmc->client) != NM_TERNARY_TRUE) {
+		/* wait longer. Permissions are not up to date. */
+		return;
+	}
+
+	g_signal_handlers_disconnect_by_func (nmc->client,
+	                                      G_CALLBACK (permission_changed),
+	                                      nmc);
 
-	if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) {
-	} else if (strcasecmp (nmc->required_fields, "all") == 0) {
+	if (!is_running) {
+		/* NetworkManager quit while we were waiting. */
+		g_string_printf (nmc->return_text, _("NetworkManager is not running."));
+		nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+		quit ();
+		return;
+	}
+
+	if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) {
+	} else if (g_ascii_strcasecmp (nmc->required_fields, "all") == 0) {
 	} else
 		fields_str = nmc->required_fields;
 
-	for (i = 0, perm = NM_CLIENT_PERMISSION_NONE + 1; perm <= NM_CLIENT_PERMISSION_LAST; perm++)
-		permissions[i++] = GINT_TO_POINTER (perm);
-	permissions[i++] = NULL;
+	for (i = 0; i < (int) G_N_ELEMENTS (nm_auth_permission_sorted); i++)
+		permissions[i] = GINT_TO_POINTER (nm_auth_permission_sorted[i]);
+	permissions[i] = NULL;
 
-	nm_cli_spawn_pager (nmc);
+	nm_cli_spawn_pager (&nmc->nmc_config, &nmc->pager_data);
 
 	if (!nmc_print (&nmc->nmc_config,
 	                permissions,
@@ -573,64 +567,48 @@ print_permissions (void *user_data)
 	}
 
 	quit ();
-	return G_SOURCE_REMOVE;
-}
-
-static gboolean
-got_permissions (NmCli *nmc)
-{
-	NMClientPermission perm;
-
-	/* The server returns all the permissions at once, so if at least one is there
-	 * we already received the reply. */
-	for (perm = NM_CLIENT_PERMISSION_NONE + 1; perm <= NM_CLIENT_PERMISSION_LAST; perm++) {
-		if (nm_client_get_permission_result (nmc->client, perm) != NM_CLIENT_PERMISSION_RESULT_UNKNOWN)
-			return TRUE;
-	}
-
-	return FALSE;
 }
 
 static void
-permission_changed (NMClient *client,
-                    NMClientPermission permission,
-                    NMClientPermissionResult result,
+permission_changed (GObject *gobject,
+                    GParamSpec *pspec,
                     NmCli *nmc)
 {
-	if (got_permissions (nmc)) {
-		/* Defer the printing, so that we have a chance to process the other
-		 * permission-changed signals. */
-		g_signal_handlers_disconnect_by_func (nmc->client,
-		                                      G_CALLBACK (permission_changed),
-		                                      nmc);
-		g_idle_remove_by_data (nmc);
-		g_idle_add (print_permissions, nmc);
-	}
+	if (NM_IN_STRSET (pspec->name, NM_CLIENT_NM_RUNNING,
+	                               NM_CLIENT_PERMISSIONS_STATE))
+		print_permissions (nmc);
 }
 
 static gboolean
 show_nm_permissions (NmCli *nmc)
 {
-	/* The permissions are available now, just print them. */
-	if (got_permissions (nmc)) {
-		print_permissions (nmc);
-		return TRUE;
-	}
+	NMClientInstanceFlags instance_flags;
+
+	instance_flags = nm_client_get_instance_flags (nmc->client);
+	instance_flags &= ~NM_CLIENT_INSTANCE_FLAGS_NO_AUTO_FETCH_PERMISSIONS;
+
+	g_object_set (nmc->client,
+	              NM_CLIENT_INSTANCE_FLAGS, (guint) instance_flags,
+	              NULL);
 
-	/* The client didn't get the permissions reply yet. Subscribe to changes. */
-	g_signal_connect (nmc->client, NM_CLIENT_PERMISSION_CHANGED,
-	                  G_CALLBACK (permission_changed), nmc);
+	g_signal_connect (nmc->client,
+	                  "notify",
+	                  G_CALLBACK (permission_changed),
+	                  nmc);
 
 	if (nmc->timeout == -1)
 		nmc->timeout = 10;
 	g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
 
 	nmc->should_wait++;
+
+	print_permissions (nmc);
+
 	return TRUE;
 }
 
-static NMCResultCode
-do_general_reload (NmCli *nmc, int argc, char **argv)
+static void
+do_general_reload (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	gs_unref_variant GVariant *result = NULL;
 	gs_free_error GError *error = NULL;
@@ -643,7 +621,7 @@ do_general_reload (NmCli *nmc, int argc, char **argv)
 
 	if (nmc->complete) {
 		if (argc == 0)
-			return nmc->return_value;
+			return;
 
 		if (argc == 1) {
 			values = nm_utils_enum_get_values (nm_manager_reload_flags_get_type (),
@@ -651,7 +629,7 @@ do_general_reload (NmCli *nmc, int argc, char **argv)
 			                                   NM_MANAGER_RELOAD_FLAG_ALL);
 			nmc_complete_strv (*argv, -1, values);
 		}
-		return nmc->return_value;
+		return;
 	}
 
 	if (argc > 0) {
@@ -664,7 +642,8 @@ do_general_reload (NmCli *nmc, int argc, char **argv)
 			                 _("Error: invalid reload flag '%s'. Allowed flags are: %s"),
 			                 err_token,
 			                 joined);
-			return NMC_RESULT_ERROR_USER_INPUT;
+			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+			return;
 		}
 		argc--;
 		argv++;
@@ -672,7 +651,8 @@ do_general_reload (NmCli *nmc, int argc, char **argv)
 
 	if (argc > 0) {
 		g_string_printf (nmc->return_text, _("Error: extra argument '%s'"), *argv);
-		return NMC_RESULT_ERROR_USER_INPUT;
+		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+		return;
 	}
 
 	result = nmc_dbus_call_sync (nmc,
@@ -687,21 +667,18 @@ do_general_reload (NmCli *nmc, int argc, char **argv)
 		g_string_printf (nmc->return_text,
 		                 _("Error: failed to reload: %s"),
 		                 nmc_error_get_simple_message (error));
-		return NMC_RESULT_ERROR_UNKNOWN;
+		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
 	}
-
-	return nmc->return_value;
 }
 
-static NMCResultCode
-do_general_permissions (NmCli *nmc, int argc, char **argv)
+static void
+do_general_permissions (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	next_arg (nmc, &argc, &argv, NULL);
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	show_nm_permissions (nmc);
-	return nmc->return_value;
 }
 
 static void
@@ -716,8 +693,8 @@ show_general_logging (NmCli *nmc)
 		.domains = &domains_cache,
 	};
 
-	if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) {
-	} else if (strcasecmp (nmc->required_fields, "all") == 0) {
+	if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) {
+	} else if (g_ascii_strcasecmp (nmc->required_fields, "all") == 0) {
 	} else
 		fields_str = nmc->required_fields;
 
@@ -750,15 +727,30 @@ nmc_complete_strings_nocase (const char *prefix, ...)
 	va_end (args);
 }
 
-static NMCResultCode
-do_general_logging (NmCli *nmc, int argc, char **argv)
+static void
+_set_logging_cb (GObject *object, GAsyncResult *result, gpointer user_data)
 {
+	NmCli *nmc = user_data;
+	gs_unref_variant GVariant *res = NULL;
 	gs_free_error GError *error = NULL;
 
+	res = nm_client_dbus_call_finish (NM_CLIENT (object), result, &error);
+	if (!res) {
+		g_dbus_error_strip_remote_error (error);
+		g_string_printf (nmc->return_text, _("Error: failed to set logging: %s"),
+		                 nmc_error_get_simple_message (error));
+		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+	}
+	quit ();
+}
+
+static void
+do_general_logging (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
+{
 	next_arg (nmc, &argc, &argv, NULL);
 	if (argc == 0) {
 		if (nmc->complete)
-			return nmc->return_value;
+			return;
 
 		show_general_logging (nmc);
 	} else {
@@ -775,7 +767,8 @@ do_general_logging (NmCli *nmc, int argc, char **argv)
 				argv++;
 				if (!argc) {
 					g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *(argv-1));
-					return NMC_RESULT_ERROR_USER_INPUT;
+					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+					return;
 				}
 				if (argc == 1 && nmc->complete) {
 					nmc_complete_strings_nocase (*argv, "TRACE", "DEBUG", "INFO", "WARN",
@@ -787,7 +780,8 @@ do_general_logging (NmCli *nmc, int argc, char **argv)
 				argv++;
 				if (!argc) {
 					g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *(argv-1));
-					return NMC_RESULT_ERROR_USER_INPUT;
+					nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+					return;
 				}
 				if (argc == 1 && nmc->complete) {
 					nmc_complete_strings_nocase (*argv, "PLATFORM", "RFKILL", "ETHER", "WIFI", "BT",
@@ -801,93 +795,90 @@ do_general_logging (NmCli *nmc, int argc, char **argv)
 				domains = *argv;
 			} else {
 				g_string_printf (nmc->return_text, _("Error: property '%s' is not known."), *argv);
-				return NMC_RESULT_ERROR_USER_INPUT;
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return;
 			}
 		} while (next_arg (nmc, &argc, &argv, NULL) == 0);
 
 		if (nmc->complete)
-			return nmc->return_value;
+			return;
 
-		nm_client_set_logging (nmc->client, level, domains, &error);
-		if (error) {
-			g_string_printf (nmc->return_text, _("Error: failed to set logging: %s"),
-			                 nmc_error_get_simple_message (error));
-			return NMC_RESULT_ERROR_UNKNOWN;
-		}
+		nmc->should_wait++;
+		nm_client_dbus_call (nmc->client,
+		                     NM_DBUS_PATH,
+		                     NM_DBUS_INTERFACE,
+		                     "SetLogging",
+		                     g_variant_new ("(ss)",
+		                                    level ?: "",
+		                                    domains ?: ""),
+		                     G_VARIANT_TYPE ("()"),
+		                     -1,
+		                     NULL,
+		                     _set_logging_cb,
+		                     nmc);
 	}
-
-	return nmc->return_value;
 }
 
 static void
 save_hostname_cb (GObject *object, GAsyncResult *result, gpointer user_data)
 {
-	NmCli *nmc = (NmCli *) user_data;
-	GError *error = NULL;
+	NmCli *nmc = user_data;
+	gs_free_error GError *error = NULL;
 
 	nm_client_save_hostname_finish (NM_CLIENT (object), result, &error);
 	if (error) {
 		g_string_printf (nmc->return_text, _("Error: failed to set hostname: %s"),
 		                 error->message);
 		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
-		g_error_free (error);
 	}
+
 	quit ();
 }
 
-static NMCResultCode
-do_general_hostname (NmCli *nmc, int argc, char **argv)
+static void
+do_general_hostname (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
+	const char *hostname;
+
 	next_arg (nmc, &argc, &argv, NULL);
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	if (argc == 0) {
 		/* no arguments -> get hostname */
-		char *hostname = NULL;
-
-		g_object_get (nmc->client, NM_CLIENT_HOSTNAME, &hostname, NULL);
-		if (hostname)
-			g_print ("%s\n", hostname);
-		g_free (hostname);
-	} else {
-		/* hostname provided -> set it */
-		const char *hostname = *argv;
-
-		if (next_arg (nmc, &argc, &argv, NULL) == 0)
-			g_print ("Warning: ignoring extra garbage after '%s' hostname\n", hostname);
+		gs_free char *s = NULL;
 
-		nmc->should_wait++;
-		nm_client_save_hostname_async (nmc->client, hostname, NULL, save_hostname_cb, nmc);
+		g_object_get (nmc->client, NM_CLIENT_HOSTNAME, &s, NULL);
+		if (s)
+			g_print ("%s\n", s);
+		return;
 	}
 
-	return nmc->return_value;
+	hostname = *argv;
+	if (next_arg (nmc, &argc, &argv, NULL) == 0)
+		g_print ("Warning: ignoring extra garbage after '%s' hostname\n", hostname);
 
+	nmc->should_wait++;
+	nm_client_save_hostname_async (nmc->client, hostname, NULL, save_hostname_cb, nmc);
 }
 
-static const NMCCommand general_cmds[] = {
-	{ "status",       do_general_status,       usage_general_status,       TRUE,   TRUE },
-	{ "hostname",     do_general_hostname,     usage_general_hostname,     TRUE,   TRUE },
-	{ "permissions",  do_general_permissions,  usage_general_permissions,  TRUE,   TRUE },
-	{ "logging",      do_general_logging,      usage_general_logging,      TRUE,   TRUE },
-	{ "reload",       do_general_reload,       usage_general_reload,       FALSE,  FALSE },
-	{ NULL,           do_general_status,       usage_general,              TRUE,   TRUE },
-};
-
-/*
- * Entry point function for general operations 'nmcli general'
- */
-NMCResultCode
-do_general (NmCli *nmc, int argc, char **argv)
+void
+nmc_command_func_general (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
+	static const NMCCommand cmds[] = {
+		{ "status",      do_general_status,      usage_general_status,      TRUE,  TRUE  },
+		{ "hostname",    do_general_hostname,    usage_general_hostname,    TRUE,  TRUE  },
+		{ "permissions", do_general_permissions, usage_general_permissions, TRUE,  TRUE  },
+		{ "logging",     do_general_logging,     usage_general_logging,     TRUE,  TRUE  },
+		{ "reload",      do_general_reload,      usage_general_reload,      FALSE, FALSE },
+		{ NULL,          do_general_status,      usage_general,             TRUE,  TRUE  },
+	};
+
 	next_arg (nmc, &argc, &argv, NULL);
 
-	/* Register polkit agent */
 	nmc_start_polkit_agent_start_try (nmc);
 
-	nmc_do_cmd (nmc, general_cmds, *argv, argc, argv);
-
-	return nmc->return_value;
+	nmc_do_cmd (nmc, cmds, *argv, argc, argv);
 }
 
 static gboolean
@@ -896,7 +887,7 @@ nmc_switch_show (NmCli *nmc, const char *switch_name, const char *header)
 	g_return_val_if_fail (nmc != NULL, FALSE);
 	g_return_val_if_fail (switch_name != NULL, FALSE);
 
-	if (nmc->required_fields && strcasecmp (nmc->required_fields, switch_name) != 0) {
+	if (nmc->required_fields && g_ascii_strcasecmp (nmc->required_fields, switch_name) != 0) {
 		g_string_printf (nmc->return_text, _("Error: '--fields' value '%s' is not valid here (allowed field: %s)"),
 		                 nmc->required_fields, switch_name);
 		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
@@ -930,42 +921,62 @@ nmc_switch_parse_on_off (NmCli *nmc, const char *arg1, const char *arg2, gboolea
 	return TRUE;
 }
 
-static NMCResultCode
-do_networking_on_off (NmCli *nmc, int argc, char **argv, gboolean enable)
+static void
+_do_networking_on_off_cb (GObject *object, GAsyncResult *result, gpointer user_data)
 {
-	if (nmc->complete)
-		return nmc->return_value;
-
-	/* Register polkit agent */
-	nmc_start_polkit_agent_start_try (nmc);
-
-	nm_client_networking_set_enabled (nmc->client, enable, NULL);
+	NmCli *nmc = user_data;
+	gs_unref_variant GVariant *ret = NULL;
+	gs_free_error GError *error = NULL;
 
-	return nmc->return_value;
+	ret = nm_client_dbus_call_finish (NM_CLIENT (object), result, &error);
+	if (!ret) {
+		if (g_error_matches (error,
+		                     NM_MANAGER_ERROR,
+		                     NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED)) {
+			/* This is fine. Be quiet about it. */
+		} else {
+			g_dbus_error_strip_remote_error (error);
+			g_string_printf (nmc->return_text, _("Error: failed to set networking: %s"),
+			                 nmc_error_get_simple_message (error));
+			nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+		}
+	}
+	quit ();
 }
 
-static NMCResultCode
-do_networking_on (NmCli *nmc, int argc, char **argv)
+static void
+do_networking_on_off (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
-	next_arg (nmc, &argc, &argv, NULL);
-	return do_networking_on_off (nmc, argc, argv, TRUE);
-}
+	gboolean enable = nm_streq (cmd->cmd, "on");
 
-static NMCResultCode
-do_networking_off (NmCli *nmc, int argc, char **argv)
-{
 	next_arg (nmc, &argc, &argv, NULL);
-	return do_networking_on_off (nmc, argc, argv, FALSE);
+
+	if (nmc->complete)
+		return;
+
+	nmc_start_polkit_agent_start_try (nmc);
+
+	nmc->should_wait++;
+	nm_client_dbus_call (nmc->client,
+	                     NM_DBUS_PATH,
+	                     NM_DBUS_INTERFACE,
+	                     "Enable",
+	                     g_variant_new ("(b)", enable),
+	                     G_VARIANT_TYPE ("()"),
+	                     -1,
+	                     NULL,
+	                     _do_networking_on_off_cb,
+	                     nmc);
 }
 
-static NMCResultCode
-do_networking_connectivity (NmCli *nmc, int argc, char **argv)
+static void
+do_networking_connectivity (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	next_arg (nmc, &argc, &argv, NULL);
 	if (nmc->complete) {
 		if (argc == 1)
 			nmc_complete_strings (*argv, "check");
-		return nmc->return_value;
+		return;
 	}
 
 	if (!argc) {
@@ -988,50 +999,41 @@ do_networking_connectivity (NmCli *nmc, int argc, char **argv)
 		g_string_printf (nmc->return_text, _("Error: 'networking' command '%s' is not valid."), *argv);
 		nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
 	}
-
-	return nmc->return_value;
 }
 
-static NMCResultCode
-do_networking_show (NmCli *nmc, int argc, char **argv)
+static void
+do_networking_show (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	next_arg (nmc, &argc, &argv, NULL);
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	nmc_switch_show (nmc, NMC_FIELDS_NM_NETWORKING, N_("Networking"));
-
-	return nmc->return_value;
 }
 
-static const NMCCommand networking_cmds[] = {
-	{ "on",           do_networking_on,           usage_networking_on,           TRUE,   TRUE },
-	{ "off",          do_networking_off,          usage_networking_off,          TRUE,   TRUE },
-	{ "connectivity", do_networking_connectivity, usage_networking_connectivity, TRUE,   TRUE },
-	{ NULL,           do_networking_show,         usage_networking,              TRUE,   TRUE },
-};
-
-/*
- * Entry point function for networking commands 'nmcli networking'
- */
-NMCResultCode
-do_networking (NmCli *nmc, int argc, char **argv)
+void
+nmc_command_func_networking (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
-	next_arg (nmc, &argc, &argv, NULL);
-	nmc_do_cmd (nmc, networking_cmds, *argv, argc, argv);
+	static const NMCCommand cmds[] = {
+		{ "on",           do_networking_on_off,       usage_networking_on,           TRUE, TRUE },
+		{ "off",          do_networking_on_off,       usage_networking_off,          TRUE, TRUE },
+		{ "connectivity", do_networking_connectivity, usage_networking_connectivity, TRUE, TRUE },
+		{ NULL,           do_networking_show,         usage_networking,              TRUE, TRUE },
+	};
 
-	return nmc->return_value;
+	next_arg (nmc, &argc, &argv, NULL);
+	nmc_do_cmd (nmc, cmds, *argv, argc, argv);
 }
 
-static NMCResultCode
-do_radio_all (NmCli *nmc, int argc, char **argv)
+static void
+do_radio_all (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	gboolean enable_flag;
 
 	next_arg (nmc, &argc, &argv, NULL);
 	if (argc == 0) {
 		if (nmc->complete)
-			return nmc->return_value;
+			return;
 
 		/* no argument, show all radio switches */
 		show_nm_status (nmc, N_("Radio switches"), NMC_FIELDS_NM_STATUS_RADIO);
@@ -1039,29 +1041,42 @@ do_radio_all (NmCli *nmc, int argc, char **argv)
 		if (nmc->complete) {
 			if (argc == 1)
 				nmc_complete_bool (*argv);
-			return nmc->return_value;
+			return;
 		}
 
 		if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
-			return nmc->return_value;
+			return;
 
 		nm_client_wireless_set_enabled (nmc->client, enable_flag);
 		nm_client_wimax_set_enabled (nmc->client, enable_flag);
 		nm_client_wwan_set_enabled (nmc->client, enable_flag);
 	}
+}
+
+static void
+_do_radio_wifi_cb (GObject *object, GAsyncResult *result, gpointer user_data)
+{
+	NmCli *nmc = user_data;
+	gs_free_error GError *error = NULL;
 
-	return nmc->return_value;
+	if (!nm_client_dbus_set_property_finish (NM_CLIENT (object), result, &error)) {
+		g_dbus_error_strip_remote_error (error);
+		g_string_printf (nmc->return_text, _("Error: failed to set Wi-Fi radio: %s"),
+		                 nmc_error_get_simple_message (error));
+		nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+	}
+	quit ();
 }
 
-static NMCResultCode
-do_radio_wifi (NmCli *nmc, int argc, char **argv)
+static void
+do_radio_wifi (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	gboolean enable_flag;
 
 	next_arg (nmc, &argc, &argv, NULL);
 	if (argc == 0) {
 		if (nmc->complete)
-			return nmc->return_value;
+			return;
 
 		/* no argument, show current Wi-Fi state */
 		nmc_switch_show (nmc, NMC_FIELDS_NM_WIFI, N_("Wi-Fi radio switch"));
@@ -1069,26 +1084,35 @@ do_radio_wifi (NmCli *nmc, int argc, char **argv)
 		if (nmc->complete) {
 			if (argc == 1)
 				nmc_complete_bool (*argv);
-			return nmc->return_value;
+			return;
 		}
 		if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
-			return nmc->return_value;
+			return;
 
-		nm_client_wireless_set_enabled (nmc->client, enable_flag);
-	}
+		nmc_start_polkit_agent_start_try (nmc);
 
-	return nmc->return_value;
+		nmc->should_wait++;
+		nm_client_dbus_set_property (nmc->client,
+		                             NM_DBUS_PATH,
+		                             NM_DBUS_INTERFACE,
+		                             "WirelessEnabled",
+		                             g_variant_new_boolean (enable_flag),
+		                             -1,
+		                             NULL,
+		                             _do_radio_wifi_cb,
+		                             nmc);
+	}
 }
 
-static NMCResultCode
-do_radio_wwan (NmCli *nmc, int argc, char **argv)
+static void
+do_radio_wwan (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	gboolean enable_flag;
 
 	next_arg (nmc, &argc, &argv, NULL);
 	if (argc == 0) {
 		if (nmc->complete)
-			return nmc->return_value;
+			return;
 
 		/* no argument, show current WWAN (mobile broadband) state */
 		nmc_switch_show (nmc, NMC_FIELDS_NM_WWAN, N_("WWAN radio switch"));
@@ -1096,38 +1120,30 @@ do_radio_wwan (NmCli *nmc, int argc, char **argv)
 		if (nmc->complete) {
 			if (argc == 1)
 				nmc_complete_bool (*argv);
-			return nmc->return_value;
+			return;
 		}
 		if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
-			return nmc->return_value;
+			return;
 
 		nm_client_wwan_set_enabled (nmc->client, enable_flag);
 	}
-
-	return nmc->return_value;
 }
 
-static const NMCCommand radio_cmds[] = {
-	{ "all",   do_radio_all,   usage_radio_all,   TRUE,   TRUE },
-	{ "wifi",  do_radio_wifi,  usage_radio_wifi,  TRUE,   TRUE },
-	{ "wwan",  do_radio_wwan,  usage_radio_wwan,  TRUE,   TRUE },
-	{ NULL,    do_radio_all,   usage_radio,       TRUE,   TRUE },
-};
-
-/*
- * Entry point function for radio switch commands 'nmcli radio'
- */
-NMCResultCode
-do_radio (NmCli *nmc, int argc, char **argv)
+void
+nmc_command_func_radio (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
+	static const NMCCommand cmds[] = {
+		{ "all",  do_radio_all,  usage_radio_all,  TRUE, TRUE },
+		{ "wifi", do_radio_wifi, usage_radio_wifi, TRUE, TRUE },
+		{ "wwan", do_radio_wwan, usage_radio_wwan, TRUE, TRUE },
+		{ NULL,   do_radio_all,  usage_radio,      TRUE, TRUE },
+	};
+
 	next_arg (nmc, &argc, &argv, NULL);
 
-	/* Register polkit agent */
 	nmc_start_polkit_agent_start_try (nmc);
 
-	nmc_do_cmd (nmc, radio_cmds, *argv, argc, argv);
-
-	return nmc->return_value;
+	nmc_do_cmd (nmc, cmds, *argv, argc, argv);
 }
 
 static void
@@ -1367,11 +1383,8 @@ ac_overview (NmCli *nmc, NMActiveConnection *ac)
 	g_string_free (outbuf, TRUE);
 }
 
-/*
- * Entry point function for 'nmcli' without arguments.
- */
-NMCResultCode
-do_overview (NmCli *nmc, int argc, char **argv)
+void
+nmc_command_func_overview (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	NMDevice **devices;
 	const GPtrArray *p;
@@ -1386,7 +1399,7 @@ do_overview (NmCli *nmc, int argc, char **argv)
 	/* Register polkit agent */
 	nmc_start_polkit_agent_start_try (nmc);
 
-	nm_cli_spawn_pager (nmc);
+	nm_cli_spawn_pager (&nmc->nmc_config, &nmc->pager_data);
 
 	/* The VPN connections don't have devices (yet?). */
 	p = nm_client_get_active_connections (nmc->client);
@@ -1481,20 +1494,15 @@ do_overview (NmCli *nmc, int argc, char **argv)
 	           "\"nmcli connection show\" to get an overview on active connection profiles.\n"
 	           "\n"
 	           "Consult nmcli(1) and nmcli-examples(7) manual pages for complete usage details.\n"));
-
-	return NMC_RESULT_SUCCESS;
 }
 
-/*
- * Entry point function for 'nmcli monitor'
- */
-NMCResultCode
-do_monitor (NmCli *nmc, int argc, char **argv)
+void
+nmc_command_func_monitor (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
 {
 	next_arg (nmc, &argc, &argv, NULL);
 
 	if (nmc->complete)
-		return nmc->return_value;
+		return;
 
 	if (argc > 0) {
 		if (!nmc_arg_is_help (*argv)) {
@@ -1503,7 +1511,7 @@ do_monitor (NmCli *nmc, int argc, char **argv)
 		}
 
 		usage_monitor ();
-		return nmc->return_value;
+		return;
 	}
 
 	if (!nm_client_get_nm_running (nmc->client)) {
@@ -1530,6 +1538,4 @@ do_monitor (NmCli *nmc, int argc, char **argv)
 
 	monitor_devices (nmc);
 	monitor_connections (nmc);
-
-	return NMC_RESULT_SUCCESS;
 }
diff --git a/clients/cli/general.h b/clients/cli/general.h
deleted file mode 100644
index dd63e43f..00000000
--- a/clients/cli/general.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2010 - 2014 Red Hat, Inc.
- */
-
-#ifndef NMC_GENERAL_H
-#define NMC_GENERAL_H
-
-#include "nmcli.h"
-
-NMCResultCode do_general    (NmCli *nmc, int argc, char **argv);
-NMCResultCode do_networking (NmCli *nmc, int argc, char **argv);
-NMCResultCode do_radio      (NmCli *nmc, int argc, char **argv);
-NMCResultCode do_monitor    (NmCli *nmc, int argc, char **argv);
-NMCResultCode do_overview   (NmCli *nmc, int argc, char **argv);
-
-#endif /* NMC_GENERAL_H */
diff --git a/clients/cli/meson.build b/clients/cli/meson.build
index 56202063..8dd05aff 100644
--- a/clients/cli/meson.build
+++ b/clients/cli/meson.build
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: LGPL-2.1+
+
 name = 'nmcli'
 
 # FIXME: nmcli-completion should be renamed to nmcli
@@ -6,33 +8,26 @@ install_data(
   install_dir: join_paths(nm_datadir, 'bash-completion', 'completions'),
 )
 
-sources = files(
-  'agent.c',
-  'common.c',
-  'connections.c',
-  'devices.c',
-  'general.c',
-  'nmcli.c',
-  'polkit-agent.c',
-  'settings.c',
-  'utils.c',
-)
-
 deps = [
   libnmc_base_dep,
   libnmc_dep,
   readline_dep,
+  libnm_libnm_aux_dep,
 ]
 
-if enable_polkit_agent
-  sources += nm_polkit_listener
-
-  deps += polkit_agent_dep
-endif
-
 executable(
   name,
-  sources,
+  files(
+    'agent.c',
+    'common.c',
+    'connections.c',
+    'devices.c',
+    'general.c',
+    'nmcli.c',
+    'polkit-agent.c',
+    'settings.c',
+    'utils.c',
+  ),
   dependencies: deps,
   c_args: clients_c_flags + ['-DG_LOG_DOMAIN="@0@"'.format(name)],
   link_args: ldflags_linker_script_binary,
diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c
index 5fbd6d72..ee5ef015 100644
--- a/clients/cli/nmcli.c
+++ b/clients/cli/nmcli.c
@@ -25,8 +25,6 @@
 #include "common.h"
 #include "connections.h"
 #include "devices.h"
-#include "general.h"
-#include "agent.h"
 #include "settings.h"
 
 #if defined(NM_DIST_VERSION)
@@ -72,7 +70,7 @@
 	[NM_META_COLOR_ENABLED]                  = "32", \
 	[NM_META_COLOR_DISABLED]                 = "31", \
 
-NmCli nm_cli = {
+static NmCli nm_cli = {
 	.client = NULL,
 
 	.return_value = NMC_RESULT_SUCCESS,
@@ -101,6 +99,9 @@ NmCli nm_cli = {
 	.editor_save_confirmation = TRUE,
 };
 
+const NmCli *const nm_cli_global_readline = &nm_cli;
+const NmCli *const nmc_meta_environment_arg = &nm_cli;
+
 /*****************************************************************************/
 
 typedef struct {
@@ -255,21 +256,21 @@ usage (void)
 	              "\n"));
 }
 
-static const NMCCommand nmcli_cmds[] = {
-	{ "general",     do_general,      NULL,   FALSE,  FALSE },
-	{ "monitor",     do_monitor,      NULL,   TRUE,   FALSE },
-	{ "networking",  do_networking,   NULL,   FALSE,  FALSE },
-	{ "radio",       do_radio,        NULL,   FALSE,  FALSE },
-	{ "connection",  do_connections,  NULL,   FALSE,  FALSE },
-	{ "device",      do_devices,      NULL,   FALSE,  FALSE },
-	{ "agent",       do_agent,        NULL,   FALSE,  FALSE },
-	{ NULL,          do_overview,     usage,  TRUE,   TRUE },
-};
-
 static gboolean
-matches_arg (NmCli *nmc, int *argc, char ***argv, const char *pattern, char **arg)
+matches_arg (NmCli *nmc,
+             int *argc,
+             const char *const**argv,
+             const char *pattern,
+             char **arg)
 {
-	char *opt = *argv[0];
+	gs_free char *opt_free = NULL;
+	const char *opt = (*argv)[0];
+	gs_free char *arg_tmp = NULL;
+	const char *s;
+
+	nm_assert (opt);
+	nm_assert (opt[0] == '-');
+	nm_assert (!arg || !*arg);
 
 	if (nmc->return_value != NMC_RESULT_SUCCESS) {
 		/* Don't process further matches if there has been an error. */
@@ -285,33 +286,31 @@ matches_arg (NmCli *nmc, int *argc, char ***argv, const char *pattern, char **ar
 	if (arg) {
 		/* If there's a "=" separator, replace it with NUL so that matches()
 		 * works and consider the part after it to be the arguemnt's value. */
-		*arg = strchr (opt, '=');
-		if (*arg) {
-			**arg = '\0';
-			(*arg)++;
+		s = strchr (opt, '=');
+		if (s) {
+			opt = nm_strndup_a (300, opt, s - opt, &opt_free);
+			arg_tmp = g_strdup (&s[1]);
 		}
 	}
 
-	if (!matches (opt, pattern)) {
-		if (arg && *arg) {
-			/* Back off the replacement of "=". */
-			(*arg)--;
-			**arg = '=';
-		}
+	if (!matches (opt, pattern))
 		return FALSE;
-	}
 
-	if (arg && !*arg) {
-		/* We need a value, but the option didn't contain a "=<value>" part.
-		 * Proceed to the next argument. */
-		(*argc)--;
-		(*argv)++;
-		if (!*argc) {
-			g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
-			nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
-			return FALSE;
+	if (arg) {
+		if (arg_tmp)
+			*arg = g_steal_pointer (&arg_tmp);
+		else {
+			/* We need a value, but the option didn't contain a "=<value>" part.
+			 * Proceed to the next argument. */
+			if (*argc <= 1) {
+				g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
+				nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+				return FALSE;
+			}
+			(*argc)--;
+			(*argv)++;
+			*arg = g_strdup (*argv[0]);
 		}
-		*arg = *argv[0];
 	}
 
 	return TRUE;
@@ -697,26 +696,43 @@ set_colors (NmcColorOption color_option,
 /*************************************************************************************/
 
 static gboolean
-process_command_line (NmCli *nmc, int argc, char **argv)
+process_command_line (NmCli *nmc, int argc, char **argv_orig)
 {
+	static const NMCCommand nmcli_cmds[] = {
+		{ "general",    nmc_command_func_general,     NULL,  FALSE, FALSE },
+		{ "monitor",    nmc_command_func_monitor,     NULL,  TRUE,  FALSE },
+		{ "networking", nmc_command_func_networking,  NULL,  FALSE, FALSE },
+		{ "radio",      nmc_command_func_radio,       NULL,  FALSE, FALSE },
+		{ "connection", nmc_command_func_connection,  NULL,  FALSE, FALSE },
+		{ "device",     nmc_command_func_device,      NULL,  FALSE, FALSE },
+		{ "agent",      nmc_command_func_agent,       NULL,  FALSE, FALSE },
+		{ NULL,         nmc_command_func_overview,    usage, TRUE,  TRUE },
+	};
 	NmcColorOption colors = NMC_USE_COLOR_AUTO;
-	char *base;
+	const char *base;
+	const char *const*argv;
 
-	base = strrchr (argv[0], '/');
+	base = strrchr (argv_orig[0], '/');
 	if (base == NULL)
-		base = argv[0];
+		base = argv_orig[0];
 	else
 		base++;
-	if (argc > 1 && nm_streq (argv[1], "--complete-args")) {
+
+	if (   argc > 1
+	    && nm_streq (argv_orig[1], "--complete-args")) {
 		nmc->complete = TRUE;
-		argv[1] = argv[0];
-		next_arg (nmc, &argc, &argv, NULL);
+		argv_orig[1] = argv_orig[0];
+		argc--;
+		argv_orig++;
 	}
+
+	argv = (const char *const*) argv_orig;
+
 	next_arg (nmc, &argc, &argv, NULL);
 
 	/* parse options */
 	while (argc) {
-		char *value;
+		gs_free char *value = NULL;
 
 		if (argv[0][0] != '-')
 			break;
@@ -909,11 +925,12 @@ signal_handler (gpointer user_data)
 }
 
 void
-nm_cli_spawn_pager (NmCli *nmc)
+nm_cli_spawn_pager (const NmcConfig *nmc_config,
+                    NmcPagerData *pager_data)
 {
-	if (nmc->pager_pid > 0)
+	if (pager_data->pid != 0)
 		return;
-	nmc->pager_pid = nmc_terminal_spawn_pager (&nmc->nmc_config);
+	pager_data->pid = nmc_terminal_spawn_pager (nmc_config);
 }
 
 static void
@@ -935,13 +952,14 @@ nmc_cleanup (NmCli *nmc)
 
 	nm_clear_g_free (&nmc->required_fields);
 
-	if (nmc->pager_pid > 0) {
+	if (nmc->pager_data.pid != 0) {
+		pid_t pid = nm_steal_int (&nmc->pager_data.pid);
+
 		fclose (stdout);
 		fclose (stderr);
 		do {
-			ret = waitpid (nmc->pager_pid, NULL, 0);
+			ret = waitpid (pid, NULL, 0);
 		} while (ret == -1 && errno == EINTR);
-		nmc->pager_pid = 0;
 	}
 
 	nm_clear_g_free (&nmc->palette_buffer);
diff --git a/clients/cli/nmcli.h b/clients/cli/nmcli.h
index 4615b046..c8d27b3d 100644
--- a/clients/cli/nmcli.h
+++ b/clients/cli/nmcli.h
@@ -101,6 +101,10 @@ typedef struct _NmcConfig {
 	const char *palette[_NM_META_COLOR_NUM];          /* Color palette */
 } NmcConfig;
 
+typedef struct {
+	pid_t pid;
+} NmcPagerData;
+
 typedef struct _NmcOutputData {
 	GPtrArray *output_data;                           /* GPtrArray of arrays of NmcOutputField structs - accumulates data for output */
 } NmcOutputData;
@@ -111,7 +115,8 @@ typedef struct _NmCli {
 
 	NMCResultCode return_value;                       /* Return code of nmcli */
 	GString *return_text;                             /* Reason text */
-	pid_t pager_pid;                                  /* PID of a pager, if one was spawned */
+
+	NmcPagerData pager_data;
 
 	int timeout;                                      /* Operation timeout */
 
@@ -135,7 +140,7 @@ typedef struct _NmCli {
 	char *palette_buffer;                             /* Buffer with sequences for terminal-colors.d(5)-based coloring. */
 } NmCli;
 
-extern NmCli nm_cli;
+extern const NmCli *const nm_cli_global_readline;
 
 /* Error quark for GError domain */
 #define NMCLI_ERROR (nmcli_error_quark ())
@@ -148,7 +153,8 @@ void     nmc_clear_sigint (void);
 void     nmc_set_sigquit_internal (void);
 void     nmc_exit (void);
 
-void nm_cli_spawn_pager (NmCli *nmc);
+void nm_cli_spawn_pager (const NmcConfig *nmc_config,
+                         NmcPagerData *pager_data);
 
 void nmc_empty_output_fields (NmcOutputData *output_data);
 
@@ -158,4 +164,27 @@ void nmc_empty_output_fields (NmcOutputData *output_data);
 		.output_data = g_ptr_array_new_full (20, g_free), \
 	}
 
+/*****************************************************************************/
+
+struct _NMCCommand;
+
+typedef struct _NMCCommand {
+	const char *cmd;
+	void (*func) (const struct _NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+	void (*usage) (void);
+	bool needs_client;
+	bool needs_nm_running;
+} NMCCommand;
+
+void nmc_command_func_agent      (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+void nmc_command_func_general    (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+void nmc_command_func_networking (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+void nmc_command_func_radio      (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+void nmc_command_func_monitor    (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+void nmc_command_func_overview   (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+void nmc_command_func_connection (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+void nmc_command_func_device     (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+
+/*****************************************************************************/
+
 #endif /* NMC_NMCLI_H */
diff --git a/clients/cli/polkit-agent.c b/clients/cli/polkit-agent.c
index 69bfb68d..183562e7 100644
--- a/clients/cli/polkit-agent.c
+++ b/clients/cli/polkit-agent.c
@@ -14,16 +14,12 @@
 #include "nm-polkit-listener.h"
 #include "common.h"
 
-#if WITH_POLKIT_AGENT
 static char *
-polkit_request (NMPolkitListener *listener,
-                const char *request,
-                const char *action_id,
-                const char *message,
-                const char *icon_name,
-                const char *user,
-                gboolean echo_on,
-                gpointer user_data)
+polkit_read_passwd (gpointer instance,
+                    const char *action_id,
+                    const char *message,
+                    const char *user,
+                    gpointer user_data)
 {
 	NmCli *nmc = user_data;
 
@@ -32,87 +28,68 @@ polkit_request (NMPolkitListener *listener,
 
 	/* Ask user for polkit authorization password */
 	if (user) {
-		gs_free char *tmp = NULL;
-		char *p;
-
-		/* chop of ": " if present */
-		tmp = g_strdup (request);
-		p = strrchr (tmp, ':');
-		if (p && nm_streq (p, ": "))
-			*p = '\0';
-		return nmc_readline_echo (&nmc->nmc_config, echo_on, "%s (%s): ", tmp, user);
+		return nmc_readline_echo (&nmc->nmc_config, FALSE, "password (%s): ", user);
 	}
-
-	return nmc_readline_echo (&nmc->nmc_config, echo_on, "%s", request);
+	return nmc_readline_echo (&nmc->nmc_config, FALSE, "password: ");
 }
 
 static void
-polkit_show_info (NMPolkitListener *listener,
-                  const char *text,
-                  gpointer user_data)
+polkit_error (gpointer instance,
+              const char *error,
+              gpointer user_data)
 {
-	g_print (_("Authentication message: %s\n"), text);
+	g_printerr (_("Error: polkit agent failed: %s\n"), error);
 }
 
-static void
-polkit_show_error (NMPolkitListener *listener,
-                   const char *text,
-                   gpointer user_data)
-{
-	g_print (_("Authentication error: %s\n"), text);
-}
-
-static void
-polkit_completed (NMPolkitListener *listener,
-                  gboolean gained_authorization,
-                  gpointer user_data)
-{
-	/* We don't print anything here. The outcome will be evident from
-	 * the operation result anyway. */
-}
-#endif
-
 gboolean
 nmc_polkit_agent_init (NmCli* nmc, gboolean for_session, GError **error)
 {
-#if WITH_POLKIT_AGENT
-	static const NMPolkitListenVtable vtable = {
-		.on_request = polkit_request,
-		.on_show_info = polkit_show_info,
-		.on_show_error = polkit_show_error,
-		.on_completed = polkit_completed,
-	};
 	NMPolkitListener *listener;
+	GDBusConnection *dbus_connection = NULL;
 
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	listener = nm_polkit_listener_new (for_session, error);
-	if (!listener)
-		return FALSE;
+	if (nmc->client && nm_client_get_dbus_connection (nmc->client)) {
+		dbus_connection = nm_client_get_dbus_connection (nmc->client);
+		listener = nm_polkit_listener_new (dbus_connection, for_session);
+	} else {
+		dbus_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM,
+		                                  NULL,
+		                                  error);
+
+		if (!dbus_connection) {
+			return FALSE;
+		}
+
+		listener = nm_polkit_listener_new (dbus_connection, for_session);
+		g_object_unref (dbus_connection);
+	}
 
-	nm_polkit_listener_set_vtable (listener, &vtable, nmc);
+	g_signal_connect (listener,
+	                  NM_POLKIT_LISTENER_SIGNAL_REQUEST_SYNC,
+	                  G_CALLBACK (polkit_read_passwd),
+	                  nmc);
+	g_signal_connect (listener,
+	                  NM_POLKIT_LISTENER_SIGNAL_ERROR,
+	                  G_CALLBACK (polkit_error),
+	                  NULL);
 
 	nmc->pk_listener = listener;
-#endif
 	return TRUE;
 }
 
 void
 nmc_polkit_agent_fini (NmCli* nmc)
 {
-#if WITH_POLKIT_AGENT
 	if (nmc->pk_listener) {
-		nm_polkit_listener_set_vtable (nmc->pk_listener, NULL, NULL);
 		g_clear_object (&nmc->pk_listener);
 	}
-#endif
 }
 
 gboolean
 nmc_start_polkit_agent_start_try (NmCli *nmc)
 {
-#if WITH_POLKIT_AGENT
-	GError *error = NULL;
+	gs_free_error GError *error = NULL;
 
 	/* We don't register polkit agent at all when running non-interactively */
 	if (!nmc->ask)
@@ -121,9 +98,7 @@ nmc_start_polkit_agent_start_try (NmCli *nmc)
 	if (!nmc_polkit_agent_init (nmc, FALSE, &error)) {
 		g_printerr (_("Warning: polkit agent initialization failed: %s\n"),
 		            error->message);
-		g_error_free (error);
 		return FALSE;
 	}
-#endif
 	return TRUE;
 }
diff --git a/clients/cli/settings.c b/clients/cli/settings.c
index 698471d7..0487fb96 100644
--- a/clients/cli/settings.c
+++ b/clients/cli/settings.c
@@ -456,8 +456,6 @@ const NMMetaEnvironment *const nmc_meta_environment = &((NMMetaEnvironment) {
 	.get_nm_connections = _env_get_nm_connections,
 });
 
-NmCli *const nmc_meta_environment_arg = &nm_cli;
-
 static char *
 get_property_val (NMSetting *setting, const char *prop, NMMetaAccessorGetType get_type, gboolean show_secrets, GError **error)
 {
@@ -475,7 +473,7 @@ get_property_val (NMSetting *setting, const char *prop, NMMetaAccessorGetType ge
 
 			value = property_info->property_type->get_fcn (property_info,
 			                                               nmc_meta_environment,
-			                                               nmc_meta_environment_arg,
+			                                               (gpointer) nmc_meta_environment_arg,
 			                                               setting,
 			                                               get_type,
 			                                               show_secrets ? NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS : 0,
@@ -568,7 +566,7 @@ nmc_setting_set_property (NMClient *client,
 	g_object_freeze_notify (G_OBJECT (setting));
 	success = property_info->property_type->set_fcn (property_info,
 	                                                 nmc_meta_environment,
-	                                                 nmc_meta_environment_arg,
+	                                                 (gpointer) nmc_meta_environment_arg,
 	                                                 setting,
 	                                                 modifier,
 	                                                 value,
diff --git a/clients/cli/utils.c b/clients/cli/utils.c
index 2e3a38f7..d0d553b9 100644
--- a/clients/cli/utils.c
+++ b/clients/cli/utils.c
@@ -154,7 +154,7 @@ parse_global_arg (NmCli *nmc, const char *arg)
  * -1 otherwise (no more args).
  */
 int
-next_arg (NmCli *nmc, int *argc, char ***argv, ...)
+next_arg (NmCli *nmc, int *argc, const char *const**argv, ...)
 {
 	va_list args;
 	const char *cmd_option;
@@ -248,7 +248,7 @@ nmc_arg_is_option (const char *str, const char *opt_name)
  * Returns: TRUE on success, FALSE on an error and sets 'error'
  */
 gboolean
-nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, char ***argv, GError **error)
+nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, const char *const**argv, GError **error)
 {
 	nmc_arg_t *p;
 	gboolean found;
@@ -321,19 +321,14 @@ nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, char ***argv, GErr
 char *
 ssid_to_hex (const char *str, gsize len)
 {
-	GString *printable;
-	char *printable_str;
-	int i;
-
-	if (str == NULL || len == 0)
+	if (len == 0)
 		return NULL;
 
-	printable = g_string_new (NULL);
-	for (i = 0; i < len; i++) {
-		g_string_append_printf (printable, "%02X", (unsigned char) str[i]);
-	}
-	printable_str = g_string_free (printable, FALSE);
-	return printable_str;
+	return nm_utils_bin2hexstr_full (str,
+	                                 len,
+	                                 '\0',
+	                                 TRUE,
+	                                 NULL);
 }
 
 /*
@@ -667,7 +662,6 @@ _output_selection_append (GArray *cols,
 	guint i;
 	const NMMetaAbstractInfo *const*nested;
 	NMMetaSelectionResultList *selection;
-	const NMMetaSelectionItem *si;
 
 	col_idx = cols->len;
 
@@ -688,6 +682,8 @@ _output_selection_append (GArray *cols,
 			gs_free char *allowed_fields = NULL;
 
 			if (parent_idx != PRINT_DATA_COL_PARENT_NIL) {
+				const NMMetaSelectionItem *si;
+
 				si = g_array_index (cols, PrintDataCol, parent_idx).selection_item;
 				allowed_fields = nm_meta_abstract_info_get_nested_names_str (si->info, si->self_selection);
 			}
@@ -719,10 +715,9 @@ _output_selection_append (GArray *cols,
 		g_ptr_array_add (gfree_keeper, selection);
 
 		for (i = 0; i < selection->num; i++) {
-			si = &selection->items[i];
 			if (!_output_selection_append (cols,
 			                               col_idx,
-			                               si,
+			                               &selection->items[i],
 			                               gfree_keeper,
 			                               error))
 				return FALSE;
@@ -778,7 +773,8 @@ _output_selection_complete (GArray *cols)
 static gboolean
 _output_selection_parse (const NMMetaAbstractInfo *const*fields,
                          const char *fields_str,
-                         GArray **out_cols,
+                         PrintDataCol **out_cols_data,
+                         guint *out_cols_len,
                          GPtrArray **out_gfree_keeper,
                          GError **error)
 {
@@ -803,16 +799,18 @@ _output_selection_parse (const NMMetaAbstractInfo *const*fields,
 	cols = g_array_new (FALSE, TRUE, sizeof (PrintDataCol));
 
 	for (i = 0; i < selection->num; i++) {
-		const NMMetaSelectionItem *si = &selection->items[i];
-
-		if (!_output_selection_append (cols, PRINT_DATA_COL_PARENT_NIL,
-		                               si, gfree_keeper, error))
+		if (!_output_selection_append (cols,
+		                               PRINT_DATA_COL_PARENT_NIL,
+		                               &selection->items[i],
+		                               gfree_keeper,
+		                               error))
 			return FALSE;
 	}
 
 	_output_selection_complete (cols);
 
-	*out_cols = g_steal_pointer (&cols);
+	*out_cols_len = cols->len;
+	*out_cols_data = (PrintDataCol *) g_array_free (g_steal_pointer (&cols), FALSE);
 	*out_gfree_keeper = g_steal_pointer (&gfree_keeper);
 	return TRUE;
 }
@@ -1069,7 +1067,7 @@ _print_fill (const NmcConfig *nmc_config,
 
 			value = nm_meta_abstract_info_get (info,
 			                                   nmc_meta_environment,
-			                                   nmc_meta_environment_arg,
+			                                   (gpointer) nmc_meta_environment_arg,
 			                                   target,
 			                                   targets_data,
 			                                   text_get_type,
@@ -1114,7 +1112,7 @@ _print_fill (const NmcConfig *nmc_config,
 
 			cell->color = GPOINTER_TO_INT (nm_meta_abstract_info_get (info,
 			                                                          nmc_meta_environment,
-			                                                          nmc_meta_environment_arg,
+			                                                          (gpointer) nmc_meta_environment_arg,
 			                                                          target,
 			                                                          targets_data,
 			                                                          NM_META_ACCESSOR_GET_TYPE_COLOR,
@@ -1142,7 +1140,8 @@ _print_fill (const NmcConfig *nmc_config,
 		header_cell->width = nmc_string_screen_width (header_cell->title, NULL);
 
 		for (i_row = 0; i_row < targets_len; i_row++) {
-			const PrintDataCell *cell = &g_array_index (cells, PrintDataCell, i_row * cols_len + i_col);
+			const PrintDataCell *cells_line = &g_array_index (cells, PrintDataCell, i_row * header_row->len);
+			const PrintDataCell *cell = &cells_line[i_col];
 			const char *const*i_strv;
 
 			switch (cell->text_format) {
@@ -1379,20 +1378,24 @@ nmc_print (const NmcConfig *nmc_config,
            GError **error)
 {
 	gs_unref_ptrarray GPtrArray *gfree_keeper = NULL;
-	gs_unref_array GArray *cols = NULL;
+	gs_free PrintDataCol *cols_data = NULL;
+	guint cols_len;
 	gs_unref_array GArray *header_row = NULL;
 	gs_unref_array GArray *cells = NULL;
 
-	if (!_output_selection_parse (fields, fields_str,
-	                              &cols, &gfree_keeper,
+	if (!_output_selection_parse (fields,
+	                              fields_str,
+	                              &cols_data,
+	                              &cols_len,
+	                              &gfree_keeper,
 	                              error))
 		return FALSE;
 
 	_print_fill (nmc_config,
 	             targets,
 	             targets_data,
-	             &g_array_index (cols, PrintDataCol, 0),
-	             cols->len,
+	             cols_data,
+	             cols_len,
 	             &header_row,
 	             &cells);
 
@@ -1568,6 +1571,7 @@ get_value_to_print (const NmcConfig *nmc_config,
  */
 void
 print_required_fields (const NmcConfig *nmc_config,
+                       NmcPagerData *pager_data,
                        NmcOfFlags of_flags,
                        const GArray *indices,
                        const char *header_name,
@@ -1584,7 +1588,7 @@ print_required_fields (const NmcConfig *nmc_config,
 	gboolean field_names = of_flags & NMC_OF_FLAG_FIELD_NAMES;
 	gboolean section_prefix = of_flags & NMC_OF_FLAG_SECTION_PREFIX;
 
-	nm_cli_spawn_pager (&nm_cli);
+	nm_cli_spawn_pager (nmc_config, pager_data);
 
 	/* --- Main header --- */
 	if (   nmc_config->print_output == NMC_PRINT_PRETTY
@@ -1793,6 +1797,7 @@ print_data_prepare_width (GPtrArray *output_data)
 
 void
 print_data (const NmcConfig *nmc_config,
+            NmcPagerData *pager_data,
             const GArray *indices,
             const char *header_name,
             int indent,
@@ -1803,9 +1808,13 @@ print_data (const NmcConfig *nmc_config,
 	for (i = 0; i < out->output_data->len; i++) {
 		const NmcOutputField *field_values = g_ptr_array_index (out->output_data, i);
 
-		print_required_fields (nmc_config, field_values[0].flags,
-		                       indices, header_name,
-		                       indent, field_values);
+		print_required_fields (nmc_config,
+		                       pager_data,
+		                       field_values[0].flags,
+		                       indices,
+		                       header_name,
+		                       indent,
+		                       field_values);
 	}
 }
 
diff --git a/clients/cli/utils.h b/clients/cli/utils.h
index e699a641..76f5bae0 100644
--- a/clients/cli/utils.h
+++ b/clients/cli/utils.h
@@ -19,10 +19,10 @@ typedef struct {
 } nmc_arg_t;
 
 /* === Functions === */
-int next_arg (NmCli *nmc, int *argc, char ***argv, ...);
+int next_arg (NmCli *nmc, int *argc, const char *const**argv, ...);
 gboolean nmc_arg_is_help (const char *arg);
 gboolean nmc_arg_is_option (const char *arg, const char *opt_name);
-gboolean nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, char ***argv, GError **error);
+gboolean nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, const char *const**argv, GError **error);
 char *ssid_to_hex (const char *str, gsize len);
 void nmc_terminal_erase_line (void);
 void nmc_terminal_show_progress (const char *str);
@@ -51,6 +51,7 @@ GArray *parse_output_fields (const char *fields_str,
 NmcOutputField *nmc_dup_fields_array (const NMMetaAbstractInfo *const*fields, NmcOfFlags flags);
 void nmc_empty_output_fields (NmcOutputData *output_data);
 void print_required_fields (const NmcConfig *nmc_config,
+                            NmcPagerData *pager_data,
                             NmcOfFlags of_flags,
                             const GArray *indices,
                             const char *header_name,
@@ -58,6 +59,7 @@ void print_required_fields (const NmcConfig *nmc_config,
                             const NmcOutputField *field_values);
 void print_data_prepare_width (GPtrArray *output_data);
 void print_data (const NmcConfig *nmc_config,
+                 NmcPagerData *pager_data,
                  const GArray *indices,
                  const char *header_name,
                  int indent,
@@ -66,7 +68,7 @@ void print_data (const NmcConfig *nmc_config,
 /*****************************************************************************/
 
 extern const NMMetaEnvironment *const nmc_meta_environment;
-extern NmCli *const nmc_meta_environment_arg;
+extern const NmCli *const nmc_meta_environment_arg;
 
 typedef enum {
 
diff --git a/clients/cloud-setup/main.c b/clients/cloud-setup/main.c
index 8250945c..4e1a9a4e 100644
--- a/clients/cloud-setup/main.c
+++ b/clients/cloud-setup/main.c
@@ -2,8 +2,9 @@
 
 #include "nm-default.h"
 
-#include "nm-cloud-setup-utils.h"
+#include "nm-libnm-aux/nm-libnm-aux.h"
 
+#include "nm-cloud-setup-utils.h"
 #include "nmcs-provider-ec2.h"
 #include "nm-libnm-core-intern/nm-libnm-core-utils.h"
 
@@ -30,7 +31,7 @@ _provider_detect_cb (GObject *source,
 
 	nm_assert (success != (!!error));
 
-	if (nm_utils_error_is_cancelled (error, FALSE))
+	if (nm_utils_error_is_cancelled (error))
 		return;
 
 	dd = user_data;
@@ -122,58 +123,6 @@ out:
 
 /*****************************************************************************/
 
-typedef struct {
-	GMainLoop *main_loop;
-	NMClient *nmc;
-} ClientCreateData;
-
-static void
-_nmc_create_cb (GObject *source_object,
-                GAsyncResult *result,
-                gpointer user_data)
-{
-	gs_unref_object NMClient *nmc = NULL;
-	ClientCreateData *data = user_data;
-	gs_free_error GError *error = NULL;
-
-	nmc = nm_client_new_finish (result, &error);
-	if (!nmc) {
-		if (!nm_utils_error_is_cancelled (error, FALSE))
-			_LOGI ("failure to talk to NetworkManager: %s", error->message);
-		goto out;
-	}
-
-	if (!nm_client_get_nm_running (nmc)) {
-		_LOGI ("NetworkManager is not running");
-		goto out;
-	}
-
-	_LOGD ("NetworkManager is running");
-	nmcs_wait_for_objects_register (nmc);
-	nmcs_wait_for_objects_register (nm_client_get_context_busy_watcher (nmc));
-
-	data->nmc = g_steal_pointer (&nmc);
-out:
-	g_main_loop_quit (data->main_loop);
-}
-
-static NMClient *
-_nmc_create (GCancellable *sigterm_cancellable)
-{
-	nm_auto_unref_gmainloop GMainLoop *main_loop = g_main_loop_new (NULL, FALSE);
-	ClientCreateData data = {
-		.main_loop = main_loop,
-	};
-
-	nm_client_new_async (sigterm_cancellable, _nmc_create_cb, &data);
-
-	g_main_loop_run (main_loop);
-
-	return data.nmc;
-}
-
-/*****************************************************************************/
-
 static char **
 _nmc_get_hwaddrs (NMClient *nmc)
 {
@@ -270,7 +219,7 @@ _get_config_cb (GObject *source,
 	config_dict = nmcs_provider_get_config_finish (NMCS_PROVIDER (source), result, &error);
 
 	if (!config_dict) {
-		if (!nm_utils_error_is_cancelled (error, FALSE))
+		if (!nm_utils_error_is_cancelled (error))
 			_LOGI ("failure to get meta data: %s", error->message);
 	} else
 		_LOGD ("meta data received");
@@ -386,7 +335,7 @@ _nmc_mangle_connection (NMDevice *device,
 		entry = nm_ip_routing_rule_new (AF_INET);
 		nm_ip_routing_rule_set_priority (entry, rt_table);
 		nm_ip_routing_rule_set_from (entry,
-		                             nm_utils_inet4_ntop (config_data->ipv4s_arr[i], sbuf),
+		                             _nm_utils_inet4_ntop (config_data->ipv4s_arr[i], sbuf),
 		                             32);
 		nm_ip_routing_rule_set_table (entry, rt_table);
 
@@ -477,7 +426,7 @@ try_again:
 	                                                         &applied_version_id,
 	                                                         &error);
 	if (!applied_connection) {
-		if (!nm_utils_error_is_cancelled (error, FALSE))
+		if (!nm_utils_error_is_cancelled (error))
 			_LOGD ("config device %s: device has no applied connection (%s). Skip", hwaddr, error->message);
 		return any_changes;
 	}
@@ -528,7 +477,7 @@ try_again:
 			goto try_again;
 		}
 
-		if (!nm_utils_error_is_cancelled (error, FALSE)) {
+		if (!nm_utils_error_is_cancelled (error)) {
 			_LOGD ("config device %s: failure to reapply connection \"%s\" (%s): %s",
 			       hwaddr,
 			       nm_connection_get_id (applied_connection),
@@ -593,6 +542,7 @@ main (int argc, const char *const*argv)
 	gs_unref_object NMCSProvider *provider = NULL;
 	gs_unref_object NMClient *nmc = NULL;
 	gs_unref_hashtable GHashTable *config_dict = NULL;
+	gs_free_error GError *error = NULL;
 
 	_nm_logging_enabled_init (g_getenv (NMCS_ENV_VARIABLE ("NM_CLOUD_SETUP_LOG")));
 
@@ -616,9 +566,25 @@ main (int argc, const char *const*argv)
 	if (!provider)
 		goto done;
 
-	nmc = _nmc_create (sigterm_cancellable);
-	if (!nmc)
+	nmc_client_new_waitsync (sigterm_cancellable,
+	                         &nmc,
+	                         &error,
+	                         NM_CLIENT_INSTANCE_FLAGS, (guint) NM_CLIENT_INSTANCE_FLAGS_NO_AUTO_FETCH_PERMISSIONS,
+	                         NULL);
+
+	nmcs_wait_for_objects_register (nmc);
+	nmcs_wait_for_objects_register (nm_client_get_context_busy_watcher (nmc));
+
+	if (error) {
+		if (!nm_utils_error_is_cancelled (error))
+			_LOGI ("failure to talk to NetworkManager: %s", error->message);
 		goto done;
+	}
+
+	if (!nm_client_get_nm_running (nmc)) {
+		_LOGI ("NetworkManager is not running");
+		goto done;
+	}
 
 	config_dict = _get_config (sigterm_cancellable, provider, nmc);
 	if (!config_dict)
diff --git a/clients/cloud-setup/meson.build b/clients/cloud-setup/meson.build
index e9cd970a..d8f96539 100644
--- a/clients/cloud-setup/meson.build
+++ b/clients/cloud-setup/meson.build
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: LGPL-2.1+
+
 name = 'nm-cloud-setup'
 
 if install_systemdunitdir
@@ -29,16 +31,15 @@ sources = files(
   'nmcs-provider.c',
 )
 
-deps = [
-  libnmc_base_dep,
-  libnmc_dep,
-  libcurl_dep,
-]
-
 executable(
   name,
   sources,
-  dependencies: deps,
+  dependencies: [
+    libnmc_base_dep,
+    libnmc_dep,
+    libcurl_dep,
+    libnm_libnm_aux_dep,
+  ],
   c_args: clients_c_flags +
           ['-DG_LOG_DOMAIN="@0@"'.format(name)],
   link_with: libnm_systemd_logging_stub,
diff --git a/clients/cloud-setup/nm-cloud-setup-utils.c b/clients/cloud-setup/nm-cloud-setup-utils.c
index 50a59892..13c9566a 100644
--- a/clients/cloud-setup/nm-cloud-setup-utils.c
+++ b/clients/cloud-setup/nm-cloud-setup-utils.c
@@ -49,11 +49,11 @@ _nm_log_impl_cs (NMLogLevel level,
 		break;
 	}
 
-	ts = nm_utils_clock_gettime_ns (CLOCK_BOOTTIME);
+	ts = nm_utils_clock_gettime_nsec (CLOCK_BOOTTIME);
 
 	g_print ("[%"G_GINT64_FORMAT".%05"G_GINT64_FORMAT"] %s %s\n",
-	         ts / NM_UTILS_NS_PER_SECOND,
-	         (ts / (NM_UTILS_NS_PER_SECOND / 10000)) % 10000,
+	         ts / NM_UTILS_NSEC_PER_SEC,
+	         (ts / (NM_UTILS_NSEC_PER_SEC / 10000)) % 10000,
 	         level_str,
 	         msg);
 }
@@ -294,7 +294,7 @@ _poll_done_cb (GObject *source,
 	                                                poll_task_data->probe_user_data,
 	                                                &error);
 
-	if (nm_utils_error_is_cancelled (error, FALSE)) {
+	if (nm_utils_error_is_cancelled (error)) {
 		/* we already handle this differently. Nothing to do. */
 		return;
 	}
@@ -305,7 +305,7 @@ _poll_done_cb (GObject *source,
 		return;
 	}
 
-	now_ms = nm_utils_get_monotonic_timestamp_ms ();
+	now_ms = nm_utils_get_monotonic_timestamp_msec ();
 	if (poll_task_data->ratelimit_timeout_ms > 0)
 		wait_ms = (poll_task_data->last_poll_start_ms + poll_task_data->ratelimit_timeout_ms) - now_ms;
 	else
@@ -328,7 +328,7 @@ _poll_start_cb (gpointer user_data)
 
 	nm_clear_g_source_inst (&poll_task_data->source_next_poll);
 
-	poll_task_data->last_poll_start_ms = nm_utils_get_monotonic_timestamp_ms ();
+	poll_task_data->last_poll_start_ms = nm_utils_get_monotonic_timestamp_msec ();
 
 	g_object_ref (poll_task_data->task); /* balanced by _poll_done_cb() */
 
diff --git a/clients/cloud-setup/nm-http-client.c b/clients/cloud-setup/nm-http-client.c
index 17c6fcdf..94f3fe2b 100644
--- a/clients/cloud-setup/nm-http-client.c
+++ b/clients/cloud-setup/nm-http-client.c
@@ -5,7 +5,6 @@
 #include "nm-http-client.h"
 
 #include <curl/curl.h>
-#include <glib-unix.h>
 
 #include "nm-cloud-setup-utils.h"
 
@@ -164,7 +163,7 @@ _ehandle_complete (EHandleData *edata,
 	                                    &edata->cancellable_id);
 
 	if (error_take) {
-		if (nm_utils_error_is_cancelled (error_take, FALSE))
+		if (nm_utils_error_is_cancelled (error_take))
 			_LOG2T (edata, "cancelled");
 		else
 			_LOG2D (edata, "failed with %s", error_take->message);
@@ -423,7 +422,7 @@ _poll_get_probe_finish_fcn (GObject *source,
 	                                     &local_error);
 
 	if (!success) {
-		if (nm_utils_error_is_cancelled (local_error, FALSE)) {
+		if (nm_utils_error_is_cancelled (local_error)) {
 			g_propagate_error (error, g_steal_pointer (&local_error));
 			return TRUE;
 		}
@@ -636,8 +635,12 @@ _mhandle_socketfunction_cb (CURL *e_handle, curl_socket_t fd, int what, void *us
 			condition = 0;
 
 		if (condition) {
-			priv->mhandle_source_socket = g_unix_fd_source_new (fd, condition);
-			g_source_set_callback (priv->mhandle_source_socket, G_SOURCE_FUNC (_mhandle_socket_cb), self, NULL);
+			priv->mhandle_source_socket = nm_g_unix_fd_source_new (fd,
+			                                                       condition,
+			                                                       G_PRIORITY_DEFAULT,
+			                                                       _mhandle_socket_cb,
+			                                                       self,
+			                                                       NULL);
 			g_source_attach (priv->mhandle_source_socket, priv->context);
 		}
 	}
diff --git a/clients/cloud-setup/nmcs-provider-ec2.c b/clients/cloud-setup/nmcs-provider-ec2.c
index b6ac5a4c..82ed0949 100644
--- a/clients/cloud-setup/nmcs-provider-ec2.c
+++ b/clients/cloud-setup/nmcs-provider-ec2.c
@@ -98,7 +98,7 @@ _detect_get_meta_data_done_cb (GObject *source,
 	                                          NULL,
 	                                          &get_error);
 
-	if (nm_utils_error_is_cancelled (get_error, FALSE)) {
+	if (nm_utils_error_is_cancelled (get_error)) {
 		g_task_return_error (task, g_steal_pointer (&get_error));
 		return;
 	}
@@ -168,7 +168,7 @@ _get_config_task_return (GetConfigIfaceData *iface_data,
 	nm_g_slice_free (iface_data);
 
 	if (error_take) {
-		if (nm_utils_error_is_cancelled (error_take, FALSE))
+		if (nm_utils_error_is_cancelled (error_take))
 			_LOGD ("get-config: cancelled");
 		else
 			_LOGD ("get-config: failed: %s", error_take->message);
@@ -204,7 +204,7 @@ _get_config_fetch_done_cb (NMHttpClient *http_client,
 	                                          NULL,
 	                                          &response_data,
 	                                          &error);
-	if (nm_utils_error_is_cancelled (error, FALSE))
+	if (nm_utils_error_is_cancelled (error))
 		return;
 
 	get_config_data = iface_data->get_config_data;
@@ -327,7 +327,7 @@ _get_config_metadata_ready_cb (GObject *source,
 		.n_pending       = 0,
 	};
 
-	if (nm_utils_error_is_cancelled (error, FALSE)) {
+	if (nm_utils_error_is_cancelled (error)) {
 		_get_config_task_return (iface_data, g_steal_pointer (&error));
 		return;
 	}
diff --git a/clients/common/meson.build b/clients/common/meson.build
index afa257b1..c32bb5e7 100644
--- a/clients/common/meson.build
+++ b/clients/common/meson.build
@@ -1,6 +1,6 @@
-common_inc = include_directories('.')
+# SPDX-License-Identifier: LGPL-2.1+
 
-nm_polkit_listener = files('nm-polkit-listener.c')
+common_inc = include_directories('.')
 
 common_deps = [
   libnm_dep,
@@ -13,6 +13,7 @@ sources = files(
   'nm-client-utils.c',
   'nm-secret-agent-simple.c',
   'nm-vpn-helpers.c',
+  'nm-polkit-listener.c',
 )
 
 libnmc_base = static_library(
diff --git a/clients/common/nm-client-utils.c b/clients/common/nm-client-utils.c
index 4d356edb..cf8b4785 100644
--- a/clients/common/nm-client-utils.c
+++ b/clients/common/nm-client-utils.c
@@ -525,6 +525,7 @@ nmc_password_subst_char (void)
 
 #pragma GCC visibility push(hidden)
 NM_PRAGMA_WARNING_DISABLE("-Wdeclaration-after-statement")
+#undef NDEBUG
 #define NDEBUG
 #include "qrcodegen.c"
 NM_PRAGMA_WARNING_REENABLE
diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c
index d9ccada9..03f9b313 100644
--- a/clients/common/nm-meta-setting-desc.c
+++ b/clients/common/nm-meta-setting-desc.c
@@ -190,8 +190,6 @@ _value_strsplit (const char *value,
                  gsize *out_len)
 {
 	gs_free const char **strv = NULL;
-	gsize i;
-	gsize len;
 
 	/* FIXME: some modes should support backslash escaping.
 	 * In particular, to distinguish from _value_str_as_index_list(), which
@@ -200,43 +198,24 @@ _value_strsplit (const char *value,
 	/* note that all modes remove empty tokens (",", "a,,b", ",,"). */
 	switch (split_mode) {
 	case VALUE_STRSPLIT_MODE_OBJLIST:
-		strv = nm_utils_strsplit_set (value, ESCAPED_TOKENS_DELIMITERS);
+		strv = nm_utils_strsplit_set_full (value,
+		                                   ESCAPED_TOKENS_DELIMITERS,
+		                                   NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP);
 		break;
 	case VALUE_STRSPLIT_MODE_MULTILIST:
-		strv = nm_utils_strsplit_set (value, ESCAPED_TOKENS_WITH_SPACES_DELIMTERS);
+		strv = nm_utils_strsplit_set_full (value,
+		                                   ESCAPED_TOKENS_WITH_SPACES_DELIMTERS,
+		                                   NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP);
 		break;
 	case VALUE_STRSPLIT_MODE_ESCAPED_TOKENS:
 		strv = nm_utils_escaped_tokens_split (value, ESCAPED_TOKENS_DELIMITERS);
-		NM_SET_OUT (out_len, NM_PTRARRAY_LEN (strv));
-		return g_steal_pointer (&strv);
+		break;
 	case VALUE_STRSPLIT_MODE_ESCAPED_TOKENS_WITH_SPACES:
 		strv = nm_utils_escaped_tokens_split (value, ESCAPED_TOKENS_WITH_SPACES_DELIMTERS);
-		NM_SET_OUT (out_len, NM_PTRARRAY_LEN (strv));
-		return g_steal_pointer (&strv);
-	default:
-		nm_assert_not_reached ();
 		break;
 	}
 
-	NM_SET_OUT (out_len, 0);
-
-	if (!strv)
-		return NULL;
-
-	len = 0;
-	for (i = 0; strv[i]; i++) {
-		const char *s = strv[i];
-
-		s = nm_str_skip_leading_spaces (s);
-		if (s[0] == '\0')
-			continue;
-
-		g_strchomp ((char *) s);
-		strv[len++] = s;
-	}
-	strv[len] = NULL;
-
-	NM_SET_OUT (out_len, len);
+	NM_SET_OUT (out_len, NM_PTRARRAY_LEN (strv));
 	return g_steal_pointer (&strv);
 }
 
@@ -364,7 +343,7 @@ _parse_ip_route (int family,
 	for (i = 1; routev[i]; i++) {
 		gint64 tmp64;
 
-		if (nm_utils_ipaddr_valid (family, routev[i])) {
+		if (nm_utils_ipaddr_is_valid (family, routev[i])) {
 			if (metric != -1 || attrs) {
 				g_set_error (error, 1, 0, _("the next hop ('%s') must be first"), routev[i]);
 				return NULL;
@@ -638,6 +617,8 @@ _env_warn_fcn (const NMMetaEnvironment *environment,
 #define ARGS_SETTING_INIT_FCN \
 	const NMMetaSettingInfoEditor *setting_info, NMSetting *setting, NMMetaAccessorSettingInitType init_type
 
+static gboolean _set_fcn_optionlist (ARGS_SET_FCN);
+
 static gboolean
 _SET_FCN_DO_RESET_DEFAULT (const NMMetaPropertyInfo *property_info, NMMetaAccessorModifier modifier, const char *value)
 {
@@ -904,6 +885,10 @@ _get_fcn_gobject_impl (const NMMetaPropertyInfo *property_info,
 		GString *str;
 		gsize i;
 
+		nm_assert (   property_info->setting_info == &nm_meta_setting_infos_editor[NM_META_SETTING_TYPE_WIRED]
+		           && NM_IN_STRSET (property_info->property_name, NM_SETTING_WIRED_S390_OPTIONS));
+		nm_assert (property_info->property_type->set_fcn == _set_fcn_optionlist);
+
 		strdict = g_value_get_boxed (&val);
 		keys = nm_utils_strdict_get_keys (strdict, TRUE, NULL);
 		if (!keys)
@@ -911,12 +896,16 @@ _get_fcn_gobject_impl (const NMMetaPropertyInfo *property_info,
 
 		str = g_string_new (NULL);
 		for (i = 0; keys[i]; i++) {
+			const char *key = keys[i];
+			const char *v = g_hash_table_lookup (strdict, key);
+			gs_free char *escaped_key = NULL;
+			gs_free char *escaped_val = NULL;
+
 			if (str->len > 0)
 				g_string_append_c (str, ',');
-			g_string_append_printf (str,
-			                        "%s=%s",
-			                        keys[i],
-			                        (const char *) g_hash_table_lookup (strdict, keys[i]));
+			g_string_append (str, nm_utils_escaped_tokens_options_escape_key (key, &escaped_key));
+			g_string_append_c (str, '=');
+			g_string_append (str, nm_utils_escaped_tokens_options_escape_val (v, &escaped_val));
 		}
 		RETURN_STR_TO_FREE (g_string_free (str, FALSE));
 	}
@@ -1761,17 +1750,6 @@ secret_flags_to_string (guint32 flags, NMMetaAccessorGetType get_type)
 	return g_string_free (flag_str, FALSE);
 }
 
-static void
-vpn_data_item (const char *key, const char *value, gpointer user_data)
-{
-	GString *ret_str = (GString *) user_data;
-
-	if (ret_str->len != 0)
-		g_string_append (ret_str, ", ");
-
-	g_string_append_printf (ret_str, "%s = %s", key, value);
-}
-
 static const char *
 _multilist_do_validate (const NMMetaPropertyInfo *property_info,
                         NMSetting *setting,
@@ -1919,6 +1897,7 @@ _set_fcn_optionlist (ARGS_SET_FCN)
 {
 	gs_free const char **strv = NULL;
 	gs_free const char **strv_val = NULL;
+	gsize strv_len;
 	gsize i, nstrv;
 
 	nm_assert (!error || !*error);
@@ -1927,24 +1906,16 @@ _set_fcn_optionlist (ARGS_SET_FCN)
 		return _gobject_property_reset_default (setting, property_info->property_name);
 
 	nstrv = 0;
-	strv = nm_utils_strsplit_set (value, ",");
+	strv = nm_utils_escaped_tokens_options_split_list (value);
 	if (strv) {
-		strv_val = g_new (const char *, NM_PTRARRAY_LEN (strv));
+		strv_len = NM_PTRARRAY_LEN (strv);
+
+		strv_val = g_new (const char *, strv_len);
 		for (i = 0; strv[i]; i++) {
 			const char *opt_name;
 			const char *opt_value;
 
-			opt_name = nm_str_skip_leading_spaces (strv[i]);
-
-			/* FIXME: support backslash escaping for the option list. */
-			opt_value = strchr (opt_name, '=');
-			if (opt_value) {
-				((char *) opt_value)[0] = '\0';
-				opt_value++;
-				opt_value = nm_str_skip_leading_spaces (opt_value);
-				g_strchomp ((char *) opt_value);
-			}
-			g_strchomp ((char *) opt_name);
+			nm_utils_escaped_tokens_options_split ((char *) strv[i], &opt_name, &opt_value);
 
 			if (   property_info->property_type->values_fcn
 			    || property_info->property_typ_data->values_static) {
@@ -2315,33 +2286,41 @@ static gconstpointer
 _get_fcn_bond_options (ARGS_GET_FCN)
 {
 	NMSettingBond *s_bond = NM_SETTING_BOND (setting);
-	GString *bond_options_s;
-	int i;
+	GString *str;
+	guint32 i, len;
 
 	RETURN_UNSUPPORTED_GET_TYPE ();
 
-	bond_options_s = g_string_new (NULL);
-	for (i = 0; i < nm_setting_bond_get_num_options (s_bond); i++) {
-		const char *key, *value;
-		gs_free char *tmp_value = NULL;
+	str = g_string_new (NULL);
+	len = nm_setting_bond_get_num_options (s_bond);
+	for (i = 0; i < len; i++) {
+		const char *key;
+		const char *val;
+		gs_free char *val_tmp = NULL;
 		char *p;
+		gs_free char *escaped_key = NULL;
+		gs_free char *escaped_val = NULL;
 
-		nm_setting_bond_get_option (s_bond, i, &key, &value);
+		nm_setting_bond_get_option (s_bond, i, &key, &val);
 
-		if (nm_streq0 (key, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)) {
-			value = tmp_value = g_strdup (value);
-			for (p = tmp_value; p && *p; p++) {
+		if (nm_streq (key, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)) {
+			val_tmp = g_strdup (val);
+			for (p = val_tmp; p && *p; p++) {
 				if (*p == ',')
 					*p = ' ';
 			}
+			val = val_tmp;
 		}
 
-		g_string_append_printf (bond_options_s, "%s=%s,", key, value);
+		if (str->len > 0u)
+			g_string_append_c (str, ',');
+		g_string_append (str, nm_utils_escaped_tokens_options_escape_key (key, &escaped_key));
+		g_string_append_c (str, '=');
+		g_string_append (str, nm_utils_escaped_tokens_options_escape_val (val, &escaped_val));
 	}
-	g_string_truncate (bond_options_s, bond_options_s->len-1);  /* chop off trailing ',' */
 
-	NM_SET_OUT (out_is_default, bond_options_s->len == 0);
-	RETURN_STR_TO_FREE (g_string_free (bond_options_s, FALSE));
+	NM_SET_OUT (out_is_default, str->len == 0);
+	RETURN_STR_TO_FREE (g_string_free (str, FALSE));
 }
 
 static gboolean
@@ -3316,7 +3295,7 @@ _set_fcn_ip_config_gateway (ARGS_SET_FCN)
 
 	value = nm_strstrip_avoid_copy_a (300, value, &value_to_free);
 
-	if (!nm_utils_ipaddr_valid (addr_family, value)) {
+	if (!nm_utils_ipaddr_is_valid (addr_family, value)) {
 		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
 		             _("invalid gateway address '%s'"),
 		             value);
@@ -3815,32 +3794,36 @@ _set_fcn_vlan_xgress_priority_map (ARGS_SET_FCN)
 	return TRUE;
 }
 
-static gconstpointer
-_get_fcn_vpn_data (ARGS_GET_FCN)
+static void
+_vpn_options_callback (const char *key, const char *val, gpointer user_data)
 {
-	NMSettingVpn *s_vpn = NM_SETTING_VPN (setting);
-	GString *data_item_str;
+	GString *str = user_data;
+	gs_free char *escaped_key = NULL;
+	gs_free char *escaped_val = NULL;
 
-	RETURN_UNSUPPORTED_GET_TYPE ();
+	if (str->len > 0u)
+		g_string_append (str, ", ");
 
-	data_item_str = g_string_new (NULL);
-	nm_setting_vpn_foreach_data_item (s_vpn, &vpn_data_item, data_item_str);
-	NM_SET_OUT (out_is_default, data_item_str->len == 0);
-	RETURN_STR_TO_FREE (g_string_free (data_item_str, FALSE));
+	g_string_append (str, nm_utils_escaped_tokens_options_escape_key (key, &escaped_key));
+	g_string_append (str, " = ");
+	g_string_append (str, nm_utils_escaped_tokens_options_escape_val (val, &escaped_val));
 }
 
 static gconstpointer
-_get_fcn_vpn_secrets (ARGS_GET_FCN)
+_get_fcn_vpn_options (ARGS_GET_FCN)
 {
 	NMSettingVpn *s_vpn = NM_SETTING_VPN (setting);
-	GString *secret_str;
+	GString *str;
 
 	RETURN_UNSUPPORTED_GET_TYPE ();
 
-	secret_str = g_string_new (NULL);
-	nm_setting_vpn_foreach_secret (s_vpn, &vpn_data_item, secret_str);
-	NM_SET_OUT (out_is_default, secret_str->len == 0);
-	RETURN_STR_TO_FREE (g_string_free (secret_str, FALSE));
+	str = g_string_new (NULL);
+	if (nm_streq (property_info->property_name, NM_SETTING_VPN_SECRETS))
+		nm_setting_vpn_foreach_secret (s_vpn, _vpn_options_callback, str);
+	else
+		nm_setting_vpn_foreach_data_item (s_vpn, _vpn_options_callback, str);
+	NM_SET_OUT (out_is_default, str->len == 0);
+	RETURN_STR_TO_FREE (g_string_free (str, FALSE));
 }
 
 static gboolean
@@ -4562,6 +4545,9 @@ static const NMMetaPropertyInfo *const property_infos_802_1X[] = {
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH,
 	    .property_type =                &_pt_gobject_string,
 	),
+	PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_DOMAIN_MATCH,
+	    .property_type =                &_pt_gobject_string,
+	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_CLIENT_CERT,
 	    .describe_message =
 	        N_("Enter file path to client certificate (optionally prefixed with file://).\n"
@@ -4659,6 +4645,9 @@ static const NMMetaPropertyInfo *const property_infos_802_1X[] = {
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH,
 	    .property_type =                &_pt_gobject_string,
 	),
+	PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_PHASE2_DOMAIN_MATCH,
+	    .property_type =                &_pt_gobject_string,
+	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_PHASE2_CLIENT_CERT,
 	    .describe_message =
 	        N_("Enter file path to client certificate for inner authentication (optionally prefixed\n"
@@ -4901,24 +4890,51 @@ static const NMMetaPropertyInfo *const property_infos_BRIDGE[] = {
 	    .prompt =                       N_("MAC address ageing time [300]"),
 	    .property_type =                &_pt_gobject_int,
 	),
+	PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_GROUP_ADDRESS,
+	    .property_type =                &_pt_gobject_mac,
+	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_GROUP_FORWARD_MASK,
 	    .is_cli_option =                TRUE,
 	    .property_alias =               "group-forward-mask",
 	    .prompt =                       N_("Group forward mask [0]"),
 	    .property_type =                &_pt_gobject_int,
 	),
+	PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_MULTICAST_QUERIER,
+	    .property_type =                &_pt_gobject_bool,
+	),
+	PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR,
+	    .property_type =                &_pt_gobject_bool,
+	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_MULTICAST_SNOOPING,
 	    .is_cli_option =                TRUE,
 	    .property_alias =               "multicast-snooping",
 	    .prompt =                       N_("Enable IGMP snooping [no]"),
 	    .property_type =                &_pt_gobject_bool,
 	),
+	PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_MULTICAST_ROUTER,
+	    .property_type =                &_pt_gobject_string,
+	    .property_typ_data = DEFINE_PROPERTY_TYP_DATA (
+	        .values_static =            NM_MAKE_STRV ("auto",
+	                                                  "disabled",
+	                                                  "enabled"),
+	    ),
+	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_VLAN_FILTERING,
 	    .property_type =                &_pt_gobject_bool,
 	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID,
 	    .property_type =                &_pt_gobject_int,
 	),
+	PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_VLAN_STATS_ENABLED,
+	    .property_type =                &_pt_gobject_bool,
+	),
+	PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_VLAN_PROTOCOL,
+	    .property_type =                &_pt_gobject_string,
+	    .property_typ_data = DEFINE_PROPERTY_TYP_DATA (
+	        .values_static =            NM_MAKE_STRV ("802.1Q",
+	                                                  "802.1ad"),
+	    ),
+	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_VLANS,
 	    .property_type =                &_pt_objlist,
 	    .property_typ_data = DEFINE_PROPERTY_TYP_DATA (
@@ -5123,7 +5139,8 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = {
 	                                                  NM_SETTING_BRIDGE_SETTING_NAME,
 	                                                  NM_SETTING_OVS_BRIDGE_SETTING_NAME,
 	                                                  NM_SETTING_OVS_PORT_SETTING_NAME,
-	                                                  NM_SETTING_TEAM_SETTING_NAME),
+	                                                  NM_SETTING_TEAM_SETTING_NAME,
+	                                                  NM_SETTING_VRF_SETTING_NAME),
 	    ),
 	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES,
@@ -6877,25 +6894,23 @@ static const NMMetaPropertyInfo *const property_infos_VPN[] = {
 	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_VPN_DATA,
 	    .property_type = DEFINE_PROPERTY_TYPE (
-	        .get_fcn =                  _get_fcn_vpn_data,
+	        .get_fcn =                  _get_fcn_vpn_options,
 	        .set_fcn =                  _set_fcn_optionlist,
 	        .set_supports_remove =      TRUE,
 	    ),
 	    .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (optionlist,
 	        .set_fcn =                  _optionlist_set_fcn_vpn_data,
-	        .no_empty_value =           TRUE,
 	    ),
 	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_VPN_SECRETS,
 	    .is_secret =                    TRUE,
 	    .property_type = DEFINE_PROPERTY_TYPE (
-	        .get_fcn =                  _get_fcn_vpn_secrets,
+	        .get_fcn =                  _get_fcn_vpn_options,
 	        .set_fcn =                  _set_fcn_optionlist,
 	        .set_supports_remove =      TRUE,
 	    ),
 	    .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (optionlist,
 	        .set_fcn =                  _optionlist_set_fcn_vpn_secrets,
-	        .no_empty_value =           TRUE,
 	    ),
 	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_VPN_PERSISTENT,
@@ -6908,6 +6923,20 @@ static const NMMetaPropertyInfo *const property_infos_VPN[] = {
 };
 
 #undef  _CURRENT_NM_META_SETTING_TYPE
+#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_VRF
+static const NMMetaPropertyInfo *const property_infos_VRF[] = {
+	PROPERTY_INFO_WITH_DESC (NM_SETTING_VRF_TABLE,
+	    .is_cli_option =                TRUE,
+	    .property_alias =               "table",
+	    .inf_flags =                    NM_META_PROPERTY_INF_FLAG_REQD,
+	    .prompt =                       N_("Table [0]"),
+	    .property_type =                &_pt_gobject_int,
+	),
+	NULL
+};
+
+
+#undef  _CURRENT_NM_META_SETTING_TYPE
 #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_VXLAN
 static const NMMetaPropertyInfo *const property_infos_VXLAN[] = {
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_VXLAN_PARENT,
@@ -7318,7 +7347,7 @@ static const NMMetaPropertyInfo *const property_infos_WIRELESS_SECURITY[] = {
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
 	    .property_type =                &_pt_gobject_string,
 	    .property_typ_data = DEFINE_PROPERTY_TYP_DATA (
-	        .values_static =            NM_MAKE_STRV ("none", "ieee8021x", "wpa-psk", "wpa-eap", "sae"),
+	        .values_static =            NM_MAKE_STRV ("none", "ieee8021x", "wpa-psk", "wpa-eap", "sae", "owe"),
 	    ),
 	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX,
@@ -7691,6 +7720,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN)
 #define SETTING_PRETTY_NAME_USER                N_("User settings")
 #define SETTING_PRETTY_NAME_VLAN                N_("VLAN connection")
 #define SETTING_PRETTY_NAME_VPN                 N_("VPN connection")
+#define SETTING_PRETTY_NAME_VRF                 N_("VRF connection")
 #define SETTING_PRETTY_NAME_VXLAN               N_("VXLAN connection")
 #define SETTING_PRETTY_NAME_WIFI_P2P            N_("Wi-Fi P2P connection")
 #define SETTING_PRETTY_NAME_WIMAX               N_("WiMAX connection")
@@ -7931,6 +7961,13 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
 	        NM_META_SETTING_VALID_PART_ITEM (VPN,                   TRUE),
 	    ),
 	),
+	SETTING_INFO (VRF,
+	    .valid_parts = NM_META_SETTING_VALID_PARTS (
+	        NM_META_SETTING_VALID_PART_ITEM (CONNECTION,            TRUE),
+	        NM_META_SETTING_VALID_PART_ITEM (VRF,                   TRUE),
+	    ),
+	),
+
 	SETTING_INFO (VXLAN,
 	    .valid_parts = NM_META_SETTING_VALID_PARTS (
 	        NM_META_SETTING_VALID_PART_ITEM (CONNECTION,            TRUE),
@@ -8055,6 +8092,10 @@ nm_meta_setting_info_valid_parts_for_slave_type (const char *slave_type, const c
 		NM_SET_OUT (out_slave_name, "team-slave");
 		return valid_settings_slave_team;
 	}
+	if (nm_streq (slave_type, NM_SETTING_VRF_SETTING_NAME)) {
+		NM_SET_OUT (out_slave_name, "vrf-slave");
+		return valid_settings_noslave;
+	}
 	return NULL;
 }
 
diff --git a/clients/common/nm-polkit-listener.c b/clients/common/nm-polkit-listener.c
index b2941652..7691ff4e 100644
--- a/clients/common/nm-polkit-listener.c
+++ b/clients/common/nm-polkit-listener.c
@@ -22,339 +22,965 @@
 
 #include "nm-polkit-listener.h"
 
-#include <stdio.h>
-#include <stdlib.h>
+#include <gio/gio.h>
+#include <pwd.h>
+#include <fcntl.h>
 
-#if WITH_POLKIT_AGENT
+#include "nm-glib-aux/nm-dbus-aux.h"
+#include "nm-glib-aux/nm-str-buf.h"
+#include "nm-glib-aux/nm-secret-utils.h"
+#include "nm-glib-aux/nm-io-utils.h"
+#include "nm-libnm-core-intern/nm-auth-subject.h"
+#include "c-list/src/c-list.h"
+
+#define LOGIND_BUS_NAME                     "org.freedesktop.login1"
+#define POLKIT_BUS_NAME                     "org.freedesktop.PolicyKit1"
+
+#define POLKIT_AUTHORITY_OBJ_PATH           "/org/freedesktop/PolicyKit1/Authority"
+#define POLKIT_AUTHORITY_IFACE_NAME         "org.freedesktop.PolicyKit1.Authority"
+
+#define POLKIT_AGENT_OBJ_PATH               "/org/freedesktop/PolicyKit1/AuthenticationAgent"
+#define POLKIT_AGENT_DBUS_INTERFACE         "org.freedesktop.PolicyKit1.AuthenticationAgent"
+
+#define LOGIND_OBJ_PATH                     "/org/freedesktop/login1"
+#define LOGIND_MANAGER_INTERFACE            "org.freedesktop.login1.Manager"
+
+#define NM_POLKIT_LISTENER_DBUS_CONNECTION  "dbus-connection"
+#define NM_POLKIT_LISTENER_SESSION_AGENT    "session-agent"
+
+#define POLKIT_DBUS_ERROR_FAILED            "org.freedesktop.PolicyKit1.Error.Failed"
 
 /*****************************************************************************/
 
-typedef struct {
-	gpointer reg_handle;  /* handle of polkit agent registration */
+enum {
+	REGISTERED,
+	REQUEST_SYNC,
+	ERROR,
+	LAST_SIGNAL
+};
 
-	GSimpleAsyncResult *simple;
-	PolkitAgentSession *active_session;
-	gulong cancel_id;
+static guint signals[LAST_SIGNAL] = { 0 };
+
+struct _NMPolkitListener {
+	GObject parent;
+	GDBusConnection *dbus_connection;
+	char *name_owner;
 	GCancellable *cancellable;
+	GMainContext *main_context;
+	CList request_lst_head;
+	guint pk_auth_agent_reg_id;
+	guint name_owner_changed_id;
+	bool session_agent:1;
+};
+
+struct _NMPolkitListenerClass {
+	GObjectClass parent;
+};
 
+G_DEFINE_TYPE (NMPolkitListener, nm_polkit_listener, G_TYPE_OBJECT);
+
+/*****************************************************************************/
+
+typedef struct {
+	CList request_lst;
+
+	NMPolkitListener *listener;
+	GSource *child_stdout_watch_source;
+	GSource *child_stdin_watch_source;
+	GDBusMethodInvocation *dbus_invocation;
 	char *action_id;
 	char *message;
-	char *icon_name;
-	char *identity;
+	char *username;
+	char *cookie;
+	NMStrBuf in_buffer;
+	NMStrBuf out_buffer;
+	gsize out_buffer_offset;
+
+	int child_stdout;
+	int child_stdin;
+
+	bool request_any_response:1;
+	bool request_is_completed:1;
+} AuthRequest;
+
+static const GDBusInterfaceInfo interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT (
+	POLKIT_AGENT_DBUS_INTERFACE,
+	.methods = NM_DEFINE_GDBUS_METHOD_INFOS (
+		NM_DEFINE_GDBUS_METHOD_INFO (
+			"BeginAuthentication",
+			.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
+				NM_DEFINE_GDBUS_ARG_INFO ("action_id", "s"),
+				NM_DEFINE_GDBUS_ARG_INFO ("message", "s"),
+				NM_DEFINE_GDBUS_ARG_INFO ("icon_name", "s"),
+				NM_DEFINE_GDBUS_ARG_INFO ("details", "a{ss}"),
+				NM_DEFINE_GDBUS_ARG_INFO ("cookie", "s"),
+				NM_DEFINE_GDBUS_ARG_INFO ("identities", "a(sa{sv})"),
+			),
+		),
+		NM_DEFINE_GDBUS_METHOD_INFO (
+			"CancelAuthentication",
+			.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
+				NM_DEFINE_GDBUS_ARG_INFO ("cookie", "s"),
+			),
+		),
+	),
+);
+
+static void
+auth_request_complete (AuthRequest *request, gboolean success)
+{
+	c_list_unlink (&request->request_lst);
 
-	const NMPolkitListenVtable *vtable;
-	gpointer vtable_user_data;
-} NMPolkitListenerPrivate;
+	if (success)
+		g_dbus_method_invocation_return_value (request->dbus_invocation, NULL);
+	else {
+		g_dbus_method_invocation_return_dbus_error (request->dbus_invocation,
+		                                            POLKIT_DBUS_ERROR_FAILED,
+		                                            "");
+	}
 
-G_DEFINE_TYPE (NMPolkitListener, nm_polkit_listener, POLKIT_AGENT_TYPE_LISTENER)
+	nm_clear_g_free (&request->action_id);
+	nm_clear_g_free (&request->message);
+	nm_clear_g_free (&request->username);
+	nm_clear_g_free (&request->cookie);
+	nm_clear_g_source_inst (&request->child_stdout_watch_source);
+	nm_clear_g_source_inst (&request->child_stdin_watch_source);
 
-#define NM_POLKIT_LISTENER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_POLKIT_LISTENER, NMPolkitListenerPrivate))
+	nm_str_buf_destroy (&request->in_buffer);
+	nm_str_buf_destroy (&request->out_buffer);
 
-/*****************************************************************************/
+	if (request->child_stdout != -1) {
+		nm_close (request->child_stdout);
+		request->child_stdout = -1;
+	}
 
-void
-nm_polkit_listener_set_vtable (NMPolkitListener *self,
-                               const NMPolkitListenVtable *vtable,
-                               gpointer user_data)
+	if (request->child_stdin != -1) {
+		nm_close (request->child_stdin);
+		request->child_stdin = -1;
+	}
+
+	nm_g_slice_free (request);
+}
+
+static gboolean
+uid_to_name (uid_t uid,
+             const char **out_name)
 {
-	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
+	const struct passwd *passwd;
 
-	priv->vtable = vtable;
-	priv->vtable_user_data = user_data;
+	if (*out_name)
+		return TRUE;
+
+	passwd = getpwuid (uid);
+	if (   !passwd
+	    || !passwd->pw_name)
+		return FALSE;
+
+	*out_name = passwd->pw_name;
+	return TRUE;
 }
 
-/*****************************************************************************/
+static char *
+choose_identity (GVariant *identities)
+{
+	GVariantIter identity_iter;
+	GVariant *details_tmp;
+	const char *kind;
+	gs_free char *username_first = NULL;
+	gs_free char *username_root = NULL;
+	const char *user;
+
+	/* Choose identity. First try current user, then root, and else
+	 * take the first one we find. */
+
+	user = getenv ("USER");
+
+	g_variant_iter_init (&identity_iter, identities);
+	while (g_variant_iter_next (&identity_iter, "(&s@a{sv})", &kind, &details_tmp)) {
+		gs_unref_variant GVariant *details = g_steal_pointer (&details_tmp);
+
+		if (nm_streq (kind, "unix-user")) {
+			gs_unref_variant GVariant *v = NULL;
+
+			v = g_variant_lookup_value (details, "uid", G_VARIANT_TYPE_UINT32);
+			if (v) {
+				guint32 uid = g_variant_get_uint32 (v);
+				const char *u = NULL;
+
+				if (user) {
+					if (!uid_to_name (uid, &u))
+						continue;
+					if (nm_streq (u, user))
+						return g_strdup (user);
+				}
+				if (   !username_root
+				    && uid == 0) {
+					if (!uid_to_name (uid, &u))
+						continue;
+					username_root = g_strdup (u);
+					if (!user)
+						break;
+				}
+				if (   !username_root
+				    && !username_first) {
+					if (!uid_to_name (uid, &u))
+						continue;
+					username_first = g_strdup (u);
+				}
+			}
+		}
+	}
+
+	if (username_root)
+		return g_steal_pointer (&username_root);
+
+	if (username_first)
+		return g_steal_pointer (&username_first);
+
+	return NULL;
+}
 
 static void
-on_request (PolkitAgentSession *session,
-            const char *request,
-            gboolean echo_on,
-            gpointer user_data)
+agent_register_cb (GObject *source_object,
+                   GAsyncResult *res,
+                   gpointer user_data)
 {
-	NMPolkitListener *self = NM_POLKIT_LISTENER (user_data);
-	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
-	gs_free char *response = NULL;
-
-	if (priv->vtable && priv->vtable->on_request) {
-		response = priv->vtable->on_request (self,
-		                                     request, priv->action_id,
-		                                     priv->message, priv->icon_name,
-		                                     priv->identity, echo_on,
-		                                     priv->vtable_user_data);
+	NMPolkitListener *listener = NM_POLKIT_LISTENER (user_data);
+	GDBusConnection *dbus_connection = G_DBUS_CONNECTION (source_object);
+	gs_free_error GError *error = NULL;
+	gs_unref_variant GVariant *ret = NULL;
+
+	ret = g_dbus_connection_call_finish (dbus_connection,
+	                                     res,
+	                                     &error);
+
+	if (nm_utils_error_is_cancelled (error)) {
+		return;
 	}
 
-	if (response)
-		polkit_agent_session_response (session, response);
-	else {
-		//FIXME: polkit_agent_session_cancel() should emit "completed", but it doesn't work for me ???
-		//polkit_agent_session_cancel (session);
-		polkit_agent_session_response (session, "");
+	if (ret) {
+		g_signal_emit (listener,
+		               signals[REGISTERED],
+		               0);
+	} else {
+		g_signal_emit (listener,
+		               signals[ERROR],
+		               0,
+		               error->message);
 	}
 }
 
 static void
-on_show_info (PolkitAgentSession *session,
-              const char *text,
-              gpointer user_data)
+agent_register (NMPolkitListener *self, const char *session_id)
 {
-	NMPolkitListener *self = NM_POLKIT_LISTENER (user_data);
-	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
+	const char *locale = NULL;
+	gs_unref_object NMAuthSubject *subject = NULL;
+	GVariant *subject_variant = NULL;
+
+	locale = g_getenv ("LANG");
+	if (locale == NULL) {
+		locale = "en_US.UTF-8";
+	}
 
-	if (priv->vtable && priv->vtable->on_show_info) {
-		priv->vtable->on_show_info (self, text,
-		                            priv->vtable_user_data);
+	if (self->session_agent) {
+		subject = nm_auth_subject_new_unix_session (session_id);
+	} else {
+		subject = nm_auth_subject_new_unix_process_self ();
 	}
+	subject_variant = nm_auth_subject_unix_to_polkit_gvariant (subject);
+
+	g_dbus_connection_call (self->dbus_connection,
+	                        self->name_owner,
+	                        POLKIT_AUTHORITY_OBJ_PATH,
+	                        POLKIT_AUTHORITY_IFACE_NAME,
+	                        "RegisterAuthenticationAgent",
+	                        g_variant_new ("(@(sa{sv})ss)",
+	                                       subject_variant,
+	                                       locale,
+	                                       POLKIT_AGENT_OBJ_PATH),
+	                        NULL,
+	                        G_DBUS_CALL_FLAGS_NONE,
+	                        -1,
+	                        self->cancellable,
+	                        agent_register_cb,
+	                        self);
 }
 
 static void
-on_show_error (PolkitAgentSession *session,
-               const char *text,
-               gpointer user_data)
+agent_unregister (NMPolkitListener *self)
 {
-	NMPolkitListener *self = NM_POLKIT_LISTENER (user_data);
-	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
+	gs_unref_object NMAuthSubject *subject = NULL;
+	GVariant *subject_variant = NULL;
+
+	subject = nm_auth_subject_new_unix_process_self ();
+	subject_variant = nm_auth_subject_unix_to_polkit_gvariant (subject);
+
+	g_dbus_connection_call (self->dbus_connection,
+	                        self->name_owner,
+	                        POLKIT_AUTHORITY_OBJ_PATH,
+	                        POLKIT_AUTHORITY_IFACE_NAME,
+	                        "UnregisterAuthenticationAgent",
+	                        g_variant_new ("(@(sa{sv})s)",
+	                                       subject_variant,
+	                                       POLKIT_AGENT_OBJ_PATH),
+	                        NULL,
+	                        G_DBUS_CALL_FLAGS_NONE,
+	                        -1,
+	                        NULL,
+	                        NULL,
+	                        self);
+}
 
-	if (priv->vtable && priv->vtable->on_show_error) {
-		priv->vtable->on_show_error (self, text,
-		                             priv->vtable_user_data);
+static void
+retrieve_session_id_cb (GObject *source_object,
+                        GAsyncResult *res,
+                        gpointer user_data)
+{
+	NMPolkitListener *listener = NM_POLKIT_LISTENER (user_data);
+	char *session_id;
+	guint32 session_uid;
+	nm_auto_free_variant_iter GVariantIter *iter;
+	gs_unref_variant GVariant *ret = NULL;
+	gs_free_error GError *error = NULL;
+	gs_free char *err_str = NULL;
+	uid_t uid = getuid ();
+
+	ret = g_dbus_connection_call_finish (listener->dbus_connection,
+	                                     res,
+	                                     &error);
+
+	if (nm_utils_error_is_cancelled (error)) {
+		return;
 	}
+
+	if (ret) {
+		g_variant_get_child (ret, 0, "a(susso)", &iter);
+
+		while (g_variant_iter_next (iter, "(&su@s@s@o)",
+		                            &session_id,
+		                            &session_uid,
+		                            NULL, NULL, NULL)) {
+			if (session_uid == uid) {
+				agent_register (listener, session_id);
+				return;
+			}
+		}
+		err_str = g_strdup_printf (_("Could not find any session id for uid %d"), uid);
+	} else {
+		err_str = g_strdup_printf (_("Could not retrieve session id: %s"),
+		                                error->message);
+	}
+
+	g_signal_emit (listener,
+	               signals[ERROR],
+	               0,
+	               err_str);
 }
 
 static void
-on_completed (PolkitAgentSession *session,
-              gboolean gained_authorization,
-              gpointer user_data)
+retrieve_session_id (NMPolkitListener *self)
+{
+	g_dbus_connection_call (self->dbus_connection,
+	                        LOGIND_BUS_NAME,
+	                        LOGIND_OBJ_PATH,
+	                        LOGIND_MANAGER_INTERFACE,
+	                        "ListSessions",
+	                        NULL,
+	                        G_VARIANT_TYPE ("(a(susso))"),
+	                        G_DBUS_CALL_FLAGS_NONE,
+	                        -1,
+	                        self->cancellable,
+	                        retrieve_session_id_cb,
+	                        self);
+}
+
+static gboolean
+io_watch_can_write (int fd,
+                    GIOCondition condition,
+                    gpointer user_data)
 {
-	NMPolkitListener *self = NM_POLKIT_LISTENER (user_data);
-	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
+	AuthRequest *request = user_data;
+	gssize n_written;
+
+	if (NM_FLAGS_ANY (condition, (G_IO_HUP | G_IO_ERR)))
+		goto done;
+
+	n_written = write (request->child_stdin,
+	                   &((nm_str_buf_get_str_unsafe (&request->out_buffer))[request->out_buffer_offset]),
+	                   request->out_buffer.len - request->out_buffer_offset);
+
+	if (   n_written < 0
+	    && errno != EAGAIN)
+		goto done;
+
+	if (n_written > 0) {
+		if ((gsize) n_written >= (request->out_buffer.len - request->out_buffer_offset)) {
+			nm_assert ((gsize) n_written == (request->out_buffer.len - request->out_buffer_offset));
+			goto done;
+		}
+		request->out_buffer_offset += (gsize) n_written;
+	}
+
+	return G_SOURCE_CONTINUE;
+
+done:
+	nm_str_buf_set_size (&request->out_buffer, 0, TRUE, FALSE);
+	request->out_buffer_offset = 0;
+	nm_clear_g_source_inst (&request->child_stdin_watch_source);
 
-	if (priv->vtable->on_completed) {
-		priv->vtable->on_completed (self, gained_authorization,
-		                            priv->vtable_user_data);
+	if (request->request_is_completed)
+		auth_request_complete (request, TRUE);
+
+	return G_SOURCE_CONTINUE;
+}
+
+static void
+queue_string_to_helper (AuthRequest *request, const char *response)
+{
+	g_return_if_fail (response);
+
+	if (!nm_str_buf_is_initalized (&request->out_buffer))
+		nm_str_buf_init (&request->out_buffer, strlen (response) + 2u,  TRUE);
+
+	nm_str_buf_append (&request->out_buffer, response);
+	nm_str_buf_ensure_trailing_c (&request->out_buffer, '\n');
+
+	if (!request->child_stdin_watch_source) {
+		request->child_stdin_watch_source = nm_g_unix_fd_source_new (request->child_stdin,
+		                                                             G_IO_OUT | G_IO_ERR | G_IO_HUP,
+		                                                             G_PRIORITY_DEFAULT,
+		                                                             io_watch_can_write,
+		                                                             request,
+		                                                             NULL);
+		g_source_attach (request->child_stdin_watch_source,
+		                 request->listener->main_context);
 	}
+}
 
-	g_simple_async_result_complete_in_idle (priv->simple);
+static gboolean
+io_watch_have_data (int fd,
+                    GIOCondition condition,
+                    gpointer user_data)
+{
+	AuthRequest *request = user_data;
+	gboolean auth_result;
+	gssize n_read;
 
-	g_object_unref (priv->simple);
-	g_object_unref (priv->active_session);
-	if (priv->cancellable) {
-		g_cancellable_disconnect (priv->cancellable, priv->cancel_id);
-		g_object_unref (priv->cancellable);
+	if (NM_FLAGS_ANY (condition, G_IO_HUP | G_IO_ERR))
+		n_read = -EIO;
+	else
+		n_read = nm_utils_fd_read (fd, &request->in_buffer);
+
+	if (n_read <= 0) {
+		if (n_read == -EAGAIN) {
+			/* wait longer. */
+			return G_SOURCE_CONTINUE;
+		}
+
+		/* Either an error or EOF happened. The data we parsed so far was not relevant.
+		 * Regardless of what we still have unprocessed in the receive buffers, we are done.
+		 *
+		 * We would expect that the other side completed with SUCCESS or FAILURE. Apparently
+		 * it didn't. If we had any good request, we assume success. */
+		auth_result = request->request_any_response;
+		goto out;
 	}
 
-	priv->simple = NULL;
-	priv->active_session = NULL;
-	priv->cancel_id = 0;
+	while (TRUE) {
+		char *line_terminator;
+		const char *line;
+
+		line = nm_str_buf_get_str (&request->in_buffer);
+		line_terminator = (char *) strchr (line, '\n');
+		if (!line_terminator) {
+			/* We don't have a complete line. Wait longer. */
+			return G_SOURCE_CONTINUE;
+		}
+		line_terminator[0] = '\0';
+
+		if (   NM_STR_HAS_PREFIX (line, "PAM_PROMPT_ECHO_OFF ")
+		    || NM_STR_HAS_PREFIX (line, "PAM_PROMPT_ECHO_ON ")) {
+			nm_auto_free_secret char *response = NULL;
+
+			/* FIXME(cli-async): emit signal and wait for response (blocking) */
+			g_signal_emit (request->listener,
+			               signals[REQUEST_SYNC],
+			               0,
+			               request->action_id,
+			               request->message,
+			               request->username,
+			               &response);
+
+			if (response) {
+				queue_string_to_helper (request, response);
+				request->request_any_response = TRUE;
+				goto erase_line;
+			}
+			auth_result = FALSE;
+		} else if (nm_streq (line, "SUCCESS"))
+			auth_result = TRUE;
+		else if (nm_streq (line, "FAILURE"))
+			auth_result = FALSE;
+		else if (   NM_STR_HAS_PREFIX (line, "PAM_ERROR_MSG ")
+		         || NM_STR_HAS_PREFIX (line, "PAM_TEXT_INFO ")) {
+			/* ignore. */
+			goto erase_line;
+		} else {
+			/* unknown command. Fail. */
+			auth_result = FALSE;
+		}
+
+		break;
+erase_line:
+		nm_str_buf_erase (&request->in_buffer, 0, line_terminator - line + 1u, TRUE);
+	}
+
+out:
+	request->request_is_completed = TRUE;
+	nm_clear_g_source_inst (&request->child_stdout_watch_source);
+	if (   auth_result
+	    && request->child_stdin_watch_source) {
+		/* we need to wait for the buffer to send the response. */
+	} else
+		auth_request_complete (request, auth_result);
 
-	g_clear_pointer (&priv->action_id, g_free);
-	g_clear_pointer (&priv->message, g_free);
-	g_clear_pointer (&priv->icon_name, g_free);
-	g_clear_pointer (&priv->identity, g_free);
+	return G_SOURCE_CONTINUE;
 }
 
 static void
-on_cancelled (GCancellable *cancellable, gpointer user_data)
+begin_authentication (AuthRequest *request)
 {
-	NMPolkitListener *self = NM_POLKIT_LISTENER (user_data);
-	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
+	int fd_flags;
+	const char *helper_argv[] = {
+		POLKIT_PACKAGE_PREFIX "/lib/polkit-1/polkit-agent-helper-1",
+		request->username,
+		NULL,
+	};
+
+	if (!request->username) {
+		auth_request_complete (request, FALSE);
+		return;
+	}
+
+	if (!g_spawn_async_with_pipes (NULL,
+	                               (char **) helper_argv,
+	                               NULL,
+	                               G_SPAWN_STDERR_TO_DEV_NULL,
+	                               NULL,
+	                               NULL,
+	                               NULL,
+	                               &request->child_stdin,
+	                               &request->child_stdout,
+	                               NULL,
+	                               NULL)) {
+		/* not findind the PolicyKit setuid helper is a critical error */
+		request->child_stdin = -1;
+		request->child_stdout = -1;
+		g_signal_emit (request->listener,
+		               signals[ERROR],
+		               0,
+		               "The PolicyKit setuid helper 'polkit-agent-helper-1' has not been found");
+
+		auth_request_complete (request, FALSE);
+		return;
+	}
+
+	fd_flags = fcntl (request->child_stdin, F_GETFD, 0);
+	fcntl (request->child_stdin, F_SETFL, fd_flags | O_NONBLOCK);
 
-	polkit_agent_session_cancel (priv->active_session);
+	fd_flags = fcntl (request->child_stdout, F_GETFD, 0);
+	fcntl (request->child_stdout, F_SETFL, fd_flags | O_NONBLOCK);
+
+	request->child_stdout_watch_source = nm_g_unix_fd_source_new (request->child_stdout,
+	                                                              G_IO_IN | G_IO_ERR | G_IO_HUP,
+	                                                              G_PRIORITY_DEFAULT,
+	                                                              io_watch_have_data,
+	                                                              request,
+	                                                              NULL);
+	g_source_attach (request->child_stdout_watch_source,
+	                 request->listener->main_context);
+
+	/* Write the cookie on stdin so it can't be seen by other processes */
+	queue_string_to_helper (request, request->cookie);
+
+	return;
 }
 
-static int
-compare_users (gconstpointer a, gconstpointer b)
+static AuthRequest*
+get_request (NMPolkitListener *listener,
+                    const char *cookie)
 {
-	char *user;
-	int ret;
+	AuthRequest *request;
 
-	if (POLKIT_IS_UNIX_USER (a))
-		user = g_strdup (polkit_unix_user_get_name (POLKIT_UNIX_USER (a)));
-	else
-		user = polkit_identity_to_string (POLKIT_IDENTITY (a));
+	c_list_for_each_entry (request, &listener->request_lst_head, request_lst) {
+		if (nm_streq0 (cookie, request->cookie)) {
+			return request;
+		}
+	}
+	return NULL;
+}
 
-	ret = g_strcmp0 ((const char *) user, (const char *) b);
-	g_free (user);
-	return ret;
+static AuthRequest*
+create_request (NMPolkitListener *listener,
+                GDBusMethodInvocation *invocation,
+                const char *action_id,
+                const char *message,
+                char *username_take,
+                const char *cookie)
+{
+	AuthRequest *request;
+
+	request = g_slice_new (AuthRequest);
+	*request = (AuthRequest) {
+		.listener             = listener,
+		.dbus_invocation      = invocation,
+		.action_id            = g_strdup (action_id),
+		.message              = g_strdup (message),
+		.username             = g_steal_pointer (&username_take),
+		.cookie               = g_strdup (cookie),
+		.request_any_response = FALSE,
+		.request_is_completed = FALSE,
+	};
+
+	nm_str_buf_init (&request->in_buffer,  NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
+
+	c_list_link_tail (&listener->request_lst_head, &request->request_lst);
+	return request;
 }
 
-static PolkitIdentity *
-choose_identity (GList *identities)
+static void
+dbus_method_call_cb (GDBusConnection *connection,
+                     const char *sender,
+                     const char *object_path,
+                     const char *interface_name,
+                     const char *method_name,
+                     GVariant *parameters,
+                     GDBusMethodInvocation *invocation,
+                     gpointer user_data)
 {
-	const char *user;
-	GList *elem;
+	NMPolkitListener *listener = NM_POLKIT_LISTENER (user_data);
+	const char *action_id;
+	const char *message;
+	const char *cookie;
+	AuthRequest *request;
+	gs_unref_variant GVariant *identities_gvariant;
+
+	if (nm_streq (method_name, "BeginAuthentication")) {
+		g_variant_get (parameters,
+		               "(&s&s&s@a{ss}&s@a(sa{sv}))",
+		               &action_id,
+		               &message,
+		               NULL,
+		               NULL,
+		               &cookie,
+		               &identities_gvariant);
+
+		request = create_request (listener,
+		                          invocation,
+		                          action_id,
+		                          message,
+		                          choose_identity (identities_gvariant),
+		                          cookie);
+		begin_authentication (request);
+		return;
+	}
 
-	/* Choose identity. First try current user, then root, and else
-	 * take the first one */
-	user = getenv("USER");
-	elem = g_list_find_custom (identities, user, (GCompareFunc) compare_users);
-	if (!elem) {
-		elem = g_list_find_custom (identities, "root", (GCompareFunc) compare_users);
-		if (!elem)
-			elem = identities;
+	if (nm_streq (method_name, "CancelAuthentication")) {
+		g_variant_get (parameters,
+		               "&s",
+		               &cookie);
+		request = get_request (listener, cookie);
+
+		if (!request) {
+			gs_free char *msg = NULL;
+
+			msg = g_strdup_printf ("No pending authentication request for cookie '%s'",
+			                       cookie);
+			g_dbus_method_invocation_return_dbus_error (invocation,
+			                                            POLKIT_DBUS_ERROR_FAILED,
+			                                            msg);
+			return;
+		}
+
+		/* Complete a cancelled request with success. */
+		auth_request_complete (request, TRUE);
+		return;
 	}
 
-	return elem->data;
+	g_dbus_method_invocation_return_error (invocation,
+	                                       G_DBUS_ERROR,
+	                                       G_DBUS_ERROR_UNKNOWN_METHOD,
+	                                       "Unknown method %s",
+	                                       method_name);
+}
+
+static gboolean
+export_dbus_iface (NMPolkitListener *self, GError **error)
+{
+	GDBusInterfaceVTable interface_vtable = {
+		.method_call = dbus_method_call_cb,
+		.set_property = NULL,
+		.get_property = NULL,
+	};
+
+	g_return_val_if_fail (NM_IS_POLKIT_LISTENER (self), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	/* Agent listener iface has been exported already */
+	if (self->pk_auth_agent_reg_id) {
+		return TRUE;
+	}
+
+	self->pk_auth_agent_reg_id =
+		g_dbus_connection_register_object (self->dbus_connection,
+		                                   POLKIT_AGENT_OBJ_PATH,
+		                                   (GDBusInterfaceInfo*) &interface_info,
+		                                   &interface_vtable,
+		                                   self,
+		                                   NULL,
+		                                   error);
+	if (!self->pk_auth_agent_reg_id) {
+		g_signal_emit (self,
+		               signals[ERROR],
+		               0,
+		               "Could not register as a PolicyKit Authentication Agent");
+	}
+	return self->pk_auth_agent_reg_id;
 }
 
 static void
-initiate_authentication (PolkitAgentListener  *listener,
-                         const char           *action_id,
-                         const char           *message,
-                         const char           *icon_name,
-                         PolkitDetails        *details,
-                         const char           *cookie,
-                         GList                *identities,
-                         GCancellable         *cancellable,
-                         GAsyncReadyCallback   callback,
-                         gpointer              user_data)
+name_owner_changed (NMPolkitListener *self,
+                    const char *name_owner)
 {
-	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (listener);
-	GSimpleAsyncResult *simple;
-	PolkitIdentity *identity;
-
-	simple = g_simple_async_result_new (G_OBJECT (listener),
-	                                    callback,
-	                                    user_data,
-	                                    initiate_authentication);
-	if (cancellable)
-		g_simple_async_result_set_check_cancellable (simple, cancellable);
-	if (priv->active_session != NULL) {
-		g_simple_async_result_set_error (simple,
-		                                 POLKIT_ERROR,
-		                                 POLKIT_ERROR_FAILED,
-		                                 _("An authentication session is already underway."));
-		g_simple_async_result_complete_in_idle (simple);
-		g_object_unref (simple);
+	gs_free_error GError *error = NULL;
+
+	name_owner = nm_str_not_empty (name_owner);
+
+	if (nm_streq0 (self->name_owner, name_owner)) {
 		return;
 	}
 
-	/* Choose identity */
-	identity = choose_identity (identities);
-
-	priv->active_session = polkit_agent_session_new (identity, cookie);
-	g_signal_connect (priv->active_session,
-	                  "completed",
-	                  G_CALLBACK (on_completed),
-	                  listener);
-	g_signal_connect (priv->active_session,
-	                  "request",
-	                  G_CALLBACK (on_request),
-	                  listener);
-	g_signal_connect (priv->active_session,
-	                  "show-info",
-	                  G_CALLBACK (on_show_info),
-	                  listener);
-	g_signal_connect (priv->active_session,
-	                  "show-error",
-	                  G_CALLBACK (on_show_error),
-	                  listener);
-
-	priv->action_id = g_strdup (action_id);
-	priv->message = g_strdup (message);
-	priv->icon_name = g_strdup (icon_name);
-	if (POLKIT_IS_UNIX_USER (identity))
-		priv->identity = g_strdup (polkit_unix_user_get_name (POLKIT_UNIX_USER (identity)));
-	else
-		priv->identity = polkit_identity_to_string (identity);
+	g_free (self->name_owner);
+	self->name_owner = g_strdup (name_owner);
 
-	priv->simple = simple;
-	priv->cancellable = g_object_ref (cancellable);
-	priv->cancel_id = g_cancellable_connect (cancellable,
-	                                         G_CALLBACK (on_cancelled),
-	                                         listener,
-	                                         NULL);
+	if (!self->name_owner) {
+		return;
+	}
 
-	polkit_agent_session_initiate (priv->active_session);
+	if (export_dbus_iface (self, &error)) {
+		if (self->session_agent) {
+			retrieve_session_id (self);
+		} else {
+			agent_register (self, NULL);
+		}
+	} else {
+		g_signal_emit (self,
+		               signals[ERROR],
+		               0,
+		               "Could not export the PolicyKit Authentication Agent DBus interface");
+	}
 }
 
-static gboolean
-initiate_authentication_finish (PolkitAgentListener *listener,
-                                GAsyncResult *result,
-                                GError **error)
+static void
+name_owner_changed_cb (GDBusConnection *connection,
+                       const char *sender_name,
+                       const char *object_path,
+                       const char *interface_name,
+                       const char *signal_name,
+                       GVariant *parameters,
+                       gpointer user_data)
+{
+	NMPolkitListener *self = user_data;
+	const char *new_owner;
+
+	if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sss)"))) {
+		return;
+	}
+
+	g_variant_get (parameters,
+	               "(&s&s&s)",
+	               NULL,
+	               NULL,
+	               &new_owner);
+
+	name_owner_changed (self, new_owner);
+}
+
+static void
+get_name_owner_cb (const char *name_owner,
+                   GError *error,
+                   gpointer user_data)
 {
-	return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
+	if (!name_owner && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+		return;
+	}
+	name_owner_changed (user_data, name_owner);
 }
 
 /*****************************************************************************/
 
+NM_GOBJECT_PROPERTIES_DEFINE (NMPolkitListener,
+	PROP_DBUS_CONNECTION,
+	PROP_SESSION_AGENT,
+);
+
+static void
+set_property (GObject *object,
+              guint prop_id,
+              const GValue *value,
+              GParamSpec *pspec)
+{
+	NMPolkitListener *self = NM_POLKIT_LISTENER (object);
+
+	switch (prop_id) {
+	case PROP_DBUS_CONNECTION:
+		self->dbus_connection = g_value_dup_object (value);
+		break;
+	case PROP_SESSION_AGENT:
+		self->session_agent = g_value_get_boolean (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nm_polkit_listener_init (NMPolkitListener *self)
+{
+	c_list_init (&self->request_lst_head);
+	self->main_context = g_main_context_ref_thread_default ();
+}
+
 static void
-nm_polkit_listener_init (NMPolkitListener *agent)
+constructed (GObject *object)
 {
+	NMPolkitListener *self = NM_POLKIT_LISTENER (object);
+
+	self->cancellable = g_cancellable_new ();
+
+	self->name_owner_changed_id =
+	    nm_dbus_connection_signal_subscribe_name_owner_changed (self->dbus_connection,
+	                                                            POLKIT_BUS_NAME,
+	                                                            name_owner_changed_cb,
+	                                                            self,
+	                                                            NULL);
+
+	nm_dbus_connection_call_get_name_owner (self->dbus_connection,
+	                                        POLKIT_BUS_NAME,
+	                                        -1,
+	                                        self->cancellable,
+	                                        get_name_owner_cb,
+	                                        self);
+
+	G_OBJECT_CLASS (nm_polkit_listener_parent_class)->constructed (object);
 }
 
 /**
  * nm_polkit_listener_new:
- * @for_session: %TRUE for registering the polkit agent for the user session,
- *   %FALSE for registering it for the running process
- * @vtable: mandatory callbacks
- * @user_data: user-data pointer for callbacks
- * @error: location to store error, or %NULL
+ * @dbus_connection: a open DBus connection
+ * @session_agent: TRUE if a session agent is wanted, FALSE for a process agent
  *
  * Creates a new #NMPolkitListener and registers it as a polkit agent.
  *
  * Returns: a new #NMPolkitListener
  */
 NMPolkitListener *
-nm_polkit_listener_new (gboolean for_session,
-                        GError **error)
+nm_polkit_listener_new (GDBusConnection *dbus_connection, gboolean session_agent)
 {
-	NMPolkitListener *listener;
-	PolkitSubject* session;
-	NMPolkitListenerPrivate *priv;
-
-	g_return_val_if_fail (!error || !*error, NULL);
-
-	listener = g_object_new (NM_TYPE_POLKIT_LISTENER, NULL);
-
-	priv = NM_POLKIT_LISTENER_GET_PRIVATE (listener);
-
-	if (for_session) {
-		session = polkit_unix_session_new_for_process_sync (getpid (), NULL, error);
-		if (!session)
-			return NULL;
-	} else
-		session = polkit_unix_process_new_for_owner (getpid (), 0, getuid ());
-
-	priv->reg_handle = polkit_agent_listener_register (POLKIT_AGENT_LISTENER (listener),
-	                                                   POLKIT_AGENT_REGISTER_FLAGS_NONE,
-	                                                   session, NULL, NULL, error);
-	if (!priv->reg_handle) {
-		g_object_unref (listener);
-		g_object_unref (session);
-		return NULL;
-	}
-
-	return listener;
+	return g_object_new (NM_TYPE_POLKIT_LISTENER,
+	                     NM_POLKIT_LISTENER_DBUS_CONNECTION, dbus_connection,
+	                     NM_POLKIT_LISTENER_SESSION_AGENT, session_agent,
+	                     NULL);
 }
 
 static void
-nm_polkit_listener_finalize (GObject *object)
+dispose (GObject *object)
 {
-	NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (object);
-
-	if (priv->reg_handle)
-		polkit_agent_listener_unregister (priv->reg_handle);
+	NMPolkitListener *self = NM_POLKIT_LISTENER (object);
+	AuthRequest *request;
+
+	nm_clear_g_cancellable (&self->cancellable);
+
+	while ((request = c_list_first_entry (&self->request_lst_head, AuthRequest, request_lst)))
+		auth_request_complete (request, FALSE);
+
+	if (self->dbus_connection) {
+		nm_clear_g_dbus_connection_signal (self->dbus_connection,
+		                                   &self->name_owner_changed_id);
+		g_dbus_connection_unregister_object (self->dbus_connection,
+		                                     self->pk_auth_agent_reg_id);
+		agent_unregister (self);
+		nm_clear_g_free (&self->name_owner);
+		g_clear_object (&self->dbus_connection);
+	}
 
-	g_free (priv->action_id);
-	g_free (priv->message);
-	g_free (priv->icon_name);
-	g_free (priv->identity);
+	nm_clear_pointer (&self->main_context, g_main_context_unref);
 
-	G_OBJECT_CLASS (nm_polkit_listener_parent_class)->finalize (object);
+	G_OBJECT_CLASS (nm_polkit_listener_parent_class)->dispose (object);
 }
 
 static void
 nm_polkit_listener_class_init (NMPolkitListenerClass *klass)
 {
-	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-	PolkitAgentListenerClass *pkal_class = POLKIT_AGENT_LISTENER_CLASS (klass);
-
-	g_type_class_add_private (klass, sizeof (NMPolkitListenerPrivate));
-
-	gobject_class->finalize = nm_polkit_listener_finalize;
-
-	pkal_class->initiate_authentication = initiate_authentication;
-	pkal_class->initiate_authentication_finish = initiate_authentication_finish;
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->set_property = set_property;
+	object_class->constructed = constructed;
+	object_class->dispose = dispose;
+
+	obj_properties[PROP_DBUS_CONNECTION] =
+	    g_param_spec_object (NM_POLKIT_LISTENER_DBUS_CONNECTION, "", "",
+	                         G_TYPE_DBUS_CONNECTION,
+	                         G_PARAM_CONSTRUCT_ONLY |
+	                         G_PARAM_WRITABLE |
+	                         G_PARAM_STATIC_STRINGS);
+
+	obj_properties[PROP_SESSION_AGENT] =
+	    g_param_spec_boolean (NM_POLKIT_LISTENER_SESSION_AGENT, "", "",
+	                          FALSE,
+	                          G_PARAM_CONSTRUCT_ONLY |
+	                          G_PARAM_WRITABLE |
+	                          G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties (object_class,
+	                                   _PROPERTY_ENUMS_LAST,
+	                                   obj_properties);
+
+	signals[REQUEST_SYNC] =
+	    g_signal_new (NM_POLKIT_LISTENER_SIGNAL_REQUEST_SYNC,
+	                  NM_TYPE_POLKIT_LISTENER,
+	                  G_SIGNAL_RUN_LAST,
+	                  0,
+	                  NULL,
+	                  NULL,
+	                  NULL,
+	                  G_TYPE_STRING,
+	                  3,
+	                  G_TYPE_STRING,
+	                  G_TYPE_STRING,
+	                  G_TYPE_STRING);
+
+	signals[REGISTERED] =
+	    g_signal_new (NM_POLKIT_LISTENER_SIGNAL_REGISTERED,
+	                  NM_TYPE_POLKIT_LISTENER,
+	                  G_SIGNAL_RUN_FIRST,
+	                  0,
+	                  NULL,
+	                  NULL,
+	                  NULL,
+	                  G_TYPE_NONE,
+	                  0);
+
+	signals[ERROR] =
+	    g_signal_new (NM_POLKIT_LISTENER_SIGNAL_ERROR,
+	                  NM_TYPE_POLKIT_LISTENER,
+	                  G_SIGNAL_RUN_FIRST,
+	                  0,
+	                  NULL,
+	                  NULL,
+	                  NULL,
+	                  G_TYPE_NONE,
+	                  1,
+	                  G_TYPE_STRING);
 }
-
-#endif /* WITH_POLKIT_AGENT */
diff --git a/clients/common/nm-polkit-listener.h b/clients/common/nm-polkit-listener.h
index 42da1bc1..c14d5932 100644
--- a/clients/common/nm-polkit-listener.h
+++ b/clients/common/nm-polkit-listener.h
@@ -6,67 +6,15 @@
 #ifndef __NM_POLKIT_LISTENER_H__
 #define __NM_POLKIT_LISTENER_H__
 
-#if WITH_POLKIT_AGENT
+#define NM_POLKIT_LISTENER_SIGNAL_REGISTERED      "registered"
+#define NM_POLKIT_LISTENER_SIGNAL_REQUEST_SYNC    "request-sync"
+#define NM_POLKIT_LISTENER_SIGNAL_AUTH_SUCCESS    "auth-success"
+#define NM_POLKIT_LISTENER_SIGNAL_AUTH_FAILURE    "auth-failure"
+#define NM_POLKIT_LISTENER_SIGNAL_ERROR           "error"
 
 typedef struct _NMPolkitListener NMPolkitListener;
 typedef struct _NMPolkitListenerClass NMPolkitListenerClass;
 
-typedef struct {
-
-	/*
-	 * @request: the request asked by polkit agent
-	 * @action_id: the action_id of the polkit request
-	 * @message: the message of the polkit request
-	 * @icon_name: the icon name of the polkit request
-	 * @user: user name
-	 * @echo_on: whether the response to the request should be echoed to the screen
-	 * @user_data: user data for the callback
-	 *
-	 * Called as a result of a request by polkit. The function should obtain response
-	 * to the request from user, i.e. get the password required.
-	 */
-	char *(*on_request) (NMPolkitListener *self,
-	                     const char *request,
-	                     const char *action_id,
-	                     const char *message,
-	                     const char *icon_name,
-	                     const char *user,
-	                     gboolean echo_on,
-	                     gpointer user_data);
-
-	/*
-	 * @text: the info text from polkit
-	 *
-	 * Called as a result of show-info signal by polkit.
-	 */
-	void (*on_show_info) (NMPolkitListener *self,
-	                      const char *text,
-	                      gpointer user_data);
-
-	/*
-	 * @text: the error text from polkit
-	 *
-	 * Called as a result of show-error signal by polkit.
-	 */
-	void (*on_show_error) (NMPolkitListener *self,
-	                       const char *text,
-	                       gpointer user_data);
-
-	/*
-	 * @gained_authorization: whether the authorization was successful
-	 *
-	 * Called as a result of completed signal by polkit.
-	 */
-	void (*on_completed) (NMPolkitListener *self,
-	                      gboolean gained_authorization,
-	                      gpointer user_data);
-} NMPolkitListenVtable;
-
-/*****************************************************************************/
-
-#define POLKIT_AGENT_I_KNOW_API_IS_SUBJECT_TO_CHANGE
-#include <polkitagent/polkitagent.h>
-
 #define NM_TYPE_POLKIT_LISTENER            (nm_polkit_listener_get_type ())
 #define NM_POLKIT_LISTENER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_POLKIT_LISTENER, NMPolkitListener))
 #define NM_POLKIT_LISTENER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_POLKIT_LISTENER, NMPolkitListenerClass))
@@ -74,65 +22,8 @@ typedef struct {
 #define NM_IS_POLKIT_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_POLKIT_LISTENER))
 #define NM_POLKIT_LISTENER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_POLKIT_LISTENER, NMPolkitListenerClass))
 
-/**
- * NMPolkitListenerOnRequestFunc:
- * @request: the request asked by polkit agent
- * @action_id: the action_id of the polkit request
- * @message: the message of the polkit request
- * @icon_name: the icon name of the polkit request
- * @user: user name
- * @echo_on: whether the response to the request should be echoed to the screen
- * @user_data: user data for the callback
- *
- * Called as a result of a request by polkit. The function should obtain response
- * to the request from user, i.e. get the password required.
- */
-typedef char * (*NMPolkitListenerOnRequestFunc) (const char *request,
-                                                 const char *action_id,
-                                                 const char *message,
-                                                 const char *icon_name,
-                                                 const char *user,
-                                                 gboolean echo_on,
-                                                 gpointer user_data);
-/**
- * NMPolkitListenerOnShowInfoFunc:
- * @text: the info text from polkit
- *
- * Called as a result of show-info signal by polkit.
- */
-typedef void (*NMPolkitListenerOnShowInfoFunc) (const char *text);
-/**
- * NMPolkitListenerOnShowErrorFunc:
- * @text: the error text from polkit
- *
- * Called as a result of show-error signal by polkit.
- */
-typedef void (*NMPolkitListenerOnShowErrorFunc) (const char *text);
-/**
- * NMPolkitListenerCompletedFunc:
- * @gained_authorization: whether the authorization was successful
- *
- * Called as a result of completed signal by polkit.
- */
-typedef void (*NMPolkitListenerOnCompletedFunc) (gboolean gained_authorization);
-
-struct _NMPolkitListener {
-	PolkitAgentListener parent;
-};
-
-struct _NMPolkitListenerClass {
-	PolkitAgentListenerClass parent;
-};
-
 GType nm_polkit_listener_get_type (void);
 
-NMPolkitListener *nm_polkit_listener_new (gboolean for_session,
-                                          GError **error);
-
-void nm_polkit_listener_set_vtable (NMPolkitListener *self,
-                                    const NMPolkitListenVtable *vtable,
-                                    gpointer user_data);
-
-#endif
+NMPolkitListener *nm_polkit_listener_new (GDBusConnection *dbus_connection, gboolean session_agent);
 
 #endif /* __NM_POLKIT_LISTENER_H__ */
diff --git a/clients/common/nm-secret-agent-simple.c b/clients/common/nm-secret-agent-simple.c
index 2bf69b20..ca9250ca 100644
--- a/clients/common/nm-secret-agent-simple.c
+++ b/clients/common/nm-secret-agent-simple.c
@@ -302,7 +302,7 @@ add_wireless_secrets (RequestData *request,
 	const char *key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
 	NMSecretAgentSimpleSecret *secret;
 
-	if (!key_mgmt)
+	if (!key_mgmt || nm_streq (key_mgmt, "owe"))
 		return FALSE;
 
 	if (NM_IN_STRSET (key_mgmt, "wpa-psk", "sae")) {
diff --git a/clients/common/nm-vpn-helpers.c b/clients/common/nm-vpn-helpers.c
index e1d83551..35ed4451 100644
--- a/clients/common/nm-vpn-helpers.c
+++ b/clients/common/nm-vpn-helpers.c
@@ -368,13 +368,13 @@ nm_vpn_wireguard_import (const char *filename,
 			memcpy (ifname, cstr, len);
 			ifname[len] = '\0';
 
-			if (nm_utils_ifname_valid_kernel (ifname, NULL))
+			if (nm_utils_ifname_valid (ifname, NMU_IFACE_KERNEL, NULL))
 				ifname_valid = TRUE;
 		}
 	}
 	if (!ifname_valid) {
 		nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN,
-		                            _("The WireGuard config file must be a valid interface name followed by \".conf\""));
+		                            _("The name of the WireGuard config must be a valid interface name followed by \".conf\""));
 		return FALSE;
 	}
 
@@ -524,7 +524,6 @@ nm_vpn_wireguard_import (const char *filename,
 				char *value_word;
 
 				while (value_split_word (&value, &value_word)) {
-					char addr_s[NM_CONST_MAX (INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
 					GPtrArray **p_data_dns;
 					NMIPAddr addr_bin;
 					int addr_family;
@@ -541,8 +540,8 @@ nm_vpn_wireguard_import (const char *filename,
 					if (!*p_data_dns)
 						*p_data_dns = g_ptr_array_new_with_free_func (g_free);
 
-					inet_ntop (addr_family, &addr_bin, addr_s, sizeof (addr_s));
-					g_ptr_array_add (*p_data_dns, g_strdup (addr_s));
+					g_ptr_array_add (*p_data_dns,
+					                 nm_utils_inet_ntop_dup (addr_family, &addr_bin));
 				}
 				continue;
 			}
@@ -745,6 +744,14 @@ fail_invalid_secret:
 		              data_addr ? method_manual : method_disabled,
 		              NULL);
 
+		/* For WireGuard profiles, always set dns-priority to a negative value,
+		 * so that DNS servers on other profiles get ignored. This is also what
+		 * wg-quick does, by calling `resolvconf -x`. */
+		g_object_set (s_ip,
+		              NM_SETTING_IP_CONFIG_DNS_PRIORITY,
+		              (int) -10,
+		              NULL);
+
 		if (data_addr) {
 			for (i = 0; i < data_addr->len; i++)
 				nm_setting_ip_config_add_address (s_ip, data_addr->pdata[i]);
@@ -752,6 +759,10 @@ fail_invalid_secret:
 		if (data_dns) {
 			for (i = 0; i < data_dns->len; i++)
 				nm_setting_ip_config_add_dns (s_ip, data_dns->pdata[i]);
+
+			/* the wg-quick file cannot handle search domains. When configuring a DNS server
+			 * in the wg-quick file, assume that the user want to use it for all searches. */
+			nm_setting_ip_config_add_dns_search (s_ip, "~");
 		}
 
 		if (data_table == _TABLE_AUTO) {
@@ -765,9 +776,10 @@ fail_invalid_secret:
 			 *   yourself to "ipv4.routes" and "ipv6.routes".
 			 *
 			 * - With "auto", wg-quick also configures policy routing to handle default-routes (/0) to
-			 *   avoid routing loops. That is not yet solved by NetworkManager, you need to configure
-			 *   that explicitly (for example, by adding a direct route to the gateway on the interface
-			 *   that has the default-route, or by using a script (possibly dispatcher script).
+			 *   avoid routing loops.
+			 *   The imported connection profile will have wireguard.ip4-auto-default-route and
+			 *   wireguard.ip6-auto-default-route set to "default". It will thus configure wg-quick's
+			 *   policy routing if the profile has any AllowedIPs ranges with /0.
 			 */
 		} else if (data_table == _TABLE_OFF) {
 			if (is_v4) {
diff --git a/clients/common/settings-docs.h b/clients/common/settings-docs.h
index 22d537e4..5cbef428 100644
--- a/clients/common/settings-docs.h
+++ b/clients/common/settings-docs.h
@@ -24,7 +24,7 @@
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_AUTH_ALG N_("When WEP is used (ie, key-mgmt = \"none\" or \"ieee8021x\") indicate the 802.11 authentication algorithm required by the AP here.  One of \"open\" for Open System, \"shared\" for Shared Key, or \"leap\" for Cisco LEAP.  When using Cisco LEAP (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\") the \"leap-username\" and \"leap-password\" properties must be specified.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_FILS N_("Indicates whether Fast Initial Link Setup (802.11ai) must be enabled for the connection.  One of NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE (1) (disable FILS), NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL (2) (enable FILS if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED (3) (enable FILS and fail if not supported).  When set to NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) and no global default is set, FILS will be optionally enabled.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_GROUP N_("A list of group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list.  For maximum compatibility leave this property empty.  Each list element may be one of \"wep40\", \"wep104\", \"tkip\", or \"ccmp\".")
-#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_KEY_MGMT N_("Key management used for the connection.  One of \"none\" (WEP), \"ieee8021x\" (Dynamic WEP), \"wpa-psk\" (infrastructure WPA-PSK), \"sae\" (SAE) or \"wpa-eap\" (WPA-Enterprise).  This property must be set for any Wi-Fi connection that uses security.")
+#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_KEY_MGMT N_("Key management used for the connection.  One of \"none\" (WEP), \"ieee8021x\" (Dynamic WEP), \"wpa-psk\" (infrastructure WPA-PSK), \"sae\" (SAE), \"owe\" (Opportunistic Wireless Encryption) or \"wpa-eap\" (WPA-Enterprise).  This property must be set for any Wi-Fi connection that uses security.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD N_("The login password for legacy LEAP connections (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\").")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS N_("Flags indicating how to handle the \"leap-password\" property.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME N_("The login username for legacy LEAP connections (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\").")
@@ -51,7 +51,8 @@
 #define DESCRIBE_DOC_NM_SETTING_802_1X_CLIENT_CERT N_("Contains the client certificate if used by the EAP method specified in the \"eap\" property. Certificate data is specified using a \"scheme\"; two are currently supported: blob and path. When using the blob scheme (which is backwards compatible with NM 0.7.x) this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string \"file://\" and ending with a terminating NUL byte.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_CLIENT_CERT_PASSWORD N_("The password used to access the client certificate stored in \"client-cert\" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_CLIENT_CERT_PASSWORD_FLAGS N_("Flags indicating how to handle the \"client-cert-password\" property.")
-#define DESCRIBE_DOC_NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH N_("Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server.  If a matching dNSName is found, this constraint is met.  If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison.")
+#define DESCRIBE_DOC_NM_SETTING_802_1X_DOMAIN_MATCH N_("Constraint for server domain name. If set, this list of FQDNs is used as a match requirement for dNSName element(s) of the certificate presented by the authentication server.  If a matching dNSName is found, this constraint is met.  If no dNSName values are present, this constraint is matched against SubjectName CN using the same comparison. Multiple valid FQDNs can be passed as a \";\" delimited list.")
+#define DESCRIBE_DOC_NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH N_("Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server.  If a matching dNSName is found, this constraint is met.  If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison. Since version 1.24, multiple valid FQDNs can be passed as a \";\" delimited list.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_EAP N_("The allowed EAP method to be used when authenticating to the network with 802.1x.  Valid methods are: \"leap\", \"md5\", \"tls\", \"peap\", \"ttls\", \"pwd\", and \"fast\".  Each method requires different configuration using the properties of this setting; refer to wpa_supplicant documentation for the allowed combinations.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_IDENTITY N_("Identity string for EAP authentication methods.  Often the user's user or login name.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_OPTIONAL N_("Whether the 802.1X authentication is optional. If TRUE, the activation will continue even after a timeout or an authentication failure. Setting the property to TRUE is currently allowed only for Ethernet connections. If set to FALSE, the activation can continue only after a successful authentication.")
@@ -74,7 +75,8 @@
 #define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_CLIENT_CERT N_("Contains the \"phase 2\" client certificate if used by the EAP method specified in the \"phase2-auth\" or \"phase2-autheap\" properties. Certificate data is specified using a \"scheme\"; two are currently supported: blob and path. When using the blob scheme (which is backwards compatible with NM 0.7.x) this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string \"file://\" and ending with a terminating NUL byte. This property can be unset even if the EAP method supports CA certificates, but this allows man-in-the-middle attacks and is NOT recommended.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD N_("The password used to access the \"phase2\" client certificate stored in \"phase2-client-cert\" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD_FLAGS N_("Flags indicating how to handle the \"phase2-client-cert-password\" property.")
-#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH N_("Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server during the inner \"phase 2\" authentication.  If a matching dNSName is found, this constraint is met.  If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison.")
+#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_DOMAIN_MATCH N_("Constraint for server domain name. If set, this list of FQDNs is used as a match requirement for dNSName element(s) of the certificate presented by the authentication server during the inner \"phase 2\" authentication. If a matching dNSName is found, this constraint is met.  If no dNSName values are present, this constraint is matched against SubjectName CN using the same comparison. Multiple valid FQDNs can be passed as a \";\" delimited list.")
+#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH N_("Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server during the inner \"phase 2\" authentication.  If a matching dNSName is found, this constraint is met.  If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison. Since version 1.24, multiple valid FQDNs can be passed as a \";\" delimited list.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_PRIVATE_KEY N_("Contains the \"phase 2\" inner private key when the \"phase2-auth\" or \"phase2-autheap\" property is set to \"tls\". Key data is specified using a \"scheme\"; two are currently supported: blob and path. When using the blob scheme and private keys, this property should be set to the key's encrypted PEM encoded data. When using private keys with the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string \"file://\" and ending with a terminating NUL byte. When using PKCS#12 format private keys and the blob scheme, this property should be set to the PKCS#12 data and the \"phase2-private-key-password\" property must be set to password used to decrypt the PKCS#12 certificate and key. When using PKCS#12 files and the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string \"file://\" and ending with a terminating NUL byte, and as with the blob scheme the \"phase2-private-key-password\" property must be set to the password used to decode the PKCS#12 private key and certificate.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD N_("The password used to decrypt the \"phase 2\" private key specified in the \"phase2-private-key\" property when the private key either uses the path scheme, or is a PKCS#12 format key.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS N_("Flags indicating how to handle the \"phase2-private-key-password\" property.")
@@ -112,15 +114,21 @@
 #define DESCRIBE_DOC_NM_SETTING_BOND_OPTIONS N_("Dictionary of key/value pairs of bonding options.  Both keys and values must be strings. Option names must contain only alphanumeric characters (ie, [a-zA-Z0-9]).")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_AGEING_TIME N_("The Ethernet MAC address aging time, in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_FORWARD_DELAY N_("The Spanning Tree Protocol (STP) forwarding delay, in seconds.")
+#define DESCRIBE_DOC_NM_SETTING_BRIDGE_GROUP_ADDRESS N_("If specified, The MAC address of the multicast group this bridge uses for STP. The address must be a link-local address in standard Ethernet MAC address format, ie an address of the form 01:80:C2:00:00:0X, with X in [0, 4..F]. If not specified the default value is 01:80:C2:00:00:00.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_GROUP_FORWARD_MASK N_("A mask of group addresses to forward. Usually, group addresses in the range from 01:80:C2:00:00:00 to 01:80:C2:00:00:0F are not forwarded according to standards. This property is a mask of 16 bits, each corresponding to a group address in that range that must be forwarded. The mask can't have bits 0, 1 or 2 set because they are used for STP, MAC pause frames and LACP.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_HELLO_TIME N_("The Spanning Tree Protocol (STP) hello time, in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MAC_ADDRESS N_("If specified, the MAC address of bridge. When creating a new bridge, this MAC address will be set. If this field is left unspecified, the \"ethernet.cloned-mac-address\" is referred instead to generate the initial MAC address. Note that setting \"ethernet.cloned-mac-address\" anyway overwrites the MAC address of the bridge later while activating the bridge. Hence, this property is deprecated. Deprecated: 1")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MAX_AGE N_("The Spanning Tree Protocol (STP) maximum message age, in seconds.")
+#define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_QUERIER N_("Enable or disable sending of multicast queries by the bridge. If not specified the option is disabled.")
+#define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR N_("If enabled the bridge's own IP address is used as the source address for IGMP queries otherwise the default of 0.0.0.0 is used.")
+#define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_ROUTER N_("Sets bridge's multicast router. multicast-snooping must be enabled for this option to work. Supported values are: 'auto', 'disabled', 'enabled'. If not specified the default value is 'auto'.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_SNOOPING N_("Controls whether IGMP snooping is enabled for this bridge. Note that if snooping was automatically disabled due to hash collisions, the system may refuse to enable the feature until the collisions are resolved.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_PRIORITY N_("Sets the Spanning Tree Protocol (STP) priority for this bridge.  Lower values are \"better\"; the lowest priority bridge will be elected the root bridge.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_STP N_("Controls whether Spanning Tree Protocol (STP) is enabled for this bridge.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID N_("The default PVID for the ports of the bridge, that is the VLAN id assigned to incoming untagged frames.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_VLAN_FILTERING N_("Control whether VLAN filtering is enabled on the bridge.")
+#define DESCRIBE_DOC_NM_SETTING_BRIDGE_VLAN_PROTOCOL N_("If specified, the protocol used for VLAN filtering. Supported values are: '802.1Q', '802.1ad'. If not specified the default value is '802.1Q'.")
+#define DESCRIBE_DOC_NM_SETTING_BRIDGE_VLAN_STATS_ENABLED N_("Controls whether per-VLAN stats accounting is enabled.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_VLANS N_("Array of bridge VLAN objects. In addition to the VLANs specified here, the bridge will also have the default-pvid VLAN configured  by the bridge.vlan-default-pvid property. In nmcli the VLAN list can be specified with the following syntax: $vid [pvid] [untagged] [, $vid [pvid] [untagged]]... where $vid is either a single id between 1 and 4094 or a range, represented as a couple of ids separated by a dash.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE N_("Enables or disables \"hairpin mode\" for the port, which allows frames to be sent back out through the port the frame was received on.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_PORT_PATH_COST N_("The Spanning Tree Protocol (STP) port cost for destinations via this port.")
@@ -213,7 +221,7 @@
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). Set to 2147483647 (MAXINT32) for infinity.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports Conditional Forwarding as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports Conditional Forwarding as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")
@@ -235,7 +243,7 @@
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). Set to 2147483647 (MAXINT32) for infinity.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.")
-#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports Conditional Forwarding as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
+#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports Conditional Forwarding as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")
@@ -310,7 +318,7 @@
 #define DESCRIBE_DOC_NM_SETTING_SERIAL_SEND_DELAY N_("Time to delay between each byte sent to the modem, in microseconds.")
 #define DESCRIBE_DOC_NM_SETTING_SERIAL_STOPBITS N_("Number of stop bits for communication on the serial port.  Either 1 or 2. The 1 in \"8n1\" for example.")
 #define DESCRIBE_DOC_NM_SETTING_SRIOV_AUTOPROBE_DRIVERS N_("Whether to autoprobe virtual functions by a compatible driver. If set to NM_TERNARY_TRUE (1), the kernel will try to bind VFs to a compatible driver and if this succeeds a new network interface will be instantiated for each VF. If set to NM_TERNARY_FALSE (0), VFs will not be claimed and no network interfaces will be created for them. When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_TRUE (1).")
-#define DESCRIBE_DOC_NM_SETTING_SRIOV_TOTAL_VFS N_("The total number of virtual functions to create. Note that when the sriov setting is present NetworkManager enforces the number of virtual functions on the interface also when it is zero. To prevent any changes to SR-IOV parameters don't add a sriov setting to the connection.")
+#define DESCRIBE_DOC_NM_SETTING_SRIOV_TOTAL_VFS N_("The total number of virtual functions to create. Note that when the sriov setting is present NetworkManager enforces the number of virtual functions on the interface (also when it is zero) during activation and resets it upon deactivation. To prevent any changes to SR-IOV parameters don't add a sriov setting to the connection.")
 #define DESCRIBE_DOC_NM_SETTING_SRIOV_VFS N_("Array of virtual function descriptors. Each VF descriptor is a dictionary mapping attribute names to GVariant values. The 'index' entry is mandatory for each VF. When represented as string a VF is in the form: \"INDEX [ATTR=VALUE[ ATTR=VALUE]...]\". for example: \"2 mac=00:11:22:33:44:55 spoof-check=true\". Multiple VFs can be specified using a comma as separator. Currently the following attributes are supported: mac, spoof-check, trust, min-tx-rate, max-tx-rate, vlans. The \"vlans\" attribute is represented as a semicolon-separated list of VLAN descriptors, where each descriptor has the form \"ID[.PRIORITY[.PROTO]]\". PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 802.1ad.")
 #define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_QDISCS N_("Array of TC queueing disciplines.")
 #define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_TFILTERS N_("Array of TC traffic filters.")
@@ -355,6 +363,7 @@
 #define DESCRIBE_DOC_NM_SETTING_VPN_SERVICE_TYPE N_("D-Bus service name of the VPN plugin that this setting uses to connect to its network.  i.e. org.freedesktop.NetworkManager.vpnc for the vpnc plugin.")
 #define DESCRIBE_DOC_NM_SETTING_VPN_TIMEOUT N_("Timeout for the VPN service to establish the connection. Some services may take quite a long time to connect. Value of 0 means a default timeout, which is 60 seconds (unless overridden by vpn.timeout in configuration file). Values greater than zero mean timeout in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_VPN_USER_NAME N_("If the VPN connection requires a user name for authentication, that name should be provided here.  If the connection is available to more than one user, and the VPN requires each user to supply a different name, then leave this property empty.  If this property is empty, NetworkManager will automatically supply the username of the user which requested the VPN connection.")
+#define DESCRIBE_DOC_NM_SETTING_VRF_TABLE N_("The routing table for this VRF.")
 #define DESCRIBE_DOC_NM_SETTING_VXLAN_AGEING N_("Specifies the lifetime in seconds of FDB entries learnt by the kernel.")
 #define DESCRIBE_DOC_NM_SETTING_VXLAN_DESTINATION_PORT N_("Specifies the UDP destination port to communicate to the remote VXLAN tunnel endpoint.")
 #define DESCRIBE_DOC_NM_SETTING_VXLAN_ID N_("Specifies the VXLAN Network Identifier (or VXLAN Segment Identifier) to use.")
diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in
index 22d537e4..5cbef428 100644
--- a/clients/common/settings-docs.h.in
+++ b/clients/common/settings-docs.h.in
@@ -24,7 +24,7 @@
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_AUTH_ALG N_("When WEP is used (ie, key-mgmt = \"none\" or \"ieee8021x\") indicate the 802.11 authentication algorithm required by the AP here.  One of \"open\" for Open System, \"shared\" for Shared Key, or \"leap\" for Cisco LEAP.  When using Cisco LEAP (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\") the \"leap-username\" and \"leap-password\" properties must be specified.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_FILS N_("Indicates whether Fast Initial Link Setup (802.11ai) must be enabled for the connection.  One of NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE (1) (disable FILS), NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL (2) (enable FILS if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED (3) (enable FILS and fail if not supported).  When set to NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) and no global default is set, FILS will be optionally enabled.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_GROUP N_("A list of group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list.  For maximum compatibility leave this property empty.  Each list element may be one of \"wep40\", \"wep104\", \"tkip\", or \"ccmp\".")
-#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_KEY_MGMT N_("Key management used for the connection.  One of \"none\" (WEP), \"ieee8021x\" (Dynamic WEP), \"wpa-psk\" (infrastructure WPA-PSK), \"sae\" (SAE) or \"wpa-eap\" (WPA-Enterprise).  This property must be set for any Wi-Fi connection that uses security.")
+#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_KEY_MGMT N_("Key management used for the connection.  One of \"none\" (WEP), \"ieee8021x\" (Dynamic WEP), \"wpa-psk\" (infrastructure WPA-PSK), \"sae\" (SAE), \"owe\" (Opportunistic Wireless Encryption) or \"wpa-eap\" (WPA-Enterprise).  This property must be set for any Wi-Fi connection that uses security.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD N_("The login password for legacy LEAP connections (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\").")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS N_("Flags indicating how to handle the \"leap-password\" property.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME N_("The login username for legacy LEAP connections (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\").")
@@ -51,7 +51,8 @@
 #define DESCRIBE_DOC_NM_SETTING_802_1X_CLIENT_CERT N_("Contains the client certificate if used by the EAP method specified in the \"eap\" property. Certificate data is specified using a \"scheme\"; two are currently supported: blob and path. When using the blob scheme (which is backwards compatible with NM 0.7.x) this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string \"file://\" and ending with a terminating NUL byte.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_CLIENT_CERT_PASSWORD N_("The password used to access the client certificate stored in \"client-cert\" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_CLIENT_CERT_PASSWORD_FLAGS N_("Flags indicating how to handle the \"client-cert-password\" property.")
-#define DESCRIBE_DOC_NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH N_("Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server.  If a matching dNSName is found, this constraint is met.  If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison.")
+#define DESCRIBE_DOC_NM_SETTING_802_1X_DOMAIN_MATCH N_("Constraint for server domain name. If set, this list of FQDNs is used as a match requirement for dNSName element(s) of the certificate presented by the authentication server.  If a matching dNSName is found, this constraint is met.  If no dNSName values are present, this constraint is matched against SubjectName CN using the same comparison. Multiple valid FQDNs can be passed as a \";\" delimited list.")
+#define DESCRIBE_DOC_NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH N_("Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server.  If a matching dNSName is found, this constraint is met.  If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison. Since version 1.24, multiple valid FQDNs can be passed as a \";\" delimited list.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_EAP N_("The allowed EAP method to be used when authenticating to the network with 802.1x.  Valid methods are: \"leap\", \"md5\", \"tls\", \"peap\", \"ttls\", \"pwd\", and \"fast\".  Each method requires different configuration using the properties of this setting; refer to wpa_supplicant documentation for the allowed combinations.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_IDENTITY N_("Identity string for EAP authentication methods.  Often the user's user or login name.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_OPTIONAL N_("Whether the 802.1X authentication is optional. If TRUE, the activation will continue even after a timeout or an authentication failure. Setting the property to TRUE is currently allowed only for Ethernet connections. If set to FALSE, the activation can continue only after a successful authentication.")
@@ -74,7 +75,8 @@
 #define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_CLIENT_CERT N_("Contains the \"phase 2\" client certificate if used by the EAP method specified in the \"phase2-auth\" or \"phase2-autheap\" properties. Certificate data is specified using a \"scheme\"; two are currently supported: blob and path. When using the blob scheme (which is backwards compatible with NM 0.7.x) this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string \"file://\" and ending with a terminating NUL byte. This property can be unset even if the EAP method supports CA certificates, but this allows man-in-the-middle attacks and is NOT recommended.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD N_("The password used to access the \"phase2\" client certificate stored in \"phase2-client-cert\" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD_FLAGS N_("Flags indicating how to handle the \"phase2-client-cert-password\" property.")
-#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH N_("Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server during the inner \"phase 2\" authentication.  If a matching dNSName is found, this constraint is met.  If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison.")
+#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_DOMAIN_MATCH N_("Constraint for server domain name. If set, this list of FQDNs is used as a match requirement for dNSName element(s) of the certificate presented by the authentication server during the inner \"phase 2\" authentication. If a matching dNSName is found, this constraint is met.  If no dNSName values are present, this constraint is matched against SubjectName CN using the same comparison. Multiple valid FQDNs can be passed as a \";\" delimited list.")
+#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH N_("Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server during the inner \"phase 2\" authentication.  If a matching dNSName is found, this constraint is met.  If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison. Since version 1.24, multiple valid FQDNs can be passed as a \";\" delimited list.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_PRIVATE_KEY N_("Contains the \"phase 2\" inner private key when the \"phase2-auth\" or \"phase2-autheap\" property is set to \"tls\". Key data is specified using a \"scheme\"; two are currently supported: blob and path. When using the blob scheme and private keys, this property should be set to the key's encrypted PEM encoded data. When using private keys with the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string \"file://\" and ending with a terminating NUL byte. When using PKCS#12 format private keys and the blob scheme, this property should be set to the PKCS#12 data and the \"phase2-private-key-password\" property must be set to password used to decrypt the PKCS#12 certificate and key. When using PKCS#12 files and the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string \"file://\" and ending with a terminating NUL byte, and as with the blob scheme the \"phase2-private-key-password\" property must be set to the password used to decode the PKCS#12 private key and certificate.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD N_("The password used to decrypt the \"phase 2\" private key specified in the \"phase2-private-key\" property when the private key either uses the path scheme, or is a PKCS#12 format key.")
 #define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS N_("Flags indicating how to handle the \"phase2-private-key-password\" property.")
@@ -112,15 +114,21 @@
 #define DESCRIBE_DOC_NM_SETTING_BOND_OPTIONS N_("Dictionary of key/value pairs of bonding options.  Both keys and values must be strings. Option names must contain only alphanumeric characters (ie, [a-zA-Z0-9]).")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_AGEING_TIME N_("The Ethernet MAC address aging time, in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_FORWARD_DELAY N_("The Spanning Tree Protocol (STP) forwarding delay, in seconds.")
+#define DESCRIBE_DOC_NM_SETTING_BRIDGE_GROUP_ADDRESS N_("If specified, The MAC address of the multicast group this bridge uses for STP. The address must be a link-local address in standard Ethernet MAC address format, ie an address of the form 01:80:C2:00:00:0X, with X in [0, 4..F]. If not specified the default value is 01:80:C2:00:00:00.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_GROUP_FORWARD_MASK N_("A mask of group addresses to forward. Usually, group addresses in the range from 01:80:C2:00:00:00 to 01:80:C2:00:00:0F are not forwarded according to standards. This property is a mask of 16 bits, each corresponding to a group address in that range that must be forwarded. The mask can't have bits 0, 1 or 2 set because they are used for STP, MAC pause frames and LACP.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_HELLO_TIME N_("The Spanning Tree Protocol (STP) hello time, in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MAC_ADDRESS N_("If specified, the MAC address of bridge. When creating a new bridge, this MAC address will be set. If this field is left unspecified, the \"ethernet.cloned-mac-address\" is referred instead to generate the initial MAC address. Note that setting \"ethernet.cloned-mac-address\" anyway overwrites the MAC address of the bridge later while activating the bridge. Hence, this property is deprecated. Deprecated: 1")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MAX_AGE N_("The Spanning Tree Protocol (STP) maximum message age, in seconds.")
+#define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_QUERIER N_("Enable or disable sending of multicast queries by the bridge. If not specified the option is disabled.")
+#define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR N_("If enabled the bridge's own IP address is used as the source address for IGMP queries otherwise the default of 0.0.0.0 is used.")
+#define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_ROUTER N_("Sets bridge's multicast router. multicast-snooping must be enabled for this option to work. Supported values are: 'auto', 'disabled', 'enabled'. If not specified the default value is 'auto'.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_SNOOPING N_("Controls whether IGMP snooping is enabled for this bridge. Note that if snooping was automatically disabled due to hash collisions, the system may refuse to enable the feature until the collisions are resolved.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_PRIORITY N_("Sets the Spanning Tree Protocol (STP) priority for this bridge.  Lower values are \"better\"; the lowest priority bridge will be elected the root bridge.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_STP N_("Controls whether Spanning Tree Protocol (STP) is enabled for this bridge.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID N_("The default PVID for the ports of the bridge, that is the VLAN id assigned to incoming untagged frames.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_VLAN_FILTERING N_("Control whether VLAN filtering is enabled on the bridge.")
+#define DESCRIBE_DOC_NM_SETTING_BRIDGE_VLAN_PROTOCOL N_("If specified, the protocol used for VLAN filtering. Supported values are: '802.1Q', '802.1ad'. If not specified the default value is '802.1Q'.")
+#define DESCRIBE_DOC_NM_SETTING_BRIDGE_VLAN_STATS_ENABLED N_("Controls whether per-VLAN stats accounting is enabled.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_VLANS N_("Array of bridge VLAN objects. In addition to the VLANs specified here, the bridge will also have the default-pvid VLAN configured  by the bridge.vlan-default-pvid property. In nmcli the VLAN list can be specified with the following syntax: $vid [pvid] [untagged] [, $vid [pvid] [untagged]]... where $vid is either a single id between 1 and 4094 or a range, represented as a couple of ids separated by a dash.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE N_("Enables or disables \"hairpin mode\" for the port, which allows frames to be sent back out through the port the frame was received on.")
 #define DESCRIBE_DOC_NM_SETTING_BRIDGE_PORT_PATH_COST N_("The Spanning Tree Protocol (STP) port cost for destinations via this port.")
@@ -213,7 +221,7 @@
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). Set to 2147483647 (MAXINT32) for infinity.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports Conditional Forwarding as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports Conditional Forwarding as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")
@@ -235,7 +243,7 @@
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). Set to 2147483647 (MAXINT32) for infinity.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.")
-#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports Conditional Forwarding as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
+#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports Conditional Forwarding as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")
@@ -310,7 +318,7 @@
 #define DESCRIBE_DOC_NM_SETTING_SERIAL_SEND_DELAY N_("Time to delay between each byte sent to the modem, in microseconds.")
 #define DESCRIBE_DOC_NM_SETTING_SERIAL_STOPBITS N_("Number of stop bits for communication on the serial port.  Either 1 or 2. The 1 in \"8n1\" for example.")
 #define DESCRIBE_DOC_NM_SETTING_SRIOV_AUTOPROBE_DRIVERS N_("Whether to autoprobe virtual functions by a compatible driver. If set to NM_TERNARY_TRUE (1), the kernel will try to bind VFs to a compatible driver and if this succeeds a new network interface will be instantiated for each VF. If set to NM_TERNARY_FALSE (0), VFs will not be claimed and no network interfaces will be created for them. When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_TRUE (1).")
-#define DESCRIBE_DOC_NM_SETTING_SRIOV_TOTAL_VFS N_("The total number of virtual functions to create. Note that when the sriov setting is present NetworkManager enforces the number of virtual functions on the interface also when it is zero. To prevent any changes to SR-IOV parameters don't add a sriov setting to the connection.")
+#define DESCRIBE_DOC_NM_SETTING_SRIOV_TOTAL_VFS N_("The total number of virtual functions to create. Note that when the sriov setting is present NetworkManager enforces the number of virtual functions on the interface (also when it is zero) during activation and resets it upon deactivation. To prevent any changes to SR-IOV parameters don't add a sriov setting to the connection.")
 #define DESCRIBE_DOC_NM_SETTING_SRIOV_VFS N_("Array of virtual function descriptors. Each VF descriptor is a dictionary mapping attribute names to GVariant values. The 'index' entry is mandatory for each VF. When represented as string a VF is in the form: \"INDEX [ATTR=VALUE[ ATTR=VALUE]...]\". for example: \"2 mac=00:11:22:33:44:55 spoof-check=true\". Multiple VFs can be specified using a comma as separator. Currently the following attributes are supported: mac, spoof-check, trust, min-tx-rate, max-tx-rate, vlans. The \"vlans\" attribute is represented as a semicolon-separated list of VLAN descriptors, where each descriptor has the form \"ID[.PRIORITY[.PROTO]]\". PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 802.1ad.")
 #define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_QDISCS N_("Array of TC queueing disciplines.")
 #define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_TFILTERS N_("Array of TC traffic filters.")
@@ -355,6 +363,7 @@
 #define DESCRIBE_DOC_NM_SETTING_VPN_SERVICE_TYPE N_("D-Bus service name of the VPN plugin that this setting uses to connect to its network.  i.e. org.freedesktop.NetworkManager.vpnc for the vpnc plugin.")
 #define DESCRIBE_DOC_NM_SETTING_VPN_TIMEOUT N_("Timeout for the VPN service to establish the connection. Some services may take quite a long time to connect. Value of 0 means a default timeout, which is 60 seconds (unless overridden by vpn.timeout in configuration file). Values greater than zero mean timeout in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_VPN_USER_NAME N_("If the VPN connection requires a user name for authentication, that name should be provided here.  If the connection is available to more than one user, and the VPN requires each user to supply a different name, then leave this property empty.  If this property is empty, NetworkManager will automatically supply the username of the user which requested the VPN connection.")
+#define DESCRIBE_DOC_NM_SETTING_VRF_TABLE N_("The routing table for this VRF.")
 #define DESCRIBE_DOC_NM_SETTING_VXLAN_AGEING N_("Specifies the lifetime in seconds of FDB entries learnt by the kernel.")
 #define DESCRIBE_DOC_NM_SETTING_VXLAN_DESTINATION_PORT N_("Specifies the UDP destination port to communicate to the remote VXLAN tunnel endpoint.")
 #define DESCRIBE_DOC_NM_SETTING_VXLAN_ID N_("Specifies the VXLAN Network Identifier (or VXLAN Segment Identifier) to use.")
diff --git a/clients/common/tests/meson.build b/clients/common/tests/meson.build
index 479cb781..43b1f7c9 100644
--- a/clients/common/tests/meson.build
+++ b/clients/common/tests/meson.build
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: LGPL-2.1+
+
 common_c_flags = clients_c_flags + ['-DNETWORKMANAGER_COMPILATION_TEST']
 
 test_name = 'test-clients-common'
diff --git a/clients/common/tests/test-clients-common.c b/clients/common/tests/test-clients-common.c
index a5d803df..70ee2cb1 100644
--- a/clients/common/tests/test-clients-common.c
+++ b/clients/common/tests/test-clients-common.c
@@ -137,6 +137,8 @@ test_client_import_wireguard_test0 (void)
 {
 	gs_unref_object NMConnection *connection;
 	NMSettingWireGuard *s_wg;
+	NMSettingIPConfig *s_ip4;
+	NMSettingIPConfig *s_ip6;
 	NMWireGuardPeer *peer;
 	gs_free_error GError *error = NULL;
 
@@ -175,6 +177,17 @@ test_client_import_wireguard_test0 (void)
 	g_assert_cmpstr (nm_wireguard_peer_get_endpoint (peer), ==, "test.wireguard.com:18981");
 	g_assert_cmpint (nm_wireguard_peer_get_allowed_ips_len (peer), ==, 1);
 	g_assert_cmpstr (nm_wireguard_peer_get_allowed_ip (peer, 0, NULL), ==, "10.10.10.230/32");
+
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
+
+	g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 1);
+	g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip6), ==, 0);
+
+	g_assert_cmpint (nm_setting_ip_config_get_num_dns_searches (s_ip4), ==, 1);
+	g_assert_cmpint (nm_setting_ip_config_get_num_dns_searches (s_ip6), ==, 0);
+
+	g_assert_cmpstr (nm_setting_ip_config_get_dns_search (s_ip4, 0), ==, "~");
 }
 
 static void
diff --git a/clients/common/tests/wg-test0.conf b/clients/common/tests/wg-test0.conf
index 61438c29..28af4a00 100644
--- a/clients/common/tests/wg-test0.conf
+++ b/clients/common/tests/wg-test0.conf
@@ -1,6 +1,8 @@
 [Interface]
 PrivateKey = yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=
 ListenPort = 51820
+Address = 10.10.10.5/32
+DNS = 10.10.10.1
 
 [Peer]
 PublicKey = xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=
diff --git a/clients/meson.build b/clients/meson.build
index 69e0bfef..5e6dd6a4 100644
--- a/clients/meson.build
+++ b/clients/meson.build
@@ -1,16 +1,17 @@
+# SPDX-License-Identifier: LGPL-2.1+
+
 clients_c_flags = ['-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_CLIENT']
 
 name = 'nm-online'
 
-deps = [
-  libnm_dep,
-  libnm_nm_default_dep,
-]
-
 executable(
   name,
   name + '.c',
-  dependencies: deps,
+  dependencies: [
+    libnm_dep,
+    libnm_nm_default_dep,
+    libnm_libnm_aux_dep,
+  ],
   c_args: clients_c_flags + ['-DG_LOG_DOMAIN="@0@"'.format(name)],
   link_args: ldflags_linker_script_binary,
   link_depends: linker_script_binary,
diff --git a/clients/nm-online.c b/clients/nm-online.c
index de9c3794..5950da56 100644
--- a/clients/nm-online.c
+++ b/clients/nm-online.c
@@ -23,6 +23,8 @@
 #include <getopt.h>
 #include <locale.h>
 
+#include "nm-libnm-aux/nm-libnm-aux.h"
+
 #define PROGRESS_STEPS 15
 
 #define EXIT_NONE               -1
@@ -198,13 +200,16 @@ got_client (GObject *source_object, GAsyncResult *res, gpointer user_data)
 {
 	OnlineData *data = user_data;
 	gs_free_error GError *error = NULL;
-	NMClient *client;
+
+	nm_assert (NM_IS_CLIENT (source_object));
+	nm_assert (NM_CLIENT (source_object) == data->client);
 
 	nm_clear_g_source (&data->client_new_timeout_id);
 	g_clear_object (&data->client_new_cancellable);
 
-	client = nm_client_new_finish (res, &error);
-	if (!client) {
+	if (!g_async_initable_init_finish (G_ASYNC_INITABLE (source_object),
+	                                   res,
+	                                   &error)) {
 		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 			return;
 		data->quiet = TRUE;
@@ -214,8 +219,6 @@ got_client (GObject *source_object, GAsyncResult *res, gpointer user_data)
 		return;
 	}
 
-	data->client = client;
-
 	if (quit_if_connected (data))
 		return;
 
@@ -285,7 +288,12 @@ main (int argc, char *argv[])
 	data.client_new_cancellable = g_cancellable_new ();
 
 	data.client_new_timeout_id = g_timeout_add_seconds (30, got_client_timeout, &data);
-	nm_client_new_async (data.client_new_cancellable, got_client, &data);
+
+	data.client = nmc_client_new_async (data.client_new_cancellable,
+	                                    got_client,
+	                                    &data,
+	                                    NM_CLIENT_INSTANCE_FLAGS, (guint) NM_CLIENT_INSTANCE_FLAGS_NO_AUTO_FETCH_PERMISSIONS,
+	                                    NULL);
 
 	g_main_loop_run (data.loop);
 
@@ -295,7 +303,7 @@ main (int argc, char *argv[])
 	nm_clear_g_signal_handler (data.client, &data.client_notify_id);
 	g_clear_object (&data.client);
 
-	g_clear_pointer (&data.loop, g_main_loop_unref);
+	nm_clear_pointer (&data.loop, g_main_loop_unref);
 
 	if (!data.quiet)
 		_print_progress (data.wait_startup, -1, NM_MAX (0, data.end_timestamp_ms - _now_ms ()), data.retval);
diff --git a/clients/tests/test-client.check-on-disk/test_001.expected b/clients/tests/test-client.check-on-disk/test_001.expected
index a7439bf1..25d4437b 100644
--- a/clients/tests/test-client.check-on-disk/test_001.expected
+++ b/clients/tests/test-client.check-on-disk/test_001.expected
@@ -100,23 +100,23 @@ returncode: 0
 stdout: 1350 bytes
 >>>
 PERMISSION                                                        VALUE   
+org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
 org.freedesktop.NetworkManager.enable-disable-network             yes     
+org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
 org.freedesktop.NetworkManager.enable-disable-wifi                yes     
-org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.enable-disable-wimax               yes     
-org.freedesktop.NetworkManager.sleep-wake                         no      
+org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.network-control                    yes     
-org.freedesktop.NetworkManager.wifi.share.protected               yes     
-org.freedesktop.NetworkManager.wifi.share.open                    yes     
-org.freedesktop.NetworkManager.settings.modify.system             yes     
-org.freedesktop.NetworkManager.settings.modify.own                yes     
-org.freedesktop.NetworkManager.settings.modify.hostname           yes     
-org.freedesktop.NetworkManager.settings.modify.global-dns         no      
 org.freedesktop.NetworkManager.reload                             no      
-org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
-org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
+org.freedesktop.NetworkManager.settings.modify.global-dns         no      
+org.freedesktop.NetworkManager.settings.modify.hostname           yes     
+org.freedesktop.NetworkManager.settings.modify.own                yes     
+org.freedesktop.NetworkManager.settings.modify.system             yes     
+org.freedesktop.NetworkManager.sleep-wake                         no      
 org.freedesktop.NetworkManager.wifi.scan                          unknown 
+org.freedesktop.NetworkManager.wifi.share.open                    yes     
+org.freedesktop.NetworkManager.wifi.share.protected               yes     
 
 <<<
 size: 1513
@@ -127,23 +127,23 @@ returncode: 0
 stdout: 1368 bytes
 >>>
 PERMISSION                                                        VALUE    
+org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
 org.freedesktop.NetworkManager.enable-disable-network             tak      
+org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
 org.freedesktop.NetworkManager.enable-disable-wifi                tak      
-org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.enable-disable-wimax               tak      
-org.freedesktop.NetworkManager.sleep-wake                         nie      
+org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.network-control                    tak      
-org.freedesktop.NetworkManager.wifi.share.protected               tak      
-org.freedesktop.NetworkManager.wifi.share.open                    tak      
-org.freedesktop.NetworkManager.settings.modify.system             tak      
-org.freedesktop.NetworkManager.settings.modify.own                tak      
-org.freedesktop.NetworkManager.settings.modify.hostname           tak      
-org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
 org.freedesktop.NetworkManager.reload                             nie      
-org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
-org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
+org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
+org.freedesktop.NetworkManager.settings.modify.hostname           tak      
+org.freedesktop.NetworkManager.settings.modify.own                tak      
+org.freedesktop.NetworkManager.settings.modify.system             tak      
+org.freedesktop.NetworkManager.sleep-wake                         nie      
 org.freedesktop.NetworkManager.wifi.scan                          nieznane 
+org.freedesktop.NetworkManager.wifi.share.open                    tak      
+org.freedesktop.NetworkManager.wifi.share.protected               tak      
 
 <<<
 size: 1614
@@ -154,23 +154,23 @@ returncode: 0
 stdout: 1467 bytes
 >>>
 PERMISSION                                                        VALUE   
+org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
 org.freedesktop.NetworkManager.enable-disable-network             yes     
+org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
 org.freedesktop.NetworkManager.enable-disable-wifi                yes     
-org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.enable-disable-wimax               yes     
-org.freedesktop.NetworkManager.sleep-wake                         no      
+org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.network-control                    yes     
-org.freedesktop.NetworkManager.wifi.share.protected               yes     
-org.freedesktop.NetworkManager.wifi.share.open                    yes     
-org.freedesktop.NetworkManager.settings.modify.system             yes     
-org.freedesktop.NetworkManager.settings.modify.own                yes     
-org.freedesktop.NetworkManager.settings.modify.hostname           yes     
-org.freedesktop.NetworkManager.settings.modify.global-dns         no      
 org.freedesktop.NetworkManager.reload                             no      
-org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
-org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
+org.freedesktop.NetworkManager.settings.modify.global-dns         no      
+org.freedesktop.NetworkManager.settings.modify.hostname           yes     
+org.freedesktop.NetworkManager.settings.modify.own                yes     
+org.freedesktop.NetworkManager.settings.modify.system             yes     
+org.freedesktop.NetworkManager.sleep-wake                         no      
 org.freedesktop.NetworkManager.wifi.scan                          unknown 
+org.freedesktop.NetworkManager.wifi.share.open                    yes     
+org.freedesktop.NetworkManager.wifi.share.protected               yes     
 
 <<<
 size: 1642
@@ -181,23 +181,23 @@ returncode: 0
 stdout: 1485 bytes
 >>>
 PERMISSION                                                        VALUE    
+org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
 org.freedesktop.NetworkManager.enable-disable-network             tak      
+org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
 org.freedesktop.NetworkManager.enable-disable-wifi                tak      
-org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.enable-disable-wimax               tak      
-org.freedesktop.NetworkManager.sleep-wake                         nie      
+org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.network-control                    tak      
-org.freedesktop.NetworkManager.wifi.share.protected               tak      
-org.freedesktop.NetworkManager.wifi.share.open                    tak      
-org.freedesktop.NetworkManager.settings.modify.system             tak      
-org.freedesktop.NetworkManager.settings.modify.own                tak      
-org.freedesktop.NetworkManager.settings.modify.hostname           tak      
-org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
 org.freedesktop.NetworkManager.reload                             nie      
-org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
-org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
+org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
+org.freedesktop.NetworkManager.settings.modify.hostname           tak      
+org.freedesktop.NetworkManager.settings.modify.own                tak      
+org.freedesktop.NetworkManager.settings.modify.system             tak      
+org.freedesktop.NetworkManager.sleep-wake                         nie      
 org.freedesktop.NetworkManager.wifi.scan                          nieznane 
+org.freedesktop.NetworkManager.wifi.share.open                    tak      
+org.freedesktop.NetworkManager.wifi.share.protected               tak      
 
 <<<
 size: 1691
@@ -212,23 +212,23 @@ stdout: 1547 bytes
 ==============================
 PERMISSION                                                        VALUE   
 ---------------------------------------------------------------------------------------------------------
+org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
 org.freedesktop.NetworkManager.enable-disable-network             yes     
+org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
 org.freedesktop.NetworkManager.enable-disable-wifi                yes     
-org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.enable-disable-wimax               yes     
-org.freedesktop.NetworkManager.sleep-wake                         no      
+org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.network-control                    yes     
-org.freedesktop.NetworkManager.wifi.share.protected               yes     
-org.freedesktop.NetworkManager.wifi.share.open                    yes     
-org.freedesktop.NetworkManager.settings.modify.system             yes     
-org.freedesktop.NetworkManager.settings.modify.own                yes     
-org.freedesktop.NetworkManager.settings.modify.hostname           yes     
-org.freedesktop.NetworkManager.settings.modify.global-dns         no      
 org.freedesktop.NetworkManager.reload                             no      
-org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
-org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
+org.freedesktop.NetworkManager.settings.modify.global-dns         no      
+org.freedesktop.NetworkManager.settings.modify.hostname           yes     
+org.freedesktop.NetworkManager.settings.modify.own                yes     
+org.freedesktop.NetworkManager.settings.modify.system             yes     
+org.freedesktop.NetworkManager.sleep-wake                         no      
 org.freedesktop.NetworkManager.wifi.scan                          unknown 
+org.freedesktop.NetworkManager.wifi.share.open                    yes     
+org.freedesktop.NetworkManager.wifi.share.protected               yes     
 
 <<<
 size: 1749
@@ -243,23 +243,23 @@ stdout: 1595 bytes
 =====================================
 PERMISSION                                                        VALUE    
 -----------------------------------------------------------------------------------------------------------------
+org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
 org.freedesktop.NetworkManager.enable-disable-network             tak      
+org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
 org.freedesktop.NetworkManager.enable-disable-wifi                tak      
-org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.enable-disable-wimax               tak      
-org.freedesktop.NetworkManager.sleep-wake                         nie      
+org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.network-control                    tak      
-org.freedesktop.NetworkManager.wifi.share.protected               tak      
-org.freedesktop.NetworkManager.wifi.share.open                    tak      
-org.freedesktop.NetworkManager.settings.modify.system             tak      
-org.freedesktop.NetworkManager.settings.modify.own                tak      
-org.freedesktop.NetworkManager.settings.modify.hostname           tak      
-org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
 org.freedesktop.NetworkManager.reload                             nie      
-org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
-org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
+org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
+org.freedesktop.NetworkManager.settings.modify.hostname           tak      
+org.freedesktop.NetworkManager.settings.modify.own                tak      
+org.freedesktop.NetworkManager.settings.modify.system             tak      
+org.freedesktop.NetworkManager.sleep-wake                         nie      
 org.freedesktop.NetworkManager.wifi.scan                          nieznane 
+org.freedesktop.NetworkManager.wifi.share.open                    tak      
+org.freedesktop.NetworkManager.wifi.share.protected               tak      
 
 <<<
 size: 1820
@@ -274,23 +274,23 @@ stdout: 1664 bytes
 ==============================
 PERMISSION                                                        VALUE   
 ---------------------------------------------------------------------------------------------------------
+org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
 org.freedesktop.NetworkManager.enable-disable-network             yes     
+org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
 org.freedesktop.NetworkManager.enable-disable-wifi                yes     
-org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.enable-disable-wimax               yes     
-org.freedesktop.NetworkManager.sleep-wake                         no      
+org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.network-control                    yes     
-org.freedesktop.NetworkManager.wifi.share.protected               yes     
-org.freedesktop.NetworkManager.wifi.share.open                    yes     
-org.freedesktop.NetworkManager.settings.modify.system             yes     
-org.freedesktop.NetworkManager.settings.modify.own                yes     
-org.freedesktop.NetworkManager.settings.modify.hostname           yes     
-org.freedesktop.NetworkManager.settings.modify.global-dns         no      
 org.freedesktop.NetworkManager.reload                             no      
-org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
-org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
+org.freedesktop.NetworkManager.settings.modify.global-dns         no      
+org.freedesktop.NetworkManager.settings.modify.hostname           yes     
+org.freedesktop.NetworkManager.settings.modify.own                yes     
+org.freedesktop.NetworkManager.settings.modify.system             yes     
+org.freedesktop.NetworkManager.sleep-wake                         no      
 org.freedesktop.NetworkManager.wifi.scan                          unknown 
+org.freedesktop.NetworkManager.wifi.share.open                    yes     
+org.freedesktop.NetworkManager.wifi.share.protected               yes     
 
 <<<
 size: 1878
@@ -305,23 +305,23 @@ stdout: 1712 bytes
 =====================================
 PERMISSION                                                        VALUE    
 -----------------------------------------------------------------------------------------------------------------
+org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
 org.freedesktop.NetworkManager.enable-disable-network             tak      
+org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
 org.freedesktop.NetworkManager.enable-disable-wifi                tak      
-org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.enable-disable-wimax               tak      
-org.freedesktop.NetworkManager.sleep-wake                         nie      
+org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.network-control                    tak      
-org.freedesktop.NetworkManager.wifi.share.protected               tak      
-org.freedesktop.NetworkManager.wifi.share.open                    tak      
-org.freedesktop.NetworkManager.settings.modify.system             tak      
-org.freedesktop.NetworkManager.settings.modify.own                tak      
-org.freedesktop.NetworkManager.settings.modify.hostname           tak      
-org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
 org.freedesktop.NetworkManager.reload                             nie      
-org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
-org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
+org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
+org.freedesktop.NetworkManager.settings.modify.hostname           tak      
+org.freedesktop.NetworkManager.settings.modify.own                tak      
+org.freedesktop.NetworkManager.settings.modify.system             tak      
+org.freedesktop.NetworkManager.sleep-wake                         nie      
 org.freedesktop.NetworkManager.wifi.scan                          nieznane 
+org.freedesktop.NetworkManager.wifi.share.open                    tak      
+org.freedesktop.NetworkManager.wifi.share.protected               tak      
 
 <<<
 size: 1090
@@ -331,23 +331,23 @@ lang: C
 returncode: 0
 stdout: 948 bytes
 >>>
+org.freedesktop.NetworkManager.checkpoint-rollback:unknown
+org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
 org.freedesktop.NetworkManager.enable-disable-network:yes
+org.freedesktop.NetworkManager.enable-disable-statistics:unknown
 org.freedesktop.NetworkManager.enable-disable-wifi:yes
-org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.enable-disable-wimax:yes
-org.freedesktop.NetworkManager.sleep-wake:no
+org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.network-control:yes
-org.freedesktop.NetworkManager.wifi.share.protected:yes
-org.freedesktop.NetworkManager.wifi.share.open:yes
-org.freedesktop.NetworkManager.settings.modify.system:yes
-org.freedesktop.NetworkManager.settings.modify.own:yes
-org.freedesktop.NetworkManager.settings.modify.hostname:yes
-org.freedesktop.NetworkManager.settings.modify.global-dns:no
 org.freedesktop.NetworkManager.reload:no
-org.freedesktop.NetworkManager.checkpoint-rollback:unknown
-org.freedesktop.NetworkManager.enable-disable-statistics:unknown
-org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
+org.freedesktop.NetworkManager.settings.modify.global-dns:no
+org.freedesktop.NetworkManager.settings.modify.hostname:yes
+org.freedesktop.NetworkManager.settings.modify.own:yes
+org.freedesktop.NetworkManager.settings.modify.system:yes
+org.freedesktop.NetworkManager.sleep-wake:no
 org.freedesktop.NetworkManager.wifi.scan:unknown
+org.freedesktop.NetworkManager.wifi.share.open:yes
+org.freedesktop.NetworkManager.wifi.share.protected:yes
 
 <<<
 size: 1100
@@ -357,23 +357,23 @@ lang: pl_PL.UTF-8
 returncode: 0
 stdout: 948 bytes
 >>>
+org.freedesktop.NetworkManager.checkpoint-rollback:unknown
+org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
 org.freedesktop.NetworkManager.enable-disable-network:yes
+org.freedesktop.NetworkManager.enable-disable-statistics:unknown
 org.freedesktop.NetworkManager.enable-disable-wifi:yes
-org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.enable-disable-wimax:yes
-org.freedesktop.NetworkManager.sleep-wake:no
+org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.network-control:yes
-org.freedesktop.NetworkManager.wifi.share.protected:yes
-org.freedesktop.NetworkManager.wifi.share.open:yes
-org.freedesktop.NetworkManager.settings.modify.system:yes
-org.freedesktop.NetworkManager.settings.modify.own:yes
-org.freedesktop.NetworkManager.settings.modify.hostname:yes
-org.freedesktop.NetworkManager.settings.modify.global-dns:no
 org.freedesktop.NetworkManager.reload:no
-org.freedesktop.NetworkManager.checkpoint-rollback:unknown
-org.freedesktop.NetworkManager.enable-disable-statistics:unknown
-org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
+org.freedesktop.NetworkManager.settings.modify.global-dns:no
+org.freedesktop.NetworkManager.settings.modify.hostname:yes
+org.freedesktop.NetworkManager.settings.modify.own:yes
+org.freedesktop.NetworkManager.settings.modify.system:yes
+org.freedesktop.NetworkManager.sleep-wake:no
 org.freedesktop.NetworkManager.wifi.scan:unknown
+org.freedesktop.NetworkManager.wifi.share.open:yes
+org.freedesktop.NetworkManager.wifi.share.protected:yes
 
 <<<
 size: 1220
@@ -383,23 +383,23 @@ lang: C
 returncode: 0
 stdout: 1065 bytes
 >>>
+org.freedesktop.NetworkManager.checkpoint-rollback:unknown
+org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
 org.freedesktop.NetworkManager.enable-disable-network:yes
+org.freedesktop.NetworkManager.enable-disable-statistics:unknown
 org.freedesktop.NetworkManager.enable-disable-wifi:yes
-org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.enable-disable-wimax:yes
-org.freedesktop.NetworkManager.sleep-wake:no
+org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.network-control:yes
-org.freedesktop.NetworkManager.wifi.share.protected:yes
-org.freedesktop.NetworkManager.wifi.share.open:yes
-org.freedesktop.NetworkManager.settings.modify.system:yes
-org.freedesktop.NetworkManager.settings.modify.own:yes
-org.freedesktop.NetworkManager.settings.modify.hostname:yes
-org.freedesktop.NetworkManager.settings.modify.global-dns:no
 org.freedesktop.NetworkManager.reload:no
-org.freedesktop.NetworkManager.checkpoint-rollback:unknown
-org.freedesktop.NetworkManager.enable-disable-statistics:unknown
-org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
+org.freedesktop.NetworkManager.settings.modify.global-dns:no
+org.freedesktop.NetworkManager.settings.modify.hostname:yes
+org.freedesktop.NetworkManager.settings.modify.own:yes
+org.freedesktop.NetworkManager.settings.modify.system:yes
+org.freedesktop.NetworkManager.sleep-wake:no
 org.freedesktop.NetworkManager.wifi.scan:unknown
+org.freedesktop.NetworkManager.wifi.share.open:yes
+org.freedesktop.NetworkManager.wifi.share.protected:yes
 
 <<<
 size: 1230
@@ -409,23 +409,23 @@ lang: pl_PL.UTF-8
 returncode: 0
 stdout: 1065 bytes
 >>>
+org.freedesktop.NetworkManager.checkpoint-rollback:unknown
+org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
 org.freedesktop.NetworkManager.enable-disable-network:yes
+org.freedesktop.NetworkManager.enable-disable-statistics:unknown
 org.freedesktop.NetworkManager.enable-disable-wifi:yes
-org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.enable-disable-wimax:yes
-org.freedesktop.NetworkManager.sleep-wake:no
+org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.network-control:yes
-org.freedesktop.NetworkManager.wifi.share.protected:yes
-org.freedesktop.NetworkManager.wifi.share.open:yes
-org.freedesktop.NetworkManager.settings.modify.system:yes
-org.freedesktop.NetworkManager.settings.modify.own:yes
-org.freedesktop.NetworkManager.settings.modify.hostname:yes
-org.freedesktop.NetworkManager.settings.modify.global-dns:no
 org.freedesktop.NetworkManager.reload:no
-org.freedesktop.NetworkManager.checkpoint-rollback:unknown
-org.freedesktop.NetworkManager.enable-disable-statistics:unknown
-org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
+org.freedesktop.NetworkManager.settings.modify.global-dns:no
+org.freedesktop.NetworkManager.settings.modify.hostname:yes
+org.freedesktop.NetworkManager.settings.modify.own:yes
+org.freedesktop.NetworkManager.settings.modify.system:yes
+org.freedesktop.NetworkManager.sleep-wake:no
 org.freedesktop.NetworkManager.wifi.scan:unknown
+org.freedesktop.NetworkManager.wifi.share.open:yes
+org.freedesktop.NetworkManager.wifi.share.protected:yes
 
 <<<
 size: 1500
@@ -436,23 +436,23 @@ returncode: 0
 stdout: 1350 bytes
 >>>
 PERMISSION                                                        VALUE   
+org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
 org.freedesktop.NetworkManager.enable-disable-network             yes     
+org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
 org.freedesktop.NetworkManager.enable-disable-wifi                yes     
-org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.enable-disable-wimax               yes     
-org.freedesktop.NetworkManager.sleep-wake                         no      
+org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.network-control                    yes     
-org.freedesktop.NetworkManager.wifi.share.protected               yes     
-org.freedesktop.NetworkManager.wifi.share.open                    yes     
-org.freedesktop.NetworkManager.settings.modify.system             yes     
-org.freedesktop.NetworkManager.settings.modify.own                yes     
-org.freedesktop.NetworkManager.settings.modify.hostname           yes     
-org.freedesktop.NetworkManager.settings.modify.global-dns         no      
 org.freedesktop.NetworkManager.reload                             no      
-org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
-org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
+org.freedesktop.NetworkManager.settings.modify.global-dns         no      
+org.freedesktop.NetworkManager.settings.modify.hostname           yes     
+org.freedesktop.NetworkManager.settings.modify.own                yes     
+org.freedesktop.NetworkManager.settings.modify.system             yes     
+org.freedesktop.NetworkManager.sleep-wake                         no      
 org.freedesktop.NetworkManager.wifi.scan                          unknown 
+org.freedesktop.NetworkManager.wifi.share.open                    yes     
+org.freedesktop.NetworkManager.wifi.share.protected               yes     
 
 <<<
 size: 1528
@@ -463,23 +463,23 @@ returncode: 0
 stdout: 1368 bytes
 >>>
 PERMISSION                                                        VALUE    
+org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
 org.freedesktop.NetworkManager.enable-disable-network             tak      
+org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
 org.freedesktop.NetworkManager.enable-disable-wifi                tak      
-org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.enable-disable-wimax               tak      
-org.freedesktop.NetworkManager.sleep-wake                         nie      
+org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.network-control                    tak      
-org.freedesktop.NetworkManager.wifi.share.protected               tak      
-org.freedesktop.NetworkManager.wifi.share.open                    tak      
-org.freedesktop.NetworkManager.settings.modify.system             tak      
-org.freedesktop.NetworkManager.settings.modify.own                tak      
-org.freedesktop.NetworkManager.settings.modify.hostname           tak      
-org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
 org.freedesktop.NetworkManager.reload                             nie      
-org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
-org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
+org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
+org.freedesktop.NetworkManager.settings.modify.hostname           tak      
+org.freedesktop.NetworkManager.settings.modify.own                tak      
+org.freedesktop.NetworkManager.settings.modify.system             tak      
+org.freedesktop.NetworkManager.sleep-wake                         nie      
 org.freedesktop.NetworkManager.wifi.scan                          nieznane 
+org.freedesktop.NetworkManager.wifi.share.open                    tak      
+org.freedesktop.NetworkManager.wifi.share.protected               tak      
 
 <<<
 size: 1629
@@ -490,23 +490,23 @@ returncode: 0
 stdout: 1467 bytes
 >>>
 PERMISSION                                                        VALUE   
+org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
 org.freedesktop.NetworkManager.enable-disable-network             yes     
+org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
 org.freedesktop.NetworkManager.enable-disable-wifi                yes     
-org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.enable-disable-wimax               yes     
-org.freedesktop.NetworkManager.sleep-wake                         no      
+org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.network-control                    yes     
-org.freedesktop.NetworkManager.wifi.share.protected               yes     
-org.freedesktop.NetworkManager.wifi.share.open                    yes     
-org.freedesktop.NetworkManager.settings.modify.system             yes     
-org.freedesktop.NetworkManager.settings.modify.own                yes     
-org.freedesktop.NetworkManager.settings.modify.hostname           yes     
-org.freedesktop.NetworkManager.settings.modify.global-dns         no      
 org.freedesktop.NetworkManager.reload                             no      
-org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
-org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
+org.freedesktop.NetworkManager.settings.modify.global-dns         no      
+org.freedesktop.NetworkManager.settings.modify.hostname           yes     
+org.freedesktop.NetworkManager.settings.modify.own                yes     
+org.freedesktop.NetworkManager.settings.modify.system             yes     
+org.freedesktop.NetworkManager.sleep-wake                         no      
 org.freedesktop.NetworkManager.wifi.scan                          unknown 
+org.freedesktop.NetworkManager.wifi.share.open                    yes     
+org.freedesktop.NetworkManager.wifi.share.protected               yes     
 
 <<<
 size: 1657
@@ -517,23 +517,23 @@ returncode: 0
 stdout: 1485 bytes
 >>>
 PERMISSION                                                        VALUE    
+org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
 org.freedesktop.NetworkManager.enable-disable-network             tak      
+org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
 org.freedesktop.NetworkManager.enable-disable-wifi                tak      
-org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.enable-disable-wimax               tak      
-org.freedesktop.NetworkManager.sleep-wake                         nie      
+org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.network-control                    tak      
-org.freedesktop.NetworkManager.wifi.share.protected               tak      
-org.freedesktop.NetworkManager.wifi.share.open                    tak      
-org.freedesktop.NetworkManager.settings.modify.system             tak      
-org.freedesktop.NetworkManager.settings.modify.own                tak      
-org.freedesktop.NetworkManager.settings.modify.hostname           tak      
-org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
 org.freedesktop.NetworkManager.reload                             nie      
-org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
-org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
+org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
+org.freedesktop.NetworkManager.settings.modify.hostname           tak      
+org.freedesktop.NetworkManager.settings.modify.own                tak      
+org.freedesktop.NetworkManager.settings.modify.system             tak      
+org.freedesktop.NetworkManager.sleep-wake                         nie      
 org.freedesktop.NetworkManager.wifi.scan                          nieznane 
+org.freedesktop.NetworkManager.wifi.share.open                    tak      
+org.freedesktop.NetworkManager.wifi.share.protected               tak      
 
 <<<
 size: 1706
@@ -548,23 +548,23 @@ stdout: 1547 bytes
 ==============================
 PERMISSION                                                        VALUE   
 ---------------------------------------------------------------------------------------------------------
+org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
 org.freedesktop.NetworkManager.enable-disable-network             yes     
+org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
 org.freedesktop.NetworkManager.enable-disable-wifi                yes     
-org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.enable-disable-wimax               yes     
-org.freedesktop.NetworkManager.sleep-wake                         no      
+org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.network-control                    yes     
-org.freedesktop.NetworkManager.wifi.share.protected               yes     
-org.freedesktop.NetworkManager.wifi.share.open                    yes     
-org.freedesktop.NetworkManager.settings.modify.system             yes     
-org.freedesktop.NetworkManager.settings.modify.own                yes     
-org.freedesktop.NetworkManager.settings.modify.hostname           yes     
-org.freedesktop.NetworkManager.settings.modify.global-dns         no      
 org.freedesktop.NetworkManager.reload                             no      
-org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
-org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
+org.freedesktop.NetworkManager.settings.modify.global-dns         no      
+org.freedesktop.NetworkManager.settings.modify.hostname           yes     
+org.freedesktop.NetworkManager.settings.modify.own                yes     
+org.freedesktop.NetworkManager.settings.modify.system             yes     
+org.freedesktop.NetworkManager.sleep-wake                         no      
 org.freedesktop.NetworkManager.wifi.scan                          unknown 
+org.freedesktop.NetworkManager.wifi.share.open                    yes     
+org.freedesktop.NetworkManager.wifi.share.protected               yes     
 
 <<<
 size: 1764
@@ -579,23 +579,23 @@ stdout: 1595 bytes
 =====================================
 PERMISSION                                                        VALUE    
 -----------------------------------------------------------------------------------------------------------------
+org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
 org.freedesktop.NetworkManager.enable-disable-network             tak      
+org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
 org.freedesktop.NetworkManager.enable-disable-wifi                tak      
-org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.enable-disable-wimax               tak      
-org.freedesktop.NetworkManager.sleep-wake                         nie      
+org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.network-control                    tak      
-org.freedesktop.NetworkManager.wifi.share.protected               tak      
-org.freedesktop.NetworkManager.wifi.share.open                    tak      
-org.freedesktop.NetworkManager.settings.modify.system             tak      
-org.freedesktop.NetworkManager.settings.modify.own                tak      
-org.freedesktop.NetworkManager.settings.modify.hostname           tak      
-org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
 org.freedesktop.NetworkManager.reload                             nie      
-org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
-org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
+org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
+org.freedesktop.NetworkManager.settings.modify.hostname           tak      
+org.freedesktop.NetworkManager.settings.modify.own                tak      
+org.freedesktop.NetworkManager.settings.modify.system             tak      
+org.freedesktop.NetworkManager.sleep-wake                         nie      
 org.freedesktop.NetworkManager.wifi.scan                          nieznane 
+org.freedesktop.NetworkManager.wifi.share.open                    tak      
+org.freedesktop.NetworkManager.wifi.share.protected               tak      
 
 <<<
 size: 1835
@@ -610,23 +610,23 @@ stdout: 1664 bytes
 ==============================
 PERMISSION                                                        VALUE   
 ---------------------------------------------------------------------------------------------------------
+org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
 org.freedesktop.NetworkManager.enable-disable-network             yes     
+org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
 org.freedesktop.NetworkManager.enable-disable-wifi                yes     
-org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.enable-disable-wimax               yes     
-org.freedesktop.NetworkManager.sleep-wake                         no      
+org.freedesktop.NetworkManager.enable-disable-wwan                yes     
 org.freedesktop.NetworkManager.network-control                    yes     
-org.freedesktop.NetworkManager.wifi.share.protected               yes     
-org.freedesktop.NetworkManager.wifi.share.open                    yes     
-org.freedesktop.NetworkManager.settings.modify.system             yes     
-org.freedesktop.NetworkManager.settings.modify.own                yes     
-org.freedesktop.NetworkManager.settings.modify.hostname           yes     
-org.freedesktop.NetworkManager.settings.modify.global-dns         no      
 org.freedesktop.NetworkManager.reload                             no      
-org.freedesktop.NetworkManager.checkpoint-rollback                unknown 
-org.freedesktop.NetworkManager.enable-disable-statistics          unknown 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  unknown 
+org.freedesktop.NetworkManager.settings.modify.global-dns         no      
+org.freedesktop.NetworkManager.settings.modify.hostname           yes     
+org.freedesktop.NetworkManager.settings.modify.own                yes     
+org.freedesktop.NetworkManager.settings.modify.system             yes     
+org.freedesktop.NetworkManager.sleep-wake                         no      
 org.freedesktop.NetworkManager.wifi.scan                          unknown 
+org.freedesktop.NetworkManager.wifi.share.open                    yes     
+org.freedesktop.NetworkManager.wifi.share.protected               yes     
 
 <<<
 size: 1893
@@ -641,23 +641,23 @@ stdout: 1712 bytes
 =====================================
 PERMISSION                                                        VALUE    
 -----------------------------------------------------------------------------------------------------------------
+org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
+org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
 org.freedesktop.NetworkManager.enable-disable-network             tak      
+org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
 org.freedesktop.NetworkManager.enable-disable-wifi                tak      
-org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.enable-disable-wimax               tak      
-org.freedesktop.NetworkManager.sleep-wake                         nie      
+org.freedesktop.NetworkManager.enable-disable-wwan                tak      
 org.freedesktop.NetworkManager.network-control                    tak      
-org.freedesktop.NetworkManager.wifi.share.protected               tak      
-org.freedesktop.NetworkManager.wifi.share.open                    tak      
-org.freedesktop.NetworkManager.settings.modify.system             tak      
-org.freedesktop.NetworkManager.settings.modify.own                tak      
-org.freedesktop.NetworkManager.settings.modify.hostname           tak      
-org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
 org.freedesktop.NetworkManager.reload                             nie      
-org.freedesktop.NetworkManager.checkpoint-rollback                nieznane 
-org.freedesktop.NetworkManager.enable-disable-statistics          nieznane 
-org.freedesktop.NetworkManager.enable-disable-connectivity-check  nieznane 
+org.freedesktop.NetworkManager.settings.modify.global-dns         nie      
+org.freedesktop.NetworkManager.settings.modify.hostname           tak      
+org.freedesktop.NetworkManager.settings.modify.own                tak      
+org.freedesktop.NetworkManager.settings.modify.system             tak      
+org.freedesktop.NetworkManager.sleep-wake                         nie      
 org.freedesktop.NetworkManager.wifi.scan                          nieznane 
+org.freedesktop.NetworkManager.wifi.share.open                    tak      
+org.freedesktop.NetworkManager.wifi.share.protected               tak      
 
 <<<
 size: 1105
@@ -667,23 +667,23 @@ lang: C
 returncode: 0
 stdout: 948 bytes
 >>>
+org.freedesktop.NetworkManager.checkpoint-rollback:unknown
+org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
 org.freedesktop.NetworkManager.enable-disable-network:yes
+org.freedesktop.NetworkManager.enable-disable-statistics:unknown
 org.freedesktop.NetworkManager.enable-disable-wifi:yes
-org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.enable-disable-wimax:yes
-org.freedesktop.NetworkManager.sleep-wake:no
+org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.network-control:yes
-org.freedesktop.NetworkManager.wifi.share.protected:yes
-org.freedesktop.NetworkManager.wifi.share.open:yes
-org.freedesktop.NetworkManager.settings.modify.system:yes
-org.freedesktop.NetworkManager.settings.modify.own:yes
-org.freedesktop.NetworkManager.settings.modify.hostname:yes
-org.freedesktop.NetworkManager.settings.modify.global-dns:no
 org.freedesktop.NetworkManager.reload:no
-org.freedesktop.NetworkManager.checkpoint-rollback:unknown
-org.freedesktop.NetworkManager.enable-disable-statistics:unknown
-org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
+org.freedesktop.NetworkManager.settings.modify.global-dns:no
+org.freedesktop.NetworkManager.settings.modify.hostname:yes
+org.freedesktop.NetworkManager.settings.modify.own:yes
+org.freedesktop.NetworkManager.settings.modify.system:yes
+org.freedesktop.NetworkManager.sleep-wake:no
 org.freedesktop.NetworkManager.wifi.scan:unknown
+org.freedesktop.NetworkManager.wifi.share.open:yes
+org.freedesktop.NetworkManager.wifi.share.protected:yes
 
 <<<
 size: 1115
@@ -693,23 +693,23 @@ lang: pl_PL.UTF-8
 returncode: 0
 stdout: 948 bytes
 >>>
+org.freedesktop.NetworkManager.checkpoint-rollback:unknown
+org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
 org.freedesktop.NetworkManager.enable-disable-network:yes
+org.freedesktop.NetworkManager.enable-disable-statistics:unknown
 org.freedesktop.NetworkManager.enable-disable-wifi:yes
-org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.enable-disable-wimax:yes
-org.freedesktop.NetworkManager.sleep-wake:no
+org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.network-control:yes
-org.freedesktop.NetworkManager.wifi.share.protected:yes
-org.freedesktop.NetworkManager.wifi.share.open:yes
-org.freedesktop.NetworkManager.settings.modify.system:yes
-org.freedesktop.NetworkManager.settings.modify.own:yes
-org.freedesktop.NetworkManager.settings.modify.hostname:yes
-org.freedesktop.NetworkManager.settings.modify.global-dns:no
 org.freedesktop.NetworkManager.reload:no
-org.freedesktop.NetworkManager.checkpoint-rollback:unknown
-org.freedesktop.NetworkManager.enable-disable-statistics:unknown
-org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
+org.freedesktop.NetworkManager.settings.modify.global-dns:no
+org.freedesktop.NetworkManager.settings.modify.hostname:yes
+org.freedesktop.NetworkManager.settings.modify.own:yes
+org.freedesktop.NetworkManager.settings.modify.system:yes
+org.freedesktop.NetworkManager.sleep-wake:no
 org.freedesktop.NetworkManager.wifi.scan:unknown
+org.freedesktop.NetworkManager.wifi.share.open:yes
+org.freedesktop.NetworkManager.wifi.share.protected:yes
 
 <<<
 size: 1235
@@ -719,23 +719,23 @@ lang: C
 returncode: 0
 stdout: 1065 bytes
 >>>
+org.freedesktop.NetworkManager.checkpoint-rollback:unknown
+org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
 org.freedesktop.NetworkManager.enable-disable-network:yes
+org.freedesktop.NetworkManager.enable-disable-statistics:unknown
 org.freedesktop.NetworkManager.enable-disable-wifi:yes
-org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.enable-disable-wimax:yes
-org.freedesktop.NetworkManager.sleep-wake:no
+org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.network-control:yes
-org.freedesktop.NetworkManager.wifi.share.protected:yes
-org.freedesktop.NetworkManager.wifi.share.open:yes
-org.freedesktop.NetworkManager.settings.modify.system:yes
-org.freedesktop.NetworkManager.settings.modify.own:yes
-org.freedesktop.NetworkManager.settings.modify.hostname:yes
-org.freedesktop.NetworkManager.settings.modify.global-dns:no
 org.freedesktop.NetworkManager.reload:no
-org.freedesktop.NetworkManager.checkpoint-rollback:unknown
-org.freedesktop.NetworkManager.enable-disable-statistics:unknown
-org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
+org.freedesktop.NetworkManager.settings.modify.global-dns:no
+org.freedesktop.NetworkManager.settings.modify.hostname:yes
+org.freedesktop.NetworkManager.settings.modify.own:yes
+org.freedesktop.NetworkManager.settings.modify.system:yes
+org.freedesktop.NetworkManager.sleep-wake:no
 org.freedesktop.NetworkManager.wifi.scan:unknown
+org.freedesktop.NetworkManager.wifi.share.open:yes
+org.freedesktop.NetworkManager.wifi.share.protected:yes
 
 <<<
 size: 1245
@@ -745,23 +745,23 @@ lang: pl_PL.UTF-8
 returncode: 0
 stdout: 1065 bytes
 >>>
+org.freedesktop.NetworkManager.checkpoint-rollback:unknown
+org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
 org.freedesktop.NetworkManager.enable-disable-network:yes
+org.freedesktop.NetworkManager.enable-disable-statistics:unknown
 org.freedesktop.NetworkManager.enable-disable-wifi:yes
-org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.enable-disable-wimax:yes
-org.freedesktop.NetworkManager.sleep-wake:no
+org.freedesktop.NetworkManager.enable-disable-wwan:yes
 org.freedesktop.NetworkManager.network-control:yes
-org.freedesktop.NetworkManager.wifi.share.protected:yes
-org.freedesktop.NetworkManager.wifi.share.open:yes
-org.freedesktop.NetworkManager.settings.modify.system:yes
-org.freedesktop.NetworkManager.settings.modify.own:yes
-org.freedesktop.NetworkManager.settings.modify.hostname:yes
-org.freedesktop.NetworkManager.settings.modify.global-dns:no
 org.freedesktop.NetworkManager.reload:no
-org.freedesktop.NetworkManager.checkpoint-rollback:unknown
-org.freedesktop.NetworkManager.enable-disable-statistics:unknown
-org.freedesktop.NetworkManager.enable-disable-connectivity-check:unknown
+org.freedesktop.NetworkManager.settings.modify.global-dns:no
+org.freedesktop.NetworkManager.settings.modify.hostname:yes
+org.freedesktop.NetworkManager.settings.modify.own:yes
+org.freedesktop.NetworkManager.settings.modify.system:yes
+org.freedesktop.NetworkManager.sleep-wake:no
 org.freedesktop.NetworkManager.wifi.scan:unknown
+org.freedesktop.NetworkManager.wifi.share.open:yes
+org.freedesktop.NetworkManager.wifi.share.protected:yes
 
 <<<
 size: 2460
@@ -771,40 +771,40 @@ lang: C
 returncode: 0
 stdout: 2308 bytes
 >>>
+PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
+VALUE:                                  unknown
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
+VALUE:                                  unknown
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-network
 VALUE:                                  yes
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
+VALUE:                                  unknown
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wifi
 VALUE:                                  yes
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
-VALUE:                                  yes
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wimax
 VALUE:                                  yes
-PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
-VALUE:                                  no
-PERMISSION:                             org.freedesktop.NetworkManager.network-control
-VALUE:                                  yes
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
 VALUE:                                  yes
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
+PERMISSION:                             org.freedesktop.NetworkManager.network-control
 VALUE:                                  yes
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
+PERMISSION:                             org.freedesktop.NetworkManager.reload
+VALUE:                                  no
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
+VALUE:                                  no
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
 VALUE:                                  yes
 PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.own
 VALUE:                                  yes
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
 VALUE:                                  yes
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
-VALUE:                                  no
-PERMISSION:                             org.freedesktop.NetworkManager.reload
+PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
 VALUE:                                  no
-PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
-VALUE:                                  unknown
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
-VALUE:                                  unknown
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
-VALUE:                                  unknown
 PERMISSION:                             org.freedesktop.NetworkManager.wifi.scan
 VALUE:                                  unknown
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
+VALUE:                                  yes
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
+VALUE:                                  yes
 
 <<<
 size: 2477
@@ -814,40 +814,40 @@ lang: pl_PL.UTF-8
 returncode: 0
 stdout: 2315 bytes
 >>>
+PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
+VALUE:                                  nieznane
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
+VALUE:                                  nieznane
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-network
 VALUE:                                  tak
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
+VALUE:                                  nieznane
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wifi
 VALUE:                                  tak
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
-VALUE:                                  tak
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wimax
 VALUE:                                  tak
-PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
-VALUE:                                  nie
-PERMISSION:                             org.freedesktop.NetworkManager.network-control
-VALUE:                                  tak
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
 VALUE:                                  tak
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
+PERMISSION:                             org.freedesktop.NetworkManager.network-control
 VALUE:                                  tak
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
+PERMISSION:                             org.freedesktop.NetworkManager.reload
+VALUE:                                  nie
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
+VALUE:                                  nie
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
 VALUE:                                  tak
 PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.own
 VALUE:                                  tak
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
 VALUE:                                  tak
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
-VALUE:                                  nie
-PERMISSION:                             org.freedesktop.NetworkManager.reload
+PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
 VALUE:                                  nie
-PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
-VALUE:                                  nieznane
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
-VALUE:                                  nieznane
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
-VALUE:                                  nieznane
 PERMISSION:                             org.freedesktop.NetworkManager.wifi.scan
 VALUE:                                  nieznane
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
+VALUE:                                  tak
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
+VALUE:                                  tak
 
 <<<
 size: 2589
@@ -857,40 +857,40 @@ lang: C
 returncode: 0
 stdout: 2425 bytes
 >>>
+PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
+VALUE:                                  unknown
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
+VALUE:                                  unknown
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-network
 VALUE:                                  yes
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
+VALUE:                                  unknown
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wifi
 VALUE:                                  yes
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
-VALUE:                                  yes
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wimax
 VALUE:                                  yes
-PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
-VALUE:                                  no
-PERMISSION:                             org.freedesktop.NetworkManager.network-control
-VALUE:                                  yes
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
 VALUE:                                  yes
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
+PERMISSION:                             org.freedesktop.NetworkManager.network-control
 VALUE:                                  yes
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
+PERMISSION:                             org.freedesktop.NetworkManager.reload
+VALUE:                                  no
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
+VALUE:                                  no
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
 VALUE:                                  yes
 PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.own
 VALUE:                                  yes
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
 VALUE:                                  yes
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
-VALUE:                                  no
-PERMISSION:                             org.freedesktop.NetworkManager.reload
+PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
 VALUE:                                  no
-PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
-VALUE:                                  unknown
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
-VALUE:                                  unknown
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
-VALUE:                                  unknown
 PERMISSION:                             org.freedesktop.NetworkManager.wifi.scan
 VALUE:                                  unknown
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
+VALUE:                                  yes
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
+VALUE:                                  yes
 
 <<<
 size: 2606
@@ -900,40 +900,40 @@ lang: pl_PL.UTF-8
 returncode: 0
 stdout: 2432 bytes
 >>>
+PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
+VALUE:                                  nieznane
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
+VALUE:                                  nieznane
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-network
 VALUE:                                  tak
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
+VALUE:                                  nieznane
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wifi
 VALUE:                                  tak
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
-VALUE:                                  tak
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wimax
 VALUE:                                  tak
-PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
-VALUE:                                  nie
-PERMISSION:                             org.freedesktop.NetworkManager.network-control
-VALUE:                                  tak
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
 VALUE:                                  tak
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
+PERMISSION:                             org.freedesktop.NetworkManager.network-control
 VALUE:                                  tak
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
+PERMISSION:                             org.freedesktop.NetworkManager.reload
+VALUE:                                  nie
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
+VALUE:                                  nie
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
 VALUE:                                  tak
 PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.own
 VALUE:                                  tak
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
 VALUE:                                  tak
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
-VALUE:                                  nie
-PERMISSION:                             org.freedesktop.NetworkManager.reload
+PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
 VALUE:                                  nie
-PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
-VALUE:                                  nieznane
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
-VALUE:                                  nieznane
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
-VALUE:                                  nieznane
 PERMISSION:                             org.freedesktop.NetworkManager.wifi.scan
 VALUE:                                  nieznane
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
+VALUE:                                  tak
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
+VALUE:                                  tak
 
 <<<
 size: 4042
@@ -946,56 +946,56 @@ stdout: 3881 bytes
 ===============================================================================
                           NetworkManager permissions
 ===============================================================================
+PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
+VALUE:                                  unknown
+-------------------------------------------------------------------------------
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
+VALUE:                                  unknown
+-------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-network
 VALUE:                                  yes
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wifi
-VALUE:                                  yes
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
+VALUE:                                  unknown
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wifi
 VALUE:                                  yes
 -------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wimax
 VALUE:                                  yes
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
-VALUE:                                  no
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
+VALUE:                                  yes
 -------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.network-control
 VALUE:                                  yes
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
-VALUE:                                  yes
+PERMISSION:                             org.freedesktop.NetworkManager.reload
+VALUE:                                  no
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
-VALUE:                                  yes
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
+VALUE:                                  no
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
 VALUE:                                  yes
 -------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.own
 VALUE:                                  yes
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
 VALUE:                                  yes
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
-VALUE:                                  no
--------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.reload
+PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
 VALUE:                                  no
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
-VALUE:                                  unknown
--------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.scan
 VALUE:                                  unknown
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
-VALUE:                                  unknown
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
+VALUE:                                  yes
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.scan
-VALUE:                                  unknown
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
+VALUE:                                  yes
 -------------------------------------------------------------------------------
 
 <<<
@@ -1009,56 +1009,56 @@ stdout: 3893 bytes
 ===============================================================================
                        Uprawnienia usługi NetworkManager
 ===============================================================================
+PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
+VALUE:                                  nieznane
+-------------------------------------------------------------------------------
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
+VALUE:                                  nieznane
+-------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-network
 VALUE:                                  tak
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wifi
-VALUE:                                  tak
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
+VALUE:                                  nieznane
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wifi
 VALUE:                                  tak
 -------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wimax
 VALUE:                                  tak
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
-VALUE:                                  nie
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
+VALUE:                                  tak
 -------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.network-control
 VALUE:                                  tak
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
-VALUE:                                  tak
+PERMISSION:                             org.freedesktop.NetworkManager.reload
+VALUE:                                  nie
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
-VALUE:                                  tak
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
+VALUE:                                  nie
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
 VALUE:                                  tak
 -------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.own
 VALUE:                                  tak
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
 VALUE:                                  tak
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
-VALUE:                                  nie
--------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.reload
+PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
 VALUE:                                  nie
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
-VALUE:                                  nieznane
--------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.scan
 VALUE:                                  nieznane
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
-VALUE:                                  nieznane
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
+VALUE:                                  tak
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.scan
-VALUE:                                  nieznane
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
+VALUE:                                  tak
 -------------------------------------------------------------------------------
 
 <<<
@@ -1072,56 +1072,56 @@ stdout: 3998 bytes
 ===============================================================================
                           NetworkManager permissions
 ===============================================================================
+PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
+VALUE:                                  unknown
+-------------------------------------------------------------------------------
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
+VALUE:                                  unknown
+-------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-network
 VALUE:                                  yes
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wifi
-VALUE:                                  yes
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
+VALUE:                                  unknown
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wifi
 VALUE:                                  yes
 -------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wimax
 VALUE:                                  yes
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
-VALUE:                                  no
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
+VALUE:                                  yes
 -------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.network-control
 VALUE:                                  yes
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
-VALUE:                                  yes
+PERMISSION:                             org.freedesktop.NetworkManager.reload
+VALUE:                                  no
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
-VALUE:                                  yes
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
+VALUE:                                  no
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
 VALUE:                                  yes
 -------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.own
 VALUE:                                  yes
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
 VALUE:                                  yes
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
-VALUE:                                  no
--------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.reload
+PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
 VALUE:                                  no
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
-VALUE:                                  unknown
--------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.scan
 VALUE:                                  unknown
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
-VALUE:                                  unknown
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
+VALUE:                                  yes
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.scan
-VALUE:                                  unknown
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
+VALUE:                                  yes
 -------------------------------------------------------------------------------
 
 <<<
@@ -1135,56 +1135,56 @@ stdout: 4010 bytes
 ===============================================================================
                        Uprawnienia usługi NetworkManager
 ===============================================================================
+PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
+VALUE:                                  nieznane
+-------------------------------------------------------------------------------
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
+VALUE:                                  nieznane
+-------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-network
 VALUE:                                  tak
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wifi
-VALUE:                                  tak
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
+VALUE:                                  nieznane
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wifi
 VALUE:                                  tak
 -------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wimax
 VALUE:                                  tak
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
-VALUE:                                  nie
+PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-wwan
+VALUE:                                  tak
 -------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.network-control
 VALUE:                                  tak
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
-VALUE:                                  tak
+PERMISSION:                             org.freedesktop.NetworkManager.reload
+VALUE:                                  nie
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
-VALUE:                                  tak
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
+VALUE:                                  nie
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
 VALUE:                                  tak
 -------------------------------------------------------------------------------
 PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.own
 VALUE:                                  tak
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.hostname
+PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.system
 VALUE:                                  tak
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.settings.modify.global-dns
-VALUE:                                  nie
--------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.reload
+PERMISSION:                             org.freedesktop.NetworkManager.sleep-wake
 VALUE:                                  nie
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.checkpoint-rollback
-VALUE:                                  nieznane
--------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-statistics
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.scan
 VALUE:                                  nieznane
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.enable-disable-connectivity-check
-VALUE:                                  nieznane
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.open
+VALUE:                                  tak
 -------------------------------------------------------------------------------
-PERMISSION:                             org.freedesktop.NetworkManager.wifi.scan
-VALUE:                                  nieznane
+PERMISSION:                             org.freedesktop.NetworkManager.wifi.share.protected
+VALUE:                                  tak
 -------------------------------------------------------------------------------
 
 <<<
@@ -1195,40 +1195,40 @@ lang: C
 returncode: 0
 stdout: 1237 bytes
 >>>
+PERMISSION:org.freedesktop.NetworkManager.checkpoint-rollback
+VALUE:unknown
+PERMISSION:org.freedesktop.NetworkManager.enable-disable-connectivity-check
+VALUE:unknown
 PERMISSION:org.freedesktop.NetworkManager.enable-disable-network
 VALUE:yes
+PERMISSION:org.freedesktop.NetworkManager.enable-disable-statistics
+VALUE:unknown
 PERMISSION:org.freedesktop.NetworkManager.enable-disable-wifi
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.enable-disable-wwan
-VALUE:yes
 PERMISSION:org.freedesktop.NetworkManager.enable-disable-wimax
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.sleep-wake
-VALUE:no
-PERMISSION:org.freedesktop.NetworkManager.network-control
-VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.wifi.share.protected
+PERMISSION:org.freedesktop.NetworkManager.enable-disable-wwan
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.wifi.share.open
+PERMISSION:org.freedesktop.NetworkManager.network-control
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.settings.modify.system
+PERMISSION:org.freedesktop.NetworkManager.reload
+VALUE:no
+PERMISSION:org.freedesktop.NetworkManager.settings.modify.global-dns
+VALUE:no
+PERMISSION:org.freedesktop.NetworkManager.settings.modify.hostname
 VALUE:yes
 PERMISSION:org.freedesktop.NetworkManager.settings.modify.own
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.settings.modify.hostname
+PERMISSION:org.freedesktop.NetworkManager.settings.modify.system
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.settings.modify.global-dns
-VALUE:no
-PERMISSION:org.freedesktop.NetworkManager.reload
+PERMISSION:org.freedesktop.NetworkManager.sleep-wake
 VALUE:no
-PERMISSION:org.freedesktop.NetworkManager.checkpoint-rollback
-VALUE:unknown
-PERMISSION:org.freedesktop.NetworkManager.enable-disable-statistics
-VALUE:unknown
-PERMISSION:org.freedesktop.NetworkManager.enable-disable-connectivity-check
-VALUE:unknown
 PERMISSION:org.freedesktop.NetworkManager.wifi.scan
 VALUE:unknown
+PERMISSION:org.freedesktop.NetworkManager.wifi.share.open
+VALUE:yes
+PERMISSION:org.freedesktop.NetworkManager.wifi.share.protected
+VALUE:yes
 
 <<<
 size: 1407
@@ -1238,40 +1238,40 @@ lang: pl_PL.UTF-8
 returncode: 0
 stdout: 1237 bytes
 >>>
+PERMISSION:org.freedesktop.NetworkManager.checkpoint-rollback
+VALUE:unknown
+PERMISSION:org.freedesktop.NetworkManager.enable-disable-connectivity-check
+VALUE:unknown
 PERMISSION:org.freedesktop.NetworkManager.enable-disable-network
 VALUE:yes
+PERMISSION:org.freedesktop.NetworkManager.enable-disable-statistics
+VALUE:unknown
 PERMISSION:org.freedesktop.NetworkManager.enable-disable-wifi
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.enable-disable-wwan
-VALUE:yes
 PERMISSION:org.freedesktop.NetworkManager.enable-disable-wimax
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.sleep-wake
-VALUE:no
-PERMISSION:org.freedesktop.NetworkManager.network-control
-VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.wifi.share.protected
+PERMISSION:org.freedesktop.NetworkManager.enable-disable-wwan
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.wifi.share.open
+PERMISSION:org.freedesktop.NetworkManager.network-control
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.settings.modify.system
+PERMISSION:org.freedesktop.NetworkManager.reload
+VALUE:no
+PERMISSION:org.freedesktop.NetworkManager.settings.modify.global-dns
+VALUE:no
+PERMISSION:org.freedesktop.NetworkManager.settings.modify.hostname
 VALUE:yes
 PERMISSION:org.freedesktop.NetworkManager.settings.modify.own
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.settings.modify.hostname
+PERMISSION:org.freedesktop.NetworkManager.settings.modify.system
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.settings.modify.global-dns
-VALUE:no
-PERMISSION:org.freedesktop.NetworkManager.reload
+PERMISSION:org.freedesktop.NetworkManager.sleep-wake
 VALUE:no
-PERMISSION:org.freedesktop.NetworkManager.checkpoint-rollback
-VALUE:unknown
-PERMISSION:org.freedesktop.NetworkManager.enable-disable-statistics
-VALUE:unknown
-PERMISSION:org.freedesktop.NetworkManager.enable-disable-connectivity-check
-VALUE:unknown
 PERMISSION:org.freedesktop.NetworkManager.wifi.scan
 VALUE:unknown
+PERMISSION:org.freedesktop.NetworkManager.wifi.share.open
+VALUE:yes
+PERMISSION:org.freedesktop.NetworkManager.wifi.share.protected
+VALUE:yes
 
 <<<
 size: 1526
@@ -1281,40 +1281,40 @@ lang: C
 returncode: 0
 stdout: 1354 bytes
 >>>
+PERMISSION:org.freedesktop.NetworkManager.checkpoint-rollback
+VALUE:unknown
+PERMISSION:org.freedesktop.NetworkManager.enable-disable-connectivity-check
+VALUE:unknown
 PERMISSION:org.freedesktop.NetworkManager.enable-disable-network
 VALUE:yes
+PERMISSION:org.freedesktop.NetworkManager.enable-disable-statistics
+VALUE:unknown
 PERMISSION:org.freedesktop.NetworkManager.enable-disable-wifi
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.enable-disable-wwan
-VALUE:yes
 PERMISSION:org.freedesktop.NetworkManager.enable-disable-wimax
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.sleep-wake
-VALUE:no
-PERMISSION:org.freedesktop.NetworkManager.network-control
-VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.wifi.share.protected
+PERMISSION:org.freedesktop.NetworkManager.enable-disable-wwan
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.wifi.share.open
+PERMISSION:org.freedesktop.NetworkManager.network-control
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.settings.modify.system
+PERMISSION:org.freedesktop.NetworkManager.reload
+VALUE:no
+PERMISSION:org.freedesktop.NetworkManager.settings.modify.global-dns
+VALUE:no
+PERMISSION:org.freedesktop.NetworkManager.settings.modify.hostname
 VALUE:yes
 PERMISSION:org.freedesktop.NetworkManager.settings.modify.own
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.settings.modify.hostname
+PERMISSION:org.freedesktop.NetworkManager.settings.modify.system
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.settings.modify.global-dns
-VALUE:no
-PERMISSION:org.freedesktop.NetworkManager.reload
+PERMISSION:org.freedesktop.NetworkManager.sleep-wake
 VALUE:no
-PERMISSION:org.freedesktop.NetworkManager.checkpoint-rollback
-VALUE:unknown
-PERMISSION:org.freedesktop.NetworkManager.enable-disable-statistics
-VALUE:unknown
-PERMISSION:org.freedesktop.NetworkManager.enable-disable-connectivity-check
-VALUE:unknown
 PERMISSION:org.freedesktop.NetworkManager.wifi.scan
 VALUE:unknown
+PERMISSION:org.freedesktop.NetworkManager.wifi.share.open
+VALUE:yes
+PERMISSION:org.freedesktop.NetworkManager.wifi.share.protected
+VALUE:yes
 
 <<<
 size: 1536
@@ -1324,39 +1324,39 @@ lang: pl_PL.UTF-8
 returncode: 0
 stdout: 1354 bytes
 >>>
+PERMISSION:org.freedesktop.NetworkManager.checkpoint-rollback
+VALUE:unknown
+PERMISSION:org.freedesktop.NetworkManager.enable-disable-connectivity-check
+VALUE:unknown
 PERMISSION:org.freedesktop.NetworkManager.enable-disable-network
 VALUE:yes
+PERMISSION:org.freedesktop.NetworkManager.enable-disable-statistics
+VALUE:unknown
 PERMISSION:org.freedesktop.NetworkManager.enable-disable-wifi
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.enable-disable-wwan
-VALUE:yes
 PERMISSION:org.freedesktop.NetworkManager.enable-disable-wimax
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.sleep-wake
-VALUE:no
-PERMISSION:org.freedesktop.NetworkManager.network-control
-VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.wifi.share.protected
+PERMISSION:org.freedesktop.NetworkManager.enable-disable-wwan
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.wifi.share.open
+PERMISSION:org.freedesktop.NetworkManager.network-control
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.settings.modify.system
+PERMISSION:org.freedesktop.NetworkManager.reload
+VALUE:no
+PERMISSION:org.freedesktop.NetworkManager.settings.modify.global-dns
+VALUE:no
+PERMISSION:org.freedesktop.NetworkManager.settings.modify.hostname
 VALUE:yes
 PERMISSION:org.freedesktop.NetworkManager.settings.modify.own
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.settings.modify.hostname
+PERMISSION:org.freedesktop.NetworkManager.settings.modify.system
 VALUE:yes
-PERMISSION:org.freedesktop.NetworkManager.settings.modify.global-dns
-VALUE:no
-PERMISSION:org.freedesktop.NetworkManager.reload
+PERMISSION:org.freedesktop.NetworkManager.sleep-wake
 VALUE:no
-PERMISSION:org.freedesktop.NetworkManager.checkpoint-rollback
-VALUE:unknown
-PERMISSION:org.freedesktop.NetworkManager.enable-disable-statistics
-VALUE:unknown
-PERMISSION:org.freedesktop.NetworkManager.enable-disable-connectivity-check
-VALUE:unknown
 PERMISSION:org.freedesktop.NetworkManager.wifi.scan
 VALUE:unknown
+PERMISSION:org.freedesktop.NetworkManager.wifi.share.open
+VALUE:yes
+PERMISSION:org.freedesktop.NetworkManager.wifi.share.protected
+VALUE:yes
 
 <<<
diff --git a/clients/tests/test-client.py b/clients/tests/test-client.py
index 2742824c..daa69842 100755
--- a/clients/tests/test-client.py
+++ b/clients/tests/test-client.py
@@ -26,11 +26,6 @@ from __future__ import print_function
 #    # The important part is that translations work. Test
 #    #  $ LANG=pl_PL.UTF-8 ./clients/cli/nmcli --version
 #    # also ensure that `locale -a` reports the Polish locale.
-#  $ rm -rf  clients/tests/test-client.check-on-disk/*.expected
-#    # (step seldom required)
-#    # Sometimes, if you want to be sure that the test would generate
-#    # exactly the same .expected files, purge the previous version first.
-#    # This is only necessary, when you remove test from this file.
 #  $ NM_TEST_REGENERATE=1 make check-local-clients-tests-test-client
 #    # Set NM_TEST_REGENERATE=1 to regenerate all files.
 #  $ git diff ... ; git add ...
@@ -137,6 +132,43 @@ _UNSTABLE_OUTPUT = object()
 
 class Util:
 
+    _signal_no_lookup = {
+         1: "SIGHUP",
+         2: "SIGINT",
+         3: "SIGQUIT",
+         4: "SIGILL",
+         5: "SIGTRAP",
+         6: "SIGABRT",
+         8: "SIGFPE",
+         9: "SIGKILL",
+        11: "SIGSEGV",
+        12: "SIGSYS",
+        13: "SIGPIPE",
+        14: "SIGALRM",
+        15: "SIGTERM",
+        16: "SIGURG",
+        17: "SIGSTOP",
+        18: "SIGTSTP",
+        19: "SIGCONT",
+        20: "SIGCHLD",
+        21: "SIGTTIN",
+        22: "SIGTTOU",
+        23: "SIGPOLL",
+        24: "SIGXCPU",
+        25: "SIGXFSZ",
+        26: "SIGVTALRM",
+        27: "SIGPROF",
+        30: "SIGUSR1",
+        31: "SIGUSR2",
+    }
+
+    @classmethod
+    def signal_no_to_str(cls, signal):
+        s = cls._signal_no_lookup.get(signal, None)
+        if s is None:
+            return "<unknown %d>" % (signal)
+        return s
+
     @staticmethod
     def python_has_version(major, minor = 0):
         return    sys.version_info[0] > major \
@@ -807,10 +839,15 @@ class TestNmcli(NmTestBase):
                 cmd = '$NMCLI %s' % (' '.join([Util.quote(a) for a in args[1:]]))
                 cmd = Util.replace_text(cmd, replace_cmd)
 
+                if returncode < 0:
+                    returncode_str = '%d (SIGNAL %s)' % (returncode, Util.signal_no_to_str(-returncode))
+                else:
+                    returncode_str = '%d' % (returncode)
+
                 content = ('location: %s\n' % (calling_location)).encode('utf8') + \
                           ('cmd: %s\n' % (cmd)).encode('utf8') + \
                           ('lang: %s\n' % (lang)).encode('utf8') + \
-                          ('returncode: %d\n' % (returncode)).encode('utf8')
+                          ('returncode: %s\n' % (returncode_str)).encode('utf8')
                 if len(stdout) > 0:
                     content += ('stdout: %d bytes\n>>>\n' % (len(stdout))).encode('utf8') + \
                                stdout + \
diff --git a/clients/tui/meson.build b/clients/tui/meson.build
index 8948d6ff..4f945a69 100644
--- a/clients/tui/meson.build
+++ b/clients/tui/meson.build
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: LGPL-2.1+
+
 name = 'nmtui'
 
 common_c_flags = clients_c_flags + ['-DG_LOG_DOMAIN="@0@"'.format(name)]
@@ -51,6 +53,7 @@ deps = [
   libnmc_base_dep,
   libnmc_dep,
   libnmt_newt_dep,
+  libnm_libnm_aux_dep,
 ]
 
 executable(
diff --git a/clients/tui/newt/meson.build b/clients/tui/newt/meson.build
index d543f7ea..f2af7b20 100644
--- a/clients/tui/newt/meson.build
+++ b/clients/tui/newt/meson.build
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: LGPL-2.1+
+
 sources = files(
   'nmt-newt-button-box.c',
   'nmt-newt-button.c',
diff --git a/clients/tui/newt/nmt-newt-form.c b/clients/tui/newt/nmt-newt-form.c
index 881b6f5d..2142e3c5 100644
--- a/clients/tui/newt/nmt-newt-form.c
+++ b/clients/tui/newt/nmt-newt-form.c
@@ -312,9 +312,9 @@ static GSList *form_stack;
 static GSource *keypress_source;
 
 static gboolean
-nmt_newt_form_keypress_callback (int          fd,
+nmt_newt_form_keypress_callback (int fd,
                                  GIOCondition condition,
-                                 gpointer     user_data)
+                                 gpointer user_data)
 {
 	g_return_val_if_fail (form_stack != NULL, FALSE);
 
@@ -340,16 +340,14 @@ static void
 nmt_newt_form_real_show (NmtNewtForm *form)
 {
 	if (!keypress_source) {
-		GIOChannel *io;
-
-		io = g_io_channel_unix_new (STDIN_FILENO);
-		keypress_source = g_io_create_watch (io, G_IO_IN);
+		keypress_source = nm_g_unix_fd_source_new (STDIN_FILENO,
+		                                           G_IO_IN,
+		                                           G_PRIORITY_DEFAULT,
+		                                           nmt_newt_form_keypress_callback,
+		                                           NULL,
+		                                           NULL);
 		g_source_set_can_recurse (keypress_source, TRUE);
-		g_source_set_callback (keypress_source,
-		                       (GSourceFunc)(void (*) (void)) nmt_newt_form_keypress_callback,
-		                       NULL, NULL);
 		g_source_attach (keypress_source, NULL);
-		g_io_channel_unref (io);
 	}
 
 	nmt_newt_form_build (form);
@@ -416,10 +414,8 @@ nmt_newt_form_quit (NmtNewtForm *form)
 
 	if (form_stack)
 		nmt_newt_form_iterate (form_stack->data);
-	else if (keypress_source) {
-		g_source_destroy (keypress_source);
-		g_clear_pointer (&keypress_source, g_source_unref);
-	}
+	else
+		nm_clear_g_source_inst (&keypress_source);
 
 	g_signal_emit (form, signals[QUIT], 0);
 	g_object_unref (form);
diff --git a/clients/tui/newt/nmt-newt-grid.c b/clients/tui/newt/nmt-newt-grid.c
index 68ac874c..ff411812 100644
--- a/clients/tui/newt/nmt-newt-grid.c
+++ b/clients/tui/newt/nmt-newt-grid.c
@@ -78,10 +78,10 @@ nmt_newt_grid_finalize (GObject *object)
 	NmtNewtGridPrivate *priv = NMT_NEWT_GRID_GET_PRIVATE (object);
 
 	g_array_unref (priv->children);
-	g_clear_pointer (&priv->row_heights, g_free);
-	g_clear_pointer (&priv->col_widths, g_free);
-	g_clear_pointer (&priv->expand_rows, g_free);
-	g_clear_pointer (&priv->expand_cols, g_free);
+	nm_clear_g_free (&priv->row_heights);
+	nm_clear_g_free (&priv->col_widths);
+	nm_clear_g_free (&priv->expand_rows);
+	nm_clear_g_free (&priv->expand_cols);
 
 	G_OBJECT_CLASS (nmt_newt_grid_parent_class)->finalize (object);
 }
diff --git a/clients/tui/nm-editor-bindings.c b/clients/tui/nm-editor-bindings.c
index 00a34fbf..c5606f11 100644
--- a/clients/tui/nm-editor-bindings.c
+++ b/clients/tui/nm-editor-bindings.c
@@ -192,7 +192,7 @@ ip_addresses_check_and_copy (GBinding     *binding,
 	strings = g_value_get_boxed (source_value);
 
 	for (i = 0; strings[i]; i++) {
-		if (!nm_utils_ipaddr_valid (addr_family, strings[i]))
+		if (!nm_utils_ipaddr_is_valid (addr_family, strings[i]))
 			return FALSE;
 	}
 
@@ -251,7 +251,7 @@ ip_gateway_from_string (GBinding     *binding,
 	const char *gateway;
 
 	gateway = g_value_get_string (source_value);
-	if (gateway && !nm_utils_ipaddr_valid (addr_family, gateway))
+	if (gateway && !nm_utils_ipaddr_is_valid (addr_family, gateway))
 		gateway = NULL;
 
 	g_value_set_string (target_value, gateway);
@@ -457,7 +457,7 @@ ip_route_transform_from_next_hop_string (GBinding     *binding,
 
 	text = g_value_get_string (source_value);
 	if (*text) {
-		if (!nm_utils_ipaddr_valid (addr_family, text))
+		if (!nm_utils_ipaddr_is_valid (addr_family, text))
 			return FALSE;
 	} else
 		text = NULL;
@@ -595,6 +595,9 @@ get_security_type (NMEditorWirelessSecurityMethodBinding *binding)
 	if (!strcmp (key_mgmt, "sae"))
 		return "wpa3-personal";
 
+	if (!strcmp (key_mgmt, "owe"))
+		return "owe";
+
 	if (!strcmp (key_mgmt, "wpa-eap"))
 		return "wpa-enterprise";
 
@@ -705,6 +708,12 @@ wireless_security_target_changed (GObject    *object,
 		              NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, NULL,
 		              NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_UNKNOWN,
 		              NULL);
+	} else if (!strcmp (method, "owe")) {
+		g_object_set (binding->s_wsec,
+		              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "owe",
+		              NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, NULL,
+		              NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_UNKNOWN,
+		              NULL);
 	} else if (!strcmp (method, "wpa-enterprise")) {
 		g_object_set (binding->s_wsec,
 		              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap",
diff --git a/clients/tui/nm-editor-utils.c b/clients/tui/nm-editor-utils.c
index 83fd8d3b..42019361 100644
--- a/clients/tui/nm-editor-utils.c
+++ b/clients/tui/nm-editor-utils.c
@@ -56,24 +56,19 @@ bond_connection_setup_func (NMConnection        *connection,
                             NMSetting           *s_hw)
 {
 	NMSettingBond *s_bond = NM_SETTING_BOND (s_hw);
-	const char *def, *cur;
+	guint i;
+	const char *value;
 	static const char *const options[] = {
-		NM_SETTING_BOND_OPTION_ARP_INTERVAL,
-		NM_SETTING_BOND_OPTION_ARP_IP_TARGET,
-		NM_SETTING_BOND_OPTION_DOWNDELAY,
-		NM_SETTING_BOND_OPTION_MIIMON,
 		NM_SETTING_BOND_OPTION_MODE,
-		NM_SETTING_BOND_OPTION_PRIMARY,
+		NM_SETTING_BOND_OPTION_MIIMON,
+		NM_SETTING_BOND_OPTION_DOWNDELAY,
 		NM_SETTING_BOND_OPTION_UPDELAY,
 	};
-	guint i;
 
-	/* Only add options supported by the UI */
 	for (i = 0; i < G_N_ELEMENTS (options); i++) {
-		def = nm_setting_bond_get_option_default (s_bond, options[i]);
-		cur = nm_setting_bond_get_option_by_name (s_bond, options[i]);
-		if (!nm_streq0 (def, cur))
-			nm_setting_bond_add_option (s_bond, options[i], def);
+		value = nm_setting_bond_get_option_default (s_bond, options[i]);
+		if (value)
+			nm_setting_bond_add_option (s_bond, options[i], value);
 	}
 }
 
diff --git a/clients/tui/nmt-connect-connection-list.c b/clients/tui/nmt-connect-connection-list.c
index 1975b1c6..411c2c00 100644
--- a/clients/tui/nmt-connect-connection-list.c
+++ b/clients/tui/nmt-connect-connection-list.c
@@ -80,7 +80,7 @@ nmt_connect_connection_free (NmtConnectConnection *nmtconn)
 static void
 nmt_connect_device_free (NmtConnectDevice *nmtdev)
 {
-	g_clear_pointer (&nmtdev->name, g_free);
+	nm_clear_g_free (&nmtdev->name);
 	g_clear_object (&nmtdev->device);
 
 	g_slist_free_full (nmtdev->conns, (GDestroyNotify) nmt_connect_connection_free);
diff --git a/clients/tui/nmt-device-entry.c b/clients/tui/nmt-device-entry.c
index 4ab59329..264bd59d 100644
--- a/clients/tui/nmt-device-entry.c
+++ b/clients/tui/nmt-device-entry.c
@@ -299,7 +299,7 @@ nmt_device_entry_set_mac_address (NmtDeviceEntry *deventry,
 		priv->mac_address = g_strdup (mac_address);
 		changed = TRUE;
 	} else if (!mac_address && priv->mac_address) {
-		g_clear_pointer (&priv->mac_address, g_free);
+		nm_clear_g_free (&priv->mac_address);
 		changed = TRUE;
 	} else if (   mac_address && priv->mac_address
 	           && !nm_utils_hwaddr_matches (mac_address, -1, priv->mac_address, -1)) {
diff --git a/clients/tui/nmt-editor-grid.c b/clients/tui/nmt-editor-grid.c
index a8ceedda..ac00c82b 100644
--- a/clients/tui/nmt-editor-grid.c
+++ b/clients/tui/nmt-editor-grid.c
@@ -77,7 +77,7 @@ nmt_editor_grid_finalize (GObject *object)
 	NmtEditorGridPrivate *priv = NMT_EDITOR_GRID_GET_PRIVATE (object);
 
 	g_array_unref (priv->rows);
-	g_clear_pointer (&priv->row_heights, g_free);
+	nm_clear_g_free (&priv->row_heights);
 
 	G_OBJECT_CLASS (nmt_editor_grid_parent_class)->finalize (object);
 }
diff --git a/clients/tui/nmt-page-team-port.c b/clients/tui/nmt-page-team-port.c
index c91633e8..dfefd80c 100644
--- a/clients/tui/nmt-page-team-port.c
+++ b/clients/tui/nmt-page-team-port.c
@@ -50,7 +50,7 @@ edit_clicked (NmtNewtButton *button,
 	new_config = nmt_newt_edit_string (config);
 
 	if (new_config && !*new_config)
-		g_clear_pointer (&new_config, g_free);
+		nm_clear_g_free (&new_config);
 	g_object_set (G_OBJECT (priv->s_port),
 	              NM_SETTING_TEAM_PORT_CONFIG, new_config,
 	              NULL);
diff --git a/clients/tui/nmt-page-team.c b/clients/tui/nmt-page-team.c
index af84db4b..a3d9d53a 100644
--- a/clients/tui/nmt-page-team.c
+++ b/clients/tui/nmt-page-team.c
@@ -103,7 +103,7 @@ edit_clicked (NmtNewtButton *button,
 	new_config = nmt_newt_edit_string (config);
 
 	if (new_config && !*new_config)
-		g_clear_pointer (&new_config, g_free);
+		nm_clear_g_free (&new_config);
 	g_object_set (G_OBJECT (priv->s_team),
 	              NM_SETTING_TEAM_CONFIG, new_config,
 	              NULL);
diff --git a/clients/tui/nmt-page-wifi.c b/clients/tui/nmt-page-wifi.c
index 2e738ac6..9494423b 100644
--- a/clients/tui/nmt-page-wifi.c
+++ b/clients/tui/nmt-page-wifi.c
@@ -72,6 +72,7 @@ static NmtNewtPopupEntry wifi_security[] = {
 	{ N_("WEP 128-bit Passphrase"),            "wep-passphrase" },
 	{ N_("Dynamic WEP (802.1x)"),              "dynamic-wep" },
 	{ N_("LEAP"),                              "leap" },
+	{ N_("Enhanced Open (OWE)"),                     "owe" },
 	{ NULL, NULL }
 };
 
diff --git a/clients/tui/nmt-password-dialog.c b/clients/tui/nmt-password-dialog.c
index 009ab7ce..979a5c68 100644
--- a/clients/tui/nmt-password-dialog.c
+++ b/clients/tui/nmt-password-dialog.c
@@ -175,8 +175,8 @@ nmt_password_dialog_finalize (GObject *object)
 
 	g_free (priv->request_id);
 	g_free (priv->prompt);
-	g_clear_pointer (&priv->entries, g_ptr_array_unref);
-	g_clear_pointer (&priv->secrets, g_ptr_array_unref);
+	nm_clear_pointer (&priv->entries, g_ptr_array_unref);
+	nm_clear_pointer (&priv->secrets, g_ptr_array_unref);
 
 	G_OBJECT_CLASS (nmt_password_dialog_parent_class)->finalize (object);
 }
diff --git a/clients/tui/nmt-route-entry.c b/clients/tui/nmt-route-entry.c
index e0f6df4e..88d64fa3 100644
--- a/clients/tui/nmt-route-entry.c
+++ b/clients/tui/nmt-route-entry.c
@@ -148,7 +148,7 @@ nmt_route_entry_finalize (GObject *object)
 {
 	NmtRouteEntryPrivate *priv = NMT_ROUTE_ENTRY_GET_PRIVATE (object);
 
-	g_clear_pointer (&priv->route, nm_ip_route_unref);
+	nm_clear_pointer (&priv->route, nm_ip_route_unref);
 
 	G_OBJECT_CLASS (nmt_route_entry_parent_class)->finalize (object);
 }
diff --git a/clients/tui/nmtui.c b/clients/tui/nmtui.c
index e9d2ab50..a6ea6f7f 100644
--- a/clients/tui/nmtui.c
+++ b/clients/tui/nmtui.c
@@ -18,6 +18,8 @@
 #include <locale.h>
 #include <stdlib.h>
 
+#include "nm-libnm-aux/nm-libnm-aux.h"
+
 #include "nmt-newt.h"
 #include "nm-editor-bindings.h"
 
@@ -231,8 +233,11 @@ main (int argc, char **argv)
 
 	nm_editor_bindings_init ();
 
-	nm_client = nm_client_new (NULL, &error);
-	if (!nm_client) {
+	if (!nmc_client_new_waitsync (NULL,
+	                              &nm_client,
+	                              &error,
+	                              NM_CLIENT_INSTANCE_FLAGS, (guint) NM_CLIENT_INSTANCE_FLAGS_NO_AUTO_FETCH_PERMISSIONS,
+	                              NULL)) {
 		g_printerr (_("Could not contact NetworkManager: %s.\n"), error->message);
 		g_error_free (error);
 		exit (1);