summary refs log tree commit diff
path: root/src/libnm-core-impl
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-core-impl')
-rw-r--r--src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in34
-rw-r--r--src/libnm-core-impl/nm-connection.c4
-rw-r--r--src/libnm-core-impl/nm-setting-6lowpan.c2
-rw-r--r--src/libnm-core-impl/nm-setting-8021x.c117
-rw-r--r--src/libnm-core-impl/nm-setting-connection.c61
-rw-r--r--src/libnm-core-impl/nm-setting-ip-config.c45
-rw-r--r--src/libnm-core-impl/nm-setting-ip6-config.c100
-rw-r--r--src/libnm-core-impl/nm-setting-loopback.c2
-rw-r--r--src/libnm-core-impl/nm-setting-macsec.c2
-rw-r--r--src/libnm-core-impl/nm-setting-match.c4
-rw-r--r--src/libnm-core-impl/nm-setting-ovs-bridge.c2
-rw-r--r--src/libnm-core-impl/nm-setting-ovs-interface.c2
-rw-r--r--src/libnm-core-impl/nm-setting-ovs-port.c2
-rw-r--r--src/libnm-core-impl/nm-setting-private.h82
-rw-r--r--src/libnm-core-impl/nm-setting-team.c8
-rw-r--r--src/libnm-core-impl/nm-setting-vlan.c2
-rw-r--r--src/libnm-core-impl/nm-setting-wired.c461
-rw-r--r--src/libnm-core-impl/nm-setting-wireless.c471
-rw-r--r--src/libnm-core-impl/nm-setting.c31
-rw-r--r--src/libnm-core-impl/nm-team-utils.c58
-rw-r--r--src/libnm-core-impl/nm-utils.c3
-rw-r--r--src/libnm-core-impl/tests/test-general.c5
-rw-r--r--src/libnm-core-impl/tests/test-keyfile.c2
-rw-r--r--src/libnm-core-impl/tests/test-secrets.c2
-rw-r--r--src/libnm-core-impl/tests/test-setting.c6
25 files changed, 1148 insertions, 360 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 146f9282..2b231983 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
@@ -103,6 +103,11 @@
                   gprop-type="gchararray"
                   />
         <property name="mac-address-blacklist"
+                  is-deprecated="1"
+                  dbus-type="as"
+                  gprop-type="GStrv"
+                  />
+        <property name="mac-address-denylist"
                   dbus-type="as"
                   gprop-type="GStrv"
                   />
@@ -306,6 +311,10 @@
                   dbus-type="s"
                   gprop-type="gchararray"
                   />
+        <property name="openssl-ciphers"
+                  dbus-type="s"
+                  gprop-type="gchararray"
+                  />
         <property name="optional"
                   dbus-type="b"
                   gprop-type="gboolean"
@@ -487,6 +496,11 @@
                   gprop-type="gchararray"
                   />
         <property name="mac-address-blacklist"
+                  is-deprecated="1"
+                  dbus-type="as"
+                  gprop-type="GStrv"
+                  />
+        <property name="mac-address-denylist"
                   dbus-type="as"
                   gprop-type="GStrv"
                   />
@@ -792,6 +806,10 @@
                   dbus-type="i"
                   gprop-type="gint"
                   />
+        <property name="down-on-poweroff"
+                  dbus-type="i"
+                  gprop-type="gint"
+                  />
         <property name="gateway-ping-timeout"
                   dbus-type="u"
                   gprop-type="guint"
@@ -1596,6 +1614,10 @@
                   dbus-type="b"
                   gprop-type="gboolean"
                   />
+        <property name="dhcp-send-release"
+                  dbus-type="i"
+                  gprop-type="NMTernary"
+                  />
         <property name="dhcp-timeout"
                   dbus-type="i"
                   gprop-type="gint"
@@ -1735,6 +1757,10 @@
                   dbus-type="b"
                   gprop-type="gboolean"
                   />
+        <property name="dhcp-send-release"
+                  dbus-type="i"
+                  gprop-type="NMTernary"
+                  />
         <property name="dhcp-timeout"
                   dbus-type="i"
                   gprop-type="gint"
@@ -1822,6 +1848,14 @@
         <property name="routing-rules"
                   dbus-type="aa{sv}"
                   />
+        <property name="temp-preferred-lifetime"
+                  dbus-type="i"
+                  gprop-type="gint"
+                  />
+        <property name="temp-valid-lifetime"
+                  dbus-type="i"
+                  gprop-type="gint"
+                  />
         <property name="token"
                   dbus-type="s"
                   gprop-type="gchararray"
diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c
index 33360d04..15b489d6 100644
--- a/src/libnm-core-impl/nm-connection.c
+++ b/src/libnm-core-impl/nm-connection.c
@@ -1093,7 +1093,7 @@ _normalize_connection_slave_type(NMConnection *self)
 
     if (!s_con)
         return FALSE;
-    if (!nm_setting_connection_get_master(s_con))
+    if (!nm_setting_connection_get_controller(s_con))
         return FALSE;
 
     slave_type = nm_setting_connection_get_port_type(s_con);
@@ -1175,7 +1175,7 @@ _supports_addr_family(NMConnection *self, int family)
         && (nm_streq0(nm_setting_connection_get_port_type(s_con), NM_SETTING_VRF_SETTING_NAME)))
         return TRUE;
 
-    return !nm_setting_connection_get_master(nm_connection_get_setting_connection(self));
+    return !nm_setting_connection_get_controller(nm_connection_get_setting_connection(self));
 }
 
 static gboolean
diff --git a/src/libnm-core-impl/nm-setting-6lowpan.c b/src/libnm-core-impl/nm-setting-6lowpan.c
index 7066c3e6..d318ab00 100644
--- a/src/libnm-core-impl/nm-setting-6lowpan.c
+++ b/src/libnm-core-impl/nm-setting-6lowpan.c
@@ -95,7 +95,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
 
             slave_type = nm_setting_connection_get_port_type(s_con);
             if (!g_strcmp0(slave_type, NM_SETTING_6LOWPAN_SETTING_NAME))
-                master = nm_setting_connection_get_master(s_con);
+                master = nm_setting_connection_get_controller(s_con);
 
             if (master && g_strcmp0(priv->parent, master) != 0) {
                 g_set_error(error,
diff --git a/src/libnm-core-impl/nm-setting-8021x.c b/src/libnm-core-impl/nm-setting-8021x.c
index 945fd6d3..4ea60729 100644
--- a/src/libnm-core-impl/nm-setting-8021x.c
+++ b/src/libnm-core-impl/nm-setting-8021x.c
@@ -131,7 +131,8 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSetting8021x,
                              PROP_PIN_FLAGS,
                              PROP_SYSTEM_CA_CERTS,
                              PROP_OPTIONAL,
-                             PROP_AUTH_TIMEOUT, );
+                             PROP_AUTH_TIMEOUT,
+                             PROP_OPENSSL_CIPHERS, );
 
 typedef struct {
     GSList *eap; /* GSList of strings */
@@ -168,6 +169,7 @@ typedef struct {
     char   *private_key_password;
     GBytes *phase2_private_key;
     char   *phase2_private_key_password;
+    char   *openssl_ciphers;
     guint   ca_cert_password_flags;
     guint   client_cert_password_flags;
     guint   phase2_ca_cert_password_flags;
@@ -2498,6 +2500,24 @@ nm_setting_802_1x_get_optional(NMSetting8021x *setting)
     return NM_SETTING_802_1X_GET_PRIVATE(setting)->optional;
 }
 
+/**
+ * nm_setting_802_1x_get_openssl_ciphers:
+ * @setting: the #NMSetting8021x
+ *
+ * Returns the openssl_ciphers configuration for wpa_supplicant.
+ *
+ * Returns: cipher string for tls setup in wpa_supplicant.
+ *
+ * Since: 1.48
+ **/
+const char *
+nm_setting_802_1x_get_openssl_ciphers(NMSetting8021x *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_802_1X(setting), NULL);
+
+    return NM_SETTING_802_1X_GET_PRIVATE(setting)->openssl_ciphers;
+}
+
 /*****************************************************************************/
 
 static void
@@ -3315,6 +3335,19 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
      * Setting this property directly is discouraged; use the
      * nm_setting_802_1x_set_ca_cert() function instead.
      **/
+    /* ---nmcli---
+     * property: ca-cert
+     * description:
+     *   Contains the path to the CA certificate if used by the EAP method
+     *   specified in the 802-1x.eap property.
+     *
+     *   This property can be unset even if the EAP method supports CA certificates,
+     *   but this allows man-in-the-middle attacks and is NOT recommended.
+     *
+     *   Note that enabling 802-1x.system-ca-certs will override this
+     *   setting to use the built-in path, if the built-in path is not a directory.
+     * ---end---
+     */
     /* ---ifcfg-rh---
      * property: ca-cert
      * variable: IEEE_8021X_CA_CERT(+)
@@ -3505,6 +3538,13 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
      * Setting this property directly is discouraged; use the
      * nm_setting_802_1x_set_client_cert() function instead.
      **/
+    /* ---nmcli---
+     * property: client-cert
+     * description:
+     *   Contains the path to the client certificate if used by the EAP method
+     *   specified in the 802-1x.eap property.
+     * ---end---
+     */
     /* ---ifcfg-rh---
      * property: client-cert
      * variable: IEEE_8021X_CLIENT_CERT(+)
@@ -3745,6 +3785,20 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
      * Setting this property directly is discouraged; use the
      * nm_setting_802_1x_set_phase2_ca_cert() function instead.
      **/
+    /* ---nmcli---
+     * property: phase2-ca-cert
+     * description:
+     *   Contains the path to the "phase 2" CA certificate if used by the EAP
+     *   method specified in the 802-1x.phase2-auth or 802-1x.phase2-autheap
+     *   properties.
+     *
+     *   This property can be unset even if the EAP method supports CA certificates,
+     *   but this allows man-in-the-middle attacks and is NOT recommended.
+     *
+     *   Note that enabling 802-1x.system-ca-certs will override this
+     *   setting to use the built-in path, if the built-in path is not a directory.
+     * ---end---
+     */
     _nm_setting_property_define_direct_bytes(properties_override,
                                              obj_properties,
                                              NM_SETTING_802_1X_PHASE2_CA_CERT,
@@ -3933,6 +3987,14 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
      * Setting this property directly is discouraged; use the
      * nm_setting_802_1x_set_phase2_client_cert() function instead.
      **/
+    /* ---nmcli---
+     * property: phase2-client-cert
+     * description:
+     *   Contains the path to the "phase 2" client certificate if used by the EAP
+     *   method specified in the 802-1x.phase2-auth or 802-1x.phase2-autheap
+     *   properties.
+     * ---end---
+     */
     /* ---ifcfg-rh---
      * property: phase2-client-cert
      * variable: IEEE_8021X_INNER_CLIENT_CERT(+)
@@ -4096,6 +4158,12 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
      * private key password to prevent unauthorized access to unencrypted
      * private key data.
      **/
+    /* ---nmcli---
+     * property: private-key
+     * description:
+     *   The path to the private key when the 802-1.eap property is set to "tls".
+     * ---end---
+     */
     /* ---ifcfg-rh---
      * property: private-key
      * variable: IEEE_8021X_PRIVATE_KEY(+)
@@ -4121,6 +4189,14 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
      * secrets to NetworkManager; it is generally set automatically when setting
      * the private key by the nm_setting_802_1x_set_private_key() function.
      **/
+    /* ---nmcli---
+     * property: private-key-password
+     * description:
+     *   The password used to decrypt the private key specified in the
+     *   802-1x.private-key property. This is normally used by secret agents,
+     *   not directly by users.
+     * ---end---
+     */
     /* ---ifcfg-rh---
      * property: private-key-password
      * variable: IEEE_8021X_PRIVATE_KEY_PASSWORD(+)
@@ -4183,6 +4259,13 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
      * Setting this property directly is discouraged; use the
      * nm_setting_802_1x_set_phase2_private_key() function instead.
      **/
+    /* ---nmcli---
+     * property: phase2-private-key
+     * description:
+     *   The path to the "phase 2" inner private key when the 802-1x.phase2-auth
+     *   or 802-1x.phase2-autheap property is set to "tls".
+     * ---end---
+     */
     /* ---ifcfg-rh---
      * property: phase2-private-key
      * variable: IEEE_8021X_INNER_PRIVATE_KEY(+)
@@ -4208,6 +4291,14 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
      * the private key by the nm_setting_802_1x_set_phase2_private_key()
      * function.
      **/
+    /* ---nmcli---
+     * property: phase2-private-key-password
+     * description:
+     *   The password used to decrypt the "phase 2" private key specified in the
+     *   802-1x.phase2-private-key property. This is normally used by secret agents,
+     *   not directly by users.
+     * ---end---
+     */
     /* ---ifcfg-rh---
      * property: phase2-private-key-password
      * variable: IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD(+)
@@ -4364,6 +4455,30 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass)
                                                NMSetting8021xPrivate,
                                                optional);
 
+    /**
+     * NMSetting8021x:openssl-ciphers:
+     *
+     * Define openssl_ciphers for wpa_supplicant. Openssl sometimes moves ciphers
+     * among SECLEVELs, thus compiled-in default value in wpa_supplicant
+     * (as modified by some linux distributions) sometimes prevents
+     * to connect to old servers that do not support new protocols.
+     *
+     * Since: 1.48
+     **/
+    /* ---ifcfg-rh---
+     * property: openssl-ciphers
+     * variable: IEEE_8021X_OPENSSL_CIPHERS(+)
+     * description: Cipher string for tls setup of wpa_supplicant.
+     * ---end---
+     */
+    _nm_setting_property_define_direct_string(properties_override,
+                                              obj_properties,
+                                              NM_SETTING_802_1X_OPENSSL_CIPHERS,
+                                              PROP_OPENSSL_CIPHERS,
+                                              NM_SETTING_PARAM_NONE,
+                                              NMSetting8021xPrivate,
+                                              openssl_ciphers);
+
     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-connection.c b/src/libnm-core-impl/nm-setting-connection.c
index 7c58c84f..30a9509b 100644
--- a/src/libnm-core-impl/nm-setting-connection.c
+++ b/src/libnm-core-impl/nm-setting-connection.c
@@ -73,7 +73,8 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingConnection,
                              PROP_AUTH_RETRIES,
                              PROP_WAIT_DEVICE_TIMEOUT,
                              PROP_MUD_URL,
-                             PROP_WAIT_ACTIVATION_DELAY, );
+                             PROP_WAIT_ACTIVATION_DELAY,
+                             PROP_DOWN_ON_POWEROFF, );
 
 typedef struct {
     GArray     *permissions;
@@ -89,6 +90,7 @@ typedef struct {
     char       *mud_url;
     guint64     timestamp;
     int         autoconnect_ports;
+    int         down_on_poweroff;
     int         metered;
     gint32      autoconnect_priority;
     gint32      autoconnect_retries;
@@ -713,7 +715,7 @@ nm_setting_connection_get_zone(NMSettingConnection *setting)
  * Returns: interface name of the master device or UUID of the master
  * connection.
  *
- * Deprecated: 1.46. Use nm_setting_connection_get_controller() instead which
+ * Deprecated: 1.46. Use nm_setting_connection_get_master() instead which
  * is just an alias.
  */
 const char *
@@ -829,6 +831,26 @@ nm_setting_connection_get_wait_activation_delay(NMSettingConnection *setting)
 }
 
 /**
+ * nm_setting_connection_get_down_on_poweroff:
+ * @setting: the #NMSettingConnection
+ *
+ * Returns the %NM_SETTING_CONNECTION_DOWN_ON_POWEROFF property.
+ *
+ * Returns: whether the connection will be brought down before the system
+ * is powered off.
+ *
+ * Since: 1.48
+ */
+NMSettingConnectionDownOnPoweroff
+nm_setting_connection_get_down_on_poweroff(NMSettingConnection *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting),
+                         NM_SETTING_CONNECTION_DOWN_ON_POWEROFF_DEFAULT);
+
+    return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->down_on_poweroff;
+}
+
+/**
  * nm_setting_connection_get_autoconnect_ports:
  * @setting: the #NMSettingConnection
  *
@@ -2643,9 +2665,9 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
      * If -1 (default) is set, global connection.autoconnect-slaves is read to
      * determine the real value. If it is default as well, this fallbacks to 0.
      *
-     * Since: 1.2
-     *
      * Deprecated 1.46. Use #NMSettingConnection:autoconnect-ports instead, this is just an alias.
+     *
+     * Since: 1.2
      **/
     /* ---ifcfg-rh---
      * property: autoconnect-slaves
@@ -2729,6 +2751,7 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
                                             NM_SETTING_CONNECTION_SECONDARIES,
                                             PROP_SECONDARIES,
                                             NM_SETTING_PARAM_FUZZY_IGNORE,
+                                            NULL,
                                             NMSettingConnectionPrivate,
                                             secondaries);
 
@@ -2852,11 +2875,12 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
      * for the connection, "no" (0) disable mDNS for the interface, "resolve"
      * (1) do not register hostname but allow resolving of mDNS host names
      * and "default" (-1) to allow lookup of a global default in NetworkManager.conf.
-     * If unspecified, "default" ultimately depends on the DNS plugin (which
-     * for systemd-resolved currently means "no").
+     * If unspecified, "default" ultimately depends on the DNS plugin.
      *
      * This feature requires a plugin which supports mDNS. Otherwise, the
-     * setting has no effect. One such plugin is dns-systemd-resolved.
+     * setting has no effect. Currently the only supported DNS plugin is
+     * systemd-resolved. For systemd-resolved, the default is configurable via
+     * MulticastDNS= setting in resolved.conf.
      *
      * Since: 1.12
      **/
@@ -3157,6 +3181,29 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
                                              NMSettingConnectionPrivate,
                                              wait_activation_delay);
 
+    /**
+     * NMSettingConnection:down-on-poweroff:
+     *
+     *
+     * Whether the connection will be brought down before the system is powered
+     * off.  The default value is %NM_SETTING_CONNECTION_DOWN_ON_POWEROFF_DEFAULT. When
+     * the default value is specified, then the global value from
+     * NetworkManager configuration is looked up, if not set, it is considered
+     * as %NM_SETTING_CONNECTION_DOWN_ON_POWEROFF_NO.
+     *
+     * Since: 1.48
+     **/
+    _nm_setting_property_define_direct_enum(properties_override,
+                                            obj_properties,
+                                            NM_SETTING_CONNECTION_DOWN_ON_POWEROFF,
+                                            PROP_DOWN_ON_POWEROFF,
+                                            NM_TYPE_SETTING_CONNECTION_DOWN_ON_POWEROFF,
+                                            NM_SETTING_CONNECTION_DOWN_ON_POWEROFF_DEFAULT,
+                                            NM_SETTING_PARAM_NONE,
+                                            NULL,
+                                            NMSettingConnectionPrivate,
+                                            down_on_poweroff);
+
     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-ip-config.c b/src/libnm-core-impl/nm-setting-ip-config.c
index 02334b54..e79f25a8 100644
--- a/src/libnm-core-impl/nm-setting-ip-config.c
+++ b/src/libnm-core-impl/nm-setting-ip-config.c
@@ -4004,7 +4004,8 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingIPConfig,
                              PROP_DHCP_IAID,
                              PROP_DHCP_REJECT_SERVERS,
                              PROP_AUTO_ROUTE_EXT_GW,
-                             PROP_REPLACE_LOCAL_RULE, );
+                             PROP_REPLACE_LOCAL_RULE,
+                             PROP_DHCP_SEND_RELEASE, );
 
 G_DEFINE_ABSTRACT_TYPE(NMSettingIPConfig, nm_setting_ip_config, NM_TYPE_SETTING)
 
@@ -5463,6 +5464,22 @@ nm_setting_ip_config_get_replace_local_rule(NMSettingIPConfig *setting)
     return NM_SETTING_IP_CONFIG_GET_PRIVATE(setting)->replace_local_rule;
 }
 
+/**
+ * nm_setting_ip_config_get_dhcp_send_release:
+ * @setting: the #NMSettingIPConfig
+ *
+ * Returns: the #NMSettingIPConfig:dhcp-send-release property of the setting
+ *
+ * Since: 1.48
+ **/
+NMTernary
+nm_setting_ip_config_get_dhcp_send_release(NMSettingIPConfig *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_IP_CONFIG(setting), NM_TERNARY_DEFAULT);
+
+    return NM_SETTING_IP_CONFIG_GET_PRIVATE(setting)->dhcp_send_release;
+}
+
 static gboolean
 verify_label(const char *label)
 {
@@ -6152,6 +6169,14 @@ _nm_sett_info_property_override_create_array_ip_config(int addr_family)
 
     _nm_properties_override_gobj(
         properties_override,
+        obj_properties[PROP_DHCP_SEND_RELEASE],
+        &nm_sett_info_propert_type_direct_enum,
+        .direct_offset =
+            NM_STRUCT_OFFSET_ENSURE_TYPE(int, NMSettingIPConfigPrivate, dhcp_send_release),
+        .direct_data.enum_gtype = NM_TYPE_TERNARY);
+
+    _nm_properties_override_gobj(
+        properties_override,
         obj_properties[PROP_DNS_SEARCH],
         &nm_sett_info_propert_type_direct_strv,
         .direct_offset =
@@ -6903,5 +6928,23 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass)
                           NM_TERNARY_DEFAULT,
                           G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
+    /**
+     * NMSettingIPConfig:dhcp-send-release:
+     *
+     * Whether the DHCP client will send RELEASE message when
+     * bringing the connection down. The default value is %NM_TERNARY_DEFAULT.
+     * When the default value is specified, then the global value from NetworkManager
+     * configuration is looked up, if not set, it is considered as %FALSE.
+     *
+     * Since: 1.48
+     */
+    obj_properties[PROP_DHCP_SEND_RELEASE] =
+        g_param_spec_enum(NM_SETTING_IP_CONFIG_DHCP_SEND_RELEASE,
+                          "",
+                          "",
+                          NM_TYPE_TERNARY,
+                          NM_TERNARY_DEFAULT,
+                          G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
     g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
 }
diff --git a/src/libnm-core-impl/nm-setting-ip6-config.c b/src/libnm-core-impl/nm-setting-ip6-config.c
index 42bb2571..335700bf 100644
--- a/src/libnm-core-impl/nm-setting-ip6-config.c
+++ b/src/libnm-core-impl/nm-setting-ip6-config.c
@@ -40,6 +40,8 @@
 /*****************************************************************************/
 
 NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_IP6_PRIVACY,
+                                  PROP_TEMP_VALID_LIFETIME,
+                                  PROP_TEMP_PREFERRED_LIFETIME,
                                   PROP_ADDR_GEN_MODE,
                                   PROP_TOKEN,
                                   PROP_DHCP_DUID,
@@ -54,6 +56,8 @@ typedef struct {
     char   *dhcp_duid;
     char   *dhcp_pd_hint;
     int     ip6_privacy;
+    gint32  temp_valid_lifetime;
+    gint32  temp_preferred_lifetime;
     gint32  addr_gen_mode;
     gint32  ra_timeout;
     guint32 mtu;
@@ -98,6 +102,44 @@ nm_setting_ip6_config_get_ip6_privacy(NMSettingIP6Config *setting)
 }
 
 /**
+ * nm_setting_ip6_config_get_temp_valid_lifetime:
+ * @setting: the #NMSettingIP6Config
+ *
+ * Returns the value contained in the #NMSettingIP6Config:temp-valid-lifetime
+ * property.
+ *
+ * Returns: The valid lifetime of autogenerated temporary addresses.
+ *
+ * Since: 1.48
+ **/
+gint32
+nm_setting_ip6_config_get_temp_valid_lifetime(NMSettingIP6Config *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_IP6_CONFIG(setting), 0);
+
+    return NM_SETTING_IP6_CONFIG_GET_PRIVATE(setting)->temp_valid_lifetime;
+}
+
+/**
+ * nm_setting_ip6_config_get_temp_preferred_lifetime:
+ * @setting: the #NMSettingIP6Config
+ *
+ * Returns the value contained in the #NMSettingIP6Config:temp-preferred-lifetime
+ * property.
+ *
+ * Returns: The preferred lifetime of autogenerated temporary addresses.
+ *
+ * Since: 1.48
+ **/
+gint32
+nm_setting_ip6_config_get_temp_preferred_lifetime(NMSettingIP6Config *setting)
+{
+    g_return_val_if_fail(NM_IS_SETTING_IP6_CONFIG(setting), 0);
+
+    return NM_SETTING_IP6_CONFIG_GET_PRIVATE(setting)->temp_preferred_lifetime;
+}
+
+/**
  * nm_setting_ip6_config_get_dhcp_pd_hint:
  * @setting: the #NMSettingIP6Config
  *
@@ -921,11 +963,11 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
      * 0: disabled, 1: enabled (prefer public address), 2: enabled (prefer temporary
      * addresses).
      *
-     * Having a per-connection setting set to "-1" (unknown) means fallback to
-     * global configuration "ipv6.ip6-privacy".
-     *
-     * If also global configuration is unspecified or set to "-1", fallback to read
-     * "/proc/sys/net/ipv6/conf/default/use_tempaddr".
+     * If set to "-1" (unknown) for a connection, the value is taken from the
+     * global "ipv6.ip6-privacy" setting. If the global setting is unspecified
+     * or also set to "-1", the value is set from the original value of
+     * "/proc/sys/net/ipv6/conf/<iface>/use_tempaddr" from before NetworkManager
+     * started.
      *
      * Note that this setting is distinct from the Stable Privacy addresses
      * that can be enabled with the "addr-gen-mode" property's "stable-privacy"
@@ -953,6 +995,54 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass)
                                                  ip6_privacy);
 
     /**
+     * NMSettingIP6Config:temp-valid-lifetime:
+     *
+     * The valid lifetime of autogenerated temporary addresses, in seconds.
+     *
+     * If set to "0" (unknown) for a connection, the value is taken from the
+     * global "ipv6.temp-valid-lifetime" setting. If the global setting is
+     * unspecified or also set to "0", the value is set from the original value
+     * of "/proc/sys/net/ipv6/conf/<iface>/temp_valid_lft" from before
+     * NetworkManager started.
+     *
+     * Since: 1.48
+     **/
+    _nm_setting_property_define_direct_int32(properties_override,
+                                             obj_properties,
+                                             NM_SETTING_IP6_CONFIG_TEMP_VALID_LIFETIME,
+                                             PROP_TEMP_VALID_LIFETIME,
+                                             0,
+                                             G_MAXINT32,
+                                             0,
+                                             NM_SETTING_PARAM_FUZZY_IGNORE,
+                                             NMSettingIP6ConfigPrivate,
+                                             temp_valid_lifetime);
+
+    /**
+     * NMSettingIP6Config:temp-preferred-lifetime:
+     *
+     * The preferred lifetime of autogenerated temporary addresses, in seconds.
+     *
+     * If set to "0" (unknown) for a connection, the value is taken from the
+     * global "ipv6.temp-preferred-lifetime" setting. If the global setting is
+     * unspecified or also set to "0", the value is set from the original value
+     * of "/proc/sys/net/ipv6/conf/<iface>/temp_prefered_lft" from before
+     * NetworkManager started.
+     *
+     * Since: 1.48
+     **/
+    _nm_setting_property_define_direct_int32(properties_override,
+                                             obj_properties,
+                                             NM_SETTING_IP6_CONFIG_TEMP_PREFERRED_LIFETIME,
+                                             PROP_TEMP_PREFERRED_LIFETIME,
+                                             0,
+                                             G_MAXINT32,
+                                             0,
+                                             NM_SETTING_PARAM_FUZZY_IGNORE,
+                                             NMSettingIP6ConfigPrivate,
+                                             temp_preferred_lifetime);
+
+    /**
      * NMSettingIP6Config:addr-gen-mode:
      *
      * Configure the method for creating the IPv6 interface identifier of
diff --git a/src/libnm-core-impl/nm-setting-loopback.c b/src/libnm-core-impl/nm-setting-loopback.c
index b329c74a..2dc26ccc 100644
--- a/src/libnm-core-impl/nm-setting-loopback.c
+++ b/src/libnm-core-impl/nm-setting-loopback.c
@@ -126,7 +126,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
 
         if ((s_con = nm_connection_get_setting_connection(connection))) {
             if (nm_setting_connection_get_port_type(s_con)
-                || nm_setting_connection_get_master(s_con)) {
+                || nm_setting_connection_get_controller(s_con)) {
                 g_set_error(error,
                             NM_CONNECTION_ERROR,
                             NM_CONNECTION_ERROR_INVALID_PROPERTY,
diff --git a/src/libnm-core-impl/nm-setting-macsec.c b/src/libnm-core-impl/nm-setting-macsec.c
index 763d306b..5732fa07 100644
--- a/src/libnm-core-impl/nm-setting-macsec.c
+++ b/src/libnm-core-impl/nm-setting-macsec.c
@@ -324,7 +324,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
 
                 slave_type = nm_setting_connection_get_port_type(s_con);
                 if (!g_strcmp0(slave_type, NM_SETTING_MACSEC_SETTING_NAME))
-                    master = nm_setting_connection_get_master(s_con);
+                    master = nm_setting_connection_get_controller(s_con);
 
                 if (master && g_strcmp0(priv->parent, master) != 0) {
                     g_set_error(error,
diff --git a/src/libnm-core-impl/nm-setting-match.c b/src/libnm-core-impl/nm-setting-match.c
index 7736b7c0..255283fc 100644
--- a/src/libnm-core-impl/nm-setting-match.c
+++ b/src/libnm-core-impl/nm-setting-match.c
@@ -739,6 +739,7 @@ nm_setting_match_class_init(NMSettingMatchClass *klass)
                                             NM_SETTING_MATCH_INTERFACE_NAME,
                                             PROP_INTERFACE_NAME,
                                             NM_SETTING_PARAM_FUZZY_IGNORE,
+                                            NULL,
                                             NMSettingMatch,
                                             interface_name);
 
@@ -764,6 +765,7 @@ nm_setting_match_class_init(NMSettingMatchClass *klass)
                                             NM_SETTING_MATCH_KERNEL_COMMAND_LINE,
                                             PROP_KERNEL_COMMAND_LINE,
                                             NM_SETTING_PARAM_FUZZY_IGNORE,
+                                            NULL,
                                             NMSettingMatch,
                                             kernel_command_line);
 
@@ -783,6 +785,7 @@ nm_setting_match_class_init(NMSettingMatchClass *klass)
                                             NM_SETTING_MATCH_DRIVER,
                                             PROP_DRIVER,
                                             NM_SETTING_PARAM_FUZZY_IGNORE,
+                                            NULL,
                                             NMSettingMatch,
                                             driver);
 
@@ -824,6 +827,7 @@ nm_setting_match_class_init(NMSettingMatchClass *klass)
                                             NM_SETTING_MATCH_PATH,
                                             PROP_PATH,
                                             NM_SETTING_PARAM_FUZZY_IGNORE,
+                                            NULL,
                                             NMSettingMatch,
                                             path);
 
diff --git a/src/libnm-core-impl/nm-setting-ovs-bridge.c b/src/libnm-core-impl/nm-setting-ovs-bridge.c
index bc5dd04a..410d8771 100644
--- a/src/libnm-core-impl/nm-setting-ovs-bridge.c
+++ b/src/libnm-core-impl/nm-setting-ovs-bridge.c
@@ -153,7 +153,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
             return FALSE;
         }
 
-        if (nm_setting_connection_get_master(s_con)) {
+        if (nm_setting_connection_get_controller(s_con)) {
             g_set_error(error,
                         NM_CONNECTION_ERROR,
                         NM_CONNECTION_ERROR_INVALID_PROPERTY,
diff --git a/src/libnm-core-impl/nm-setting-ovs-interface.c b/src/libnm-core-impl/nm-setting-ovs-interface.c
index 88379087..47c73665 100644
--- a/src/libnm-core-impl/nm-setting-ovs-interface.c
+++ b/src/libnm-core-impl/nm-setting-ovs-interface.c
@@ -308,7 +308,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
             return FALSE;
         }
 
-        if (!nm_setting_connection_get_master(s_con)) {
+        if (!nm_setting_connection_get_controller(s_con)) {
             g_set_error(error,
                         NM_CONNECTION_ERROR,
                         NM_CONNECTION_ERROR_INVALID_PROPERTY,
diff --git a/src/libnm-core-impl/nm-setting-ovs-port.c b/src/libnm-core-impl/nm-setting-ovs-port.c
index f2071d43..107d76cd 100644
--- a/src/libnm-core-impl/nm-setting-ovs-port.c
+++ b/src/libnm-core-impl/nm-setting-ovs-port.c
@@ -413,7 +413,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
             return FALSE;
         }
 
-        if (!nm_setting_connection_get_master(s_con)) {
+        if (!nm_setting_connection_get_controller(s_con)) {
             g_set_error(error,
                         NM_CONNECTION_ERROR,
                         NM_CONNECTION_ERROR_INVALID_PROPERTY,
diff --git a/src/libnm-core-impl/nm-setting-private.h b/src/libnm-core-impl/nm-setting-private.h
index 1276c903..a1ae6825 100644
--- a/src/libnm-core-impl/nm-setting-private.h
+++ b/src/libnm-core-impl/nm-setting-private.h
@@ -189,6 +189,7 @@ typedef struct {
     gint64      route_metric;
     int         auto_route_ext_gw;
     int         replace_local_rule;
+    int         dhcp_send_release;
     gint32      required_timeout;
     gint32      dad_timeout;
     gint32      dhcp_timeout;
@@ -421,6 +422,19 @@ _nm_setting_connection_autoconnect_ports_to_dbus(_NM_SETT_INFO_PROP_TO_DBUS_FCN_
 gboolean
 _nm_setting_connection_autoconnect_slaves_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil);
 
+gboolean _nm_setting_wireless_mac_denylist_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil);
+
+GVariant *_nm_setting_wireless_mac_denylist_to_dbus(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil);
+
+gboolean
+_nm_setting_wireless_mac_blacklist_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil);
+
+gboolean _nm_setting_wired_mac_denylist_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil);
+
+GVariant *_nm_setting_wired_mac_denylist_to_dbus(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil);
+
+gboolean _nm_setting_wired_mac_blacklist_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil);
+
 GVariant *_nm_setting_to_dbus(NMSetting                              *setting,
                               NMConnection                           *connection,
                               NMConnectionSerializationFlags          flags,
@@ -741,7 +755,7 @@ _nm_properties_override(GArray *properties_override, const NMSettInfoProperty *p
             !NM_FLAGS_ANY((param_flags),                                                          \
                           ~(NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_INFERRABLE)));       \
         G_STATIC_ASSERT((min_value) <= (default_value));                                          \
-        G_STATIC_ASSERT((default_value) == 0 || (default_value) -1u < (max_value));               \
+        G_STATIC_ASSERT((default_value) == 0 || (default_value) - 1u < (max_value));              \
         G_STATIC_ASSERT((max_value) <= G_MAXUINT64);                                              \
                                                                                                   \
         _param_spec = g_param_spec_uint64("" prop_name "",                                        \
@@ -868,39 +882,39 @@ _nm_properties_override(GArray *properties_override, const NMSettInfoProperty *p
 
 /*****************************************************************************/
 
-#define _nm_setting_property_define_direct_strv(properties_override,                         \
-                                                obj_properties,                              \
-                                                prop_name,                                   \
-                                                prop_id,                                     \
-                                                param_flags,                                 \
-                                                private_struct_type,                         \
-                                                private_struct_field,                        \
-                                                ... /* extra NMSettInfoProperty fields */)   \
-    G_STMT_START                                                                             \
-    {                                                                                        \
-        GParamSpec *_param_spec;                                                             \
-                                                                                             \
-        G_STATIC_ASSERT(!NM_FLAGS_ANY((param_flags), ~(NM_SETTING_PARAM_FUZZY_IGNORE)));     \
-                                                                                             \
-        _param_spec = g_param_spec_boxed("" prop_name "",                                    \
-                                         "",                                                 \
-                                         "",                                                 \
-                                         G_TYPE_STRV,                                        \
-                                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY         \
-                                             | G_PARAM_STATIC_STRINGS | (param_flags));      \
-                                                                                             \
-        (obj_properties)[(prop_id)] = _param_spec;                                           \
-                                                                                             \
-        _nm_properties_override_gobj((properties_override),                                  \
-                                     _param_spec,                                            \
-                                     &nm_sett_info_propert_type_direct_strv,                 \
-                                     .direct_offset =                                        \
-                                         NM_STRUCT_OFFSET_ENSURE_TYPE(NMValueStrv,           \
-                                                                      private_struct_type,   \
-                                                                      private_struct_field), \
-                                     __VA_ARGS__);                                           \
-    }                                                                                        \
-    G_STMT_END
+#define _nm_setting_property_define_direct_strv(properties_override,                             \
+                                                obj_properties,                                  \
+                                                prop_name,                                       \
+                                                prop_id,                                         \
+                                                param_flags,                                     \
+                                                property_type,                                   \
+                                                private_struct_type,                             \
+                                                private_struct_field,                            \
+                                                ... /* extra NMSettInfoProperty fields */)       \
+    ({                                                                                           \
+        GParamSpec                  *_param_spec;                                                \
+        const NMSettInfoPropertType *_property_type;                                             \
+        G_STATIC_ASSERT(!NM_FLAGS_ANY((param_flags), ~(NM_SETTING_PARAM_FUZZY_IGNORE)));         \
+                                                                                                 \
+        _param_spec = g_param_spec_boxed("" prop_name "",                                        \
+                                         "",                                                     \
+                                         "",                                                     \
+                                         G_TYPE_STRV,                                            \
+                                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY             \
+                                             | G_PARAM_STATIC_STRINGS | (param_flags));          \
+                                                                                                 \
+        (obj_properties)[(prop_id)] = _param_spec;                                               \
+        _property_type              = (property_type) ?: &nm_sett_info_propert_type_direct_strv; \
+                                                                                                 \
+        _nm_properties_override_gobj((properties_override),                                      \
+                                     _param_spec,                                                \
+                                     _property_type,                                             \
+                                     .direct_offset =                                            \
+                                         NM_STRUCT_OFFSET_ENSURE_TYPE(NMValueStrv,               \
+                                                                      private_struct_type,       \
+                                                                      private_struct_field),     \
+                                     __VA_ARGS__);                                               \
+    })
 
 /*****************************************************************************/
 
diff --git a/src/libnm-core-impl/nm-setting-team.c b/src/libnm-core-impl/nm-setting-team.c
index 191ed9ae..08364af8 100644
--- a/src/libnm-core-impl/nm-setting-team.c
+++ b/src/libnm-core-impl/nm-setting-team.c
@@ -122,19 +122,13 @@ nm_team_link_watcher_new_ethtool(int delay_up, int delay_down, GError **error)
         return NULL;
     }
 
-    NM_PRAGMA_WARNING_DISABLE("-Warray-bounds")
-    NM_PRAGMA_WARNING_DISABLE("-Walloc-size")
-
-    watcher = g_malloc(nm_offsetofend(NMTeamLinkWatcher, ethtool));
+    watcher = g_malloc(sizeof(NMTeamLinkWatcher));
 
     watcher->ref_count          = 1;
     watcher->type               = LINK_WATCHER_ETHTOOL;
     watcher->ethtool.delay_up   = delay_up;
     watcher->ethtool.delay_down = delay_down;
 
-    NM_PRAGMA_WARNING_REENABLE
-    NM_PRAGMA_WARNING_REENABLE
-
     return watcher;
 }
 
diff --git a/src/libnm-core-impl/nm-setting-vlan.c b/src/libnm-core-impl/nm-setting-vlan.c
index 534ed713..16e3cf2a 100644
--- a/src/libnm-core-impl/nm-setting-vlan.c
+++ b/src/libnm-core-impl/nm-setting-vlan.c
@@ -616,7 +616,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
 
                 slave_type = nm_setting_connection_get_port_type(s_con);
                 if (!g_strcmp0(slave_type, NM_SETTING_VLAN_SETTING_NAME))
-                    master = nm_setting_connection_get_master(s_con);
+                    master = nm_setting_connection_get_controller(s_con);
 
                 if (master && g_strcmp0(priv->parent, master) != 0) {
                     g_set_error(error,
diff --git a/src/libnm-core-impl/nm-setting-wired.c b/src/libnm-core-impl/nm-setting-wired.c
index e09fd70d..2c8562d3 100644
--- a/src/libnm-core-impl/nm-setting-wired.c
+++ b/src/libnm-core-impl/nm-setting-wired.c
@@ -39,6 +39,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingWired,
                              PROP_CLONED_MAC_ADDRESS,
                              PROP_GENERATE_MAC_ADDRESS_MASK,
                              PROP_MAC_ADDRESS_BLACKLIST,
+                             PROP_MAC_ADDRESS_DENYLIST,
                              PROP_MTU,
                              PROP_S390_SUBCHANNELS,
                              PROP_S390_NETTYPE,
@@ -53,20 +54,20 @@ typedef struct {
         guint              len;
         guint              n_alloc;
     } s390_options;
-    GArray *mac_address_blacklist;
-    char  **s390_subchannels;
-    char   *port;
-    char   *duplex;
-    char   *device_mac_address;
-    char   *cloned_mac_address;
-    char   *generate_mac_address_mask;
-    char   *s390_nettype;
-    char   *wol_password;
-    int     accept_all_mac_addresses;
-    guint32 wake_on_lan;
-    guint32 speed;
-    guint32 mtu;
-    bool    auto_negotiate;
+    char      **s390_subchannels;
+    char       *port;
+    char       *duplex;
+    char       *device_mac_address;
+    char       *cloned_mac_address;
+    char       *generate_mac_address_mask;
+    char       *s390_nettype;
+    char       *wol_password;
+    NMValueStrv mac_address_denylist;
+    int         accept_all_mac_addresses;
+    guint32     wake_on_lan;
+    guint32     speed;
+    guint32     mtu;
+    bool        auto_negotiate;
 } NMSettingWiredPrivate;
 
 /**
@@ -277,166 +278,349 @@ nm_setting_wired_get_generate_mac_address_mask(NMSettingWired *setting)
 }
 
 /**
- * nm_setting_wired_get_mac_address_blacklist:
+ * nm_setting_wired_get_mac_address_denylist:
  * @setting: the #NMSettingWired
  *
- * Returns: the #NMSettingWired:mac-address-blacklist property of the setting
+ * Returns: the #NMSettingWired:mac-address-denylist property of the setting
+ * 
+ * Since: 1.48
  **/
 const char *const *
-nm_setting_wired_get_mac_address_blacklist(NMSettingWired *setting)
+nm_setting_wired_get_mac_address_denylist(NMSettingWired *setting)
 {
-    NMSettingWiredPrivate *priv;
-
     g_return_val_if_fail(NM_IS_SETTING_WIRED(setting), NULL);
 
-    priv = NM_SETTING_WIRED_GET_PRIVATE(setting);
-    return nm_g_array_data(priv->mac_address_blacklist);
+    return nm_strvarray_get_strv_notnull(
+        NM_SETTING_WIRED_GET_PRIVATE(setting)->mac_address_denylist.arr,
+        NULL);
 }
 
 /**
- * nm_setting_wired_get_num_mac_blacklist_items:
+ * nm_setting_wired_get_num_mac_denylist_items:
  * @setting: the #NMSettingWired
  *
- * Returns: the number of blacklisted MAC addresses
+ * Returns: the number of denylisted MAC addresses
+ * 
+ * Since: 1.48
  **/
-guint32
-nm_setting_wired_get_num_mac_blacklist_items(NMSettingWired *setting)
+guint
+nm_setting_wired_get_num_mac_denylist_items(NMSettingWired *setting)
 {
     g_return_val_if_fail(NM_IS_SETTING_WIRED(setting), 0);
 
-    return NM_SETTING_WIRED_GET_PRIVATE(setting)->mac_address_blacklist->len;
+    return nm_g_array_len(NM_SETTING_WIRED_GET_PRIVATE(setting)->mac_address_denylist.arr);
 }
 
 /**
- * nm_setting_wired_get_mac_blacklist_item:
+ * nm_setting_wired_get_mac_denylist_item:
  * @setting: the #NMSettingWired
  * @idx: the zero-based index of the MAC address entry
  *
- * Since 1.46, access at index "len" is allowed and returns NULL.
- *
- * Returns: the blacklisted MAC address string (hex-digits-and-colons notation)
+ * Returns: the denylisted MAC address string (hex-digits-and-colons notation)
  * at index @idx
+ * 
+ * Since: 1.48
  **/
 const char *
-nm_setting_wired_get_mac_blacklist_item(NMSettingWired *setting, guint32 idx)
+nm_setting_wired_get_mac_denylist_item(NMSettingWired *setting, guint idx)
 {
-    NMSettingWiredPrivate *priv;
-
     g_return_val_if_fail(NM_IS_SETTING_WIRED(setting), NULL);
 
-    priv = NM_SETTING_WIRED_GET_PRIVATE(setting);
-
-    if (idx == priv->mac_address_blacklist->len) {
-        return NULL;
-    }
-
-    g_return_val_if_fail(idx < priv->mac_address_blacklist->len, NULL);
-
-    return nm_g_array_index(priv->mac_address_blacklist, const char *, idx);
+    return nm_strvarray_get_idxnull_or_greturn(
+        NM_SETTING_WIRED_GET_PRIVATE(setting)->mac_address_denylist.arr,
+        idx);
 }
 
 /**
- * nm_setting_wired_add_mac_blacklist_item:
+ * nm_setting_wired_add_mac_denylist_item:
  * @setting: the #NMSettingWired
- * @mac: the MAC address string (hex-digits-and-colons notation) to blacklist
+ * @mac: the MAC address string (hex-digits-and-colons notation) to denylist
  *
- * Adds a new MAC address to the #NMSettingWired:mac-address-blacklist property.
+ * Adds a new MAC address to the #NMSettingWired:mac-address-denylist property.
  *
  * Returns: %TRUE if the MAC address was added; %FALSE if the MAC address
  * is invalid or was already present
+ * 
+ * Since: 1.48
  **/
 gboolean
-nm_setting_wired_add_mac_blacklist_item(NMSettingWired *setting, const char *mac)
+nm_setting_wired_add_mac_denylist_item(NMSettingWired *setting, const char *mac)
 {
     NMSettingWiredPrivate *priv;
+    guint8                 mac_bin[ETH_ALEN];
     const char            *candidate;
-    int                    i;
+    guint                  i;
+    guint                  len;
 
     g_return_val_if_fail(NM_IS_SETTING_WIRED(setting), FALSE);
     g_return_val_if_fail(mac != NULL, FALSE);
 
-    if (!nm_utils_hwaddr_valid(mac, ETH_ALEN))
+    if (!_nm_utils_hwaddr_aton_exact(mac, mac_bin, ETH_ALEN))
         return FALSE;
 
     priv = NM_SETTING_WIRED_GET_PRIVATE(setting);
-    for (i = 0; i < priv->mac_address_blacklist->len; i++) {
-        candidate = nm_g_array_index(priv->mac_address_blacklist, char *, i);
-        if (nm_utils_hwaddr_matches(mac, -1, candidate, -1))
+    len  = nm_g_array_len(priv->mac_address_denylist.arr);
+    for (i = 0; i < len; i++) {
+        candidate = nm_g_array_index(priv->mac_address_denylist.arr, char *, i);
+        if (nm_utils_hwaddr_matches(mac_bin, ETH_ALEN, candidate, -1))
             return FALSE;
     }
 
-    mac = nm_utils_hwaddr_canonical(mac, ETH_ALEN);
-    g_array_append_val(priv->mac_address_blacklist, mac);
-    _notify(setting, PROP_MAC_ADDRESS_BLACKLIST);
+    nm_g_array_append_simple(nm_strvarray_ensure(&priv->mac_address_denylist.arr),
+                             nm_utils_hwaddr_ntoa(mac_bin, ETH_ALEN));
+    _notify(setting, PROP_MAC_ADDRESS_DENYLIST);
     return TRUE;
 }
 
 /**
- * nm_setting_wired_remove_mac_blacklist_item:
+ * nm_setting_wired_remove_mac_denylist_item:
  * @setting: the #NMSettingWired
  * @idx: index number of the MAC address
  *
- * Removes the MAC address at index @idx from the blacklist.
+ * Removes the MAC address at index @idx from the denylist.
+ * 
+ * Since: 1.48
  **/
 void
-nm_setting_wired_remove_mac_blacklist_item(NMSettingWired *setting, guint32 idx)
+nm_setting_wired_remove_mac_denylist_item(NMSettingWired *setting, guint idx)
 {
     NMSettingWiredPrivate *priv;
 
     g_return_if_fail(NM_IS_SETTING_WIRED(setting));
 
     priv = NM_SETTING_WIRED_GET_PRIVATE(setting);
-    g_return_if_fail(idx < priv->mac_address_blacklist->len);
+    if (!priv->mac_address_denylist.arr) {
+        return;
+    }
+
+    g_return_if_fail(idx < priv->mac_address_denylist.arr->len);
 
-    g_array_remove_index(priv->mac_address_blacklist, idx);
-    _notify(setting, PROP_MAC_ADDRESS_BLACKLIST);
+    g_array_remove_index(priv->mac_address_denylist.arr, idx);
+    _notify(setting, PROP_MAC_ADDRESS_DENYLIST);
 }
 
 /**
- * nm_setting_wired_remove_mac_blacklist_item_by_value:
+ * nm_setting_wired_remove_mac_denylist_item_by_value:
  * @setting: the #NMSettingWired
  * @mac: the MAC address string (hex-digits-and-colons notation) to remove from
- * the blacklist
+ * the denylist
  *
- * Removes the MAC address @mac from the blacklist.
+ * Removes the MAC address @mac from the denylist.
  *
  * Returns: %TRUE if the MAC address was found and removed; %FALSE if it was not.
+ * 
+ * Since: 1.48
  **/
 gboolean
-nm_setting_wired_remove_mac_blacklist_item_by_value(NMSettingWired *setting, const char *mac)
+nm_setting_wired_remove_mac_denylist_item_by_value(NMSettingWired *setting, const char *mac)
 {
     NMSettingWiredPrivate *priv;
+    guint8                 mac_bin[ETH_ALEN];
     const char            *candidate;
-    int                    i;
+    guint                  i;
 
     g_return_val_if_fail(NM_IS_SETTING_WIRED(setting), FALSE);
     g_return_val_if_fail(mac != NULL, FALSE);
 
+    if (!_nm_utils_hwaddr_aton_exact(mac, mac_bin, ETH_ALEN))
+        return FALSE;
+
     priv = NM_SETTING_WIRED_GET_PRIVATE(setting);
-    for (i = 0; i < priv->mac_address_blacklist->len; i++) {
-        candidate = nm_g_array_index(priv->mac_address_blacklist, char *, i);
-        if (!nm_utils_hwaddr_matches(mac, -1, candidate, -1)) {
-            g_array_remove_index(priv->mac_address_blacklist, i);
-            _notify(setting, PROP_MAC_ADDRESS_BLACKLIST);
-            return TRUE;
+    if (priv->mac_address_denylist.arr) {
+        for (i = 0; i < priv->mac_address_denylist.arr->len; i++) {
+            candidate = nm_g_array_index(priv->mac_address_denylist.arr, char *, i);
+            if (nm_utils_hwaddr_matches(mac_bin, ETH_ALEN, candidate, -1)) {
+                g_array_remove_index(priv->mac_address_denylist.arr, i);
+                _notify(setting, PROP_MAC_ADDRESS_DENYLIST);
+                return TRUE;
+            }
         }
     }
+
     return FALSE;
 }
 
 /**
+ * nm_setting_wired_clear_mac_denylist_items:
+ * @setting: the #NMSettingWired
+ *
+ * Removes all denylisted MAC addresses.
+ * 
+ * Since: 1.48
+ **/
+void
+nm_setting_wired_clear_mac_denylist_items(NMSettingWired *setting)
+{
+    g_return_if_fail(NM_IS_SETTING_WIRED(setting));
+
+    if (nm_strvarray_clear(&NM_SETTING_WIRED_GET_PRIVATE(setting)->mac_address_denylist.arr))
+        _notify(setting, PROP_MAC_ADDRESS_DENYLIST);
+}
+
+/**
+ * nm_setting_wired_get_mac_address_blacklist:
+ * @setting: the #NMSettingWired
+ *
+ * Returns: the #NMSettingWired:mac-address-blacklist property of the setting
+ *
+ * Deprecated: 1.48. Use nm_setting_wired_get_mac_address_denylist() instead.
+ **/
+const char *const *
+nm_setting_wired_get_mac_address_blacklist(NMSettingWired *setting)
+{
+    return nm_setting_wired_get_mac_address_denylist(setting);
+}
+
+/**
+ * nm_setting_wired_get_num_mac_blacklist_items:
+ * @setting: the #NMSettingWired
+ *
+ * Returns: the number of blacklisted MAC addresses
+ *
+ * Deprecated: 1.48. Use nm_setting_wired_get_num_mac_denylist_items() instead.
+ **/
+guint32
+nm_setting_wired_get_num_mac_blacklist_items(NMSettingWired *setting)
+{
+    return nm_setting_wired_get_num_mac_denylist_items(setting);
+}
+
+/**
+ * nm_setting_wired_get_mac_blacklist_item:
+ * @setting: the #NMSettingWired
+ * @idx: the zero-based index of the MAC address entry
+ *
+ * Since 1.48, access at index "len" is allowed and returns NULL.
+ *
+ * Returns: the blacklisted MAC address string (hex-digits-and-colons notation)
+ * at index @idx
+ *
+ * Deprecated: 1.48. Use nm_setting_wired_get_mac_denylist_item() instead.
+ **/
+const char *
+nm_setting_wired_get_mac_blacklist_item(NMSettingWired *setting, guint32 idx)
+{
+    return nm_setting_wired_get_mac_denylist_item(setting, idx);
+}
+
+/**
+ * nm_setting_wired_add_mac_blacklist_item:
+ * @setting: the #NMSettingWired
+ * @mac: the MAC address string (hex-digits-and-colons notation) to blacklist
+ *
+ * Adds a new MAC address to the #NMSettingWired:mac-address-blacklist property.
+ *
+ * Returns: %TRUE if the MAC address was added; %FALSE if the MAC address
+ * is invalid or was already present
+ *
+ * Deprecated: 1.48. Use nm_setting_wired_add_mac_denylist_item() instead.
+ **/
+gboolean
+nm_setting_wired_add_mac_blacklist_item(NMSettingWired *setting, const char *mac)
+{
+    return nm_setting_wired_add_mac_denylist_item(setting, mac);
+}
+
+/**
+ * nm_setting_wired_remove_mac_blacklist_item:
+ * @setting: the #NMSettingWired
+ * @idx: index number of the MAC address
+ *
+ * Removes the MAC address at index @idx from the blacklist.
+ *
+ * Deprecated: 1.48. Use nm_setting_wired_remove_mac_denylist_item() instead.
+ **/
+void
+nm_setting_wired_remove_mac_blacklist_item(NMSettingWired *setting, guint32 idx)
+{
+    return nm_setting_wired_remove_mac_denylist_item(setting, idx);
+}
+
+/**
+ * nm_setting_wired_remove_mac_blacklist_item_by_value:
+ * @setting: the #NMSettingWired
+ * @mac: the MAC address string (hex-digits-and-colons notation) to remove from
+ * the blacklist
+ *
+ * Removes the MAC address @mac from the blacklist.
+ *
+ * Returns: %TRUE if the MAC address was found and removed; %FALSE if it was not.
+ *
+ * Deprecated: 1.48. Use nm_setting_wired_remove_mac_denylist_item_by_value() instead.
+ **/
+gboolean
+nm_setting_wired_remove_mac_blacklist_item_by_value(NMSettingWired *setting, const char *mac)
+{
+    return nm_setting_wired_remove_mac_denylist_item_by_value(setting, mac);
+}
+
+/**
  * nm_setting_wired_clear_mac_blacklist_items:
  * @setting: the #NMSettingWired
  *
  * Removes all blacklisted MAC addresses.
+ *
+ * Deprecated: 1.48. Use nm_setting_wired_clear_mac_denylist_items() instead.
  **/
 void
 nm_setting_wired_clear_mac_blacklist_items(NMSettingWired *setting)
 {
-    g_return_if_fail(NM_IS_SETTING_WIRED(setting));
+    return nm_setting_wired_clear_mac_denylist_items(setting);
+}
+
+gboolean
+_nm_setting_wired_mac_blacklist_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
+{
+    const gchar **mac_blacklist;
+
+    if (!_nm_setting_use_legacy_property(setting,
+                                         connection_dict,
+                                         NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST,
+                                         NM_SETTING_WIRED_MAC_ADDRESS_DENYLIST)) {
+        *out_is_modified = FALSE;
+        return TRUE;
+    }
+    mac_blacklist = g_variant_get_strv(value, NULL);
+
+    g_object_set(setting, NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST, mac_blacklist, NULL);
+    return TRUE;
+}
+
+gboolean
+_nm_setting_wired_mac_denylist_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
+{
+    const gchar **mac_denylist;
+
+    if (!_nm_setting_use_legacy_property(setting,
+                                         connection_dict,
+                                         NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST,
+                                         NM_SETTING_WIRED_MAC_ADDRESS_DENYLIST)) {
+        *out_is_modified = FALSE;
+        return TRUE;
+    }
+    mac_denylist = g_variant_get_strv(value, NULL);
+
+    g_object_set(setting, NM_SETTING_WIRED_MAC_ADDRESS_DENYLIST, mac_denylist, NULL);
+    return TRUE;
+}
+
+GVariant *
+_nm_setting_wired_mac_denylist_to_dbus(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil)
+{
+    const char *const *mac_denylist;
+    /* FIXME: `mac-address-denylist` is an alias of `mac-address-blacklist` property.
+     * Serializing the property to the clients would break them as they won't
+     * be able to drop it if they are not aware of the existance of
+     * `mac-address-denylist`. In order to give them time to adapt their code,
+     * NetworkManager is not serializing `mac-address-denylist` on DBus.
+     */
+    if (_nm_utils_is_manager_process) {
+        return NULL;
+    }
 
-    g_array_set_size(NM_SETTING_WIRED_GET_PRIVATE(setting)->mac_address_blacklist, 0);
-    _notify(setting, PROP_MAC_ADDRESS_BLACKLIST);
+    mac_denylist = nm_setting_wired_get_mac_address_denylist(NM_SETTING_WIRED(setting));
+
+    return g_variant_new_strv(mac_denylist, -1);
 }
 
 /**
@@ -815,20 +999,22 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
         return FALSE;
     }
 
-    for (i = 0; i < priv->mac_address_blacklist->len; i++) {
-        const char *mac = nm_g_array_index(priv->mac_address_blacklist, const char *, i);
+    if (priv->mac_address_denylist.arr) {
+        for (i = 0; i < priv->mac_address_denylist.arr->len; i++) {
+            const char *mac = nm_g_array_index(priv->mac_address_denylist.arr, const char *, i);
 
-        if (!nm_utils_hwaddr_valid(mac, ETH_ALEN)) {
-            g_set_error(error,
-                        NM_CONNECTION_ERROR,
-                        NM_CONNECTION_ERROR_INVALID_PROPERTY,
-                        _("'%s' is not a valid MAC address"),
-                        mac);
-            g_prefix_error(error,
-                           "%s.%s: ",
-                           NM_SETTING_WIRED_SETTING_NAME,
-                           NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST);
-            return FALSE;
+            if (!nm_utils_hwaddr_valid(mac, ETH_ALEN)) {
+                g_set_error(error,
+                            NM_CONNECTION_ERROR,
+                            NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                            _("'%s' is not a valid MAC address"),
+                            mac);
+                g_prefix_error(error,
+                               "%s.%s: ",
+                               NM_SETTING_WIRED_SETTING_NAME,
+                               NM_SETTING_WIRED_MAC_ADDRESS_DENYLIST);
+                return FALSE;
+            }
         }
     }
 
@@ -993,14 +1179,6 @@ compare_fcn_cloned_mac_address(_NM_SETT_INFO_PROP_COMPARE_FCN_ARGS _nm_nil)
 /*****************************************************************************/
 
 static void
-clear_blacklist_item(char **item_p)
-{
-    g_free(*item_p);
-}
-
-/*****************************************************************************/
-
-static void
 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 {
     NMSettingWired        *setting = NM_SETTING_WIRED(object);
@@ -1012,9 +1190,6 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
     case PROP_CLONED_MAC_ADDRESS:
         g_value_set_string(value, nm_setting_wired_get_cloned_mac_address(setting));
         break;
-    case PROP_MAC_ADDRESS_BLACKLIST:
-        g_value_set_boxed(value, nm_g_array_data(priv->mac_address_blacklist));
-        break;
     case PROP_S390_SUBCHANNELS:
         g_value_set_boxed(value, priv->s390_subchannels);
         break;
@@ -1037,8 +1212,6 @@ static void
 set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
 {
     NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE(object);
-    const char *const     *blacklist;
-    const char            *mac;
 
     switch (prop_id) {
     case PROP_CLONED_MAC_ADDRESS:
@@ -1046,18 +1219,6 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps
         priv->cloned_mac_address =
             _nm_utils_hwaddr_canonical_or_invalid(g_value_get_string(value), ETH_ALEN);
         break;
-    case PROP_MAC_ADDRESS_BLACKLIST:
-        blacklist = g_value_get_boxed(value);
-        g_array_set_size(priv->mac_address_blacklist, 0);
-        if (blacklist && *blacklist) {
-            guint i;
-
-            for (i = 0; blacklist[i]; i++) {
-                mac = _nm_utils_hwaddr_canonical_or_invalid(blacklist[i], ETH_ALEN);
-                g_array_append_val(priv->mac_address_blacklist, mac);
-            }
-        }
-        break;
     case PROP_S390_SUBCHANNELS:
         if (priv->s390_subchannels)
             g_strfreev(priv->s390_subchannels);
@@ -1135,13 +1296,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps
 
 static void
 nm_setting_wired_init(NMSettingWired *setting)
-{
-    NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE(setting);
-
-    /* We use GArray rather than GPtrArray so it will automatically be NULL-terminated */
-    priv->mac_address_blacklist = g_array_new(TRUE, FALSE, sizeof(char *));
-    g_array_set_clear_func(priv->mac_address_blacklist, (GDestroyNotify) clear_blacklist_item);
-}
+{}
 
 /**
  * nm_setting_wired_new:
@@ -1164,7 +1319,6 @@ finalize(GObject *object)
     _s390_options_clear(priv);
 
     g_free(priv->cloned_mac_address);
-    g_array_unref(priv->mac_address_blacklist);
     g_strfreev(priv->s390_subchannels);
 
     G_OBJECT_CLASS(nm_setting_wired_parent_class)->finalize(object);
@@ -1176,6 +1330,7 @@ nm_setting_wired_class_init(NMSettingWiredClass *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();
+    guint           prop_idx;
 
     object_class->get_property = get_property;
     object_class->set_property = set_property;
@@ -1486,11 +1641,67 @@ nm_setting_wired_class_init(NMSettingWiredClass *klass)
      * example: HWADDR_BLACKLIST="00:22:68:11:69:08 00:11:22:11:44:55"
      * ---end---
      */
-    _nm_setting_property_define_gprop_strv_oldstyle(properties_override,
-                                                    obj_properties,
-                                                    NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST,
-                                                    PROP_MAC_ADDRESS_BLACKLIST,
-                                                    NM_SETTING_PARAM_FUZZY_IGNORE);
+    prop_idx = _nm_setting_property_define_direct_strv(
+        properties_override,
+        obj_properties,
+        NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST,
+        PROP_MAC_ADDRESS_BLACKLIST,
+        NM_SETTING_PARAM_FUZZY_IGNORE,
+        NM_SETT_INFO_PROPERT_TYPE_DBUS(G_VARIANT_TYPE_STRING_ARRAY,
+                                       .direct_type = NM_VALUE_TYPE_STRV,
+                                       .compare_fcn = _nm_setting_property_compare_fcn_direct,
+                                       .to_dbus_fcn = _nm_setting_property_to_dbus_fcn_direct,
+                                       .from_dbus_fcn =
+                                           _nm_setting_wired_mac_blacklist_from_dbus, ),
+        NMSettingWiredPrivate,
+        mac_address_denylist,
+        .direct_set_strv_normalize_hwaddr = TRUE,
+        .direct_strv_not_null             = TRUE,
+        .direct_is_aliased_field          = TRUE,
+        .is_deprecated                    = TRUE);
+
+    /**
+     * NMSettingWired:mac-address-denylist:
+     *
+     * If specified, this connection will never apply to the Ethernet device
+     * whose permanent MAC address matches an address in the list.  Each MAC
+     * address is in the standard hex-digits-and-colons notation
+     * (00:11:22:33:44:55).
+     **/
+    /* ---keyfile---
+     * property: mac-address-denylist
+     * format: list of MACs (separated with semicolons)
+     * description: MAC address denylist.
+     * example: mac-address-denylist= 00:22:68:12:79:A6;00:22:68:12:79:78
+     * ---end---
+     */
+    /* ---ifcfg-rh---
+     * property: mac-address-denylist
+     * variable: HWADDR_BLACKLIST(+)
+     * description: It denies usage of the connection for any device whose address
+     *   is listed.
+     * example: HWADDR_BLACKLIST="00:22:68:11:69:08 00:11:22:11:44:55"
+     * ---end---
+     */
+    _nm_setting_property_define_direct_strv(
+        properties_override,
+        obj_properties,
+        NM_SETTING_WIRED_MAC_ADDRESS_DENYLIST,
+        PROP_MAC_ADDRESS_DENYLIST,
+        NM_SETTING_PARAM_FUZZY_IGNORE,
+        NM_SETT_INFO_PROPERT_TYPE_DBUS(G_VARIANT_TYPE_STRING_ARRAY,
+                                       .direct_type   = NM_VALUE_TYPE_STRV,
+                                       .compare_fcn   = _nm_setting_property_compare_fcn_direct,
+                                       .to_dbus_fcn   = _nm_setting_wired_mac_denylist_to_dbus,
+                                       .from_dbus_fcn = _nm_setting_wired_mac_denylist_from_dbus, ),
+        NMSettingWiredPrivate,
+        mac_address_denylist,
+        .direct_set_strv_normalize_hwaddr = TRUE,
+        .direct_strv_not_null             = TRUE,
+        .direct_also_notify               = obj_properties[PROP_MAC_ADDRESS_BLACKLIST], );
+
+    nm_g_array_index(properties_override, NMSettInfoProperty, prop_idx).direct_also_notify =
+        obj_properties[PROP_MAC_ADDRESS_DENYLIST];
 
     /**
      * NMSettingWired:mtu:
diff --git a/src/libnm-core-impl/nm-setting-wireless.c b/src/libnm-core-impl/nm-setting-wireless.c
index 244dcdcc..207b47d8 100644
--- a/src/libnm-core-impl/nm-setting-wireless.c
+++ b/src/libnm-core-impl/nm-setting-wireless.c
@@ -37,6 +37,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingWireless,
                              PROP_CLONED_MAC_ADDRESS,
                              PROP_GENERATE_MAC_ADDRESS_MASK,
                              PROP_MAC_ADDRESS_BLACKLIST,
+                             PROP_MAC_ADDRESS_DENYLIST,
                              PROP_MTU,
                              PROP_SEEN_BSSIDS,
                              PROP_HIDDEN,
@@ -46,24 +47,24 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingWireless,
                              PROP_AP_ISOLATION, );
 
 typedef struct {
-    GBytes    *ssid;
-    GArray    *mac_address_blacklist;
-    GPtrArray *seen_bssids;
-    char      *mode;
-    char      *band;
-    char      *bssid;
-    char      *device_mac_address;
-    char      *cloned_mac_address;
-    char      *generate_mac_address_mask;
-    int        ap_isolation;
-    guint32    mac_address_randomization;
-    guint32    channel;
-    guint32    rate;
-    guint32    tx_power;
-    guint32    mtu;
-    guint32    powersave;
-    guint32    wake_on_wlan;
-    bool       hidden;
+    GBytes     *ssid;
+    GPtrArray  *seen_bssids;
+    char       *mode;
+    char       *band;
+    char       *bssid;
+    char       *device_mac_address;
+    char       *cloned_mac_address;
+    char       *generate_mac_address_mask;
+    NMValueStrv mac_address_denylist;
+    int         ap_isolation;
+    guint32     mac_address_randomization;
+    guint32     channel;
+    guint32     rate;
+    guint32     tx_power;
+    guint32     mtu;
+    guint32     powersave;
+    guint32     wake_on_wlan;
+    bool        hidden;
 } NMSettingWirelessPrivate;
 
 /**
@@ -462,166 +463,295 @@ nm_setting_wireless_get_generate_mac_address_mask(NMSettingWireless *setting)
 }
 
 /**
- * nm_setting_wireless_get_mac_address_blacklist:
+ * nm_setting_wireless_get_mac_address_denylist:
  * @setting: the #NMSettingWireless
  *
- * Returns: the #NMSettingWireless:mac-address-blacklist property of the setting
+ * Returns: the #NMSettingWireless:mac-address-denylist property of the setting
+ *
+ * Since: 1.48
  **/
 const char *const *
-nm_setting_wireless_get_mac_address_blacklist(NMSettingWireless *setting)
+nm_setting_wireless_get_mac_address_denylist(NMSettingWireless *setting)
 {
-    NMSettingWirelessPrivate *priv;
-
     g_return_val_if_fail(NM_IS_SETTING_WIRELESS(setting), NULL);
 
-    priv = NM_SETTING_WIRELESS_GET_PRIVATE(setting);
-    return nm_g_array_data(priv->mac_address_blacklist);
+    return nm_strvarray_get_strv_notnull(
+        NM_SETTING_WIRELESS_GET_PRIVATE(setting)->mac_address_denylist.arr,
+        NULL);
 }
 
 /**
- * nm_setting_wireless_get_num_mac_blacklist_items:
+ * nm_setting_wireless_get_num_mac_denylist_items:
  * @setting: the #NMSettingWireless
  *
- * Returns: the number of blacklisted MAC addresses
+ * Returns: the number of denylisted MAC addresses
+ *
+ * Since: 1.48
  **/
-guint32
-nm_setting_wireless_get_num_mac_blacklist_items(NMSettingWireless *setting)
+guint
+nm_setting_wireless_get_num_mac_denylist_items(NMSettingWireless *setting)
 {
     g_return_val_if_fail(NM_IS_SETTING_WIRELESS(setting), 0);
 
-    return NM_SETTING_WIRELESS_GET_PRIVATE(setting)->mac_address_blacklist->len;
+    return nm_g_array_len(NM_SETTING_WIRELESS_GET_PRIVATE(setting)->mac_address_denylist.arr);
 }
 
 /**
- * nm_setting_wireless_get_mac_blacklist_item:
+ * nm_setting_wireless_get_mac_denylist_item:
  * @setting: the #NMSettingWireless
  * @idx: the zero-based index of the MAC address entry
  *
- * Since 1.46, access at index "len" is allowed and returns NULL.
- *
- * Returns: the blacklisted MAC address string (hex-digits-and-colons notation)
+ * Returns: the denylisted MAC address string (hex-digits-and-colons notation)
  * at index @idx
+ *
+ * Since: 1.48
  **/
 const char *
-nm_setting_wireless_get_mac_blacklist_item(NMSettingWireless *setting, guint32 idx)
+nm_setting_wireless_get_mac_denylist_item(NMSettingWireless *setting, guint32 idx)
 {
-    NMSettingWirelessPrivate *priv;
-
     g_return_val_if_fail(NM_IS_SETTING_WIRELESS(setting), NULL);
 
-    priv = NM_SETTING_WIRELESS_GET_PRIVATE(setting);
-
-    if (idx == priv->mac_address_blacklist->len) {
-        return NULL;
-    }
-
-    g_return_val_if_fail(idx < priv->mac_address_blacklist->len, NULL);
-
-    return nm_g_array_index(priv->mac_address_blacklist, const char *, idx);
+    return nm_strvarray_get_idxnull_or_greturn(
+        NM_SETTING_WIRELESS_GET_PRIVATE(setting)->mac_address_denylist.arr,
+        idx);
 }
 
 /**
- * nm_setting_wireless_add_mac_blacklist_item:
+ * nm_setting_wireless_add_mac_denylist_item:
  * @setting: the #NMSettingWireless
- * @mac: the MAC address string (hex-digits-and-colons notation) to blacklist
+ * @mac: the MAC address string (hex-digits-and-colons notation) to denylist
  *
- * Adds a new MAC address to the #NMSettingWireless:mac-address-blacklist property.
+ * Adds a new MAC address to the #NMSettingWireless:mac-address-denylist property.
  *
  * Returns: %TRUE if the MAC address was added; %FALSE if the MAC address
  * is invalid or was already present
+ *
+ * Since: 1.48
  **/
 gboolean
-nm_setting_wireless_add_mac_blacklist_item(NMSettingWireless *setting, const char *mac)
+nm_setting_wireless_add_mac_denylist_item(NMSettingWireless *setting, const char *mac)
 {
     NMSettingWirelessPrivate *priv;
+    guint8                    mac_bin[ETH_ALEN];
     const char               *candidate;
-    int                       i;
+    guint                     i;
+    guint                     len;
 
     g_return_val_if_fail(NM_IS_SETTING_WIRELESS(setting), FALSE);
     g_return_val_if_fail(mac != NULL, FALSE);
 
-    if (!nm_utils_hwaddr_valid(mac, ETH_ALEN))
+    if (!_nm_utils_hwaddr_aton_exact(mac, mac_bin, ETH_ALEN))
         return FALSE;
 
     priv = NM_SETTING_WIRELESS_GET_PRIVATE(setting);
-    for (i = 0; i < priv->mac_address_blacklist->len; i++) {
-        candidate = nm_g_array_index(priv->mac_address_blacklist, char *, i);
-        if (nm_utils_hwaddr_matches(mac, -1, candidate, -1))
+    len  = nm_g_array_len(priv->mac_address_denylist.arr);
+    for (i = 0; i < len; i++) {
+        candidate = nm_g_array_index(priv->mac_address_denylist.arr, char *, i);
+        if (nm_utils_hwaddr_matches(mac_bin, ETH_ALEN, candidate, -1))
             return FALSE;
     }
 
-    mac = nm_utils_hwaddr_canonical(mac, ETH_ALEN);
-    g_array_append_val(priv->mac_address_blacklist, mac);
-    _notify(setting, PROP_MAC_ADDRESS_BLACKLIST);
+    nm_g_array_append_simple(nm_strvarray_ensure(&priv->mac_address_denylist.arr),
+                             nm_utils_hwaddr_ntoa(mac_bin, ETH_ALEN));
+    _notify(setting, PROP_MAC_ADDRESS_DENYLIST);
     return TRUE;
 }
 
 /**
- * nm_setting_wireless_remove_mac_blacklist_item:
+ * nm_setting_wireless_remove_mac_denylist_item:
  * @setting: the #NMSettingWireless
  * @idx: index number of the MAC address
  *
- * Removes the MAC address at index @idx from the blacklist.
+ * Removes the MAC address at index @idx from the denylist.
+ *
+ * Since: 1.48
  **/
 void
-nm_setting_wireless_remove_mac_blacklist_item(NMSettingWireless *setting, guint32 idx)
+nm_setting_wireless_remove_mac_denylist_item(NMSettingWireless *setting, guint idx)
 {
     NMSettingWirelessPrivate *priv;
 
     g_return_if_fail(NM_IS_SETTING_WIRELESS(setting));
 
     priv = NM_SETTING_WIRELESS_GET_PRIVATE(setting);
-    g_return_if_fail(idx < priv->mac_address_blacklist->len);
+    if (!priv->mac_address_denylist.arr) {
+        return;
+    }
+
+    g_return_if_fail(idx < priv->mac_address_denylist.arr->len);
 
-    g_array_remove_index(priv->mac_address_blacklist, idx);
-    _notify(setting, PROP_MAC_ADDRESS_BLACKLIST);
+    g_array_remove_index(priv->mac_address_denylist.arr, idx);
+    _notify(setting, PROP_MAC_ADDRESS_DENYLIST);
 }
 
 /**
- * nm_setting_wireless_remove_mac_blacklist_item_by_value:
+ * nm_setting_wireless_remove_mac_denylist_item_by_value:
  * @setting: the #NMSettingWireless
  * @mac: the MAC address string (hex-digits-and-colons notation) to remove from
- * the blacklist
+ * the denylist
  *
- * Removes the MAC address @mac from the blacklist.
+ * Removes the MAC address @mac from the denylist.
  *
  * Returns: %TRUE if the MAC address was found and removed; %FALSE if it was not.
+ *
+ * Since: 1.48
  **/
 gboolean
-nm_setting_wireless_remove_mac_blacklist_item_by_value(NMSettingWireless *setting, const char *mac)
+nm_setting_wireless_remove_mac_denylist_item_by_value(NMSettingWireless *setting, const char *mac)
 {
     NMSettingWirelessPrivate *priv;
+    guint8                    mac_bin[ETH_ALEN];
     const char               *candidate;
-    int                       i;
+    guint                     i;
 
     g_return_val_if_fail(NM_IS_SETTING_WIRELESS(setting), FALSE);
     g_return_val_if_fail(mac != NULL, FALSE);
 
+    if (!_nm_utils_hwaddr_aton_exact(mac, mac_bin, ETH_ALEN))
+        return FALSE;
+
     priv = NM_SETTING_WIRELESS_GET_PRIVATE(setting);
-    for (i = 0; i < priv->mac_address_blacklist->len; i++) {
-        candidate = nm_g_array_index(priv->mac_address_blacklist, char *, i);
-        if (nm_utils_hwaddr_matches(mac, -1, candidate, -1)) {
-            g_array_remove_index(priv->mac_address_blacklist, i);
-            _notify(setting, PROP_MAC_ADDRESS_BLACKLIST);
-            return TRUE;
+
+    if (priv->mac_address_denylist.arr) {
+        for (i = 0; i < priv->mac_address_denylist.arr->len; i++) {
+            candidate = nm_g_array_index(priv->mac_address_denylist.arr, char *, i);
+            if (nm_utils_hwaddr_matches(mac_bin, ETH_ALEN, candidate, -1)) {
+                g_array_remove_index(priv->mac_address_denylist.arr, i);
+                _notify(setting, PROP_MAC_ADDRESS_DENYLIST);
+                return TRUE;
+            }
         }
     }
+
     return FALSE;
 }
 
 /**
- * nm_setting_wireless_clear_mac_blacklist_items:
+ * nm_setting_wireless_clear_mac_denylist_items:
  * @setting: the #NMSettingWireless
  *
- * Removes all blacklisted MAC addresses.
+ * Removes all denylisted MAC addresses.
+ *
+ * Since: 1.48
  **/
 void
-nm_setting_wireless_clear_mac_blacklist_items(NMSettingWireless *setting)
+nm_setting_wireless_clear_mac_denylist_items(NMSettingWireless *setting)
 {
     g_return_if_fail(NM_IS_SETTING_WIRELESS(setting));
 
-    g_array_set_size(NM_SETTING_WIRELESS_GET_PRIVATE(setting)->mac_address_blacklist, 0);
-    _notify(setting, PROP_MAC_ADDRESS_BLACKLIST);
+    if (nm_strvarray_clear(&NM_SETTING_WIRELESS_GET_PRIVATE(setting)->mac_address_denylist.arr))
+        _notify(setting, PROP_MAC_ADDRESS_DENYLIST);
+}
+
+/**
+ * nm_setting_wireless_get_mac_address_blacklist:
+ * @setting: the #NMSettingWireless
+ *
+ * Returns: the #NMSettingWireless:mac-address-blacklist property of the setting
+ *
+ * Deprecated: 1.48. Use nm_setting_wireless_get_mac_address_denylist() instead.
+ **/
+const char *const *
+nm_setting_wireless_get_mac_address_blacklist(NMSettingWireless *setting)
+{
+    return nm_setting_wireless_get_mac_address_denylist(setting);
+}
+
+/**
+ * nm_setting_wireless_get_num_mac_blacklist_items:
+ * @setting: the #NMSettingWireless
+ *
+ * Returns: the number of blacklist MAC addresses
+ *
+ * Deprecated: 1.48. Use nm_setting_wireless_get_num_mac_denylist_items() instead.
+ **/
+guint32
+nm_setting_wireless_get_num_mac_blacklist_items(NMSettingWireless *setting)
+{
+    return nm_setting_wireless_get_num_mac_denylist_items(setting);
+}
+
+/**
+ * nm_setting_wireless_get_mac_blacklist_item:
+ * @setting: the #NMSettingWireless
+ * @idx: the zero-based index of the MAC address entry
+ *
+ * Since 1.46, access at index "len" is allowed and returns NULL.
+ *
+ * Returns: the denylisted MAC address string (hex-digits-and-colons notation)
+ * at index @idx
+ *
+ * Deprecated: 1.48. Use nm_setting_wireless_get_mac_denylist_item() instead.
+ **/
+const char *
+nm_setting_wireless_get_mac_blacklist_item(NMSettingWireless *setting, guint32 idx)
+{
+    return nm_setting_wireless_get_mac_denylist_item(setting, idx);
+}
+
+/**
+ * nm_setting_wireless_add_mac_blacklist_item:
+ * @setting: the #NMSettingWireless
+ * @mac: the MAC address string (hex-digits-and-colons notation) to denylist
+ *
+ * Adds a new MAC address to the #NMSettingWireless:mac-address-denylist property.
+ *
+ * Returns: %TRUE if the MAC address was added; %FALSE if the MAC address
+ * is invalid or was already present
+ *
+ * Deprecated: 1.48. Use nm_setting_wireless_add_mac_denylist_item() instead.
+ **/
+gboolean
+nm_setting_wireless_add_mac_blacklist_item(NMSettingWireless *setting, const char *mac)
+{
+    return nm_setting_wireless_add_mac_denylist_item(setting, mac);
+}
+
+/**
+ * nm_setting_wireless_remove_mac_blacklist_item:
+ * @setting: the #NMSettingWireless
+ * @idx: index number of the MAC address
+ *
+ * Removes the MAC address at index @idx from the denylist.
+ *
+ * Deprecated: 1.48. Use nm_setting_wireless_remove_mac_denylist_item() instead.
+ **/
+void
+nm_setting_wireless_remove_mac_blacklist_item(NMSettingWireless *setting, guint32 idx)
+{
+    return nm_setting_wireless_remove_mac_denylist_item(setting, idx);
+}
+
+/**
+ * nm_setting_wireless_remove_mac_blacklist_item_by_value:
+ * @setting: the #NMSettingWireless
+ * @mac: the MAC address string (hex-digits-and-colons notation) to remove from
+ * the denylist
+ *
+ * Removes the MAC address @mac from the denylist.
+ *
+ * Returns: %TRUE if the MAC address was found and removed; %FALSE if it was not.
+ *
+ * Deprecated: 1.48. Use nm_setting_wireless_remove_mac_denylist_item_by_value() instead.
+ **/
+gboolean
+nm_setting_wireless_remove_mac_blacklist_item_by_value(NMSettingWireless *setting, const char *mac)
+{
+    return nm_setting_wireless_remove_mac_denylist_item_by_value(setting, mac);
+}
+
+/**
+ * nm_setting_wireless_clear_mac_blacklist_items:
+ * @setting: the #NMSettingWireless
+ *
+ * Removes all denylisted MAC addresses.
+ *
+ * Deprecated: 1.48. Use nm_setting_wireless_clear_mac_denylist_items() instead.
+ **/
+void
+nm_setting_wireless_clear_mac_blacklist_items(NMSettingWireless *setting)
+{
+    return nm_setting_wireless_clear_mac_denylist_items(setting);
 }
 
 /**
@@ -783,6 +913,61 @@ _to_dbus_fcn_seen_bssids(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil)
     return NULL;
 }
 
+gboolean
+_nm_setting_wireless_mac_blacklist_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
+{
+    const gchar **mac_blacklist;
+
+    if (!_nm_setting_use_legacy_property(setting,
+                                         connection_dict,
+                                         NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST,
+                                         NM_SETTING_WIRELESS_MAC_ADDRESS_DENYLIST)) {
+        *out_is_modified = FALSE;
+        return TRUE;
+    }
+    mac_blacklist = g_variant_get_strv(value, NULL);
+
+    g_object_set(setting, NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST, mac_blacklist, NULL);
+    return TRUE;
+}
+
+gboolean
+_nm_setting_wireless_mac_denylist_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
+{
+    const gchar **mac_blacklist;
+
+    if (!_nm_setting_use_legacy_property(setting,
+                                         connection_dict,
+                                         NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST,
+                                         NM_SETTING_WIRELESS_MAC_ADDRESS_DENYLIST)) {
+        *out_is_modified = FALSE;
+        return TRUE;
+    }
+    mac_blacklist = g_variant_get_strv(value, NULL);
+
+    g_object_set(setting, NM_SETTING_WIRELESS_MAC_ADDRESS_DENYLIST, mac_blacklist, NULL);
+    return TRUE;
+}
+
+GVariant *
+_nm_setting_wireless_mac_denylist_to_dbus(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil)
+{
+    const char *const *mac_denylist;
+    /* FIXME: `mac-address-denylist` is an alias of `mac-address-blacklist` property.
+     * Serializing the property to the clients would break them as they won't
+     * be able to drop it if they are not aware of the existance of
+     * `mac-address-denylist`. In order to give them time to adapt their code,
+     * NetworkManager is not serializing `mac-address-denylist` on DBus.
+     */
+    if (_nm_utils_is_manager_process) {
+        return NULL;
+    }
+
+    mac_denylist = nm_setting_wireless_get_mac_address_denylist(NM_SETTING_WIRELESS(setting));
+
+    return g_variant_new_strv(mac_denylist, -1);
+}
+
 static gboolean
 _from_dbus_fcn_seen_bssids(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
 {
@@ -1041,20 +1226,22 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
         return FALSE;
     }
 
-    for (i = 0; i < priv->mac_address_blacklist->len; i++) {
-        const char *mac = nm_g_array_index(priv->mac_address_blacklist, const char *, i);
+    if (priv->mac_address_denylist.arr) {
+        for (i = 0; i < priv->mac_address_denylist.arr->len; i++) {
+            const char *mac = nm_g_array_index(priv->mac_address_denylist.arr, const char *, i);
 
-        if (!nm_utils_hwaddr_valid(mac, ETH_ALEN)) {
-            g_set_error(error,
-                        NM_CONNECTION_ERROR,
-                        NM_CONNECTION_ERROR_INVALID_PROPERTY,
-                        _("'%s' is not a valid MAC address"),
-                        mac);
-            g_prefix_error(error,
-                           "%s.%s: ",
-                           NM_SETTING_WIRELESS_SETTING_NAME,
-                           NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST);
-            return FALSE;
+            if (!nm_utils_hwaddr_valid(mac, ETH_ALEN)) {
+                g_set_error(error,
+                            NM_CONNECTION_ERROR,
+                            NM_CONNECTION_ERROR_INVALID_PROPERTY,
+                            _("'%s' is not a valid MAC address"),
+                            mac);
+                g_prefix_error(error,
+                               "%s.%s: ",
+                               NM_SETTING_WIRELESS_SETTING_NAME,
+                               NM_SETTING_WIRELESS_MAC_ADDRESS_DENYLIST);
+                return FALSE;
+            }
         }
     }
 
@@ -1216,12 +1403,6 @@ nm_setting_wireless_get_wake_on_wlan(NMSettingWireless *setting)
     return NM_SETTING_WIRELESS_GET_PRIVATE(setting)->wake_on_wlan;
 }
 
-static void
-clear_blacklist_item(char **item_p)
-{
-    g_free(*item_p);
-}
-
 /*****************************************************************************/
 
 static void
@@ -1234,9 +1415,6 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
     case PROP_CLONED_MAC_ADDRESS:
         g_value_set_string(value, nm_setting_wireless_get_cloned_mac_address(setting));
         break;
-    case PROP_MAC_ADDRESS_BLACKLIST:
-        g_value_set_boxed(value, nm_g_array_data(priv->mac_address_blacklist));
-        break;
     case PROP_SEEN_BSSIDS:
         g_value_take_boxed(
             value,
@@ -1255,8 +1433,6 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps
 {
     NMSettingWireless        *self = NM_SETTING_WIRELESS(object);
     NMSettingWirelessPrivate *priv = NM_SETTING_WIRELESS_GET_PRIVATE(self);
-    const char *const        *blacklist;
-    const char               *mac;
     gboolean                  bool_val;
     _PropertyEnums            prop1 = PROP_0;
     _PropertyEnums            prop2 = PROP_0;
@@ -1281,18 +1457,6 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps
 
         nm_gobject_notify_together(self, prop1, prop2);
         break;
-    case PROP_MAC_ADDRESS_BLACKLIST:
-        blacklist = g_value_get_boxed(value);
-        g_array_set_size(priv->mac_address_blacklist, 0);
-        if (blacklist && blacklist[0]) {
-            gsize i;
-
-            for (i = 0; blacklist[i]; i++) {
-                mac = _nm_utils_hwaddr_canonical_or_invalid(blacklist[i], ETH_ALEN);
-                g_array_append_val(priv->mac_address_blacklist, mac);
-            }
-        }
-        break;
     case PROP_SEEN_BSSIDS:
     {
         gs_unref_ptrarray GPtrArray *arr_old = NULL;
@@ -1321,13 +1485,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps
 
 static void
 nm_setting_wireless_init(NMSettingWireless *setting)
-{
-    NMSettingWirelessPrivate *priv = NM_SETTING_WIRELESS_GET_PRIVATE(setting);
-
-    /* We use GArray rather than GPtrArray so it will automatically be NULL-terminated */
-    priv->mac_address_blacklist = g_array_new(TRUE, FALSE, sizeof(char *));
-    g_array_set_clear_func(priv->mac_address_blacklist, (GDestroyNotify) clear_blacklist_item);
-}
+{}
 
 /**
  * nm_setting_wireless_new:
@@ -1348,7 +1506,6 @@ finalize(GObject *object)
     NMSettingWirelessPrivate *priv = NM_SETTING_WIRELESS_GET_PRIVATE(object);
 
     g_free(priv->cloned_mac_address);
-    g_array_unref(priv->mac_address_blacklist);
     nm_g_ptr_array_unref(priv->seen_bssids);
 
     G_OBJECT_CLASS(nm_setting_wireless_parent_class)->finalize(object);
@@ -1360,6 +1517,7 @@ nm_setting_wireless_class_init(NMSettingWirelessClass *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_sized(25);
+    guint           prop_idx;
 
     object_class->set_property = set_property;
     object_class->get_property = get_property;
@@ -1733,11 +1891,66 @@ nm_setting_wireless_class_init(NMSettingWirelessClass *klass)
      *   is listed.
      * ---end---
      */
-    _nm_setting_property_define_gprop_strv_oldstyle(properties_override,
-                                                    obj_properties,
-                                                    NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST,
-                                                    PROP_MAC_ADDRESS_BLACKLIST,
-                                                    NM_SETTING_PARAM_FUZZY_IGNORE);
+    prop_idx = _nm_setting_property_define_direct_strv(
+        properties_override,
+        obj_properties,
+        NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST,
+        PROP_MAC_ADDRESS_BLACKLIST,
+        NM_SETTING_PARAM_FUZZY_IGNORE,
+        NM_SETT_INFO_PROPERT_TYPE_DBUS(G_VARIANT_TYPE_STRING_ARRAY,
+                                       .direct_type = NM_VALUE_TYPE_STRV,
+                                       .compare_fcn = _nm_setting_property_compare_fcn_direct,
+                                       .to_dbus_fcn = _nm_setting_property_to_dbus_fcn_direct,
+                                       .from_dbus_fcn =
+                                           _nm_setting_wireless_mac_blacklist_from_dbus, ),
+        NMSettingWirelessPrivate,
+        mac_address_denylist,
+        .direct_set_strv_normalize_hwaddr = TRUE,
+        .direct_strv_not_null             = TRUE,
+        .direct_is_aliased_field          = TRUE,
+        .is_deprecated                    = TRUE);
+
+    /**
+     * NMSettingWireless:mac-address-denylist:
+     *
+     * A list of permanent MAC addresses of Wi-Fi devices to which this
+     * connection should never apply.  Each MAC address should be given in the
+     * standard hex-digits-and-colons notation (eg "00:11:22:33:44:55").
+     **/
+    /* ---keyfile---
+     * property: mac-address-denylist
+     * format: list of MACs (separated with semicolons)
+     * description: MAC address denylist.
+     * example: mac-address-denylist= 00:22:68:12:79:A6;00:22:68:12:79:78
+     * ---end---
+     */
+    /* ---ifcfg-rh---
+     * property: mac-address-denylist
+     * variable: HWADDR_BLACKLIST(+)
+     * description: It denies usage of the connection for any device whose address
+     *   is listed.
+     * ---end---
+     */
+    _nm_setting_property_define_direct_strv(
+        properties_override,
+        obj_properties,
+        NM_SETTING_WIRELESS_MAC_ADDRESS_DENYLIST,
+        PROP_MAC_ADDRESS_DENYLIST,
+        NM_SETTING_PARAM_FUZZY_IGNORE,
+        NM_SETT_INFO_PROPERT_TYPE_DBUS(G_VARIANT_TYPE_STRING_ARRAY,
+                                       .direct_type = NM_VALUE_TYPE_STRV,
+                                       .compare_fcn = _nm_setting_property_compare_fcn_direct,
+                                       .to_dbus_fcn = _nm_setting_wireless_mac_denylist_to_dbus,
+                                       .from_dbus_fcn =
+                                           _nm_setting_wireless_mac_denylist_from_dbus, ),
+        NMSettingWirelessPrivate,
+        mac_address_denylist,
+        .direct_set_strv_normalize_hwaddr = TRUE,
+        .direct_strv_not_null             = TRUE,
+        .direct_also_notify               = obj_properties[PROP_MAC_ADDRESS_BLACKLIST], );
+
+    nm_g_array_index(properties_override, NMSettInfoProperty, prop_idx).direct_also_notify =
+        obj_properties[PROP_MAC_ADDRESS_DENYLIST];
 
     /**
      * NMSettingWireless:seen-bssids:
diff --git a/src/libnm-core-impl/nm-setting.c b/src/libnm-core-impl/nm-setting.c
index 8bc7b4bf..bbaa6fcd 100644
--- a/src/libnm-core-impl/nm-setting.c
+++ b/src/libnm-core-impl/nm-setting.c
@@ -8,6 +8,8 @@
 
 #include "nm-setting.h"
 
+#include <linux/if_ether.h>
+
 #include "libnm-core-intern/nm-core-internal.h"
 #include "libnm-glib-aux/nm-ref-string.h"
 #include "libnm-glib-aux/nm-secret-utils.h"
@@ -739,10 +741,29 @@ _property_direct_set_strv(const NMSettInfoSetting  *sett_info,
     if (!property_info->direct_strv_preserve_empty && strv && !strv[0])
         strv = NULL;
 
-    if (nm_strvarray_equal_strv(p_val->arr, strv, -1))
-        return FALSE;
+    if (property_info->direct_set_strv_normalize_hwaddr) {
+        gs_unref_array GArray *arr = NULL;
+        if (strv) {
+            nm_strvarray_ensure(&arr);
+
+            for (; strv[0]; strv++) {
+                nm_strvarray_add_take(arr,
+                                      _nm_utils_hwaddr_canonical_or_invalid(strv[0], ETH_ALEN));
+            }
+        }
+
+        if (nm_strvarray_equal(p_val->arr, arr))
+            return FALSE;
 
+        NM_SWAP(&p_val->arr, &arr);
+        return TRUE;
+    }
+
+    if (nm_strvarray_equal_strv(p_val->arr, strv, -1)) {
+        return FALSE;
+    }
     nm_strvarray_set_strv_full(&p_val->arr, strv, property_info->direct_strv_preserve_empty);
+
     return TRUE;
 }
 
@@ -844,7 +865,7 @@ _nm_setting_property_get_property_direct(GObject    *object,
             value,
             nm_strvarray_get_strv_full_dup(p_val->arr,
                                            NULL,
-                                           FALSE,
+                                           property_info->direct_strv_not_null,
                                            property_info->direct_strv_preserve_empty));
         return;
     }
@@ -2711,7 +2732,9 @@ _nm_setting_property_compare_fcn_direct(_NM_SETT_INFO_PROP_COMPARE_FCN_ARGS _nm_
                         _nm_setting_property_to_dbus_fcn_direct_mac_address,
                         _nm_setting_connection_controller_to_dbus,
                         _nm_setting_connection_port_type_to_dbus,
-                        _nm_setting_connection_autoconnect_ports_to_dbus));
+                        _nm_setting_connection_autoconnect_ports_to_dbus,
+                        _nm_setting_wireless_mac_denylist_to_dbus,
+                        _nm_setting_wired_mac_denylist_to_dbus));
 
     if (!property_info->param_spec)
         return nm_assert_unreachable_val(NM_TERNARY_DEFAULT);
diff --git a/src/libnm-core-impl/nm-team-utils.c b/src/libnm-core-impl/nm-team-utils.c
index 6f2f5dd2..83452569 100644
--- a/src/libnm-core-impl/nm-team-utils.c
+++ b/src/libnm-core-impl/nm-team-utils.c
@@ -172,17 +172,17 @@ static const TeamAttrData team_attr_datas[] = {
 
 #define _VAL_INT32_RANGE(_default, _min, _max) \
     _VAL_INT32(_default), .has_range = TRUE,   \
-                          .range.r_int32 = {   \
-                              .min = _min,     \
-                              .max = _max,     \
+        .range.r_int32 = {                     \
+            .min = _min,                       \
+            .max = _max,                       \
     }
 
 #define _VAL_STRING() .default_val.v_string = NULL
 
-#define _VAL_STRING_RANGE(_valid_names)               \
-    _VAL_STRING(), .has_range = TRUE,                 \
-                   .range.r_string = {                \
-                       .valid_names = (_valid_names), \
+#define _VAL_STRING_RANGE(_valid_names)    \
+    _VAL_STRING(), .has_range = TRUE,      \
+        .range.r_string = {                \
+            .valid_names = (_valid_names), \
     }
 
 #define _VAL_UNSPEC() .default_val.v_string = (NULL)
@@ -1957,23 +1957,23 @@ _js_parse_locate_keys(const NMJsonVt *vt,
 
     nm_assert(vt);
 
-#define _handle(_self, _cur_key, _cur_val, _keys, _level, _found_keys, _out_unrecognized_content)  \
-    ({                                                                                             \
-        const TeamAttrData *_attr_data;                                                            \
-        gboolean            _handled = FALSE;                                                      \
-                                                                                                   \
-        (_keys)[(_level) -1] = (_cur_key);                                                         \
-        _attr_data           = _attr_data_find_by_json_key((_self)->d.is_port, (_keys), (_level)); \
-        if (_attr_data && _attr_data->js_keys_len == (_level)) {                                   \
-            if ((_found_keys)[_attr_data->team_attr])                                              \
-                *(_out_unrecognized_content) = TRUE;                                               \
-            (_found_keys)[_attr_data->team_attr] = (_cur_val);                                     \
-            _handled                             = TRUE;                                           \
-        } else if (!_attr_data || !nm_json_is_object((_cur_val))) {                                \
-            *(_out_unrecognized_content) = TRUE;                                                   \
-            _handled                     = TRUE;                                                   \
-        }                                                                                          \
-        _handled;                                                                                  \
+#define _handle(_self, _cur_key, _cur_val, _keys, _level, _found_keys, _out_unrecognized_content)   \
+    ({                                                                                              \
+        const TeamAttrData *_attr_data;                                                             \
+        gboolean            _handled = FALSE;                                                       \
+                                                                                                    \
+        (_keys)[(_level) - 1] = (_cur_key);                                                         \
+        _attr_data            = _attr_data_find_by_json_key((_self)->d.is_port, (_keys), (_level)); \
+        if (_attr_data && _attr_data->js_keys_len == (_level)) {                                    \
+            if ((_found_keys)[_attr_data->team_attr])                                               \
+                *(_out_unrecognized_content) = TRUE;                                                \
+            (_found_keys)[_attr_data->team_attr] = (_cur_val);                                      \
+            _handled                             = TRUE;                                            \
+        } else if (!_attr_data || !nm_json_is_object((_cur_val))) {                                 \
+            *(_out_unrecognized_content) = TRUE;                                                    \
+            _handled                     = TRUE;                                                    \
+        }                                                                                           \
+        _handled;                                                                                   \
     })
 
     nm_json_object_foreach (vt, root_js_obj, cur_key1, cur_val1) {
@@ -2809,16 +2809,8 @@ NMTeamSetting *
 nm_team_setting_new(gboolean is_port, const char *js_str)
 {
     NMTeamSetting *self;
-    gsize          l;
 
-    G_STATIC_ASSERT_EXPR(sizeof(*self) == sizeof(self->_data_priv));
-    G_STATIC_ASSERT_EXPR(
-        sizeof(*self)
-        == NM_MAX(nm_offsetofend(NMTeamSetting, d.master), nm_offsetofend(NMTeamSetting, d.port)));
-
-    l = is_port ? nm_offsetofend(NMTeamSetting, d.port) : nm_offsetofend(NMTeamSetting, d.master);
-
-    self = g_malloc0(l);
+    self = g_malloc0(sizeof(NMTeamSetting));
 
     self->_data_priv.is_port                 = is_port;
     self->_data_priv.strict_validated        = TRUE;
diff --git a/src/libnm-core-impl/nm-utils.c b/src/libnm-core-impl/nm-utils.c
index 761f74bd..b6e24141 100644
--- a/src/libnm-core-impl/nm-utils.c
+++ b/src/libnm-core-impl/nm-utils.c
@@ -506,7 +506,8 @@ nmtst_system_encodings_get(void)
 
 /*****************************************************************************/
 
-static void __attribute__((constructor)) _nm_utils_init(void)
+static void __attribute__((constructor))
+_nm_utils_init(void)
 {
     static int initialized = 0;
 
diff --git a/src/libnm-core-impl/tests/test-general.c b/src/libnm-core-impl/tests/test-general.c
index bf0f272c..f745d059 100644
--- a/src/libnm-core-impl/tests/test-general.c
+++ b/src/libnm-core-impl/tests/test-general.c
@@ -3962,7 +3962,7 @@ typedef struct {
 
 typedef struct {
     const char *name;
-    DiffKey     keys[32];
+    DiffKey     keys[33];
 } DiffSetting;
 
 #define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
@@ -4036,6 +4036,7 @@ test_connection_diff_a_only(void)
           {NM_SETTING_CONNECTION_MUD_URL, NM_SETTING_DIFF_RESULT_IN_A},
           {NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A},
           {NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY, NM_SETTING_DIFF_RESULT_IN_A},
+          {NM_SETTING_CONNECTION_DOWN_ON_POWEROFF, NM_SETTING_DIFF_RESULT_IN_A},
           {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN}}},
         {NM_SETTING_WIRED_SETTING_NAME,
          {
@@ -4047,6 +4048,7 @@ test_connection_diff_a_only(void)
              {NM_SETTING_WIRED_CLONED_MAC_ADDRESS, NM_SETTING_DIFF_RESULT_IN_A},
              {NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK, NM_SETTING_DIFF_RESULT_IN_A},
              {NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST, NM_SETTING_DIFF_RESULT_IN_A},
+             {NM_SETTING_WIRED_MAC_ADDRESS_DENYLIST, NM_SETTING_DIFF_RESULT_IN_A},
              {NM_SETTING_WIRED_MTU, NM_SETTING_DIFF_RESULT_IN_A},
              {NM_SETTING_WIRED_S390_SUBCHANNELS, NM_SETTING_DIFF_RESULT_IN_A},
              {NM_SETTING_WIRED_S390_NETTYPE, NM_SETTING_DIFF_RESULT_IN_A},
@@ -4088,6 +4090,7 @@ test_connection_diff_a_only(void)
              {NM_SETTING_IP4_CONFIG_LINK_LOCAL, NM_SETTING_DIFF_RESULT_IN_A},
              {NM_SETTING_IP_CONFIG_AUTO_ROUTE_EXT_GW, NM_SETTING_DIFF_RESULT_IN_A},
              {NM_SETTING_IP_CONFIG_REPLACE_LOCAL_RULE, NM_SETTING_DIFF_RESULT_IN_A},
+             {NM_SETTING_IP_CONFIG_DHCP_SEND_RELEASE, NM_SETTING_DIFF_RESULT_IN_A},
              {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN},
          }},
     };
diff --git a/src/libnm-core-impl/tests/test-keyfile.c b/src/libnm-core-impl/tests/test-keyfile.c
index 2b21e583..9f546971 100644
--- a/src/libnm-core-impl/tests/test-keyfile.c
+++ b/src/libnm-core-impl/tests/test-keyfile.c
@@ -200,7 +200,7 @@ _nm_keyfile_read(GKeyFile            *keyfile,
              * keyfile reader does not add that (unless a [proxy] section
              * is present. */
             s_con = nm_connection_get_setting_connection(con);
-            if (s_con && !nm_setting_connection_get_master(s_con)
+            if (s_con && !nm_setting_connection_get_controller(s_con)
                 && !nm_connection_get_setting_proxy(con))
                 nm_connection_add_setting(con, nm_setting_proxy_new());
         }
diff --git a/src/libnm-core-impl/tests/test-secrets.c b/src/libnm-core-impl/tests/test-secrets.c
index 2fa3f105..cb5c23a4 100644
--- a/src/libnm-core-impl/tests/test-secrets.c
+++ b/src/libnm-core-impl/tests/test-secrets.c
@@ -250,6 +250,8 @@ make_tls_phase2_connection(const char *detail, NMSetting8021xCKScheme scheme)
                                           &error);
     nmtst_assert_success(success, error);
 
+    g_object_set(s_8021x, NM_SETTING_802_1X_OPENSSL_CIPHERS, "DEFAULT@SECLEVEL=0", NULL);
+
     /* IP4 setting */
     s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new();
     nm_connection_add_setting(connection, NM_SETTING(s_ip4));
diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c
index 4b5a0b6f..f3309166 100644
--- a/src/libnm-core-impl/tests/test-setting.c
+++ b/src/libnm-core-impl/tests/test-setting.c
@@ -4732,8 +4732,10 @@ test_setting_metadata(void)
                 g_assert(sip->param_spec->value_type == G_TYPE_BYTES);
             } else if (sip->property_type->direct_type == NM_VALUE_TYPE_STRV) {
                 g_assert(g_variant_type_equal(sip->property_type->dbus_type, "as"));
-                g_assert(sip->property_type->to_dbus_fcn
-                         == _nm_setting_property_to_dbus_fcn_direct);
+                g_assert(NM_IN_SET(sip->property_type->to_dbus_fcn,
+                                   _nm_setting_property_to_dbus_fcn_direct,
+                                   _nm_setting_wireless_mac_denylist_to_dbus,
+                                   _nm_setting_wired_mac_denylist_to_dbus));
                 g_assert(sip->param_spec);
                 g_assert(sip->param_spec->value_type == G_TYPE_STRV);
             } else