about summary refs log tree commit diff
path: root/libnm
diff options
context:
space:
mode:
authorSebastien Bacher <seb128@ubuntu.com>2019-01-25 11:24:41 +0100
committerSebastien Bacher <seb128@ubuntu.com>2019-01-25 11:24:41 +0100
commitbbae86d3d2997a853ca0365e8eb7a3ca7489ee09 (patch)
tree1f7fa49b47ab13aea3effbe839559d221f6323b4 /libnm
parent404ebe62622150e77e311777dff8617eb974e834 (diff)
New upstream version 1.15.2
Diffstat (limited to 'libnm')
-rw-r--r--libnm/fake-typelib/meson.build6
-rwxr-xr-xlibnm/generate-plugin-docs.pl2
-rw-r--r--libnm/libnm.ver9
-rw-r--r--libnm/meson.build37
-rw-r--r--libnm/nm-active-connection.c7
-rw-r--r--libnm/nm-client.c151
-rw-r--r--libnm/nm-client.h15
-rw-r--r--libnm/nm-dbus-helpers.c2
-rw-r--r--libnm/nm-device-vxlan.c2
-rw-r--r--libnm/nm-device-wifi.c4
-rw-r--r--libnm/nm-device.c76
-rw-r--r--libnm/nm-device.h4
-rw-r--r--libnm/nm-libnm-utils.c2
-rw-r--r--libnm/nm-manager.c144
-rw-r--r--libnm/nm-manager.h17
-rw-r--r--libnm/nm-object.c2
-rw-r--r--libnm/nm-object.h2
-rw-r--r--libnm/nm-property-docs.xml22
-rw-r--r--libnm/nm-settings-docs-overrides.xml4
-rw-r--r--libnm/nm-settings-docs.xml26
-rw-r--r--libnm/nm-settings-ifcfg-rh-docs.xml2
-rw-r--r--libnm/nm-vpn-service-plugin.c80
-rw-r--r--libnm/tests/meson.build7
-rw-r--r--libnm/tests/test-general.c274
24 files changed, 776 insertions, 121 deletions
diff --git a/libnm/fake-typelib/meson.build b/libnm/fake-typelib/meson.build
index c0a779a2..cafe013a 100644
--- a/libnm/fake-typelib/meson.build
+++ b/libnm/fake-typelib/meson.build
@@ -2,7 +2,7 @@ g_ir_compiler = find_program('g-ir-compiler')
 
 girs = [
   'NetworkManager',
-  'NMClient'
+  'NMClient',
 ]
 
 resource_data = []
@@ -14,7 +14,7 @@ foreach gir: girs
     gir_typelib,
     input: gir + '.gir',
     output: gir_typelib,
-    command: [g_ir_compiler, '@INPUT@', '-o', '@OUTPUT@']
+    command: [g_ir_compiler, '@INPUT@', '-o', '@OUTPUT@'],
   )
 endforeach
 
@@ -26,5 +26,5 @@ sources += gnome.compile_resources(
   source_dir: '.',
   dependencies: resource_data,
   extra_args: '--manual-register',
-  export: true
+  export: true,
 )
diff --git a/libnm/generate-plugin-docs.pl b/libnm/generate-plugin-docs.pl
index e4963b7c..74e2126c 100755
--- a/libnm/generate-plugin-docs.pl
+++ b/libnm/generate-plugin-docs.pl
@@ -60,7 +60,7 @@ open $fo, '>', $output or die "Can't open $output: $!";
 # write XML header
 write_header();
 
-# write generated documenation for each setting
+# write generated documentation for each setting
 foreach my $c_file (@source_files) {
   my $setting_name = get_setting_name($c_file);
   if ($setting_name) {
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index 1f76dc0f..652e01eb 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -1444,3 +1444,12 @@ global:
 	nm_utils_sriov_vf_from_str;
 	nm_utils_sriov_vf_to_str;
 } libnm_1_12_0;
+
+libnm_1_16_0 {
+global:
+	nm_client_add_and_activate_connection2;
+	nm_client_add_and_activate_connection2_finish;
+	nm_device_get_connectivity;
+	nm_team_link_watcher_get_vlanid;
+	nm_team_link_watcher_new_arp_ping2;
+} libnm_1_14_0;
diff --git a/libnm/meson.build b/libnm/meson.build
index 62e3e9d7..2e44a6a4 100644
--- a/libnm/meson.build
+++ b/libnm/meson.build
@@ -4,7 +4,7 @@ sources = files('nm-libnm-utils.c')
 
 deps = [
   libnmdbus_dep,
-  shared_dep
+  shared_dep,
 ]
 
 cflags = [
@@ -22,7 +22,7 @@ libnm_utils = static_library(
   sources: sources,
   include_directories: libnm_core_inc,
   dependencies: deps,
-  c_args: cflags
+  c_args: cflags,
 )
 
 libnm_headers = files(
@@ -69,12 +69,12 @@ libnm_headers = files(
   'nm-vpn-editor.h',
   'nm-vpn-plugin-old.h',
   'nm-vpn-service-plugin.h',
-  'nm-wimax-nsp.h'
+  'nm-wimax-nsp.h',
 )
 
 install_headers(
   libnm_core_headers + libnm_headers + [version_header],
-  subdir: libnm_name
+  subdir: libnm_name,
 )
 
 enum_headers = libnm_headers + [version_header]
@@ -87,7 +87,7 @@ libnm_enum = gnome.mkenums(
   c_template: enum_types + '.c.template',
   h_template: enum_types + '.h.template',
   install_header: true,
-  install_dir: libnm_pkgincludedir
+  install_dir: libnm_pkgincludedir,
 )
 
 libnm_sources = files(
@@ -139,14 +139,15 @@ libnm_sources = files(
   'nm-vpn-plugin-old.c',
   'nm-vpn-editor.c',
   'nm-vpn-service-plugin.c',
-  'nm-wimax-nsp.c'
+  'nm-wimax-nsp.c',
 )
 
 deps = [
   dl_dep,
   libudev_dep,
   shared_dep,
-  uuid_dep
+  uuid_dep,
+  libnm_systemd_shared_no_logging_dep,
 ]
 
 linker_script = join_paths(meson.current_source_dir(), 'libnm.ver')
@@ -165,13 +166,13 @@ libnm = shared_library(
     '-Wl,--version-script,@0@'.format(linker_script),
   ],
   link_depends: linker_script,
-  install: true
+  install: true,
 )
 
 libnm_dep = declare_dependency(
   sources: libnm_enum[1],
   include_directories: libnm_inc,
-  link_with: libnm
+  link_with: libnm,
 )
 
 pkg.generate(
@@ -184,8 +185,8 @@ pkg.generate(
   requires: 'gio-2.0',
   variables: [
     'exec_prefix=${prefix}',
-    'vpnservicedir=' + join_paths(nm_pkglibdir, 'VPN')
-  ]
+    'vpnservicedir=' + join_paths('${prefix}', 'lib', nm_name, 'VPN'),
+  ],
 )
 
 test(
@@ -208,7 +209,7 @@ if enable_introspection
     includes: 'Gio-2.0',
     extra_args: cflags,
     header: 'NetworkManager.h',
-    install: true
+    install: true,
   )
 
   generate_plugin_docs = join_paths(meson.current_source_dir(), 'generate-plugin-docs.pl')
@@ -218,7 +219,7 @@ if enable_introspection
     name,
     input: libnm_core_settings_sources,
     output: name,
-    command: [perl, generate_plugin_docs, 'keyfile', '@OUTPUT@', '@INPUT@']
+    command: [perl, generate_plugin_docs, 'keyfile', '@OUTPUT@', '@INPUT@'],
   )
 
   name = 'nm-settings-docs-overrides.xml'
@@ -226,7 +227,7 @@ if enable_introspection
     name,
     input: libnm_core_settings_sources,
     output: name,
-    command: [perl, generate_plugin_docs, 'dbus', '@OUTPUT@', '@INPUT@']
+    command: [perl, generate_plugin_docs, 'dbus', '@OUTPUT@', '@INPUT@'],
   )
 
   if enable_ifcfg_rh
@@ -235,7 +236,7 @@ if enable_introspection
       name,
       input: libnm_core_settings_sources,
       output: name,
-      command: [perl, generate_plugin_docs, 'ifcfg-rh', '@OUTPUT@', '@INPUT@']
+      command: [perl, generate_plugin_docs, 'ifcfg-rh', '@OUTPUT@', '@INPUT@'],
     )
   endif
 
@@ -256,7 +257,7 @@ if enable_introspection
   generate_setting_docs_env = [
     'env', '-i',
     'GI_TYPELIB_PATH=' + gi_typelib_path,
-    'LD_LIBRARY_PATH=' + ld_library_path
+    'LD_LIBRARY_PATH=' + ld_library_path,
   ]
 
   name = 'nm-property-docs.xml'
@@ -265,7 +266,7 @@ if enable_introspection
     input: libnm_gir[0],
     output: name,
     command: [generate_setting_docs_env, generate_setting_docs, '--lib-path', meson.current_build_dir(), '--gir', '@INPUT@', '--output', '@OUTPUT@'],
-    depends: libnm_gir
+    depends: libnm_gir,
   )
 
   name = 'nm-settings-docs.xml'
@@ -274,7 +275,7 @@ if enable_introspection
     input: libnm_gir[0],
     output: name,
     command: [generate_setting_docs_env, generate_setting_docs, '--lib-path', meson.current_build_dir(), '--gir', '@INPUT@', '--overrides', nm_settings_docs_overrides, '--output', '@OUTPUT@'],
-    depends: libnm_gir
+    depends: libnm_gir,
   )
 endif
 
diff --git a/libnm/nm-active-connection.c b/libnm/nm-active-connection.c
index 0314667f..5b238b3b 100644
--- a/libnm/nm-active-connection.c
+++ b/libnm/nm-active-connection.c
@@ -795,7 +795,12 @@ nm_active_connection_class_init (NMActiveConnectionClass *ap_class)
 		                      G_PARAM_READABLE |
 		                      G_PARAM_STATIC_STRINGS));
 
-	/* signals */
+	/**
+	 * NMActiveConnection::state-changed:
+	 * @active_connection: the source #NMActiveConnection
+	 * @state: the new state number (#NMActiveConnectionState)
+	 * @reason: the state change reason (#NMActiveConnectionStateReason)
+	 */
 	signals[STATE_CHANGED] =
 		g_signal_new ("state-changed",
 		              G_OBJECT_CLASS_TYPE (object_class),
diff --git a/libnm/nm-client.c b/libnm/nm-client.c
index 1da22540..e2522229 100644
--- a/libnm/nm-client.c
+++ b/libnm/nm-client.c
@@ -1163,18 +1163,20 @@ add_activate_cb (GObject *object,
                  GAsyncResult *result,
                  gpointer user_data)
 {
-	GSimpleAsyncResult *simple = user_data;
+	gs_unref_object GSimpleAsyncResult *simple = user_data;
+	gs_unref_variant GVariant *result_data = NULL;
 	NMActiveConnection *ac;
 	GError *error = NULL;
 
-	ac = nm_manager_add_and_activate_connection_finish (NM_MANAGER (object), result, &error);
-	if (ac)
-		g_simple_async_result_set_op_res_gpointer (simple, ac, g_object_unref);
-	else
+	ac = nm_manager_add_and_activate_connection_finish (NM_MANAGER (object), result, &result_data, &error);
+	if (ac) {
+		g_simple_async_result_set_op_res_gpointer (simple,
+		                                           _nm_activate_result_new (ac, result_data),
+		                                           (GDestroyNotify) _nm_activate_result_free);
+	} else
 		g_simple_async_result_take_error (simple, error);
 
 	g_simple_async_result_complete (simple);
-	g_object_unref (simple);
 }
 
 /**
@@ -1233,8 +1235,14 @@ nm_client_add_and_activate_connection_async (NMClient *client,
 	if (cancellable)
 		g_simple_async_result_set_check_cancellable (simple, cancellable);
 	nm_manager_add_and_activate_connection_async (NM_CLIENT_GET_PRIVATE (client)->manager,
-	                                              partial, device, specific_object,
-	                                              cancellable, add_activate_cb, simple);
+	                                              partial,
+	                                              device,
+	                                              specific_object,
+	                                              NULL,
+	                                              FALSE,
+	                                              cancellable,
+	                                              add_activate_cb,
+	                                              simple);
 }
 
 /**
@@ -1257,6 +1265,7 @@ nm_client_add_and_activate_connection_finish (NMClient *client,
                                               GError **error)
 {
 	GSimpleAsyncResult *simple;
+	_NMActivateResult *r;
 
 	g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
 	g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
@@ -1264,8 +1273,128 @@ nm_client_add_and_activate_connection_finish (NMClient *client,
 	simple = G_SIMPLE_ASYNC_RESULT (result);
 	if (g_simple_async_result_propagate_error (simple, error))
 		return NULL;
-	else
-		return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+	r = g_simple_async_result_get_op_res_gpointer (simple);
+	return g_object_ref (r->active);
+}
+
+/**
+ * nm_client_add_and_activate_connection2:
+ * @client: a #NMClient
+ * @partial: (allow-none): an #NMConnection to add; the connection may be
+ *   partially filled (or even %NULL) and will be completed by NetworkManager
+ *   using the given @device and @specific_object before being added
+ * @device: the #NMDevice
+ * @specific_object: (allow-none): the object path of a connection-type-specific
+ *   object this activation should use. This parameter is currently ignored for
+ *   wired and mobile broadband connections, and the value of %NULL should be used
+ *   (ie, no specific object).  For Wi-Fi or WiMAX connections, pass the object
+ *   path of a #NMAccessPoint or #NMWimaxNsp owned by @device, which you can
+ *   get using nm_object_get_path(), and which will be used to complete the
+ *   details of the newly added connection.
+ * @options: a #GVariant containing a dictionary with options, or %NULL
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: callback to be called when the activation has started
+ * @user_data: caller-specific data passed to @callback
+ *
+ * Adds a new connection using the given details (if any) as a template,
+ * automatically filling in missing settings with the capabilities of the given
+ * device and specific object.  The new connection is then asynchronously
+ * activated as with nm_client_activate_connection_async(). Cannot be used for
+ * VPN connections at this time.
+ *
+ * Note that the callback is invoked when NetworkManager has started activating
+ * the new connection, not when it finishes. You can used the returned
+ * #NMActiveConnection object (in particular, #NMActiveConnection:state) to
+ * track the activation to its completion.
+ *
+ * This is identitcal to nm_client_add_and_activate_connection_async() but takes
+ * a further @options parameter. Currently the following options are supported
+ * by the daemon:
+ *  * "persist": A string describing how the connection should be stored.
+ *               The default is "disk", but it can be modified to "memory" (until
+ *               the daemon quits) or "volatile" (will be deleted on disconnect).
+ *  * "bind-activation": Bind the connection lifetime to something. The default is "none",
+ *            meaning an explicit disconnect is needed. The value "dbus-client"
+ *            means the connection will automatically be deactivated when the calling
+ *            DBus client disappears from the system bus.
+ *
+ * Since: 1.16
+ **/
+void
+nm_client_add_and_activate_connection2 (NMClient *client,
+                                        NMConnection *partial,
+                                        NMDevice *device,
+                                        const char *specific_object,
+                                        GVariant *options,
+                                        GCancellable *cancellable,
+                                        GAsyncReadyCallback callback,
+                                        gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	GError *error = NULL;
+
+	g_return_if_fail (NM_IS_CLIENT (client));
+	g_return_if_fail (NM_IS_DEVICE (device));
+	if (partial)
+		g_return_if_fail (NM_IS_CONNECTION (partial));
+
+	if (!_nm_client_check_nm_running (client, &error)) {
+		g_simple_async_report_take_gerror_in_idle (G_OBJECT (client), callback, user_data, error);
+		return;
+	}
+
+	simple = g_simple_async_result_new (G_OBJECT (client), callback, user_data,
+	                                    nm_client_add_and_activate_connection2);
+	if (cancellable)
+		g_simple_async_result_set_check_cancellable (simple, cancellable);
+	nm_manager_add_and_activate_connection_async (NM_CLIENT_GET_PRIVATE (client)->manager,
+	                                              partial,
+	                                              device,
+	                                              specific_object,
+	                                              options,
+	                                              TRUE,
+	                                              cancellable,
+	                                              add_activate_cb,
+	                                              simple);
+}
+
+/**
+ * nm_client_add_and_activate_connection2_finish:
+ * @client: an #NMClient
+ * @result: the result passed to the #GAsyncReadyCallback
+ * @error: location for a #GError, or %NULL
+ * @out_result: (allow-none): (transfer full): the output result
+ *   of type "a{sv}" returned by D-Bus' AddAndActivate2 call. Currently no
+ *   output is implemented yet.
+ *
+ * Gets the result of a call to nm_client_add_and_activate_connection2().
+ *
+ * You can call nm_active_connection_get_connection() on the returned
+ * #NMActiveConnection to find the path of the created #NMConnection.
+ *
+ * Returns: (transfer full): the new #NMActiveConnection on success, %NULL on
+ *   failure, in which case @error will be set.
+ **/
+NMActiveConnection *
+nm_client_add_and_activate_connection2_finish (NMClient *client,
+                                               GAsyncResult *result,
+                                               GVariant **out_result,
+                                               GError **error)
+{
+	GSimpleAsyncResult *simple;
+	_NMActivateResult *r;
+
+	g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+	g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	if (g_simple_async_result_propagate_error (simple, error)) {
+		NM_SET_OUT (out_result, NULL);
+		return NULL;
+	}
+	r = g_simple_async_result_get_op_res_gpointer (simple);
+	NM_SET_OUT (out_result, nm_g_variant_ref (r->add_and_activate_output));
+	return g_object_ref (r->active);
 }
 
 /**
@@ -2470,7 +2599,7 @@ proxy_type (GDBusObjectManagerClient *manager,
             const char *interface_name,
             gpointer user_data)
 {
-	/* ObjectManager asks us for an object proxy. Unfortunatelly, we can't
+	/* ObjectManager asks us for an object proxy. Unfortunately, we can't
 	 * decide that by interface name and GDBusObjectManager doesn't allow
 	 * us to look at the known interface list. Thus we need to create a
 	 * generic GDBusObject and only couple a NMObject subclass later. */
diff --git a/libnm/nm-client.h b/libnm/nm-client.h
index 6259b122..97363ef7 100644
--- a/libnm/nm-client.h
+++ b/libnm/nm-client.h
@@ -339,6 +339,21 @@ NMActiveConnection *nm_client_add_and_activate_connection_finish (NMClient *clie
                                                                   GAsyncResult *result,
                                                                   GError **error);
 
+NM_AVAILABLE_IN_1_16
+void                nm_client_add_and_activate_connection2 (NMClient *client,
+                                                            NMConnection *partial,
+                                                            NMDevice *device,
+                                                            const char *specific_object,
+                                                            GVariant *options,
+                                                            GCancellable *cancellable,
+                                                            GAsyncReadyCallback callback,
+                                                            gpointer user_data);
+NM_AVAILABLE_IN_1_16
+NMActiveConnection *nm_client_add_and_activate_connection2_finish (NMClient *client,
+                                                                   GAsyncResult *result,
+                                                                   GVariant **out_result,
+                                                                   GError **error);
+
 gboolean nm_client_deactivate_connection        (NMClient *client,
                                                  NMActiveConnection *active,
                                                  GCancellable *cancellable,
diff --git a/libnm/nm-dbus-helpers.c b/libnm/nm-dbus-helpers.c
index 33c68191..44eed0c8 100644
--- a/libnm/nm-dbus-helpers.c
+++ b/libnm/nm-dbus-helpers.c
@@ -105,7 +105,7 @@ _nm_dbus_is_connection_private (GDBusConnection *connection)
  * rule the proxy added and ensure a less granular rule is present instead.
  *
  * Also, don't do this immediately since it has a performance penalty.
- * Still better than loosing the signals altogether.
+ * Still better than losing the signals altogether.
  *
  * Ideally, we should be able to tell glib not to hook its rules:
  * https://bugzilla.gnome.org/show_bug.cgi?id=758749
diff --git a/libnm/nm-device-vxlan.c b/libnm/nm-device-vxlan.c
index 27b9c981..9a87ad13 100644
--- a/libnm/nm-device-vxlan.c
+++ b/libnm/nm-device-vxlan.c
@@ -361,7 +361,7 @@ nm_device_vxlan_get_l2miss (NMDeviceVxlan *device)
  * nm_device_vxlan_get_l3miss:
  * @device: a #NMDeviceVxlan
  *
- * Returns: wether netlink IP ADDR miss notifications are generated
+ * Returns: whether netlink IP ADDR miss notifications are generated
  *
  * Since: 1.2
  **/
diff --git a/libnm/nm-device-wifi.c b/libnm/nm-device-wifi.c
index 848e297c..9fb1eebf 100644
--- a/libnm/nm-device-wifi.c
+++ b/libnm/nm-device-wifi.c
@@ -370,7 +370,7 @@ nm_device_wifi_request_scan (NMDeviceWifi *device,
  * after that for the scan to complete.
  * This is the same as @nm_device_wifi_request_scan except it accepts @options
  * for the scanning. The argument is the dictionary passed to RequestScan()
- * D-Bus call. Valid otions inside the dictionary are:
+ * D-Bus call. Valid options inside the dictionary are:
  * 'ssids' => array of SSIDs (saay)
  *
  * Returns: %TRUE on success, %FALSE on error, in which case @error will be
@@ -487,7 +487,7 @@ nm_device_wifi_request_scan_async (NMDeviceWifi *device,
  * that for the scan to complete.
  * This is the same as @nm_device_wifi_request_scan_async except it accepts @options
  * for the scanning. The argument is the dictionary passed to RequestScan()
- * D-Bus call. Valid otions inside the dictionary are:
+ * D-Bus call. Valid options inside the dictionary are:
  * 'ssids' => array of SSIDs (saay)
  *
  * Since: 1.2
diff --git a/libnm/nm-device.c b/libnm/nm-device.c
index 3f1cc636..4bcd7c6c 100644
--- a/libnm/nm-device.c
+++ b/libnm/nm-device.c
@@ -74,6 +74,8 @@ typedef struct {
 	NMDhcpConfig *dhcp4_config;
 	NMIPConfig *ip6_config;
 	NMDhcpConfig *dhcp6_config;
+	NMConnectivityState ip4_connectivity;
+	NMConnectivityState ip6_connectivity;
 	NMDeviceState state;
 	NMDeviceState last_seen_state;
 	NMDeviceStateReason reason;
@@ -120,6 +122,8 @@ enum {
 	PROP_MTU,
 	PROP_METERED,
 	PROP_LLDP_NEIGHBORS,
+	PROP_IP4_CONNECTIVITY,
+	PROP_IP6_CONNECTIVITY,
 
 	LAST_PROP
 };
@@ -144,6 +148,8 @@ nm_device_init (NMDevice *device)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
 
+	priv->ip4_connectivity = NM_CONNECTIVITY_UNKNOWN;
+	priv->ip6_connectivity = NM_CONNECTIVITY_UNKNOWN;
 	priv->state = NM_DEVICE_STATE_UNKNOWN;
 	priv->reason = NM_DEVICE_STATE_REASON_NONE;
 	priv->lldp_neighbors = g_ptr_array_new ();
@@ -216,6 +222,8 @@ init_dbus (NMObject *object)
 		{ NM_DEVICE_DHCP4_CONFIG,      &priv->dhcp4_config, NULL, NM_TYPE_DHCP4_CONFIG },
 		{ NM_DEVICE_IP6_CONFIG,        &priv->ip6_config, NULL, NM_TYPE_IP6_CONFIG },
 		{ NM_DEVICE_DHCP6_CONFIG,      &priv->dhcp6_config, NULL, NM_TYPE_DHCP6_CONFIG },
+		{ NM_DEVICE_IP4_CONNECTIVITY,  &priv->ip4_connectivity },
+		{ NM_DEVICE_IP6_CONNECTIVITY,  &priv->ip6_connectivity },
 		{ NM_DEVICE_STATE,             &priv->state },
 		{ NM_DEVICE_STATE_REASON,      &priv->reason, demarshal_state_reason },
 		{ NM_DEVICE_ACTIVE_CONNECTION, &priv->active_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
@@ -428,6 +436,12 @@ get_property (GObject *object,
 	case PROP_LLDP_NEIGHBORS:
 		g_value_set_boxed (value, nm_device_get_lldp_neighbors (device));
 		break;
+	case PROP_IP4_CONNECTIVITY:
+		g_value_set_enum (value, nm_device_get_connectivity (device, AF_INET));
+		break;
+	case PROP_IP6_CONNECTIVITY:
+		g_value_set_enum (value, nm_device_get_connectivity (device, AF_INET6));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -701,6 +715,36 @@ nm_device_class_init (NMDeviceClass *device_class)
 		                      G_PARAM_STATIC_STRINGS));
 
 	/**
+	 * NMDevice:ip4-connectivity:
+	 *
+	 * The IPv4 connectivity state of the device.
+	 *
+	 * Since: 1.16
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_IP4_CONNECTIVITY,
+		 g_param_spec_enum (NM_DEVICE_IP4_CONNECTIVITY, "", "",
+		                    NM_TYPE_CONNECTIVITY_STATE,
+		                    NM_CONNECTIVITY_UNKNOWN,
+		                    G_PARAM_READABLE |
+		                    G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * NMDevice:ip6-connectivity:
+	 *
+	 * The IPv6 connectivity state of the device.
+	 *
+	 * Since: 1.16
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_IP6_CONNECTIVITY,
+		 g_param_spec_enum (NM_DEVICE_IP6_CONNECTIVITY, "", "",
+		                    NM_TYPE_CONNECTIVITY_STATE,
+		                    NM_CONNECTIVITY_UNKNOWN,
+		                    G_PARAM_READABLE |
+		                    G_PARAM_STATIC_STRINGS));
+
+	/**
 	 * NMDevice:state:
 	 *
 	 * The state of the device.
@@ -1231,6 +1275,36 @@ nm_device_get_dhcp6_config (NMDevice *device)
 }
 
 /**
+ * nm_device_get_connectivity:
+ * @device: a #NMDevice
+ * @addr_family: network address family
+ *
+ * The connectivity state of the device for given address family.
+ * Supported address families are %AF_INET for IPv4, %AF_INET6
+ * for IPv6 or %AF_UNSPEC for any.
+ *
+ * Returns: the current connectivity state
+ *
+ * Since: 1.16
+ **/
+NMConnectivityState
+nm_device_get_connectivity (NMDevice *device, int addr_family)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
+
+	switch (addr_family) {
+	case AF_INET:
+		return priv->ip4_connectivity;
+	case AF_INET6:
+		return priv->ip6_connectivity;
+	case AF_UNSPEC:
+		return NM_MAX (priv->ip4_connectivity, priv->ip6_connectivity);
+	default:
+		g_return_val_if_reached (NM_CONNECTIVITY_UNKNOWN);
+	}
+}
+
+/**
  * nm_device_get_state:
  * @device: a #NMDevice
  *
@@ -2392,7 +2466,7 @@ device_delete_cb (GObject *proxy,
  * @callback: callback to be called when delete operation completes
  * @user_data: caller-specific data passed to @callback
  *
- * Asynchronously begins deleteing the software device. Hardware devices can't
+ * Asynchronously begins deleting the software device. Hardware devices can't
  * be deleted.
  **/
 void
diff --git a/libnm/nm-device.h b/libnm/nm-device.h
index 91f31b87..fcda93ab 100644
--- a/libnm/nm-device.h
+++ b/libnm/nm-device.h
@@ -64,6 +64,8 @@ G_BEGIN_DECLS
 #define NM_DEVICE_MTU "mtu"
 #define NM_DEVICE_METERED "metered"
 #define NM_DEVICE_LLDP_NEIGHBORS "lldp-neighbors"
+#define NM_DEVICE_IP4_CONNECTIVITY "ip4-connectivity"
+#define NM_DEVICE_IP6_CONNECTIVITY "ip6-connectivity"
 
 /**
  * NMDevice:
@@ -121,6 +123,8 @@ NMIPConfig *         nm_device_get_ip4_config       (NMDevice *device);
 NMDhcpConfig *       nm_device_get_dhcp4_config     (NMDevice *device);
 NMIPConfig *         nm_device_get_ip6_config       (NMDevice *device);
 NMDhcpConfig *       nm_device_get_dhcp6_config     (NMDevice *device);
+NM_AVAILABLE_IN_1_16
+NMConnectivityState  nm_device_get_connectivity     (NMDevice *device, int addr_family);
 NMDeviceState        nm_device_get_state            (NMDevice *device);
 NMDeviceStateReason  nm_device_get_state_reason     (NMDevice *device);
 NMActiveConnection * nm_device_get_active_connection(NMDevice *device);
diff --git a/libnm/nm-libnm-utils.c b/libnm/nm-libnm-utils.c
index 36219065..f740c37c 100644
--- a/libnm/nm-libnm-utils.c
+++ b/libnm/nm-libnm-utils.c
@@ -125,7 +125,7 @@ next:
 	}
 	if (square_brackets_sensible) {
 		/* If there's a [<string>] that survived the substitution, then the string
-		 * is a short form that is generally preferrable. */
+		 * is a short form that is generally preferable. */
 		q = strchr (desc_full, ']');
 		if (p && q > p) {
 			p++;
diff --git a/libnm/nm-manager.c b/libnm/nm-manager.c
index a5425127..3254d4a0 100644
--- a/libnm/nm-manager.c
+++ b/libnm/nm-manager.c
@@ -870,16 +870,49 @@ nm_manager_get_activating_connection (NMManager *manager)
 	return NM_MANAGER_GET_PRIVATE (manager)->activating_connection;
 }
 
+typedef enum {
+	ACTIVATE_TYPE_ACTIVATE_CONNECTION,
+	ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION,
+	ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION2,
+} ActivateType;
+
 typedef struct {
 	CList lst;
 	NMManager *manager;
 	GSimpleAsyncResult *simple;
 	GCancellable *cancellable;
-	gulong cancelled_id;
 	char *active_path;
 	char *new_connection_path;
+	GVariant *add_and_activate_output;
+	gulong cancelled_id;
+	ActivateType activate_type;
 } ActivateInfo;
 
+_NMActivateResult *
+_nm_activate_result_new (NMActiveConnection *active,
+                         GVariant *add_and_activate_output)
+{
+	_NMActivateResult *r;
+
+	nm_assert (!add_and_activate_output || g_variant_is_of_type (add_and_activate_output, G_VARIANT_TYPE ("a{sv}")));
+	nm_assert (!add_and_activate_output || !g_variant_is_floating (add_and_activate_output));
+
+	r = g_slice_new (_NMActivateResult);
+	*r = (_NMActivateResult) {
+		.active                  = g_object_ref (active),
+		.add_and_activate_output = nm_g_variant_ref (add_and_activate_output),
+	};
+	return r;
+}
+
+void
+_nm_activate_result_free (_NMActivateResult *result)
+{
+	g_object_unref (result->active);
+	nm_g_variant_unref (result->add_and_activate_output);
+	g_slice_free (_NMActivateResult, result);
+}
+
 static void
 activate_info_complete (ActivateInfo *info,
                         NMActiveConnection *active,
@@ -889,12 +922,17 @@ activate_info_complete (ActivateInfo *info,
 
 	c_list_unlink_stale (&info->lst);
 
-	if (active)
-		g_simple_async_result_set_op_res_gpointer (info->simple, g_object_ref (active), g_object_unref);
-	else
+	if (active) {
+		g_simple_async_result_set_op_res_gpointer (info->simple,
+		                                           _nm_activate_result_new (active,
+		                                                                    info->add_and_activate_output),
+		                                           (GDestroyNotify) _nm_activate_result_free);
+	} else
 		g_simple_async_result_set_from_error (info->simple, error);
+
 	g_simple_async_result_complete (info->simple);
 
+	nm_g_variant_unref (info->add_and_activate_output);
 	g_free (info->active_path);
 	g_free (info->new_connection_path);
 	g_object_unref (info->simple);
@@ -1035,6 +1073,7 @@ nm_manager_activate_connection_async (NMManager *manager,
 	priv = NM_MANAGER_GET_PRIVATE (manager);
 
 	info = g_slice_new0 (ActivateInfo);
+	info->activate_type = ACTIVATE_TYPE_ACTIVATE_CONNECTION;
 	info->manager = manager;
 	info->simple = g_simple_async_result_new (G_OBJECT (manager), callback, user_data,
 	                                          nm_manager_activate_connection_async);
@@ -1058,14 +1097,16 @@ nm_manager_activate_connection_finish (NMManager *manager,
                                        GError **error)
 {
 	GSimpleAsyncResult *simple;
+	_NMActivateResult *r;
 
 	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (manager), nm_manager_activate_connection_async), NULL);
 
 	simple = G_SIMPLE_ASYNC_RESULT (result);
 	if (g_simple_async_result_propagate_error (simple, error))
 		return NULL;
-	else
-		return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+
+	r = g_simple_async_result_get_op_res_gpointer (simple);
+	return g_object_ref (r->active);
 }
 
 static void
@@ -1074,23 +1115,35 @@ add_activate_cb (GObject *object,
                  gpointer user_data)
 {
 	ActivateInfo *info = user_data;
-	GError *error = NULL;
-
-	if (nmdbus_manager_call_add_and_activate_connection_finish (NMDBUS_MANAGER (object),
-	                                                            NULL,
-	                                                            &info->active_path,
-	                                                            result, &error)) {
-		if (info->cancellable) {
-			info->cancelled_id = g_signal_connect (info->cancellable, "cancelled",
-			                                       G_CALLBACK (activation_cancelled), info);
-		}
-
-		recheck_pending_activations (info->manager);
+	gs_free_error GError *error = NULL;
+	gboolean success;
+
+	if (info->activate_type == ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION) {
+		success = nmdbus_manager_call_add_and_activate_connection_finish (NMDBUS_MANAGER (object),
+		                                                                  NULL,
+		                                                                  &info->active_path,
+		                                                                  result,
+		                                                                  &error);
 	} else {
+		success = nmdbus_manager_call_add_and_activate_connection2_finish (NMDBUS_MANAGER (object),
+		                                                                   NULL,
+		                                                                   &info->active_path,
+		                                                                   &info->add_and_activate_output,
+		                                                                   result,
+		                                                                   &error);
+	}
+	if (!success) {
 		g_dbus_error_strip_remote_error (error);
 		activate_info_complete (info, NULL, error);
-		g_clear_error (&error);
+		return;
+	}
+
+	if (info->cancellable) {
+		info->cancelled_id = g_signal_connect (info->cancellable, "cancelled",
+		                                       G_CALLBACK (activation_cancelled), info);
 	}
+
+	recheck_pending_activations (info->manager);
 }
 
 void
@@ -1098,6 +1151,8 @@ nm_manager_add_and_activate_connection_async (NMManager *manager,
                                               NMConnection *partial,
                                               NMDevice *device,
                                               const char *specific_object,
+                                              GVariant *options,
+                                              gboolean force_v2,
                                               GCancellable *cancellable,
                                               GAsyncReadyCallback callback,
                                               gpointer user_data)
@@ -1105,6 +1160,7 @@ nm_manager_add_and_activate_connection_async (NMManager *manager,
 	NMManagerPrivate *priv;
 	GVariant *dict = NULL;
 	ActivateInfo *info;
+	ActivateType activate_type = ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION;
 
 	g_return_if_fail (NM_IS_MANAGER (manager));
 	g_return_if_fail (NM_IS_DEVICE (device));
@@ -1127,29 +1183,61 @@ nm_manager_add_and_activate_connection_async (NMManager *manager,
 		dict = nm_connection_to_dbus (partial, NM_CONNECTION_SERIALIZE_ALL);
 	if (!dict)
 		dict = g_variant_new_array (G_VARIANT_TYPE ("{sa{sv}}"), NULL, 0);
+	if (force_v2) {
+		if (!options)
+			options = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0);
+		activate_type = ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION2;
+	} else {
+		if (options) {
+			if (g_variant_n_children (options) > 0)
+				activate_type = ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION2;
+			else
+				nm_g_variant_unref_floating (options);
+		}
+	}
 
-	nmdbus_manager_call_add_and_activate_connection (priv->proxy,
-	                                                 dict,
-	                                                 nm_object_get_path (NM_OBJECT (device)),
-	                                                 specific_object ?: "/",
-	                                                 cancellable,
-	                                                 add_activate_cb, info);
+	info->activate_type = activate_type;
+
+	if (activate_type == ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION2) {
+		nmdbus_manager_call_add_and_activate_connection2 (priv->proxy,
+		                                                  dict,
+		                                                  nm_object_get_path (NM_OBJECT (device)),
+		                                                  specific_object ?: "/",
+		                                                  options,
+		                                                  cancellable,
+		                                                  add_activate_cb,
+		                                                  info);
+	} else {
+		nmdbus_manager_call_add_and_activate_connection (priv->proxy,
+		                                                  dict,
+		                                                  nm_object_get_path (NM_OBJECT (device)),
+		                                                  specific_object ?: "/",
+		                                                  cancellable,
+		                                                  add_activate_cb,
+		                                                  info);
+	}
 }
 
 NMActiveConnection *
 nm_manager_add_and_activate_connection_finish (NMManager *manager,
                                                GAsyncResult *result,
+                                               GVariant **out_result,
                                                GError **error)
 {
 	GSimpleAsyncResult *simple;
+	_NMActivateResult *r;
 
 	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (manager), nm_manager_add_and_activate_connection_async), NULL);
 
 	simple = G_SIMPLE_ASYNC_RESULT (result);
-	if (g_simple_async_result_propagate_error (simple, error))
+	if (g_simple_async_result_propagate_error (simple, error)) {
+		NM_SET_OUT (out_result, NULL);
 		return NULL;
-	else
-		return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+	}
+
+	r = g_simple_async_result_get_op_res_gpointer (simple);
+	NM_SET_OUT (out_result, nm_g_variant_ref (r->add_and_activate_output));
+	return g_object_ref (r->active);
 }
 
 static void
diff --git a/libnm/nm-manager.h b/libnm/nm-manager.h
index 0a278aee..04e12eb3 100644
--- a/libnm/nm-manager.h
+++ b/libnm/nm-manager.h
@@ -163,11 +163,14 @@ void                nm_manager_add_and_activate_connection_async  (NMManager *ma
                                                                    NMConnection *partial,
                                                                    NMDevice *device,
                                                                    const char *specific_object,
+                                                                   GVariant *options,
+                                                                   gboolean force_v2,
                                                                    GCancellable *cancellable,
                                                                    GAsyncReadyCallback callback,
                                                                    gpointer user_data);
 NMActiveConnection *nm_manager_add_and_activate_connection_finish (NMManager *manager,
                                                                    GAsyncResult *result,
+                                                                   GVariant **out_result,
                                                                    GError **error);
 
 gboolean nm_manager_deactivate_connection        (NMManager *manager,
@@ -220,4 +223,18 @@ gboolean nm_manager_checkpoint_adjust_rollback_timeout_finish (NMManager *manage
                                                                GAsyncResult *result,
                                                                GError **error);
 
+/*****************************************************************************/
+
+typedef struct {
+	NMActiveConnection *active;
+	GVariant *add_and_activate_output;
+} _NMActivateResult;
+
+_NMActivateResult *_nm_activate_result_new (NMActiveConnection *active,
+                                            GVariant *add_and_activate_output);
+
+void _nm_activate_result_free (_NMActivateResult *result);
+
+/*****************************************************************************/
+
 #endif /* __NM_MANAGER_H__ */
diff --git a/libnm/nm-object.c b/libnm/nm-object.c
index 70f90b63..d2ae25aa 100644
--- a/libnm/nm-object.c
+++ b/libnm/nm-object.c
@@ -612,7 +612,7 @@ handle_object_property (NMObject *self, const char *property_name, GVariant *val
 		 *
 		 * NOTE: We've ignored this before and the server hits the condition
 		 * more often that it should. Given we're able to recover from
-		 * ther error, let's lower the severity of the log message to
+		 * the error, let's lower the severity of the log message to
 		 * avoid unnecessarily bothering the user. This can be removed
 		 * once the issue is fixed on the server. */
 #if NM_MORE_ASSERTS
diff --git a/libnm/nm-object.h b/libnm/nm-object.h
index 5b4580eb..1cc61a73 100644
--- a/libnm/nm-object.h
+++ b/libnm/nm-object.h
@@ -57,7 +57,7 @@ typedef struct {
 
 	/* The "object-creation-failed" method is PRIVATE for libnm and
 	 * is not meant for any external usage.  It indicates that an error
-	 * occured during creation of an object.
+	 * occurred during creation of an object.
 	 */
 	void (*object_creation_failed) (NMObject *master_object,
 	                                const char *failed_path);
diff --git a/libnm/nm-property-docs.xml b/libnm/nm-property-docs.xml
index 22aed0ea..31bceefb 100644
--- a/libnm/nm-property-docs.xml
+++ b/libnm/nm-property-docs.xml
@@ -22,7 +22,7 @@
     <property name="read-only" name_upper="READ_ONLY" type="boolean" default="FALSE" description="FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified." />
     <property name="secondaries" name_upper="SECONDARIES" type="array of string" default="[]" description="List of connection UUIDs that should be activated when the base connection itself is activated. Currently only VPN connections are supported." />
     <property name="slave-type" name_upper="SLAVE_TYPE" type="string" description="Setting name of the device type of this slave's master connection (eg, &quot;bond&quot;), or NULL if this connection is not a slave." />
-    <property name="stable-id" name_upper="STABLE_ID" type="string" description="This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are &quot;${CONNECTION}&quot;, &quot;${DEVICE}&quot;, &quot;${BOOT}&quot;, &quot;${RANDOM}&quot;. These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that &quot;${DEVICE}&quot; corresponds the the interface name of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as &quot;$$&quot;. For example, set it to &quot;${CONNECTION}-${BOOT}-${DEVICE}&quot; to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to &quot;${CONNECTION}&quot; and uses a unique, fixed ID for the connection." />
+    <property name="stable-id" name_upper="STABLE_ID" type="string" description="This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are &quot;${CONNECTION}&quot;, &quot;${DEVICE}&quot;, &quot;${MAC}&quot;, &quot;${BOOT}&quot;, &quot;${RANDOM}&quot;. These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that &quot;${DEVICE}&quot; corresponds the the interface name of the device and &quot;${MAC}&quot; is the permanent MAC address of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as &quot;$$&quot;. For example, set it to &quot;${CONNECTION}-${BOOT}-${DEVICE}&quot; to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to &quot;${CONNECTION}&quot; and uses a unique, fixed ID for the connection." />
     <property name="timestamp" name_upper="TIMESTAMP" type="uint64" default="0" description="The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved)." />
     <property name="type" name_upper="TYPE" type="string" description="Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, &quot;802-3-ethernet&quot; or &quot;802-11-wireless&quot; or &quot;bluetooth&quot;, etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, &quot;vpn&quot; or &quot;bridge&quot;, etc)." />
     <property name="uuid" name_upper="UUID" type="string" description="A universally unique identifier for the connection, for example generated with libuuid.  It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network.  For example, it should not be changed when the &quot;id&quot; property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or &quot;type&quot; property changes. The UUID must be in the format &quot;2815492f-7e56-435e-b2e9-246bd7cdc664&quot; (ie, contains only hexadecimal characters and &quot;-&quot;)." />
@@ -145,7 +145,7 @@
     <property name="home-only" name_upper="HOME_ONLY" type="boolean" default="FALSE" description="When TRUE, only connections to the home network will be allowed. Connections to roaming networks will not be made." />
     <property name="mtu" name_upper="MTU" type="uint32" default="0" description="If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames." />
     <property name="network-id" name_upper="NETWORK_ID" type="string" description="The Network ID (GSM LAI format, ie MCC-MNC) to force specific network registration.  If the Network ID is specified, NetworkManager will attempt to force the device to register only on the specified network. This can be used to ensure that the device does not roam when direct roaming control of the device is not otherwise possible." />
-    <property name="number" name_upper="NUMBER" type="string" description="Number to dial when establishing a PPP data session with the GSM-based mobile broadband network.  Many modems do not require PPP for connections to the mobile network and thus this property should be left blank, which allows NetworkManager to select the appropriate settings automatically." />
+    <property name="number" name_upper="NUMBER" type="string" description="Legacy setting that used to help establishing PPP data sessions for GSM-based modems. Deprecated: 1" />
     <property name="password" name_upper="PASSWORD" type="string" description="The password used to authenticate with the network, if required.  Many providers do not require a password, or accept any password.  But if a password is required, it is specified here." />
     <property name="password-flags" name_upper="PASSWORD_FLAGS" type="NMSettingSecretFlags (uint32)" description="Flags indicating how to handle the &quot;password&quot; property." />
     <property name="pin" name_upper="PIN" type="string" description="If the SIM is locked with a PIN it must be unlocked before any other operations are requested.  Specify the PIN here to allow operation of the device." />
@@ -164,14 +164,14 @@
   <setting name="ipv4" description="IPv4 Settings" name_upper="IP4_CONFIG" >
     <property name="addresses" name_upper="ADDRESSES" type="array of array of uint32" default="[]" description="Array of IP addresses." />
     <property name="dad-timeout" name_upper="DAD_TIMEOUT" type="int32" default="-1" description="Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero).  A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4." />
-    <property name="dhcp-client-id" name_upper="DHCP_CLIENT_ID" type="string" description="A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values &quot;mac&quot; and &quot;perm-mac&quot; are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. The special value &quot;stable&quot; is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If unset, a globally configured default is used. If still unset, the client-id from the last lease is reused." />
+    <property name="dhcp-client-id" name_upper="DHCP_CLIENT_ID" type="string" description="A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values &quot;mac&quot; and &quot;perm-mac&quot; are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. The special value &quot;duid&quot; generates a RFC4361-compliant client identifier based on a hash of the interface name as IAID and /etc/machine-id. The special value &quot;stable&quot; is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If you set the stable-id, you may want to include the &quot;${DEVICE}&quot; or &quot;${MAC}&quot; specifier to get a per-device key. If unset, a globally configured default is used. If still unset, the default depends on the DHCP plugin." />
     <property name="dhcp-fqdn" name_upper="DHCP_FQDN" type="string" description="If the &quot;dhcp-send-hostname&quot; property is TRUE, then the specified FQDN will be sent to the DHCP server when acquiring a lease. This property and &quot;dhcp-hostname&quot; are mutually exclusive and cannot be set at the same time." />
     <property name="dhcp-hostname" name_upper="DHCP_HOSTNAME" type="string" description="If the &quot;dhcp-send-hostname&quot; property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and &quot;dhcp-fqdn&quot; are mutually exclusive and cannot be set at the same time." />
     <property name="dhcp-send-hostname" name_upper="DHCP_SEND_HOSTNAME" type="boolean" default="TRUE" description="If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the &quot;dhcp-hostname&quot; property is NULL and this property is TRUE, the current persistent hostname of the computer is sent." />
     <property name="dhcp-timeout" name_upper="DHCP_TIMEOUT" type="int32" default="0" description="A timeout for a DHCP transaction in seconds." />
     <property name="dns" name_upper="DNS" type="array of uint32" default="[]" description="Array of IP addresses of DNS servers." />
     <property name="dns-options" name_upper="DNS_OPTIONS" type="array of string" default="[]" description="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." />
-    <property name="dns-priority" name_upper="DNS_PRIORITY" type="int32" default="0" description="DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority).  Zero selects the default value, which is 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, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS 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." />
+    <property name="dns-priority" name_upper="DNS_PRIORITY" type="int32" default="0" description="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, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS 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." />
     <property name="dns-search" name_upper="DNS_SEARCH" type="array of string" default="[]" description="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." />
     <property name="gateway" name_upper="GATEWAY" type="string" description="The gateway associated with this configuration. This is only meaningful if &quot;addresses&quot; is also set." />
     <property name="ignore-auto-dns" name_upper="IGNORE_AUTO_DNS" type="boolean" default="FALSE" description="When &quot;method&quot; is set to &quot;auto&quot; and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the &quot;dns&quot; and &quot;dns-search&quot; properties, if any, are used." />
@@ -187,13 +187,13 @@
     <property name="addr-gen-mode" name_upper="ADDR_GEN_MODE" type="int32" default="1" description="Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. On D-Bus, the absence of an addr-gen-mode setting equals enabling stable-privacy. For keyfile plugin, the absence of the setting on disk means EUI64 so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by &quot;ip6-privacy&quot; property and it does not affect the temporary addresses configured with this option." />
     <property name="addresses" name_upper="ADDRESSES" type="array of legacy IPv6 address struct" default="[]" description="Array of IP addresses." />
     <property name="dad-timeout" name_upper="DAD_TIMEOUT" type="int32" default="-1" description="Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero).  A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4." />
-    <property name="dhcp-duid" name_upper="DHCP_DUID" type="string" description="A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. The special value &quot;lease&quot; will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and &quot;dhclient&quot; is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. The special values &quot;llt&quot; and &quot;ll&quot; will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. The special values &quot;stable-llt&quot;, &quot;stable-ll&quot; and &quot;stable-uuid&quot; will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. So, the link-layer address of &quot;stable-ll&quot; and &quot;stable-llt&quot; will be a generated address derived from the stable id. The DUID-LLT time value in the &quot;stable-llt&quot; option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in &quot;llt&quot;). When the property is unset, the global value provided for &quot;ipv6.dhcp-duid&quot; is used. If no global value is provided, the default &quot;lease&quot; value is assumed." />
+    <property name="dhcp-duid" name_upper="DHCP_DUID" type="string" description="A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. The special value &quot;lease&quot; will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and &quot;dhclient&quot; is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. The special values &quot;llt&quot; and &quot;ll&quot; will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. The special values &quot;stable-llt&quot;, &quot;stable-ll&quot; and &quot;stable-uuid&quot; will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. You may want to include the &quot;${DEVICE}&quot; or &quot;${MAC}&quot; specifier in the stable-id, in case this profile gets activated on multiple devices. So, the link-layer address of &quot;stable-ll&quot; and &quot;stable-llt&quot; will be a generated address derived from the stable id. The DUID-LLT time value in the &quot;stable-llt&quot; option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in &quot;llt&quot;). When the property is unset, the global value provided for &quot;ipv6.dhcp-duid&quot; is used. If no global value is provided, the default &quot;lease&quot; value is assumed." />
     <property name="dhcp-hostname" name_upper="DHCP_HOSTNAME" type="string" description="If the &quot;dhcp-send-hostname&quot; property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and &quot;dhcp-fqdn&quot; are mutually exclusive and cannot be set at the same time." />
     <property name="dhcp-send-hostname" name_upper="DHCP_SEND_HOSTNAME" type="boolean" default="TRUE" description="If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the &quot;dhcp-hostname&quot; property is NULL and this property is TRUE, the current persistent hostname of the computer is sent." />
     <property name="dhcp-timeout" name_upper="DHCP_TIMEOUT" type="int32" default="0" description="A timeout for a DHCP transaction in seconds." />
     <property name="dns" name_upper="DNS" type="array of byte array" default="[]" description="Array of IP addresses of DNS servers." />
     <property name="dns-options" name_upper="DNS_OPTIONS" type="array of string" default="[]" description="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." />
-    <property name="dns-priority" name_upper="DNS_PRIORITY" type="int32" default="0" description="DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority).  Zero selects the default value, which is 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, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS 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." />
+    <property name="dns-priority" name_upper="DNS_PRIORITY" type="int32" default="0" description="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, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS 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." />
     <property name="dns-search" name_upper="DNS_SEARCH" type="array of string" default="[]" description="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." />
     <property name="gateway" name_upper="GATEWAY" type="string" description="The gateway associated with this configuration. This is only meaningful if &quot;addresses&quot; is also set." />
     <property name="ignore-auto-dns" name_upper="IGNORE_AUTO_DNS" type="boolean" default="FALSE" description="When &quot;method&quot; is set to &quot;auto&quot; and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the &quot;dns&quot; and &quot;dns-search&quot; properties, if any, are used." />
@@ -309,8 +309,8 @@
   </setting>
   <setting name="sriov" description="SR-IOV settings." name_upper="SRIOV" >
     <property name="autoprobe-drivers" name_upper="AUTOPROBE_DRIVERS" type="NMTernary (int32)" description="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)." />
-    <property name="total-vfs" name_upper="TOTAL_VFS" type="uint32" default="0" description="The total number of virtual functions to create." />
-    <property name="vfs" name_upper="VFS" type="array of vardict" default="[]" description="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: &quot;INDEX [ATTR=VALUE[ ATTR=VALUE]...]&quot;. for example: &quot;2 mac=00:11:22:33:44:55 spoof-check=true&quot;. The &quot;vlans&quot; attribute is represented as a semicolor-separated list of VLAN descriptors, where each descriptor has the form &quot;ID[.PRIORITY[.PROTO]]&quot;. PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 802.1ad." />
+    <property name="total-vfs" name_upper="TOTAL_VFS" type="uint32" default="0" description="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." />
+    <property name="vfs" name_upper="VFS" type="array of vardict" default="[]" description="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: &quot;INDEX [ATTR=VALUE[ ATTR=VALUE]...]&quot;. for example: &quot;2 mac=00:11:22:33:44:55 spoof-check=true&quot;. 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 &quot;vlans&quot; attribute is represented as a semicolon-separated list of VLAN descriptors, where each descriptor has the form &quot;ID[.PRIORITY[.PROTO]]&quot;. PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 802.1ad." />
   </setting>
   <setting name="tc" description="Linux Traffic Control Settings." name_upper="TC_CONFIG" >
     <property name="qdiscs" name_upper="QDISCS" type="array of vardict" default="[]" description="Array of TC queueing disciplines." />
@@ -318,7 +318,7 @@
   </setting>
   <setting name="team" description="Teaming Settings" name_upper="TEAM" >
     <property name="config" name_upper="CONFIG" type="string" description="The JSON configuration for the team network interface.  The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used.  See man teamd.conf for the format details." />
-    <property name="link-watchers" name_upper="LINK_WATCHERS" type="array of vardict" default="[]" description="Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are:   ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-incative', 'send-always'. See teamd.conf man for more details." />
+    <property name="link-watchers" name_upper="LINK_WATCHERS" type="array of vardict" default="[]" description="Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are:   ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-inactive', 'send-always'. See teamd.conf man for more details." />
     <property name="mcast-rejoin-count" name_upper="MCAST_REJOIN_COUNT" type="int32" default="0" description="Corresponds to the teamd mcast_rejoin.count." />
     <property name="mcast-rejoin-interval" name_upper="MCAST_REJOIN_INTERVAL" type="int32" default="0" description="Corresponds to the teamd mcast_rejoin.interval." />
     <property name="notify-peers-count" name_upper="NOTIFY_PEERS_COUNT" type="int32" default="0" description="Corresponds to the teamd notify_peers.count." />
@@ -338,7 +338,7 @@
     <property name="config" name_upper="CONFIG" type="string" description="The JSON configuration for the team port. The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used. See man teamd.conf for the format details." />
     <property name="lacp-key" name_upper="LACP_KEY" type="int32" default="0" description="Corresponds to the teamd ports.PORTIFNAME.lacp_key." />
     <property name="lacp-prio" name_upper="LACP_PRIO" type="int32" default="255" description="Corresponds to the teamd ports.PORTIFNAME.lacp_prio." />
-    <property name="link-watchers" name_upper="LINK_WATCHERS" type="array of vardict" default="[]" description="Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are:   ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-incative', 'send-always'. See teamd.conf man for more details." />
+    <property name="link-watchers" name_upper="LINK_WATCHERS" type="array of vardict" default="[]" description="Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are:   ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-inactive', 'send-always'. See teamd.conf man for more details." />
     <property name="prio" name_upper="PRIO" type="int32" default="0" description="Corresponds to the teamd ports.PORTIFNAME.prio." />
     <property name="queue-id" name_upper="QUEUE_ID" type="int32" default="-1" description="Corresponds to the teamd ports.PORTIFNAME.queue_id. When set to -1 means the parameter is skipped from the json config." />
     <property name="sticky" name_upper="STICKY" type="boolean" default="FALSE" description="Corresponds to the teamd ports.PORTIFNAME.sticky." />
@@ -449,7 +449,9 @@
     <property name="wps-method" name_upper="WPS_METHOD" type="uint32" default="0" description="Flags indicating which mode of WPS is to be used if any. There's little point in changing the default setting as NetworkManager will automatically determine whether it's feasible to start WPS enrollment from the Access Point capabilities. WPS can be disabled by setting this property to a value of 1." />
   </setting>
   <setting name="wpan" description="IEEE 802.15.4 (WPAN) MAC Settings" name_upper="WPAN" >
+    <property name="channel" name_upper="CHANNEL" type="int32" default="-1" description="IEEE 802.15.4 channel. A positive integer or -1, meaning &quot;do not set, use whatever the device is already set to&quot;." />
     <property name="mac-address" name_upper="MAC_ADDRESS" type="string" description="If specified, this connection will only apply to the IEEE 802.15.4 (WPAN) MAC layer device whose permanent MAC address matches." />
+    <property name="page" name_upper="PAGE" type="int32" default="-1" description="IEEE 802.15.4 channel page. A positive integer or -1, meaning &quot;do not set, use whatever the device is already set to&quot;." />
     <property name="pan-id" name_upper="PAN_ID" type="uint32" default="65535" description="IEEE 802.15.4 Personal Area Network (PAN) identifier." />
     <property name="short-address" name_upper="SHORT_ADDRESS" type="uint32" default="65535" description="Short IEEE 802.15.4 address to be used within a restricted environment." />
   </setting>
diff --git a/libnm/nm-settings-docs-overrides.xml b/libnm/nm-settings-docs-overrides.xml
index 276253c6..54d85107 100644
--- a/libnm/nm-settings-docs-overrides.xml
+++ b/libnm/nm-settings-docs-overrides.xml
@@ -172,7 +172,7 @@ For libnm and nmcli, this field is called &quot;cloned-mac-address&quot;."/>
 a hardware address in ASCII representation, or one of the special values
 &quot;preserve&quot;, &quot;permanent&quot;, &quot;random&quot; or &quot;stable&quot;.
 This field replaces the deprecated &quot;cloned-mac-address&quot; on D-Bus, which
-can only contain explict hardware addresses. Note that this property
+can only contain explicit hardware addresses. Note that this property
 only exists in D-Bus API. libnm and nmcli continue to call this property
 &quot;cloned-mac-address&quot;."/>
 </setting>
@@ -186,7 +186,7 @@ For libnm and nmcli, this field is called &quot;cloned-mac-address&quot;."/>
 a hardware address in ASCII representation, or one of the special values
 &quot;preserve&quot;, &quot;permanent&quot;, &quot;random&quot; or &quot;stable&quot;.
 This field replaces the deprecated &quot;cloned-mac-address&quot; on D-Bus, which
-can only contain explict hardware addresses. Note that this property
+can only contain explicit hardware addresses. Note that this property
 only exists in D-Bus API. libnm and nmcli continue to call this property
 &quot;cloned-mac-address&quot;."/>
 <property name="security" variable="security" format="" values="" default="" example="" description="This property is deprecated, but can be set to the value
diff --git a/libnm/nm-settings-docs.xml b/libnm/nm-settings-docs.xml
index 258d3558..5c33c2a4 100644
--- a/libnm/nm-settings-docs.xml
+++ b/libnm/nm-settings-docs.xml
@@ -22,7 +22,7 @@
     <property name="read-only" name_upper="READ_ONLY" type="boolean" default="FALSE" description="FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified." />
     <property name="secondaries" name_upper="SECONDARIES" type="array of string" default="[]" description="List of connection UUIDs that should be activated when the base connection itself is activated. Currently only VPN connections are supported." />
     <property name="slave-type" name_upper="SLAVE_TYPE" type="string" description="Setting name of the device type of this slave's master connection (eg, &quot;bond&quot;), or NULL if this connection is not a slave." />
-    <property name="stable-id" name_upper="STABLE_ID" type="string" description="This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are &quot;${CONNECTION}&quot;, &quot;${DEVICE}&quot;, &quot;${BOOT}&quot;, &quot;${RANDOM}&quot;. These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that &quot;${DEVICE}&quot; corresponds the the interface name of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as &quot;$$&quot;. For example, set it to &quot;${CONNECTION}-${BOOT}-${DEVICE}&quot; to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to &quot;${CONNECTION}&quot; and uses a unique, fixed ID for the connection." />
+    <property name="stable-id" name_upper="STABLE_ID" type="string" description="This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are &quot;${CONNECTION}&quot;, &quot;${DEVICE}&quot;, &quot;${MAC}&quot;, &quot;${BOOT}&quot;, &quot;${RANDOM}&quot;. These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that &quot;${DEVICE}&quot; corresponds the the interface name of the device and &quot;${MAC}&quot; is the permanent MAC address of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as &quot;$$&quot;. For example, set it to &quot;${CONNECTION}-${BOOT}-${DEVICE}&quot; to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to &quot;${CONNECTION}&quot; and uses a unique, fixed ID for the connection." />
     <property name="timestamp" name_upper="TIMESTAMP" type="uint64" default="0" description="The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved)." />
     <property name="type" name_upper="TYPE" type="string" description="Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, &quot;802-3-ethernet&quot; or &quot;802-11-wireless&quot; or &quot;bluetooth&quot;, etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, &quot;vpn&quot; or &quot;bridge&quot;, etc)." />
     <property name="uuid" name_upper="UUID" type="string" description="A universally unique identifier for the connection, for example generated with libuuid.  It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network.  For example, it should not be changed when the &quot;id&quot; property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or &quot;type&quot; property changes. The UUID must be in the format &quot;2815492f-7e56-435e-b2e9-246bd7cdc664&quot; (ie, contains only hexadecimal characters and &quot;-&quot;)." />
@@ -147,7 +147,7 @@
     <property name="home-only" name_upper="HOME_ONLY" type="boolean" default="FALSE" description="When TRUE, only connections to the home network will be allowed. Connections to roaming networks will not be made." />
     <property name="mtu" name_upper="MTU" type="uint32" default="0" description="If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames." />
     <property name="network-id" name_upper="NETWORK_ID" type="string" description="The Network ID (GSM LAI format, ie MCC-MNC) to force specific network registration.  If the Network ID is specified, NetworkManager will attempt to force the device to register only on the specified network. This can be used to ensure that the device does not roam when direct roaming control of the device is not otherwise possible." />
-    <property name="number" name_upper="NUMBER" type="string" description="Number to dial when establishing a PPP data session with the GSM-based mobile broadband network.  Many modems do not require PPP for connections to the mobile network and thus this property should be left blank, which allows NetworkManager to select the appropriate settings automatically." />
+    <property name="number" name_upper="NUMBER" type="string" description="Legacy setting that used to help establishing PPP data sessions for GSM-based modems. Deprecated: 1" />
     <property name="password" name_upper="PASSWORD" type="string" description="The password used to authenticate with the network, if required.  Many providers do not require a password, or accept any password.  But if a password is required, it is specified here." />
     <property name="password-flags" name_upper="PASSWORD_FLAGS" type="NMSettingSecretFlags (uint32)" description="Flags indicating how to handle the &quot;password&quot; property." />
     <property name="pin" name_upper="PIN" type="string" description="If the SIM is locked with a PIN it must be unlocked before any other operations are requested.  Specify the PIN here to allow operation of the device." />
@@ -167,14 +167,14 @@
     <property name="address-data" name_upper="ADDRESS_DATA" type="array of vardict" description="Array of IPv4 addresses. Each address dictionary contains at least 'address' and 'prefix' entries, containing the IP address as a string, and the prefix length as a uint32. Additional attributes may also exist on some addresses." />
     <property name="addresses" name_upper="ADDRESSES" type="array of array of uint32" default="[]" description="Deprecated in favor of the 'address-data' and 'gateway' properties, but this can be used for backward-compatibility with older daemons. Note that if you send this property the daemon will ignore 'address-data' and 'gateway'.  Array of IPv4 address structures.  Each IPv4 address structure is composed of 3 32-bit values; the first being the IPv4 address (network byte order), the second the prefix (1 - 32), and last the IPv4 gateway (network byte order). The gateway may be left as 0 if no gateway exists for that subnet." />
     <property name="dad-timeout" name_upper="DAD_TIMEOUT" type="int32" default="-1" description="Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero).  A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4." />
-    <property name="dhcp-client-id" name_upper="DHCP_CLIENT_ID" type="string" description="A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values &quot;mac&quot; and &quot;perm-mac&quot; are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. The special value &quot;stable&quot; is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If unset, a globally configured default is used. If still unset, the client-id from the last lease is reused." />
+    <property name="dhcp-client-id" name_upper="DHCP_CLIENT_ID" type="string" description="A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values &quot;mac&quot; and &quot;perm-mac&quot; are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. The special value &quot;duid&quot; generates a RFC4361-compliant client identifier based on a hash of the interface name as IAID and /etc/machine-id. The special value &quot;stable&quot; is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If you set the stable-id, you may want to include the &quot;${DEVICE}&quot; or &quot;${MAC}&quot; specifier to get a per-device key. If unset, a globally configured default is used. If still unset, the default depends on the DHCP plugin." />
     <property name="dhcp-fqdn" name_upper="DHCP_FQDN" type="string" description="If the &quot;dhcp-send-hostname&quot; property is TRUE, then the specified FQDN will be sent to the DHCP server when acquiring a lease. This property and &quot;dhcp-hostname&quot; are mutually exclusive and cannot be set at the same time." />
     <property name="dhcp-hostname" name_upper="DHCP_HOSTNAME" type="string" description="If the &quot;dhcp-send-hostname&quot; property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and &quot;dhcp-fqdn&quot; are mutually exclusive and cannot be set at the same time." />
     <property name="dhcp-send-hostname" name_upper="DHCP_SEND_HOSTNAME" type="boolean" default="TRUE" description="If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the &quot;dhcp-hostname&quot; property is NULL and this property is TRUE, the current persistent hostname of the computer is sent." />
     <property name="dhcp-timeout" name_upper="DHCP_TIMEOUT" type="int32" default="0" description="A timeout for a DHCP transaction in seconds." />
     <property name="dns" name_upper="DNS" type="array of uint32" default="[]" description="Array of IP addresses of DNS servers (as network-byte-order integers)" />
     <property name="dns-options" name_upper="DNS_OPTIONS" type="array of string" default="[]" description="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." />
-    <property name="dns-priority" name_upper="DNS_PRIORITY" type="int32" default="0" description="DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority).  Zero selects the default value, which is 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, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS 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." />
+    <property name="dns-priority" name_upper="DNS_PRIORITY" type="int32" default="0" description="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, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS 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." />
     <property name="dns-search" name_upper="DNS_SEARCH" type="array of string" default="[]" description="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." />
     <property name="gateway" name_upper="GATEWAY" type="string" description="The gateway associated with this configuration. This is only meaningful if &quot;addresses&quot; is also set." />
     <property name="ignore-auto-dns" name_upper="IGNORE_AUTO_DNS" type="boolean" default="FALSE" description="When &quot;method&quot; is set to &quot;auto&quot; and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the &quot;dns&quot; and &quot;dns-search&quot; properties, if any, are used." />
@@ -192,13 +192,13 @@
     <property name="address-data" name_upper="ADDRESS_DATA" type="array of vardict" description="Array of IPv6 addresses. Each address dictionary contains at least 'address' and 'prefix' entries, containing the IP address as a string, and the prefix length as a uint32. Additional attributes may also exist on some addresses." />
     <property name="addresses" name_upper="ADDRESSES" type="array of legacy IPv6 address struct (a(ayuay))" default="[]" description="Deprecated in favor of the 'address-data' and 'gateway' properties, but this can be used for backward-compatibility with older daemons. Note that if you send this property the daemon will ignore 'address-data' and 'gateway'.  Array of IPv6 address structures.  Each IPv6 address structure is composed of an IPv6 address, a prefix length (1 - 128), and an IPv6 gateway address. The gateway may be zeroed out if no gateway exists for that subnet." />
     <property name="dad-timeout" name_upper="DAD_TIMEOUT" type="int32" default="-1" description="Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero).  A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4." />
-    <property name="dhcp-duid" name_upper="DHCP_DUID" type="string" description="A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. The special value &quot;lease&quot; will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and &quot;dhclient&quot; is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. The special values &quot;llt&quot; and &quot;ll&quot; will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. The special values &quot;stable-llt&quot;, &quot;stable-ll&quot; and &quot;stable-uuid&quot; will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. So, the link-layer address of &quot;stable-ll&quot; and &quot;stable-llt&quot; will be a generated address derived from the stable id. The DUID-LLT time value in the &quot;stable-llt&quot; option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in &quot;llt&quot;). When the property is unset, the global value provided for &quot;ipv6.dhcp-duid&quot; is used. If no global value is provided, the default &quot;lease&quot; value is assumed." />
+    <property name="dhcp-duid" name_upper="DHCP_DUID" type="string" description="A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. The special value &quot;lease&quot; will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and &quot;dhclient&quot; is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. The special values &quot;llt&quot; and &quot;ll&quot; will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. The special values &quot;stable-llt&quot;, &quot;stable-ll&quot; and &quot;stable-uuid&quot; will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. You may want to include the &quot;${DEVICE}&quot; or &quot;${MAC}&quot; specifier in the stable-id, in case this profile gets activated on multiple devices. So, the link-layer address of &quot;stable-ll&quot; and &quot;stable-llt&quot; will be a generated address derived from the stable id. The DUID-LLT time value in the &quot;stable-llt&quot; option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in &quot;llt&quot;). When the property is unset, the global value provided for &quot;ipv6.dhcp-duid&quot; is used. If no global value is provided, the default &quot;lease&quot; value is assumed." />
     <property name="dhcp-hostname" name_upper="DHCP_HOSTNAME" type="string" description="If the &quot;dhcp-send-hostname&quot; property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and &quot;dhcp-fqdn&quot; are mutually exclusive and cannot be set at the same time." />
     <property name="dhcp-send-hostname" name_upper="DHCP_SEND_HOSTNAME" type="boolean" default="TRUE" description="If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the &quot;dhcp-hostname&quot; property is NULL and this property is TRUE, the current persistent hostname of the computer is sent." />
     <property name="dhcp-timeout" name_upper="DHCP_TIMEOUT" type="int32" default="0" description="A timeout for a DHCP transaction in seconds." />
     <property name="dns" name_upper="DNS" type="array of byte array" default="[]" description="Array of IP addresses of DNS servers (in network byte order)" />
     <property name="dns-options" name_upper="DNS_OPTIONS" type="array of string" default="[]" description="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." />
-    <property name="dns-priority" name_upper="DNS_PRIORITY" type="int32" default="0" description="DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority).  Zero selects the default value, which is 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, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS 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." />
+    <property name="dns-priority" name_upper="DNS_PRIORITY" type="int32" default="0" description="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, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS 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." />
     <property name="dns-search" name_upper="DNS_SEARCH" type="array of string" default="[]" description="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." />
     <property name="gateway" name_upper="GATEWAY" type="string" description="The gateway associated with this configuration. This is only meaningful if &quot;addresses&quot; is also set." />
     <property name="ignore-auto-dns" name_upper="IGNORE_AUTO_DNS" type="boolean" default="FALSE" description="When &quot;method&quot; is set to &quot;auto&quot; and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the &quot;dns&quot; and &quot;dns-search&quot; properties, if any, are used." />
@@ -315,8 +315,8 @@
   </setting>
   <setting name="sriov" description="SR-IOV settings." name_upper="SRIOV" >
     <property name="autoprobe-drivers" name_upper="AUTOPROBE_DRIVERS" type="NMTernary (int32)" description="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)." />
-    <property name="total-vfs" name_upper="TOTAL_VFS" type="uint32" default="0" description="The total number of virtual functions to create." />
-    <property name="vfs" name_upper="VFS" type="array of vardict" default="[]" description="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: &quot;INDEX [ATTR=VALUE[ ATTR=VALUE]...]&quot;. for example: &quot;2 mac=00:11:22:33:44:55 spoof-check=true&quot;. The &quot;vlans&quot; attribute is represented as a semicolor-separated list of VLAN descriptors, where each descriptor has the form &quot;ID[.PRIORITY[.PROTO]]&quot;. PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 802.1ad." />
+    <property name="total-vfs" name_upper="TOTAL_VFS" type="uint32" default="0" description="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." />
+    <property name="vfs" name_upper="VFS" type="array of vardict" default="[]" description="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: &quot;INDEX [ATTR=VALUE[ ATTR=VALUE]...]&quot;. for example: &quot;2 mac=00:11:22:33:44:55 spoof-check=true&quot;. 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 &quot;vlans&quot; attribute is represented as a semicolon-separated list of VLAN descriptors, where each descriptor has the form &quot;ID[.PRIORITY[.PROTO]]&quot;. PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 802.1ad." />
   </setting>
   <setting name="tc" description="Linux Traffic Control Settings." name_upper="TC_CONFIG" >
     <property name="qdiscs" name_upper="QDISCS" type="array of vardict" default="[]" description="Array of TC queueing disciplines." />
@@ -325,7 +325,7 @@
   <setting name="team" description="Teaming Settings" name_upper="TEAM" >
     <property name="config" name_upper="CONFIG" type="string" description="The JSON configuration for the team network interface.  The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used.  See man teamd.conf for the format details." />
     <property name="interface-name" name_upper="INTERFACE_NAME" type="string" description="Deprecated in favor of connection.interface-name, but can be used for backward-compatibility with older daemons, to set the team's interface name." />
-    <property name="link-watchers" name_upper="LINK_WATCHERS" type="array of vardict" default="[]" description="Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are:   ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-incative', 'send-always'. See teamd.conf man for more details." />
+    <property name="link-watchers" name_upper="LINK_WATCHERS" type="array of vardict" default="[]" description="Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are:   ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-inactive', 'send-always'. See teamd.conf man for more details." />
     <property name="mcast-rejoin-count" name_upper="MCAST_REJOIN_COUNT" type="int32" default="0" description="Corresponds to the teamd mcast_rejoin.count." />
     <property name="mcast-rejoin-interval" name_upper="MCAST_REJOIN_INTERVAL" type="int32" default="0" description="Corresponds to the teamd mcast_rejoin.interval." />
     <property name="notify-peers-count" name_upper="NOTIFY_PEERS_COUNT" type="int32" default="0" description="Corresponds to the teamd notify_peers.count." />
@@ -345,7 +345,7 @@
     <property name="config" name_upper="CONFIG" type="string" description="The JSON configuration for the team port. The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used. See man teamd.conf for the format details." />
     <property name="lacp-key" name_upper="LACP_KEY" type="int32" default="0" description="Corresponds to the teamd ports.PORTIFNAME.lacp_key." />
     <property name="lacp-prio" name_upper="LACP_PRIO" type="int32" default="255" description="Corresponds to the teamd ports.PORTIFNAME.lacp_prio." />
-    <property name="link-watchers" name_upper="LINK_WATCHERS" type="array of vardict" default="[]" description="Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are:   ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-incative', 'send-always'. See teamd.conf man for more details." />
+    <property name="link-watchers" name_upper="LINK_WATCHERS" type="array of vardict" default="[]" description="Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are:   ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-inactive', 'send-always'. See teamd.conf man for more details." />
     <property name="prio" name_upper="PRIO" type="int32" default="0" description="Corresponds to the teamd ports.PORTIFNAME.prio." />
     <property name="queue-id" name_upper="QUEUE_ID" type="int32" default="-1" description="Corresponds to the teamd ports.PORTIFNAME.queue_id. When set to -1 means the parameter is skipped from the json config." />
     <property name="sticky" name_upper="STICKY" type="boolean" default="FALSE" description="Corresponds to the teamd ports.PORTIFNAME.sticky." />
@@ -400,7 +400,7 @@
     <property name="network-name" name_upper="NETWORK_NAME" type="string" description="Network Service Provider (NSP) name of the WiMAX network this connection should use. Deprecated: 1" />
   </setting>
   <setting name="802-3-ethernet" description="Wired Ethernet Settings" name_upper="WIRED" >
-    <property name="assigned-mac-address" name_upper="ASSIGNED_MAC_ADDRESS" type="string" description="The new field for the cloned MAC address. It can be either a hardware address in ASCII representation, or one of the special values &quot;preserve&quot;, &quot;permanent&quot;, &quot;random&quot; or &quot;stable&quot;. This field replaces the deprecated &quot;cloned-mac-address&quot; on D-Bus, which can only contain explict hardware addresses. Note that this property only exists in D-Bus API. libnm and nmcli continue to call this property &quot;cloned-mac-address&quot;." />
+    <property name="assigned-mac-address" name_upper="ASSIGNED_MAC_ADDRESS" type="string" description="The new field for the cloned MAC address. It can be either a hardware address in ASCII representation, or one of the special values &quot;preserve&quot;, &quot;permanent&quot;, &quot;random&quot; or &quot;stable&quot;. This field replaces the deprecated &quot;cloned-mac-address&quot; on D-Bus, which can only contain explicit hardware addresses. Note that this property only exists in D-Bus API. libnm and nmcli continue to call this property &quot;cloned-mac-address&quot;." />
     <property name="auto-negotiate" name_upper="AUTO_NEGOTIATE" type="boolean" default="FALSE" description="When TRUE, enforce auto-negotiation of speed and duplex mode. If &quot;speed&quot; and &quot;duplex&quot; properties are both specified, only that single mode will be advertised and accepted during the link auto-negotiation process: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. When FALSE, &quot;speed&quot; and &quot;duplex&quot; properties should be both set or link configuration will be skipped." />
     <property name="cloned-mac-address" name_upper="CLONED_MAC_ADDRESS" type="byte array" description="This D-Bus field is deprecated in favor of &quot;assigned-mac-address&quot; which is more flexible and allows specifying special variants like &quot;random&quot;. For libnm and nmcli, this field is called &quot;cloned-mac-address&quot;." />
     <property name="duplex" name_upper="DUPLEX" type="string" description="When a value is set, either &quot;half&quot; or &quot;full&quot;, configures the device to use the specified duplex mode. If &quot;auto-negotiate&quot; is &quot;yes&quot; the specified duplex mode will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. If the value is unset (the default), the link configuration will be either skipped (if &quot;auto-negotiate&quot; is &quot;no&quot;, the default) or will be auto-negotiated (if &quot;auto-negotiate&quot; is &quot;yes&quot;) and the local device will advertise all the supported duplex modes. Must be set together with the &quot;speed&quot; property if specified. Before specifying a duplex mode be sure your device supports it." />
@@ -417,7 +417,7 @@
     <property name="wake-on-lan-password" name_upper="WAKE_ON_LAN_PASSWORD" type="string" description="If specified, the password used with magic-packet-based Wake-on-LAN, represented as an Ethernet MAC address.  If NULL, no password will be required." />
   </setting>
   <setting name="802-11-wireless" description="Wi-Fi Settings" name_upper="WIRELESS" >
-    <property name="assigned-mac-address" name_upper="ASSIGNED_MAC_ADDRESS" type="string" description="The new field for the cloned MAC address. It can be either a hardware address in ASCII representation, or one of the special values &quot;preserve&quot;, &quot;permanent&quot;, &quot;random&quot; or &quot;stable&quot;. This field replaces the deprecated &quot;cloned-mac-address&quot; on D-Bus, which can only contain explict hardware addresses. Note that this property only exists in D-Bus API. libnm and nmcli continue to call this property &quot;cloned-mac-address&quot;." />
+    <property name="assigned-mac-address" name_upper="ASSIGNED_MAC_ADDRESS" type="string" description="The new field for the cloned MAC address. It can be either a hardware address in ASCII representation, or one of the special values &quot;preserve&quot;, &quot;permanent&quot;, &quot;random&quot; or &quot;stable&quot;. This field replaces the deprecated &quot;cloned-mac-address&quot; on D-Bus, which can only contain explicit hardware addresses. Note that this property only exists in D-Bus API. libnm and nmcli continue to call this property &quot;cloned-mac-address&quot;." />
     <property name="band" name_upper="BAND" type="string" description="802.11 frequency band of the network.  One of &quot;a&quot; for 5GHz 802.11a or &quot;bg&quot; for 2.4GHz 802.11.  This will lock associations to the Wi-Fi network to the specific band, i.e. if &quot;a&quot; is specified, the device will not associate with the same network in the 2.4GHz band even if the network's settings are compatible.  This setting depends on specific driver capability and may not work with all drivers." />
     <property name="bssid" name_upper="BSSID" type="byte array" description="If specified, directs the device to only associate with the given access point.  This capability is highly driver dependent and not supported by all devices.  Note: this property does not control the BSSID used when creating an Ad-Hoc network and is unlikely to in the future." />
     <property name="channel" name_upper="CHANNEL" type="uint32" default="0" description="Wireless channel to use for the Wi-Fi connection.  The device will only join (or create for Ad-Hoc networks) a Wi-Fi network on the specified channel.  Because channel numbers overlap between bands, this property also requires the &quot;band&quot; property to be set." />
@@ -460,7 +460,9 @@
     <property name="wps-method" name_upper="WPS_METHOD" type="uint32" default="0" description="Flags indicating which mode of WPS is to be used if any. There's little point in changing the default setting as NetworkManager will automatically determine whether it's feasible to start WPS enrollment from the Access Point capabilities. WPS can be disabled by setting this property to a value of 1." />
   </setting>
   <setting name="wpan" description="IEEE 802.15.4 (WPAN) MAC Settings" name_upper="WPAN" >
+    <property name="channel" name_upper="CHANNEL" type="int32" default="-1" description="IEEE 802.15.4 channel. A positive integer or -1, meaning &quot;do not set, use whatever the device is already set to&quot;." />
     <property name="mac-address" name_upper="MAC_ADDRESS" type="string" description="If specified, this connection will only apply to the IEEE 802.15.4 (WPAN) MAC layer device whose permanent MAC address matches." />
+    <property name="page" name_upper="PAGE" type="int32" default="-1" description="IEEE 802.15.4 channel page. A positive integer or -1, meaning &quot;do not set, use whatever the device is already set to&quot;." />
     <property name="pan-id" name_upper="PAN_ID" type="uint32" default="65535" description="IEEE 802.15.4 Personal Area Network (PAN) identifier." />
     <property name="short-address" name_upper="SHORT_ADDRESS" type="uint32" default="65535" description="Short IEEE 802.15.4 address to be used within a restricted environment." />
   </setting>
diff --git a/libnm/nm-settings-ifcfg-rh-docs.xml b/libnm/nm-settings-ifcfg-rh-docs.xml
index 11f3115d..d1913062 100644
--- a/libnm/nm-settings-ifcfg-rh-docs.xml
+++ b/libnm/nm-settings-ifcfg-rh-docs.xml
@@ -135,7 +135,7 @@ means &quot;do not transmit priority pause&quot;, &quot;1&quot; means &quot;tran
 The sum of the numbers must be 100."/>
 <property name="priority-strict-bandwidth" variable="DCB_PG_STRICT" format="" values="" default="" example="DCB_PG_STRICT=01101110" description="Priority values. String of eight &quot;0&quot; or &quot;1&quot;, where &quot;0&quot; means
 &quot;may not utilize all bandwidth&quot;, &quot;1&quot; means &quot;may utilize all bandwidth&quot;."/>
-<property name="priority-traffic-class" variable="DCB_PG_UP2TC" format="" values="" default="" example="DCB_PG_UP2TC=01623701" description="Priority values. String of eight trafic class values (0 - 7)."/>
+<property name="priority-traffic-class" variable="DCB_PG_UP2TC" format="" values="" default="" example="DCB_PG_UP2TC=01623701" description="Priority values. String of eight traffic class values (0 - 7)."/>
 </setting>
 <setting name="dummy">
 </setting>
diff --git a/libnm/nm-vpn-service-plugin.c b/libnm/nm-vpn-service-plugin.c
index 2213824e..ed9da7f7 100644
--- a/libnm/nm-vpn-service-plugin.c
+++ b/libnm/nm-vpn-service-plugin.c
@@ -787,10 +787,13 @@ nm_vpn_service_plugin_read_vpn_details (int fd,
 	gs_unref_hashtable GHashTable *data = NULL;
 	gs_unref_hashtable GHashTable *secrets = NULL;
 	gboolean success = FALSE;
-	char *key = NULL, *val = NULL;
+	GHashTable *hash = NULL;
+	GString *key = NULL, *val = NULL;
 	nm_auto_free_gstring GString *line = NULL;
 	char c;
 
+	GString *str = NULL;
+
 	if (out_data)
 		g_return_val_if_fail (*out_data == NULL, FALSE);
 	if (out_secrets)
@@ -804,49 +807,80 @@ nm_vpn_service_plugin_read_vpn_details (int fd,
 	/* Read stdin for data and secret items until we get a DONE */
 	while (1) {
 		ssize_t nr;
-		GHashTable *hash = NULL;
 
 		errno = 0;
 		nr = read (fd, &c, 1);
-		if (nr == -1) {
+		if (nr < 0) {
 			if (errno == EAGAIN) {
 				g_usleep (100);
 				continue;
 			}
 			break;
 		}
-
-		if (c != '\n') {
+		if (nr > 0 && c != '\n') {
 			g_string_append_c (line, c);
 			continue;
 		}
 
-		/* Check for the finish marker */
-		if (strcmp (line->str, "DONE") == 0)
-			break;
+		if (str && *line->str == '=') {
+			/* continuation */
+			g_string_append_c (str, '\n');
+			g_string_append (str, line->str + 1);
+		} else if (key && val) {
+			/* done a line */
+			g_return_val_if_fail (hash, FALSE);
+			g_hash_table_insert (hash,
+					     g_string_free (key, FALSE),
+					     g_string_free (val, FALSE));
+			key = NULL;
+			val = NULL;
+			hash = NULL;
+			success = TRUE;  /* Got at least one value */
+		}
 
-		/* Otherwise it's a data/secret item */
-		if (strncmp (line->str, DATA_KEY_TAG, strlen (DATA_KEY_TAG)) == 0) {
+		if (strcmp (line->str, "DONE") == 0) {
+			 /* finish marker */
+			break;
+		} else if (strncmp (line->str, DATA_KEY_TAG, strlen (DATA_KEY_TAG)) == 0) {
+			if (key != NULL) {
+				g_warning ("a value expected");
+				g_string_free (key, TRUE);
+			}
+			key = g_string_new (line->str + strlen (DATA_KEY_TAG));
+			str = key;
 			hash = data;
-			key = g_strdup (line->str + strlen (DATA_KEY_TAG));
 		} else if (strncmp (line->str, DATA_VAL_TAG, strlen (DATA_VAL_TAG)) == 0) {
-			hash = data;
-			val = g_strdup (line->str + strlen (DATA_VAL_TAG));
+			if (val != NULL)
+				g_string_free (val, TRUE);
+			if (val || !key || hash != data) {
+				g_warning ("%s not preceded by %s", DATA_VAL_TAG, DATA_KEY_TAG);
+				break;
+			}
+			val = g_string_new (line->str + strlen (DATA_VAL_TAG));
+			str = val;
 		} else if (strncmp (line->str, SECRET_KEY_TAG, strlen (SECRET_KEY_TAG)) == 0) {
+			if (key != NULL) {
+				g_warning ("a value expected");
+				g_string_free (key, TRUE);
+			}
+			key = g_string_new (line->str + strlen (SECRET_KEY_TAG));
+			str = key;
 			hash = secrets;
-			key = g_strdup (line->str + strlen (SECRET_KEY_TAG));
 		} else if (strncmp (line->str, SECRET_VAL_TAG, strlen (SECRET_VAL_TAG)) == 0) {
-			hash = secrets;
-			val = g_strdup (line->str + strlen (SECRET_VAL_TAG));
+			if (val != NULL)
+				g_string_free (val, TRUE);
+			if (val || !key || hash != secrets) {
+				g_warning ("%s not preceded by %s", SECRET_VAL_TAG, SECRET_KEY_TAG);
+				break;
+			}
+			val = g_string_new (line->str + strlen (SECRET_VAL_TAG));
+			str = val;
 		}
+
 		g_string_truncate (line, 0);
 
-		if (key && val && hash) {
-			g_hash_table_insert (hash, key, val);
-			key = NULL;
-			val = NULL;
-			success = TRUE;  /* Got at least one value */
-		}
+		if (nr == 0)
+			break;
 	}
 
 	if (success) {
@@ -1325,7 +1359,7 @@ nm_vpn_service_plugin_initable_iface_init (GInitableIface *iface)
 /*****************************************************************************/
 
 /* this header is intended to be copied to users of nm_vpn_editor_plugin_call(),
- * to simplify invocation of generic functions. Include it here, to complile
+ * to simplify invocation of generic functions. Include it here, to compile
  * the code. */
 #include "nm-utils/nm-vpn-editor-plugin-call.h"
 
diff --git a/libnm/tests/meson.build b/libnm/tests/meson.build
index ae2f7124..d0a2dd30 100644
--- a/libnm/tests/meson.build
+++ b/libnm/tests/meson.build
@@ -20,16 +20,17 @@ foreach test_unit: test_units
     dependencies: [
       libnm_dep,
       nm_core_dep,
+      libnm_systemd_shared_no_logging_dep,
     ],
     c_args: cflags,
-    link_with: test_unit[1]
+    link_with: test_unit[1],
   )
 
   test(
     'libnm/' + test_unit[0],
     test_script,
     timeout: test_unit[2],
-    args: test_args + [exe.full_path()]
+    args: test_args + [exe.full_path()],
   )
 endforeach
 
@@ -39,5 +40,5 @@ libnm_vpn_plugin_utils_test = static_library(
   sources: shared_nm_utils_nm_vpn_plugin_utils_c + [libnm_enum[1]],
   include_directories: libnm_inc,
   dependencies: nm_core_dep,
-  c_args: cflags
+  c_args: cflags,
 )
diff --git a/libnm/tests/test-general.c b/libnm/tests/test-general.c
index 5959a4e6..410087af 100644
--- a/libnm/tests/test-general.c
+++ b/libnm/tests/test-general.c
@@ -20,8 +20,16 @@
 
 #include "nm-default.h"
 
+#if defined (HAVE_DECL_MEMFD_CREATE) && HAVE_DECL_MEMFD_CREATE
+#include <linux/memfd.h>
+#endif
+
+#include <sys/mman.h>
+
 #include "nm-libnm-utils.h"
 
+#include "nm-vpn-service-plugin.h"
+
 #include "nm-utils/nm-test-utils.h"
 
 /*****************************************************************************/
@@ -2158,6 +2166,271 @@ test_fixup_product_string (void)
 
 /*****************************************************************************/
 
+static int
+_memfd_create (const char *name)
+{
+#if defined (HAVE_DECL_MEMFD_CREATE) && HAVE_DECL_MEMFD_CREATE
+	return memfd_create (name, MFD_CLOEXEC);
+#endif
+	return -1;
+}
+
+typedef struct {
+	const char *key;
+	const char *val;
+} ReadVpnDetailData;
+
+#define READ_VPN_DETAIL_DATA(...) \
+	((ReadVpnDetailData []) { __VA_ARGS__ })
+
+static gboolean
+_do_read_vpn_details_impl1 (const char *file,
+                            int line,
+                            int memfd,
+                            char *mem,
+                            gsize len,
+                            const ReadVpnDetailData *expected_data,
+                            guint expected_data_len,
+                            const ReadVpnDetailData *expected_secrets,
+                            guint expected_secrets_len)
+{
+	gssize written;
+	off_t lseeked;
+	gs_unref_hashtable GHashTable *data = NULL;
+	gs_unref_hashtable GHashTable *secrets = NULL;
+
+	written = write (memfd, mem, len);
+	g_assert_cmpint (written, ==, (gssize) len);
+
+	lseeked = lseek (memfd, 0, SEEK_SET);
+	g_assert_cmpint (lseeked, ==, 0);
+
+	if (!nm_vpn_service_plugin_read_vpn_details (memfd,
+	                                             &data,
+	                                             &secrets)) {
+		g_assert (!data);
+		g_assert (!secrets);
+		g_assert_cmpint (expected_data_len, ==, 0);
+		g_assert_cmpint (expected_secrets_len, ==, 0);
+		return TRUE;
+	}
+
+#define _assert_hash(hash, expected, expected_len) \
+	G_STMT_START { \
+		GHashTable *_hash = (hash); \
+		guint _expected_len = (expected_len); \
+		const ReadVpnDetailData *_expected = (expected); \
+		GHashTableIter _iter; \
+		const char *_k, *_v; \
+		guint _i; \
+		\
+		g_assert (_hash); \
+		\
+		g_hash_table_iter_init (&_iter, _hash); \
+		while (g_hash_table_iter_next (&_iter, (gpointer *) &_k, (gpointer *) &_v)) { \
+			for (_i = 0; _i < _expected_len; _i++) { \
+				if (nm_streq (_expected[_i].key, _k)) \
+					break; \
+			} \
+			if (_i >= _expected_len) \
+				g_error ("%s:%d: hash '%s' contains unexpected data key '%s' with value '%s'", file, line, G_STRINGIFY (hash), _k, _v); \
+		} \
+		\
+		for (_i = 0; _i < _expected_len; _i++) { \
+			const ReadVpnDetailData *_d = &_expected[_i]; \
+			\
+			g_assert (_d->key); \
+			g_assert (_d->val); \
+			_v = g_hash_table_lookup (_hash, _d->key); \
+			if (!nm_streq0 (_v, _d->val)) \
+				g_error ("%s:%d: hash '%s' contains data key '%s' with value %s%s%s but we expected '%s'", file, line, G_STRINGIFY (hash), _d->key, NM_PRINT_FMT_QUOTE_STRING (_v), _d->val); \
+		} \
+		\
+		g_assert_cmpint (g_hash_table_size (_hash), ==, _expected_len); \
+	} G_STMT_END
+
+	_assert_hash (data, expected_data, expected_data_len);
+	_assert_hash (secrets, expected_secrets, expected_secrets_len);
+
+#undef _assert_hash
+	return TRUE;
+}
+
+#define _do_read_vpn_details_impl0(str, expected_data, expected_data_len, expected_secrets, expected_secrets_len, pre_setup_cmd) \
+	G_STMT_START { \
+		nm_auto_close int _memfd = _memfd_create ("libnm-test-read-vpn-details"); \
+		\
+		if (_memfd < 0) \
+			g_test_skip ("cannot create memfd"); \
+		else { \
+			{ pre_setup_cmd ; } \
+			_do_read_vpn_details_impl1 (__FILE__, \
+			                            __LINE__, \
+			                            _memfd, \
+			                            ""str"", \
+			                            NM_STRLEN (str), \
+			                            expected_data, \
+			                            expected_data_len, \
+			                            expected_secrets, \
+			                            expected_secrets_len); \
+		} \
+	} G_STMT_END
+
+#define _do_read_vpn_details_empty(str) \
+	_do_read_vpn_details_impl0 (str, \
+	                            NULL, \
+	                            0, \
+	                            NULL, \
+	                            0, \
+	                            { } )
+
+#define _do_read_vpn_details(str, expected_data, expected_secrets, pre_setup_cmd) \
+	_do_read_vpn_details_impl0 (str, \
+	                            expected_data, \
+	                            G_N_ELEMENTS (expected_data), \
+	                            expected_secrets, \
+	                            G_N_ELEMENTS (expected_secrets), \
+	                            pre_setup_cmd)
+
+static void
+test_nm_vpn_service_plugin_read_vpn_details (void)
+{
+	_do_read_vpn_details_empty ("");
+	_do_read_vpn_details_empty ("hallo");
+	_do_read_vpn_details_empty ("DONE");
+	_do_read_vpn_details_empty ("DONE\n");
+	_do_read_vpn_details_empty ("DONE\0");
+	_do_read_vpn_details_empty ("\0DONE\0");
+
+	_do_read_vpn_details (""
+	                      "DATA_KEY=some-key\n"
+	                      "DATA_VAL=string\n"
+	                      "\n"
+	                      "DATA_KEY=some-other-key\n"
+	                      "DATA_VAL=val2\n"
+	                      "\n"
+	                      "SECRET_KEY=some-secret\n"
+	                      "SECRET_VAL=val3\n"
+	                      "\n"
+	                      "DONE\n"
+	                      "\n"
+	                      "",
+	                      READ_VPN_DETAIL_DATA (
+	                        { "some-key", "string" },
+	                        { "some-other-key", "val2" },
+	                      ),
+	                      READ_VPN_DETAIL_DATA (
+	                        { "some-secret", "val3" },
+	                      ),
+	                      );
+
+	_do_read_vpn_details (""
+	                      "DATA_KEY=some-key\n"
+	                      "DATA_VAL=string\n"
+	                      "DONE\n",
+	                      READ_VPN_DETAIL_DATA (
+	                        { "some-key", "string" },
+	                      ),
+	                      READ_VPN_DETAIL_DATA (),
+	                      );
+
+	_do_read_vpn_details (""
+	                      "DATA_KEY=some-key\n"
+	                      "DATA_VAL=string\n"
+	                      "=continued after a line break\n"
+	                      "SECRET_KEY=key names\n"
+	                      "=can have\n"
+	                      "=continuations too\n"
+	                      "bogus1=\n"
+	                      "SECRET_VAL=value\n"
+	                      "bogus=value\n"
+	                      "bogus=\n"
+	                      "DATA_VAL=x\n"
+	                      "DATA_KEY=\n"
+	                      "DATA_VAL=\n"
+	                      "DATA_VAL=y\n"
+	                      "DATA_KEY=y\n"
+	                      "DATA_KEY=y\n"
+	                      "DATA_KEY=z\n"
+	                      "SECRET_KEY=s1\n"
+	                      "DATA_VAL=z\n"
+	                      "SECRET_VAL=S1\n"
+	                      "\n"
+	                      "DONE\n"
+	                      "",
+	                      READ_VPN_DETAIL_DATA (
+	                        { "some-key", "string\ncontinued after a line break" },
+	                      ),
+	                      READ_VPN_DETAIL_DATA (
+	                        { "key names\ncan have\ncontinuations too", "value" },
+	                      ),
+	                      NMTST_EXPECT_LIBNM_WARNING ("DATA_VAL= not preceded by DATA_KEY=")
+	                      );
+
+	_do_read_vpn_details (""
+	                      "DATA_KEY=some-key\n"
+	                      "DATA_VAL=string\n"
+	                      "=continued after a line break\n"
+	                      "SECRET_KEY=key names\n"
+	                      "=can have\n"
+	                      "=continuations too\n"
+	                      "SECRET_VAL=value\n"
+	                      "",
+	                      READ_VPN_DETAIL_DATA (
+	                        { "some-key", "string\ncontinued after a line break" },
+	                      ),
+	                      READ_VPN_DETAIL_DATA (
+	                        { "key names\ncan have\ncontinuations too", "value" },
+	                      ),
+	                      );
+
+	_do_read_vpn_details (""
+	                      "DATA_KEY=some-key\n"
+	                      "DATA_VAL=string\n"
+	                      "\n"
+	                      "DATA_KEY=some\n"
+	                      "=key-2\n"
+	                      "DATA_VAL=val2\n"
+	                      "\n"
+	                      "DATA_KEY=key3\0"
+	                      "=key-2\n"
+	                      "DATA_VAL=val3\n"
+	                      "\n"
+	                      "SECRET_KEY=some-secret\n"
+	                      "SECRET_VAL=val3\n"
+	                      "\n"
+	                      "SECRET_KEY=\n"
+	                      "SECRET_VAL=val3\n"
+	                      "\n"
+	                      "SECRET_KEY=keyx\n"
+	                      "SECRET_VAL=\n"
+	                      "\n"
+	                      "SECRET_KEY=ke\xc0yx\n"
+	                      "SECRET_VAL=inval\n"
+	                      "\n"
+	                      "SECRET_KEY=key-inval\n"
+	                      "SECRET_VAL=in\xc1val\n"
+	                      "\n"
+	                      "DONE\n"
+	                      "\n"
+	                      "",
+	                      READ_VPN_DETAIL_DATA (
+	                        { "some\nkey-2", "val2" },
+	                        { "some-key", "string" },
+	                        { "key3", "val3" },
+	                      ),
+	                      READ_VPN_DETAIL_DATA (
+	                        { "some-secret", "val3" },
+	                        { "", "val3" },
+	                        { "keyx", "" },
+	                        { "ke\xc0yx", "inval" },
+	                        { "key-inval", "in\xc1val" },
+	                      ),
+	                      );
+}
+
+/*****************************************************************************/
+
 NMTST_DEFINE ();
 
 int main (int argc, char **argv)
@@ -2166,6 +2439,7 @@ int main (int argc, char **argv)
 
 	g_test_add_func ("/libnm/general/fixup_product_string", test_fixup_product_string);
 	g_test_add_func ("/libnm/general/fixup_vendor_string", test_fixup_vendor_string);
+	g_test_add_func ("/libnm/general/nm_vpn_service_plugin_read_vpn_details", test_nm_vpn_service_plugin_read_vpn_details);
 
 	return g_test_run ();
 }