summary refs log tree commit diff
path: root/src/libnm-core-impl
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2023-08-09 21:55:35 +0200
committerMichael Biebl <biebl@debian.org>2023-08-09 21:55:35 +0200
commit05e4a733f2141995181a551854d5df929f084adf (patch)
tree83bb937740a6667525ba0df046748ecaa829c269 /src/libnm-core-impl
parent14b0f3a9dc9ea90d60a3b057350fd4d637dc021a (diff)
New upstream version 1.44.0 upstream/1.44.0
Diffstat (limited to 'src/libnm-core-impl')
-rw-r--r--src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in35
-rw-r--r--src/libnm-core-impl/meson.build1
-rw-r--r--src/libnm-core-impl/nm-connection.c230
-rw-r--r--src/libnm-core-impl/nm-keyfile.c25
-rw-r--r--src/libnm-core-impl/nm-meta-setting-base-impl.c9
-rw-r--r--src/libnm-core-impl/nm-setting-8021x.c4
-rw-r--r--src/libnm-core-impl/nm-setting-bond-port.c4
-rw-r--r--src/libnm-core-impl/nm-setting-bond.c86
-rw-r--r--src/libnm-core-impl/nm-setting-connection.c65
-rw-r--r--src/libnm-core-impl/nm-setting-ethtool.c8
-rw-r--r--src/libnm-core-impl/nm-setting-gsm.c186
-rw-r--r--src/libnm-core-impl/nm-setting-infiniband.c44
-rw-r--r--src/libnm-core-impl/nm-setting-ip-config.c58
-rw-r--r--src/libnm-core-impl/nm-setting-ip4-config.c58
-rw-r--r--src/libnm-core-impl/nm-setting-ip6-config.c274
-rw-r--r--src/libnm-core-impl/nm-setting-link.c241
-rw-r--r--src/libnm-core-impl/nm-setting-match.c8
-rw-r--r--src/libnm-core-impl/nm-setting-ovs-external-ids.c6
-rw-r--r--src/libnm-core-impl/nm-setting-ovs-other-config.c2
-rw-r--r--src/libnm-core-impl/nm-setting-sriov.c8
-rw-r--r--src/libnm-core-impl/nm-setting-tc-config.c15
-rw-r--r--src/libnm-core-impl/nm-setting-team.c6
-rw-r--r--src/libnm-core-impl/nm-setting-user.c4
-rw-r--r--src/libnm-core-impl/nm-setting-vlan.c4
-rw-r--r--src/libnm-core-impl/nm-setting-vpn.c12
-rw-r--r--src/libnm-core-impl/nm-setting-wired.c13
-rw-r--r--src/libnm-core-impl/nm-setting-wireguard.c20
-rw-r--r--src/libnm-core-impl/nm-setting-wireless.c61
-rw-r--r--src/libnm-core-impl/nm-setting.c22
-rw-r--r--src/libnm-core-impl/nm-utils.c71
-rw-r--r--src/libnm-core-impl/nm-vpn-editor-plugin.c2
-rw-r--r--src/libnm-core-impl/nm-vpn-plugin-info.c12
-rw-r--r--src/libnm-core-impl/tests/test-general.c99
-rw-r--r--src/libnm-core-impl/tests/test-setting.c3
34 files changed, 1255 insertions, 441 deletions
diff --git a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in
index 4a6e70fe..4e17a45b 100644
--- a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in
+++ b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in
@@ -124,6 +124,7 @@
                   gprop-type="guint"
                   />
         <property name="rate"
+                  is-deprecated="1"
                   dbus-type="u"
                   gprop-type="guint"
                   />
@@ -140,6 +141,7 @@
                   gprop-type="GBytes"
                   />
         <property name="tx-power"
+                  is-deprecated="1"
                   dbus-type="u"
                   gprop-type="guint"
                   />
@@ -830,6 +832,7 @@
                   gprop-type="GStrv"
                   />
         <property name="read-only"
+                  is-deprecated="1"
                   dbus-type="b"
                   gprop-type="gboolean"
                   />
@@ -1317,6 +1320,14 @@
                   dbus-type="b"
                   gprop-type="gboolean"
                   />
+        <property name="initial-eps-bearer-apn"
+                  dbus-type="s"
+                  gprop-type="gchararray"
+                  />
+        <property name="initial-eps-bearer-configure"
+                  dbus-type="b"
+                  gprop-type="gboolean"
+                  />
         <property name="mtu"
                   dbus-type="u"
                   gprop-type="guint"
@@ -1645,6 +1656,10 @@
                   dbus-type="s"
                   gprop-type="gchararray"
                   />
+        <property name="dhcp-pd-hint"
+                  dbus-type="s"
+                  gprop-type="gchararray"
+                  />
         <property name="dhcp-reject-servers"
                   dbus-type="as"
                   gprop-type="GStrv"
@@ -1745,6 +1760,26 @@
                   gprop-type="gchararray"
                   />
     </setting>
+    <setting name="link"
+             gtype="NMSettingLink"
+             >
+        <property name="gro-max-size"
+                  dbus-type="x"
+                  gprop-type="gint64"
+                  />
+        <property name="gso-max-segments"
+                  dbus-type="x"
+                  gprop-type="gint64"
+                  />
+        <property name="gso-max-size"
+                  dbus-type="x"
+                  gprop-type="gint64"
+                  />
+        <property name="tx-queue-length"
+                  dbus-type="x"
+                  gprop-type="gint64"
+                  />
+    </setting>
     <setting name="loopback"
              gtype="NMSettingLoopback"
              >
diff --git a/src/libnm-core-impl/meson.build b/src/libnm-core-impl/meson.build
index 6408ae17..635b417b 100644
--- a/src/libnm-core-impl/meson.build
+++ b/src/libnm-core-impl/meson.build
@@ -24,6 +24,7 @@ libnm_core_settings_sources = files(
   'nm-setting-ip-tunnel.c',
   'nm-setting-ip4-config.c',
   'nm-setting-ip6-config.c',
+  'nm-setting-link.c',
   'nm-setting-loopback.c',
   'nm-setting-macsec.c',
   'nm-setting-macvlan.c',
diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c
index b017a6e5..6ffc750a 100644
--- a/src/libnm-core-impl/nm-connection.c
+++ b/src/libnm-core-impl/nm-connection.c
@@ -276,26 +276,7 @@ nm_connection_remove_setting(NMConnection *connection, GType setting_type)
 }
 
 static gpointer
-_connection_get_setting(NMConnection *connection, GType setting_type)
-{
-    NMSetting               *setting;
-    const NMMetaSettingInfo *setting_info;
-
-    nm_assert(NM_IS_CONNECTION(connection));
-    nm_assert(g_type_is_a(setting_type, NM_TYPE_SETTING));
-
-    setting_info = _nm_meta_setting_info_from_gtype(setting_type);
-    if (!setting_info)
-        g_return_val_if_reached(NULL);
-
-    setting = NM_CONNECTION_GET_PRIVATE(connection)->settings[setting_info->meta_type];
-
-    nm_assert(!setting || G_TYPE_CHECK_INSTANCE_TYPE(setting, setting_type));
-    return setting;
-}
-
-static gpointer
-_connection_get_setting_by_meta_type(NMConnectionPrivate *priv, NMMetaSettingType meta_type)
+_get_setting_by_metatype(NMConnectionPrivate *priv, NMMetaSettingType meta_type)
 {
     nm_assert(priv);
     nm_assert(_NM_INT_NOT_NEGATIVE(meta_type));
@@ -304,20 +285,15 @@ _connection_get_setting_by_meta_type(NMConnectionPrivate *priv, NMMetaSettingTyp
     return priv->settings[meta_type];
 }
 
-static gpointer
-_connection_get_setting_check(NMConnection *connection, GType setting_type)
+/* The "unsafe" part here is that _nm_connection_get_setting_by_metatype() has a compile
+ * time check that meta_type is valid. With the unsafe variant, the caller must ensure that,
+ * and we only get an nm_assert() check -- which is basically nothing. */
+gpointer
+_nm_connection_get_setting_by_metatype_unsafe(NMConnection *connection, NMMetaSettingType meta_type)
 {
     g_return_val_if_fail(NM_IS_CONNECTION(connection), NULL);
 
-    return _connection_get_setting(connection, setting_type);
-}
-
-static gpointer
-_connection_get_setting_by_meta_type_check(NMConnection *connection, NMMetaSettingType meta_type)
-{
-    g_return_val_if_fail(NM_IS_CONNECTION(connection), NULL);
-
-    return _connection_get_setting_by_meta_type(NM_CONNECTION_GET_PRIVATE(connection), meta_type);
+    return _get_setting_by_metatype(NM_CONNECTION_GET_PRIVATE(connection), meta_type);
 }
 
 /**
@@ -334,19 +310,34 @@ _connection_get_setting_by_meta_type_check(NMConnection *connection, NMMetaSetti
 NMSetting *
 nm_connection_get_setting(NMConnection *connection, GType setting_type)
 {
-    g_return_val_if_fail(g_type_is_a(setting_type, NM_TYPE_SETTING), NULL);
+    NMSetting               *setting;
+    const NMMetaSettingInfo *setting_info;
 
-    return _connection_get_setting_check(connection, setting_type);
+    g_return_val_if_fail(NM_IS_CONNECTION(connection), NULL);
+
+    setting_info = _nm_meta_setting_info_from_gtype(setting_type);
+
+    if (!setting_info)
+        g_return_val_if_reached(NULL);
+
+    setting = NM_CONNECTION_GET_PRIVATE(connection)->settings[setting_info->meta_type];
+
+    nm_assert(!setting || G_TYPE_CHECK_INSTANCE_TYPE(setting, setting_type));
+
+    return setting;
 }
 
 NMSettingIPConfig *
 nm_connection_get_setting_ip_config(NMConnection *connection, int addr_family)
 {
+    g_return_val_if_fail(NM_IS_CONNECTION(connection), NULL);
+
     nm_assert_addr_family(addr_family);
 
-    return NM_SETTING_IP_CONFIG(_connection_get_setting(
-        connection,
-        (addr_family == AF_INET) ? NM_TYPE_SETTING_IP4_CONFIG : NM_TYPE_SETTING_IP6_CONFIG));
+    return NM_SETTING_IP_CONFIG(_get_setting_by_metatype(NM_CONNECTION_GET_PRIVATE(connection),
+                                                         (addr_family == AF_INET)
+                                                             ? NM_META_SETTING_TYPE_IP4_CONFIG
+                                                             : NM_META_SETTING_TYPE_IP6_CONFIG));
 }
 
 /**
@@ -363,12 +354,14 @@ nm_connection_get_setting_ip_config(NMConnection *connection, int addr_family)
 NMSetting *
 nm_connection_get_setting_by_name(NMConnection *connection, const char *name)
 {
-    GType type;
+    const NMMetaSettingInfo *setting_info;
 
     g_return_val_if_fail(NM_IS_CONNECTION(connection), NULL);
 
-    type = nm_setting_lookup_type(name);
-    return type ? _connection_get_setting(connection, type) : NULL;
+    setting_info = nm_meta_setting_infos_by_name(name);
+    return setting_info ? _get_setting_by_metatype(NM_CONNECTION_GET_PRIVATE(connection),
+                                                   setting_info->meta_type)
+                        : NULL;
 }
 
 /*****************************************************************************/
@@ -764,10 +757,11 @@ diff_one_connection(NMConnection         *a,
  * @a: a #NMConnection
  * @b: a second #NMConnection to compare with the first
  * @flags: compare flags, e.g. %NM_SETTING_COMPARE_FLAG_EXACT
- * @out_settings: (element-type utf8 GLib.HashTable): if the
- * connections differ, on return a hash table mapping setting names to
- * second-level GHashTable (utf8 to guint32), which contains the key names that
- * differ mapped to one or more of %NMSettingDiffResult as a bitfield
+ * @out_settings: (out) (element-type utf8 GLib.HashTable(utf8,uint32)) (optional) (nullable):
+ * if the connections differ, on return a hash table
+ * mapping setting names to second-level GHashTable (utf8 to guint32), which
+ * contains the key names that differ mapped to one or more of
+ * %NMSettingDiffResult as a bitfield
  *
  * Compares two #NMConnection objects for similarity, with comparison behavior
  * modified by a set of flags.  See nm_setting_compare() for a description of
@@ -882,6 +876,20 @@ _normalize_connection_uuid(NMConnection *self)
     return TRUE;
 }
 
+static gboolean
+_normalize_connection(NMConnection *self)
+{
+    NMSettingConnection *s_con   = nm_connection_get_setting_connection(self);
+    gboolean             changed = FALSE;
+
+    if (nm_setting_connection_get_read_only(s_con)) {
+        g_object_set(s_con, NM_SETTING_CONNECTION_READ_ONLY, FALSE, NULL);
+        changed = TRUE;
+    }
+
+    return changed;
+}
+
 gboolean
 _nm_setting_connection_verify_secondaries(GArray *secondaries, GError **error)
 {
@@ -1471,6 +1479,28 @@ _normalize_wireless_mac_address_randomization(NMConnection *self)
 }
 
 static gboolean
+_normalize_wireless(NMConnection *self)
+{
+    NMSettingWireless *s_wifi  = nm_connection_get_setting_wireless(self);
+    gboolean           changed = FALSE;
+
+    if (!s_wifi)
+        return FALSE;
+
+    if (nm_setting_wireless_get_rate(s_wifi) != 0) {
+        g_object_set(s_wifi, NM_SETTING_WIRELESS_RATE, 0u, NULL);
+        changed = TRUE;
+    }
+
+    if (nm_setting_wireless_get_tx_power(s_wifi) != 0) {
+        g_object_set(s_wifi, NM_SETTING_WIRELESS_TX_POWER, 0u, NULL);
+        changed = TRUE;
+    }
+
+    return changed;
+}
+
+static gboolean
 _normalize_macsec(NMConnection *self)
 {
     NMSettingMacsec *s_macsec = nm_connection_get_setting_macsec(self);
@@ -1658,8 +1688,8 @@ _normalize_802_1x_empty_strings(NMConnection *self)
     NMSetting8021x *s_8021x;
     gboolean        changed = FALSE;
 
-    s_8021x = _connection_get_setting_by_meta_type(NM_CONNECTION_GET_PRIVATE(self),
-                                                   NM_META_SETTING_TYPE_802_1X);
+    s_8021x =
+        _get_setting_by_metatype(NM_CONNECTION_GET_PRIVATE(self), NM_META_SETTING_TYPE_802_1X);
     if (!s_8021x)
         return FALSE;
 
@@ -1809,7 +1839,7 @@ _nm_connection_verify(NMConnection *connection, GError **error)
 
     priv = NM_CONNECTION_GET_PRIVATE(connection);
 
-    if (!_connection_get_setting_by_meta_type(priv, NM_META_SETTING_TYPE_CONNECTION)) {
+    if (!_get_setting_by_metatype(priv, NM_META_SETTING_TYPE_CONNECTION)) {
         g_set_error_literal(error,
                             NM_CONNECTION_ERROR,
                             NM_CONNECTION_ERROR_MISSING_SETTING,
@@ -1854,9 +1884,9 @@ _nm_connection_verify(NMConnection *connection, GError **error)
         g_clear_error(&verify_error);
     }
 
-    s_ip4   = _connection_get_setting_by_meta_type(priv, NM_META_SETTING_TYPE_IP4_CONFIG);
-    s_ip6   = _connection_get_setting_by_meta_type(priv, NM_META_SETTING_TYPE_IP6_CONFIG);
-    s_proxy = _connection_get_setting_by_meta_type(priv, NM_META_SETTING_TYPE_PROXY);
+    s_ip4   = _get_setting_by_metatype(priv, NM_META_SETTING_TYPE_IP4_CONFIG);
+    s_ip6   = _get_setting_by_metatype(priv, NM_META_SETTING_TYPE_IP6_CONFIG);
+    s_proxy = _get_setting_by_metatype(priv, NM_META_SETTING_TYPE_PROXY);
 
     nm_assert(normalizable_error_type != NM_SETTING_VERIFY_ERROR);
     if (NM_IN_SET(normalizable_error_type,
@@ -2005,6 +2035,7 @@ _connection_normalize(NMConnection *connection,
     was_modified |= _normalize_connection_type(connection);
     was_modified |= _normalize_connection_slave_type(connection);
     was_modified |= _normalize_connection_secondaries(connection);
+    was_modified |= _normalize_connection(connection);
     was_modified |= _normalize_required_settings(connection);
     was_modified |= _normalize_invalid_slave_port_settings(connection);
     was_modified |= _normalize_ip_config(connection, parameters);
@@ -2013,6 +2044,7 @@ _connection_normalize(NMConnection *connection,
     was_modified |= _normalize_bond_mode(connection);
     was_modified |= _normalize_bond_options(connection);
     was_modified |= _normalize_wireless_mac_address_randomization(connection);
+    was_modified |= _normalize_wireless(connection);
     was_modified |= _normalize_macsec(connection);
     was_modified |= _normalize_team_config(connection);
     was_modified |= _normalize_team_port_config(connection);
@@ -2057,12 +2089,12 @@ _connection_normalize(NMConnection *connection,
 /**
  * nm_connection_normalize:
  * @connection: the #NMConnection to normalize
- * @parameters: (allow-none) (element-type utf8 gpointer): a #GHashTable with
+ * @parameters: (nullable) (element-type utf8 gpointer): a #GHashTable with
  * normalization parameters to allow customization of the normalization by providing
  * specific arguments. Unknown arguments will be ignored and the default will be
  * used. The keys must be strings compared with g_str_equal() function.
  * The values are opaque and depend on the parameter name.
- * @modified: (out) (allow-none): outputs whether any settings were modified.
+ * @modified: (out) (optional): outputs whether any settings were modified.
  * @error: location to store error, or %NULL. Contains the reason,
  * why the connection is invalid, if the function returns an error.
  *
@@ -2413,7 +2445,7 @@ _need_secrets(NMConnection *connection, gboolean check_rerequest, GPtrArray **hi
 /**
  * nm_connection_need_secrets:
  * @connection: the #NMConnection
- * @hints: (out) (element-type utf8) (allow-none) (transfer container):
+ * @hints: (out) (element-type utf8) (nullable) (transfer container):
  *   the address of a pointer to a #GPtrArray, initialized to %NULL, which on
  *   return points to an allocated #GPtrArray containing the property names of
  *   secrets of the #NMSetting which may be required; the caller owns the array
@@ -2426,8 +2458,8 @@ _need_secrets(NMConnection *connection, gboolean check_rerequest, GPtrArray **hi
  * circumstances, there is no way to conclusively determine exactly which
  * secrets are needed.
  *
- * Returns: the setting name of the #NMSetting object which has invalid or
- *   missing secrets
+ * Returns: (nullable): the setting name of the #NMSetting object which has
+ *   invalid or missing secrets
  **/
 const char *
 nm_connection_need_secrets(NMConnection *connection, GPtrArray **hints)
@@ -2442,7 +2474,7 @@ nm_connection_need_secrets(NMConnection *connection, GPtrArray **hints)
  * nm_connection_need_secrets_for_rerequest:
  * @connection: the #NMConnection
  *
- * Returns TRUE if some secret needs to be re-requested
+ * Returns: %TRUE if some secret needs to be re-requested
  **/
 gboolean
 nm_connection_need_secrets_for_rerequest(NMConnection *connection)
@@ -2468,7 +2500,7 @@ nm_connection_clear_secrets(NMConnection *connection)
 /**
  * nm_connection_clear_secrets_with_flags:
  * @connection: the #NMConnection
- * @func: (scope call) (allow-none): function to be called to determine whether a
+ * @func: (scope call) (nullable): function to be called to determine whether a
  *     specific secret should be cleared or not. If %NULL, all secrets are cleared.
  * @user_data: caller-supplied data passed to @func
  *
@@ -2780,15 +2812,14 @@ _nm_connection_get_settings_arr(NMConnection *connection)
 /**
  * nm_connection_get_settings:
  * @connection: the #NMConnection instance
- * @out_length: (allow-none) (out): the length of the returned array
+ * @out_length: (out) (optional): the length of the returned array
  *
  * Retrieves the settings in @connection.
  *
  * The returned array is %NULL-terminated.
  *
- * Returns: (array length=out_length) (transfer container): a
- *   %NULL-terminated array containing every setting of
- *   @connection.
+ * Returns: (array length=out_length) (transfer container) (nullable): a
+ *   %NULL-terminated array containing every setting of @connection.
  *   If the connection has no settings, %NULL is returned.
  *
  * Since: 1.10
@@ -3247,7 +3278,7 @@ nm_connection_get_virtual_device_description(NMConnection *connection)
 NMSetting8021x *
 nm_connection_get_setting_802_1x(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_802_1X);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_802_1X);
 }
 
 /**
@@ -3261,7 +3292,7 @@ nm_connection_get_setting_802_1x(NMConnection *connection)
 NMSettingBluetooth *
 nm_connection_get_setting_bluetooth(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_BLUETOOTH);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_BLUETOOTH);
 }
 
 /**
@@ -3275,7 +3306,7 @@ nm_connection_get_setting_bluetooth(NMConnection *connection)
 NMSettingBond *
 nm_connection_get_setting_bond(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_BOND);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_BOND);
 }
 
 /**
@@ -3289,7 +3320,7 @@ nm_connection_get_setting_bond(NMConnection *connection)
 NMSettingTeam *
 nm_connection_get_setting_team(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_TEAM);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_TEAM);
 }
 
 /**
@@ -3303,7 +3334,7 @@ nm_connection_get_setting_team(NMConnection *connection)
 NMSettingTeamPort *
 nm_connection_get_setting_team_port(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_TEAM_PORT);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_TEAM_PORT);
 }
 
 /**
@@ -3317,7 +3348,7 @@ nm_connection_get_setting_team_port(NMConnection *connection)
 NMSettingBridge *
 nm_connection_get_setting_bridge(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_BRIDGE);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_BRIDGE);
 }
 
 /**
@@ -3331,7 +3362,7 @@ nm_connection_get_setting_bridge(NMConnection *connection)
 NMSettingCdma *
 nm_connection_get_setting_cdma(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_CDMA);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_CDMA);
 }
 
 /**
@@ -3345,7 +3376,7 @@ nm_connection_get_setting_cdma(NMConnection *connection)
 NMSettingConnection *
 nm_connection_get_setting_connection(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_CONNECTION);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_CONNECTION);
 }
 
 /**
@@ -3359,7 +3390,7 @@ nm_connection_get_setting_connection(NMConnection *connection)
 NMSettingDcb *
 nm_connection_get_setting_dcb(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_DCB);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_DCB);
 }
 
 /**
@@ -3375,7 +3406,7 @@ nm_connection_get_setting_dcb(NMConnection *connection)
 NMSettingDummy *
 nm_connection_get_setting_dummy(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_DUMMY);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_DUMMY);
 }
 
 /**
@@ -3389,7 +3420,7 @@ nm_connection_get_setting_dummy(NMConnection *connection)
 NMSettingGeneric *
 nm_connection_get_setting_generic(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_GENERIC);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_GENERIC);
 }
 
 /**
@@ -3403,7 +3434,7 @@ nm_connection_get_setting_generic(NMConnection *connection)
 NMSettingGsm *
 nm_connection_get_setting_gsm(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_GSM);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_GSM);
 }
 
 /**
@@ -3417,7 +3448,7 @@ nm_connection_get_setting_gsm(NMConnection *connection)
 NMSettingInfiniband *
 nm_connection_get_setting_infiniband(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_INFINIBAND);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_INFINIBAND);
 }
 
 /**
@@ -3436,7 +3467,7 @@ nm_connection_get_setting_infiniband(NMConnection *connection)
 NMSettingIPConfig *
 nm_connection_get_setting_ip4_config(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_IP4_CONFIG);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_IP4_CONFIG);
 }
 
 /**
@@ -3452,7 +3483,7 @@ nm_connection_get_setting_ip4_config(NMConnection *connection)
 NMSettingIPTunnel *
 nm_connection_get_setting_ip_tunnel(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_IP_TUNNEL);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_IP_TUNNEL);
 }
 
 /**
@@ -3471,7 +3502,7 @@ nm_connection_get_setting_ip_tunnel(NMConnection *connection)
 NMSettingIPConfig *
 nm_connection_get_setting_ip6_config(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_IP6_CONFIG);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_IP6_CONFIG);
 }
 
 /**
@@ -3487,7 +3518,7 @@ nm_connection_get_setting_ip6_config(NMConnection *connection)
 NMSettingMacsec *
 nm_connection_get_setting_macsec(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_MACSEC);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_MACSEC);
 }
 
 /**
@@ -3503,7 +3534,7 @@ nm_connection_get_setting_macsec(NMConnection *connection)
 NMSettingMacvlan *
 nm_connection_get_setting_macvlan(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_MACVLAN);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_MACVLAN);
 }
 
 /**
@@ -3517,7 +3548,7 @@ nm_connection_get_setting_macvlan(NMConnection *connection)
 NMSettingOlpcMesh *
 nm_connection_get_setting_olpc_mesh(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_OLPC_MESH);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_OLPC_MESH);
 }
 
 /**
@@ -3533,7 +3564,7 @@ nm_connection_get_setting_olpc_mesh(NMConnection *connection)
 NMSettingOvsBridge *
 nm_connection_get_setting_ovs_bridge(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_OVS_BRIDGE);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_OVS_BRIDGE);
 }
 
 /**
@@ -3549,8 +3580,7 @@ nm_connection_get_setting_ovs_bridge(NMConnection *connection)
 NMSettingOvsInterface *
 nm_connection_get_setting_ovs_interface(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection,
-                                                      NM_META_SETTING_TYPE_OVS_INTERFACE);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_OVS_INTERFACE);
 }
 
 /**
@@ -3566,7 +3596,7 @@ nm_connection_get_setting_ovs_interface(NMConnection *connection)
 NMSettingOvsPatch *
 nm_connection_get_setting_ovs_patch(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_OVS_PATCH);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_OVS_PATCH);
 }
 
 /**
@@ -3582,7 +3612,7 @@ nm_connection_get_setting_ovs_patch(NMConnection *connection)
 NMSettingOvsPort *
 nm_connection_get_setting_ovs_port(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_OVS_PORT);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_OVS_PORT);
 }
 
 /**
@@ -3596,7 +3626,7 @@ nm_connection_get_setting_ovs_port(NMConnection *connection)
 NMSettingPpp *
 nm_connection_get_setting_ppp(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_PPP);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_PPP);
 }
 
 /**
@@ -3610,7 +3640,7 @@ nm_connection_get_setting_ppp(NMConnection *connection)
 NMSettingPppoe *
 nm_connection_get_setting_pppoe(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_PPPOE);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_PPPOE);
 }
 
 /**
@@ -3626,7 +3656,7 @@ nm_connection_get_setting_pppoe(NMConnection *connection)
 NMSettingProxy *
 nm_connection_get_setting_proxy(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_PROXY);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_PROXY);
 }
 
 /**
@@ -3640,7 +3670,7 @@ nm_connection_get_setting_proxy(NMConnection *connection)
 NMSettingSerial *
 nm_connection_get_setting_serial(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_SERIAL);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_SERIAL);
 }
 
 /**
@@ -3656,7 +3686,7 @@ nm_connection_get_setting_serial(NMConnection *connection)
 NMSettingTCConfig *
 nm_connection_get_setting_tc_config(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_TC_CONFIG);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_TC_CONFIG);
 }
 
 /**
@@ -3672,7 +3702,7 @@ nm_connection_get_setting_tc_config(NMConnection *connection)
 NMSettingTun *
 nm_connection_get_setting_tun(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_TUN);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_TUN);
 }
 
 /**
@@ -3686,7 +3716,7 @@ nm_connection_get_setting_tun(NMConnection *connection)
 NMSettingVpn *
 nm_connection_get_setting_vpn(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_VPN);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_VPN);
 }
 
 /**
@@ -3702,7 +3732,7 @@ nm_connection_get_setting_vpn(NMConnection *connection)
 NMSettingVxlan *
 nm_connection_get_setting_vxlan(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_VXLAN);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_VXLAN);
 }
 
 /**
@@ -3716,7 +3746,7 @@ nm_connection_get_setting_vxlan(NMConnection *connection)
 NMSettingWimax *
 nm_connection_get_setting_wimax(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_WIMAX);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_WIMAX);
 }
 
 /**
@@ -3730,7 +3760,7 @@ nm_connection_get_setting_wimax(NMConnection *connection)
 NMSettingWired *
 nm_connection_get_setting_wired(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_WIRED);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_WIRED);
 }
 
 /**
@@ -3744,7 +3774,7 @@ nm_connection_get_setting_wired(NMConnection *connection)
 NMSettingAdsl *
 nm_connection_get_setting_adsl(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_ADSL);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_ADSL);
 }
 
 /**
@@ -3758,7 +3788,7 @@ nm_connection_get_setting_adsl(NMConnection *connection)
 NMSettingWireless *
 nm_connection_get_setting_wireless(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_WIRELESS);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_WIRELESS);
 }
 
 /**
@@ -3772,8 +3802,8 @@ nm_connection_get_setting_wireless(NMConnection *connection)
 NMSettingWirelessSecurity *
 nm_connection_get_setting_wireless_security(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection,
-                                                      NM_META_SETTING_TYPE_WIRELESS_SECURITY);
+    return _nm_connection_get_setting_by_metatype(connection,
+                                                  NM_META_SETTING_TYPE_WIRELESS_SECURITY);
 }
 
 /**
@@ -3787,7 +3817,7 @@ nm_connection_get_setting_wireless_security(NMConnection *connection)
 NMSettingBridgePort *
 nm_connection_get_setting_bridge_port(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_BRIDGE_PORT);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_BRIDGE_PORT);
 }
 
 /**
@@ -3801,7 +3831,7 @@ nm_connection_get_setting_bridge_port(NMConnection *connection)
 NMSettingVlan *
 nm_connection_get_setting_vlan(NMConnection *connection)
 {
-    return _connection_get_setting_by_meta_type_check(connection, NM_META_SETTING_TYPE_VLAN);
+    return _nm_connection_get_setting_by_metatype(connection, NM_META_SETTING_TYPE_VLAN);
 }
 
 NMSettingBluetooth *
diff --git a/src/libnm-core-impl/nm-keyfile.c b/src/libnm-core-impl/nm-keyfile.c
index 9a6ffc6f..82581d9f 100644
--- a/src/libnm-core-impl/nm-keyfile.c
+++ b/src/libnm-core-impl/nm-keyfile.c
@@ -3911,9 +3911,9 @@ nm_keyfile_read_ensure_uuid(NMConnection *connection, const char *fallback_uuid_
  *   the relative path is made absolute using @base_dir. This must
  *   be an absolute path.
  * @handler_flags: the #NMKeyfileHandlerFlags.
- * @handler: (allow-none) (scope call): read handler
+ * @handler: (nullable) (scope call): read handler
  * @user_data: user data for read handler
- * @error: (allow-none) (out): error
+ * @error: error
  *
  * Tries to create a NMConnection from a keyfile. The resulting keyfile is
  * not normalized and might not even verify.
@@ -4256,7 +4256,7 @@ _write_setting_wireguard(NMSetting *setting, KeyfileWriterInfo *info)
  * nm_keyfile_write:
  * @connection: the #NMConnection to persist to keyfile.
  * @handler_flags: the #NMKeyfileHandlerFlags.
- * @handler: (allow-none) (scope call): optional handler for events and
+ * @handler: (nullable) (scope call): optional handler for events and
  *   to override the default behavior.
  * @user_data: argument for @handler.
  * @error: the #GError in case writing fails.
@@ -4554,13 +4554,14 @@ nm_keyfile_handler_data_fail_with_error(NMKeyfileHandlerData *handler_data, GErr
 /**
  * nm_keyfile_handler_data_get_context:
  * @handler_data: the #NMKeyfileHandlerData for any event.
- * @out_kf_group_name: (out) (allow-none) (transfer none): if the event is in the
- *   context of a keyfile group, the group name.
- * @out_kf_key_name: (out) (allow-none) (transfer none): if the event is in the
- *   context of a keyfile value, the key name.
- * @out_cur_setting: (out) (allow-none) (transfer none): if the event happens while
- *   handling a particular #NMSetting instance.
- * @out_cur_property_name: (out) (allow-none) (transfer none): the property name if applicable.
+ * @out_kf_group_name: (out) (optional) (nullable) (transfer none): if the event
+ *   is in the context of a keyfile group, the group name.
+ * @out_kf_key_name: (out) (optional) (nullable) (transfer none): if the event
+ *   is in the context of a keyfile value, the key name.
+ * @out_cur_setting: (out) (optional) (nullable) (transfer none): if the event
+ *   happens while handling a particular #NMSetting instance.
+ * @out_cur_property_name: (out) (optional) (nullable) (transfer none): the
+ *   property name if applicable.
  *
  * Get context information of the current event. This function can be called
  * on all events, but the context information may be unset.
@@ -4605,8 +4606,8 @@ _nm_keyfile_handler_data_warn_get_message(const NMKeyfileHandlerData *handler_da
  * nm_keyfile_handler_data_warn_get:
  * @handler_data: the #NMKeyfileHandlerData for a %NM_KEYFILE_HANDLER_TYPE_WARN
  *  event.
- * @out_message: (out) (allow-none) (transfer none): the warning message.
- * @out_severity: (out) (allow-none): the #NMKeyfileWarnSeverity warning severity.
+ * @out_message: (out) (optional) (transfer none): the warning message.
+ * @out_severity: (out) (optional): the #NMKeyfileWarnSeverity warning severity.
  *
  * Since: 1.30
  */
diff --git a/src/libnm-core-impl/nm-meta-setting-base-impl.c b/src/libnm-core-impl/nm-meta-setting-base-impl.c
index 19082671..b531ae85 100644
--- a/src/libnm-core-impl/nm-meta-setting-base-impl.c
+++ b/src/libnm-core-impl/nm-meta-setting-base-impl.c
@@ -34,6 +34,7 @@
 #include "nm-setting-ip-tunnel.h"
 #include "nm-setting-ip4-config.h"
 #include "nm-setting-ip6-config.h"
+#include "nm-setting-link.h"
 #include "nm-setting-loopback.h"
 #include "nm-setting-macsec.h"
 #include "nm-setting-macvlan.h"
@@ -362,6 +363,13 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = {
             .setting_name      = NM_SETTING_IP_TUNNEL_SETTING_NAME,
             .get_setting_gtype = nm_setting_ip_tunnel_get_type,
         },
+    [NM_META_SETTING_TYPE_LINK] =
+        {
+            .meta_type         = NM_META_SETTING_TYPE_LINK,
+            .setting_priority  = NM_SETTING_PRIORITY_AUX,
+            .setting_name      = NM_SETTING_LINK_SETTING_NAME,
+            .get_setting_gtype = nm_setting_link_get_type,
+        },
     [NM_META_SETTING_TYPE_LOOPBACK] =
         {
             .meta_type         = NM_META_SETTING_TYPE_LOOPBACK,
@@ -660,6 +668,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = {
     NM_META_SETTING_TYPE_BOND_PORT,
     NM_META_SETTING_TYPE_BRIDGE_PORT,
     NM_META_SETTING_TYPE_ETHTOOL,
+    NM_META_SETTING_TYPE_LINK,
     NM_META_SETTING_TYPE_MATCH,
     NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS,
     NM_META_SETTING_TYPE_OVS_OTHER_CONFIG,
diff --git a/src/libnm-core-impl/nm-setting-8021x.c b/src/libnm-core-impl/nm-setting-8021x.c
index 1bc4de9d..626673e8 100644
--- a/src/libnm-core-impl/nm-setting-8021x.c
+++ b/src/libnm-core-impl/nm-setting-8021x.c
@@ -208,9 +208,9 @@ G_DEFINE_TYPE(NMSetting8021x, nm_setting_802_1x, NM_TYPE_SETTING)
 
 /**
  * nm_setting_802_1x_check_cert_scheme:
- * @pdata: (allow-none): the data pointer
+ * @pdata: (nullable): the data pointer
  * @length: the length of the data
- * @error: (allow-none) (out): validation reason
+ * @error: validation reason
  *
  * Determines and verifies the blob type.
  * When setting certificate properties of NMSetting8021x
diff --git a/src/libnm-core-impl/nm-setting-bond-port.c b/src/libnm-core-impl/nm-setting-bond-port.c
index 16512a6a..e8917902 100644
--- a/src/libnm-core-impl/nm-setting-bond-port.c
+++ b/src/libnm-core-impl/nm-setting-bond-port.c
@@ -72,7 +72,7 @@ nm_setting_bond_port_get_queue_id(NMSettingBondPort *setting)
  *
  * Returns: the #NMSettingBondPort:prio property of the setting
  *
- * Since: 1.44, 1.42.8
+ * Since: 1.44
  **/
 gint32
 nm_setting_bond_port_get_prio(NMSettingBondPort *setting)
@@ -190,7 +190,7 @@ nm_setting_bond_port_class_init(NMSettingBondPortClass *klass)
      * the highest priority. This option is only compatible with active-backup,
      * balance-tlb and balance-alb modes.
      *
-     * Since: 1.44, 1.42.8
+     * Since: 1.44
      **/
     /* ---ifcfg-rh---
      * property: prio
diff --git a/src/libnm-core-impl/nm-setting-bond.c b/src/libnm-core-impl/nm-setting-bond.c
index 54030e0b..81c67d51 100644
--- a/src/libnm-core-impl/nm-setting-bond.c
+++ b/src/libnm-core-impl/nm-setting-bond.c
@@ -92,6 +92,9 @@ static const char *const valid_options_lst[] = {
     NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB,
     NM_SETTING_BOND_OPTION_LP_INTERVAL,
     NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY,
+    NM_SETTING_BOND_OPTION_ARP_MISSED_MAX,
+    NM_SETTING_BOND_OPTION_LACP_ACTIVE,
+    NM_SETTING_BOND_OPTION_NS_IP6_TARGET,
     NULL,
 };
 
@@ -133,6 +136,7 @@ _nm_assert_bond_meta(const OptionMeta *option_meta)
         }));
         return TRUE;
     case NM_BOND_OPTION_TYPE_IP:
+    case NM_BOND_OPTION_TYPE_IP6:
         nm_assert(option_meta->val);
         /* fall-through */
     case NM_BOND_OPTION_TYPE_IFNAME:
@@ -154,8 +158,9 @@ static char const *const _option_default_strv_arp_validate[] =
     NM_MAKE_STRV("none", "active", "backup", "all", "filter", "filter_active", "filter_backup");
 static char const *const _option_default_strv_fail_over_mac[] =
     NM_MAKE_STRV("none", "active", "follow");
-static char const *const _option_default_strv_lacp_rate[] = NM_MAKE_STRV("slow", "fast");
-static char const *const _option_default_strv_mode[]      = NM_MAKE_STRV("balance-rr",
+static char const *const _option_default_strv_lacp_rate[]   = NM_MAKE_STRV("slow", "fast");
+static char const *const _option_default_strv_lacp_active[] = NM_MAKE_STRV("off", "on");
+static char const *const _option_default_strv_mode[]        = NM_MAKE_STRV("balance-rr",
                                                                     "active-backup",
                                                                     "balance-xor",
                                                                     "broadcast",
@@ -194,12 +199,15 @@ static NM_UTILS_STRING_TABLE_LOOKUP_STRUCT_DEFINE(
      {"any", NM_BOND_OPTION_TYPE_BOTH, 0, 1, _option_default_strv_arp_all_targets}},
     {NM_SETTING_BOND_OPTION_ARP_INTERVAL, {"0", NM_BOND_OPTION_TYPE_INT, 0, G_MAXINT}},
     {NM_SETTING_BOND_OPTION_ARP_IP_TARGET, {"", NM_BOND_OPTION_TYPE_IP}},
+    {NM_SETTING_BOND_OPTION_ARP_MISSED_MAX, {"0", NM_BOND_OPTION_TYPE_INT, 0, 255}},
     {NM_SETTING_BOND_OPTION_ARP_VALIDATE,
      {"none", NM_BOND_OPTION_TYPE_BOTH, 0, 6, _option_default_strv_arp_validate}},
     {NM_SETTING_BOND_OPTION_BALANCE_SLB, {"0", NM_BOND_OPTION_TYPE_INT, 0, 1}},
     {NM_SETTING_BOND_OPTION_DOWNDELAY, {"0", NM_BOND_OPTION_TYPE_INT, 0, G_MAXINT}},
     {NM_SETTING_BOND_OPTION_FAIL_OVER_MAC,
      {"none", NM_BOND_OPTION_TYPE_BOTH, 0, 2, _option_default_strv_fail_over_mac}},
+    {NM_SETTING_BOND_OPTION_LACP_ACTIVE,
+     {"on", NM_BOND_OPTION_TYPE_BOTH, 0, 1, _option_default_strv_lacp_active}},
     {NM_SETTING_BOND_OPTION_LACP_RATE,
      {"slow", NM_BOND_OPTION_TYPE_BOTH, 0, 1, _option_default_strv_lacp_rate}},
     {NM_SETTING_BOND_OPTION_LP_INTERVAL, {"1", NM_BOND_OPTION_TYPE_INT, 1, G_MAXINT}},
@@ -207,6 +215,7 @@ static NM_UTILS_STRING_TABLE_LOOKUP_STRUCT_DEFINE(
     {NM_SETTING_BOND_OPTION_MIN_LINKS, {"0", NM_BOND_OPTION_TYPE_INT, 0, G_MAXINT}},
     {NM_SETTING_BOND_OPTION_MODE,
      {"balance-rr", NM_BOND_OPTION_TYPE_BOTH, 0, 6, _option_default_strv_mode}},
+    {NM_SETTING_BOND_OPTION_NS_IP6_TARGET, {"", NM_BOND_OPTION_TYPE_IP6}},
     {NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, {"1", NM_BOND_OPTION_TYPE_INT, 0, 255}},
     {NM_SETTING_BOND_OPTION_NUM_UNSOL_NA, {"1", NM_BOND_OPTION_TYPE_INT, 0, 255}},
     {NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, {"1", NM_BOND_OPTION_TYPE_INT, 0, 65535}},
@@ -504,12 +513,12 @@ validate_list(const char *name, const char *value, const OptionMeta *option_meta
 }
 
 static gboolean
-validate_ip(const char *name, const char *value, GError **error)
+validate_ip(int addr_family, const char *name, const char *value, GError **error)
 {
     gs_free const char **addrs = NULL;
     gsize                i;
 
-    addrs = nm_utils_bond_option_arp_ip_targets_split(value);
+    addrs = nm_utils_bond_option_ip_split(value);
     if (!addrs) {
         g_set_error(error,
                     NM_CONNECTION_ERROR,
@@ -518,13 +527,18 @@ validate_ip(const char *name, const char *value, GError **error)
                     name);
         return FALSE;
     }
+
+    /* An empty list is invalid. */
+    nm_assert(addrs[0]);
+
     for (i = 0; addrs[i]; i++) {
-        if (!nm_inet_parse_bin(AF_INET, addrs[i], NULL, NULL)) {
+        if (!nm_inet_parse_bin(addr_family, addrs[i], NULL, NULL)) {
             g_set_error(error,
                         NM_CONNECTION_ERROR,
                         NM_CONNECTION_ERROR_INVALID_PROPERTY,
-                        _("'%s' is not a valid IPv4 address for '%s' option"),
+                        _("'%s' is not a valid %s address for '%s' option"),
                         addrs[i],
+                        addr_family == AF_INET ? "IPv4" : "IPv6",
                         name);
             return FALSE;
         }
@@ -574,7 +588,10 @@ _nm_setting_bond_validate_option(const char *name, const char *value, GError **e
         goto handle_error;
     case NM_BOND_OPTION_TYPE_IP:
         nm_assert(nm_streq0(name, NM_SETTING_BOND_OPTION_ARP_IP_TARGET));
-        return validate_ip(name, value, error);
+        return validate_ip(AF_INET, name, value, error);
+    case NM_BOND_OPTION_TYPE_IP6:
+        nm_assert(nm_streq0(name, NM_SETTING_BOND_OPTION_NS_IP6_TARGET));
+        return validate_ip(AF_INET6, name, value, error);
     case NM_BOND_OPTION_TYPE_MAC:
         success = nm_utils_hwaddr_valid(value, ETH_ALEN);
         goto handle_error;
@@ -601,7 +618,7 @@ handle_error:
 /**
  * nm_setting_bond_validate_option:
  * @name: the name of the option to validate
- * @value: (allow-none): the value of the option to validate.
+ * @value: (nullable): the value of the option to validate.
  *
  * Checks whether @name is a valid bond option and @value is a valid value for
  * the @name. If @value is %NULL, the function only validates the option name.
@@ -703,13 +720,13 @@ nm_setting_bond_remove_option(NMSettingBond *setting, const char *name)
 
 /**
  * nm_setting_bond_get_valid_options:
- * @setting: (allow-none): the #NMSettingBond
+ * @setting: (nullable): the #NMSettingBond
  *
  * Returns a list of valid bond options.
  *
  * The @setting argument is unused and may be passed as %NULL.
  *
- * Returns: (transfer none): a %NULL-terminated array of strings of valid bond options.
+ * Returns: (transfer none) (nullable): a %NULL-terminated array of strings of valid bond options.
  **/
 const char **
 nm_setting_bond_get_valid_options(NMSettingBond *setting)
@@ -846,12 +863,15 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
     NMSettingBondPrivate    *priv = NM_SETTING_BOND_GET_PRIVATE(setting);
     int                      miimon;
     int                      arp_interval;
+    int                      arp_missed_max;
     int                      num_grat_arp;
     int                      num_unsol_na;
     int                      peer_notif_delay;
     const char              *mode_str;
     const char              *arp_ip_target = NULL;
+    const char              *ns_ip6_target;
     const char              *lacp_rate;
+    const char              *lacp_active;
     const char              *primary;
     const char              *s;
     NMBondMode               bond_mode;
@@ -876,6 +896,8 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
 
     miimon       = _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_MIIMON));
     arp_interval = _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_ARP_INTERVAL));
+    arp_missed_max =
+        _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_ARP_MISSED_MAX));
     num_grat_arp = _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP));
     num_unsol_na = _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_NUM_UNSOL_NA));
     peer_notif_delay =
@@ -886,6 +908,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
      * arp_interval conflicts [ alb, tlb ]
      * arp_interval needs arp_ip_target
      * arp_validate does not work with [ BOND_MODE_8023AD, BOND_MODE_TLB, BOND_MODE_ALB ]
+     * arp_missed_max does not work with [ BOND_MODE_8023AD, BOND_MODE_TLB, BOND_MODE_ALB ]
      * downdelay needs miimon
      * updelay needs miimon
      * peer_notif_delay needs miimon enabled
@@ -929,6 +952,17 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
             g_prefix_error(error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
             return FALSE;
         }
+        if (arp_missed_max > 0) {
+            g_set_error(error,
+                        NM_CONNECTION_ERROR,
+                        NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                        _("'%s=%s' is incompatible with '%s > 0'"),
+                        NM_SETTING_BOND_OPTION_MODE,
+                        mode_str,
+                        NM_SETTING_BOND_OPTION_ARP_MISSED_MAX);
+            g_prefix_error(error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
+            return FALSE;
+        }
     }
 
     primary = _bond_get_option(self, NM_SETTING_BOND_OPTION_PRIMARY);
@@ -1028,18 +1062,20 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
         }
     }
 
-    /* arp_ip_target can only be used with arp_interval, and must
+    /* arp_ip_target and ns_ip6_target can only be used with arp_interval, and must
      * contain a comma-separated list of IPv4 addresses.
      */
+    ns_ip6_target = _bond_get_option(self, NM_SETTING_BOND_OPTION_NS_IP6_TARGET);
     arp_ip_target = _bond_get_option(self, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
     if (arp_interval > 0) {
-        if (!arp_ip_target) {
+        if (!arp_ip_target && !ns_ip6_target) {
             g_set_error(error,
                         NM_CONNECTION_ERROR,
                         NM_CONNECTION_ERROR_INVALID_PROPERTY,
-                        _("'%s' option requires '%s' option to be set"),
+                        _("'%s' option requires '%s' or '%s'option to be set"),
                         NM_SETTING_BOND_OPTION_ARP_INTERVAL,
-                        NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
+                        NM_SETTING_BOND_OPTION_ARP_IP_TARGET,
+                        NM_SETTING_BOND_OPTION_NS_IP6_TARGET);
             g_prefix_error(error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
             return FALSE;
         }
@@ -1054,6 +1090,16 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
             g_prefix_error(error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
             return FALSE;
         }
+        if (ns_ip6_target) {
+            g_set_error(error,
+                        NM_CONNECTION_ERROR,
+                        NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                        _("'%s' option requires '%s' option to be set"),
+                        NM_SETTING_BOND_OPTION_NS_IP6_TARGET,
+                        NM_SETTING_BOND_OPTION_ARP_INTERVAL);
+            g_prefix_error(error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
+            return FALSE;
+        }
     }
 
     lacp_rate = _bond_get_option(self, NM_SETTING_BOND_OPTION_LACP_RATE);
@@ -1068,6 +1114,18 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
         return FALSE;
     }
 
+    lacp_active = _bond_get_option(self, NM_SETTING_BOND_OPTION_LACP_ACTIVE);
+    if (lacp_active && bond_mode != NM_BOND_MODE_8023AD) {
+        g_set_error(error,
+                    NM_CONNECTION_ERROR,
+                    NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                    _("'%s' option is only valid with mode '%s'"),
+                    NM_SETTING_BOND_OPTION_LACP_RATE,
+                    "802.3ad");
+        g_prefix_error(error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
+        return FALSE;
+    }
+
     if (_bond_get_option(self, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP)
         && _bond_get_option(self, NM_SETTING_BOND_OPTION_NUM_UNSOL_NA)
         && num_grat_arp != num_unsol_na) {
diff --git a/src/libnm-core-impl/nm-setting-connection.c b/src/libnm-core-impl/nm-setting-connection.c
index 0ec36a89..3c26ab5d 100644
--- a/src/libnm-core-impl/nm-setting-connection.c
+++ b/src/libnm-core-impl/nm-setting-connection.c
@@ -398,7 +398,7 @@ nm_setting_connection_permissions_user_allowed(NMSettingConnection *setting, con
  * @setting: the #NMSettingConnection
  * @ptype: the permission type; at this time only "user" is supported
  * @pitem: the permission item formatted as required for @ptype
- * @detail: (allow-none): unused at this time; must be %NULL
+ * @detail: (nullable): unused at this time; must be %NULL
  *
  * Adds a permission to the connection's permission list.  At this time, only
  * the "user" permission type is supported, and @pitem must be a username. See
@@ -481,7 +481,7 @@ nm_setting_connection_remove_permission(NMSettingConnection *setting, guint32 id
  * @setting: the #NMSettingConnection
  * @ptype: the permission type; at this time only "user" is supported
  * @pitem: the permission item formatted as required for @ptype
- * @detail: (allow-none): unused at this time; must be %NULL
+ * @detail: (nullable): unused at this time; must be %NULL
  *
  * Removes the permission from the connection.
  * At this time, only the "user" permission type is supported, and @pitem must
@@ -647,6 +647,8 @@ _to_dbus_fcn_timestamp(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil)
  * Returns the #NMSettingConnection:read-only property of the connection.
  *
  * Returns: %TRUE if the connection is read-only, %FALSE if it is not
+ *
+ * Deprecated: 1.44: This property is deprecated and has no meaning.
  **/
 gboolean
 nm_setting_connection_get_read_only(NMSettingConnection *setting)
@@ -1608,6 +1610,18 @@ after_interface_name:
     if (!_nm_setting_connection_verify_secondaries(priv->secondaries.arr, error))
         return NM_SETTING_VERIFY_NORMALIZABLE;
 
+    if (priv->read_only) {
+        g_set_error_literal(error,
+                            NM_CONNECTION_ERROR,
+                            NM_CONNECTION_ERROR_MISSING_PROPERTY,
+                            _("read-only is deprecated and not settable for the user"));
+        g_prefix_error(error,
+                       "%s.%s: ",
+                       NM_SETTING_CONNECTION_SETTING_NAME,
+                       NM_SETTING_CONNECTION_READ_ONLY);
+        return NM_SETTING_VERIFY_NORMALIZABLE;
+    }
+
     return TRUE;
 }
 
@@ -1883,12 +1897,13 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
      * 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].
+     * 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 to derive the DHCP
+     * client identifier with ipv4.dhcp-client-id=stable, the DHCPv6 DUID with
+     * ipv6.dhcp-duid=stable-[llt,ll,uuid] and the DHCP IAID with
+     * ipv4.iaid=stable and ipv6.iaid=stable.
      *
      * 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
@@ -1898,22 +1913,21 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
      * The per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key.
      * See NetworkManager(8) manual about the secret-key and the host identity.
      *
-     * The '$' character is treated special to perform dynamic substitutions
-     * at runtime. Currently, supported are "${CONNECTION}", "${DEVICE}", "${MAC}",
-     * "${BOOT}", "${RANDOM}".
-     * These effectively create unique IDs per-connection, per-device, per-boot,
-     * or every time. Note that "${DEVICE}" corresponds to the interface name of the
-     * device and "${MAC}" is the permanent MAC address of the device.
+     * The '$' character is treated special to perform dynamic substitutions at
+     * activation time. Currently, supported are "${CONNECTION}", "${DEVICE}",
+     * "${MAC}", "${BOOT}", "${RANDOM}".  These effectively create unique IDs
+     * per-connection, per-device, per-boot, or every time. The "${CONNECTION}"
+     * uses the profile's connection.uuid, the "${DEVICE}" uses the interface
+     * name of the device and "${MAC}" 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 "$$".
-     * For example, set it to "${CONNECTION}-${BOOT}-${DEVICE}" to create a unique id for
-     * this connection that changes with every reboot and differs depending on the
-     * interface where the profile activates.
+     * are reserved for future use. You are thus advised to avoid '$' or escape
+     * it as "$$".  For example, set it to "${CONNECTION}-${BOOT}-${DEVICE}" 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 "${CONNECTION}" and uses
-     * a unique, fixed ID for the connection.
+     * value is still unset, the default is "default${CONNECTION}" go generate
+     * an ID unique per connection profile.
      *
      * Since: 1.4
      **/
@@ -2190,9 +2204,9 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
     /**
      * NMSettingConnection:read-only:
      *
-     * %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.
+     * This property is deprecated and has no meaning.
+     *
+     * Deprecated: 1.44: This property is deprecated and has no meaning.
      **/
     _nm_setting_property_define_direct_boolean(properties_override,
                                                obj_properties,
@@ -2201,7 +2215,8 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
                                                FALSE,
                                                NM_SETTING_PARAM_FUZZY_IGNORE,
                                                NMSettingConnectionPrivate,
-                                               read_only);
+                                               read_only,
+                                               .is_deprecated = TRUE, );
 
     /**
      * NMSettingConnection:zone:
diff --git a/src/libnm-core-impl/nm-setting-ethtool.c b/src/libnm-core-impl/nm-setting-ethtool.c
index d5199823..ab1ed0e2 100644
--- a/src/libnm-core-impl/nm-setting-ethtool.c
+++ b/src/libnm-core-impl/nm-setting-ethtool.c
@@ -25,7 +25,7 @@
 
 /**
  * nm_ethtool_optname_is_feature:
- * @optname: (allow-none): the option name to check
+ * @optname: (nullable): the option name to check
  *
  * Checks whether @optname is a valid option name for an offload feature.
  *
@@ -45,7 +45,7 @@ nm_ethtool_optname_is_feature(const char *optname)
 
 /**
  * nm_ethtool_optname_is_coalesce:
- * @optname: (allow-none): the option name to check
+ * @optname: (nullable): the option name to check
  *
  * Checks whether @optname is a valid option name for a coalesce setting.
  *
@@ -61,7 +61,7 @@ nm_ethtool_optname_is_coalesce(const char *optname)
 
 /**
  * nm_ethtool_optname_is_ring:
- * @optname: (allow-none): the option name to check
+ * @optname: (nullable): the option name to check
  *
  * Checks whether @optname is a valid option name for a ring setting.
  *
@@ -77,7 +77,7 @@ nm_ethtool_optname_is_ring(const char *optname)
 
 /**
  * nm_ethtool_optname_is_pause:
- * @optname: (allow-none): the option name to check
+ * @optname: (nullable): the option name to check
  *
  * Checks whether @optname is a valid option name for a pause setting.
  *
diff --git a/src/libnm-core-impl/nm-setting-gsm.c b/src/libnm-core-impl/nm-setting-gsm.c
index 3fe5dfa1..4dde515a 100644
--- a/src/libnm-core-impl/nm-setting-gsm.c
+++ b/src/libnm-core-impl/nm-setting-gsm.c
@@ -36,7 +36,9 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_AUTO_CONFIG,
                                   PROP_DEVICE_ID,
                                   PROP_SIM_ID,
                                   PROP_SIM_OPERATOR_ID,
-                                  PROP_MTU, );
+                                  PROP_MTU,
+                                  PROP_INITIAL_EPS_CONFIG,
+                                  PROP_INITIAL_EPS_APN, );
 
 typedef struct {
     char   *number;
@@ -48,11 +50,13 @@ typedef struct {
     char   *apn;
     char   *network_id;
     char   *pin;
+    char   *initial_eps_apn;
     guint   password_flags;
     guint   pin_flags;
     guint32 mtu;
     bool    auto_config;
     bool    home_only;
+    bool    initial_eps_config;
 } NMSettingGsmPrivate;
 
 /**
@@ -286,6 +290,103 @@ nm_setting_gsm_get_mtu(NMSettingGsm *setting)
     return NM_SETTING_GSM_GET_PRIVATE(setting)->mtu;
 }
 
+/**
+ * nm_setting_gsm_get_initial_eps_config:
+ * @setting: the #NMSettingGsm
+ *
+ * Returns: the #NMSettingGsm:initial-eps-bearer-configure property of the setting
+ *
+ * Since: 1.44
+ **/
+gboolean
+nm_setting_gsm_get_initial_eps_config(NMSettingGsm *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_GSM(setting), FALSE);
+
+    return NM_SETTING_GSM_GET_PRIVATE(setting)->initial_eps_config;
+}
+
+/**
+ * nm_setting_gsm_get_initial_eps_apn:
+ * @setting: the #NMSettingGsm
+ *
+ * Returns: the #NMSettingGsm:initial-eps-bearer-apn property of the setting
+ *
+ * Since: 1.44
+ **/
+const char *
+nm_setting_gsm_get_initial_eps_apn(NMSettingGsm *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_GSM(setting), NULL);
+
+    return NM_SETTING_GSM_GET_PRIVATE(setting)->initial_eps_apn;
+}
+
+static gboolean
+_verify_apn(const char *apn, gboolean allow_empty, const char *property_name, GError **error)
+{
+    gsize apn_len;
+    gsize i;
+
+    if (!apn)
+        return TRUE;
+
+    apn_len = strlen(apn);
+
+    if (!allow_empty && apn_len == 0) {
+        g_set_error(error,
+                    NM_CONNECTION_ERROR,
+                    NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                    _("property value is empty"));
+        g_prefix_error(error, "%s.%s: ", NM_SETTING_GSM_SETTING_NAME, property_name);
+        return FALSE;
+    }
+
+    if (apn_len > 64) {
+        g_set_error(error,
+                    NM_CONNECTION_ERROR,
+                    NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                    _("property value is too long (>64)"));
+        g_prefix_error(error, "%s.%s: ", NM_SETTING_GSM_SETTING_NAME, property_name);
+        return FALSE;
+    }
+
+    /* APNs roughly follow the same rules as DNS domain names.  Allowed
+     * characters are a-z, 0-9, . and -.  GSM 03.03 Section 9.1 states:
+     *
+     *   The syntax of the APN shall follow the Name Syntax defined in
+     *   RFC 2181 [14] and RFC 1035 [15]. The APN consists of one or
+     *   more labels. Each label is coded as one octet length field
+     *   followed by that number of octets coded as 8 bit ASCII characters.
+     *   Following RFC 1035 [15] the labels should consist only of the
+     *   alphabetic characters (A-Z and a-z), digits (0-9) and the
+     *   dash (-). The case of alphabetic characters is not significant.
+     *
+     * A dot (.) is commonly used to separate parts of the APN, and
+     * apparently the underscore (_) is used as well.  RFC 2181 indicates
+     * that no restrictions of any kind are placed on DNS labels, and thus
+     * it would appear that none are placed on APNs either, but many modems
+     * and networks will fail to accept APNs that include odd characters
+     * like space ( ) and such.
+     */
+    for (i = 0; i < apn_len; i++) {
+        if (g_ascii_isalnum(apn[i]))
+            continue;
+        if (NM_IN_SET(apn[i], '.', '_', '-'))
+            continue;
+
+        g_set_error(error,
+                    NM_CONNECTION_ERROR,
+                    NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                    _("'%s' contains invalid char(s) (use [A-Za-z._-])"),
+                    apn);
+        g_prefix_error(error, "%s.%s: ", NM_SETTING_GSM_SETTING_NAME, property_name);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
 static gboolean
 verify(NMSetting *setting, NMConnection *connection, GError **error)
 {
@@ -300,51 +401,11 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
         return FALSE;
     }
 
-    if (priv->apn) {
-        gsize apn_len = strlen(priv->apn);
-        gsize i;
-
-        if (apn_len > 64) {
-            g_set_error(error,
-                        NM_CONNECTION_ERROR,
-                        NM_CONNECTION_ERROR_INVALID_PROPERTY,
-                        _("property value '%s' is empty or too long (>64)"),
-                        priv->apn);
-            g_prefix_error(error, "%s.%s: ", NM_SETTING_GSM_SETTING_NAME, NM_SETTING_GSM_APN);
-            return FALSE;
-        }
+    if (!_verify_apn(priv->apn, TRUE, NM_SETTING_GSM_APN, error))
+        return FALSE;
 
-        /* APNs roughly follow the same rules as DNS domain names.  Allowed
-         * characters are a-z, 0-9, . and -.  GSM 03.03 Section 9.1 states:
-         *
-         *   The syntax of the APN shall follow the Name Syntax defined in
-         *   RFC 2181 [14] and RFC 1035 [15]. The APN consists of one or
-         *   more labels. Each label is coded as one octet length field
-         *   followed by that number of octets coded as 8 bit ASCII characters.
-         *   Following RFC 1035 [15] the labels should consist only of the
-         *   alphabetic characters (A-Z and a-z), digits (0-9) and the
-         *   dash (-). The case of alphabetic characters is not significant.
-         *
-         * A dot (.) is commonly used to separate parts of the APN, and
-         * apparently the underscore (_) is used as well.  RFC 2181 indicates
-         * that no restrictions of any kind are placed on DNS labels, and thus
-         * it would appear that none are placed on APNs either, but many modems
-         * and networks will fail to accept APNs that include odd characters
-         * like space ( ) and such.
-         */
-        for (i = 0; i < apn_len; i++) {
-            if (!g_ascii_isalnum(priv->apn[i]) && (priv->apn[i] != '.') && (priv->apn[i] != '_')
-                && (priv->apn[i] != '-')) {
-                g_set_error(error,
-                            NM_CONNECTION_ERROR,
-                            NM_CONNECTION_ERROR_INVALID_PROPERTY,
-                            _("'%s' contains invalid char(s) (use [A-Za-z._-])"),
-                            priv->apn);
-                g_prefix_error(error, "%s.%s: ", NM_SETTING_GSM_SETTING_NAME, NM_SETTING_GSM_APN);
-                return FALSE;
-            }
-        }
-    }
+    if (!_verify_apn(priv->initial_eps_apn, FALSE, NM_SETTING_GSM_INITIAL_EPS_BEARER_APN, error))
+        return FALSE;
 
     if (priv->username && priv->username[0] == '\0') {
         g_set_error_literal(error,
@@ -742,6 +803,41 @@ nm_setting_gsm_class_init(NMSettingGsmClass *klass)
                                               NMSettingGsmPrivate,
                                               mtu);
 
+    /**
+     * NMSettingGsm:initial-eps-bearer-configure:
+     *
+     * For LTE modems, this setting determines whether the initial EPS bearer
+     * shall be configured when bringing up the connection.  It is inferred TRUE
+     * if initial-eps-bearer-apn is set.
+     *
+     * Since: 1.44
+     **/
+    _nm_setting_property_define_direct_boolean(properties_override,
+                                               obj_properties,
+                                               NM_SETTING_GSM_INITIAL_EPS_BEARER_CONFIGURE,
+                                               PROP_INITIAL_EPS_CONFIG,
+                                               FALSE,
+                                               NM_SETTING_PARAM_NONE,
+                                               NMSettingGsmPrivate,
+                                               initial_eps_config);
+
+    /**
+     * NMSettingGsm:initial-eps-bearer-apn:
+     *
+     * For LTE modems, this sets the APN for the initial EPS bearer that is set
+     * up when attaching to the network.  Setting this parameter implies
+     * initial-eps-bearer-configure to be TRUE.
+     *
+     * Since: 1.44
+     **/
+    _nm_setting_property_define_direct_string(properties_override,
+                                              obj_properties,
+                                              NM_SETTING_GSM_INITIAL_EPS_BEARER_APN,
+                                              PROP_INITIAL_EPS_APN,
+                                              NM_SETTING_PARAM_NONE,
+                                              NMSettingGsmPrivate,
+                                              initial_eps_apn);
+
     /* Ignore incoming deprecated properties */
     _nm_properties_override_dbus(properties_override,
                                  "allowed-bands",
diff --git a/src/libnm-core-impl/nm-setting-infiniband.c b/src/libnm-core-impl/nm-setting-infiniband.c
index a3bda692..a0d5578c 100644
--- a/src/libnm-core-impl/nm-setting-infiniband.c
+++ b/src/libnm-core-impl/nm-setting-infiniband.c
@@ -36,9 +36,7 @@ typedef struct {
     char   *mac_address;
     char   *transport_mode;
     char   *parent;
-    char   *virtual_iface_name;
-    gsize   virtual_iface_name_parent_length;
-    gint32  virtual_iface_name_p_key;
+    char    virtual_iface_name[NM_IFNAMSIZ];
     gint32  p_key;
     guint32 mtu;
 } NMSettingInfinibandPrivate;
@@ -145,17 +143,6 @@ nm_setting_infiniband_get_parent(NMSettingInfiniband *setting)
     return NM_SETTING_INFINIBAND_GET_PRIVATE(setting)->parent;
 }
 
-char *
-nm_setting_infiniband_create_virtual_interface_name(const char *parent, int p_key)
-{
-    char *s;
-
-    s = g_strdup_printf("%s.%04x", parent, (guint) p_key);
-    if (strlen(s) >= NMP_IFNAMSIZ)
-        s[NMP_IFNAMSIZ - 1] = '\0';
-    return s;
-}
-
 /**
  * nm_setting_infiniband_get_virtual_interface_name:
  * @setting: the #NMSettingInfiniband
@@ -170,25 +157,11 @@ const char *
 nm_setting_infiniband_get_virtual_interface_name(NMSettingInfiniband *setting)
 {
     NMSettingInfinibandPrivate *priv = NM_SETTING_INFINIBAND_GET_PRIVATE(setting);
-    gsize                       len;
 
-    if (priv->p_key == -1 || !priv->parent) {
-        nm_clear_g_free(&priv->virtual_iface_name);
+    if (priv->p_key == -1 || !priv->parent)
         return NULL;
-    }
-
-    len = strlen(priv->parent);
-    if (!priv->virtual_iface_name || priv->virtual_iface_name_p_key != priv->p_key
-        || priv->virtual_iface_name_parent_length != len
-        || memcmp(priv->parent, priv->virtual_iface_name, len) != 0) {
-        priv->virtual_iface_name_p_key         = priv->p_key;
-        priv->virtual_iface_name_parent_length = len;
-        g_free(priv->virtual_iface_name);
-        priv->virtual_iface_name =
-            nm_setting_infiniband_create_virtual_interface_name(priv->parent, priv->p_key);
-    }
 
-    return priv->virtual_iface_name;
+    return nm_net_devname_infiniband(priv->virtual_iface_name, priv->parent, priv->p_key);
 }
 
 static gboolean
@@ -353,16 +326,6 @@ nm_setting_infiniband_new(void)
 }
 
 static void
-finalize(GObject *object)
-{
-    NMSettingInfinibandPrivate *priv = NM_SETTING_INFINIBAND_GET_PRIVATE(object);
-
-    g_free(priv->virtual_iface_name);
-
-    G_OBJECT_CLASS(nm_setting_infiniband_parent_class)->finalize(object);
-}
-
-static void
 nm_setting_infiniband_class_init(NMSettingInfinibandClass *klass)
 {
     GObjectClass   *object_class        = G_OBJECT_CLASS(klass);
@@ -373,7 +336,6 @@ nm_setting_infiniband_class_init(NMSettingInfinibandClass *klass)
 
     object_class->get_property = _nm_setting_property_get_property_direct;
     object_class->set_property = _nm_setting_property_set_property_direct;
-    object_class->finalize     = finalize;
 
     setting_class->verify = verify;
 
diff --git a/src/libnm-core-impl/nm-setting-ip-config.c b/src/libnm-core-impl/nm-setting-ip-config.c
index 3e49eb15..727a4bae 100644
--- a/src/libnm-core-impl/nm-setting-ip-config.c
+++ b/src/libnm-core-impl/nm-setting-ip-config.c
@@ -553,7 +553,7 @@ nm_ip_address_get_attribute(NMIPAddress *address, const char *name)
  * nm_ip_address_set_attribute:
  * @address: the #NMIPAddress
  * @name: the name of an address attribute
- * @value: (transfer none) (allow-none): the value
+ * @value: (transfer none) (nullable): the value
  *
  * Sets or clears the named attribute on @address to the given value.
  **/
@@ -602,7 +602,7 @@ struct NMIPRoute {
  *   <literal>AF_INET6</literal>)
  * @dest: the IP address of the route's destination
  * @prefix: the address prefix length
- * @next_hop: (allow-none): the IP address of the next hop (or %NULL)
+ * @next_hop: (nullable): the IP address of the next hop (or %NULL)
  * @metric: the route metric (or -1 for "default")
  * @error: location to store error, or %NULL
  *
@@ -653,7 +653,7 @@ nm_ip_route_new(int         family,
  *   <literal>AF_INET6</literal>)
  * @dest: the IP address of the route's destination
  * @prefix: the address prefix length
- * @next_hop: (allow-none): the IP address of the next hop (or %NULL)
+ * @next_hop: (nullable): the IP address of the next hop (or %NULL)
  * @metric: the route metric (or -1 for "default")
  * @error: location to store error, or %NULL
  *
@@ -995,7 +995,7 @@ nm_ip_route_get_next_hop(NMIPRoute *route)
 /**
  * nm_ip_route_set_next_hop:
  * @route: the #NMIPRoute
- * @next_hop: (allow-none): the route's next hop, as a string
+ * @next_hop: (nullable): the route's next hop, as a string
  *
  * Sets the next-hop property of this route object.
  *
@@ -1113,13 +1113,13 @@ _nm_ip_route_get_attributes(NMIPRoute *route)
  * @route: the #NMIPRoute
  * @sorted: whether to sort the names. Otherwise, their order is
  *   undefined and unstable.
- * @out_length: (allow-none) (out): the number of elements
+ * @out_length: (out) (optional): the number of elements
  *
  * Gets an array of attribute names defined on @route.
  *
- * Returns: (array length=out_length) (transfer container): a %NULL-terminated array
- *   of attribute names or %NULL if there are no attributes. The order of the returned
- *   names depends on @sorted.
+ * Returns: (array length=out_length) (transfer container) (nullable): a %NULL-terminated
+ *   array of attribute names or %NULL if there are no attributes. The order of the
+ *   returned names depends on @sorted.
  **/
 const char **
 _nm_ip_route_get_attribute_names(const NMIPRoute *route, gboolean sorted, guint *out_length)
@@ -1174,7 +1174,7 @@ nm_ip_route_get_attribute(NMIPRoute *route, const char *name)
  * nm_ip_route_set_attribute:
  * @route: the #NMIPRoute
  * @name: the name of a route attribute
- * @value: (transfer none) (allow-none): the value
+ * @value: (transfer none) (nullable): the value
  *
  * Sets the named attribute on @route to the given value.
  **/
@@ -1461,7 +1461,7 @@ _ip_route_attribute_validate(const char           *name,
  * @value: the attribute value
  * @family: IP address family of the route
  * @known: (out): on return, whether the attribute name is a known one
- * @error: (allow-none): return location for a #GError, or %NULL
+ * @error: return location for a #GError, or %NULL
  *
  * Validates a route attribute, i.e. checks that the attribute is a known one
  * and the value is of the correct type and well-formed.
@@ -1734,7 +1734,7 @@ nm_ip_routing_rule_new_clone(const NMIPRoutingRule *rule)
 
 /**
  * nm_ip_routing_rule_ref:
- * @self: (allow-none): the #NMIPRoutingRule instance
+ * @self: (nullable): the #NMIPRoutingRule instance
  *
  * Increases the reference count of the instance.
  *
@@ -1761,7 +1761,7 @@ nm_ip_routing_rule_ref(NMIPRoutingRule *self)
 
 /**
  * nm_ip_routing_rule_unref:
- * @self: (allow-none): the #NMIPRoutingRule instance
+ * @self: (nullable): the #NMIPRoutingRule instance
  *
  * Decreases the reference count of the instance and destroys
  * the instance if the reference count reaches zero.
@@ -1984,7 +1984,7 @@ nm_ip_routing_rule_set_from_bin(NMIPRoutingRule *self, gconstpointer from, guint
 /**
  * nm_ip_routing_rule_set_from:
  * @self: the #NMIPRoutingRule instance
- * @from: (allow-none): the from/src address to set.
+ * @from: (nullable): the from/src address to set.
  *   The address family must match.
  * @len: the corresponding prefix length of the address.
  *
@@ -2084,7 +2084,7 @@ nm_ip_routing_rule_set_to_bin(NMIPRoutingRule *self, gconstpointer to, guint8 le
 /**
  * nm_ip_routing_rule_set_to:
  * @self: the #NMIPRoutingRule instance
- * @to: (allow-none): the to/dst address to set.
+ * @to: (nullable): the to/dst address to set.
  *   The address family must match.
  * @len: the corresponding prefix length of the address.
  *   If @to is %NULL, this valid is ignored.
@@ -2371,7 +2371,7 @@ nm_ip_routing_rule_get_xifname_bin(const NMIPRoutingRule *self,
 /**
  * nm_ip_routing_rule_set_iifname:
  * @self: the #NMIPRoutingRule instance.
- * @iifname: (allow-none): the iifname to set or %NULL to unset.
+ * @iifname: (nullable): the iifname to set or %NULL to unset.
  *
  * The name supports C backslash escaping for non-UTF-8 characters.
  * Note that nm_ip_routing_rule_from_string() too uses backslash
@@ -2408,7 +2408,7 @@ nm_ip_routing_rule_get_oifname(const NMIPRoutingRule *self)
 /**
  * nm_ip_routing_rule_set_oifname:
  * @self: the #NMIPRoutingRule instance.
- * @oifname: (allow-none): the oifname to set or %NULL to unset.
+ * @oifname: (nullable): the oifname to set or %NULL to unset.
  *
  * The name supports C backslash escaping for non-UTF-8 characters.
  * Note that nm_ip_routing_rule_from_string() too uses backslash
@@ -2526,9 +2526,9 @@ nm_ip_routing_rule_set_suppress_prefixlength(NMIPRoutingRule *self, gint32 suppr
 /**
  * nm_ip_routing_rule_get_uid_range:
  * @self: the #NMIPRoutingRule instance
- * @out_range_start: (out) (allow-none): returns the start of the range
+ * @out_range_start: (out) (optional): returns the start of the range
  *   or 0 if the range is not set.
- * @out_range_end: (out) (allow-none): returns the end of the range
+ * @out_range_end: (out) (optional): returns the end of the range
  *   or 0 if the range is not set.
  *
  * Returns: %TRUE if a uid range is set.
@@ -2586,8 +2586,8 @@ nm_ip_routing_rule_set_uid_range(NMIPRoutingRule *self,
 
 /**
  * nm_ip_routing_rule_cmp:
- * @rule: (allow-none): the #NMIPRoutingRule instance to compare
- * @other: (allow-none): the other #NMIPRoutingRule instance to compare
+ * @rule: (nullable): the #NMIPRoutingRule instance to compare
+ * @other: (nullable): the other #NMIPRoutingRule instance to compare
  *
  * Returns: zero, a positive, or a negative integer to indicate
  *   equality or how the arguments compare.
@@ -2709,7 +2709,7 @@ _rr_xport_range_parse(char *str, gint64 *out_start, guint16 *out_end)
 /**
  * nm_ip_routing_rule_validate:
  * @self: the #NMIPRoutingRule instance to validate
- * @error: (allow-none) (out): the error result if validation fails.
+ * @error: the error result if validation fails.
  *
  * Returns: %TRUE if the rule validates.
  *
@@ -3349,9 +3349,9 @@ _rr_string_addr_family_from_flags(NMIPRoutingRuleAsStringFlags to_string_flags)
  * @str: the string representation to convert to an #NMIPRoutingRule
  * @to_string_flags: #NMIPRoutingRuleAsStringFlags for controlling the
  *   string conversion.
- * @extra_args: (allow-none): extra arguments for controlling the string
+ * @extra_args: (nullable): extra arguments for controlling the string
  *   conversion. Currently, not extra arguments are supported.
- * @error: (allow-none) (out): the error reason.
+ * @error: the error reason.
  *
  * Returns: (transfer full): the new #NMIPRoutingRule or %NULL on error.
  *
@@ -3813,9 +3813,9 @@ _rr_string_append_inet_addr(NMStrBuf       *str,
  * @self: the #NMIPRoutingRule instance to convert to string.
  * @to_string_flags: #NMIPRoutingRuleAsStringFlags for controlling the
  *   string conversion.
- * @extra_args: (allow-none): extra arguments for controlling the string
+ * @extra_args: (nullable): extra arguments for controlling the string
  *   conversion. Currently, not extra arguments are supported.
- * @error: (allow-none) (out): the error reason.
+ * @error: the error reason.
  *
  * Returns: (transfer full): the string representation or %NULL on error.
  *
@@ -5349,7 +5349,7 @@ nm_setting_ip_config_get_dhcp_iaid(NMSettingIPConfig *setting)
 /**
  * nm_setting_ip_config_get_dhcp_reject_servers:
  * @setting: the #NMSettingIPConfig
- * @out_len: (allow-none) (out): the number of returned elements
+ * @out_len: (out) (optional): the number of returned elements
  *
  * Returns: (array length=out_len zero-terminated=1) (transfer none):
  *   A %NULL terminated array of DHCP reject servers. Even if no reject
@@ -5453,7 +5453,7 @@ nm_setting_ip_config_get_auto_route_ext_gw(NMSettingIPConfig *setting)
  *
  * Returns: the #NMSettingIPConfig:replace-local-rule property of the setting
  *
- * Since: 1.44, 1.42.2
+ * Since: 1.44
  **/
 NMTernary
 nm_setting_ip_config_get_replace_local_rule(NMSettingIPConfig *setting)
@@ -6730,7 +6730,7 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass)
      *
      * A string containing the "Identity Association Identifier" (IAID) used by
      * the DHCP client. The string can be a 32-bit number (either decimal,
-     * hexadecimal or or as colon separated hexadecimal numbers). Alternatively
+     * hexadecimal or as colon separated hexadecimal numbers). Alternatively
      * it can be set to the special values "mac", "perm-mac", "ifname" or
      * "stable". When set to "mac" (or "perm-mac"), the last 4 bytes of the
      * current (or permanent) MAC address are used as IAID. When set to
@@ -6839,7 +6839,7 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass)
      * Connections will default to keep the autogenerated priority 0 local rule
      * unless this setting is set to %TRUE.
      *
-     * Since: 1.44, 1.42.2
+     * Since: 1.44
      */
     obj_properties[PROP_REPLACE_LOCAL_RULE] =
         g_param_spec_enum(NM_SETTING_IP_CONFIG_REPLACE_LOCAL_RULE,
diff --git a/src/libnm-core-impl/nm-setting-ip4-config.c b/src/libnm-core-impl/nm-setting-ip4-config.c
index 7819c2e8..9ed39507 100644
--- a/src/libnm-core-impl/nm-setting-ip4-config.c
+++ b/src/libnm-core-impl/nm-setting-ip4-config.c
@@ -778,6 +778,34 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass)
      * ---end---
      */
 
+    /* ---nmcli---
+     * property: dns-options
+     * format: a comma separated list of DNS options
+     * description:
+     *   DNS options for /etc/resolv.conf as described in resolv.conf(5) manual.
+     *
+     *   The currently supported options are "attempts", "debug", "edns0",
+     *   "ndots", "no-aaaa", "no-check-names", "no-reload", "no-tld-query",
+     *   "rotate", "single-request", "single-request-reopen", "timeout",
+     *   "trust-ad", "use-vc". See the resolv.conf(5) manual.
+     *
+     *   Note that there is a distinction between an unset (default) list
+     *   and an empty list. In nmcli, to unset the list set the value to
+     *   "". To set an empty list, set it to " ". Currently, an unset list
+     *   has the same meaning as an empty list. That might change in the future.
+     *
+     *   The "trust-ad" setting is only honored if the profile contributes
+     *   name servers to resolv.conf, and if all contributing profiles have
+     *   "trust-ad" enabled.
+     *
+     *   When using a caching DNS plugin (dnsmasq or systemd-resolved in
+     *   NetworkManager.conf) then "edns0" and "trust-ad" are automatically
+     *   added.
+     *
+     *   The valid "ipv4.dns-options" and "ipv6.dns-options" get merged together.
+     * ---end---
+     */
+
     /* ---ifcfg-rh---
      * property: dns-options
      * variable: RES_OPTIONS(+)
@@ -1224,6 +1252,36 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass)
      * ---end---
      */
 
+    /* ---nmcli---
+     * property: method
+     * format: string
+     * description: The IPv4 connection method.
+     * description-docbook:
+     *   <para>
+     *     Sets the IPv4 connection method. You can set one of the following values:
+     *   </para>
+     *   <para>
+     *     <itemizedlist>
+     *        <listitem>
+     *          <para><literal>"auto"</literal> - Enables automatic IPv4 address assignment from DHCP, PPP, or similar services.</para>
+     *        </listitem>
+     *        <listitem>
+     *          <para><literal>"manual"</literal> - Enables the configuration of static IPv4 addresses on the interface. Note that you must set at least one IP address and subnet mask in the "ipv4.addresses" property.</para>
+     *        </listitem>
+     *        <listitem>
+     *          <para><literal>"disabled"</literal> - Disables the IPv4 protocol in this connection profile.</para>
+     *        </listitem>
+     *        <listitem>
+     *          <para><literal>"shared"</literal> - Provides network access to other computers. If you do not specify an IP address and subnet mask in "ipv4.addresses", NetworkManager assigns 10.42.x.1/24 to the interface. Additionally, NetworkManager starts a DHCP server and DNS forwarder. Hosts that connect to this interface will then receive an IP address from the configured range, and NetworkManager configures NAT to map client addresses to the one of the current default network connection.</para>
+     *        </listitem>
+     *        <listitem>
+     *          <para><literal>"link-local"</literal> - Enables link-local addresses according to RFC 3927. NetworkManager assigns a random link-local address from the 169.254.0.0/16 subnet to the interface.</para>
+     *        </listitem>
+     *     </itemizedlist>
+     *   </para>
+     * ---end---
+     */
+
     g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
     _nm_setting_class_commit(setting_class,
diff --git a/src/libnm-core-impl/nm-setting-ip6-config.c b/src/libnm-core-impl/nm-setting-ip6-config.c
index 573211b2..661a451e 100644
--- a/src/libnm-core-impl/nm-setting-ip6-config.c
+++ b/src/libnm-core-impl/nm-setting-ip6-config.c
@@ -44,13 +44,15 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_IP6_PRIVACY,
                                   PROP_TOKEN,
                                   PROP_DHCP_DUID,
                                   PROP_RA_TIMEOUT,
-                                  PROP_MTU, );
+                                  PROP_MTU,
+                                  PROP_DHCP_PD_HINT, );
 
 typedef struct {
     NMSettingIPConfigPrivate parent;
 
     char   *token;
     char   *dhcp_duid;
+    char   *dhcp_pd_hint;
     int     ip6_privacy;
     gint32  addr_gen_mode;
     gint32  ra_timeout;
@@ -98,6 +100,26 @@ nm_setting_ip6_config_get_ip6_privacy(NMSettingIP6Config *setting)
 }
 
 /**
+ * nm_setting_ip6_config_get_dhcp_pd_hint:
+ * @setting: the #NMSettingIP6Config
+ *
+ * Returns the value contained in the #NMSettingIP6Config:dhcp-pd-hint
+ * property.
+ *
+ * Returns: a string containing an address and prefix length to be used
+ * as hint for DHCPv6 prefix delegation.
+ *
+ * Since: 1.44
+ **/
+const char *
+nm_setting_ip6_config_get_dhcp_pd_hint(NMSettingIP6Config *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_IP6_CONFIG(setting), NULL);
+
+    return NM_SETTING_IP6_CONFIG_GET_PRIVATE(setting)->dhcp_pd_hint;
+}
+
+/**
  * nm_setting_ip6_config_get_addr_gen_mode:
  * @setting: the #NMSettingIP6Config
  *
@@ -349,6 +371,23 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
         }
     }
 
+    if (priv->dhcp_pd_hint) {
+        int prefix;
+
+        if (!nm_inet_parse_with_prefix_bin(AF_INET6, priv->dhcp_pd_hint, NULL, NULL, &prefix)
+            || prefix < 1 || prefix > 128) {
+            g_set_error_literal(error,
+                                NM_CONNECTION_ERROR,
+                                NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                                _("must be a valid IPv6 address with prefix"));
+            g_prefix_error(error,
+                           "%s.%s: ",
+                           NM_SETTING_IP6_CONFIG_SETTING_NAME,
+                           NM_SETTING_IP6_CONFIG_DHCP_PD_HINT);
+            return FALSE;
+        }
+    }
+
     /* Failures from here on, are NORMALIZABLE_ERROR... */
 
     if (token_needs_normalization) {
@@ -523,6 +562,41 @@ ip6_route_data_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
     return TRUE;
 }
 
+static gboolean
+_set_string_fcn_dhcp_pd_hint(const NMSettInfoSetting  *sett_info,
+                             const NMSettInfoProperty *property_info,
+                             NMSetting                *setting,
+                             const char               *str)
+{
+    NMSettingIP6ConfigPrivate *priv = NM_SETTING_IP6_CONFIG_GET_PRIVATE(setting);
+    char                       buf[NM_INET_ADDRSTRLEN];
+    char                       bufp[NM_INET_ADDRSTRLEN + 16];
+    gs_free char              *old = NULL;
+    NMIPAddr                   addr;
+    int                        prefix;
+
+    if (!str)
+        goto do_set;
+
+    if (!nm_inet_parse_with_prefix_bin(AF_INET6, str, NULL, &addr, &prefix)) {
+        /* address not valid, set as is */
+        goto do_set;
+    }
+
+    /* address valid, normalize */
+    nm_inet6_ntop(&addr.addr6, buf);
+    nm_sprintf_buf(bufp, "%s/%d", buf, prefix);
+    str = bufp;
+
+do_set:
+    if (!nm_streq0(priv->dhcp_pd_hint, str)) {
+        old                = priv->dhcp_pd_hint;
+        priv->dhcp_pd_hint = g_strdup(str);
+        return TRUE;
+    }
+    return FALSE;
+}
+
 /*****************************************************************************/
 
 static void
@@ -733,6 +807,35 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
      * ---end---
      */
 
+    /* ---nmcli---
+     * property: dns-options
+     * format: a comma separated list of DNS options
+     * description:
+     *   DNS options for /etc/resolv.conf as described in resolv.conf(5) manual.
+     *
+     *   The currently supported options are "attempts", "debug", "edns0",
+     *   "ndots", "no-aaaa", "no-check-names", "no-reload", "no-tld-query",
+     *   "rotate", "single-request", "single-request-reopen", "timeout",
+     *   "trust-ad", "use-vc" and "inet6", "ip6-bytestring", "ip6-dotint",
+     *   "no-ip6-dotint". See the resolv.conf(5) manual.
+     *
+     *   Note that there is a distinction between an unset (default) list
+     *   and an empty list. In nmcli, to unset the list set the value to
+     *   "". To set an empty list, set it to " ". Currently, an unset list
+     *   has the same meaning as an empty list. That might change in the future.
+     *
+     *   The "trust-ad" setting is only honored if the profile contributes
+     *   name servers to resolv.conf, and if all contributing profiles have
+     *   "trust-ad" enabled.
+     *
+     *   When using a caching DNS plugin (dnsmasq or systemd-resolved in
+     *   NetworkManager.conf) then "edns0" and "trust-ad" are automatically
+     *   added.
+     *
+     *   The valid "ipv4.dns-options" and "ipv6.dns-options" get merged together.
+     * ---end---
+     */
+
     /* ---ifcfg-rh---
      * property: dns-options
      * variable: IPV6_RES_OPTIONS(+)
@@ -805,37 +908,42 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
     /**
      * NMSettingIP6Config:addr-gen-mode:
      *
-     * 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,
+     * Configure the method for creating the IPv6 interface identifier of
+     * addresses for RFC4862 IPv6 Stateless Address Autoconfiguration and IPv6
+     * Link Local.
+     *
+     * The permitted values are: %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
      * %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY.
-     * %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64
-     * or %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT.
+     * %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64 or
+     * %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT.
      *
-     * 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.
+     * If the property is set to "eui64", the addresses will be generated using
+     * the interface token derived from the hardware address. This makes the
+     * host part of the address constant, making it possible to track the
+     * host's presence when it changes networks. The address changes when the
+     * interface hardware is replaced. If a duplicate address is detected,
+     * there is no fallback to generate another address. When configured, the
+     * "ipv6.token" is used instead of the MAC address to generate addresses
+     * for stateless autoconfiguration.
      *
-     * 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.
+     * If the property is set to "stable-privacy", the interface identifier is
+     * generated as specified by RFC7217. This works by hashing a host specific
+     * key (see NetworkManager(8) manual), the interface name, the connection's
+     * "connection.stable-id" property and the address prefix.  This improves
+     * privacy by making it harder to use the address to track the host's
+     * presence as every prefix and network has a different identifier. Also,
+     * the address is stable when the network interface hardware is replaced.
      *
-     * The special values "default" and "default-or-eui64" will fallback to the global
-     * connection default in as documented in NetworkManager.conf(5) manual. If the
-     * global default is not specified, the fallback value is "stable-privacy"
-     * or "eui64", respectively.
+     * The special values "default" and "default-or-eui64" will fallback to the
+     * global connection default as documented in the NetworkManager.conf(5)
+     * manual. If the global default is not specified, the fallback value is
+     * "stable-privacy" or "eui64", respectively.
      *
-     * For libnm, the property defaults to "default" since 1.40.
-     * Previously it defaulted to "stable-privacy".
-     * On D-Bus, the absence of an addr-gen-mode setting equals
-     * "default". For keyfile plugin, the absence of the setting
-     * on disk means "default-or-eui64" so that the property doesn't change on upgrade
-     * from older versions.
+     * For libnm, the property defaults to "default" since 1.40.  Previously it
+     * used to default to "stable-privacy".  On D-Bus, the absence of an
+     * addr-gen-mode setting equals "default". For keyfile plugin, the absence
+     * of the setting on disk means "default-or-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 "ip6-privacy" property and it does not affect the
@@ -852,6 +960,45 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
      * example: IPV6_ADDR_GEN_MODE=stable-privacy
      * ---end---
      */
+    /* ---nmcli---
+     * property: addr-gen-mode
+     * format: one of "eui64" (0), "stable-privacy" (1), "default" (3) or "default-or-eui64" (2)
+     * description: Configure method for creating the
+     * IPv6 interface identifer of addresses with RFC4862 IPv6 Stateless
+     * Address Autoconfiguration and Link Local addresses.
+     *
+     * The permitted values are: "eui64" (0), "stable-privacy" (1), "default"
+     * (3) or "default-or-eui64" (2).
+     *
+     * If the property is set to "eui64", the addresses will be generated using
+     * the interface token derived from hardware address. This makes the host
+     * part of the address to stay constant, making it possible to track the
+     * host's presence when it changes networks. The address changes when the
+     * interface hardware is replaced. If a duplicate address is detected,
+     * there is also no fallback to generate another address. When configured,
+     * the "ipv6.token" is used instead of the MAC address to generate
+     * addresses for stateless autoconfiguration.
+     *
+     * If the property is set to "stable-privacy", the interface identifier is
+     * generated as specified by RFC7217. This works by hashing a host specific
+     * key (see NetworkManager(8) manual), the interface name, the connection's
+     * "connection.stable-id" property and the address prefix.  This improves
+     * privacy by making it harder to use the address to track the host's
+     * presence and the address is stable when the network interface hardware
+     * is replaced.
+     *
+     * The special values "default" and "default-or-eui64" will fallback to the
+     * global connection default as documented in the NetworkManager.conf(5)
+     * manual. If the global default is not specified, the fallback value is
+     * "stable-privacy" or "eui64", respectively.
+     *
+     * If not specified, when creating a new profile the default is "default".
+     *
+     * Note that this setting is distinct from the Privacy Extensions as
+     * configured by "ip6-privacy" property and it does not affect the
+     * temporary addresses configured with this option.
+     * ---end---
+     */
     _nm_setting_property_define_direct_int32(properties_override,
                                              obj_properties,
                                              NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
@@ -869,6 +1016,10 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
      * Configure the token for draft-chown-6man-tokenised-ipv6-identifiers-02
      * IPv6 tokenized interface identifiers. Useful with eui64 addr-gen-mode.
      *
+     * When set, the token is used as IPv6 interface identifier instead of the
+     * hardware address. This only applies to addresses from stateless
+     * autoconfiguration, not to IPv6 link local addresses.
+     *
      * Since: 1.4
      **/
     /* ---ifcfg-rh---
@@ -989,6 +1140,35 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
                                               NMSettingIP6ConfigPrivate,
                                               dhcp_duid);
 
+    /**
+     * NMSettingIP6Config:dhcp-pd-hint:
+     *
+     * A IPv6 address followed by a slash and a prefix length. If set, the value is
+     * sent to the DHCPv6 server as hint indicating the prefix delegation (IA_PD) we
+     * want to receive.
+     * To only hint a prefix length without prefix, set the address part to the
+     * zero address (for example "::/60").
+     *
+     * Since: 1.44
+     **/
+    /* ---ifcfg-rh---
+     * property: dhcp-pd-hint
+     * variable: DHCPV6_PD_HINT(+)
+     * description: Hint for DHCPv6 prefix delegation
+     * example: DHCPV6_PD_HINT=2001:db8:1111:2220::/60
+     *          DHCPV6_PD_HINT=::/60
+     * ---end---
+     */
+    _nm_setting_property_define_direct_string(properties_override,
+                                              obj_properties,
+                                              NM_SETTING_IP6_CONFIG_DHCP_PD_HINT,
+                                              PROP_DHCP_PD_HINT,
+                                              NM_SETTING_PARAM_NONE,
+                                              NMSettingIP6ConfigPrivate,
+                                              dhcp_pd_hint,
+                                              .direct_hook.set_string_fcn =
+                                                  _set_string_fcn_dhcp_pd_hint);
+
     /* IP6-specific property overrides */
 
     /* ---dbus---
@@ -1075,6 +1255,7 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
     /* ---nmcli---
      * property: routes
      * format: a comma separated list of routes
+     * description: Array of IP routes.
      * description-docbook:
      *   <para>
      *     A list of IPv6 destination addresses, prefix length, optional IPv6
@@ -1199,6 +1380,45 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
      * ---end---
      */
 
+    /* ---nmcli---
+     * property: method
+     * format: string
+     * description: The IPv6 connection method.
+     * description-docbook:
+     *   <para>
+     *     Sets the IPv6 connection method. You can set one of the following values:
+     *   </para>
+     *   <para>
+     *     <itemizedlist>
+     *        <listitem>
+     *          <para><literal>"auto"</literal> - Enables IPv6 auto-configuration. By default, NetworkManager uses Router Advertisements and, if the router announces the "managed" flag, NetworkManager requests an IPv6 address and prefix from a DHCPv6 server.</para>
+     *        </listitem>
+     *        <listitem>
+     *          <para><literal>"dhcp"</literal> - Requests an IPv6 address and prefix from a DHCPv6 server. Note that DHCPv6 does not have options to provide routes and the default gateway. As a consequence, by using the "dhcp" method, connections are limited to their own subnet.</para>
+     *        </listitem>
+     *        <listitem>
+     *          <para><literal>"manual"</literal> - Enables the configuration of static IPv6 addresses on the interface. Note that you must set at least one IP address and prefix in the "ipv6.addresses" property.</para>
+     *        </listitem>
+     *        <listitem>
+     *          <para><literal>"disabled"</literal> - Disables the IPv6 protocol in this connection profile.</para>
+     *        </listitem>
+     *        <listitem>
+     *          <para><literal>"ignore"</literal> - Configures NetworkManager to make no changes to the IPv6 configuration on the interface. For example, you can then use the "accept_ra" feature of the kernel to accept Router Advertisements.</para>
+     *        </listitem>
+     *        <listitem>
+     *          <para><literal>"shared"</literal> - Provides network access to other computers. NetworkManager requests a prefix from an upstream DHCPv6 server, assigns an address to the interface, and announces the prefix to clients that connect to this interface.</para>
+     *        </listitem>
+     *        <listitem>
+     *          <para><literal>"link-local"</literal> - Assigns a random link-local address from the fe80::/64 subnet to the interface.</para>
+     *        </listitem>
+     *     </itemizedlist>
+     *     <para>
+     *       If you set <literal>"auto"</literal>, <literal>"dhcp"</literal>, <literal>"manual"</literal>, <literal>"ignore"</literal>, or <literal>"shared"</literal>, NetworkManager assigns, in addition to the global address, an IPv6 link-local address to the interface. This is compliant with RFC 4291.
+     *     </para>
+     *   </para>
+     * ---end---
+     */
+
     g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 
     _nm_setting_class_commit(setting_class,
diff --git a/src/libnm-core-impl/nm-setting-link.c b/src/libnm-core-impl/nm-setting-link.c
new file mode 100644
index 00000000..29d56d67
--- /dev/null
+++ b/src/libnm-core-impl/nm-setting-link.c
@@ -0,0 +1,241 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2023 Red Hat, Inc.
+ */
+
+#include "libnm-core-impl/nm-default-libnm-core.h"
+
+#include "nm-setting-link.h"
+
+#include "nm-setting-private.h"
+#include "nm-utils-private.h"
+
+/**
+ * SECTION:nm-setting-link
+ * @short_description: Contains properties related to the link
+ * @include: nm-setting-link.h
+ **/
+
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE(NMSettingLink,
+                             PROP_TX_QUEUE_LENGTH,
+                             PROP_GSO_MAX_SIZE,
+                             PROP_GSO_MAX_SEGMENTS,
+                             PROP_GRO_MAX_SIZE, );
+
+/**
+ * NMSettingLink:
+ *
+ * Link settings
+ *
+ * Since: 1.44
+ */
+struct _NMSettingLink {
+    NMSetting parent;
+    gint64    tx_queue_length;
+    gint64    gso_max_size;
+    gint64    gso_max_segments;
+    gint64    gro_max_size;
+};
+
+struct _NMSettingLinkClass {
+    NMSettingClass parent;
+};
+
+G_DEFINE_TYPE(NMSettingLink, nm_setting_link, NM_TYPE_SETTING)
+
+/**
+ * nm_setting_link_get_tx_queue_length:
+ * @setting: the #NMSettingLink
+ *
+ * Returns the value contained in the #NMSettingLink:tx-queue-length
+ * property.
+ *
+ * Returns: the 'tx-queue-length' property value
+ *
+ * Since: 1.44
+ **/
+gint64
+nm_setting_link_get_tx_queue_length(NMSettingLink *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_LINK(setting), 0);
+
+    return setting->tx_queue_length;
+}
+
+/**
+ * nm_setting_link_get_gso_max_size:
+ * @setting: the #NMSettingLink
+ *
+ * Returns the value contained in the #NMSettingLink:gso-max-size
+ * property.
+ *
+ * Returns: the 'gso-max-size' property value
+ *
+ * Since: 1.44
+ **/
+gint64
+nm_setting_link_get_gso_max_size(NMSettingLink *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_LINK(setting), 0);
+
+    return setting->gso_max_size;
+}
+
+/**
+ * nm_setting_link_get_gso_max_segments:
+ * @setting: the #NMSettingLink
+ *
+ * Returns the value contained in the #NMSettingLink:gso-max-segments
+ * property.
+ *
+ * Returns: the 'gso-max-segments' property value
+ *
+ * Since: 1.44
+ **/
+gint64
+nm_setting_link_get_gso_max_segments(NMSettingLink *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_LINK(setting), 0);
+
+    return setting->gso_max_segments;
+}
+
+/**
+ * nm_setting_link_get_gro_max_size:
+ * @setting: the #NMSettingLink
+ *
+ * Returns the value contained in the #NMSettingLink:gro-max-size
+ * property.
+ *
+ * Returns: the 'gro-max-size' property value
+ *
+ * Since: 1.44
+ **/
+gint64
+nm_setting_link_get_gro_max_size(NMSettingLink *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_LINK(setting), 0);
+
+    return setting->gro_max_size;
+}
+
+/*****************************************************************************/
+
+static void
+nm_setting_link_init(NMSettingLink *setting)
+{}
+
+/**
+ * nm_setting_link_new:
+ *
+ * Creates a new #NMSettingLink object with default values.
+ *
+ * Returns: (transfer full): the new empty #NMSettingLink object
+ *
+ * Since: 1.44
+ **/
+NMSetting *
+nm_setting_link_new(void)
+{
+    return g_object_new(NM_TYPE_SETTING_LINK, NULL);
+}
+
+static void
+nm_setting_link_class_init(NMSettingLinkClass *klass)
+{
+    GObjectClass   *object_class        = G_OBJECT_CLASS(klass);
+    NMSettingClass *setting_class       = NM_SETTING_CLASS(klass);
+    GArray         *properties_override = _nm_sett_info_property_override_create_array();
+
+    object_class->get_property = _nm_setting_property_get_property_direct;
+    object_class->set_property = _nm_setting_property_set_property_direct;
+
+    /**
+     * NMSettingLink:tx-queue-length
+     *
+     * The size of the transmit queue for the device, in number of packets. The value
+     * must be between 0 and 4294967295. When set to -1, the existing value is preserved.
+     *
+     * Since: 1.44
+     **/
+    _nm_setting_property_define_direct_int64(properties_override,
+                                             obj_properties,
+                                             NM_SETTING_LINK_TX_QUEUE_LENGTH,
+                                             PROP_TX_QUEUE_LENGTH,
+                                             -1,
+                                             G_MAXUINT32,
+                                             -1,
+                                             NM_SETTING_PARAM_NONE,
+                                             NMSettingLink,
+                                             tx_queue_length);
+
+    /**
+     * NMSettingLink:gso-max-size
+     *
+     * The maximum size of a Generic Segment Offload packet the device should accept.
+     * The value must be between 0 and 4294967295. When set to -1, the existing value
+     * is preserved.
+     *
+     * Since: 1.44
+     **/
+    _nm_setting_property_define_direct_int64(properties_override,
+                                             obj_properties,
+                                             NM_SETTING_LINK_GSO_MAX_SIZE,
+                                             PROP_GSO_MAX_SIZE,
+                                             -1,
+                                             G_MAXUINT32,
+                                             -1,
+                                             NM_SETTING_PARAM_NONE,
+                                             NMSettingLink,
+                                             gso_max_size);
+
+    /**
+     * NMSettingLink:gso-max-segments
+     *
+     * The maximum segments of a Generic Segment Offload packet the device should accept.
+     * The value must be between 0 and 4294967295. When set to -1, the existing value
+     * is preserved.
+     *
+     * Since: 1.44
+     **/
+    _nm_setting_property_define_direct_int64(properties_override,
+                                             obj_properties,
+                                             NM_SETTING_LINK_GSO_MAX_SEGMENTS,
+                                             PROP_GSO_MAX_SEGMENTS,
+                                             -1,
+                                             G_MAXUINT32,
+                                             -1,
+                                             NM_SETTING_PARAM_NONE,
+                                             NMSettingLink,
+                                             gso_max_segments);
+
+    /**
+     * NMSettingLink:gro-max-size
+     *
+     * The maximum size of a packet built by the Generic Receive Offload stack for
+     * this device. The value must be between 0 and 4294967295. When set to -1, the
+     * existing value is preserved.
+     *
+     * Since: 1.44
+     **/
+    _nm_setting_property_define_direct_int64(properties_override,
+                                             obj_properties,
+                                             NM_SETTING_LINK_GRO_MAX_SIZE,
+                                             PROP_GRO_MAX_SIZE,
+                                             -1,
+                                             G_MAXUINT32,
+                                             -1,
+                                             NM_SETTING_PARAM_NONE,
+                                             NMSettingLink,
+                                             gro_max_size);
+
+    g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+
+    _nm_setting_class_commit(setting_class,
+                             NM_META_SETTING_TYPE_LINK,
+                             NULL,
+                             properties_override,
+                             0);
+}
diff --git a/src/libnm-core-impl/nm-setting-match.c b/src/libnm-core-impl/nm-setting-match.c
index f0e9fdf8..0ece65f1 100644
--- a/src/libnm-core-impl/nm-setting-match.c
+++ b/src/libnm-core-impl/nm-setting-match.c
@@ -171,7 +171,7 @@ nm_setting_match_clear_interface_names(NMSettingMatch *setting)
 /**
  * nm_setting_match_get_interface_names:
  * @setting: the #NMSettingMatch
- * @length: (out) (allow-none): the length of the returned interface names array.
+ * @length: (out) (optional): the length of the returned interface names array.
  *
  * Returns all the interface names.
  *
@@ -317,7 +317,7 @@ nm_setting_match_clear_kernel_command_lines(NMSettingMatch *setting)
 /**
  * nm_setting_match_get_kernel_command_lines:
  * @setting: the #NMSettingMatch
- * @length: (out) (allow-none): the length of the returned interface names array.
+ * @length: (out) (optional): the length of the returned interface names array.
  *
  * Returns all the interface names.
  *
@@ -456,7 +456,7 @@ nm_setting_match_clear_drivers(NMSettingMatch *setting)
 /**
  * nm_setting_match_get_drivers:
  * @setting: the #NMSettingMatch
- * @length: (out) (allow-none): the length of the returned interface names array.
+ * @length: (out) (optional): the length of the returned interface names array.
  *
  * Returns all the drivers.
  *
@@ -595,7 +595,7 @@ nm_setting_match_clear_paths(NMSettingMatch *setting)
 /**
  * nm_setting_match_get_paths:
  * @setting: the #NMSettingMatch
- * @length: (out) (allow-none): the length of the returned paths array.
+ * @length: (out) (optional): the length of the returned paths array.
  *
  * Returns all the paths.
  *
diff --git a/src/libnm-core-impl/nm-setting-ovs-external-ids.c b/src/libnm-core-impl/nm-setting-ovs-external-ids.c
index 54684380..0cdf3e6b 100644
--- a/src/libnm-core-impl/nm-setting-ovs-external-ids.c
+++ b/src/libnm-core-impl/nm-setting-ovs-external-ids.c
@@ -56,7 +56,7 @@ G_DEFINE_TYPE(NMSettingOvsExternalIDs, nm_setting_ovs_external_ids, NM_TYPE_SETT
 
 /**
  * nm_setting_ovs_external_ids_check_key:
- * @key: (allow-none): the key to check
+ * @key: (nullable): the key to check
  * @error: a #GError, %NULL to ignore.
  *
  * Checks whether @key is a valid key for OVS' external-ids.
@@ -171,7 +171,7 @@ _nm_setting_ovs_verify_connection_type(GType gtype, NMConnection *connection, GE
 
 /**
  * nm_setting_ovs_external_ids_check_val:
- * @val: (allow-none): the value to check
+ * @val: (nullable): the value to check
  * @error: a #GError, %NULL to ignore.
  *
  * Checks whether @val is a valid user data value. This means,
@@ -297,7 +297,7 @@ nm_setting_ovs_external_ids_get_data(NMSettingOvsExternalIDs *setting, const cha
  * nm_setting_ovs_external_ids_set_data:
  * @setting: the #NMSettingOvsExternalIDs instance
  * @key: the key to set
- * @val: (allow-none): the value to set or %NULL to clear a key.
+ * @val: (nullable): the value to set or %NULL to clear a key.
  *
  * Since: 1.30
  */
diff --git a/src/libnm-core-impl/nm-setting-ovs-other-config.c b/src/libnm-core-impl/nm-setting-ovs-other-config.c
index ca46ae95..46d991d4 100644
--- a/src/libnm-core-impl/nm-setting-ovs-other-config.c
+++ b/src/libnm-core-impl/nm-setting-ovs-other-config.c
@@ -135,7 +135,7 @@ nm_setting_ovs_other_config_get_data(NMSettingOvsOtherConfig *setting, const cha
  * nm_setting_ovs_other_config_set_data:
  * @setting: the #NMSettingOvsOtherConfig instance
  * @key: the key to set
- * @val: (allow-none): the value to set or %NULL to clear a key.
+ * @val: (nullable): the value to set or %NULL to clear a key.
  *
  * Since: 1.42
  */
diff --git a/src/libnm-core-impl/nm-setting-sriov.c b/src/libnm-core-impl/nm-setting-sriov.c
index 091cc0c6..b9faad56 100644
--- a/src/libnm-core-impl/nm-setting-sriov.c
+++ b/src/libnm-core-impl/nm-setting-sriov.c
@@ -286,7 +286,7 @@ nm_sriov_vf_get_index(const NMSriovVF *vf)
  * nm_sriov_vf_set_attribute:
  * @vf: the #NMSriovVF
  * @name: the name of a route attribute
- * @value: (transfer none) (allow-none): the value
+ * @value: (transfer none) (nullable): the value
  *
  * Sets the named attribute on @vf to the given value.
  *
@@ -364,8 +364,8 @@ const NMVariantAttributeSpec *const _nm_sriov_vf_attribute_spec[] = {
  * nm_sriov_vf_attribute_validate:
  * @name: the attribute name
  * @value: the attribute value
- * @known: (out): on return, whether the attribute name is a known one
- * @error: (allow-none): return location for a #GError, or %NULL
+ * @known: (out) (optional): on return, whether the attribute name is a known one
+ * @error: return location for a #GError, or %NULL
  *
  * Validates a VF attribute, i.e. checks that the attribute is a known one,
  * the value is of the correct type and well-formed.
@@ -533,7 +533,7 @@ vlan_id_compare(gconstpointer a, gconstpointer b, gpointer user_data)
 /**
  * nm_sriov_vf_get_vlan_ids:
  * @vf: the #NMSriovVF
- * @length: (out) (allow-none): on return, the number of VLANs configured
+ * @length: (out) (optional): on return, the number of VLANs configured
  *
  * Returns the VLANs currently configured on the VF. Currently kernel only
  * supports one VLAN per VF.
diff --git a/src/libnm-core-impl/nm-setting-tc-config.c b/src/libnm-core-impl/nm-setting-tc-config.c
index 80135201..c5947e40 100644
--- a/src/libnm-core-impl/nm-setting-tc-config.c
+++ b/src/libnm-core-impl/nm-setting-tc-config.c
@@ -359,7 +359,7 @@ nm_tc_qdisc_get_attribute(NMTCQdisc *qdisc, const char *name)
  * nm_tc_qdisc_set_attribute:
  * @qdisc: the #NMTCQdisc
  * @name: the name of an qdisc attribute
- * @value: (transfer none) (allow-none): the value
+ * @value: (transfer none) (nullable): the value
  *
  * Sets or clears the named attribute on @qdisc to the given value.
  *
@@ -634,7 +634,7 @@ nm_tc_action_get_attribute(NMTCAction *action, const char *name)
  * nm_tc_action_set_attribute:
  * @action: the #NMTCAction
  * @name: the name of an action attribute
- * @value: (transfer none) (allow-none): the value
+ * @value: (transfer none) (nullable): the value
  *
  * Sets or clears the named attribute on @action to the given value.
  *
@@ -1794,6 +1794,12 @@ nm_setting_tc_config_class_init(NMSettingTCConfigClass *klass)
     /* ---nmcli---
      * property: qdiscs
      * format: GPtrArray(NMTCQdisc)
+     * description: Array of TC queueing disciplines. When the "tc" setting is
+     *   present, qdiscs from this property are applied upon activation. If the
+     *   property is empty, all qdiscs are removed and the device will only have
+     *   the default qdisc assigned by kernel according to the
+     *   "net.core.default_qdisc" sysctl. If the "tc" setting is not present,
+     *   NetworkManager doesn't touch the qdiscs present on the interface.
      * description-docbook:
      *  <para>
      *  Array of TC queueing disciplines. qdisc is a basic block in the
@@ -2106,6 +2112,11 @@ nm_setting_tc_config_class_init(NMSettingTCConfigClass *klass)
     /* ---nmcli---
      * property: tfilters
      * format: GPtrArray(NMTCTfilter)
+     * description: Array of TC traffic filters. When the "tc" setting is
+     *   present, filters from this property are applied upon activation. If the
+     *   property is empty, NetworkManager removes all the filters. If the "tc"
+     *   setting is not present, NetworkManager doesn't touch the filters present
+     *   on the interface.
      * description-docbook:
      *  <para>
      *   Array of TC traffic filters. Traffic control can manage the packet content during
diff --git a/src/libnm-core-impl/nm-setting-team.c b/src/libnm-core-impl/nm-setting-team.c
index e6e375e7..83de8b6f 100644
--- a/src/libnm-core-impl/nm-setting-team.c
+++ b/src/libnm-core-impl/nm-setting-team.c
@@ -143,7 +143,7 @@ nm_team_link_watcher_new_ethtool(int delay_up, int delay_down, GError **error)
  * @missed_max: missed_max value
  * @target_host: the host name or the ipv6 address that will be used as
  *   target address in the NS packet
- * @error: (out) (allow-none): location to store the error on failure
+ * @error: location to store the error on failure
  *
  * Creates a new nsna_ping #NMTeamLinkWatcher object
  *
@@ -223,7 +223,7 @@ nm_team_link_watcher_new_nsna_ping(int         init_wait,
  * @source_host: the host name or the ip address that will be used as source
  *   address in the arp request
  * @flags: the watcher #NMTeamLinkWatcherArpPingFlags
- * @error: (out) (allow-none): location to store the error on failure
+ * @error: location to store the error on failure
  *
  * Creates a new arp_ping #NMTeamLinkWatcher object
  *
@@ -261,7 +261,7 @@ nm_team_link_watcher_new_arp_ping(int                           init_wait,
  * @source_host: the host name or the ip address that will be used as source
  *   address in the arp request
  * @flags: the watcher #NMTeamLinkWatcherArpPingFlags
- * @error: (out) (allow-none): location to store the error on failure
+ * @error: location to store the error on failure
  *
  * Creates a new arp_ping #NMTeamLinkWatcher object
  *
diff --git a/src/libnm-core-impl/nm-setting-user.c b/src/libnm-core-impl/nm-setting-user.c
index 70bdc62a..8c2a9942 100644
--- a/src/libnm-core-impl/nm-setting-user.c
+++ b/src/libnm-core-impl/nm-setting-user.c
@@ -268,8 +268,8 @@ nm_setting_user_get_data(NMSettingUser *setting, const char *key)
  * nm_setting_user_set_data:
  * @setting: the #NMSettingUser instance
  * @key: the key to set
- * @val: (allow-none): the value to set or %NULL to clear a key.
- * @error: (allow-none): optional error argument
+ * @val: (nullable): the value to set or %NULL to clear a key.
+ * @error: optional error argument
  *
  * Since: 1.8
  *
diff --git a/src/libnm-core-impl/nm-setting-vlan.c b/src/libnm-core-impl/nm-setting-vlan.c
index 696799d8..e5a99ce9 100644
--- a/src/libnm-core-impl/nm-setting-vlan.c
+++ b/src/libnm-core-impl/nm-setting-vlan.c
@@ -297,8 +297,8 @@ nm_setting_vlan_get_num_priorities(NMSettingVlan *setting, NMVlanPriorityMap map
  * @setting: the #NMSettingVlan
  * @map: the type of priority map
  * @idx: the zero-based index of the ingress/egress priority map entry
- * @out_from: (out) (allow-none): on return the value of the priority map's 'from' item
- * @out_to: (out) (allow-none): on return the value of priority map's 'to' item
+ * @out_from: (out) (optional): on return the value of the priority map's 'from' item
+ * @out_to: (out) (optional): on return the value of priority map's 'to' item
  *
  * Retrieve one of the entries of the #NMSettingVlan:ingress_priority_map
  * or #NMSettingVlan:egress_priority_map properties of this setting.
diff --git a/src/libnm-core-impl/nm-setting-vpn.c b/src/libnm-core-impl/nm-setting-vpn.c
index 4ff98908..5984f773 100644
--- a/src/libnm-core-impl/nm-setting-vpn.c
+++ b/src/libnm-core-impl/nm-setting-vpn.c
@@ -178,7 +178,7 @@ nm_setting_vpn_get_num_data_items(NMSettingVpn *setting)
  * nm_setting_vpn_add_data_item:
  * @setting: the #NMSettingVpn
  * @key: a name that uniquely identifies the given value @item
- * @item: (allow-none): the value to be referenced by @key
+ * @item: (nullable): the value to be referenced by @key
  *
  * Establishes a relationship between @key and @item internally in the
  * setting which may be retrieved later.  Should not be used to store passwords
@@ -227,11 +227,11 @@ nm_setting_vpn_get_data_item(NMSettingVpn *setting, const char *key)
 /**
  * nm_setting_vpn_get_data_keys:
  * @setting: the #NMSettingVpn
- * @out_length: (allow-none) (out): the length of the returned array
+ * @out_length: (out) (optional): the length of the returned array
  *
  * Retrieves every data key inside @setting, as an array.
  *
- * Returns: (array length=out_length) (transfer container): a
+ * Returns: (array length=out_length) (transfer container) (nullable): a
  *   %NULL-terminated array containing each data key or %NULL if
  *   there are no data items.
  *
@@ -346,7 +346,7 @@ nm_setting_vpn_get_num_secrets(NMSettingVpn *setting)
  * nm_setting_vpn_add_secret:
  * @setting: the #NMSettingVpn
  * @key: a name that uniquely identifies the given secret @secret
- * @secret: (allow-none): the secret to be referenced by @key
+ * @secret: (nullable): the secret to be referenced by @key
  *
  * Establishes a relationship between @key and @secret internally in the
  * setting which may be retrieved later.
@@ -394,11 +394,11 @@ nm_setting_vpn_get_secret(NMSettingVpn *setting, const char *key)
 /**
  * nm_setting_vpn_get_secret_keys:
  * @setting: the #NMSettingVpn
- * @out_length: (allow-none) (out): the length of the returned array
+ * @out_length: (out) (optional): the length of the returned array
  *
  * Retrieves every secret key inside @setting, as an array.
  *
- * Returns: (array length=out_length) (transfer container): a
+ * Returns: (array length=out_length) (transfer container) (nullable): a
  *   %NULL-terminated array containing each secret key or %NULL if
  *   there are no secrets.
  *
diff --git a/src/libnm-core-impl/nm-setting-wired.c b/src/libnm-core-impl/nm-setting-wired.c
index 3acd5d97..1ee16df5 100644
--- a/src/libnm-core-impl/nm-setting-wired.c
+++ b/src/libnm-core-impl/nm-setting-wired.c
@@ -507,11 +507,12 @@ nm_setting_wired_get_num_s390_options(NMSettingWired *setting)
  * @setting: the #NMSettingWired
  * @idx: index of the desired option, from 0 to
  * nm_setting_wired_get_num_s390_options() - 1
- * @out_key: (allow-none) (out) (transfer none): on return, the key name of the s390 specific
- *   option; this value is owned by the setting and should not be modified
- * @out_value: (allow-none) (out) (transfer none): on return, the value of the key of the
- *   s390 specific option; this value is owned by the setting and should not be
- *   modified
+ * @out_key: (out) (optional) (nullable) (transfer none): on return, the key
+ *   name of the s390 specific option; this value is owned by the setting and
+ *   should not be modified
+ * @out_value: (out) (optional) (nullable) (transfer none): on return, the value
+ *   of the key of the s390 specific option; this value is owned by the setting
+ *   and should not be modified
  *
  * Given an index, return the value of the s390 option at that index.  indexes
  * are *not* guaranteed to be static across modifications to options done by
@@ -701,7 +702,7 @@ _nm_setting_wired_clear_s390_options(NMSettingWired *setting)
 
 /**
  * nm_setting_wired_get_valid_s390_options:
- * @setting: (allow-none): the #NMSettingWired. This argument is unused
+ * @setting: (nullable): the #NMSettingWired. This argument is unused
  *   and you may pass %NULL.
  *
  * Returns a list of valid s390 options.
diff --git a/src/libnm-core-impl/nm-setting-wireguard.c b/src/libnm-core-impl/nm-setting-wireguard.c
index a981187f..b0e3f66c 100644
--- a/src/libnm-core-impl/nm-setting-wireguard.c
+++ b/src/libnm-core-impl/nm-setting-wireguard.c
@@ -125,7 +125,7 @@ nm_wireguard_peer_new_clone(const NMWireGuardPeer *self, gboolean with_secrets)
 
 /**
  * nm_wireguard_peer_ref:
- * @self: (allow-none): the #NMWireGuardPeer instance
+ * @self: (nullable): the #NMWireGuardPeer instance
  *
  * Returns: returns the input argument @self after incrementing
  *   the reference count.
@@ -150,7 +150,7 @@ nm_wireguard_peer_ref(NMWireGuardPeer *self)
 
 /**
  * nm_wireguard_peer_unref:
- * @self: (allow-none): the #NMWireGuardPeer instance
+ * @self: (nullable): the #NMWireGuardPeer instance
  *
  * Drop a reference to @self. If the last reference is dropped,
  * the instance is freed and all associate data released.
@@ -260,7 +260,7 @@ nm_wireguard_peer_get_public_key(const NMWireGuardPeer *self)
 /**
  * nm_wireguard_peer_set_public_key:
  * @self: the unsealed #NMWireGuardPeer instance
- * @public_key: (allow-none) (transfer none): the new public
+ * @public_key: (nullable) (transfer none): the new public
  *   key or %NULL to clear the public key.
  * @accept_invalid: if %TRUE and @public_key is not %NULL and
  *   invalid, then do not modify the instance.
@@ -339,7 +339,7 @@ nm_wireguard_peer_get_preshared_key(const NMWireGuardPeer *self)
 /**
  * nm_wireguard_peer_set_preshared_key:
  * @self: the unsealed #NMWireGuardPeer instance
- * @preshared_key: (allow-none) (transfer none): the new preshared
+ * @preshared_key: (nullable) (transfer none): the new preshared
  *   key or %NULL to clear the preshared key.
  * @accept_invalid: whether to allow setting the key to an invalid
  *   value. If %FALSE, @self is unchanged if the key is invalid
@@ -564,13 +564,13 @@ nm_wireguard_peer_get_allowed_ips_len(const NMWireGuardPeer *self)
  * @self: the #NMWireGuardPeer instance
  * @idx: the index from zero to (allowed-ips-len - 1) to
  *   retrieve.
- * @out_is_valid: (allow-none): %TRUE if the returned value is a valid allowed-ip
+ * @out_is_valid: (nullable): %TRUE if the returned value is a valid allowed-ip
  *   setting.
  *   This parameter is wrongly not marked as (out) argument, it is
  *   thus not accessible via introspection. This cannot be fixed without
  *   breaking API for introspection users.
  *
- * Returns: (transfer none): the allowed-ip setting at index @idx.
+ * Returns: (transfer none) (nullable): the allowed-ip setting at index @idx.
  *   If @idx is out of range, %NULL will be returned.
  *
  * Since: 1.16
@@ -813,8 +813,8 @@ nm_wireguard_peer_is_valid(const NMWireGuardPeer *self,
 
 /**
  * nm_wireguard_peer_cmp:
- * @a: (allow-none): the #NMWireGuardPeer to compare.
- * @b: (allow-none): the other #NMWireGuardPeer to compare.
+ * @a: (nullable): the #NMWireGuardPeer to compare.
+ * @b: (nullable): the other #NMWireGuardPeer to compare.
  * @compare_flags: #NMSettingCompareFlags to affect the comparison.
  *
  * Returns: zero of the two instances are equivalent or
@@ -1222,11 +1222,11 @@ nm_setting_wireguard_get_peer(NMSettingWireGuard *self, guint idx)
  * @self: the #NMSettingWireGuard instance
  * @public_key: the public key for looking up the
  *   peer.
- * @out_idx: (out) (allow-none): optional output argument
+ * @out_idx: (out) (optional): optional output argument
  *   for the index of the found peer. If no index is found,
  *   this is set to the nm_setting_wireguard_get_peers_len().
  *
- * Returns: (transfer none): the #NMWireGuardPeer instance with a
+ * Returns: (transfer none) (nullable): the #NMWireGuardPeer instance with a
  *   matching public key. If no such peer exists, %NULL is returned.
  *
  * Since: 1.16
diff --git a/src/libnm-core-impl/nm-setting-wireless.c b/src/libnm-core-impl/nm-setting-wireless.c
index 33e16d4b..e2cd1f49 100644
--- a/src/libnm-core-impl/nm-setting-wireless.c
+++ b/src/libnm-core-impl/nm-setting-wireless.c
@@ -392,6 +392,8 @@ nm_setting_wireless_get_bssid(NMSettingWireless *setting)
  * @setting: the #NMSettingWireless
  *
  * Returns: the #NMSettingWireless:rate property of the setting
+ *
+ * Deprecated: 1.44: This setting is not implemented and has no effect.
  **/
 guint32
 nm_setting_wireless_get_rate(NMSettingWireless *setting)
@@ -406,6 +408,8 @@ nm_setting_wireless_get_rate(NMSettingWireless *setting)
  * @setting: the #NMSettingWireless
  *
  * Returns: the #NMSettingWireless:tx-power property of the setting
+ *
+ * Deprecated: 1.44: This setting is not implemented and has no effect.
  **/
 guint32
 nm_setting_wireless_get_tx_power(NMSettingWireless *setting)
@@ -1100,6 +1104,19 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
     return NM_SETTING_VERIFY_NORMALIZABLE;
 mac_addr_rand_ok:
 
+    if (priv->tx_power != 0 || priv->rate != 0) {
+        g_set_error(error,
+                    NM_CONNECTION_ERROR,
+                    NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                    _("property is deprecated and not implemented"));
+        g_prefix_error(error,
+                       "%s.%s: ",
+                       NM_SETTING_WIRELESS_SETTING_NAME,
+                       priv->tx_power != 0 ? NM_SETTING_WIRELESS_TX_POWER
+                                           : NM_SETTING_WIRELESS_RATE);
+        return NM_SETTING_VERIFY_NORMALIZABLE;
+    }
+
     return TRUE;
 }
 
@@ -1434,15 +1451,14 @@ nm_setting_wireless_class_init(NMSettingWirelessClass *klass)
     /**
      * NMSettingWireless:rate:
      *
-     * If non-zero, directs the device to only use the specified bitrate for
-     * communication with the access point.  Units are in Kb/s, ie 5500 = 5.5
-     * Mbit/s.  This property is highly driver dependent and not all devices
-     * support setting a static bitrate.
+     * This property is not implemented and has no effect.
+     *
+     * Deprecated: 1.44: This property is not implemented and has no effect.
      **/
     /* ---ifcfg-rh---
      * property: rate
      * variable: (none)
-     * description: This property is not handled by ifcfg-rh plugin.
+     * description: This property is deprecated and not handled by ifcfg-rh plugin.
      * ---end---
      */
     _nm_setting_property_define_direct_uint32(properties_override,
@@ -1454,19 +1470,20 @@ nm_setting_wireless_class_init(NMSettingWirelessClass *klass)
                                               0,
                                               NM_SETTING_PARAM_FUZZY_IGNORE,
                                               NMSettingWirelessPrivate,
-                                              rate);
+                                              rate,
+                                              .is_deprecated = TRUE, );
 
     /**
      * NMSettingWireless:tx-power:
      *
-     * If non-zero, directs the device to use the specified transmit power.
-     * Units are dBm.  This property is highly driver dependent and not all
-     * devices support setting a static transmit power.
+     * This property is not implemented and has no effect.
+     *
+     * Deprecated: 1.44: This property is not implemented and has no effect.
      **/
     /* ---ifcfg-rh---
      * property: tx-power
      * variable: (none)
-     * description: This property is not handled by ifcfg-rh plugin.
+     * description: This property is deprecated and not handled by ifcfg-rh plugin.
      * ---end---
      */
     _nm_setting_property_define_direct_uint32(properties_override,
@@ -1478,7 +1495,8 @@ nm_setting_wireless_class_init(NMSettingWirelessClass *klass)
                                               0,
                                               NM_SETTING_PARAM_FUZZY_IGNORE,
                                               NMSettingWirelessPrivate,
-                                              tx_power);
+                                              tx_power,
+                                              .is_deprecated = TRUE, );
 
     /**
      * NMSettingWireless:mac-address:
@@ -1675,11 +1693,16 @@ nm_setting_wireless_class_init(NMSettingWirelessClass *klass)
      * property is only meant for reading and reflects the BSSID list of
      * NetworkManager. The changes you make to this property will not be
      * preserved.
+     *
+     * This is not a regular property that the user would configure. Instead,
+     * NetworkManager automatically sets the seen BSSIDs and tracks them internally
+     * in "/var/lib/NetworkManager/seen-bssids" file.
      **/
     /* ---ifcfg-rh---
      * property: seen-bssids
      * variable: (none)
-     * description: This property is not handled by ifcfg-rh plugin.
+     * description: This is not a regular property that would be configured by the
+     *   user. It is not handled by ifcfg-rh plugin.
      * ---end---
      */
     obj_properties[PROP_SEEN_BSSIDS] = g_param_spec_boxed(
@@ -1814,19 +1837,11 @@ nm_setting_wireless_class_init(NMSettingWirelessClass *klass)
                                               mac_address_randomization,
                                               .is_deprecated = TRUE, );
 
-    /* Compatibility for deprecated property */
-    /* ---ifcfg-rh---
-     * property: security
-     * variable: (none)
-     * description: This property is deprecated and not handled by ifcfg-rh-plugin.
-     * ---end---
-     */
     /* ---dbus---
      * property: security
-     * description: This property is deprecated, but can be set to the value
-     *   '802-11-wireless-security' when a wireless security setting is also
-     *   present in the connection dictionary, for compatibility with very old
-     *   NetworkManager daemons.
+     * description: This property is deprecated and has no effect.
+     * For backwards compatibility, it can be set to "802-11-wireless-security"
+     * if the profile has a wireless security setting.
      * ---end---
      */
     _nm_properties_override_dbus(
diff --git a/src/libnm-core-impl/nm-setting.c b/src/libnm-core-impl/nm-setting.c
index 5a46a1b4..276dfd34 100644
--- a/src/libnm-core-impl/nm-setting.c
+++ b/src/libnm-core-impl/nm-setting.c
@@ -110,6 +110,10 @@ nm_setting_lookup_type(const char *name)
 {
     const NMMetaSettingInfo *setting_info;
 
+    /* various callers check whether the result is valid with plain `if (gtype)`.
+     * Assert that G_TYPE_INVALID is zero. */
+    G_STATIC_ASSERT(G_TYPE_INVALID == 0);
+
     g_return_val_if_fail(name, G_TYPE_INVALID);
 
     setting_info = nm_meta_setting_infos_by_name(name);
@@ -2383,7 +2387,7 @@ nm_setting_get_name(NMSetting *setting)
 /**
  * nm_setting_verify:
  * @setting: the #NMSetting to verify
- * @connection: (allow-none): the #NMConnection that @setting came from, or
+ * @connection: (nullable): the #NMConnection that @setting came from, or
  *   %NULL if @setting is being verified in isolation.
  * @error: location to store error, or %NULL
  *
@@ -2421,7 +2425,7 @@ _nm_setting_verify(NMSetting *setting, NMConnection *connection, GError **error)
 /**
  * nm_setting_verify_secrets:
  * @setting: the #NMSetting to verify secrets in
- * @connection: (allow-none): the #NMConnection that @setting came from, or
+ * @connection: (nullable): the #NMConnection that @setting came from, or
  *   %NULL if @setting is being verified in isolation.
  * @error: location to store error, or %NULL
  *
@@ -3828,11 +3832,11 @@ out_zero:
 /**
  * nm_setting_option_get_all_names:
  * @setting: the #NMSetting
- * @out_len: (allow-none) (out):
+ * @out_len: (out) (optional):
  *
  * Gives the name of all set options.
  *
- * Returns: (array length=out_len zero-terminated=1) (transfer none):
+ * Returns: (array length=out_len zero-terminated=1) (transfer none) (nullable):
  *   A %NULL terminated array of key names. If no names are present, this returns
  *   %NULL. The returned array and the names are owned by %NMSetting and might be invalidated
  *   by the next operation.
@@ -3870,7 +3874,7 @@ _nm_setting_option_clear(NMSetting *setting, const char *optname)
 /**
  * nm_setting_option_clear_by_name:
  * @setting: the #NMSetting
- * @predicate: (allow-none) (scope call): the predicate for which names
+ * @predicate: (nullable) (scope call): the predicate for which names
  *   should be clear.
  *   If the predicate returns %TRUE for an option name, the option
  *   gets removed. If %NULL, all options will be removed.
@@ -3937,7 +3941,7 @@ nm_setting_option_get(NMSetting *setting, const char *opt_name)
  * nm_setting_option_get_boolean:
  * @setting: the #NMSetting
  * @opt_name: the option to get
- * @out_value: (allow-none) (out): the optional output value.
+ * @out_value: (out) (nullable): the optional output value.
  *   If the option is unset, %FALSE will be returned.
  *
  * Returns: %TRUE if @opt_name is set to a boolean variant.
@@ -3962,7 +3966,7 @@ nm_setting_option_get_boolean(NMSetting *setting, const char *opt_name, gboolean
  * nm_setting_option_get_uint32:
  * @setting: the #NMSetting
  * @opt_name: the option to get
- * @out_value: (allow-none) (out): the optional output value.
+ * @out_value: (out) (nullable): the optional output value.
  *   If the option is unset, 0 will be returned.
  *
  * Returns: %TRUE if @opt_name is set to a uint32 variant.
@@ -3987,7 +3991,7 @@ nm_setting_option_get_uint32(NMSetting *setting, const char *opt_name, guint32 *
  * nm_setting_option_set:
  * @setting: the #NMSetting
  * @opt_name: the option name to set
- * @variant: (allow-none): the variant to set.
+ * @variant: (nullable): the variant to set.
  *
  * If @variant is %NULL, this clears the option if it is set.
  * Otherwise, @variant is set as the option. If @variant is
@@ -4287,7 +4291,7 @@ nm_range_to_str(const NMRange *range)
 /**
  * nm_range_from_str:
  * @str: the string representation of a range
- * @error: (out) (allow-none): location to store the error on failure
+ * @error: location to store the error on failure
  *
  * Parses the string representation of the range to create a %NMRange
  * instance.
diff --git a/src/libnm-core-impl/nm-utils.c b/src/libnm-core-impl/nm-utils.c
index c389213f..2bd8936d 100644
--- a/src/libnm-core-impl/nm-utils.c
+++ b/src/libnm-core-impl/nm-utils.c
@@ -175,7 +175,7 @@ nm_sock_addr_endpoint_new(const char *endpoint)
 
 /**
  * nm_sock_addr_endpoint_ref:
- * @self: (allow-none): the #NMSockAddrEndpoint
+ * @self: (nullable): the #NMSockAddrEndpoint
  */
 NMSockAddrEndpoint *
 nm_sock_addr_endpoint_ref(NMSockAddrEndpoint *self)
@@ -193,7 +193,7 @@ nm_sock_addr_endpoint_ref(NMSockAddrEndpoint *self)
 
 /**
  * nm_sock_addr_endpoint_unref:
- * @self: (allow-none): the #NMSockAddrEndpoint
+ * @self: (nullable): the #NMSockAddrEndpoint
  */
 void
 nm_sock_addr_endpoint_unref(NMSockAddrEndpoint *self)
@@ -1380,7 +1380,7 @@ nm_utils_ip4_dns_from_variant(GVariant *value)
 /**
  * nm_utils_ip4_addresses_to_variant:
  * @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
- * @gateway: (allow-none): the gateway IP address
+ * @gateway: (nullable): the gateway IP address
  *
  * Utility function to convert a #GPtrArray of #NMIPAddress objects representing
  * IPv4 addresses into a #GVariant of type 'aau' representing an array of
@@ -1430,7 +1430,8 @@ nm_utils_ip4_addresses_to_variant(GPtrArray *addresses, const char *gateway)
 /**
  * nm_utils_ip4_addresses_from_variant:
  * @value: a #GVariant of type 'aau'
- * @out_gateway: (out) (allow-none) (transfer full): on return, will contain the IP gateway
+ * @out_gateway: (out) (optional) (nullable) (transfer full): on return, will
+ *   contain the IP gateway
  *
  * Utility function to convert a #GVariant of type 'aau' representing a list of
  * NetworkManager IPv4 addresses (which are tuples of address, prefix, and
@@ -1673,7 +1674,7 @@ nm_utils_ip6_dns_from_variant(GVariant *value)
 /**
  * nm_utils_ip6_addresses_to_variant:
  * @addresses: (element-type NMIPAddress): an array of #NMIPAddress objects
- * @gateway: (allow-none): the gateway IP address
+ * @gateway: (nullable): the gateway IP address
  *
  * Utility function to convert a #GPtrArray of #NMIPAddress objects representing
  * IPv6 addresses into a #GVariant of type 'a(ayuay)' representing an array of
@@ -1725,7 +1726,8 @@ nm_utils_ip6_addresses_to_variant(GPtrArray *addresses, const char *gateway)
 /**
  * nm_utils_ip6_addresses_from_variant:
  * @value: a #GVariant of type 'a(ayuay)'
- * @out_gateway: (out) (allow-none) (transfer full): on return, will contain the IP gateway
+ * @out_gateway: (out) (optional) (nullable) (transfer full): on return, will
+ *   contain the IP gateway
  *
  * Utility function to convert a #GVariant of type 'a(ayuay)' representing a
  * list of NetworkManager IPv6 addresses (which are tuples of address, prefix,
@@ -2821,7 +2823,7 @@ extern const NMVariantAttributeSpec *const _nm_sriov_vf_attribute_spec[];
  * nm_utils_sriov_vf_to_str:
  * @vf: the %NMSriovVF
  * @omit_index: if %TRUE, the VF index will be omitted from output string
- * @error: (out) (allow-none): location to store the error on failure
+ * @error: location to store the error on failure
  *
  * Converts a SR-IOV virtual function object to its string representation.
  *
@@ -2982,7 +2984,7 @@ _nm_sriov_vf_parse_vlans(NMSriovVF *vf, const char *str, GError **error)
 /**
  * nm_utils_sriov_vf_from_str:
  * @str: the input string
- * @error: (out) (allow-none): location to store the error on failure
+ * @error: location to store the error on failure
  *
  * Converts a string to a SR-IOV virtual function object.
  *
@@ -3210,17 +3212,17 @@ _nm_utils_check_module_file(const char               *name,
  * nm_utils_file_search_in_paths:
  * @progname: the helper program name, like "iptables"
  *   Must be a non-empty string, without path separator (/).
- * @try_first: (allow-none): a custom path to try first before searching.
+ * @try_first: (nullable): a custom path to try first before searching.
  *   It is silently ignored if it is empty or not an absolute path.
- * @paths: (allow-none): a %NULL terminated list of search paths.
+ * @paths: (nullable): a %NULL terminated list of search paths.
  *   Can be empty or %NULL, in which case only @try_first is checked.
  * @file_test_flags: the flags passed to g_file_test() when searching
  *   for @progname. Set it to 0 to skip the g_file_test().
  * @predicate: (scope call): if given, pass the file name to this function
  *   for additional checks. This check is performed after the check for
  *   @file_test_flags. You cannot omit both @file_test_flags and @predicate.
- * @user_data: (closure) (allow-none): user data for @predicate function.
- * @error: (allow-none): on failure, set a "not found" error %G_IO_ERROR %G_IO_ERROR_NOT_FOUND.
+ * @user_data: (closure) (nullable): user data for @predicate function.
+ * @error: on failure, set a "not found" error %G_IO_ERROR %G_IO_ERROR_NOT_FOUND.
  *
  * Searches for a @progname file in a list of search @paths.
  *
@@ -3595,7 +3597,7 @@ _nm_property_variant_to_gvalue(GVariant *src_value, GValue *dst_value)
  * Before 1.28, it was an error to call this function with any value other than
  * <literal>ARPHRD_ETHER</literal> or <literal>ARPHRD_INFINIBAND</literal>.
  *
- * Return value: the length or zero if the type is unrecognized.
+ * Returns: the length or zero if the type is unrecognized.
  */
 gsize
 nm_utils_hwaddr_len(int type)
@@ -3619,7 +3621,7 @@ nm_utils_hwaddr_len(int type)
  * eg "00:11" or "0:1".  Any "0x" at the beginning of @hex is ignored.  @hex
  * may not start or end with ':'.
  *
- * Return value: (transfer full): the converted bytes, or %NULL on error
+ * Returns: (transfer full): the converted bytes, or %NULL on error
  */
 GBytes *
 nm_utils_hexstr2bin(const char *hex)
@@ -3642,7 +3644,7 @@ nm_utils_hexstr2bin(const char *hex)
  * Parses @asc and converts it to binary form in a #GByteArray. See
  * nm_utils_hwaddr_aton() if you don't want a #GByteArray.
  *
- * Return value: (transfer full): a new #GByteArray, or %NULL if @asc couldn't
+ * Returns: (transfer full): a new #GByteArray, or %NULL if @asc couldn't
  * be parsed
  */
 GByteArray *
@@ -3674,7 +3676,7 @@ fail:
  * Parses @asc and converts it to binary form in @buffer.
  * Bytes in @asc can be separated by colons (:), or hyphens (-), but not mixed.
  *
- * Return value: @buffer, or %NULL if @asc couldn't be parsed
+ * Returns: @buffer, or %NULL if @asc couldn't be parsed
  *   or would be shorter or longer than @length.
  */
 guint8 *
@@ -3697,7 +3699,7 @@ nm_utils_hwaddr_aton(const char *asc, gpointer buffer, gsize length)
  * greater than -1, the returned string is terminated at that index
  * (returned_string[final_len] == '\0'),
  *
- * Return value: (transfer full): the textual form of @bytes
+ * Returns: (transfer full): the textual form of @bytes
  */
 char *
 nm_utils_bin2hexstr(gconstpointer src, gsize len, int final_len)
@@ -3718,7 +3720,7 @@ nm_utils_bin2hexstr(gconstpointer src, gsize len, int final_len)
  *
  * Converts @addr to textual form.
  *
- * Return value: (transfer full): the textual form of @addr
+ * Returns: (transfer full): the textual form of @addr
  */
 char *
 nm_utils_hwaddr_ntoa(gconstpointer addr, gsize length)
@@ -3738,7 +3740,7 @@ nm_utils_hwaddr_ntoa(gconstpointer addr, gsize length)
  * Parses @asc to see if it is a valid hardware address of the given
  * length.
  *
- * Return value: %TRUE if @asc appears to be a valid hardware address
+ * Returns: %TRUE if @asc appears to be a valid hardware address
  *   of the indicated length, %FALSE if not.
  */
 gboolean
@@ -3769,7 +3771,7 @@ nm_utils_hwaddr_valid(const char *asc, gssize length)
  * length, and if so, returns it in canonical form (uppercase, with
  * leading 0s as needed, and with colons rather than hyphens).
  *
- * Return value: (transfer full): the canonicalized address if @asc appears to
+ * Returns: (transfer full): the canonicalized address if @asc appears to
  *   be a valid hardware address of the indicated length, %NULL if not.
  */
 char *
@@ -3830,7 +3832,7 @@ _nm_utils_ipaddr_canonical_or_invalid(int addr_family, const char *ip, gboolean
 /*
  * Determine if given Ethernet address is link-local
  *
- * Return value: %TRUE if @mac is link local
+ * Returns: %TRUE if @mac is link local
  * reserved addr (01:80:c2:00:00:0X) per IEEE 802.1Q 8.6.3 Frame filtering, %FALSE if not.
  */
 gboolean
@@ -3887,7 +3889,7 @@ _nm_utils_hwaddr_link_local_valid(const char *mac)
  * sanity-checked before comparing them against known good addresses; they are
  * guaranteed to not match if they are invalid.)
  *
- * Return value: %TRUE if @hwaddr1 and @hwaddr2 are equivalent, %FALSE if they are
+ * Returns: %TRUE if @hwaddr1 and @hwaddr2 are equivalent, %FALSE if they are
  *   different (or either of them is invalid).
  */
 gboolean
@@ -4296,7 +4298,7 @@ nm_utils_is_valid_iface_name_utf8safe(const char *utf8safe_name)
 
 /**
  * nm_utils_is_valid_iface_name:
- * @name: (allow-none): Name of interface
+ * @name: (nullable): Name of interface
  * @error: location to store the error occurring, or %NULL to ignore
  *
  * Validate the network interface name.
@@ -4321,7 +4323,7 @@ nm_utils_is_valid_iface_name(const char *name, GError **error)
 
 /**
  * nm_utils_iface_valid_name:
- * @name: (allow-none): Name of interface
+ * @name: (nullable): Name of interface
  *
  * Validate the network interface name.
  *
@@ -4340,7 +4342,7 @@ nm_utils_iface_valid_name(const char *name)
 
 /**
  * nm_utils_is_uuid:
- * @str: (allow-none): a string that might be a UUID
+ * @str: (nullable): a string that might be a UUID
  *
  * Checks if @str is a UUID
  *
@@ -4429,7 +4431,7 @@ nm_utils_inet6_ntop(const struct in6_addr *in6addr, char *dst)
  *
  * Checks if @ip contains a valid IP address of the given family.
  *
- * Return value: %TRUE or %FALSE
+ * Returns: %TRUE or %FALSE
  */
 gboolean
 nm_utils_ipaddr_valid(int family, const char *ip)
@@ -4446,7 +4448,7 @@ nm_utils_ipaddr_valid(int family, const char *ip)
  * Checks if @duid string contains either a special duid value ("ll",
  * "llt", "lease" or the "stable" variants) or a valid hex DUID.
  *
- * Return value: %TRUE or %FALSE
+ * Returns: %TRUE or %FALSE
  */
 gboolean
 _nm_utils_dhcp_duid_valid(const char *duid, GBytes **out_duid_bin)
@@ -4711,10 +4713,10 @@ validate_dns_option(const char                 *name,
 /**
  * _nm_utils_dns_option_validate:
  * @option: option string
- * @out_name: (out) (allow-none): the option name
- * @out_value: (out) (allow-none): the option value
+ * @out_name: (out) (optional) (nullable): the option name
+ * @out_value: (out) (optional): the option value
  * @ipv6: whether the option refers to a IPv6 configuration
- * @option_descs: (allow-none): an array of NMUtilsDNSOptionDesc which describes the
+ * @option_descs: (nullable): an array of NMUtilsDNSOptionDesc which describes the
  * valid options
  *
  * Parses a DNS option in the form "name" or "name:number" and, if
@@ -4834,8 +4836,9 @@ nm_utils_enum_to_str(GType type, int value)
  * nm_utils_enum_from_str:
  * @type: the %GType of the enum
  * @str: the input string
- * @out_value: (out) (allow-none): the output value
- * @err_token: (out) (allow-none) (transfer full): location to store the first unrecognized token
+ * @out_value: (out) (optional): the output value
+ * @err_token: (out) (optional) (nullable) (transfer full): location to store
+ *   the first unrecognized token
  *
  * Converts a string to the matching enum value.
  *
@@ -5030,7 +5033,7 @@ _nm_variant_attribute_spec_find_binary_search(const NMVariantAttributeSpec *cons
  * @key_value_separator: character separating key and values
  * @ignore_unknown: whether unknown attributes should be ignored
  * @spec: the attribute format specifiers
- * @error: (out) (allow-none): location to store the error on failure
+ * @error: location to store the error on failure
  *
  * Parse attributes from a string.
  *
@@ -5330,7 +5333,7 @@ NM_UTILS_FLAGS2STR_DEFINE(nm_bluetooth_capability_to_string,
  * @base64_key: the (possibly invalid) base64 encode key.
  * @required_key_len: the expected (binary) length of the key after
  *   decoding. If the length does not match, the validation fails.
- * @out_key: (allow-none): (out): an optional output buffer for the binary
+ * @out_key: (out) (optional): an optional output buffer for the binary
  *   key. If given, it will be filled with exactly @required_key_len
  *   bytes.
  *
diff --git a/src/libnm-core-impl/nm-vpn-editor-plugin.c b/src/libnm-core-impl/nm-vpn-editor-plugin.c
index 3a6abbc2..6c9aff43 100644
--- a/src/libnm-core-impl/nm-vpn-editor-plugin.c
+++ b/src/libnm-core-impl/nm-vpn-editor-plugin.c
@@ -129,7 +129,7 @@ nm_vpn_editor_plugin_get_plugin_info(NMVpnEditorPlugin *plugin)
 /**
  * nm_vpn_editor_plugin_set_plugin_info:
  * @plugin: the #NMVpnEditorPlugin instance
- * @plugin_info: (allow-none): a #NMVpnPluginInfo instance or %NULL
+ * @plugin_info: (nullable): a #NMVpnPluginInfo instance or %NULL
  *
  * Set or clear the plugin-info instance.
  * This takes a weak reference on @plugin_info, to avoid circular
diff --git a/src/libnm-core-impl/nm-vpn-plugin-info.c b/src/libnm-core-impl/nm-vpn-plugin-info.c
index 61e9cde5..d2ce9ed8 100644
--- a/src/libnm-core-impl/nm-vpn-plugin-info.c
+++ b/src/libnm-core-impl/nm-vpn-plugin-info.c
@@ -143,7 +143,7 @@ nm_vpn_plugin_info_check_file_full(const char               *filename,
  *   other users.
  * @check_file: pass a callback to do your own validation.
  * @user_data: user data for @check_file.
- * @error: (allow-none) (out): the error reason if the check fails.
+ * @error: the error reason if the check fails.
  *
  * Check whether the file exists and is a valid name file (in keyfile format).
  * Additionally, also check for file permissions.
@@ -236,7 +236,7 @@ _nm_vpn_plugin_info_get_default_dir_user(void)
  * @check_owner: if set to a non-negative number, check that the file
  *   owner is either the same uid or 0. In that case, also check
  *   that the file is not writable by group or other.
- * @check_file: (allow-none): callback to check whether the file is valid.
+ * @check_file: (nullable): callback to check whether the file is valid.
  * @user_data: data for @check_file
  *
  * Iterate over the content of @dirname and load name files.
@@ -352,16 +352,16 @@ nm_vpn_plugin_info_list_load(void)
 
 /**
  * nm_vpn_plugin_info_new_search_file:
- * @name: (allow-none): the name to search for. Either @name or @service
+ * @name: (nullable): the name to search for. Either @name or @service
  *   must be present.
- * @service: (allow-none): the service to search for. Either @name  or
+ * @service: (nullable): the service to search for. Either @name  or
  *   @service must be present.
  *
  * This has the same effect as doing a full nm_vpn_plugin_info_list_load()
  * followed by a search for the first matching VPN plugin info that has the
  * given @name and/or @service.
  *
- * Returns: (transfer full): a newly created instance of plugin info
+ * Returns: (transfer full) (nullable): a newly created instance of plugin info
  *   or %NULL if no matching value was found.
  *
  * Since: 1.4
@@ -987,7 +987,7 @@ nm_vpn_plugin_info_get_editor_plugin(NMVpnPluginInfo *self)
 /**
  * nm_vpn_plugin_info_set_editor_plugin:
  * @self: plugin info instance
- * @plugin: (allow-none): plugin instance
+ * @plugin: (nullable): plugin instance
  *
  * Set the internal plugin instance. If %NULL, only clear the previous instance.
  *
diff --git a/src/libnm-core-impl/tests/test-general.c b/src/libnm-core-impl/tests/test-general.c
index 87f7b042..30b1ca5d 100644
--- a/src/libnm-core-impl/tests/test-general.c
+++ b/src/libnm-core-impl/tests/test-general.c
@@ -7,6 +7,7 @@
 
 #include "libnm-core-impl/nm-default-libnm-core.h"
 
+#include <ctype.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -87,21 +88,65 @@ G_STATIC_ASSERT(NM_UTILS_HWADDR_LEN_MAX == _NM_UTILS_HWADDR_LEN_MAX);
 static void
 test_nm_ascii_spaces(void)
 {
-    int               i;
-    const char *const S = NM_ASCII_SPACES;
+    int i;
+
+    {
+        const char *const S = NM_ASCII_SPACES;
 
-    for (i = 0; S[i]; i++)
-        g_assert(!strchr(&S[i + 1], S[i]));
+        for (i = 0; S[i]; i++)
+            g_assert(!strchr(&S[i + 1], S[i]));
 
-    for (i = 0; S[i] != '\0'; i++)
-        g_assert(g_ascii_isspace(S[i]));
+        for (i = 0; S[i] != '\0'; i++)
+            g_assert(g_ascii_isspace(S[i]));
 
-    g_assert(!g_ascii_isspace((char) 0));
-    for (i = 1; i < 0x100; i++) {
-        if (g_ascii_isspace((char) i))
-            g_assert(strchr(S, (char) i));
-        else
-            g_assert(!strchr(S, (char) i));
+        g_assert(!g_ascii_isspace((char) 0));
+        for (i = 1; i < 0x100; i++) {
+            g_assert((!!g_ascii_isspace((char) i)) == (!!strchr(S, (char) i)));
+        }
+    }
+
+    {
+        const char *const S = NM_ASCII_WHITESPACES;
+
+        for (i = 0; S[i]; i++)
+            g_assert(!strchr(&S[i + 1], S[i]));
+
+        for (i = 0; S[i] != '\0'; i++)
+            g_assert(nm_ascii_is_whitespace(S[i]));
+
+        g_assert(!nm_ascii_is_whitespace((char) 0));
+        for (i = 1; i < 0x100; i++) {
+            g_assert(nm_ascii_is_whitespace((char) i) == (!!strchr(S, (char) i)));
+        }
+    }
+
+    {
+        const char *const S = NM_ASCII_SPACES_CTYPE;
+
+        for (i = 0; S[i]; i++)
+            g_assert(!strchr(&S[i + 1], S[i]));
+
+        if (nm_streq0(g_getenv("LANG"), "C")) {
+            g_assert(!isspace((char) 0));
+            for (i = 1; i < 0x100; i++) {
+                g_assert((!!isspace((char) i)) == (!!strchr(S, (char) i)));
+            }
+        }
+    }
+
+    {
+        const char *const S = NM_ASCII_SPACES_KERNEL;
+
+        for (i = 0; S[i]; i++)
+            g_assert(!strchr(&S[i + 1], S[i]));
+
+        for (i = 0; S[i] != '\0'; i++)
+            g_assert(nm_ascii_is_space_kernel(S[i]));
+
+        g_assert(!nm_ascii_is_space_kernel((char) 0));
+        for (i = 1; i < 0x100; i++) {
+            g_assert(nm_ascii_is_space_kernel((char) i) == (!!strchr(S, (char) i)));
+        }
     }
 }
 
@@ -1417,6 +1462,7 @@ _do_test_c_list_sort(CListSort *elements, guint n_list, gboolean headless)
 
     g_assert(!c_list_is_empty(&head));
     g_assert(c_list_length(&head) == n_list);
+    g_assert(c_list_is_empty_or_single(&head) == (n_list <= 1));
 
     el_prev = NULL;
     c_list_for_each (iter, &head) {
@@ -1443,6 +1489,10 @@ test_c_list_sort(void)
     guint              n_list;
     guint              repeat;
 
+    g_assert(!c_list_is_linked(NULL));
+    g_assert(c_list_is_empty(NULL));
+    g_assert(c_list_is_empty_or_single(NULL));
+
     {
         CList head;
 
@@ -1450,6 +1500,7 @@ test_c_list_sort(void)
         c_list_sort(&head, _c_list_sort_cmp, NULL);
         g_assert(c_list_length(&head) == 0);
         g_assert(c_list_is_empty(&head));
+        g_assert(c_list_is_empty_or_single(&head));
     }
 
     elements = g_new0(CListSort, N_ELEMENTS);
@@ -1517,6 +1568,8 @@ _do_test_c_list_insert_sorted(CListSort *elements, guint n_list, bool append_equ
     g_assert(c_list_length_is(&head, n_list));
     g_assert(!c_list_length_is(&head, n_list + 1));
 
+    g_assert(c_list_is_empty_or_single(&head) == (n_list <= 1));
+
     el_prev = NULL;
     c_list_for_each_entry (el, &head, lst) {
         if (el_prev) {
@@ -3202,7 +3255,7 @@ test_setting_new_from_dbus_bad(void)
     nmtst_assert_success(conn, error);
     setting = nm_connection_get_setting(conn, NM_TYPE_SETTING_WIRELESS);
     g_assert(setting);
-    g_assert_cmpint(nm_setting_wireless_get_rate(NM_SETTING_WIRELESS(setting)), ==, 10);
+    g_assert_cmpint(nm_setting_wireless_get_rate(NM_SETTING_WIRELESS(setting)), ==, 0);
     g_object_unref(conn);
     g_variant_unref(dict);
 
@@ -6247,14 +6300,16 @@ test_connection_normalize_infiniband(void)
     nmtst_connection_normalize(con);
     g_assert_cmpstr(nm_connection_get_interface_name(con), ==, "x234567890123.0");
 
-#define iface_name(parent, p_key, expected)                                                        \
-    G_STMT_START                                                                                   \
-    {                                                                                              \
-        gs_free char *_s = nm_setting_infiniband_create_virtual_interface_name((parent), (p_key)); \
-                                                                                                   \
-        g_assert(nm_utils_ifname_valid_kernel(_s, NULL));                                          \
-        g_assert_cmpstr(_s, ==, (expected));                                                       \
-    }                                                                                              \
+#define iface_name(parent, p_key, expected)                  \
+    G_STMT_START                                             \
+    {                                                        \
+        char _name[NM_IFNAMSIZ];                             \
+                                                             \
+        nm_net_devname_infiniband(_name, (parent), (p_key)); \
+                                                             \
+        g_assert(nm_utils_ifname_valid_kernel(_name, NULL)); \
+        g_assert_cmpstr(_name, ==, (expected));              \
+    }                                                        \
     G_STMT_END
 
     iface_name("foo", 15, "foo.000f");
@@ -10515,7 +10570,7 @@ test_nm_ip_addr_zero(void)
     g_assert_cmpstr(nm_inet_ntop(AF_INET, &nm_ip_addr_zero, buf), ==, "0.0.0.0");
     g_assert_cmpstr(nm_inet_ntop(AF_INET6, &nm_ip_addr_zero, buf), ==, "::");
 
-    G_STATIC_ASSERT_EXPR(sizeof(a) == sizeof(a.array));
+    G_STATIC_ASSERT_EXPR(sizeof(a) == sizeof(a.addr_ptr));
 }
 
 static void
diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c
index 09e0fc70..b30758ff 100644
--- a/src/libnm-core-impl/tests/test-setting.c
+++ b/src/libnm-core-impl/tests/test-setting.c
@@ -121,8 +121,6 @@ test_nm_meta_setting_types_by_priority(void)
     G_STATIC_ASSERT_EXPR(_NM_META_SETTING_TYPE_NUM
                          == G_N_ELEMENTS(nm_meta_setting_types_by_priority));
 
-    G_STATIC_ASSERT_EXPR(_NM_META_SETTING_TYPE_NUM == 54);
-
     arr = g_ptr_array_new_with_free_func(g_object_unref);
 
     for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) {
@@ -5261,6 +5259,7 @@ test_bond_meta(void)
     _A(_nm_setting_bond_opt_value_as_u16, set, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO, 0, EINVAL);
     _A(_nm_setting_bond_opt_value_as_u16, set, NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY, 0, EINVAL);
     _A(_nm_setting_bond_opt_value_as_u8, set, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, 1, 0);
+    _A(_nm_setting_bond_opt_value_as_u8, set, NM_SETTING_BOND_OPTION_ARP_MISSED_MAX, 0, 0);
     _A(_nm_setting_bond_opt_value_as_u8, set, NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE, 0, 0);
     _A(_nm_setting_bond_opt_value_as_intbool, set, NM_SETTING_BOND_OPTION_USE_CARRIER, 1, 0);
     _A(_nm_setting_bond_opt_value_as_intbool,