summary refs log tree commit diff
path: root/src/libnm-client-impl
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2024-01-25 09:46:18 +0100
committerMichael Biebl <biebl@debian.org>2024-01-25 09:46:18 +0100
commit70e18d99b8e3e77bb37e218d7ac582130156f8ef (patch)
treed40c587e6d3f0e094ff558e415f1bb9803643214 /src/libnm-client-impl
parentd4d8b2b91f7ba000d97a8b2aab48c85000c11314 (diff)
New upstream version 1.45.90 upstream/1.45.90
Diffstat (limited to 'src/libnm-client-impl')
-rw-r--r--src/libnm-client-impl/libnm.ver22
-rw-r--r--src/libnm-client-impl/meson.build117
-rw-r--r--src/libnm-client-impl/nm-access-point.c39
-rw-r--r--src/libnm-client-impl/nm-client.c1
-rw-r--r--src/libnm-client-impl/nm-dbus-helpers.h2
-rw-r--r--src/libnm-client-impl/nm-device-hsr.c279
-rw-r--r--src/libnm-client-impl/nm-device-ip-tunnel.c39
-rw-r--r--src/libnm-client-impl/nm-device.c3
-rw-r--r--src/libnm-client-impl/nm-dhcp4-config.h2
-rw-r--r--src/libnm-client-impl/nm-dhcp6-config.h2
-rw-r--r--src/libnm-client-impl/nm-dns-manager.h2
-rw-r--r--src/libnm-client-impl/nm-ip-config.c2
-rw-r--r--src/libnm-client-impl/nm-ip4-config.h2
-rw-r--r--src/libnm-client-impl/nm-ip6-config.h2
-rw-r--r--src/libnm-client-impl/nm-libnm-utils.c48
-rw-r--r--src/libnm-client-impl/nm-libnm-utils.h46
-rw-r--r--src/libnm-client-impl/nm-object-private.h2
-rw-r--r--src/libnm-client-impl/nm-remote-connection-private.h2
-rwxr-xr-xsrc/libnm-client-impl/tests/test-gir.py2
-rw-r--r--src/libnm-client-impl/tests/test-libnm.c4
20 files changed, 527 insertions, 91 deletions
diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver
index 919ffc74..3b603b81 100644
--- a/src/libnm-client-impl/libnm.ver
+++ b/src/libnm-client-impl/libnm.ver
@@ -1943,3 +1943,25 @@ global:
 	nm_setting_link_get_type;
 	nm_setting_link_new;
 } libnm_1_42_0;
+
+libnm_1_46_0 {
+global:
+	nm_access_point_get_bandwidth;
+	nm_device_hsr_get_multicast_spec;
+	nm_device_hsr_get_port1;
+	nm_device_hsr_get_port2;
+	nm_device_hsr_get_prp;
+	nm_device_hsr_get_supervision_address;
+	nm_device_hsr_get_type;
+	nm_device_ip_tunnel_get_fwmark;
+	nm_ethtool_optname_is_channels;
+	nm_ethtool_optname_is_eee;
+	nm_setting_connection_get_controller;
+	nm_setting_connection_get_port_type;
+	nm_setting_hsr_get_multicast_spec;
+	nm_setting_hsr_get_port1;
+	nm_setting_hsr_get_port2;
+	nm_setting_hsr_get_prp;
+	nm_setting_hsr_get_type;
+	nm_setting_hsr_new;
+} libnm_1_44_0;
diff --git a/src/libnm-client-impl/meson.build b/src/libnm-client-impl/meson.build
index fb879dca..79ac9559 100644
--- a/src/libnm-client-impl/meson.build
+++ b/src/libnm-client-impl/meson.build
@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 
+libnm_client_impl_inc = include_directories('.')
+
 libnm_client_impl_sources = files(
   'nm-access-point.c',
   'nm-active-connection.c',
@@ -15,6 +17,7 @@ libnm_client_impl_sources = files(
   'nm-device-dummy.c',
   'nm-device-ethernet.c',
   'nm-device-generic.c',
+  'nm-device-hsr.c',
   'nm-device-infiniband.c',
   'nm-device-ip-tunnel.c',
   'nm-device-loopback.c',
@@ -163,38 +166,76 @@ if enable_introspection
     install: true,
   )
 
-  infos = [ 'dbus', 'nmcli', 'keyfile' ]
+  gi_typelib_path = run_command('printenv', 'GI_TYPELIB_PATH').stdout()
+  if gi_typelib_path != ''
+    gi_typelib_path = ':' + gi_typelib_path
+  endif
+  gi_typelib_path = meson.current_build_dir() + gi_typelib_path
+
+  ld_library_path = run_command('printenv', 'LD_LIBRARY_PATH').stdout()
+  if ld_library_path != ''
+    ld_library_path = ':' + ld_library_path
+  endif
+  ld_library_path = meson.current_build_dir() + ld_library_path
+
+  gen_infos_cmd = join_paths(meson.source_root(), 'tools', 'generate-docs-nm-property-infos.py')
+  gen_gir_cmd = join_paths(meson.source_root(), 'tools', 'generate-docs-nm-settings-docs-gir.py')
+
+  names = [ 'dbus', 'nmcli', 'keyfile' ]
   if enable_ifcfg_rh
-    infos += [ 'ifcfg-rh' ]
+    names += [ 'ifcfg-rh' ]
   endif
-  foreach info: infos
-    t = custom_target(
-      'nm-propery-infos-' + info + '.xml',
-      input: libnm_core_settings_sources,
-      output: 'nm-propery-infos-' + info + '.xml',
+  foreach name: names
+    t_infos = custom_target(
+      'nm-property-infos-' + name + '.xml',
+      input: [gen_infos_cmd, libnm_gir[0]] + libnm_core_settings_sources,
+      output: 'nm-property-infos-' + name + '.xml',
       command: [
         python.path(),
-        join_paths(meson.source_root(), 'tools', 'generate-docs-nm-property-infos.py'),
-        info,
+        gen_infos_cmd,
+        name,
         '@OUTPUT@',
-        '@INPUT@'
+        libnm_gir[0]
+      ] + libnm_core_settings_sources,
+    )
+
+    t_gir = custom_target(
+      'nm-settings-docs-gir-' + name + '.xml',
+      input: [gen_gir_cmd, libnm_gir[0]],
+      output: 'nm-settings-docs-gir-' + name + '.xml',
+      command: [
+        'env',
+        'GI_TYPELIB_PATH=' + gi_typelib_path,
+        'LD_LIBRARY_PATH=' + ld_library_path,
+        python.path(),
+        gen_gir_cmd,
+        '--lib-path', meson.current_build_dir(),
+        '--gir', libnm_gir[0],
+        '--output', '@OUTPUT@',
+        '--target', name
       ],
+      depends: libnm_gir,
     )
 
     # meson 0.47 doesn't support non-static keys for dicts
     # nor extending dicts incrementally. Workaround.
-    if info == 'dbus'
-      nm_property_infos_xml_dbus = t
-    elif info == 'keyfile'
-      nm_property_infos_xml_keyfile = t
-    elif info == 'ifcfg-rh'
-      nm_property_infos_xml_ifcfg_rh = t
-    elif info == 'nmcli'
-      nm_property_infos_xml_nmcli = t
+    if name == 'dbus'
+      nm_property_infos_xml_dbus = t_infos
+      nm_settings_docs_xml_gir_dbus = t_gir
+    elif name == 'keyfile'
+      nm_property_infos_xml_keyfile = t_infos
+      nm_settings_docs_xml_gir_keyfile = t_gir
+    elif name == 'ifcfg-rh'
+      nm_property_infos_xml_ifcfg_rh = t_infos
+      nm_settings_docs_xml_gir_ifcfg_rh = t_gir
+    elif name == 'nmcli'
+      nm_property_infos_xml_nmcli = t_infos
+      nm_settings_docs_xml_gir_nmcli = t_gir
     else
       assert(false)
     endif
   endforeach
+
   if enable_ifcfg_rh
     nm_property_infos_xml = {
       'dbus':     nm_property_infos_xml_dbus,
@@ -202,40 +243,22 @@ if enable_introspection
       'nmcli':    nm_property_infos_xml_nmcli,
       'ifcfg-rh': nm_property_infos_xml_ifcfg_rh,
     }
+    nm_settings_docs_xml_gir = {
+      'dbus':     nm_settings_docs_xml_gir_dbus,
+      'keyfile':  nm_settings_docs_xml_gir_keyfile,
+      'nmcli':    nm_settings_docs_xml_gir_nmcli,
+      'ifcfg-rh': nm_settings_docs_xml_gir_ifcfg_rh,
+    }
   else
     nm_property_infos_xml = {
       'dbus':    nm_property_infos_xml_dbus,
       'keyfile': nm_property_infos_xml_keyfile,
       'nmcli':   nm_property_infos_xml_nmcli,
     }
+    nm_settings_docs_xml_gir = {
+      'dbus':     nm_settings_docs_xml_gir_dbus,
+      'keyfile':  nm_settings_docs_xml_gir_keyfile,
+      'nmcli':    nm_settings_docs_xml_gir_nmcli,
+    }
   endif
-
-  gi_typelib_path = run_command('printenv', 'GI_TYPELIB_PATH').stdout()
-  if gi_typelib_path != ''
-    gi_typelib_path = ':' + gi_typelib_path
-  endif
-  gi_typelib_path = meson.current_build_dir() + gi_typelib_path
-
-  ld_library_path = run_command('printenv', 'LD_LIBRARY_PATH').stdout()
-  if ld_library_path != ''
-    ld_library_path = ':' + ld_library_path
-  endif
-  ld_library_path = meson.current_build_dir() + ld_library_path
-
-  nm_settings_docs_xml_gir = custom_target(
-    'nm-settings-docs-gir.xml',
-    input: libnm_gir[0],
-    output: 'nm-settings-docs-gir.xml',
-    command: [
-      'env',
-      'GI_TYPELIB_PATH=' + gi_typelib_path,
-      'LD_LIBRARY_PATH=' + ld_library_path,
-      python.path(),
-      join_paths(meson.source_root(), 'tools', 'generate-docs-nm-settings-docs-gir.py'),
-      '--lib-path', meson.current_build_dir(),
-      '--gir', '@INPUT@',
-      '--output', '@OUTPUT@'
-    ],
-    depends: libnm_gir,
-  )
 endif
diff --git a/src/libnm-client-impl/nm-access-point.c b/src/libnm-client-impl/nm-access-point.c
index 94b38f03..a06bee48 100644
--- a/src/libnm-client-impl/nm-access-point.c
+++ b/src/libnm-client-impl/nm-access-point.c
@@ -30,6 +30,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMAccessPoint,
                              PROP_HW_ADDRESS,
                              PROP_MODE,
                              PROP_MAX_BITRATE,
+                             PROP_BANDWIDTH,
                              PROP_STRENGTH,
                              PROP_BSSID,
                              PROP_LAST_SEEN, );
@@ -43,6 +44,7 @@ typedef struct {
     guint32 frequency;
     guint32 mode;
     guint32 max_bitrate;
+    guint32 bandwidth;
     gint32  last_seen;
     guint8  strength;
 } NMAccessPointPrivate;
@@ -199,6 +201,24 @@ nm_access_point_get_max_bitrate(NMAccessPoint *ap)
 }
 
 /**
+ * nm_access_point_get_bandwidth:
+ * @ap: a #NMAccessPoint
+ *
+ * Gets the bandwidth advertised by the access point in MHz.
+ *
+ * Returns: the advertised bandwidth (MHz)
+ *
+ * Since: 1.46
+ **/
+guint32
+nm_access_point_get_bandwidth(NMAccessPoint *ap)
+{
+    g_return_val_if_fail(NM_IS_ACCESS_POINT(ap), 0);
+
+    return NM_ACCESS_POINT_GET_PRIVATE(ap)->bandwidth;
+}
+
+/**
  * nm_access_point_get_strength:
  * @ap: a #NMAccessPoint
  *
@@ -463,6 +483,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
     case PROP_MAX_BITRATE:
         g_value_set_uint(value, nm_access_point_get_max_bitrate(ap));
         break;
+    case PROP_BANDWIDTH:
+        g_value_set_uint(value, nm_access_point_get_bandwidth(ap));
+        break;
     case PROP_STRENGTH:
         g_value_set_uchar(value, nm_access_point_get_strength(ap));
         break;
@@ -480,6 +503,7 @@ const NMLDBusMetaIface _nml_dbus_meta_iface_nm_accesspoint = NML_DBUS_META_IFACE
     nm_access_point_get_type,
     NML_DBUS_META_INTERFACE_PRIO_INSTANTIATE_30,
     NML_DBUS_META_IFACE_DBUS_PROPERTIES(
+        NML_DBUS_META_PROPERTY_INIT_U("Bandwidth", PROP_BANDWIDTH, NMAccessPoint, _priv.bandwidth),
         NML_DBUS_META_PROPERTY_INIT_U("Flags", PROP_FLAGS, NMAccessPoint, _priv.flags),
         NML_DBUS_META_PROPERTY_INIT_U("Frequency", PROP_FREQUENCY, NMAccessPoint, _priv.frequency),
         NML_DBUS_META_PROPERTY_INIT_FCN("HwAddress",
@@ -621,6 +645,21 @@ nm_access_point_class_init(NMAccessPointClass *ap_class)
                                                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
     /**
+     * NMAccessPoint:bandwidth:
+     *
+     * The channel bandwidth announced by the AP in MHz.
+     *
+     * Since: 1.46
+     **/
+    obj_properties[PROP_BANDWIDTH] = g_param_spec_uint(NM_ACCESS_POINT_BANDWIDTH,
+                                                       "",
+                                                       "",
+                                                       0,
+                                                       G_MAXUINT32,
+                                                       0,
+                                                       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+    /**
      * NMAccessPoint:strength:
      *
      * The current signal strength of the access point.
diff --git a/src/libnm-client-impl/nm-client.c b/src/libnm-client-impl/nm-client.c
index f3ab6d69..1598fb30 100644
--- a/src/libnm-client-impl/nm-client.c
+++ b/src/libnm-client-impl/nm-client.c
@@ -29,6 +29,7 @@
 #include "nm-device-dummy.h"
 #include "nm-device-ethernet.h"
 #include "nm-device-generic.h"
+#include "nm-device-hsr.h"
 #include "nm-device-infiniband.h"
 #include "nm-device-ip-tunnel.h"
 #include "nm-device-loopback.h"
diff --git a/src/libnm-client-impl/nm-dbus-helpers.h b/src/libnm-client-impl/nm-dbus-helpers.h
index 5a6b2d62..96c8ee75 100644
--- a/src/libnm-client-impl/nm-dbus-helpers.h
+++ b/src/libnm-client-impl/nm-dbus-helpers.h
@@ -6,7 +6,7 @@
 #ifndef __NM_DBUS_HELPERS_PRIVATE_H__
 #define __NM_DBUS_HELPERS_PRIVATE_H__
 
-#if !((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
+#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
 #error Cannot use this header.
 #endif
 
diff --git a/src/libnm-client-impl/nm-device-hsr.c b/src/libnm-client-impl/nm-device-hsr.c
new file mode 100644
index 00000000..7160bf6d
--- /dev/null
+++ b/src/libnm-client-impl/nm-device-hsr.c
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2023 Red Hat, Inc.
+ */
+
+#include "libnm-client-impl/nm-default-libnm.h"
+
+#include "nm-device-hsr.h"
+
+#include "nm-setting-connection.h"
+#include "nm-setting-hsr.h"
+#include "nm-utils.h"
+#include "nm-object-private.h"
+
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_PORT1,
+                                  PROP_PORT2,
+                                  PROP_SUPERVISION_ADDRESS,
+                                  PROP_MULTICAST_SPEC,
+                                  PROP_PRP, );
+
+typedef struct {
+    char            *supervision_address;
+    NMLDBusPropertyO port1;
+    NMLDBusPropertyO port2;
+    guint8           multicast_spec;
+    bool             prp;
+} NMDeviceHsrPrivate;
+
+struct _NMDeviceHsr {
+    NMDevice           parent;
+    NMDeviceHsrPrivate _priv;
+};
+
+struct _NMDeviceHsrClass {
+    NMDeviceClass parent;
+};
+
+G_DEFINE_TYPE(NMDeviceHsr, nm_device_hsr, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_HSR_GET_PRIVATE(self) \
+    _NM_GET_PRIVATE(self, NMDeviceHsr, NM_IS_DEVICE_HSR, NMObject, NMDevice)
+
+/*****************************************************************************/
+
+/**
+ * nm_device_hsr_get_port1:
+ * @device: a #NMDeviceHsr
+ *
+ * Returns: (transfer none): the device's port1 device
+ *
+ * Since: 1.46
+ **/
+NMDevice *
+nm_device_hsr_get_port1(NMDeviceHsr *device)
+{
+    g_return_val_if_fail(NM_IS_DEVICE_HSR(device), NULL);
+
+    return nml_dbus_property_o_get_obj(&NM_DEVICE_HSR_GET_PRIVATE(device)->port1);
+}
+
+/**
+ * nm_device_hsr_get_port2:
+ * @device: a #NMDeviceHsr
+ *
+ * Returns: (transfer none): the device's port2 device
+ *
+ * Since: 1.46
+ **/
+NMDevice *
+nm_device_hsr_get_port2(NMDeviceHsr *device)
+{
+    g_return_val_if_fail(NM_IS_DEVICE_HSR(device), NULL);
+
+    return nml_dbus_property_o_get_obj(&NM_DEVICE_HSR_GET_PRIVATE(device)->port2);
+}
+
+/**
+ * nm_device_hsr_get_supervision_address:
+ * @device: a #NMDeviceHsr
+ *
+ * Returns: the supervision MAC adddress
+ *
+ * Since: 1.46
+ **/
+const char *
+nm_device_hsr_get_supervision_address(NMDeviceHsr *device)
+{
+    g_return_val_if_fail(NM_IS_DEVICE_HSR(device), NULL);
+
+    return NM_DEVICE_HSR_GET_PRIVATE(device)->supervision_address;
+}
+
+/**
+ * nm_device_hsr_get_multicast_spec:
+ * @device: a #NMDeviceHsr
+ *
+ * Returns: the last byte of the supervision address
+ *
+ * Since: 1.46
+ **/
+guint8
+nm_device_hsr_get_multicast_spec(NMDeviceHsr *device)
+{
+    g_return_val_if_fail(NM_IS_DEVICE_HSR(device), 0);
+
+    return NM_DEVICE_HSR_GET_PRIVATE(device)->multicast_spec;
+}
+
+/**
+ * nm_device_hsr_get_prp:
+ * @device: a #NMDeviceHsr
+ *
+ * Returns: whether PRP protocol is used or not
+ *
+ * Since: 1.46
+ **/
+gboolean
+nm_device_hsr_get_prp(NMDeviceHsr *device)
+{
+    g_return_val_if_fail(NM_IS_DEVICE_HSR(device), FALSE);
+
+    return NM_DEVICE_HSR_GET_PRIVATE(device)->prp;
+}
+
+/*****************************************************************************/
+
+static void
+nm_device_hsr_init(NMDeviceHsr *device)
+{}
+
+static void
+finalize(GObject *object)
+{
+    NMDeviceHsrPrivate *priv = NM_DEVICE_HSR_GET_PRIVATE(object);
+
+    g_free(priv->supervision_address);
+
+    G_OBJECT_CLASS(nm_device_hsr_parent_class)->finalize(object);
+}
+
+static void
+get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+    NMDeviceHsr *device = NM_DEVICE_HSR(object);
+
+    switch (prop_id) {
+    case PROP_PORT1:
+        g_value_set_object(value, nm_device_hsr_get_port1(device));
+        break;
+    case PROP_PORT2:
+        g_value_set_object(value, nm_device_hsr_get_port2(device));
+        break;
+    case PROP_SUPERVISION_ADDRESS:
+        g_value_set_string(value, nm_device_hsr_get_supervision_address(device));
+        break;
+    case PROP_MULTICAST_SPEC:
+        g_value_set_uchar(value, nm_device_hsr_get_multicast_spec(device));
+        break;
+    case PROP_PRP:
+        g_value_set_boolean(value, nm_device_hsr_get_prp(device));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_hsr = NML_DBUS_META_IFACE_INIT_PROP(
+    NM_DBUS_INTERFACE_DEVICE_HSR,
+    nm_device_hsr_get_type,
+    NML_DBUS_META_INTERFACE_PRIO_INSTANTIATE_30,
+    NML_DBUS_META_IFACE_DBUS_PROPERTIES(
+        NML_DBUS_META_PROPERTY_INIT_Y("MulticastSpec",
+                                      PROP_MULTICAST_SPEC,
+                                      NMDeviceHsr,
+                                      _priv.multicast_spec),
+        NML_DBUS_META_PROPERTY_INIT_O_PROP("Port1",
+                                           PROP_PORT1,
+                                           NMDeviceHsr,
+                                           _priv.port1,
+                                           nm_device_get_type),
+        NML_DBUS_META_PROPERTY_INIT_O_PROP("Port2",
+                                           PROP_PORT2,
+                                           NMDeviceHsr,
+                                           _priv.port2,
+                                           nm_device_get_type),
+        NML_DBUS_META_PROPERTY_INIT_B("Prp", PROP_PRP, NMDeviceHsr, _priv.prp),
+        NML_DBUS_META_PROPERTY_INIT_S("SupervisionAddress",
+                                      PROP_SUPERVISION_ADDRESS,
+                                      NMDeviceHsr,
+                                      _priv.supervision_address), ), );
+
+static void
+nm_device_hsr_class_init(NMDeviceHsrClass *klass)
+{
+    GObjectClass  *object_class    = G_OBJECT_CLASS(klass);
+    NMObjectClass *nm_object_class = NM_OBJECT_CLASS(klass);
+
+    object_class->get_property = get_property;
+    object_class->finalize     = finalize;
+
+    _NM_OBJECT_CLASS_INIT_PRIV_PTR_DIRECT(nm_object_class, NMDeviceHsr);
+
+    _NM_OBJECT_CLASS_INIT_PROPERTY_O_FIELDS_1(nm_object_class, NMDeviceHsrPrivate, port1);
+    _NM_OBJECT_CLASS_INIT_PROPERTY_O_FIELDS_1(nm_object_class, NMDeviceHsrPrivate, port2);
+
+    /**
+     * NMDeviceHsr:port1:
+     *
+     * The device's port1 device.
+     *
+     * Since: 1.46
+     **/
+    obj_properties[PROP_PORT1] = g_param_spec_object(NM_DEVICE_HSR_PORT1,
+                                                     "",
+                                                     "",
+                                                     NM_TYPE_DEVICE,
+                                                     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+    /**
+     * NMDeviceHsr:port2:
+     *
+     * The device's port2 device.
+     *
+     * Since: 1.46
+     **/
+    obj_properties[PROP_PORT2] = g_param_spec_object(NM_DEVICE_HSR_PORT2,
+                                                     "",
+                                                     "",
+                                                     NM_TYPE_DEVICE,
+                                                     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+    /**
+     * NMDeviceHsr:supervision-address:
+     *
+     * The device supervision MAC adddress.
+     *
+     * Since: 1.46
+     **/
+    obj_properties[PROP_SUPERVISION_ADDRESS] =
+        g_param_spec_string(NM_DEVICE_HSR_SUPERVISION_ADDRESS,
+                            "",
+                            "",
+                            FALSE,
+                            G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+    /**
+     * NMDeviceHsr:multicast-spec:
+     *
+     * The device last byte of the supervision address.
+     *
+     * Since: 1.46
+     **/
+    obj_properties[PROP_MULTICAST_SPEC] =
+        g_param_spec_uchar(NM_DEVICE_HSR_MULTICAST_SPEC,
+                           "",
+                           "",
+                           0,
+                           G_MAXUINT8,
+                           0,
+                           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+    /**
+     * NMDeviceHsr:prp:
+     *
+     * Whether the PRP protocol is used or not.
+     *
+     * Since: 1.46
+     **/
+    obj_properties[PROP_PRP] = g_param_spec_boolean(NM_DEVICE_HSR_PRP,
+                                                    "",
+                                                    "",
+                                                    FALSE,
+                                                    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+    _nml_dbus_meta_class_init_with_properties(object_class, &_nml_dbus_meta_iface_nm_device_hsr);
+}
diff --git a/src/libnm-client-impl/nm-device-ip-tunnel.c b/src/libnm-client-impl/nm-device-ip-tunnel.c
index c34ad84b..cba02c75 100644
--- a/src/libnm-client-impl/nm-device-ip-tunnel.c
+++ b/src/libnm-client-impl/nm-device-ip-tunnel.c
@@ -26,6 +26,7 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_MODE,
                                   PROP_OUTPUT_KEY,
                                   PROP_ENCAPSULATION_LIMIT,
                                   PROP_FLOW_LABEL,
+                                  PROP_FWMARK,
                                   PROP_FLAGS, );
 
 typedef struct {
@@ -37,6 +38,7 @@ typedef struct {
     guint32          mode;
     guint32          flow_label;
     guint32          flags;
+    guint32          fwmark;
     guint8           ttl;
     guint8           tos;
     guint8           encapsulation_limit;
@@ -237,6 +239,23 @@ nm_device_ip_tunnel_get_flow_label(NMDeviceIPTunnel *device)
 }
 
 /**
+ * nm_device_ip_tunnel_get_fwmark:
+ * @device: a #NMDeviceIPTunnel
+ *
+ * Returns: the fwmark assigned to tunnel packets. This property applies only
+ * to VTI tunnels.
+ *
+ * Since: 1.46
+ **/
+guint32
+nm_device_ip_tunnel_get_fwmark(NMDeviceIPTunnel *device)
+{
+    g_return_val_if_fail(NM_IS_DEVICE_IP_TUNNEL(device), 0);
+
+    return NM_DEVICE_IP_TUNNEL_GET_PRIVATE(device)->fwmark;
+}
+
+/**
  * nm_device_ip_tunnel_get_flags:
  * @device: a #NMDeviceIPTunnel
  *
@@ -334,6 +353,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
     case PROP_FLOW_LABEL:
         g_value_set_uint(value, nm_device_ip_tunnel_get_flow_label(device));
         break;
+    case PROP_FWMARK:
+        g_value_set_uint(value, nm_device_ip_tunnel_get_fwmark(device));
+        break;
     case PROP_FLAGS:
         g_value_set_uint(value, nm_device_ip_tunnel_get_flags(device));
         break;
@@ -357,6 +379,7 @@ const NMLDBusMetaIface _nml_dbus_meta_iface_nm_device_iptunnel = NML_DBUS_META_I
                                       PROP_FLOW_LABEL,
                                       NMDeviceIPTunnel,
                                       _priv.flow_label),
+        NML_DBUS_META_PROPERTY_INIT_U("FwMark", PROP_FWMARK, NMDeviceIPTunnel, _priv.fwmark),
         NML_DBUS_META_PROPERTY_INIT_S("InputKey",
                                       PROP_INPUT_KEY,
                                       NMDeviceIPTunnel,
@@ -559,6 +582,22 @@ nm_device_ip_tunnel_class_init(NMDeviceIPTunnelClass *klass)
                                                         G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
     /**
+     * NMDeviceIPTunnel:fwmark:
+     *
+     * The fwmark value to assign to tunnel packets. This property applies only
+     * to VTI tunnels.
+     *
+     * Since: 1.46
+     **/
+    obj_properties[PROP_FWMARK] = g_param_spec_uint(NM_DEVICE_IP_TUNNEL_FWMARK,
+                                                    "",
+                                                    "",
+                                                    0,
+                                                    G_MAXUINT32,
+                                                    0,
+                                                    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+    /**
      * NMDeviceIPTunnel:flags:
      *
      * Tunnel flags.
diff --git a/src/libnm-client-impl/nm-device.c b/src/libnm-client-impl/nm-device.c
index e3e6ca6e..2d3be64c 100644
--- a/src/libnm-client-impl/nm-device.c
+++ b/src/libnm-client-impl/nm-device.c
@@ -313,6 +313,7 @@ coerce_type(NMDeviceType type)
     case NM_DEVICE_TYPE_WIFI_P2P:
     case NM_DEVICE_TYPE_VRF:
     case NM_DEVICE_TYPE_LOOPBACK:
+    case NM_DEVICE_TYPE_HSR:
         return type;
     }
     return NM_DEVICE_TYPE_UNKNOWN;
@@ -1814,6 +1815,8 @@ get_type_name(NMDevice *device)
         return _("VRF");
     case NM_DEVICE_TYPE_LOOPBACK:
         return _("Loopback");
+    case NM_DEVICE_TYPE_HSR:
+        return _("HSR");
     case NM_DEVICE_TYPE_GENERIC:
     case NM_DEVICE_TYPE_UNUSED1:
     case NM_DEVICE_TYPE_UNUSED2:
diff --git a/src/libnm-client-impl/nm-dhcp4-config.h b/src/libnm-client-impl/nm-dhcp4-config.h
index ab400393..b3130f5d 100644
--- a/src/libnm-client-impl/nm-dhcp4-config.h
+++ b/src/libnm-client-impl/nm-dhcp4-config.h
@@ -6,7 +6,7 @@
 #ifndef __NM_DHCP4_CONFIG_H__
 #define __NM_DHCP4_CONFIG_H__
 
-#if !((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
+#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
 #error Cannot use this header.
 #endif
 
diff --git a/src/libnm-client-impl/nm-dhcp6-config.h b/src/libnm-client-impl/nm-dhcp6-config.h
index 49334275..e42e9826 100644
--- a/src/libnm-client-impl/nm-dhcp6-config.h
+++ b/src/libnm-client-impl/nm-dhcp6-config.h
@@ -6,7 +6,7 @@
 #ifndef __NM_DHCP6_CONFIG_H__
 #define __NM_DHCP6_CONFIG_H__
 
-#if !((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
+#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
 #error Cannot use this header.
 #endif
 
diff --git a/src/libnm-client-impl/nm-dns-manager.h b/src/libnm-client-impl/nm-dns-manager.h
index 20a5286e..cac922ad 100644
--- a/src/libnm-client-impl/nm-dns-manager.h
+++ b/src/libnm-client-impl/nm-dns-manager.h
@@ -6,7 +6,7 @@
 #ifndef __NM_DNS_MANAGER_H__
 #define __NM_DNS_MANAGER_H__
 
-#if !((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
+#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
 #error Cannot use this header.
 #endif
 
diff --git a/src/libnm-client-impl/nm-ip-config.c b/src/libnm-client-impl/nm-ip-config.c
index 9aa2e778..c054f2cc 100644
--- a/src/libnm-client-impl/nm-ip-config.c
+++ b/src/libnm-client-impl/nm-ip-config.c
@@ -190,7 +190,7 @@ next:
             if (arr && arr->len > 0)
                 nameservers_new = nm_strv_dup((char **) arr->pdata, arr->len, FALSE);
             else
-                nameservers_new = g_new0(char *, 1);
+                nameservers_new = nm_strv_empty_new();
         }
         nm_assert(nameservers_new);
     }
diff --git a/src/libnm-client-impl/nm-ip4-config.h b/src/libnm-client-impl/nm-ip4-config.h
index 3c4b128e..bfd21b64 100644
--- a/src/libnm-client-impl/nm-ip4-config.h
+++ b/src/libnm-client-impl/nm-ip4-config.h
@@ -7,7 +7,7 @@
 #ifndef __NM_IP4_CONFIG_H__
 #define __NM_IP4_CONFIG_H__
 
-#if !((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
+#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
 #error Cannot use this header.
 #endif
 
diff --git a/src/libnm-client-impl/nm-ip6-config.h b/src/libnm-client-impl/nm-ip6-config.h
index b44cd34b..7682004a 100644
--- a/src/libnm-client-impl/nm-ip6-config.h
+++ b/src/libnm-client-impl/nm-ip6-config.h
@@ -7,7 +7,7 @@
 #ifndef __NM_IP6_CONFIG_H__
 #define __NM_IP6_CONFIG_H__
 
-#if !((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
+#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
 #error Cannot use this header.
 #endif
 
diff --git a/src/libnm-client-impl/nm-libnm-utils.c b/src/libnm-client-impl/nm-libnm-utils.c
index 398c6ebc..9ebca216 100644
--- a/src/libnm-client-impl/nm-libnm-utils.c
+++ b/src/libnm-client-impl/nm-libnm-utils.c
@@ -30,8 +30,12 @@ _nml_dbus_log_level_init(void)
     const GDebugKey keys[] = {
         {"trace", _NML_DBUS_LOG_LEVEL_TRACE},
         {"debug", _NML_DBUS_LOG_LEVEL_DEBUG},
+        {"warn", _NML_DBUS_LOG_LEVEL_WARN},
         {"warning", _NML_DBUS_LOG_LEVEL_WARN},
         {"error", _NML_DBUS_LOG_LEVEL_ERROR},
+        {"WARN", _NML_DBUS_LOG_LEVEL_WARN | NML_DBUS_LOG_ASSERT},
+        {"WARNING", _NML_DBUS_LOG_LEVEL_WARN | NML_DBUS_LOG_ASSERT},
+        {"ERROR", _NML_DBUS_LOG_LEVEL_ERROR | NML_DBUS_LOG_ASSERT},
         {"stdout", NML_DBUS_LOG_STDOUT},
     };
     int l;
@@ -147,6 +151,12 @@ _nml_dbus_log(NMLDBusLogLevel level, gboolean use_stdout, const char *fmt, ...)
     gint64          ts;
     pid_t           pid;
 
+    nm_assert(NM_IN_SET(level,
+                        NML_DBUS_LOG_LEVEL_TRACE,
+                        NML_DBUS_LOG_LEVEL_DEBUG,
+                        NML_DBUS_LOG_LEVEL_WARN,
+                        NML_DBUS_LOG_LEVEL_ERROR));
+
     /* we only call _nml_dbus_log() after nml_dbus_log_enabled(), which already does
      * an atomic access to the variable. Since the value is only initialized once and
      * never changes, we can just access it without additional locking. */
@@ -167,21 +177,13 @@ _nml_dbus_log(NMLDBusLogLevel level, gboolean use_stdout, const char *fmt, ...)
         break;
     case NML_DBUS_LOG_LEVEL_WARN:
         prefix = "<warn > ";
-        if (NM_FLAGS_HAS(configured_log_level, _NML_DBUS_LOG_LEVEL_WARN)) {
+        if (NM_FLAGS_HAS(configured_log_level, NML_DBUS_LOG_ASSERT))
             g_warning("libnm-dbus: %s%s", prefix, msg);
-            return;
-        }
         break;
     case NML_DBUS_LOG_LEVEL_ERROR:
         prefix = "<error> ";
-        if (NM_FLAGS_HAS(configured_log_level, _NML_DBUS_LOG_LEVEL_ERROR)) {
+        if (NM_FLAGS_HAS(configured_log_level, NML_DBUS_LOG_ASSERT))
             g_critical("libnm-dbus: %s%s", prefix, msg);
-            return;
-        }
-        if (NM_FLAGS_HAS(configured_log_level, _NML_DBUS_LOG_LEVEL_WARN)) {
-            g_warning("libnm-dbus: %s%s", prefix, msg);
-            return;
-        }
         break;
     default:
         break;
@@ -299,7 +301,7 @@ _fixup_string(const char        *desc,
         if (eow)
             *eow = '\0';
 
-        if (nm_strv_find_first(ignored_words, -1, p) >= 0)
+        if (nm_strv_contains(ignored_words, -1, p))
             goto next;
 
         l = strlen(p);
@@ -987,10 +989,26 @@ nm_utils_g_param_spec_is_default(const GParamSpec *pspec)
  * with these functions (it implements additional buffering). By
  * using nm_utils_print(), the same logging mechanisms can be used.
  *
- * Also, libnm honors LIBNM_CLIENT_DEBUG_FILE environment. If this
- * is set to a filename pattern (accepting "%p" for the process ID),
- * then the debug log is written to that file instead. With @output_mode
- * zero, the same location will be written. Since: 1.44.
+ * LIBNM_CLIENT_DEBUG is a list of keywords separated by commas. The keyword
+ * "trace" enables printing messages of the lowest up to the highest severity.
+ * Likewise, the severities "debug", "warn" ("warning") and "error" are honored
+ * in similar way. Setting the flags "ERROR" or "WARN" ("WARNING") implies that
+ * respective levels are enabled, but also are ERROR messages printed with
+ * g_critical() and WARN messages with g_warning(). Together with G_DEBUG="fatal-warnings"
+ * or G_DEBUG="fatal-critical" this can be used to abort the program on errors.
+ * Note that all &lt;error&gt; messages imply an unexpected data on the D-Bus API
+ * (due to a bug). &lt;warn&gt; also implies unexepected data, but that can happen
+ * when using different versions of libnm and daemon. For testing, it is
+ * good to turn these into assertions.
+ *
+ * By default, messages are printed to stderr, unless LIBNM_CLIENT_DEBUG
+ * contains "stdout" flag. Also, libnm honors LIBNM_CLIENT_DEBUG_FILE
+ * environment. If this is set to a filename pattern (accepting "%%p" for the
+ * process ID), then the debug log is written to that file instead of
+ * stderr/stdout. With @output_mode zero, the same location will be written.
+ *
+ * LIBNM_CLIENT_DEBUG_FILE is supported since 1.44. "ERROR", "WARN" and "WARNING"
+ * are supported since 1.46.
  *
  * Since: 1.30
  */
diff --git a/src/libnm-client-impl/nm-libnm-utils.h b/src/libnm-client-impl/nm-libnm-utils.h
index 5b9883ef..d56d0fc1 100644
--- a/src/libnm-client-impl/nm-libnm-utils.h
+++ b/src/libnm-client-impl/nm-libnm-utils.h
@@ -26,31 +26,35 @@ typedef enum {
 
     _NML_DBUS_LOG_LEVEL_INITIALIZED = 0x01,
 
-    _NML_DBUS_LOG_LEVEL_TRACE = 0x02,
+    NML_DBUS_LOG_LEVEL_TRACE = 0x02,
 
-    _NML_DBUS_LOG_LEVEL_DEBUG = 0x04,
+    NML_DBUS_LOG_LEVEL_DEBUG = 0x04,
 
     /* the difference between a warning and a critical is that it results in
-     * g_warning() vs. g_critical() messages. Note that we want to use "warnings"
-     * for unknown D-Bus API that could just result because we run against a
-     * newer NetworkManager version (such warnings are more graceful, because
-     * we want that libnm can be forward compatible against newer servers).
-     * Critical warnings should be emitted when NetworkManager exposes something
-     * on D-Bus that breaks the current expectations. Usually NetworkManager
-     * should not break API, hence such issues are more severe. */
-    _NML_DBUS_LOG_LEVEL_WARN  = 0x08,
-    _NML_DBUS_LOG_LEVEL_ERROR = 0x10,
+     * g_warning() vs. g_critical() messages (with NML_DBUS_LOG_ASSERT). Note
+     * that we want to use "warnings" for unknown D-Bus API that could just
+     * result because we run against a newer NetworkManager version (such
+     * warnings are more graceful, because we want that libnm can be forward
+     * compatible against newer servers).  Critical warnings should be emitted
+     * when NetworkManager exposes something on D-Bus that breaks the current
+     * expectations. Usually NetworkManager should not break API, hence such
+     * issues are more severe. */
+    NML_DBUS_LOG_LEVEL_WARN  = 0x08,
+    NML_DBUS_LOG_LEVEL_ERROR = 0x10,
 
     /* ANY is only relevant for nml_dbus_log_enabled() to check whether any of the
      * options is on. */
     NML_DBUS_LOG_LEVEL_ANY = _NML_DBUS_LOG_LEVEL_INITIALIZED,
 
-    NML_DBUS_LOG_LEVEL_TRACE = _NML_DBUS_LOG_LEVEL_TRACE,
-    NML_DBUS_LOG_LEVEL_DEBUG = _NML_DBUS_LOG_LEVEL_DEBUG | NML_DBUS_LOG_LEVEL_TRACE,
-    NML_DBUS_LOG_LEVEL_WARN  = _NML_DBUS_LOG_LEVEL_WARN | NML_DBUS_LOG_LEVEL_DEBUG,
-    NML_DBUS_LOG_LEVEL_ERROR = _NML_DBUS_LOG_LEVEL_ERROR | NML_DBUS_LOG_LEVEL_WARN,
-
     NML_DBUS_LOG_STDOUT = 0x20,
+
+    NML_DBUS_LOG_ASSERT = 0x40,
+
+    _NML_DBUS_LOG_LEVEL_ERROR = NML_DBUS_LOG_LEVEL_ERROR,
+    _NML_DBUS_LOG_LEVEL_WARN  = NML_DBUS_LOG_LEVEL_WARN | _NML_DBUS_LOG_LEVEL_ERROR,
+    _NML_DBUS_LOG_LEVEL_DEBUG = NML_DBUS_LOG_LEVEL_DEBUG | _NML_DBUS_LOG_LEVEL_WARN,
+    _NML_DBUS_LOG_LEVEL_TRACE = NML_DBUS_LOG_LEVEL_TRACE | _NML_DBUS_LOG_LEVEL_DEBUG,
+
 } NMLDBusLogLevel;
 
 #undef _LOGL_TRACE
@@ -61,7 +65,6 @@ typedef enum {
 
 #define _LOGL_TRACE NML_DBUS_LOG_LEVEL_TRACE
 #define _LOGL_DEBUG NML_DBUS_LOG_LEVEL_DEBUG
-#define _LOGL_INFO  NML_DBUS_LOG_LEVEL_INFO
 #define _LOGL_WARN  NML_DBUS_LOG_LEVEL_WARN
 #define _LOGL_ERR   NML_DBUS_LOG_LEVEL_ERR
 
@@ -87,9 +90,14 @@ nml_dbus_log_enabled_full(NMLDBusLogLevel level, gboolean *out_use_stdout)
         l = _nml_dbus_log_level_init();
 
     nm_assert(l & _NML_DBUS_LOG_LEVEL_INITIALIZED);
+
     NM_SET_OUT(out_use_stdout, NM_FLAGS_HAS(l, NML_DBUS_LOG_STDOUT));
-    if (level == NML_DBUS_LOG_LEVEL_ANY)
-        return l != _NML_DBUS_LOG_LEVEL_INITIALIZED;
+
+    if (level == NML_DBUS_LOG_LEVEL_ANY) {
+        return NM_FLAGS_ANY(l,
+                            NML_DBUS_LOG_LEVEL_TRACE | NML_DBUS_LOG_LEVEL_DEBUG
+                                | NML_DBUS_LOG_LEVEL_WARN | NML_DBUS_LOG_LEVEL_ERROR);
+    }
     return !!(((NMLDBusLogLevel) l) & level);
 }
 
diff --git a/src/libnm-client-impl/nm-object-private.h b/src/libnm-client-impl/nm-object-private.h
index 11afc639..34dad188 100644
--- a/src/libnm-client-impl/nm-object-private.h
+++ b/src/libnm-client-impl/nm-object-private.h
@@ -6,7 +6,7 @@
 #ifndef __NM_OBJECT_PRIVATE_H__
 #define __NM_OBJECT_PRIVATE_H__
 
-#if !((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
+#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
 #error Cannot use this header.
 #endif
 
diff --git a/src/libnm-client-impl/nm-remote-connection-private.h b/src/libnm-client-impl/nm-remote-connection-private.h
index f0869347..a0493bfc 100644
--- a/src/libnm-client-impl/nm-remote-connection-private.h
+++ b/src/libnm-client-impl/nm-remote-connection-private.h
@@ -6,7 +6,7 @@
 #ifndef __NM_REMOTE_CONNECTION_PRIVATE_H__
 #define __NM_REMOTE_CONNECTION_PRIVATE_H__
 
-#if !((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
+#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE)
 #error Cannot use this header.
 #endif
 
diff --git a/src/libnm-client-impl/tests/test-gir.py b/src/libnm-client-impl/tests/test-gir.py
index 9b42431c..554080fa 100755
--- a/src/libnm-client-impl/tests/test-gir.py
+++ b/src/libnm-client-impl/tests/test-gir.py
@@ -118,7 +118,7 @@ ver_syms = syms_from_ver(args.ver)
 
 exit_code = 0
 
-for (gir_sym, gir_ver) in gir_syms.items():
+for gir_sym, gir_ver in gir_syms.items():
     if gir_sym not in ver_syms:
         exit_code = 1
         print(
diff --git a/src/libnm-client-impl/tests/test-libnm.c b/src/libnm-client-impl/tests/test-libnm.c
index 456f1855..59774f96 100644
--- a/src/libnm-client-impl/tests/test-libnm.c
+++ b/src/libnm-client-impl/tests/test-libnm.c
@@ -3188,6 +3188,10 @@ check_dbus_properties:
                            && nm_streq(pspec->name, NM_DEVICE_WIREGUARD_FWMARK)) {
                     g_assert_cmpstr(obj_property_name, ==, "fw-mark");
                     expected_property_name = NM_DEVICE_WIREGUARD_FWMARK;
+                } else if (mif == &_nml_dbus_meta_iface_nm_device_iptunnel
+                           && nm_streq(pspec->name, NM_DEVICE_IP_TUNNEL_FWMARK)) {
+                    g_assert_cmpstr(obj_property_name, ==, "fw-mark");
+                    expected_property_name = NM_DEVICE_IP_TUNNEL_FWMARK;
                 } else if (NM_IN_SET(mif,
                                      &_nml_dbus_meta_iface_nm_ip4config,
                                      &_nml_dbus_meta_iface_nm_ip6config)