summary refs log tree commit diff
path: root/src/libnm-glib-aux
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2022-01-13 22:30:39 +0100
committerMichael Biebl <biebl@debian.org>2022-01-13 22:30:39 +0100
commit88c227d90a6b7b388c5c85d72802a0ca8f05ed5c (patch)
tree71f32df6617802270e8a78574bd8e1637dc532f4 /src/libnm-glib-aux
parente74c568b07b50b97873fb4ee1d776dedefbd54d6 (diff)
New upstream version 1.34.0 upstream/1.34.0
Diffstat (limited to 'src/libnm-glib-aux')
-rw-r--r--src/libnm-glib-aux/nm-dbus-aux.c87
-rw-r--r--src/libnm-glib-aux/nm-dbus-aux.h49
-rw-r--r--src/libnm-glib-aux/nm-default-glib.h24
-rw-r--r--src/libnm-glib-aux/nm-gassert-patch.h68
-rw-r--r--src/libnm-glib-aux/nm-glib.h352
-rw-r--r--src/libnm-glib-aux/nm-hash-utils.c6
-rw-r--r--src/libnm-glib-aux/nm-hash-utils.h158
-rw-r--r--src/libnm-glib-aux/nm-io-utils.c99
-rw-r--r--src/libnm-glib-aux/nm-io-utils.h17
-rw-r--r--src/libnm-glib-aux/nm-jansson.h24
-rw-r--r--src/libnm-glib-aux/nm-json-aux.c4
-rw-r--r--src/libnm-glib-aux/nm-json-aux.h61
-rw-r--r--src/libnm-glib-aux/nm-logging-base.c60
-rw-r--r--src/libnm-glib-aux/nm-logging-base.h16
-rw-r--r--src/libnm-glib-aux/nm-logging-fwd.h126
-rw-r--r--src/libnm-glib-aux/nm-macros-internal.h602
-rw-r--r--src/libnm-glib-aux/nm-random-utils.c14
-rw-r--r--src/libnm-glib-aux/nm-ref-string.h12
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.c359
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.h532
-rw-r--r--src/libnm-glib-aux/nm-test-utils.h584
-rw-r--r--src/libnm-glib-aux/nm-uuid.c69
-rw-r--r--src/libnm-glib-aux/nm-uuid.h51
-rw-r--r--src/libnm-glib-aux/nm-value-type.h134
-rw-r--r--src/libnm-glib-aux/tests/test-shared-general.c47
25 files changed, 2089 insertions, 1466 deletions
diff --git a/src/libnm-glib-aux/nm-dbus-aux.c b/src/libnm-glib-aux/nm-dbus-aux.c
index f4f53a7d..454bd2d8 100644
--- a/src/libnm-glib-aux/nm-dbus-aux.c
+++ b/src/libnm-glib-aux/nm-dbus-aux.c
@@ -403,3 +403,90 @@ _nm_dbus_error_is(GError *error, ...)
 
     return FALSE;
 }
+
+/*****************************************************************************/
+
+typedef struct {
+    GDBusConnection **p_dbus_connection;
+    GError **         p_error;
+} BusGetData;
+
+static void
+_bus_get_cb(GObject *source, GAsyncResult *result, gpointer user_data)
+{
+    BusGetData *data = user_data;
+
+    *data->p_dbus_connection = g_bus_get_finish(result, data->p_error);
+}
+
+/**
+ * nm_g_bus_get_blocking:
+ * @cancellable: (allow-none): a #GCancellable to abort the operation.
+ * @error: (allow-none): the error.
+ *
+ * This calls g_bus_get(), but iterates the current (thread-default) GMainContext
+ * until the response is ready. As such, it's similar to g_bus_get_sync(),
+ * but it allows to cancel the operation (without having multiple threads).
+ *
+ * Returns: (transfer full): the new #GDBusConnection or %NULL on error.
+ */
+GDBusConnection *
+nm_g_bus_get_blocking(GCancellable *cancellable, GError **error)
+{
+    gs_free_error GError *local_error                = NULL;
+    gs_unref_object GDBusConnection *dbus_connection = NULL;
+    GMainContext *                   main_context    = g_main_context_get_thread_default();
+    BusGetData                       data            = {
+        .p_dbus_connection = &dbus_connection,
+        .p_error           = &local_error,
+    };
+
+    g_bus_get(G_BUS_TYPE_SYSTEM, cancellable, _bus_get_cb, &data);
+
+    while (!dbus_connection && !local_error)
+        g_main_context_iteration(main_context, TRUE);
+
+    if (!dbus_connection) {
+        g_propagate_error(error, g_steal_pointer(&local_error));
+        return NULL;
+    }
+
+    return g_steal_pointer(&dbus_connection);
+}
+
+/*****************************************************************************/
+
+void
+nm_dbus_connection_call_blocking_callback(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+    NMDBusConnectionCallBlockingData *data = user_data;
+
+    nm_assert(data);
+    nm_assert(!data->result);
+    nm_assert(!data->error);
+
+    data->result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &data->error);
+}
+
+GVariant *
+nm_dbus_connection_call_blocking(NMDBusConnectionCallBlockingData *data, GError **error)
+{
+    GMainContext *main_context        = g_main_context_get_thread_default();
+    gs_free_error GError *local_error = NULL;
+    gs_unref_variant GVariant *result = NULL;
+
+    nm_assert(data);
+
+    while (!data->result && !data->error)
+        g_main_context_iteration(main_context, TRUE);
+
+    local_error = g_steal_pointer(&data->error);
+    result      = g_steal_pointer(&data->result);
+
+    if (!result) {
+        g_propagate_error(error, g_steal_pointer(&local_error));
+        return NULL;
+    }
+
+    return g_steal_pointer(&result);
+}
diff --git a/src/libnm-glib-aux/nm-dbus-aux.h b/src/libnm-glib-aux/nm-dbus-aux.h
index 65a91311..420a0c55 100644
--- a/src/libnm-glib-aux/nm-dbus-aux.h
+++ b/src/libnm-glib-aux/nm-dbus-aux.h
@@ -84,6 +84,29 @@ void nm_dbus_connection_call_get_name_owner(GDBusConnection *                  d
                                             NMDBusConnectionCallGetNameOwnerCb callback,
                                             gpointer                           user_data);
 
+static inline void
+nm_dbus_connection_call_request_name(GDBusConnection *   dbus_connection,
+                                     const char *        name,
+                                     guint32             flags,
+                                     int                 timeout_msec,
+                                     GCancellable *      cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer            user_data)
+{
+    g_dbus_connection_call(dbus_connection,
+                           DBUS_SERVICE_DBUS,
+                           DBUS_PATH_DBUS,
+                           DBUS_INTERFACE_DBUS,
+                           "RequestName",
+                           g_variant_new("(su)", name, flags),
+                           G_VARIANT_TYPE("(u)"),
+                           G_DBUS_CALL_FLAGS_NONE,
+                           timeout_msec,
+                           cancellable,
+                           callback,
+                           user_data);
+}
+
 static inline guint
 nm_dbus_connection_signal_subscribe_properties_changed(GDBusConnection *   dbus_connection,
                                                        const char *        bus_name,
@@ -215,4 +238,30 @@ gboolean _nm_dbus_error_is(GError *error, ...) G_GNUC_NULL_TERMINATED;
 
 /*****************************************************************************/
 
+GDBusConnection *nm_g_bus_get_blocking(GCancellable *cancellable, GError **error);
+
+/*****************************************************************************/
+
+typedef struct {
+    GVariant *result;
+    GError *  error;
+} NMDBusConnectionCallBlockingData;
+
+void
+nm_dbus_connection_call_blocking_callback(GObject *source, GAsyncResult *res, gpointer user_data);
+
+GVariant *nm_dbus_connection_call_blocking(NMDBusConnectionCallBlockingData *data, GError **error);
+
+/*****************************************************************************/
+
+static inline gboolean
+nm_g_variant_tuple_get_u(GVariant *v, guint32 *out_u)
+{
+    if (g_variant_is_of_type(v, G_VARIANT_TYPE("(u)"))) {
+        g_variant_get(v, "(u)", out_u);
+        return TRUE;
+    }
+    return FALSE;
+}
+
 #endif /* __NM_DBUS_AUX_H__ */
diff --git a/src/libnm-glib-aux/nm-default-glib.h b/src/libnm-glib-aux/nm-default-glib.h
index e5ccd47f..9d04ddc4 100644
--- a/src/libnm-glib-aux/nm-default-glib.h
+++ b/src/libnm-glib-aux/nm-default-glib.h
@@ -18,21 +18,21 @@
 #include <glib.h>
 
 #if defined(_NETWORKMANAGER_COMPILATION_GLIB_I18N_PROG)
-    #if defined(_NETWORKMANAGER_COMPILATION_GLIB_I18N_LIB)
-        #error Cannot define _NETWORKMANAGER_COMPILATION_GLIB_I18N_LIB and _NETWORKMANAGER_COMPILATION_GLIB_I18N_PROG together
-    #endif
-    #undef _NETWORKMANAGER_COMPILATION_GLIB_I18N_PROG
-    #include <glib/gi18n.h>
+#if defined(_NETWORKMANAGER_COMPILATION_GLIB_I18N_LIB)
+#error Cannot define _NETWORKMANAGER_COMPILATION_GLIB_I18N_LIB and _NETWORKMANAGER_COMPILATION_GLIB_I18N_PROG together
+#endif
+#undef _NETWORKMANAGER_COMPILATION_GLIB_I18N_PROG
+#include <glib/gi18n.h>
 #elif defined(_NETWORKMANAGER_COMPILATION_GLIB_I18N_LIB)
-    #undef _NETWORKMANAGER_COMPILATION_GLIB_I18N_LIB
-    #include <glib/gi18n-lib.h>
+#undef _NETWORKMANAGER_COMPILATION_GLIB_I18N_LIB
+#include <glib/gi18n-lib.h>
 #endif
 
 /*****************************************************************************/
 
 #if NM_MORE_ASSERTS == 0
-    #ifndef G_DISABLE_CAST_CHECKS
-        /* Unless compiling with G_DISABLE_CAST_CHECKS, glib performs type checking
+#ifndef G_DISABLE_CAST_CHECKS
+/* Unless compiling with G_DISABLE_CAST_CHECKS, glib performs type checking
          * during G_VARIANT_TYPE() via g_variant_type_checked_(). This is not necessary
          * because commonly this cast is needed during something like
          *
@@ -54,9 +54,9 @@
          *
          * Just patch G_VARIANT_TYPE() to perform no check.
          */
-        #undef G_VARIANT_TYPE
-        #define G_VARIANT_TYPE(type_string) ((const GVariantType *) (type_string))
-    #endif
+#undef G_VARIANT_TYPE
+#define G_VARIANT_TYPE(type_string) ((const GVariantType *) (type_string))
+#endif
 #endif
 
 /*****************************************************************************/
diff --git a/src/libnm-glib-aux/nm-gassert-patch.h b/src/libnm-glib-aux/nm-gassert-patch.h
index bac8697c..e4ea23e4 100644
--- a/src/libnm-glib-aux/nm-gassert-patch.h
+++ b/src/libnm-glib-aux/nm-gassert-patch.h
@@ -25,50 +25,50 @@ _nm_g_return_if_fail_warning(const char *log_domain, const char *file, int line)
     g_return_if_fail_warning(log_domain, file_buf, "<dropped>");
 }
 
-    #define g_return_if_fail_warning(log_domain, pretty_function, expression) \
-        _nm_g_return_if_fail_warning(log_domain, __FILE__, __LINE__)
+#define g_return_if_fail_warning(log_domain, pretty_function, expression) \
+    _nm_g_return_if_fail_warning(log_domain, __FILE__, __LINE__)
 
-    #define g_assertion_message_expr(domain, file, line, func, expr) \
-        g_assertion_message_expr(domain, file, line, "<unknown-fcn>", (expr) ? "<dropped>" : NULL)
+#define g_assertion_message_expr(domain, file, line, func, expr) \
+    g_assertion_message_expr(domain, file, line, "<unknown-fcn>", (expr) ? "<dropped>" : NULL)
 
-    #undef g_return_val_if_reached
-    #define g_return_val_if_reached(val)                          \
-        G_STMT_START                                              \
-        {                                                         \
-            g_log(G_LOG_DOMAIN,                                   \
-                  G_LOG_LEVEL_CRITICAL,                           \
-                  "file %s: line %d (%s): should not be reached", \
-                  __FILE__,                                       \
-                  __LINE__,                                       \
-                  "<dropped>");                                   \
-            return (val);                                         \
-        }                                                         \
-        G_STMT_END
+#undef g_return_val_if_reached
+#define g_return_val_if_reached(val)                          \
+    G_STMT_START                                              \
+    {                                                         \
+        g_log(G_LOG_DOMAIN,                                   \
+              G_LOG_LEVEL_CRITICAL,                           \
+              "file %s: line %d (%s): should not be reached", \
+              __FILE__,                                       \
+              __LINE__,                                       \
+              "<dropped>");                                   \
+        return (val);                                         \
+    }                                                         \
+    G_STMT_END
 
-    #undef g_return_if_reached
-    #define g_return_if_reached()                                 \
-        G_STMT_START                                              \
-        {                                                         \
-            g_log(G_LOG_DOMAIN,                                   \
-                  G_LOG_LEVEL_CRITICAL,                           \
-                  "file %s: line %d (%s): should not be reached", \
-                  __FILE__,                                       \
-                  __LINE__,                                       \
-                  "<dropped>");                                   \
-            return;                                               \
-        }                                                         \
-        G_STMT_END
+#undef g_return_if_reached
+#define g_return_if_reached()                                 \
+    G_STMT_START                                              \
+    {                                                         \
+        g_log(G_LOG_DOMAIN,                                   \
+              G_LOG_LEVEL_CRITICAL,                           \
+              "file %s: line %d (%s): should not be reached", \
+              __FILE__,                                       \
+              __LINE__,                                       \
+              "<dropped>");                                   \
+        return;                                               \
+    }                                                         \
+    G_STMT_END
 #endif
 
 /*****************************************************************************/
 
 #if NM_MORE_ASSERTS == 0
-    #define NM_ASSERT_G_RETURN_EXPR(expr) "<dropped>"
-    #define NM_ASSERT_NO_MSG              1
+#define NM_ASSERT_G_RETURN_EXPR(expr) "<dropped>"
+#define NM_ASSERT_NO_MSG              1
 
 #else
-    #define NM_ASSERT_G_RETURN_EXPR(expr) "" expr ""
-    #define NM_ASSERT_NO_MSG              0
+#define NM_ASSERT_G_RETURN_EXPR(expr) "" expr ""
+#define NM_ASSERT_NO_MSG              0
 #endif
 
 /*****************************************************************************/
diff --git a/src/libnm-glib-aux/nm-glib.h b/src/libnm-glib-aux/nm-glib.h
index 66e5c16e..49470d92 100644
--- a/src/libnm-glib-aux/nm-glib.h
+++ b/src/libnm-glib-aux/nm-glib.h
@@ -9,21 +9,21 @@
 /*****************************************************************************/
 
 #ifndef __NM_MACROS_INTERNAL_H__
-    #error "nm-glib.h requires nm-macros-internal.h. Do not include this directly"
+#error "nm-glib.h requires nm-macros-internal.h. Do not include this directly"
 #endif
 
 /*****************************************************************************/
 
 #ifdef __clang__
 
-    #undef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-    #undef G_GNUC_END_IGNORE_DEPRECATIONS
+#undef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+#undef G_GNUC_END_IGNORE_DEPRECATIONS
 
-    #define G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
-        _Pragma("clang diagnostic push")     \
-            _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
+#define G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
+    _Pragma("clang diagnostic push")     \
+        _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
 
-    #define G_GNUC_END_IGNORE_DEPRECATIONS _Pragma("clang diagnostic pop")
+#define G_GNUC_END_IGNORE_DEPRECATIONS _Pragma("clang diagnostic pop")
 
 #endif
 
@@ -47,23 +47,23 @@ __g_type_ensure(GType type)
 
 #if !GLIB_CHECK_VERSION(2, 34, 0)
 
-    #define g_clear_pointer(pp, destroy)                           \
-        G_STMT_START                                               \
-        {                                                          \
-            G_STATIC_ASSERT(sizeof *(pp) == sizeof(gpointer));     \
-            /* Only one access, please */                          \
-            gpointer *_pp = (gpointer *) (pp);                     \
-            gpointer  _p;                                          \
-            /* This assignment is needed to avoid a gcc warning */ \
-            GDestroyNotify _destroy = (GDestroyNotify) (destroy);  \
-                                                                   \
-            _p = *_pp;                                             \
-            if (_p) {                                              \
-                *_pp = NULL;                                       \
-                _destroy(_p);                                      \
-            }                                                      \
-        }                                                          \
-        G_STMT_END
+#define g_clear_pointer(pp, destroy)                           \
+    G_STMT_START                                               \
+    {                                                          \
+        G_STATIC_ASSERT(sizeof *(pp) == sizeof(gpointer));     \
+        /* Only one access, please */                          \
+        gpointer *_pp = (gpointer *) (pp);                     \
+        gpointer  _p;                                          \
+        /* This assignment is needed to avoid a gcc warning */ \
+        GDestroyNotify _destroy = (GDestroyNotify) (destroy);  \
+                                                               \
+        _p = *_pp;                                             \
+        if (_p) {                                              \
+            *_pp = NULL;                                       \
+            _destroy(_p);                                      \
+        }                                                      \
+    }                                                          \
+    G_STMT_END
 
 #endif
 
@@ -71,94 +71,94 @@ __g_type_ensure(GType type)
 
 #if !GLIB_CHECK_VERSION(2, 34, 0)
 
-    /* These are used to clean up the output of test programs; we can just let
+/* These are used to clean up the output of test programs; we can just let
  * them no-op in older glib.
  */
-    #define g_test_expect_message(log_domain, log_level, pattern)
-    #define g_test_assert_expected_messages()
+#define g_test_expect_message(log_domain, log_level, pattern)
+#define g_test_assert_expected_messages()
 
 #else
 
-    /* We build with -DGLIB_MAX_ALLOWED_VERSION set to 2.32 to make sure we don't
+/* We build with -DGLIB_MAX_ALLOWED_VERSION set to 2.32 to make sure we don't
  * accidentally use new API that we shouldn't. But we don't want warnings for
  * the APIs that we emulate above.
  */
 
-    #define g_test_expect_message(domain, level, format...) \
-        G_STMT_START                                        \
-        {                                                   \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS                \
-            g_test_expect_message(domain, level, format);   \
-            G_GNUC_END_IGNORE_DEPRECATIONS                  \
-        }                                                   \
-        G_STMT_END
-
-    #define g_test_assert_expected_messages_internal(domain, file, line, func)  \
-        G_STMT_START                                                            \
-        {                                                                       \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                    \
-            g_test_assert_expected_messages_internal(domain, file, line, func); \
-            G_GNUC_END_IGNORE_DEPRECATIONS                                      \
-        }                                                                       \
-        G_STMT_END
+#define g_test_expect_message(domain, level, format...) \
+    G_STMT_START                                        \
+    {                                                   \
+        G_GNUC_BEGIN_IGNORE_DEPRECATIONS                \
+        g_test_expect_message(domain, level, format);   \
+        G_GNUC_END_IGNORE_DEPRECATIONS                  \
+    }                                                   \
+    G_STMT_END
+
+#define g_test_assert_expected_messages_internal(domain, file, line, func)  \
+    G_STMT_START                                                            \
+    {                                                                       \
+        G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                    \
+        g_test_assert_expected_messages_internal(domain, file, line, func); \
+        G_GNUC_END_IGNORE_DEPRECATIONS                                      \
+    }                                                                       \
+    G_STMT_END
 
 #endif
 
 /*****************************************************************************/
 
 #if GLIB_CHECK_VERSION(2, 35, 0)
-    /* For glib >= 2.36, g_type_init() is deprecated.
+/* For glib >= 2.36, g_type_init() is deprecated.
  * But since 2.35.1 (7c42ab23b55c43ab96d0ac2124b550bf1f49c1ec) this function
  * does nothing. Replace the call with empty statement. */
-    #define nm_g_type_init() \
-        G_STMT_START         \
-        {                    \
-            (void) 0;        \
-        }                    \
-        G_STMT_END
+#define nm_g_type_init() \
+    G_STMT_START         \
+    {                    \
+        (void) 0;        \
+    }                    \
+    G_STMT_END
 #else
-    #define nm_g_type_init() \
-        G_STMT_START         \
-        {                    \
-            g_type_init();   \
-        }                    \
-        G_STMT_END
+#define nm_g_type_init() \
+    G_STMT_START         \
+    {                    \
+        g_type_init();   \
+    }                    \
+    G_STMT_END
 #endif
 
 /*****************************************************************************/
 
 /* g_test_initialized() is only available since glib 2.36. */
 #if !GLIB_CHECK_VERSION(2, 36, 0)
-    #define g_test_initialized() (g_test_config_vars->test_initialized)
+#define g_test_initialized() (g_test_config_vars->test_initialized)
 #endif
 
 /*****************************************************************************/
 
 /* g_assert_cmpmem() is only available since glib 2.46. */
 #if !GLIB_CHECK_VERSION(2, 45, 7)
-    #define g_assert_cmpmem(m1, l1, m2, l2)                                                 \
-        G_STMT_START                                                                        \
-        {                                                                                   \
-            gconstpointer __m1 = m1, __m2 = m2;                                             \
-            int           __l1 = l1, __l2 = l2;                                             \
-            if (__l1 != __l2)                                                               \
-                g_assertion_message_cmpnum(G_LOG_DOMAIN,                                    \
-                                           __FILE__,                                        \
-                                           __LINE__,                                        \
-                                           G_STRFUNC,                                       \
-                                           #l1 " (len(" #m1 ")) == " #l2 " (len(" #m2 "))", \
-                                           __l1,                                            \
-                                           "==",                                            \
-                                           __l2,                                            \
-                                           'i');                                            \
-            else if (memcmp(__m1, __m2, __l1) != 0)                                         \
-                g_assertion_message(G_LOG_DOMAIN,                                           \
-                                    __FILE__,                                               \
-                                    __LINE__,                                               \
-                                    G_STRFUNC,                                              \
-                                    "assertion failed (" #m1 " == " #m2 ")");               \
-        }                                                                                   \
-        G_STMT_END
+#define g_assert_cmpmem(m1, l1, m2, l2)                                                 \
+    G_STMT_START                                                                        \
+    {                                                                                   \
+        gconstpointer __m1 = m1, __m2 = m2;                                             \
+        int           __l1 = l1, __l2 = l2;                                             \
+        if (__l1 != __l2)                                                               \
+            g_assertion_message_cmpnum(G_LOG_DOMAIN,                                    \
+                                       __FILE__,                                        \
+                                       __LINE__,                                        \
+                                       G_STRFUNC,                                       \
+                                       #l1 " (len(" #m1 ")) == " #l2 " (len(" #m2 "))", \
+                                       __l1,                                            \
+                                       "==",                                            \
+                                       __l2,                                            \
+                                       'i');                                            \
+        else if (memcmp(__m1, __m2, __l1) != 0)                                         \
+            g_assertion_message(G_LOG_DOMAIN,                                           \
+                                __FILE__,                                               \
+                                __LINE__,                                               \
+                                G_STRFUNC,                                              \
+                                "assertion failed (" #m1 " == " #m2 ")");               \
+    }                                                                                   \
+    G_STMT_END
 #endif
 
 /*****************************************************************************/
@@ -288,21 +288,21 @@ _nm_g_ptr_array_insert(GPtrArray *array, int index_, gpointer data)
 #endif
 
 #if !GLIB_CHECK_VERSION(2, 40, 0)
-    #define g_ptr_array_insert(array, index, data)      \
-        G_STMT_START                                    \
-        {                                               \
-            _nm_g_ptr_array_insert(array, index, data); \
-        }                                               \
-        G_STMT_END
+#define g_ptr_array_insert(array, index, data)      \
+    G_STMT_START                                    \
+    {                                               \
+        _nm_g_ptr_array_insert(array, index, data); \
+    }                                               \
+    G_STMT_END
 #else
-    #define g_ptr_array_insert(array, index, data)  \
-        G_STMT_START                                \
-        {                                           \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS        \
-            g_ptr_array_insert(array, index, data); \
-            G_GNUC_END_IGNORE_DEPRECATIONS          \
-        }                                           \
-        G_STMT_END
+#define g_ptr_array_insert(array, index, data)  \
+    G_STMT_START                                \
+    {                                           \
+        G_GNUC_BEGIN_IGNORE_DEPRECATIONS        \
+        g_ptr_array_insert(array, index, data); \
+        G_GNUC_END_IGNORE_DEPRECATIONS          \
+    }                                           \
+    G_STMT_END
 #endif
 
 /*****************************************************************************/
@@ -327,37 +327,37 @@ _g_key_file_save_to_file(GKeyFile *key_file, const char *filename, GError **erro
 
     return success;
 }
-    #define g_key_file_save_to_file(key_file, filename, error) \
-        _g_key_file_save_to_file(key_file, filename, error)
+#define g_key_file_save_to_file(key_file, filename, error) \
+    _g_key_file_save_to_file(key_file, filename, error)
 #else
-    #define g_key_file_save_to_file(key_file, filename, error)             \
-        ({                                                                 \
-            gboolean _success;                                             \
-                                                                           \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS                               \
-            _success = g_key_file_save_to_file(key_file, filename, error); \
-            G_GNUC_END_IGNORE_DEPRECATIONS                                 \
-            _success;                                                      \
-        })
+#define g_key_file_save_to_file(key_file, filename, error)             \
+    ({                                                                 \
+        gboolean _success;                                             \
+                                                                       \
+        G_GNUC_BEGIN_IGNORE_DEPRECATIONS                               \
+        _success = g_key_file_save_to_file(key_file, filename, error); \
+        G_GNUC_END_IGNORE_DEPRECATIONS                                 \
+        _success;                                                      \
+    })
 #endif
 
 /*****************************************************************************/
 
 #if GLIB_CHECK_VERSION(2, 36, 0)
-    #define g_credentials_get_unix_pid(creds, error)                                        \
-        ({                                                                                  \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS(g_credentials_get_unix_pid)((creds), (error)); \
-            G_GNUC_END_IGNORE_DEPRECATIONS                                                  \
-        })
+#define g_credentials_get_unix_pid(creds, error)                                        \
+    ({                                                                                  \
+        G_GNUC_BEGIN_IGNORE_DEPRECATIONS(g_credentials_get_unix_pid)((creds), (error)); \
+        G_GNUC_END_IGNORE_DEPRECATIONS                                                  \
+    })
 #else
-    #define g_credentials_get_unix_pid(creds, error)                                          \
-        ({                                                                                    \
-            struct ucred *native_creds;                                                       \
-                                                                                              \
-            native_creds = g_credentials_get_native((creds), G_CREDENTIALS_TYPE_LINUX_UCRED); \
-            g_assert(native_creds);                                                           \
-            native_creds->pid;                                                                \
-        })
+#define g_credentials_get_unix_pid(creds, error)                                          \
+    ({                                                                                    \
+        struct ucred *native_creds;                                                       \
+                                                                                          \
+        native_creds = g_credentials_get_native((creds), G_CREDENTIALS_TYPE_LINUX_UCRED); \
+        g_assert(native_creds);                                                           \
+        native_creds->pid;                                                                \
+    })
 #endif
 
 /*****************************************************************************/
@@ -387,38 +387,39 @@ _nm_g_hash_table_get_keys_as_array(GHashTable *hash_table, guint *length)
 }
 #endif
 #if !GLIB_CHECK_VERSION(2, 40, 0)
-    #define g_hash_table_get_keys_as_array(hash_table, length) \
-        ({ _nm_g_hash_table_get_keys_as_array(hash_table, length); })
+#define g_hash_table_get_keys_as_array(hash_table, length) \
+    ({ _nm_g_hash_table_get_keys_as_array(hash_table, length); })
 #else
-    #define g_hash_table_get_keys_as_array(hash_table, length)               \
-        ({                                                                   \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS(g_hash_table_get_keys_as_array) \
-            ((hash_table), (length));                                        \
-            G_GNUC_END_IGNORE_DEPRECATIONS                                   \
-        })
+#define g_hash_table_get_keys_as_array(hash_table, length)               \
+    ({                                                                   \
+        G_GNUC_BEGIN_IGNORE_DEPRECATIONS(g_hash_table_get_keys_as_array) \
+        ((hash_table), (length));                                        \
+        G_GNUC_END_IGNORE_DEPRECATIONS                                   \
+    })
 #endif
 
 /*****************************************************************************/
 
 #ifndef g_info
-    /* g_info was only added with 2.39.2 */
-    #define g_info(...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, __VA_ARGS__)
+/* g_info was only added with 2.39.2 */
+#define g_info(...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, __VA_ARGS__)
 #endif
 
 /*****************************************************************************/
 
 #ifdef g_steal_pointer
-    #undef g_steal_pointer
+#undef g_steal_pointer
 #endif
 
-#define g_steal_pointer(pp)                                \
-    ({                                                     \
-        typeof(*(pp)) *const         _pp           = (pp); \
-        typeof(*_pp)                 _p            = *_pp; \
-        _nm_unused const void *const _p_type_check = _p;   \
-                                                           \
-        *_pp = NULL;                                       \
-        _p;                                                \
+#define g_steal_pointer(pp)              \
+    ({                                   \
+        typeof(*(pp)) *const _pp = (pp); \
+        typeof(*_pp)         _p  = *_pp; \
+                                         \
+        _NM_ENSURE_POINTER(_p);          \
+                                         \
+        *_pp = NULL;                     \
+        _p;                              \
     })
 
 /*****************************************************************************/
@@ -460,7 +461,7 @@ _nm_g_variant_new_take_string(char *string)
     return value;
 #elif !GLIB_CHECK_VERSION(2, 38, 0)
     GVariant *value;
-    GBytes *  bytes;
+    GBytes *bytes;
 
     g_return_val_if_fail(string != NULL, NULL);
     g_return_val_if_fail(g_utf8_validate(string, -1, NULL), NULL);
@@ -494,17 +495,17 @@ _nm_printf(1, 2) static inline GVariant *_nm_g_variant_new_printf(const char *fo
 
     return g_variant_new_take_string(string);
 }
-    #define g_variant_new_printf(...) _nm_g_variant_new_printf(__VA_ARGS__)
+#define g_variant_new_printf(...) _nm_g_variant_new_printf(__VA_ARGS__)
 #else
-    #define g_variant_new_printf(...)               \
-        ({                                          \
-            GVariant *_v;                           \
-                                                    \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS        \
-            _v = g_variant_new_printf(__VA_ARGS__); \
-            G_GNUC_END_IGNORE_DEPRECATIONS          \
-            _v;                                     \
-        })
+#define g_variant_new_printf(...)               \
+    ({                                          \
+        GVariant *_v;                           \
+                                                \
+        G_GNUC_BEGIN_IGNORE_DEPRECATIONS        \
+        _v = g_variant_new_printf(__VA_ARGS__); \
+        G_GNUC_END_IGNORE_DEPRECATIONS          \
+        _v;                                     \
+    })
 #endif
 
 /*****************************************************************************/
@@ -525,11 +526,11 @@ _nm_printf(1, 2) static inline GVariant *_nm_g_variant_new_printf(const char *fo
 /*****************************************************************************/
 
 #ifndef g_autofree
-    /* we still don't rely on recent glib to provide g_autofree. Hence, we continue
+/* we still don't rely on recent glib to provide g_autofree. Hence, we continue
  * to use our gs_* free macros that we took from libgsystem.
  *
  * To ease migration towards g_auto*, add a compat define for g_autofree. */
-    #define g_autofree gs_free
+#define g_autofree gs_free
 #endif
 
 /*****************************************************************************/
@@ -553,7 +554,7 @@ _nm_g_value_unset(GValue *value)
     if (value->g_type != 0)
         g_value_unset(value);
 }
-    #define g_value_unset _nm_g_value_unset
+#define g_value_unset _nm_g_value_unset
 #endif
 
 /* G_PID_FORMAT was added only in 2.53.5. Define it ourself.
@@ -571,7 +572,7 @@ _nm_g_value_unset(GValue *value)
 
 /* G_SOURCE_FUNC was added in 2.57.2. */
 #undef G_SOURCE_FUNC
-#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f))
+#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void))(f))
 
 /*****************************************************************************/
 
@@ -666,30 +667,39 @@ g_hash_table_steal_extended(GHashTable *  hash_table,
     return FALSE;
 }
 #else
-    #define g_hash_table_steal_extended(hash_table, lookup_key, stolen_key, stolen_value)    \
-        ({                                                                                   \
-            gpointer *_stolen_key   = (stolen_key);                                          \
-            gpointer *_stolen_value = (stolen_value);                                        \
-                                                                                             \
-            /* we cannot allow NULL arguments, because then we would leak the values in
+#define g_hash_table_steal_extended(hash_table, lookup_key, stolen_key, stolen_value)    \
+    ({                                                                                   \
+        gpointer *_stolen_key   = (stolen_key);                                          \
+        gpointer *_stolen_value = (stolen_value);                                        \
+                                                                                         \
+        /* we cannot allow NULL arguments, because then we would leak the values in
              * the compat implementation. */      \
-            g_assert(_stolen_key);                                                           \
-            g_assert(_stolen_value);                                                         \
-                                                                                             \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                                 \
-            g_hash_table_steal_extended(hash_table, lookup_key, _stolen_key, _stolen_value); \
-            G_GNUC_END_IGNORE_DEPRECATIONS                                                   \
-        })
+        g_assert(_stolen_key);                                                           \
+        g_assert(_stolen_value);                                                         \
+                                                                                         \
+        G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                                 \
+        g_hash_table_steal_extended(hash_table, lookup_key, _stolen_key, _stolen_value); \
+        G_GNUC_END_IGNORE_DEPRECATIONS                                                   \
+    })
 #endif
 
 /*****************************************************************************/
 
-__attribute__((
-    __deprecated__("Don't use g_cancellable_reset(). Create a new cancellable instead."))) void
-_nm_g_cancellable_reset(GCancellable *cancellable);
+_nm_deprecated("Don't use this API") void _nm_forbidden_glib_api_0(void);
+_nm_deprecated("Don't use this API") void _nm_forbidden_glib_api_n(gconstpointer arg0, ...);
 
 #undef g_cancellable_reset
-#define g_cancellable_reset(cancellable) _nm_g_cancellable_reset(cancellable)
+#define g_cancellable_reset(cancellable) _nm_forbidden_glib_api_n(cancellable)
+
+#undef g_idle_remove_by_data
+#define g_idle_remove_by_data(data) _nm_forbidden_glib_api_n(data)
+
+#undef g_source_remove_by_funcs_user_data
+#define g_source_remove_by_funcs_user_data(funcs, user_data) \
+    _nm_forbidden_glib_api_n(funcs, user_data)
+
+#undef g_source_remove_by_user_data
+#define g_source_remove_by_user_data(user_data) _nm_forbidden_glib_api_n(user_data)
 
 /*****************************************************************************/
 
diff --git a/src/libnm-glib-aux/nm-hash-utils.c b/src/libnm-glib-aux/nm-hash-utils.c
index 10fc097c..a6949ebd 100644
--- a/src/libnm-glib-aux/nm-hash-utils.c
+++ b/src/libnm-glib-aux/nm-hash-utils.c
@@ -255,7 +255,7 @@ nm_ppdirect_equal(gconstpointer a, gconstpointer b)
 /*****************************************************************************/
 
 guint
-nm_gbytes_hash(gconstpointer p)
+nm_g_bytes_hash(gconstpointer p)
 {
     GBytes *      ptr = (GBytes *) p;
     gconstpointer arr;
@@ -266,7 +266,7 @@ nm_gbytes_hash(gconstpointer p)
 }
 
 guint
-nm_pgbytes_hash(gconstpointer p)
+nm_pg_bytes_hash(gconstpointer p)
 {
     GBytes *const *ptr = p;
     gconstpointer  arr;
@@ -277,7 +277,7 @@ nm_pgbytes_hash(gconstpointer p)
 }
 
 gboolean
-nm_pgbytes_equal(gconstpointer a, gconstpointer b)
+nm_pg_bytes_equal(gconstpointer a, gconstpointer b)
 {
     GBytes *const *ptr_a = a;
     GBytes *const *ptr_b = b;
diff --git a/src/libnm-glib-aux/nm-hash-utils.h b/src/libnm-glib-aux/nm-hash-utils.h
index e79fb894..d7de2de4 100644
--- a/src/libnm-glib-aux/nm-hash-utils.h
+++ b/src/libnm-glib-aux/nm-hash-utils.h
@@ -122,138 +122,26 @@ nm_hash_update_bool(NMHashState *state, bool val)
     nm_hash_update(state, &val, sizeof(val));
 }
 
-#define _NM_HASH_COMBINE_BOOLS_x_1(t, y) ((y) ? ((t) (1ull << 0)) : ((t) 0ull))
-#define _NM_HASH_COMBINE_BOOLS_x_2(t, y, ...) \
-    ((y) ? ((t) (1ull << 1)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_1(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_3(t, y, ...) \
-    ((y) ? ((t) (1ull << 2)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_2(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_4(t, y, ...) \
-    ((y) ? ((t) (1ull << 3)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_3(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_5(t, y, ...) \
-    ((y) ? ((t) (1ull << 4)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_4(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_6(t, y, ...) \
-    ((y) ? ((t) (1ull << 5)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_5(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_7(t, y, ...) \
-    ((y) ? ((t) (1ull << 6)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_6(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_8(t, y, ...) \
-    ((y) ? ((t) (1ull << 7)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_7(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_9(t, y, ...) \
-    ((y) ? ((t) (1ull << 8)) : ((t) 0ull))    \
-        | (G_STATIC_ASSERT_EXPR(sizeof(t) >= 2), (_NM_HASH_COMBINE_BOOLS_x_8(t, __VA_ARGS__)))
-#define _NM_HASH_COMBINE_BOOLS_x_10(t, y, ...) \
-    ((y) ? ((t) (1ull << 9)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_9(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_11(t, y, ...) \
-    ((y) ? ((t) (1ull << 10)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_10(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_n2(t, n, ...) _NM_HASH_COMBINE_BOOLS_x_##n(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_n(t, n, ...)  _NM_HASH_COMBINE_BOOLS_n2(t, n, __VA_ARGS__)
-
-#define NM_HASH_COMBINE_BOOLS(type, ...) \
-    ((type) (_NM_HASH_COMBINE_BOOLS_n(type, NM_NARG(__VA_ARGS__), __VA_ARGS__)))
+#define _NM_HASH_COMBINE_BOOLS_OP(x, n) ((x) ? NM_BIT((n)) : 0u)
+
+#define NM_HASH_COMBINE_BOOLS(type, ...)                                               \
+    ((type) (NM_STATIC_ASSERT_EXPR_1(NM_NARG(__VA_ARGS__) <= 8 * sizeof(type))         \
+                 ? (NM_VA_ARGS_FOREACH(, , |, _NM_HASH_COMBINE_BOOLS_OP, __VA_ARGS__)) \
+                 : 0))
 
 #define nm_hash_update_bools(state, ...) \
     nm_hash_update_val(state, NM_HASH_COMBINE_BOOLS(guint8, __VA_ARGS__))
 
-#define _NM_HASH_COMBINE_VALS_typ_x_1(y) typeof(y) _v1;
-#define _NM_HASH_COMBINE_VALS_typ_x_2(y, ...) \
-    typeof(y) _v2;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_1(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_3(y, ...) \
-    typeof(y) _v3;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_2(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_4(y, ...) \
-    typeof(y) _v4;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_3(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_5(y, ...) \
-    typeof(y) _v5;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_4(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_6(y, ...) \
-    typeof(y) _v6;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_5(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_7(y, ...) \
-    typeof(y) _v7;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_6(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_8(y, ...) \
-    typeof(y) _v8;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_7(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_9(y, ...) \
-    typeof(y) _v9;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_8(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_10(y, ...) \
-    typeof(y) _v10;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_9(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_11(y, ...) \
-    typeof(y) _v11;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_10(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_12(y, ...) \
-    typeof(y) _v12;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_11(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_13(y, ...) \
-    typeof(y) _v13;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_12(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_14(y, ...) \
-    typeof(y) _v14;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_13(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_15(y, ...) \
-    typeof(y) _v15;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_14(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_16(y, ...) \
-    typeof(y) _v16;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_15(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_17(y, ...) \
-    typeof(y) _v17;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_16(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_18(y, ...) \
-    typeof(y) _v18;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_17(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_19(y, ...) \
-    typeof(y) _v19;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_18(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_20(y, ...) \
-    typeof(y) _v20;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_19(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_n2(n, ...) _NM_HASH_COMBINE_VALS_typ_x_##n(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_n(n, ...)  _NM_HASH_COMBINE_VALS_typ_n2(n, __VA_ARGS__)
-
-#define _NM_HASH_COMBINE_VALS_val_x_1(y)      ._v1 = (y),
-#define _NM_HASH_COMBINE_VALS_val_x_2(y, ...) ._v2 = (y), _NM_HASH_COMBINE_VALS_val_x_1(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_3(y, ...) ._v3 = (y), _NM_HASH_COMBINE_VALS_val_x_2(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_4(y, ...) ._v4 = (y), _NM_HASH_COMBINE_VALS_val_x_3(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_5(y, ...) ._v5 = (y), _NM_HASH_COMBINE_VALS_val_x_4(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_6(y, ...) ._v6 = (y), _NM_HASH_COMBINE_VALS_val_x_5(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_7(y, ...) ._v7 = (y), _NM_HASH_COMBINE_VALS_val_x_6(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_8(y, ...) ._v8 = (y), _NM_HASH_COMBINE_VALS_val_x_7(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_9(y, ...) ._v9 = (y), _NM_HASH_COMBINE_VALS_val_x_8(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_10(y, ...) \
-    ._v10 = (y), _NM_HASH_COMBINE_VALS_val_x_9(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_11(y, ...) \
-    ._v11 = (y), _NM_HASH_COMBINE_VALS_val_x_10(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_12(y, ...) \
-    ._v12 = (y), _NM_HASH_COMBINE_VALS_val_x_11(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_13(y, ...) \
-    ._v13 = (y), _NM_HASH_COMBINE_VALS_val_x_12(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_14(y, ...) \
-    ._v14 = (y), _NM_HASH_COMBINE_VALS_val_x_13(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_15(y, ...) \
-    ._v15 = (y), _NM_HASH_COMBINE_VALS_val_x_14(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_16(y, ...) \
-    ._v16 = (y), _NM_HASH_COMBINE_VALS_val_x_15(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_17(y, ...) \
-    ._v17 = (y), _NM_HASH_COMBINE_VALS_val_x_16(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_18(y, ...) \
-    ._v18 = (y), _NM_HASH_COMBINE_VALS_val_x_17(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_19(y, ...) \
-    ._v19 = (y), _NM_HASH_COMBINE_VALS_val_x_18(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_20(y, ...) \
-    ._v20 = (y), _NM_HASH_COMBINE_VALS_val_x_19(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_n2(n, ...) _NM_HASH_COMBINE_VALS_val_x_##n(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_n(n, ...)  _NM_HASH_COMBINE_VALS_val_n2(n, __VA_ARGS__)
+#define _NM_HASH_COMBINE_VALS_TYPE_OP(x, idx) typeof(x) _v##idx;
+#define _NM_HASH_COMBINE_VALS_INIT_OP(x, idx) ._v##idx = (x),
 
 /* NM_HASH_COMBINE_VALS() is faster then nm_hash_update_val() as it combines multiple
  * calls to nm_hash_update() using a packed structure. */
-#define NM_HASH_COMBINE_VALS(var, ...)                                 \
-    const struct _nm_packed {                                          \
-        _NM_HASH_COMBINE_VALS_typ_n(NM_NARG(__VA_ARGS__), __VA_ARGS__) \
-    } var _nm_alignas(guint64) = {_NM_HASH_COMBINE_VALS_val_n(NM_NARG(__VA_ARGS__), __VA_ARGS__)}
+#define NM_HASH_COMBINE_VALS(var, ...)                                       \
+    const struct _nm_packed {                                                \
+        NM_VA_ARGS_FOREACH(, , , _NM_HASH_COMBINE_VALS_TYPE_OP, __VA_ARGS__) \
+    } var _nm_alignas(guint64) = {                                           \
+        NM_VA_ARGS_FOREACH(, , , _NM_HASH_COMBINE_VALS_INIT_OP, __VA_ARGS__)}
 
 /* nm_hash_update_vals() is faster then nm_hash_update_val() as it combines multiple
  * calls to nm_hash_update() using a packed structure. */
@@ -301,15 +189,15 @@ nm_hash_update_str(NMHashState *state, const char *str)
 }
 
 #if _NM_CC_SUPPORT_GENERIC
-    /* Like nm_hash_update_str(), but restricted to arrays only. nm_hash_update_str() only works
+/* Like nm_hash_update_str(), but restricted to arrays only. nm_hash_update_str() only works
  * with a @str argument that cannot be NULL. If you have a string pointer, that is never NULL, use
  * nm_hash_update() instead. */
-    #define nm_hash_update_strarr(state, str)                                \
-        (_Generic(&(str), const char(*)[sizeof(str)]                         \
-                  : nm_hash_update_str((state), (str)), char(*)[sizeof(str)] \
-                  : nm_hash_update_str((state), (str))))
+#define nm_hash_update_strarr(state, str)                                \
+    (_Generic(&(str), const char(*)[sizeof(str)]                         \
+              : nm_hash_update_str((state), (str)), char(*)[sizeof(str)] \
+              : nm_hash_update_str((state), (str))))
 #else
-    #define nm_hash_update_strarr(state, str) nm_hash_update_str((state), (str))
+#define nm_hash_update_strarr(state, str) nm_hash_update_str((state), (str))
 #endif
 
 guint nm_hash_ptr(gconstpointer ptr);
@@ -379,11 +267,11 @@ gboolean nm_ppdirect_equal(gconstpointer a, gconstpointer b);
 
 /*****************************************************************************/
 
-guint nm_gbytes_hash(gconstpointer p);
-#define nm_gbytes_equal g_bytes_equal
+guint nm_g_bytes_hash(gconstpointer p);
+#define nm_g_bytes_equal g_bytes_equal
 
-guint    nm_pgbytes_hash(gconstpointer p);
-gboolean nm_pgbytes_equal(gconstpointer a, gconstpointer b);
+guint    nm_pg_bytes_hash(gconstpointer p);
+gboolean nm_pg_bytes_equal(gconstpointer a, gconstpointer b);
 
 /*****************************************************************************/
 
diff --git a/src/libnm-glib-aux/nm-io-utils.c b/src/libnm-glib-aux/nm-io-utils.c
index 87478a2d..85a81f69 100644
--- a/src/libnm-glib-aux/nm-io-utils.c
+++ b/src/libnm-glib-aux/nm-io-utils.c
@@ -7,9 +7,11 @@
 
 #include "nm-io-utils.h"
 
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
 
 #include "nm-str-buf.h"
 #include "nm-shared-utils.h"
@@ -628,3 +630,96 @@ next:;
     g_ptr_array_add(arr, NULL);
     return (char **) g_ptr_array_free(arr, FALSE);
 }
+
+/*****************************************************************************/
+
+/* taken from systemd's sockaddr_un_set_path(). */
+int
+nm_io_sockaddr_un_set(struct sockaddr_un *ret, NMOptionBool is_abstract, const char *path)
+{
+    gsize l;
+
+    g_return_val_if_fail(ret, -EINVAL);
+    g_return_val_if_fail(path, -EINVAL);
+    nm_assert_is_ternary(is_abstract);
+
+    if (is_abstract == NM_OPTION_BOOL_DEFAULT)
+        is_abstract = nm_io_sockaddr_un_path_is_abstract(path, &path);
+
+    l = strlen(path);
+    if (l < 1)
+        return -EINVAL;
+    if (l > sizeof(ret->sun_path) - 1)
+        return -EINVAL;
+
+    if (!is_abstract) {
+        if (path[0] != '/') {
+            /* non-abstract paths must be absolute. */
+            return -EINVAL;
+        }
+    }
+
+    memset(ret, 0, nm_offsetof(struct sockaddr_un, sun_path));
+    ret->sun_family = AF_UNIX;
+
+    if (is_abstract) {
+        ret->sun_path[0] = '\0';
+        memcpy(&ret->sun_path[1], path, NM_MIN(l + 1, sizeof(ret->sun_path) - 1));
+    } else
+        memcpy(&ret->sun_path, path, l + 1);
+
+    /* For pathname addresses, we return the size with the trailing NUL.
+     * For abstract addresses, we return the size without the trailing NUL
+     * (which may not be even written). But as abstract sockets also have
+     * a NUL at the beginning of sun_path, the total length is always
+     * calculated the same. */
+    return (nm_offsetof(struct sockaddr_un, sun_path) + 1) + l;
+}
+
+/*****************************************************************************/
+
+/* taken from systemd's sd_notify(). */
+int
+nm_sd_notify(const char *state)
+{
+    struct sockaddr_un sockaddr;
+    struct iovec       iovec;
+    struct msghdr      msghdr = {
+        .msg_iov    = &iovec,
+        .msg_iovlen = 1,
+        .msg_name   = &sockaddr,
+    };
+    nm_auto_close int fd = -1;
+    const char *      e;
+    int               r;
+
+    if (!state)
+        g_return_val_if_reached(-EINVAL);
+
+    e = getenv("NOTIFY_SOCKET");
+    if (!e)
+        return 0;
+
+    r = nm_io_sockaddr_un_set(&sockaddr, NM_OPTION_BOOL_DEFAULT, e);
+    if (r < 0)
+        return r;
+    msghdr.msg_namelen = r;
+
+    fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+    if (fd < 0)
+        return -NM_ERRNO_NATIVE(errno);
+
+    /* systemd calls here fd_set_sndbuf(fd, SNDBUF_SIZE) .We don't bother. */
+
+    iovec = (struct iovec){
+        .iov_base = (gpointer) state,
+        .iov_len  = strlen(state),
+    };
+
+    /* systemd sends ucred, if geteuid()/getegid() does not match getuid()/getgid(). We don't bother. */
+
+    if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
+        return -NM_ERRNO_NATIVE(errno);
+
+    return 0;
+}
diff --git a/src/libnm-glib-aux/nm-io-utils.h b/src/libnm-glib-aux/nm-io-utils.h
index 31ff6d05..479d0e51 100644
--- a/src/libnm-glib-aux/nm-io-utils.h
+++ b/src/libnm-glib-aux/nm-io-utils.h
@@ -60,4 +60,21 @@ void nm_g_subprocess_terminate_in_background(GSubprocess *subprocess, int timeou
 
 char **nm_utils_find_mkstemp_files(const char *dirname, const char *filename);
 
+static inline gboolean
+nm_io_sockaddr_un_path_is_abstract(const char *path, const char **out_path)
+{
+    if (path && path[0] == '@') {
+        NM_SET_OUT(out_path, &path[1]);
+        return TRUE;
+    }
+    NM_SET_OUT(out_path, path);
+    return FALSE;
+}
+
+struct sockaddr_un;
+
+int nm_io_sockaddr_un_set(struct sockaddr_un *ret, NMOptionBool is_abstract, const char *path);
+
+int nm_sd_notify(const char *state);
+
 #endif /* __NM_IO_UTILS_H__ */
diff --git a/src/libnm-glib-aux/nm-jansson.h b/src/libnm-glib-aux/nm-jansson.h
index 6173a7ac..a907d2bb 100644
--- a/src/libnm-glib-aux/nm-jansson.h
+++ b/src/libnm-glib-aux/nm-jansson.h
@@ -10,20 +10,20 @@
 
 #if WITH_JANSSON
 
-    #include <jansson.h>
-
-    /* Added in Jansson v2.8 */
-    #ifndef json_object_foreach_safe
-        #define json_object_foreach_safe(object, n, key, value)                         \
-            for (key = json_object_iter_key(json_object_iter(object)),                  \
-                n    = json_object_iter_next(object, json_object_key_to_iter(key));     \
-                 key && (value = json_object_iter_value(json_object_key_to_iter(key))); \
-                 key = json_object_iter_key(n),                                         \
-                n    = json_object_iter_next(object, json_object_key_to_iter(key)))
-    #endif
+#include <jansson.h>
+
+/* Added in Jansson v2.8 */
+#ifndef json_object_foreach_safe
+#define json_object_foreach_safe(object, n, key, value)                         \
+    for (key = json_object_iter_key(json_object_iter(object)),                  \
+        n    = json_object_iter_next(object, json_object_key_to_iter(key));     \
+         key && (value = json_object_iter_value(json_object_key_to_iter(key))); \
+         key = json_object_iter_key(n),                                         \
+        n    = json_object_iter_next(object, json_object_key_to_iter(key)))
+#endif
 
 NM_AUTO_DEFINE_FCN0(json_t *, _nm_auto_decref_json, json_decref);
-    #define nm_auto_decref_json nm_auto(_nm_auto_decref_json)
+#define nm_auto_decref_json nm_auto(_nm_auto_decref_json)
 
 #endif /* WITH_JANSON */
 
diff --git a/src/libnm-glib-aux/nm-json-aux.c b/src/libnm-glib-aux/nm-json-aux.c
index dc67d6d5..0a3b25f8 100644
--- a/src/libnm-glib-aux/nm-json-aux.c
+++ b/src/libnm-glib-aux/nm-json-aux.c
@@ -16,7 +16,7 @@
  * program). But that needs to be fixed by the json libraries, and it is by adding
  * symbol versioning in recent versions. */
 #ifndef RTLD_DEEPBIND
-    #define RTLD_DEEPBIND 0
+#define RTLD_DEEPBIND 0
 #endif
 
 /*****************************************************************************/
@@ -174,7 +174,7 @@ _nm_json_vt_internal_load(void)
 #elif !WITH_JANSSON && !defined(JANSSON_SONAME)
     soname = NULL;
 #else
-    #error "WITH_JANSON and JANSSON_SONAME are defined inconsistently."
+#error "WITH_JANSON and JANSSON_SONAME are defined inconsistently."
 #endif
 
     if (!soname)
diff --git a/src/libnm-glib-aux/nm-json-aux.h b/src/libnm-glib-aux/nm-json-aux.h
index 936e9146..088d67a9 100644
--- a/src/libnm-glib-aux/nm-json-aux.h
+++ b/src/libnm-glib-aux/nm-json-aux.h
@@ -271,6 +271,49 @@ nm_jansson_json_as_int64(const NMJsonVt *vt, const nm_json_t *elem, gint64 *out_
 }
 
 static inline int
+nm_jansson_json_as_uint32(const NMJsonVt *vt, const nm_json_t *elem, guint32 *out_val)
+{
+    nm_json_int_t v;
+
+    if (!elem)
+        return 0;
+
+    if (!nm_json_is_integer(elem))
+        return -EINVAL;
+
+    v = vt->nm_json_integer_value(elem);
+    if (v < 0)
+        return -ERANGE;
+    if (v > (guint64) G_MAXUINT32)
+        return -ERANGE;
+
+    NM_SET_OUT(out_val, v);
+    return 1;
+}
+
+static inline int
+nm_jansson_json_as_uint(const NMJsonVt *vt, const nm_json_t *elem, guint *out_val)
+{
+    nm_json_int_t v;
+
+    if (!elem)
+        return 0;
+
+    if (!nm_json_is_integer(elem))
+        return -EINVAL;
+
+    v = vt->nm_json_integer_value(elem);
+    if (v < 0)
+        return -ERANGE;
+
+    if (v > (guint64) G_MAXUINT)
+        return -ERANGE;
+
+    NM_SET_OUT(out_val, v);
+    return 1;
+}
+
+static inline int
 nm_jansson_json_as_uint64(const NMJsonVt *vt, const nm_json_t *elem, guint64 *out_val)
 {
     nm_json_int_t v;
@@ -328,17 +371,27 @@ nm_value_type_to_json(NMValueType value_type, GString *gstr, gconstpointer p_fie
         nm_json_gstr_append_int64(gstr, *((const gint32 *) p_field));
         return;
     case NM_VALUE_TYPE_INT:
+    case NM_VALUE_TYPE_ENUM:
         nm_json_gstr_append_int64(gstr, *((const int *) p_field));
         return;
     case NM_VALUE_TYPE_INT64:
         nm_json_gstr_append_int64(gstr, *((const gint64 *) p_field));
         return;
+    case NM_VALUE_TYPE_UINT32:
+        nm_json_gstr_append_uint64(gstr, *((const guint32 *) p_field));
+        return;
+    case NM_VALUE_TYPE_UINT:
+    case NM_VALUE_TYPE_FLAGS:
+        nm_json_gstr_append_uint64(gstr, *((const guint *) p_field));
+        return;
     case NM_VALUE_TYPE_UINT64:
         nm_json_gstr_append_uint64(gstr, *((const guint64 *) p_field));
         return;
     case NM_VALUE_TYPE_STRING:
         nm_json_gstr_append_string(gstr, *((const char *const *) p_field));
         return;
+    case NM_VALUE_TYPE_BYTES:
+    case NM_VALUE_TYPE_NONE:
     case NM_VALUE_TYPE_UNSPEC:
         break;
     }
@@ -357,9 +410,15 @@ nm_value_type_from_json(const NMJsonVt * vt,
     case NM_VALUE_TYPE_INT32:
         return (nm_jansson_json_as_int32(vt, elem, out_val) > 0);
     case NM_VALUE_TYPE_INT:
+    case NM_VALUE_TYPE_ENUM:
         return (nm_jansson_json_as_int(vt, elem, out_val) > 0);
     case NM_VALUE_TYPE_INT64:
         return (nm_jansson_json_as_int64(vt, elem, out_val) > 0);
+    case NM_VALUE_TYPE_UINT32:
+        return (nm_jansson_json_as_uint32(vt, elem, out_val) > 0);
+    case NM_VALUE_TYPE_UINT:
+    case NM_VALUE_TYPE_FLAGS:
+        return (nm_jansson_json_as_uint(vt, elem, out_val) > 0);
     case NM_VALUE_TYPE_UINT64:
         return (nm_jansson_json_as_uint64(vt, elem, out_val) > 0);
 
@@ -368,6 +427,8 @@ nm_value_type_from_json(const NMJsonVt * vt,
     case NM_VALUE_TYPE_STRING:
         return (nm_jansson_json_as_string(vt, elem, out_val) > 0);
 
+    case NM_VALUE_TYPE_BYTES:
+    case NM_VALUE_TYPE_NONE:
     case NM_VALUE_TYPE_UNSPEC:
         break;
     }
diff --git a/src/libnm-glib-aux/nm-logging-base.c b/src/libnm-glib-aux/nm-logging-base.c
index e11bd9f3..cc19ef15 100644
--- a/src/libnm-glib-aux/nm-logging-base.c
+++ b/src/libnm-glib-aux/nm-logging-base.c
@@ -6,6 +6,8 @@
 
 #include <syslog.h>
 
+#include "nm-time-utils.h"
+
 /*****************************************************************************/
 
 const LogLevelDesc nm_log_level_desc[_LOGL_N] = {
@@ -77,3 +79,61 @@ _nm_log_parse_level(const char *level, NMLogLevel *out_level)
 
     return FALSE;
 }
+
+/*****************************************************************************/
+
+volatile NMLogLevel _nm_logging_enabled_value = LOGL_TRACE;
+
+void
+_nm_logging_enabled_init(const char *level_str)
+{
+    NMLogLevel level;
+
+    if (!_nm_log_parse_level(level_str, &level))
+        level = LOGL_WARN;
+    else if (level == _LOGL_KEEP)
+        level = LOGL_WARN;
+
+    _nm_logging_enabled_value = level;
+}
+
+/*****************************************************************************/
+
+void
+_nm_log_simple_printf(NMLogLevel level, const char *fmt, ...)
+{
+    gs_free char *msg_heap = NULL;
+    char          msg_stack[700];
+    const char *  msg;
+    const char *  level_str;
+    gint64        ts;
+
+    ts = nm_utils_clock_gettime_nsec(CLOCK_BOOTTIME);
+
+    msg = nm_vsprintf_buf_or_alloc(fmt, fmt, msg_stack, &msg_heap, NULL);
+
+    switch (level) {
+    case LOGL_TRACE:
+        level_str = "<trace>";
+        break;
+    case LOGL_DEBUG:
+        level_str = "<debug>";
+        break;
+    case LOGL_INFO:
+        level_str = "<info> ";
+        break;
+    case LOGL_WARN:
+        level_str = "<warn> ";
+        break;
+    default:
+        nm_assert(level == LOGL_ERR);
+        level_str = "<error>";
+        break;
+    }
+
+    g_print("[%" G_GINT64_FORMAT ".%05" G_GINT64_FORMAT "] %s %s\n",
+            ts / NM_UTILS_NSEC_PER_SEC,
+            (ts / (NM_UTILS_NSEC_PER_SEC / 10000)) % 10000,
+            level_str,
+            msg);
+}
diff --git a/src/libnm-glib-aux/nm-logging-base.h b/src/libnm-glib-aux/nm-logging-base.h
index 136f0c04..3d76b378 100644
--- a/src/libnm-glib-aux/nm-logging-base.h
+++ b/src/libnm-glib-aux/nm-logging-base.h
@@ -25,4 +25,20 @@ extern const LogLevelDesc nm_log_level_desc[_LOGL_N];
 
 gboolean _nm_log_parse_level(const char *level, NMLogLevel *out_level);
 
+/*****************************************************************************/
+
+extern volatile NMLogLevel _nm_logging_enabled_value;
+
+static inline gboolean
+_nm_logging_enabled(NMLogLevel level)
+{
+    return level >= _nm_logging_enabled_value;
+}
+
+void _nm_logging_enabled_init(const char *level_str);
+
+/*****************************************************************************/
+
+void _nm_log_simple_printf(NMLogLevel level, const char *fmt, ...) _nm_printf(2, 3);
+
 #endif /* __NM_LOGGING_BASE_H__ */
diff --git a/src/libnm-glib-aux/nm-logging-fwd.h b/src/libnm-glib-aux/nm-logging-fwd.h
index 0ede91b2..3e999c4a 100644
--- a/src/libnm-glib-aux/nm-logging-fwd.h
+++ b/src/libnm-glib-aux/nm-logging-fwd.h
@@ -182,28 +182,28 @@ extern void _nm_utils_monotonic_timestamp_initialized(const struct timespec *tp,
 /* _LOGT() and _LOGt() both log with level TRACE, but the latter is disabled by default,
  * unless building with --with-more-logging. */
 #if NM_MORE_LOGGING
-    #define _LOGt_ENABLED(...)    _NMLOG_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)
-    #define _LOGt(...)            _NMLOG(_LOGL_TRACE, __VA_ARGS__)
-    #define _LOGt_err(errsv, ...) _NMLOG_err(errsv, _LOGL_TRACE, __VA_ARGS__)
+#define _LOGt_ENABLED(...)    _NMLOG_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)
+#define _LOGt(...)            _NMLOG(_LOGL_TRACE, __VA_ARGS__)
+#define _LOGt_err(errsv, ...) _NMLOG_err(errsv, _LOGL_TRACE, __VA_ARGS__)
 #else
-    /* still call the logging macros to get compile time checks, but they will be optimized out. */
-    #define _LOGt_ENABLED(...) (FALSE && (_NMLOG_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)))
-    #define _LOGt(...)                            \
-        G_STMT_START                              \
-        {                                         \
-            if (FALSE) {                          \
-                _NMLOG(_LOGL_TRACE, __VA_ARGS__); \
-            }                                     \
-        }                                         \
-        G_STMT_END
-    #define _LOGt_err(errsv, ...)                            \
-        G_STMT_START                                         \
-        {                                                    \
-            if (FALSE) {                                     \
-                _NMLOG_err(errsv, _LOGL_TRACE, __VA_ARGS__); \
-            }                                                \
-        }                                                    \
-        G_STMT_END
+/* still call the logging macros to get compile time checks, but they will be optimized out. */
+#define _LOGt_ENABLED(...) (FALSE && (_NMLOG_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)))
+#define _LOGt(...)                            \
+    G_STMT_START                              \
+    {                                         \
+        if (FALSE) {                          \
+            _NMLOG(_LOGL_TRACE, __VA_ARGS__); \
+        }                                     \
+    }                                         \
+    G_STMT_END
+#define _LOGt_err(errsv, ...)                            \
+    G_STMT_START                                         \
+    {                                                    \
+        if (FALSE) {                                     \
+            _NMLOG_err(errsv, _LOGL_TRACE, __VA_ARGS__); \
+        }                                                \
+    }                                                    \
+    G_STMT_END
 #endif
 
 /*****************************************************************************/
@@ -236,28 +236,28 @@ extern void _nm_utils_monotonic_timestamp_initialized(const struct timespec *tp,
 #define _LOG2E_err(errsv, ...) _NMLOG2_err(errsv, _LOGL_ERR, __VA_ARGS__)
 
 #if NM_MORE_LOGGING
-    #define _LOG2t_ENABLED(...)    _NMLOG2_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)
-    #define _LOG2t(...)            _NMLOG2(_LOGL_TRACE, __VA_ARGS__)
-    #define _LOG2t_err(errsv, ...) _NMLOG2_err(errsv, _LOGL_TRACE, __VA_ARGS__)
+#define _LOG2t_ENABLED(...)    _NMLOG2_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)
+#define _LOG2t(...)            _NMLOG2(_LOGL_TRACE, __VA_ARGS__)
+#define _LOG2t_err(errsv, ...) _NMLOG2_err(errsv, _LOGL_TRACE, __VA_ARGS__)
 #else
-    /* still call the logging macros to get compile time checks, but they will be optimized out. */
-    #define _LOG2t_ENABLED(...) (FALSE && (_NMLOG2_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)))
-    #define _LOG2t(...)                            \
-        G_STMT_START                               \
-        {                                          \
-            if (FALSE) {                           \
-                _NMLOG2(_LOGL_TRACE, __VA_ARGS__); \
-            }                                      \
-        }                                          \
-        G_STMT_END
-    #define _LOG2t_err(errsv, ...)                            \
-        G_STMT_START                                          \
-        {                                                     \
-            if (FALSE) {                                      \
-                _NMLOG2_err(errsv, _LOGL_TRACE, __VA_ARGS__); \
-            }                                                 \
-        }                                                     \
-        G_STMT_END
+/* still call the logging macros to get compile time checks, but they will be optimized out. */
+#define _LOG2t_ENABLED(...) (FALSE && (_NMLOG2_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)))
+#define _LOG2t(...)                            \
+    G_STMT_START                               \
+    {                                          \
+        if (FALSE) {                           \
+            _NMLOG2(_LOGL_TRACE, __VA_ARGS__); \
+        }                                      \
+    }                                          \
+    G_STMT_END
+#define _LOG2t_err(errsv, ...)                            \
+    G_STMT_START                                          \
+    {                                                     \
+        if (FALSE) {                                      \
+            _NMLOG2_err(errsv, _LOGL_TRACE, __VA_ARGS__); \
+        }                                                 \
+    }                                                     \
+    G_STMT_END
 #endif
 
 #define _NMLOG3_ENABLED(level) (nm_logging_enabled((level), (_NMLOG3_DOMAIN)))
@@ -281,28 +281,28 @@ extern void _nm_utils_monotonic_timestamp_initialized(const struct timespec *tp,
 #define _LOG3E_err(errsv, ...) _NMLOG3_err(errsv, _LOGL_ERR, __VA_ARGS__)
 
 #if NM_MORE_LOGGING
-    #define _LOG3t_ENABLED(...)    _NMLOG3_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)
-    #define _LOG3t(...)            _NMLOG3(_LOGL_TRACE, __VA_ARGS__)
-    #define _LOG3t_err(errsv, ...) _NMLOG3_err(errsv, _LOGL_TRACE, __VA_ARGS__)
+#define _LOG3t_ENABLED(...)    _NMLOG3_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)
+#define _LOG3t(...)            _NMLOG3(_LOGL_TRACE, __VA_ARGS__)
+#define _LOG3t_err(errsv, ...) _NMLOG3_err(errsv, _LOGL_TRACE, __VA_ARGS__)
 #else
-    /* still call the logging macros to get compile time checks, but they will be optimized out. */
-    #define _LOG3t_ENABLED(...) (FALSE && (_NMLOG3_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)))
-    #define _LOG3t(...)                            \
-        G_STMT_START                               \
-        {                                          \
-            if (FALSE) {                           \
-                _NMLOG3(_LOGL_TRACE, __VA_ARGS__); \
-            }                                      \
-        }                                          \
-        G_STMT_END
-    #define _LOG3t_err(errsv, ...)                            \
-        G_STMT_START                                          \
-        {                                                     \
-            if (FALSE) {                                      \
-                _NMLOG3_err(errsv, _LOGL_TRACE, __VA_ARGS__); \
-            }                                                 \
-        }                                                     \
-        G_STMT_END
+/* still call the logging macros to get compile time checks, but they will be optimized out. */
+#define _LOG3t_ENABLED(...) (FALSE && (_NMLOG3_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)))
+#define _LOG3t(...)                            \
+    G_STMT_START                               \
+    {                                          \
+        if (FALSE) {                           \
+            _NMLOG3(_LOGL_TRACE, __VA_ARGS__); \
+        }                                      \
+    }                                          \
+    G_STMT_END
+#define _LOG3t_err(errsv, ...)                            \
+    G_STMT_START                                          \
+    {                                                     \
+        if (FALSE) {                                      \
+            _NMLOG3_err(errsv, _LOGL_TRACE, __VA_ARGS__); \
+        }                                                 \
+    }                                                     \
+    G_STMT_END
 #endif
 
 /*****************************************************************************/
diff --git a/src/libnm-glib-aux/nm-macros-internal.h b/src/libnm-glib-aux/nm-macros-internal.h
index f2d81e1c..e7ee7f38 100644
--- a/src/libnm-glib-aux/nm-macros-internal.h
+++ b/src/libnm-glib-aux/nm-macros-internal.h
@@ -13,6 +13,7 @@
 #include <string.h>
 
 #include <gio/gio.h>
+#include <glib-unix.h>
 
 /*****************************************************************************/
 
@@ -42,10 +43,6 @@
 
 /*****************************************************************************/
 
-#define nm_offsetofend(t, m) (G_STRUCT_OFFSET(t, m) + sizeof(((t *) NULL)->m))
-
-/*****************************************************************************/
-
 #define gs_free            nm_auto_g_free
 #define gs_unref_object    nm_auto_unref_object
 #define gs_unref_variant   nm_auto_unref_variant
@@ -155,280 +152,6 @@ _nm_auto_freev(gpointer ptr)
 
 /*****************************************************************************/
 
-#define _NM_MACRO_SELECT_ARG_64(_1,  \
-                                _2,  \
-                                _3,  \
-                                _4,  \
-                                _5,  \
-                                _6,  \
-                                _7,  \
-                                _8,  \
-                                _9,  \
-                                _10, \
-                                _11, \
-                                _12, \
-                                _13, \
-                                _14, \
-                                _15, \
-                                _16, \
-                                _17, \
-                                _18, \
-                                _19, \
-                                _20, \
-                                _21, \
-                                _22, \
-                                _23, \
-                                _24, \
-                                _25, \
-                                _26, \
-                                _27, \
-                                _28, \
-                                _29, \
-                                _30, \
-                                _31, \
-                                _32, \
-                                _33, \
-                                _34, \
-                                _35, \
-                                _36, \
-                                _37, \
-                                _38, \
-                                _39, \
-                                _40, \
-                                _41, \
-                                _42, \
-                                _43, \
-                                _44, \
-                                _45, \
-                                _46, \
-                                _47, \
-                                _48, \
-                                _49, \
-                                _50, \
-                                _51, \
-                                _52, \
-                                _53, \
-                                _54, \
-                                _55, \
-                                _56, \
-                                _57, \
-                                _58, \
-                                _59, \
-                                _60, \
-                                _61, \
-                                _62, \
-                                _63, \
-                                N,   \
-                                ...) \
-    N
-
-/* http://stackoverflow.com/a/2124385/354393
- * https://stackoverflow.com/questions/11317474/macro-to-count-number-of-arguments
- */
-
-#define NM_NARG(...)                       \
-    _NM_MACRO_SELECT_ARG_64(,              \
-                            ##__VA_ARGS__, \
-                            62,            \
-                            61,            \
-                            60,            \
-                            59,            \
-                            58,            \
-                            57,            \
-                            56,            \
-                            55,            \
-                            54,            \
-                            53,            \
-                            52,            \
-                            51,            \
-                            50,            \
-                            49,            \
-                            48,            \
-                            47,            \
-                            46,            \
-                            45,            \
-                            44,            \
-                            43,            \
-                            42,            \
-                            41,            \
-                            40,            \
-                            39,            \
-                            38,            \
-                            37,            \
-                            36,            \
-                            35,            \
-                            34,            \
-                            33,            \
-                            32,            \
-                            31,            \
-                            30,            \
-                            29,            \
-                            28,            \
-                            27,            \
-                            26,            \
-                            25,            \
-                            24,            \
-                            23,            \
-                            22,            \
-                            21,            \
-                            20,            \
-                            19,            \
-                            18,            \
-                            17,            \
-                            16,            \
-                            15,            \
-                            14,            \
-                            13,            \
-                            12,            \
-                            11,            \
-                            10,            \
-                            9,             \
-                            8,             \
-                            7,             \
-                            6,             \
-                            5,             \
-                            4,             \
-                            3,             \
-                            2,             \
-                            1,             \
-                            0)
-#define NM_NARG_MAX1(...)                  \
-    _NM_MACRO_SELECT_ARG_64(,              \
-                            ##__VA_ARGS__, \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            0)
-#define NM_NARG_MAX2(...)                  \
-    _NM_MACRO_SELECT_ARG_64(,              \
-                            ##__VA_ARGS__, \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            1,             \
-                            0)
-
-#define _NM_MACRO_CALL(macro, ...) macro(__VA_ARGS__)
-
-/*****************************************************************************/
-
 #define _NM_MACRO_COMMA_IF_ARGS(...) \
     _NM_MACRO_CALL(G_PASTE(__NM_MACRO_COMMA_IF_ARGS_, NM_NARG_MAX1(__VA_ARGS__)), __VA_ARGS__)
 #define __NM_MACRO_COMMA_IF_ARGS_0()
@@ -449,9 +172,9 @@ _nm_auto_freev(gpointer ptr)
 /*****************************************************************************/
 
 #if defined(__GNUC__)
-    #define _NM_PRAGMA_WARNING_DO(warning) G_STRINGIFY(GCC diagnostic ignored warning)
+#define _NM_PRAGMA_WARNING_DO(warning) G_STRINGIFY(GCC diagnostic ignored warning)
 #elif defined(__clang__)
-    #define _NM_PRAGMA_WARNING_DO(warning) G_STRINGIFY(clang diagnostic ignored warning)
+#define _NM_PRAGMA_WARNING_DO(warning) G_STRINGIFY(clang diagnostic ignored warning)
 #endif
 
 /* you can only suppress a specific warning that the compiler
@@ -461,23 +184,22 @@ _nm_auto_freev(gpointer ptr)
  * same name for the same warning. */
 
 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
-    #define NM_PRAGMA_WARNING_DISABLE(warning) \
-        _Pragma("GCC diagnostic push") _Pragma(_NM_PRAGMA_WARNING_DO(warning))
+#define NM_PRAGMA_WARNING_DISABLE(warning) \
+    _Pragma("GCC diagnostic push") _Pragma(_NM_PRAGMA_WARNING_DO(warning))
 #elif defined(__clang__)
-    #define NM_PRAGMA_WARNING_DISABLE(warning)                         \
-        _Pragma("clang diagnostic push")                               \
-            _Pragma(_NM_PRAGMA_WARNING_DO("-Wunknown-warning-option")) \
-                _Pragma(_NM_PRAGMA_WARNING_DO(warning))
+#define NM_PRAGMA_WARNING_DISABLE(warning)                                                      \
+    _Pragma("clang diagnostic push") _Pragma(_NM_PRAGMA_WARNING_DO("-Wunknown-warning-option")) \
+        _Pragma(_NM_PRAGMA_WARNING_DO(warning))
 #else
-    #define NM_PRAGMA_WARNING_DISABLE(warning)
+#define NM_PRAGMA_WARNING_DISABLE(warning)
 #endif
 
 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
-    #define NM_PRAGMA_WARNING_REENABLE _Pragma("GCC diagnostic pop")
+#define NM_PRAGMA_WARNING_REENABLE _Pragma("GCC diagnostic pop")
 #elif defined(__clang__)
-    #define NM_PRAGMA_WARNING_REENABLE _Pragma("clang diagnostic pop")
+#define NM_PRAGMA_WARNING_REENABLE _Pragma("clang diagnostic pop")
 #else
-    #define NM_PRAGMA_WARNING_REENABLE
+#define NM_PRAGMA_WARNING_REENABLE
 #endif
 
 /*****************************************************************************/
@@ -502,37 +224,9 @@ NM_G_ERROR_MSG(GError *error)
 
 /*****************************************************************************/
 
-#ifndef _NM_CC_SUPPORT_AUTO_TYPE
-    #if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)))
-        #define _NM_CC_SUPPORT_AUTO_TYPE 1
-    #else
-        #define _NM_CC_SUPPORT_AUTO_TYPE 0
-    #endif
-#endif
-
-#ifndef _NM_CC_SUPPORT_GENERIC
-    /* In the meantime, NetworkManager requires C11 and _Generic() should always be available.
-     * However, shared/nm-utils may also be used in VPN/applet, which possibly did not yet
-     * bump the C standard requirement. Leave this for the moment, but eventually we can
-     * drop it.
-     *
-     * Technically, gcc 4.9 already has some support for _Generic(). But there seems
-     * to be issues with propagating "const char *[5]" to "const char **". Only assume
-     * we have _Generic() since gcc 5. */
-    #if (defined(__GNUC__) && __GNUC__ >= 5) || (defined(__clang__))
-        #define _NM_CC_SUPPORT_GENERIC 1
-    #else
-        #define _NM_CC_SUPPORT_GENERIC 0
-    #endif
-#endif
-
-#if _NM_CC_SUPPORT_AUTO_TYPE
-    #define _nm_auto_type __auto_type
-#endif
-
 #if _NM_CC_SUPPORT_GENERIC
-    #define _NM_CONSTCAST_FULL_1(type, obj_expr, obj) \
-        (_Generic ((obj_expr), \
+#define _NM_CONSTCAST_FULL_1(type, obj_expr, obj) \
+    (_Generic ((obj_expr), \
                const void        *const: ((const type *) (obj)), \
                const void        *     : ((const type *) (obj)), \
                      void        *const: ((      type *) (obj)), \
@@ -541,8 +235,8 @@ NM_G_ERROR_MSG(GError *error)
                const type        *     : ((const type *) (obj)), \
                      type        *const: ((      type *) (obj)), \
                      type        *     : ((      type *) (obj))))
-    #define _NM_CONSTCAST_FULL_2(type, obj_expr, obj, alias_type2) \
-        (_Generic ((obj_expr), \
+#define _NM_CONSTCAST_FULL_2(type, obj_expr, obj, alias_type2) \
+    (_Generic ((obj_expr), \
                const void        *const: ((const type *) (obj)), \
                const void        *     : ((const type *) (obj)), \
                      void        *const: ((      type *) (obj)), \
@@ -555,8 +249,8 @@ NM_G_ERROR_MSG(GError *error)
                const type        *     : ((const type *) (obj)), \
                      type        *const: ((      type *) (obj)), \
                      type        *     : ((      type *) (obj))))
-    #define _NM_CONSTCAST_FULL_3(type, obj_expr, obj, alias_type2, alias_type3) \
-        (_Generic ((obj_expr), \
+#define _NM_CONSTCAST_FULL_3(type, obj_expr, obj, alias_type2, alias_type3) \
+    (_Generic ((obj_expr), \
                const void        *const: ((const type *) (obj)), \
                const void        *     : ((const type *) (obj)), \
                      void        *const: ((      type *) (obj)), \
@@ -573,8 +267,8 @@ NM_G_ERROR_MSG(GError *error)
                const type        *     : ((const type *) (obj)), \
                      type        *const: ((      type *) (obj)), \
                      type        *     : ((      type *) (obj))))
-    #define _NM_CONSTCAST_FULL_4(type, obj_expr, obj, alias_type2, alias_type3, alias_type4) \
-        (_Generic ((obj_expr), \
+#define _NM_CONSTCAST_FULL_4(type, obj_expr, obj, alias_type2, alias_type3, alias_type4) \
+    (_Generic ((obj_expr), \
                const void        *const: ((const type *) (obj)), \
                const void        *     : ((const type *) (obj)), \
                      void        *const: ((      type *) (obj)), \
@@ -595,34 +289,34 @@ NM_G_ERROR_MSG(GError *error)
                const type        *     : ((const type *) (obj)), \
                      type        *const: ((      type *) (obj)), \
                      type        *     : ((      type *) (obj))))
-    #define _NM_CONSTCAST_FULL_x(type, obj_expr, obj, n, ...) \
-        (_NM_CONSTCAST_FULL_##n(type, obj_expr, obj, ##__VA_ARGS__))
-    #define _NM_CONSTCAST_FULL_y(type, obj_expr, obj, n, ...) \
-        (_NM_CONSTCAST_FULL_x(type, obj_expr, obj, n, ##__VA_ARGS__))
-    #define NM_CONSTCAST_FULL(type, obj_expr, obj, ...) \
-        (_NM_CONSTCAST_FULL_y(type, obj_expr, obj, NM_NARG(dummy, ##__VA_ARGS__), ##__VA_ARGS__))
+#define _NM_CONSTCAST_FULL_x(type, obj_expr, obj, n, ...) \
+    (_NM_CONSTCAST_FULL_##n(type, obj_expr, obj, ##__VA_ARGS__))
+#define _NM_CONSTCAST_FULL_y(type, obj_expr, obj, n, ...) \
+    (_NM_CONSTCAST_FULL_x(type, obj_expr, obj, n, ##__VA_ARGS__))
+#define NM_CONSTCAST_FULL(type, obj_expr, obj, ...) \
+    (_NM_CONSTCAST_FULL_y(type, obj_expr, obj, NM_NARG(dummy, ##__VA_ARGS__), ##__VA_ARGS__))
 #else
-    #define NM_CONSTCAST_FULL(type, obj_expr, obj, ...) ((type *) (obj))
+#define NM_CONSTCAST_FULL(type, obj_expr, obj, ...) ((type *) (obj))
 #endif
 
 #define NM_CONSTCAST(type, obj, ...) NM_CONSTCAST_FULL(type, (obj), (obj), ##__VA_ARGS__)
 
 #if _NM_CC_SUPPORT_GENERIC
-    #define NM_UNCONST_PTR(type, arg) \
-        _Generic((arg), const type * : ((type *) (arg)), type * : ((type *) (arg)))
+#define NM_UNCONST_PTR(type, arg) \
+    _Generic((arg), const type * : ((type *) (arg)), type * : ((type *) (arg)))
 #else
-    #define NM_UNCONST_PTR(type, arg) ((type *) (arg))
+#define NM_UNCONST_PTR(type, arg) ((type *) (arg))
 #endif
 
 #if _NM_CC_SUPPORT_GENERIC
-    #define NM_UNCONST_PPTR(type, arg) \
-        _Generic ((arg), \
+#define NM_UNCONST_PPTR(type, arg) \
+    _Generic ((arg), \
               const type *     *: ((type **) (arg)), \
                     type *     *: ((type **) (arg)), \
               const type *const*: ((type **) (arg)), \
                     type *const*: ((type **) (arg)))
 #else
-    #define NM_UNCONST_PPTR(type, arg) ((type **) (arg))
+#define NM_UNCONST_PPTR(type, arg) ((type **) (arg))
 #endif
 
 #define NM_GOBJECT_CAST(type, obj, is_check, ...)                     \
@@ -649,71 +343,42 @@ NM_G_ERROR_MSG(GError *error)
         _ptr;                     \
     })
 
-#if _NM_CC_SUPPORT_GENERIC
-    /* returns @value, if the type of @value matches @type.
-     * This requires support for C11 _Generic(). If no support is
-     * present, this returns @value directly.
-     *
-     * It's useful to check the let the compiler ensure that @value is
-     * of a certain type. */
-    #define _NM_ENSURE_TYPE(type, value) (_Generic((value), type : (value)))
-    #define _NM_ENSURE_TYPE_CONST(type, value)               \
-        (_Generic((value), const type                        \
-                  : ((const type) (value)), const type const \
-                  : ((const type) (value)), type             \
-                  : ((const type) (value)), type const       \
-                  : ((const type) (value))))
-#else
-    #define _NM_ENSURE_TYPE(type, value)       (value)
-    #define _NM_ENSURE_TYPE_CONST(type, value) ((const type) (value))
-#endif
-
-#if _NM_CC_SUPPORT_GENERIC && (!defined(__clang__) || __clang_major__ > 3)
-    #define NM_STRUCT_OFFSET_ENSURE_TYPE(type, container, field) \
-        (_Generic((&(((container *) NULL)->field))[0], type : G_STRUCT_OFFSET(container, field)))
-#else
-    #define NM_STRUCT_OFFSET_ENSURE_TYPE(type, container, field) G_STRUCT_OFFSET(container, field)
-#endif
-
 /* Casts (arg) to (type**), but also having a compile time check that
  * the arg is some sort of pointer to a pointer.
  *
  * The only purpose of this macro is some additional compile time safety,
  * that the argument is a pointer to pointer. But then it will C cast any kind
  * of such argument. */
-#define NM_CAST_PPTR(type, arg)                                   \
-    ({                                                            \
-        typeof(*(arg)) *const        _arg  = (arg);               \
-        typeof(*_arg)                _arg2 = _arg ? *_arg : NULL; \
-        _nm_unused const void *const _arg3 = _arg2;               \
-                                                                  \
-        (type **) _arg;                                           \
+#define NM_CAST_PPTR(type, arg)     \
+    ({                              \
+        _NM_ENSURE_POINTER(*(arg)); \
+        (type **) (arg);            \
     })
 
 #if _NM_CC_SUPPORT_GENERIC
-    /* these macros cast (value) to
-     *  - "const char **"      (for "MC", mutable-const)
-     *  - "const char *const*" (for "CC", const-const)
-     * The point is to do this cast, but only accepting pointers
-     * that are compatible already.
-     *
-     * The problem is, if you add a function like g_strdupv(), the input
-     * argument is not modified (CC), but you want to make it work also
-     * for "char **". C doesn't allow this form of casting (for good reasons),
-     * so the function makes a choice like g_strdupv(char**). That means,
-     * every time you want to call it with a const argument, you need to
-     * explicitly cast it.
-     *
-     * These macros do the cast, but they only accept a compatible input
-     * type, otherwise they will fail compilation.
-     */
-    #define NM_CAST_STRV_MC(value) \
-        (_Generic ((value), \
+/* these macros cast (value) to
+ *  - "const char **"      (for "MC", mutable-const)
+ *  - "const char *const*" (for "CC", const-const)
+ * The point is to do this cast, but only accepting pointers
+ * that are compatible already.
+ *
+ * The problem is, if you add a function like g_strdupv(), the input
+ * argument is not modified (CC), but you want to make it work also
+ * for "char **". C doesn't allow this form of casting (for good reasons),
+ * so the function makes a choice like g_strdupv(char**). That means,
+ * every time you want to call it with a const argument, you need to
+ * explicitly cast it.
+ *
+ * These macros do the cast, but they only accept a compatible input
+ * type, otherwise they will fail compilation.
+ */
+#define NM_CAST_STRV_MC(value) \
+    (_Generic ((value), \
                const char *     *: (const char *     *) (value), \
                      char *     *: (const char *     *) (value), \
                            void *: (const char *     *) (value)))
-    #define NM_CAST_STRV_CC(value) \
-        (_Generic ((value), \
+#define NM_CAST_STRV_CC(value) \
+    (_Generic ((value), \
                const char *const*: (const char *const*) (value), \
                const char *     *: (const char *const*) (value), \
                      char *const*: (const char *const*) (value), \
@@ -727,18 +392,18 @@ NM_G_ERROR_MSG(GError *error)
                      const void *const: (const char *const*) (value), \
                            void *const: (const char *const*) (value)))
 #else
-    #define NM_CAST_STRV_MC(value) ((const char **) (value))
-    #define NM_CAST_STRV_CC(value) ((const char *const *) (value))
+#define NM_CAST_STRV_MC(value) ((const char **) (value))
+#define NM_CAST_STRV_CC(value) ((const char *const *) (value))
 #endif
 
 #if _NM_CC_SUPPORT_GENERIC
-    #define NM_PROPAGATE_CONST(test_expr, ptr) \
-        (_Generic ((test_expr), \
+#define NM_PROPAGATE_CONST(test_expr, ptr) \
+    (_Generic ((test_expr), \
                const typeof (*(test_expr)) *: ((const typeof (*(ptr)) *) (ptr)), \
                                      default: (_Generic ((test_expr), \
                                                          typeof (*(test_expr)) *: (ptr)))))
 #else
-    #define NM_PROPAGATE_CONST(test_expr, ptr) (ptr)
+#define NM_PROPAGATE_CONST(test_expr, ptr) (ptr)
 #endif
 
 /* with the way it is implemented, the caller may or may not pass a trailing
@@ -958,16 +623,16 @@ nm_str_realloc(char *str)
 #define _NM_GET_PRIVATE(self, type, is_check, ...) \
     (&(NM_GOBJECT_CAST_NON_NULL(type, (self), is_check, ##__VA_ARGS__)->_priv))
 #if _NM_CC_SUPPORT_AUTO_TYPE
-    #define _NM_GET_PRIVATE_PTR(self, type, is_check, ...)                       \
-        ({                                                                       \
-            _nm_auto_type _self_get_private =                                    \
-                NM_GOBJECT_CAST_NON_NULL(type, (self), is_check, ##__VA_ARGS__); \
-                                                                                 \
-            NM_PROPAGATE_CONST(_self_get_private, _self_get_private->_priv);     \
-        })
+#define _NM_GET_PRIVATE_PTR(self, type, is_check, ...)                       \
+    ({                                                                       \
+        _nm_auto_type _self_get_private =                                    \
+            NM_GOBJECT_CAST_NON_NULL(type, (self), is_check, ##__VA_ARGS__); \
+                                                                             \
+        NM_PROPAGATE_CONST(_self_get_private, _self_get_private->_priv);     \
+    })
 #else
-    #define _NM_GET_PRIVATE_PTR(self, type, is_check, ...) \
-        (NM_GOBJECT_CAST_NON_NULL(type, (self), is_check, ##__VA_ARGS__)->_priv)
+#define _NM_GET_PRIVATE_PTR(self, type, is_check, ...) \
+    (NM_GOBJECT_CAST_NON_NULL(type, (self), is_check, ##__VA_ARGS__)->_priv)
 #endif
 
 /*****************************************************************************/
@@ -1225,6 +890,12 @@ nm_g_variant_take_ref(GVariant *v)
     return v;
 }
 
+static inline gboolean
+nm_g_variant_equal(GVariant *a, GVariant *b)
+{
+    return (a == b) || (a && b && g_variant_equal(a, b));
+}
+
 /*****************************************************************************/
 
 #define NM_DIV_ROUND_UP(x, y)     \
@@ -1245,27 +916,21 @@ nm_g_variant_take_ref(GVariant *v)
         return (v);                          \
     }
 #define NM_UTILS_LOOKUP_ITEM(v, n) \
-    (void) 0;                      \
-case v:                            \
-    return (n);                    \
-    (void) 0
+    case v:                        \
+        return (n);
 #define NM_UTILS_LOOKUP_STR_ITEM(v, n) NM_UTILS_LOOKUP_ITEM(v, "" n "")
 #define NM_UTILS_LOOKUP_ITEM_IGNORE(v) \
-    (void) 0;                          \
-case v:                                \
-    break;                             \
-    (void) 0
+    case v:                            \
+        break;
 #define NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER() \
-    (void) 0;                               \
-default:                                    \
-    break;                                  \
-    (void) 0
+    default:                                \
+        break;
 
 #define NM_UTILS_LOOKUP_DEFINE(fcn_name, lookup_type, result_type, unknown_val, ...) \
     result_type fcn_name(lookup_type val)                                            \
     {                                                                                \
         switch (val) {                                                               \
-            (void) 0, __VA_ARGS__(void) 0;                                           \
+            NM_VA_ARGS_JOIN(, __VA_ARGS__)                                           \
         };                                                                           \
         {                                                                            \
             unknown_val;                                                             \
@@ -1471,17 +1136,15 @@ nm_strcmp_p(gconstpointer a, gconstpointer b)
 /*****************************************************************************/
 
 static inline int
-_NM_IN_STRSET_ASCII_CASE_op_streq(const char *x, const char *s)
+_NM_IN_STRSET_EVAL_op_streq_ascii_case(const char *x1, const char *x)
 {
-    return s && g_ascii_strcasecmp(x, s) == 0;
+    return x && g_ascii_strcasecmp(x1, x) == 0;
 }
 
-#define NM_IN_STRSET_ASCII_CASE(x, ...)                     \
-    _NM_IN_STRSET_EVAL_N(||,                                \
-                         _NM_IN_STRSET_ASCII_CASE_op_streq, \
-                         x,                                 \
-                         NM_NARG(__VA_ARGS__),              \
-                         __VA_ARGS__)
+#define _NM_IN_STRSET_EVAL_OP_STREQ_ASCII_CASE(x, idx) \
+    _NM_IN_STRSET_EVAL_op_streq_ascii_case(_x1, x)
+#define NM_IN_STRSET_ASCII_CASE(x1, ...) \
+    _NM_IN_STRSET_EVAL(||, _NM_IN_STRSET_EVAL_OP_STREQ_ASCII_CASE, x1, __VA_ARGS__)
 
 #define NM_STR_HAS_SUFFIX_ASCII_CASE(str, suffix)                                               \
     ({                                                                                          \
@@ -1511,6 +1174,25 @@ _NM_IN_STRSET_ASCII_CASE_op_streq(const char *x, const char *s)
 
 /*****************************************************************************/
 
+static inline int
+nm_memcmp_n(gconstpointer p1, gsize len1, gconstpointer p2, gsize len2, gsize element_size)
+{
+    nm_assert(element_size > 0);
+
+    NM_CMP_DIRECT(len1, len2);
+    if (len1 > 0)
+        NM_CMP_DIRECT_MEMCMP(p1, p2, len1 * element_size);
+    return 0;
+}
+
+static inline int
+nm_memeq_n(gconstpointer p1, gsize len1, gconstpointer p2, gsize len2, gsize element_size)
+{
+    return nm_memcmp_n(p1, len1, p2, len2, element_size) == 0;
+}
+
+/*****************************************************************************/
+
 /* like g_memdup(). The difference is that the @size argument is of type
  * gsize, while g_memdup() has type guint. Since, the size of container types
  * like GArray is guint as well, this means trying to g_memdup() an
@@ -1668,28 +1350,28 @@ _nm_strndup_a_step(char *s, const char *str, gsize len)
  *
  * Instead, this generic macro is supposed to handle all integers correctly. */
 #if _NM_CC_SUPPORT_GENERIC
-    #define nm_strdup_int(val)                                                       \
-        _Generic((val), char                                                         \
-                 : g_strdup_printf("%d", (int) (val)),                               \
-                                                                                     \
-                   signed char                                                       \
-                 : g_strdup_printf("%d", (signed) (val)), signed short               \
-                 : g_strdup_printf("%d", (signed) (val)), signed                     \
-                 : g_strdup_printf("%d", (signed) (val)), signed long                \
-                 : g_strdup_printf("%ld", (signed long) (val)), signed long long     \
-                 : g_strdup_printf("%lld", (signed long long) (val)),                \
-                                                                                     \
-                   unsigned char                                                     \
-                 : g_strdup_printf("%u", (unsigned) (val)), unsigned short           \
-                 : g_strdup_printf("%u", (unsigned) (val)), unsigned                 \
-                 : g_strdup_printf("%u", (unsigned) (val)), unsigned long            \
-                 : g_strdup_printf("%lu", (unsigned long) (val)), unsigned long long \
-                 : g_strdup_printf("%llu", (unsigned long long) (val)))
+#define nm_strdup_int(val)                                                       \
+    _Generic((val), char                                                         \
+             : g_strdup_printf("%d", (int) (val)),                               \
+                                                                                 \
+               signed char                                                       \
+             : g_strdup_printf("%d", (signed) (val)), signed short               \
+             : g_strdup_printf("%d", (signed) (val)), signed                     \
+             : g_strdup_printf("%d", (signed) (val)), signed long                \
+             : g_strdup_printf("%ld", (signed long) (val)), signed long long     \
+             : g_strdup_printf("%lld", (signed long long) (val)),                \
+                                                                                 \
+               unsigned char                                                     \
+             : g_strdup_printf("%u", (unsigned) (val)), unsigned short           \
+             : g_strdup_printf("%u", (unsigned) (val)), unsigned                 \
+             : g_strdup_printf("%u", (unsigned) (val)), unsigned long            \
+             : g_strdup_printf("%lu", (unsigned long) (val)), unsigned long long \
+             : g_strdup_printf("%llu", (unsigned long long) (val)))
 #else
-    #define nm_strdup_int(val)                                        \
-        ((sizeof(val) == sizeof(guint64) && ((typeof(val)) -1) > 0)   \
-             ? g_strdup_printf("%" G_GUINT64_FORMAT, (guint64) (val)) \
-             : g_strdup_printf("%" G_GINT64_FORMAT, (gint64) (val)))
+#define nm_strdup_int(val)                                        \
+    ((sizeof(val) == sizeof(guint64) && ((typeof(val)) -1) > 0)   \
+         ? g_strdup_printf("%" G_GUINT64_FORMAT, (guint64) (val)) \
+         : g_strdup_printf("%" G_GINT64_FORMAT, (gint64) (val)))
 #endif
 
 /*****************************************************************************/
@@ -1877,7 +1559,7 @@ nm_decode_version(guint version, guint *major, guint *minor, guint *micro)
 /*****************************************************************************/
 
 #ifdef _G_BOOLEAN_EXPR
-    /* g_assert() uses G_LIKELY(), which in turn uses _G_BOOLEAN_EXPR().
+/* g_assert() uses G_LIKELY(), which in turn uses _G_BOOLEAN_EXPR().
  * As glib's implementation uses a local variable _g_boolean_var_,
  * we cannot do
  *   g_assert (some_macro ());
@@ -1887,8 +1569,8 @@ nm_decode_version(guint version, guint *major, guint *minor, guint *micro)
  *
  * Workaround that by re-defining _G_BOOLEAN_EXPR()
  **/
-    #undef _G_BOOLEAN_EXPR
-    #define _G_BOOLEAN_EXPR(expr) NM_BOOLEAN_EXPR(expr)
+#undef _G_BOOLEAN_EXPR
+#define _G_BOOLEAN_EXPR(expr) NM_BOOLEAN_EXPR(expr)
 #endif
 
 /*****************************************************************************/
@@ -1913,4 +1595,22 @@ NM_AUTO_DEFINE_FCN_VOID0(GMutex *, _nm_auto_unlock_g_mutex, g_mutex_unlock);
 
 /*****************************************************************************/
 
+static inline GObject *
+nm_g_object_freeze_notify(gpointer obj)
+{
+    if (obj)
+        g_object_freeze_notify(obj);
+    return obj;
+}
+
+static inline void
+nm_g_object_thaw_notify_clear(GObject **p_obj)
+{
+    nm_clear_pointer(p_obj, g_object_thaw_notify);
+}
+
+#define nm_auto_g_object_thaw_notify nm_auto(nm_g_object_thaw_notify_clear)
+
+/*****************************************************************************/
+
 #endif /* __NM_MACROS_INTERNAL_H__ */
diff --git a/src/libnm-glib-aux/nm-random-utils.c b/src/libnm-glib-aux/nm-random-utils.c
index b055bc3f..2f42f3f6 100644
--- a/src/libnm-glib-aux/nm-random-utils.c
+++ b/src/libnm-glib-aux/nm-random-utils.c
@@ -12,9 +12,9 @@
 #include <sys/syscall.h>
 
 #if USE_SYS_RANDOM_H
-    #include <sys/random.h>
+#include <sys/random.h>
 #else
-    #include <linux/random.h>
+#include <linux/random.h>
 #endif
 
 #include "nm-shared-utils.h"
@@ -23,15 +23,15 @@
 /*****************************************************************************/
 
 #if !defined(SYS_getrandom) && defined(__NR_getrandom)
-    #define SYS_getrandom __NR_getrandom
+#define SYS_getrandom __NR_getrandom
 #endif
 
 #ifndef GRND_NONBLOCK
-    #define GRND_NONBLOCK 0x01
+#define GRND_NONBLOCK 0x01
 #endif
 
 #ifndef GRND_INSECURE
-    #define GRND_INSECURE 0x04
+#define GRND_INSECURE 0x04
 #endif
 
 #if !HAVE_GETRANDOM && defined(SYS_getrandom)
@@ -40,8 +40,8 @@ getrandom(void *buf, size_t buflen, unsigned flags)
 {
     return syscall(SYS_getrandom, buf, buflen, flags);
 }
-    #undef HAVE_GETRANDOM
-    #define HAVE_GETRANDOM 1
+#undef HAVE_GETRANDOM
+#define HAVE_GETRANDOM 1
 #endif
 
 /*****************************************************************************/
diff --git a/src/libnm-glib-aux/nm-ref-string.h b/src/libnm-glib-aux/nm-ref-string.h
index df37d583..6950d1b9 100644
--- a/src/libnm-glib-aux/nm-ref-string.h
+++ b/src/libnm-glib-aux/nm-ref-string.h
@@ -152,6 +152,18 @@ NM_REF_STRING_UPCAST(const char *str)
     return rstr;
 }
 
+static inline NMRefString *
+nm_ref_string_ref_upcast(const char *str)
+{
+    return nm_ref_string_ref(NM_REF_STRING_UPCAST(str));
+}
+
+static inline void
+nm_ref_string_unref_upcast(const char *str)
+{
+    nm_ref_string_unref(NM_REF_STRING_UPCAST(str));
+}
+
 static inline gboolean
 nm_ref_string_reset_str(NMRefString **ptr, const char *str)
 {
diff --git a/src/libnm-glib-aux/nm-shared-utils.c b/src/libnm-glib-aux/nm-shared-utils.c
index 81852aea..9d1a1bf1 100644
--- a/src/libnm-glib-aux/nm-shared-utils.c
+++ b/src/libnm-glib-aux/nm-shared-utils.c
@@ -12,7 +12,6 @@
 #include <poll.h>
 #include <fcntl.h>
 #include <sys/syscall.h>
-#include <glib-unix.h>
 #include <net/if.h>
 #include <net/ethernet.h>
 #include <pthread.h>
@@ -100,6 +99,29 @@ nm_ip_addr_set_from_untrusted(int           addr_family,
     return TRUE;
 }
 
+gboolean
+nm_ip_addr_set_from_variant(int addr_family, gpointer dst, GVariant *variant, int *out_addr_family)
+{
+    gconstpointer bytes;
+    gsize         len;
+
+    g_return_val_if_fail(dst, FALSE);
+    g_return_val_if_fail(variant, FALSE);
+
+    /* This function always expects IP addressea a byte arrays ("ay"). Note that
+     * several NetworkManager API uses "u" (32 bit unsigned intergers) for IPv4 addresses.
+     * So this function won't work in those cases.
+     *
+     * Btw, using "u" for IPv4 address messes badly with the endianness (host
+     * vs network byte order). Don't do that.
+     */
+    g_return_val_if_fail(g_variant_is_of_type(variant, G_VARIANT_TYPE("ay")), FALSE);
+
+    bytes = g_variant_get_fixed_array(variant, &len, sizeof(guint8));
+
+    return nm_ip_addr_set_from_untrusted(addr_family, dst, bytes, len, out_addr_family);
+}
+
 /*****************************************************************************/
 
 G_STATIC_ASSERT(ETH_ALEN == sizeof(struct ether_addr));
@@ -141,9 +163,9 @@ _nm_utils_inet6_is_token(const struct in6_addr *in6addr)
  * token.
  */
 void
-nm_utils_ipv6_addr_set_interface_identifier(struct in6_addr *addr, const NMUtilsIPv6IfaceId iid)
+nm_utils_ipv6_addr_set_interface_identifier(struct in6_addr *addr, const NMUtilsIPv6IfaceId *iid)
 {
-    memcpy(addr->s6_addr + 8, &iid.id_u8, 8);
+    memcpy(addr->s6_addr + 8, &iid->id_u8, 8);
 }
 
 /**
@@ -199,8 +221,8 @@ nm_utils_ipv6_interface_identifier_get_from_token(NMUtilsIPv6IfaceId *iid, const
  * Returns: the input buffer filled with the id as string.
  */
 const char *
-nm_utils_inet6_interface_identifier_to_token(NMUtilsIPv6IfaceId iid,
-                                             char               buf[static INET6_ADDRSTRLEN])
+nm_utils_inet6_interface_identifier_to_token(const NMUtilsIPv6IfaceId *iid,
+                                             char                      buf[static INET6_ADDRSTRLEN])
 {
     struct in6_addr i6_token = {.s6_addr = {
                                     0,
@@ -264,7 +286,7 @@ _nm_assert_on_main_thread(void)
 /*****************************************************************************/
 
 void
-nm_utils_strbuf_append_c(char **buf, gsize *len, char c)
+nm_strbuf_append_c(char **buf, gsize *len, char c)
 {
     switch (*len) {
     case 0:
@@ -284,7 +306,7 @@ nm_utils_strbuf_append_c(char **buf, gsize *len, char c)
 }
 
 void
-nm_utils_strbuf_append_bin(char **buf, gsize *len, gconstpointer str, gsize str_len)
+nm_strbuf_append_bin(char **buf, gsize *len, gconstpointer str, gsize str_len)
 {
     switch (*len) {
     case 0:
@@ -319,7 +341,7 @@ nm_utils_strbuf_append_bin(char **buf, gsize *len, gconstpointer str, gsize str_
 }
 
 void
-nm_utils_strbuf_append_str(char **buf, gsize *len, const char *str)
+nm_strbuf_append_str(char **buf, gsize *len, const char *str)
 {
     gsize src_len;
 
@@ -353,7 +375,7 @@ nm_utils_strbuf_append_str(char **buf, gsize *len, const char *str)
 }
 
 void
-nm_utils_strbuf_append(char **buf, gsize *len, const char *format, ...)
+nm_strbuf_append(char **buf, gsize *len, const char *format, ...)
 {
     char *  p = *buf;
     va_list args;
@@ -376,25 +398,25 @@ nm_utils_strbuf_append(char **buf, gsize *len, const char *format, ...)
 }
 
 /**
- * nm_utils_strbuf_seek_end:
+ * nm_strbuf_seek_end:
  * @buf: the input/output buffer
  * @len: the input/output length of the buffer.
  *
- * Commonly, one uses nm_utils_strbuf_append*(), to incrementally
+ * Commonly, one uses nm_strbuf_append*(), to incrementally
  * append strings to the buffer. However, sometimes we need to use
  * existing API to write to the buffer.
  * After doing so, we want to adjust the buffer counter.
  * Essentially,
  *
  *   g_snprintf (buf, len, ...);
- *   nm_utils_strbuf_seek_end (&buf, &len);
+ *   nm_strbuf_seek_end (&buf, &len);
  *
  * is almost the same as
  *
- *   nm_utils_strbuf_append (&buf, &len, ...);
+ *   nm_strbuf_append (&buf, &len, ...);
  *
  * The only difference is the behavior when the string got truncated:
- * nm_utils_strbuf_append() will recognize that and set the remaining
+ * nm_strbuf_append() will recognize that and set the remaining
  * length to zero.
  *
  * In general, the behavior is:
@@ -412,13 +434,13 @@ nm_utils_strbuf_append(char **buf, gsize *len, const char *format, ...)
  *    the NUL byte. This would happen with
  *
  *       strncpy (buf, long_str, len);
- *       nm_utils_strbuf_seek_end (&buf, &len).
+ *       nm_strbuf_seek_end (&buf, &len).
  *
  *    where strncpy() does truncate the string and not NUL terminate it.
- *    nm_utils_strbuf_seek_end() would then NUL terminate it.
+ *    nm_strbuf_seek_end() would then NUL terminate it.
  */
 void
-nm_utils_strbuf_seek_end(char **buf, gsize *len)
+nm_strbuf_seek_end(char **buf, gsize *len)
 {
     gsize l;
     char *end;
@@ -455,7 +477,7 @@ truncate:
 /*****************************************************************************/
 
 GBytes *
-nm_gbytes_get_empty(void)
+nm_g_bytes_get_empty(void)
 {
     static GBytes *bytes = NULL;
     GBytes *       b;
@@ -487,8 +509,18 @@ nm_g_bytes_new_from_str(const char *str)
     return g_bytes_new_take(nm_memdup(str, l + 1u), l);
 }
 
+GBytes *
+nm_g_bytes_new_from_variant_ay(GVariant *var)
+{
+    if (!var)
+        return NULL;
+    if (!g_variant_is_of_type(var, G_VARIANT_TYPE_BYTESTRING))
+        g_return_val_if_reached(NULL);
+    return g_variant_get_data_as_bytes(var);
+}
+
 /**
- * nm_utils_gbytes_equal_mem:
+ * nm_g_bytes_equal_mem:
  * @bytes: (allow-none): a #GBytes array to compare. Note that
  *   %NULL is treated like an #GBytes array of length zero.
  * @mem_data: the data pointer with @mem_len bytes
@@ -498,7 +530,7 @@ nm_g_bytes_new_from_str(const char *str)
  *   special case, a %NULL @bytes is treated like an empty array.
  */
 gboolean
-nm_utils_gbytes_equal_mem(GBytes *bytes, gconstpointer mem_data, gsize mem_len)
+nm_g_bytes_equal_mem(GBytes *bytes, gconstpointer mem_data, gsize mem_len)
 {
     gconstpointer p;
     gsize         l;
@@ -516,7 +548,7 @@ nm_utils_gbytes_equal_mem(GBytes *bytes, gconstpointer mem_data, gsize mem_len)
 }
 
 GVariant *
-nm_utils_gbytes_to_variant_ay(GBytes *bytes)
+nm_g_bytes_to_variant_ay(const GBytes *bytes)
 {
     const guint8 *p = NULL;
     gsize         l = 0;
@@ -524,7 +556,7 @@ nm_utils_gbytes_to_variant_ay(GBytes *bytes)
     if (!bytes) {
         /* for convenience, accept NULL to return an empty variant */
     } else
-        p = g_bytes_get_data(bytes, &l);
+        p = g_bytes_get_data((GBytes *) bytes, &l);
 
     return nm_g_variant_new_ay(p, l);
 }
@@ -560,6 +592,12 @@ nm_g_variant_singleton_u_0(void)
 }
 
 GVariant *
+nm_g_variant_singleton_i_0(void)
+{
+    return _variant_singleton_get(g_variant_new_int32(0));
+}
+
+GVariant *
 nm_g_variant_singleton_b(gboolean value)
 {
     return value ? _variant_singleton_get(g_variant_new_boolean(TRUE))
@@ -603,6 +641,24 @@ _variant_singleton_get_array_init(GVariant **p_singleton, const char *variant_ty
     })
 
 GVariant *
+nm_g_variant_singleton_au(void)
+{
+    return _variant_singleton_get_array("u");
+}
+
+GVariant *
+nm_g_variant_singleton_aay(void)
+{
+    return _variant_singleton_get_array("ay");
+}
+
+GVariant *
+nm_g_variant_singleton_as(void)
+{
+    return _variant_singleton_get_array("s");
+}
+
+GVariant *
 nm_g_variant_singleton_aLsvI(void)
 {
     return _variant_singleton_get_array("{sv}");
@@ -620,10 +676,37 @@ nm_g_variant_singleton_aaLsvI(void)
     return _variant_singleton_get_array("a{sv}");
 }
 
+GVariant *
+nm_g_variant_singleton_ao(void)
+{
+    return _variant_singleton_get_array("o");
+}
+
+GVariant *
+nm_g_variant_maybe_singleton_i(gint32 value)
+{
+    /* Warning: this function always returns a non-floating reference
+     * that must be consumed (and later unrefed) by the caller.
+     *
+     * The instance is either a singleton instance or a newly created
+     * instance.
+     *
+     * The idea of this is that common values (zero) can use the immutable
+     * singleton/flyweight instance and avoid allocating a new instance in
+     * the (presumable) common case.
+     */
+    switch (value) {
+    case 0:
+        return g_variant_ref(nm_g_variant_singleton_i_0());
+    default:
+        return g_variant_take_ref(g_variant_new_int32(value));
+    }
+}
+
 /*****************************************************************************/
 
 GHashTable *
-nm_utils_strdict_clone(GHashTable *src)
+nm_strdict_clone(GHashTable *src)
 {
     GHashTable *   dst;
     GHashTableIter iter;
@@ -645,7 +728,7 @@ nm_utils_strdict_clone(GHashTable *src)
  * Returns a floating reference.
  */
 GVariant *
-nm_utils_strdict_to_variant_ass(GHashTable *strdict)
+nm_strdict_to_variant_ass(GHashTable *strdict)
 {
     gs_free NMUtilsNamedValue *values_free = NULL;
     NMUtilsNamedValue          values_prepared[20];
@@ -666,7 +749,7 @@ nm_utils_strdict_to_variant_ass(GHashTable *strdict)
 /*****************************************************************************/
 
 GVariant *
-nm_utils_strdict_to_variant_asv(GHashTable *strdict)
+nm_strdict_to_variant_asv(GHashTable *strdict)
 {
     gs_free NMUtilsNamedValue *values_free = NULL;
     NMUtilsNamedValue          values_prepared[20];
@@ -715,7 +798,7 @@ nm_strquote(char *buf, gsize buf_len, const char *str)
     const char *const buf0 = buf;
 
     if (!str) {
-        nm_utils_strbuf_append_str(&buf, &buf_len, "(null)");
+        nm_strbuf_append_str(&buf, &buf_len, "(null)");
         goto out;
     }
 
@@ -734,7 +817,7 @@ nm_strquote(char *buf, gsize buf_len, const char *str)
     *(buf++) = '"';
     buf_len--;
 
-    nm_utils_strbuf_append_str(&buf, &buf_len, str);
+    nm_strbuf_append_str(&buf, &buf_len, str);
 
     /* if the string was too long we indicate truncation with a
      * '^' instead of a closing quote. */
@@ -762,7 +845,7 @@ out:
 
 /*****************************************************************************/
 
-char _nm_utils_to_string_buffer[];
+_nm_thread_local char _nm_utils_to_string_buffer[] = {0};
 
 void
 nm_utils_to_string_buffer_init(char **buf, gsize *len)
@@ -818,7 +901,7 @@ nm_utils_flags2str(const NMUtilsFlags2StrDesc *descs,
     if (!flags) {
         for (i = 0; i < n_descs; i++) {
             if (!descs[i].flag) {
-                nm_utils_strbuf_append_str(&p, &len, descs[i].name);
+                nm_strbuf_append_str(&p, &len, descs[i].name);
                 break;
             }
         }
@@ -830,14 +913,14 @@ nm_utils_flags2str(const NMUtilsFlags2StrDesc *descs,
             flags &= ~descs[i].flag;
 
             if (buf[0] != '\0')
-                nm_utils_strbuf_append_c(&p, &len, ',');
-            nm_utils_strbuf_append_str(&p, &len, descs[i].name);
+                nm_strbuf_append_c(&p, &len, ',');
+            nm_strbuf_append_str(&p, &len, descs[i].name);
         }
     }
     if (flags) {
         if (buf[0] != '\0')
-            nm_utils_strbuf_append_c(&p, &len, ',');
-        nm_utils_strbuf_append(&p, &len, "0x%x", flags);
+            nm_strbuf_append_c(&p, &len, ',');
+        nm_strbuf_append(&p, &len, "0x%x", flags);
     }
     return buf;
 };
@@ -1733,7 +1816,7 @@ _char_lookup_has_all(const CharLookupTable *lookup, const char *candidates)
 }
 
 /**
- * nm_utils_strsplit_set_full:
+ * nm_strsplit_set_full:
  * @str: the string to split.
  * @delimiters: the set of delimiters.
  * @flags: additional flags for controlling the operation.
@@ -1747,7 +1830,7 @@ _char_lookup_has_all(const CharLookupTable *lookup, const char *candidates)
  * This never returns an empty array.
  *
  * Returns: %NULL if @str is %NULL or "".
- *   If @str only contains delimiters and %NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY
+ *   If @str only contains delimiters and %NM_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY
  *   is not set, it also returns %NULL.
  *   Otherwise, a %NULL terminated strv array containing the split words.
  *   (delimiter characters are removed).
@@ -1758,7 +1841,7 @@ _char_lookup_has_all(const CharLookupTable *lookup, const char *candidates)
  *   like "g_strstrip((char *) iter[0])".
  */
 const char **
-nm_utils_strsplit_set_full(const char *str, const char *delimiters, NMUtilsStrsplitSetFlags flags)
+nm_strsplit_set_full(const char *str, const char *delimiters, NMUtilsStrsplitSetFlags flags)
 {
     const char **   ptr;
     gsize           num_tokens;
@@ -1767,12 +1850,11 @@ nm_utils_strsplit_set_full(const char *str, const char *delimiters, NMUtilsStrsp
     const char *    c_str;
     char *          s;
     CharLookupTable ch_lookup;
-    const gboolean  f_escaped = NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED);
+    const gboolean  f_escaped = NM_FLAGS_HAS(flags, NM_STRSPLIT_SET_FLAGS_ESCAPED);
     const gboolean  f_allow_escaping =
-        f_escaped || NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING);
-    const gboolean f_preserve_empty =
-        NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY);
-    const gboolean f_strstrip = NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP);
+        f_escaped || NM_FLAGS_HAS(flags, NM_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING);
+    const gboolean f_preserve_empty = NM_FLAGS_HAS(flags, NM_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY);
+    const gboolean f_strstrip       = NM_FLAGS_HAS(flags, NM_STRSPLIT_SET_FLAGS_STRSTRIP);
 
     if (!str)
         return NULL;
@@ -1791,8 +1873,8 @@ nm_utils_strsplit_set_full(const char *str, const char *delimiters, NMUtilsStrsp
     }
 
     if (!str[0]) {
-        /* We return %NULL here, also with NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY.
-         * That makes nm_utils_strsplit_set_full() with NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY
+        /* We return %NULL here, also with NM_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY.
+         * That makes nm_strsplit_set_full() with NM_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY
          * different from g_strsplit_set(), which would in this case return an empty array.
          * If you need to handle %NULL, and "" specially, then check the input string first. */
         return NULL;
@@ -2175,7 +2257,7 @@ nm_utils_escaped_tokens_options_split(char *str, const char **out_key, const cha
  * with the flags "EXTRACT_UNQUOTE | EXTRACT_RELAX". This is what
  * systemd uses to parse /proc/cmdline, and we do too.
  *
- * Splits the string. We have nm_utils_strsplit_set() which
+ * Splits the string. We have nm_strsplit_set() which
  * supports a variety of flags. However, extending that already
  * complex code to also support quotation and escaping is hard.
  * Instead, add a naive implementation.
@@ -2262,7 +2344,7 @@ nm_utils_strsplit_quoted(const char *str)
 /*****************************************************************************/
 
 /**
- * nm_utils_strv_find_first:
+ * _nm_strv_find_first:
  * @list: the strv list to search
  * @len: the length of the list, or a negative value if @list is %NULL terminated.
  * @needle: the value to search for. The search is done using strcmp().
@@ -2275,7 +2357,7 @@ nm_utils_strsplit_quoted(const char *str)
  * Returns: index of first occurrence or -1 if @needle is not found in @list.
  */
 gssize
-nm_utils_strv_find_first(char **list, gssize len, const char *needle)
+_nm_strv_find_first(const char *const *list, gssize len, const char *needle)
 {
     gssize i;
 
@@ -2337,13 +2419,80 @@ nm_strv_has_duplicate(const char *const *strv, gssize len, gboolean is_sorted)
     return FALSE;
 }
 
+gboolean
+nm_strv_is_same_unordered(const char *const *strv1,
+                          gssize             len1,
+                          const char *const *strv2,
+                          gssize             len2)
+{
+    gs_free const char **ss1_free = NULL;
+    gs_free const char **ss2_free = NULL;
+    gsize                l2;
+    gsize                l;
+    gsize                i;
+
+    if (len1 < 0)
+        l = NM_PTRARRAY_LEN(strv1);
+    else
+        l = (gsize) len1;
+
+    if (len2 < 0)
+        l2 = NM_PTRARRAY_LEN(strv2);
+    else
+        l2 = (gsize) len2;
+
+    if (l != l2)
+        return FALSE;
+
+    if (l == 0) {
+        /* An empty array. We treat (NULL, -1), (NULL, 0) and ([...], 0)
+         * all the same. */
+        return TRUE;
+    }
+
+    if (l > 1) {
+        strv1 = nm_memdup_maybe_a(300, strv1, sizeof(char *) * l, &ss1_free);
+        strv2 = nm_memdup_maybe_a(300, strv2, sizeof(char *) * l2, &ss2_free);
+        _nm_strv_sort((const char **) strv1, l);
+        _nm_strv_sort((const char **) strv2, l);
+    }
+
+    for (i = 0; i < l; i++) {
+        if (!nm_streq0(strv1[i], strv2[i]))
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+const char **
+nm_strv_cleanup_const(const char **strv, gboolean skip_empty, gboolean skip_repeated)
+{
+    gsize i;
+    gsize j;
+
+    if (!strv || !*strv)
+        return strv;
+
+    if (!skip_empty && !skip_repeated)
+        return strv;
+
+    j = 0;
+    for (i = 0; strv[i]; i++) {
+        if ((skip_empty && !*strv[i])
+            || (skip_repeated && nm_strv_find_first(strv, j, strv[i]) >= 0))
+            continue;
+        strv[j++] = strv[i];
+    }
+    strv[j] = NULL;
+    return strv;
+}
+
 char **
-_nm_utils_strv_cleanup(char **  strv,
-                       gboolean strip_whitespace,
-                       gboolean skip_empty,
-                       gboolean skip_repeated)
+nm_strv_cleanup(char **strv, gboolean strip_whitespace, gboolean skip_empty, gboolean skip_repeated)
 {
-    guint i, j;
+    gsize i;
+    gsize j;
 
     if (!strv || !*strv)
         return strv;
@@ -2359,7 +2508,7 @@ _nm_utils_strv_cleanup(char **  strv,
     j = 0;
     for (i = 0; strv[i]; i++) {
         if ((skip_empty && !*strv[i])
-            || (skip_repeated && nm_utils_strv_find_first(strv, j, strv[i]) >= 0))
+            || (skip_repeated && nm_strv_find_first(strv, j, strv[i]) >= 0))
             g_free(strv[i]);
         else
             strv[j++] = strv[i];
@@ -3762,7 +3911,7 @@ nm_utils_hashtable_cmp(const GHashTable *a,
 }
 
 char **
-nm_utils_strv_make_deep_copied(const char **strv)
+nm_strv_make_deep_copied(const char **strv)
 {
     gsize i;
 
@@ -3779,7 +3928,7 @@ nm_utils_strv_make_deep_copied(const char **strv)
 }
 
 char **
-nm_utils_strv_make_deep_copied_n(const char **strv, gsize len)
+nm_strv_make_deep_copied_n(const char **strv, gsize len)
 {
     gsize i;
 
@@ -3822,7 +3971,7 @@ nm_utils_strv_make_deep_copied_n(const char **strv, gsize len)
  *   cloned or not.
  */
 char **
-_nm_utils_strv_dup(const char *const *strv, gssize len, gboolean deep_copied)
+_nm_strv_dup(const char *const *strv, gssize len, gboolean deep_copied)
 {
     gsize  i, l;
     char **v;
@@ -3858,7 +4007,7 @@ _nm_utils_strv_dup(const char *const *strv, gssize len, gboolean deep_copied)
 }
 
 const char **
-_nm_utils_strv_dup_packed(const char *const *strv, gssize len)
+_nm_strv_dup_packed(const char *const *strv, gssize len)
 
 {
     gs_free gsize *str_len_free = NULL;
@@ -4219,7 +4368,7 @@ nm_utils_get_start_time_for_pid(pid_t pid, char *out_state, pid_t *out_ppid)
 
     state = p[0];
 
-    tokens = nm_utils_strsplit_set(p, " ");
+    tokens = nm_strsplit_set(p, " ");
 
     if (NM_PTRARRAY_LEN(tokens) < 20)
         goto fail;
@@ -4247,7 +4396,7 @@ fail:
 /*****************************************************************************/
 
 /**
- * _nm_utils_strv_sort:
+ * _nm_strv_sort:
  * @strv: pointer containing strings that will be sorted
  *   in-place, %NULL is allowed, unless @len indicates
  *   that there are more elements.
@@ -4261,7 +4410,7 @@ fail:
  * comparison.
  */
 void
-_nm_utils_strv_sort(const char **strv, gssize len)
+_nm_strv_sort(const char **strv, gssize len)
 {
     GCompareDataFunc cmp;
     gsize            l;
@@ -4283,7 +4432,7 @@ _nm_utils_strv_sort(const char **strv, gssize len)
 }
 
 /**
- * _nm_utils_strv_cmp_n:
+ * _nm_strv_cmp_n:
  * @strv1: a string array
  * @len1: the length of @strv1, or -1 for NULL terminated array.
  * @strv2: a string array
@@ -4306,7 +4455,7 @@ _nm_utils_strv_sort(const char **strv, gssize len)
  * Returns: 0 if the arrays are equal (using strcmp).
  **/
 int
-_nm_utils_strv_cmp_n(const char *const *strv1, gssize len1, const char *const *strv2, gssize len2)
+_nm_strv_cmp_n(const char *const *strv1, gssize len1, const char *const *strv2, gssize len2)
 {
     gsize n, n2;
 
@@ -5015,12 +5164,12 @@ nm_g_unix_signal_source_new(int            signum,
 }
 
 GSource *
-nm_g_unix_fd_source_new(int          fd,
-                        GIOCondition io_condition,
-                        int          priority,
-                        gboolean (*source_func)(int fd, GIOCondition condition, gpointer user_data),
-                        gpointer       user_data,
-                        GDestroyNotify destroy_notify)
+nm_g_unix_fd_source_new(int               fd,
+                        GIOCondition      io_condition,
+                        int               priority,
+                        GUnixFDSourceFunc source_func,
+                        gpointer          user_data,
+                        GDestroyNotify    destroy_notify)
 {
     GSource *source;
 
@@ -5032,6 +5181,23 @@ nm_g_unix_fd_source_new(int          fd,
     return source;
 }
 
+GSource *
+nm_g_child_watch_source_new(GPid            pid,
+                            int             priority,
+                            GChildWatchFunc handler,
+                            gpointer        user_data,
+                            GDestroyNotify  notify)
+{
+    GSource *source;
+
+    source = g_child_watch_source_new(pid);
+
+    if (priority != G_PRIORITY_DEFAULT)
+        g_source_set_priority(source, priority);
+    g_source_set_callback(source, G_SOURCE_FUNC(handler), user_data, notify);
+    return source;
+}
+
 /*****************************************************************************/
 
 #define _CTX_LOG(fmt, ...)                                                                       \
@@ -6363,6 +6529,35 @@ nm_utils_get_process_exit_status_desc(int status)
 
 /*****************************************************************************/
 
+gboolean
+nm_utils_validate_hostname(const char *hostname)
+{
+    const char *p;
+    gboolean    dot = TRUE;
+
+    if (!hostname || !hostname[0])
+        return FALSE;
+
+    for (p = hostname; *p; p++) {
+        if (*p == '.') {
+            if (dot)
+                return FALSE;
+            dot = TRUE;
+        } else {
+            if (!g_ascii_isalnum(*p) && (*p != '-') && (*p != '_'))
+                return FALSE;
+            dot = FALSE;
+        }
+    }
+
+    if (dot)
+        return FALSE;
+
+    return (p - hostname <= HOST_NAME_MAX);
+}
+
+/*****************************************************************************/
+
 typedef struct {
     CList          lst;
     gpointer       tls_data;
@@ -6437,3 +6632,33 @@ nm_utils_thread_local_register_destroy(gpointer tls_data, GDestroyNotify destroy
     entry->destroy_notify = destroy_notify;
     c_list_link_tail(lst_head, &entry->lst);
 }
+
+/*****************************************************************************/
+
+static gboolean
+_iterate_for_msec_timeout(gpointer user_data)
+{
+    GSource **p_source = user_data;
+
+    nm_clear_g_source_inst(p_source);
+    return G_SOURCE_CONTINUE;
+}
+
+void
+nm_g_main_context_iterate_for_msec(GMainContext *context, guint timeout_msec)
+{
+    GSource *source;
+
+    /* In production is this function not very useful. It is however useful to
+     * have in the toolbox for printf debugging. */
+
+    source = g_timeout_source_new(timeout_msec);
+    g_source_set_callback(source, _iterate_for_msec_timeout, &source, NULL);
+
+    if (!context)
+        context = g_main_context_default();
+
+    g_source_attach(source, context);
+    while (source)
+        g_main_context_iteration(context, TRUE);
+}
diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h
index dcf37cd3..8dd53dcf 100644
--- a/src/libnm-glib-aux/nm-shared-utils.h
+++ b/src/libnm-glib-aux/nm-shared-utils.h
@@ -18,6 +18,7 @@ typedef enum _nm_packed {
     NM_OPTION_BOOL_TRUE    = 1,
 } NMOptionBool;
 
+#define nm_assert_is_bool(value)    nm_assert(NM_IN_SET((value), 0, 1))
 #define nm_assert_is_ternary(value) nm_assert(NM_IN_SET((value), -1, 0, 1))
 
 /*****************************************************************************/
@@ -35,19 +36,19 @@ pid_t nm_utils_gettid(void);
 gboolean _nm_assert_on_main_thread(void);
 
 #if NM_MORE_ASSERTS > 5
-    #define NM_ASSERT_ON_MAIN_THREAD()              \
-        G_STMT_START                                \
-        {                                           \
-            nm_assert(_nm_assert_on_main_thread()); \
-        }                                           \
-        G_STMT_END
+#define NM_ASSERT_ON_MAIN_THREAD()              \
+    G_STMT_START                                \
+    {                                           \
+        nm_assert(_nm_assert_on_main_thread()); \
+    }                                           \
+    G_STMT_END
 #else
-    #define NM_ASSERT_ON_MAIN_THREAD() \
-        G_STMT_START                   \
-        {                              \
-            ;                          \
-        }                              \
-        G_STMT_END
+#define NM_ASSERT_ON_MAIN_THREAD() \
+    G_STMT_START                   \
+    {                              \
+        ;                          \
+    }                              \
+    G_STMT_END
 #endif
 
 /*****************************************************************************/
@@ -79,20 +80,20 @@ _NM_INT_NOT_NEGATIVE(gssize val)
  * Together with the G_STATIC_ASSERT(), we make sure that this is always satisfied. */
 G_STATIC_ASSERT(sizeof(int) == sizeof(gint32));
 #if _NM_CC_SUPPORT_GENERIC
-    #define _NM_INT_LE_MAXINT32(value)                 \
-        ({                                             \
-            _nm_unused typeof(value) _value = (value); \
-                                                       \
-            _Generic((value), int : TRUE);             \
-        })
+#define _NM_INT_LE_MAXINT32(value)                 \
+    ({                                             \
+        _nm_unused typeof(value) _value = (value); \
+                                                   \
+        _Generic((value), int : TRUE);             \
+    })
 #else
-    #define _NM_INT_LE_MAXINT32(value)                   \
-        ({                                               \
-            _nm_unused typeof(value) _value   = (value); \
-            _nm_unused const int *   _p_value = &_value; \
-                                                         \
-            TRUE;                                        \
-        })
+#define _NM_INT_LE_MAXINT32(value)                   \
+    ({                                               \
+        _nm_unused typeof(value) _value   = (value); \
+        _nm_unused const int *   _p_value = &_value; \
+                                                     \
+        TRUE;                                        \
+    })
 #endif
 
 /*****************************************************************************/
@@ -247,7 +248,6 @@ extern const NMIPAddr nm_ip_addr_zero;
 static inline int
 nm_ip_addr_cmp(int addr_family, gconstpointer a, gconstpointer b)
 {
-    nm_assert_addr_family(addr_family);
     nm_assert(a);
     nm_assert(b);
 
@@ -264,20 +264,27 @@ static inline gboolean
 nm_ip_addr_is_null(int addr_family, gconstpointer addr)
 {
     nm_assert(addr);
-    if (addr_family == AF_INET6)
-        return IN6_IS_ADDR_UNSPECIFIED((const struct in6_addr *) addr);
-    nm_assert(addr_family == AF_INET);
-    return ((const struct in_addr *) addr)->s_addr == 0;
+
+    if (NM_IS_IPv4(addr_family)) {
+        in_addr_t t;
+
+        /* also for in_addr_t type (AF_INET), we accept that the pointer might
+         * be unaligned. */
+        memcpy(&t, addr, sizeof(t));
+        return t == 0;
+    }
+
+    return IN6_IS_ADDR_UNSPECIFIED((const struct in6_addr *) addr);
 }
 
 static inline void
 nm_ip_addr_set(int addr_family, gpointer dst, gconstpointer src)
 {
-    nm_assert_addr_family(addr_family);
     nm_assert(dst);
     nm_assert(src);
 
-    memcpy(dst, src, NM_IS_IPv4(addr_family) ? sizeof(in_addr_t) : sizeof(struct in6_addr));
+    /* this MUST use memcpy() (or similar means) to support unaligned src/dst pointers. */
+    memcpy(dst, src, nm_utils_addr_family_to_size(addr_family));
 }
 
 static inline NMIPAddr
@@ -308,6 +315,9 @@ gboolean nm_ip_addr_set_from_untrusted(int           addr_family,
                                        gsize         src_len,
                                        int *         out_addr_family);
 
+gboolean
+nm_ip_addr_set_from_variant(int addr_family, gpointer dst, GVariant *variant, int *out_addr_family);
+
 static inline gboolean
 nm_ip4_addr_is_localhost(in_addr_t addr4)
 {
@@ -365,8 +375,8 @@ typedef struct _NMUtilsIPv6IfaceId {
         }                           \
     }
 
-void nm_utils_ipv6_addr_set_interface_identifier(struct in6_addr *        addr,
-                                                 const NMUtilsIPv6IfaceId iid);
+void nm_utils_ipv6_addr_set_interface_identifier(struct in6_addr *         addr,
+                                                 const NMUtilsIPv6IfaceId *iid);
 
 void nm_utils_ipv6_interface_identifier_get_from_addr(NMUtilsIPv6IfaceId *   iid,
                                                       const struct in6_addr *addr);
@@ -374,7 +384,7 @@ void nm_utils_ipv6_interface_identifier_get_from_addr(NMUtilsIPv6IfaceId *   iid
 gboolean nm_utils_ipv6_interface_identifier_get_from_token(NMUtilsIPv6IfaceId *iid,
                                                            const char *        token);
 
-const char *nm_utils_inet6_interface_identifier_to_token(NMUtilsIPv6IfaceId iid,
+const char *nm_utils_inet6_interface_identifier_to_token(const NMUtilsIPv6IfaceId *iid,
                                                          char buf[static INET6_ADDRSTRLEN]);
 
 gboolean nm_utils_get_ipv6_interface_identifier(NMLinkType          link_type,
@@ -559,25 +569,25 @@ extern const void *const _NM_PTRARRAY_EMPTY[1];
 #define NM_STRV_EMPTY_CC()      NM_PTRARRAY_EMPTY(const char *)
 
 static inline void
-_nm_utils_strbuf_init(char *buf, gsize len, char **p_buf_ptr, gsize *p_buf_len)
+nm_strbuf_init(char *buf, gsize len, char **p_buf_ptr, gsize *p_buf_len)
 {
     NM_SET_OUT(p_buf_len, len);
     NM_SET_OUT(p_buf_ptr, buf);
     buf[0] = '\0';
 }
 
-#define nm_utils_strbuf_init(buf, p_buf_ptr, p_buf_len)                                    \
+#define nm_strbuf_init_arr(buf, p_buf_ptr, p_buf_len)                                      \
     G_STMT_START                                                                           \
     {                                                                                      \
         G_STATIC_ASSERT(G_N_ELEMENTS(buf) == sizeof(buf) && sizeof(buf) > sizeof(char *)); \
-        _nm_utils_strbuf_init((buf), sizeof(buf), (p_buf_ptr), (p_buf_len));               \
+        nm_strbuf_init((buf), sizeof(buf), (p_buf_ptr), (p_buf_len));                      \
     }                                                                                      \
     G_STMT_END
-void nm_utils_strbuf_append(char **buf, gsize *len, const char *format, ...) _nm_printf(3, 4);
-void nm_utils_strbuf_append_c(char **buf, gsize *len, char c);
-void nm_utils_strbuf_append_str(char **buf, gsize *len, const char *str);
-void nm_utils_strbuf_append_bin(char **buf, gsize *len, gconstpointer str, gsize str_len);
-void nm_utils_strbuf_seek_end(char **buf, gsize *len);
+void nm_strbuf_append(char **buf, gsize *len, const char *format, ...) _nm_printf(3, 4);
+void nm_strbuf_append_c(char **buf, gsize *len, char c);
+void nm_strbuf_append_str(char **buf, gsize *len, const char *str);
+void nm_strbuf_append_bin(char **buf, gsize *len, gconstpointer str, gsize str_len);
+void nm_strbuf_seek_end(char **buf, gsize *len);
 
 const char *nm_strquote(char *buf, gsize buf_len, const char *str);
 
@@ -589,24 +599,25 @@ nm_utils_is_separator(const char c)
 
 /*****************************************************************************/
 
-GBytes *nm_gbytes_get_empty(void);
+GBytes *nm_g_bytes_get_empty(void);
 
 GBytes *nm_g_bytes_new_from_str(const char *str);
+GBytes *nm_g_bytes_new_from_variant_ay(GVariant *var);
 
 static inline gboolean
-nm_gbytes_equal0(GBytes *a, GBytes *b)
+nm_g_bytes_equal0(const GBytes *a, const GBytes *b)
 {
     return a == b || (a && b && g_bytes_equal(a, b));
 }
 
-gboolean nm_utils_gbytes_equal_mem(GBytes *bytes, gconstpointer mem_data, gsize mem_len);
+gboolean nm_g_bytes_equal_mem(GBytes *bytes, gconstpointer mem_data, gsize mem_len);
 
-GVariant *nm_utils_gbytes_to_variant_ay(GBytes *bytes);
+GVariant *nm_g_bytes_to_variant_ay(const GBytes *bytes);
 
-GHashTable *nm_utils_strdict_clone(GHashTable *src);
+GHashTable *nm_strdict_clone(GHashTable *src);
 
-GVariant *nm_utils_strdict_to_variant_ass(GHashTable *strdict);
-GVariant *nm_utils_strdict_to_variant_asv(GHashTable *strdict);
+GVariant *nm_strdict_to_variant_ass(GHashTable *strdict);
+GVariant *nm_strdict_to_variant_asv(GHashTable *strdict);
 
 /*****************************************************************************/
 
@@ -650,95 +661,105 @@ int nm_utils_dbus_path_cmp(const char *dbus_path_a, const char *dbus_path_b);
 /*****************************************************************************/
 
 typedef enum {
-    NM_UTILS_STRSPLIT_SET_FLAGS_NONE = 0,
+    NM_STRSPLIT_SET_FLAGS_NONE = 0,
 
     /* by default, strsplit will coalesce consecutive delimiters and remove
      * them from the result. If this flag is present, empty values are preserved
      * and returned.
      *
-     * When combined with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP, if a value gets
+     * When combined with %NM_STRSPLIT_SET_FLAGS_STRSTRIP, if a value gets
      * empty after strstrip(), it also gets removed. */
-    NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY = (1u << 0),
+    NM_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY = (1u << 0),
 
-    /* %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING means that delimiters prefixed
+    /* %NM_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING means that delimiters prefixed
      * by a backslash are not treated as a separator. Such delimiters and their escape
      * character are copied to the current word without unescaping them. In general,
-     * nm_utils_strsplit_set_full() does not remove any backslash escape characters
+     * nm_strsplit_set_full() does not remove any backslash escape characters
      * and does no unescaping. It only considers them for skipping to split at
      * an escaped delimiter.
      *
-     * If this is combined with (or implied by %NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED), then
+     * If this is combined with (or implied by %NM_STRSPLIT_SET_FLAGS_ESCAPED), then
      * the backslash escapes are removed from the result.
      */
-    NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING = (1u << 1),
+    NM_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING = (1u << 1),
 
     /* If flag is set, does the same as g_strstrip() on the returned tokens.
      * This will remove leading and trailing ascii whitespaces (g_ascii_isspace()
      * and NM_ASCII_SPACES).
      *
-     * - when combined with !%NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY,
+     * - when combined with !%NM_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY,
      *   empty tokens will be removed (and %NULL will be returned if that
      *   results in an empty string array).
-     * - when combined with %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING,
+     * - when combined with %NM_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING,
      *   trailing whitespace escaped by backslash are not stripped. */
-    NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP = (1u << 2),
+    NM_STRSPLIT_SET_FLAGS_STRSTRIP = (1u << 2),
 
-    /* This implies %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING.
+    /* This implies %NM_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING.
      *
      * This will do a final run over all tokens and remove all backslash
      * escape characters that
      *   - precede a delimiter.
      *   - precede a backslash.
-     *   - precede a whitespace (only with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP).
+     *   - precede a whitespace (only with %NM_STRSPLIT_SET_FLAGS_STRSTRIP).
      *
-     *  Note that with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP, it is only
+     *  Note that with %NM_STRSPLIT_SET_FLAGS_STRSTRIP, it is only
      *  necessary to escape the very last whitespace (if the delimiters
      *  are not whitespace themself). So, technically, it would be sufficient
      *  to only unescape a backslash before the last whitespace and the user
      *  still could express everything. However, such a rule would be complicated
-     *  to understand, so when using backslash escaping with nm_utils_strsplit_set_full(),
+     *  to understand, so when using backslash escaping with nm_strsplit_set_full(),
      *  then all characters (including backslash) are treated verbatim, except:
      *
      *    - "\\$DELIMITER" (escaped delimiter)
      *    - "\\\\" (escaped backslash)
-     *    - "\\$SPACE" (escaped space) (only with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP).
+     *    - "\\$SPACE" (escaped space) (only with %NM_STRSPLIT_SET_FLAGS_STRSTRIP).
      *
      * Note that all other escapes like "\\n" or "\\001" are left alone.
      * That makes the escaping/unescaping rules simple. Also, for the most part
      * a text is just taken as-is, with little additional rules. Only backslashes
      * need extra care, and then only if they proceed one of the relevant characters.
      */
-    NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED = (1u << 3),
+    NM_STRSPLIT_SET_FLAGS_ESCAPED = (1u << 3),
 
 } NMUtilsStrsplitSetFlags;
 
 const char **
-nm_utils_strsplit_set_full(const char *str, const char *delimiter, NMUtilsStrsplitSetFlags flags);
+nm_strsplit_set_full(const char *str, const char *delimiter, NMUtilsStrsplitSetFlags flags);
 
 static inline const char **
-nm_utils_strsplit_set_with_empty(const char *str, const char *delimiters)
+nm_strsplit_set_with_empty(const char *str, const char *delimiters)
 {
     /* this returns the same result as g_strsplit_set(str, delimiters, -1), except
      * it does not deep-clone the strv array.
      * Also, for @str == "", this returns %NULL while g_strsplit_set() would return
      * an empty strv array. */
-    return nm_utils_strsplit_set_full(str, delimiters, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY);
+    return nm_strsplit_set_full(str, delimiters, NM_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY);
 }
 
 static inline const char **
-nm_utils_strsplit_set(const char *str, const char *delimiters)
+nm_strsplit_set(const char *str, const char *delimiters)
 {
-    return nm_utils_strsplit_set_full(str, delimiters, NM_UTILS_STRSPLIT_SET_FLAGS_NONE);
+    return nm_strsplit_set_full(str, delimiters, NM_STRSPLIT_SET_FLAGS_NONE);
 }
 
-gssize nm_utils_strv_find_first(char **list, gssize len, const char *needle);
+gssize _nm_strv_find_first(const char *const *list, gssize len, const char *needle);
+
+#define nm_strv_find_first(list, len, needle) \
+    _nm_strv_find_first(NM_CAST_STRV_CC(list), (len), (needle))
 
 gboolean nm_strv_has_duplicate(const char *const *list, gssize len, gboolean is_sorted);
 
-char **_nm_utils_strv_cleanup(char **  strv,
-                              gboolean strip_whitespace,
-                              gboolean skip_empty,
-                              gboolean skip_repeated);
+const char **nm_strv_cleanup_const(const char **strv, gboolean skip_empty, gboolean skip_repeated);
+
+char **nm_strv_cleanup(char **  strv,
+                       gboolean strip_whitespace,
+                       gboolean skip_empty,
+                       gboolean skip_repeated);
+
+gboolean nm_strv_is_same_unordered(const char *const *strv1,
+                                   gssize             len1,
+                                   const char *const *strv2,
+                                   gssize             len2);
 
 /*****************************************************************************/
 
@@ -753,10 +774,9 @@ nm_copy_func_g_strdup(gconstpointer arg, gpointer user_data)
 static inline const char **
 nm_utils_escaped_tokens_split(const char *str, const char *delimiters)
 {
-    return nm_utils_strsplit_set_full(str,
-                                      delimiters,
-                                      NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED
-                                          | NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP);
+    return nm_strsplit_set_full(str,
+                                delimiters,
+                                NM_STRSPLIT_SET_FLAGS_ESCAPED | NM_STRSPLIT_SET_FLAGS_STRSTRIP);
 }
 
 typedef enum {
@@ -879,10 +899,10 @@ char **nm_utils_strsplit_quoted(const char *str);
 static inline const char **
 nm_utils_escaped_tokens_options_split_list(const char *str)
 {
-    return nm_utils_strsplit_set_full(str,
-                                      ",",
-                                      NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP
-                                          | NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING);
+    return nm_strsplit_set_full(str,
+                                ",",
+                                NM_STRSPLIT_SET_FLAGS_STRSTRIP
+                                    | NM_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING);
 }
 
 void nm_utils_escaped_tokens_options_split(char *str, const char **out_key, const char **out_val);
@@ -1033,7 +1053,7 @@ int _nm_utils_ascii_str_to_bool(const char *str, int default_value);
 
 /*****************************************************************************/
 
-extern char _nm_utils_to_string_buffer[2096];
+extern _nm_thread_local char _nm_utils_to_string_buffer[2096];
 
 void     nm_utils_to_string_buffer_init(char **buf, gsize *len);
 gboolean nm_utils_to_string_buffer_init_null(gconstpointer obj, char **buf, gsize *len);
@@ -1069,16 +1089,12 @@ const char *nm_utils_flags2str(const NMUtilsFlags2StrDesc *descs,
 /*****************************************************************************/
 
 #define NM_UTILS_ENUM2STR(v, n) \
-    (void) 0;                   \
-case v:                         \
-    s = "" n "";                \
-    break;                      \
-    (void) 0
+    case v:                     \
+        s = "" n "";            \
+        break;
 #define NM_UTILS_ENUM2STR_IGNORE(v) \
-    (void) 0;                       \
-case v:                             \
-    break;                          \
-    (void) 0
+    case v:                         \
+        break;
 
 #define NM_UTILS_ENUM2STR_DEFINE_FULL(fcn_name, lookup_type, int_fmt, ...) \
     const char *fcn_name(lookup_type val, char *buf, gsize len)            \
@@ -1087,7 +1103,7 @@ case v:                             \
         if (len) {                                                         \
             const char *s = NULL;                                          \
             switch (val) {                                                 \
-                (void) 0, __VA_ARGS__(void) 0;                             \
+                NM_VA_ARGS_JOIN(, __VA_ARGS__)                             \
             };                                                             \
             if (s)                                                         \
                 g_strlcpy(buf, s, len);                                    \
@@ -1107,14 +1123,26 @@ case v:                             \
     static inline void _nm_g_slice_free_fcn_##mem_size(gpointer mem_block) \
     {                                                                      \
         g_slice_free1(mem_size, mem_block);                                \
-    }
+    }                                                                      \
+    _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON
 
-_nm_g_slice_free_fcn_define(1) _nm_g_slice_free_fcn_define(2) _nm_g_slice_free_fcn_define(4)
-    _nm_g_slice_free_fcn_define(8) _nm_g_slice_free_fcn_define(10) _nm_g_slice_free_fcn_define(12)
-        _nm_g_slice_free_fcn_define(16) _nm_g_slice_free_fcn_define(32)
+_nm_g_slice_free_fcn_define(1);
+_nm_g_slice_free_fcn_define(2);
+_nm_g_slice_free_fcn_define(4);
+_nm_g_slice_free_fcn_define(8);
+_nm_g_slice_free_fcn_define(10);
+_nm_g_slice_free_fcn_define(12);
+_nm_g_slice_free_fcn_define(16);
+_nm_g_slice_free_fcn_define(32);
+
+_nm_warn_unused_result static inline GDestroyNotify
+_nm_get_warn_unused_result_gdestroynotify(GDestroyNotify f)
+{
+    return f;
+}
 
 #define nm_g_slice_free_fcn1(mem_size)                                                        \
-    ({                                                                                        \
+    _nm_get_warn_unused_result_gdestroynotify(({                                              \
         void (*_fcn)(gpointer);                                                               \
                                                                                               \
         /* If mem_size is a compile time constant, the compiler
@@ -1153,8 +1181,9 @@ _nm_g_slice_free_fcn_define(1) _nm_g_slice_free_fcn_define(2) _nm_g_slice_free_f
             _fcn = NULL;                                                                      \
             break;                                                                            \
         }                                                                                     \
+                                                                                              \
         _fcn;                                                                                 \
-    })
+    }))
 
 /**
  * nm_g_slice_free_fcn:
@@ -1185,7 +1214,8 @@ _nm_g_slice_free_fcn_define(1) _nm_g_slice_free_fcn_define(2) _nm_g_slice_free_f
         _error && _error->domain == (err_domain) && NM_IN_SET(_error->code, __VA_ARGS__); \
     })
 
-            static inline void nm_g_set_error_take(GError **error, GError *error_take)
+static inline void
+nm_g_set_error_take(GError **error, GError *error_take)
 {
     if (!error_take)
         g_return_if_reached();
@@ -1420,21 +1450,41 @@ GParamSpec *nm_g_object_class_find_property_from_gtype(GType gtype, const char *
         ((const _c_type *) _param_spec);                                     \
     })
 
+#define _NM_G_PARAM_SPEC_CAST_IS_A(param_spec, _value_type, _c_type)                  \
+    ({                                                                                \
+        const GParamSpec *const _param_spec = (param_spec);                           \
+                                                                                      \
+        nm_assert(!_param_spec || g_type_is_a(_param_spec->value_type, _value_type)); \
+        ((const _c_type *) _param_spec);                                              \
+    })
+
 #define NM_G_PARAM_SPEC_CAST_BOOLEAN(param_spec) \
     _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_BOOLEAN, GParamSpecBoolean)
+#define NM_G_PARAM_SPEC_CAST_INT(param_spec) \
+    _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_INT, GParamSpecInt)
 #define NM_G_PARAM_SPEC_CAST_UINT(param_spec) \
     _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_UINT, GParamSpecUInt)
 #define NM_G_PARAM_SPEC_CAST_UINT64(param_spec) \
     _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_UINT64, GParamSpecUInt64)
+#define NM_G_PARAM_SPEC_CAST_ENUM(param_spec) \
+    _NM_G_PARAM_SPEC_CAST_IS_A(param_spec, G_TYPE_ENUM, GParamSpecEnum)
+#define NM_G_PARAM_SPEC_CAST_FLAGS(param_spec) \
+    _NM_G_PARAM_SPEC_CAST_IS_A(param_spec, G_TYPE_FLAGS, GParamSpecFlags)
 #define NM_G_PARAM_SPEC_CAST_STRING(param_spec) \
     _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_STRING, GParamSpecString)
 
 #define NM_G_PARAM_SPEC_GET_DEFAULT_BOOLEAN(param_spec) \
     (NM_G_PARAM_SPEC_CAST_BOOLEAN(NM_ENSURE_NOT_NULL(param_spec))->default_value)
+#define NM_G_PARAM_SPEC_GET_DEFAULT_INT(param_spec) \
+    (NM_G_PARAM_SPEC_CAST_INT(NM_ENSURE_NOT_NULL(param_spec))->default_value)
 #define NM_G_PARAM_SPEC_GET_DEFAULT_UINT(param_spec) \
     (NM_G_PARAM_SPEC_CAST_UINT(NM_ENSURE_NOT_NULL(param_spec))->default_value)
 #define NM_G_PARAM_SPEC_GET_DEFAULT_UINT64(param_spec) \
     (NM_G_PARAM_SPEC_CAST_UINT64(NM_ENSURE_NOT_NULL(param_spec))->default_value)
+#define NM_G_PARAM_SPEC_GET_DEFAULT_ENUM(param_spec) \
+    (NM_G_PARAM_SPEC_CAST_ENUM(NM_ENSURE_NOT_NULL(param_spec))->default_value)
+#define NM_G_PARAM_SPEC_GET_DEFAULT_FLAGS(param_spec) \
+    (NM_G_PARAM_SPEC_CAST_FLAGS(NM_ENSURE_NOT_NULL(param_spec))->default_value)
 #define NM_G_PARAM_SPEC_GET_DEFAULT_STRING(param_spec) \
     (NM_G_PARAM_SPEC_CAST_STRING(NM_ENSURE_NOT_NULL(param_spec))->default_value)
 
@@ -1498,10 +1548,17 @@ char *nm_utils_str_utf8safe_escape_take(char *str, NMUtilsStrUtf8SafeFlags flags
 
 GVariant *nm_g_variant_singleton_b(gboolean value);
 GVariant *nm_g_variant_singleton_u_0(void);
+GVariant *nm_g_variant_singleton_i_0(void);
 GVariant *nm_g_variant_singleton_s_empty(void);
+GVariant *nm_g_variant_singleton_au(void);
+GVariant *nm_g_variant_singleton_aay(void);
+GVariant *nm_g_variant_singleton_as(void);
 GVariant *nm_g_variant_singleton_aLsvI(void);
 GVariant *nm_g_variant_singleton_aLsaLsvII(void);
 GVariant *nm_g_variant_singleton_aaLsvI(void);
+GVariant *nm_g_variant_singleton_ao(void);
+
+GVariant *nm_g_variant_maybe_singleton_i(gint32 v);
 
 static inline void
 nm_g_variant_unref_floating(GVariant *var)
@@ -1599,6 +1656,19 @@ nm_g_variant_builder_add_sv_str(GVariantBuilder *builder, const char *key, const
 static inline void
 nm_g_source_destroy_and_unref(GSource *source)
 {
+    /* Note that calling g_source_destroy() on a currently attached source,
+     * will destroy the user-data of the callback right away (and not only
+     * during the last g_source_unref()).
+     *
+     * It also means, that if the user data itself has the reference to the
+     * source, then this will lead to crash:
+     *
+     *     g_source_destroy(user_data->my_source);
+     *     // ups, user_data was destroyed (if source was attached).
+     *     g_source_unref(user_data->my_source);
+     *
+     *  nm_g_source_destroy_and_unref() and nm_clear_g_source_inst() does not
+     *  suffer from this problem. */
     g_source_destroy(source);
     g_source_unref(source);
 }
@@ -1673,19 +1743,25 @@ GSource *nm_g_timeout_source_new_seconds(guint          timeout_sec,
                                          gpointer       user_data,
                                          GDestroyNotify destroy_notify);
 
-GSource *
-         nm_g_unix_fd_source_new(int          fd,
-                                 GIOCondition io_condition,
-                                 int          priority,
-                                 gboolean (*source_func)(int fd, GIOCondition condition, gpointer user_data),
-                                 gpointer       user_data,
-                                 GDestroyNotify destroy_notify);
+GSource *nm_g_unix_fd_source_new(int               fd,
+                                 GIOCondition      io_condition,
+                                 int               priority,
+                                 GUnixFDSourceFunc source_func,
+                                 gpointer          user_data,
+                                 GDestroyNotify    destroy_notify);
+
 GSource *nm_g_unix_signal_source_new(int            signum,
                                      int            priority,
                                      GSourceFunc    handler,
                                      gpointer       user_data,
                                      GDestroyNotify notify);
 
+GSource *nm_g_child_watch_source_new(GPid            pid,
+                                     int             priority,
+                                     GChildWatchFunc handler,
+                                     gpointer        user_data,
+                                     GDestroyNotify  notify);
+
 static inline GSource *
 nm_g_source_attach(GSource *source, GMainContext *context)
 {
@@ -1693,10 +1769,25 @@ nm_g_source_attach(GSource *source, GMainContext *context)
     return source;
 }
 
+static inline void
+nm_g_idle_add(GSourceFunc func, gpointer user_data)
+{
+    /* g_idle_add() is discouraged because it relies on the guint source IDs.
+     *
+     * Usually, you would want to use nm_g_idle_add_source() which returns a GSource*
+     * instance.
+     *
+     * However, if you don't care to ever call g_source_remove() on the source ID, then
+     * g_idle_add() is fine. But our checkpatch script would complain about it. In
+     * that case use nm_g_idle_add(), which makes it clear that you really want to
+     * use g_idle_add() and ignore the source ID. */
+    g_idle_add(func, user_data);
+}
+
 static inline GSource *
 nm_g_idle_add_source(GSourceFunc func, gpointer user_data)
 {
-    /* G convenience function to attach a new timeout source to the default GMainContext.
+    /* A convenience function to attach a new timeout source to the default GMainContext.
      * In that sense it's very similar to g_idle_add() except that it returns a
      * reference to the new source.  */
     return nm_g_source_attach(nm_g_idle_source_new(G_PRIORITY_DEFAULT, func, user_data, NULL),
@@ -1706,7 +1797,7 @@ nm_g_idle_add_source(GSourceFunc func, gpointer user_data)
 static inline GSource *
 nm_g_timeout_add_source(guint timeout_msec, GSourceFunc func, gpointer user_data)
 {
-    /* G convenience function to attach a new timeout source to the default GMainContext.
+    /* A convenience function to attach a new timeout source to the default GMainContext.
      * In that sense it's very similar to g_timeout_add() except that it returns a
      * reference to the new source.  */
     return nm_g_source_attach(
@@ -1715,9 +1806,9 @@ nm_g_timeout_add_source(guint timeout_msec, GSourceFunc func, gpointer user_data
 }
 
 static inline GSource *
-nm_g_timeout_add_source_seconds(guint timeout_sec, GSourceFunc func, gpointer user_data)
+nm_g_timeout_add_seconds_source(guint timeout_sec, GSourceFunc func, gpointer user_data)
 {
-    /* G convenience function to attach a new timeout source to the default GMainContext.
+    /* A convenience function to attach a new timeout source to the default GMainContext.
      * In that sense it's very similar to g_timeout_add_seconds() except that it returns a
      * reference to the new source.  */
     return nm_g_source_attach(
@@ -1746,6 +1837,36 @@ nm_g_timeout_add_source_approx(guint       timeout_msec,
     return nm_g_source_attach(source, NULL);
 }
 
+static inline GSource *
+nm_g_unix_fd_add_source(int               fd,
+                        GIOCondition      condition,
+                        GUnixFDSourceFunc function,
+                        gpointer          user_data)
+{
+    /* A convenience function to attach a new unix-fd source to the default GMainContext.
+     * In that sense it's very similar to g_unix_fd_add() except that it returns a
+     * reference to the new source.  */
+    return nm_g_source_attach(
+        nm_g_unix_fd_source_new(fd, condition, G_PRIORITY_DEFAULT, function, user_data, NULL),
+        NULL);
+}
+
+static inline GSource *
+nm_g_unix_signal_add_source(int signum, GSourceFunc handler, gpointer user_data)
+{
+    return nm_g_source_attach(
+        nm_g_unix_signal_source_new(signum, G_PRIORITY_DEFAULT, handler, user_data, NULL),
+        NULL);
+}
+
+static inline GSource *
+nm_g_child_watch_add_source(GPid pid, GChildWatchFunc handler, gpointer user_data)
+{
+    return nm_g_source_attach(
+        nm_g_child_watch_source_new(pid, G_PRIORITY_DEFAULT, handler, user_data, NULL),
+        NULL);
+}
+
 NM_AUTO_DEFINE_FCN0(GMainContext *, _nm_auto_unref_gmaincontext, g_main_context_unref);
 #define nm_auto_unref_gmaincontext nm_auto(_nm_auto_unref_gmaincontext)
 
@@ -1801,6 +1922,16 @@ nm_g_main_context_push_thread_default_if_necessary(GMainContext *context)
     return context;
 }
 
+static inline void
+nm_g_main_context_iterate_ready(GMainContext *context)
+{
+    while (g_main_context_iteration(context, FALSE)) {
+        ;
+    }
+}
+
+void nm_g_main_context_iterate_for_msec(GMainContext *context, guint timeout_msec);
+
 /*****************************************************************************/
 
 static inline int
@@ -1893,7 +2024,7 @@ gpointer *nm_utils_hash_values_to_array(GHashTable *     hash,
                                         guint *          out_len);
 
 static inline const char **
-nm_utils_strdict_get_keys(const GHashTable *hash, gboolean sorted, guint *out_length)
+nm_strdict_get_keys(const GHashTable *hash, gboolean sorted, guint *out_length)
 {
     return (const char **) nm_utils_hash_keys_to_array((GHashTable *) hash,
                                                        sorted ? nm_strcmp_p_with_data : NULL,
@@ -1924,26 +2055,26 @@ int nm_utils_hashtable_cmp(const GHashTable *a,
                            GCompareDataFunc  cmp_values,
                            gpointer          user_data);
 
-char **nm_utils_strv_make_deep_copied(const char **strv);
+char **nm_strv_make_deep_copied(const char **strv);
 
-char **nm_utils_strv_make_deep_copied_n(const char **strv, gsize len);
+char **nm_strv_make_deep_copied_n(const char **strv, gsize len);
 
 static inline char **
-nm_utils_strv_make_deep_copied_nonnull(const char **strv)
+nm_strv_make_deep_copied_nonnull(const char **strv)
 {
-    return nm_utils_strv_make_deep_copied(strv) ?: g_new0(char *, 1);
+    return nm_strv_make_deep_copied(strv) ?: g_new0(char *, 1);
 }
 
-char **_nm_utils_strv_dup(const char *const *strv, gssize len, gboolean deep_copied);
+char **_nm_strv_dup(const char *const *strv, gssize len, gboolean deep_copied);
 
-#define nm_utils_strv_dup(strv, len, deep_copied) \
-    _nm_utils_strv_dup(NM_CAST_STRV_CC(strv), (len), (deep_copied))
+#define nm_strv_dup(strv, len, deep_copied) \
+    _nm_strv_dup(NM_CAST_STRV_CC(strv), (len), (deep_copied))
 
-const char **_nm_utils_strv_dup_packed(const char *const *strv, gssize len);
+const char **_nm_strv_dup_packed(const char *const *strv, gssize len);
 
-#define nm_utils_strv_dup_packed(strv, len) _nm_utils_strv_dup_packed(NM_CAST_STRV_CC(strv), (len))
+#define nm_strv_dup_packed(strv, len) _nm_strv_dup_packed(NM_CAST_STRV_CC(strv), (len))
 
-#define nm_utils_strv_dup_shallow_maybe_a(alloca_maxlen, strv, len, to_free)       \
+#define nm_strv_dup_shallow_maybe_a(alloca_maxlen, strv, len, to_free)             \
     ({                                                                             \
         const char *const *const _strv    = NM_CAST_STRV_CC(strv);                 \
         const gssize             _len     = (len);                                 \
@@ -1994,6 +2125,28 @@ nm_g_array_unref(GArray *arr)
         g_array_unref(arr);
 }
 
+#define nm_g_array_first(arr, type)   \
+    ({                                \
+        GArray *const _arr = (arr);   \
+        guint         _len;           \
+                                      \
+        nm_assert(_arr);              \
+        _len = _arr->len;             \
+        nm_assert(_len > 0);          \
+        &g_array_index(arr, type, 0); \
+    })
+
+#define nm_g_array_last(arr, type)            \
+    ({                                        \
+        GArray *const _arr = (arr);           \
+        guint         _len;                   \
+                                              \
+        nm_assert(_arr);                      \
+        _len = _arr->len;                     \
+        nm_assert(_len > 0);                  \
+        &g_array_index(arr, type, _len - 1u); \
+    })
+
 #define nm_g_array_append_new(arr, type)   \
     ({                                     \
         GArray *const _arr = (arr);        \
@@ -2091,17 +2244,17 @@ GPtrArray *_nm_g_ptr_array_copy(GPtrArray *    array,
  * Note that the @element_free_func MUST correspond to free function set in @array.
  */
 #if GLIB_CHECK_VERSION(2, 62, 0)
-    #define nm_g_ptr_array_copy(array, func, user_data, element_free_func)            \
-        ({                                                                            \
-            _nm_unused GDestroyNotify const _element_free_func = (element_free_func); \
-                                                                                      \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS;                                         \
-            g_ptr_array_copy((array), (func), (user_data));                           \
-            G_GNUC_END_IGNORE_DEPRECATIONS;                                           \
-        })
+#define nm_g_ptr_array_copy(array, func, user_data, element_free_func)            \
+    ({                                                                            \
+        _nm_unused GDestroyNotify const _element_free_func = (element_free_func); \
+                                                                                  \
+        G_GNUC_BEGIN_IGNORE_DEPRECATIONS;                                         \
+        g_ptr_array_copy((array), (func), (user_data));                           \
+        G_GNUC_END_IGNORE_DEPRECATIONS;                                           \
+    })
 #else
-    #define nm_g_ptr_array_copy(array, func, user_data, element_free_func) \
-        _nm_g_ptr_array_copy((array), (func), (user_data), (element_free_func))
+#define nm_g_ptr_array_copy(array, func, user_data, element_free_func) \
+    _nm_g_ptr_array_copy((array), (func), (user_data), (element_free_func))
 #endif
 
 /*****************************************************************************/
@@ -2165,7 +2318,7 @@ gssize nm_utils_ptrarray_find_binary_search_range(gconstpointer *  list,
                                                   gssize *         out_idx_first,
                                                   gssize *         out_idx_last);
 
-#define nm_utils_strv_find_binary_search(strv, len, needle)           \
+#define nm_strv_find_binary_search(strv, len, needle)                 \
     ({                                                                \
         const char *const *const _strv   = NM_CAST_STRV_CC(strv);     \
         const gsize              _len    = (len);                     \
@@ -2192,16 +2345,89 @@ gssize nm_utils_ptrarray_find_first(gconstpointer *list, gssize len, gconstpoint
 
 /*****************************************************************************/
 
-void _nm_utils_strv_sort(const char **strv, gssize len);
-#define nm_utils_strv_sort(strv, len) _nm_utils_strv_sort(NM_CAST_STRV_MC(strv), len)
+void _nm_strv_sort(const char **strv, gssize len);
+#define nm_strv_sort(strv, len) _nm_strv_sort(NM_CAST_STRV_MC(strv), len)
+
+int _nm_strv_cmp_n(const char *const *strv1, gssize len1, const char *const *strv2, gssize len2);
+
+#define nm_strv_cmp_n(strv1, len1, strv2, len2) \
+    _nm_strv_cmp_n(NM_CAST_STRV_CC(strv1), (len1), NM_CAST_STRV_CC(strv2), (len2))
+
+/* This is like nm_strv_cmp_n(). The difference is that a NULL strv array (strv=NULL,len=-1)
+ * is treated the same as an empty one (with len=0). */
+#define nm_strv_cmp_n_null(strv1, len1, strv2, len2)              \
+    ({                                                            \
+        const char *const *const _strv1 = NM_CAST_STRV_CC(strv1); \
+        const char *const *const _strv2 = NM_CAST_STRV_CC(strv2); \
+        const gssize             _len1  = (len1);                 \
+        const gssize             _len2  = (len2);                 \
+                                                                  \
+        _nm_strv_cmp_n(_strv1,                                    \
+                       (_len1 >= 0 ? _len1 : (_strv1 ? -1 : 0)),  \
+                       _strv2,                                    \
+                       (_len2 >= 0 ? _len2 : (_strv2 ? -1 : 0))); \
+    })
+
+#define nm_strv_equal_n(strv1, len1, strv2, len2) \
+    (nm_strv_cmp_n((strv1), (len1), (strv2), (len2)) == 0)
 
-int
-_nm_utils_strv_cmp_n(const char *const *strv1, gssize len1, const char *const *strv2, gssize len2);
+#define nm_strv_equal(strv1, strv2) nm_strv_equal_n((strv1), -1, (strv2), -1)
 
-#define nm_utils_strv_cmp_n(strv1, len1, strv2, len2) \
-    _nm_utils_strv_cmp_n(NM_CAST_STRV_CC(strv1), (len1), NM_CAST_STRV_CC(strv2), (len2))
+#define nm_strv_equal_n_null(strv1, len1, strv2, len2) \
+    (nm_strv_cmp_n_null((strv1), (len1), (strv2), (len2)) == 0)
 
-#define nm_utils_strv_equal(strv1, strv2) (nm_utils_strv_cmp_n((strv1), -1, (strv2), -1) == 0)
+/*****************************************************************************/
+
+/* nm_arr_insert_at() does @arr[@idx] = @value, but first memmove's
+ * the elements @arr[@idx..@len-1] one element up. That means, @arr currently
+ * has @len valid elements, but it must have space for one more element,
+ * which will be overwritten.
+ *
+ * The use case is to have a sorted array (nm_strv_find_binary_search()) and
+ * to insert the element at he desired index. The caller must make sure that
+ * @len is large enough to contain one more element. */
+#define nm_arr_insert_at(arr, len, idx, value)                                           \
+    G_STMT_START                                                                         \
+    {                                                                                    \
+        typeof(*(arr)) *const _arr  = (arr);                                             \
+        typeof(len)           _len  = (len);                                             \
+        typeof(idx)           _idx  = (idx);                                             \
+        const gsize           _len2 = (_len);                                            \
+        const gsize           _idx2 = (_idx);                                            \
+                                                                                         \
+        nm_assert(_arr);                                                                 \
+        nm_assert(_NM_INT_NOT_NEGATIVE(_len));                                           \
+        nm_assert(_NM_INT_NOT_NEGATIVE(_idx));                                           \
+        nm_assert(_idx <= _len);                                                         \
+                                                                                         \
+        if (_idx2 != _len2)                                                              \
+            memmove(&_arr[_idx2 + 1u], &_arr[_idx2], sizeof(_arr[0]) * (_len2 - _idx2)); \
+                                                                                         \
+        _arr[_idx2] = (value);                                                           \
+    }                                                                                    \
+    G_STMT_END
+
+/* nm_arr_remove_at() removes the element at arr[idx], by memmove'ing
+ * the elements from arr[idx+1..len-1] down. All it does is one memmove(),
+ * if there is anything to move. */
+#define nm_arr_remove_at(arr, len, idx)                                                         \
+    G_STMT_START                                                                                \
+    {                                                                                           \
+        typeof(*(arr)) *const _arr  = (arr);                                                    \
+        typeof(len)           _len  = (len);                                                    \
+        typeof(idx)           _idx  = (idx);                                                    \
+        const gsize           _len2 = (_len);                                                   \
+        const gsize           _idx2 = (_idx);                                                   \
+                                                                                                \
+        nm_assert(_arr);                                                                        \
+        nm_assert(_len > 0);                                                                    \
+        nm_assert(_NM_INT_NOT_NEGATIVE(_idx));                                                  \
+        nm_assert(_idx < _len);                                                                 \
+                                                                                                \
+        if (_idx2 != _len2 - 1u)                                                                \
+            memmove(&_arr[_idx2], &_arr[_idx2 + 1u], sizeof(_arr[0]) * ((_len2 - 1u) - _idx2)); \
+    }                                                                                           \
+    G_STMT_END
 
 /*****************************************************************************/
 
@@ -2406,7 +2632,7 @@ nm_strv_ptrarray_find_first(const GPtrArray *strv, const char *str)
 {
     if (!strv)
         return -1;
-    return nm_utils_strv_find_first((char **) strv->pdata, strv->len, str);
+    return nm_strv_find_first((const char *const *) strv->pdata, strv->len, str);
 }
 
 static inline gboolean
@@ -2418,14 +2644,14 @@ nm_strv_ptrarray_contains(const GPtrArray *strv, const char *str)
 static inline int
 nm_strv_ptrarray_cmp(const GPtrArray *a, const GPtrArray *b)
 {
-    /* nm_utils_strv_cmp_n() will treat NULL and empty arrays the same.
+    /* nm_strv_cmp_n() will treat NULL and empty arrays the same.
      * That means, an empty strv array can both be represented by NULL
      * and an array of length zero.
      * If you need to distinguish between these case, do that yourself. */
-    return nm_utils_strv_cmp_n((const char *const *) nm_g_ptr_array_pdata(a),
-                               nm_g_ptr_array_len(a),
-                               (const char *const *) nm_g_ptr_array_pdata(b),
-                               nm_g_ptr_array_len(b));
+    return nm_strv_cmp_n((const char *const *) nm_g_ptr_array_pdata(a),
+                         nm_g_ptr_array_len(a),
+                         (const char *const *) nm_g_ptr_array_pdata(b),
+                         nm_g_ptr_array_len(b));
 }
 
 /*****************************************************************************/
@@ -2750,7 +2976,7 @@ guint nm_utils_parse_debug_string(const char *string, const GDebugKey *keys, gui
 /*****************************************************************************/
 
 static inline gboolean
-nm_utils_strdup_reset(char **dst, const char *src)
+nm_strdup_reset(char **dst, const char *src)
 {
     char *old;
 
@@ -2765,12 +2991,12 @@ nm_utils_strdup_reset(char **dst, const char *src)
 }
 
 static inline gboolean
-nm_utils_strdup_reset_take(char **dst, char *src)
+nm_strdup_reset_take(char **dst, char *src)
 {
     char *old;
 
     nm_assert(dst);
-    nm_assert(src != *dst);
+    nm_assert(!src || src != *dst);
 
     if (nm_streq0(*dst, src)) {
         if (src)
@@ -2854,7 +3080,7 @@ nm_strvarray_get_strv_non_empty_dup(GArray *arr, guint *length)
 
     NM_SET_OUT(length, arr->len);
     strv = &g_array_index(arr, const char *, 0);
-    return nm_utils_strv_dup(strv, arr->len, TRUE);
+    return nm_strv_dup(strv, arr->len, TRUE);
 }
 
 static inline const char *const *
@@ -2988,6 +3214,8 @@ void nm_crypto_md5_hash(const guint8 *salt,
 
 char *nm_utils_get_process_exit_status_desc(int status);
 
+gboolean nm_utils_validate_hostname(const char *hostname);
+
 /*****************************************************************************/
 
 void nm_utils_thread_local_register_destroy(gpointer tls_data, GDestroyNotify destroy_notify);
diff --git a/src/libnm-glib-aux/nm-test-utils.h b/src/libnm-glib-aux/nm-test-utils.h
index ff8eb606..253aaf0e 100644
--- a/src/libnm-glib-aux/nm-test-utils.h
+++ b/src/libnm-glib-aux/nm-test-utils.h
@@ -81,8 +81,8 @@
  *******************************************************************************/
 
 #if defined(NM_ASSERT_NO_MSG) && NM_ASSERT_NO_MSG
-    #undef g_return_if_fail_warning
-    #undef g_assertion_message_expr
+#undef g_return_if_fail_warning
+#undef g_assertion_message_expr
 #endif
 
 #include <arpa/inet.h>
@@ -693,42 +693,42 @@ nmtst_test_quick(void)
 }
 
 #if GLIB_CHECK_VERSION(2, 34, 0)
-    #undef g_test_expect_message
-    #define g_test_expect_message(...)                                                   \
-        G_STMT_START                                                                     \
-        {                                                                                \
-            g_assert(nmtst_initialized());                                               \
-            if (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message) { \
-                g_debug("nmtst: assert-logging: g_test_expect_message %s",               \
-                        G_STRINGIFY((__VA_ARGS__)));                                     \
-            } else {                                                                     \
-                G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                         \
-                g_test_expect_message(__VA_ARGS__);                                      \
-                G_GNUC_END_IGNORE_DEPRECATIONS                                           \
-            }                                                                            \
-        }                                                                                \
-        G_STMT_END
-    #undef g_test_assert_expected_messages_internal
-    #define g_test_assert_expected_messages_internal(domain, file, line, func)                   \
-        G_STMT_START                                                                             \
-        {                                                                                        \
-            const char *_domain = (domain);                                                      \
-            const char *_file   = (file);                                                        \
-            const char *_func   = (func);                                                        \
-            int         _line   = (line);                                                        \
-                                                                                                 \
-            if (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message)           \
-                g_debug("nmtst: assert-logging: g_test_assert_expected_messages(%s, %s:%d, %s)", \
-                        _domain ?: "",                                                           \
-                        _file ?: "",                                                             \
-                        _line,                                                                   \
-                        _func ?: "");                                                            \
-                                                                                                 \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                                     \
-            g_test_assert_expected_messages_internal(_domain, _file, _line, _func);              \
-            G_GNUC_END_IGNORE_DEPRECATIONS                                                       \
-        }                                                                                        \
-        G_STMT_END
+#undef g_test_expect_message
+#define g_test_expect_message(...)                                                   \
+    G_STMT_START                                                                     \
+    {                                                                                \
+        g_assert(nmtst_initialized());                                               \
+        if (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message) { \
+            g_debug("nmtst: assert-logging: g_test_expect_message %s",               \
+                    G_STRINGIFY((__VA_ARGS__)));                                     \
+        } else {                                                                     \
+            G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                         \
+            g_test_expect_message(__VA_ARGS__);                                      \
+            G_GNUC_END_IGNORE_DEPRECATIONS                                           \
+        }                                                                            \
+    }                                                                                \
+    G_STMT_END
+#undef g_test_assert_expected_messages_internal
+#define g_test_assert_expected_messages_internal(domain, file, line, func)                   \
+    G_STMT_START                                                                             \
+    {                                                                                        \
+        const char *_domain = (domain);                                                      \
+        const char *_file   = (file);                                                        \
+        const char *_func   = (func);                                                        \
+        int         _line   = (line);                                                        \
+                                                                                             \
+        if (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message)           \
+            g_debug("nmtst: assert-logging: g_test_assert_expected_messages(%s, %s:%d, %s)", \
+                    _domain ?: "",                                                           \
+                    _file ?: "",                                                             \
+                    _line,                                                                   \
+                    _func ?: "");                                                            \
+                                                                                             \
+        G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                                     \
+        g_test_assert_expected_messages_internal(_domain, _file, _line, _func);              \
+        G_GNUC_END_IGNORE_DEPRECATIONS                                                       \
+    }                                                                                        \
+    G_STMT_END
 #endif
 
 #define NMTST_EXPECT(domain, level, msg) g_test_expect_message(domain, level, msg)
@@ -1032,7 +1032,7 @@ nmtst_rand_perm_strv(const char *const *strv)
     /* this returns a (scrambled) SHALLOW copy of the strv array! */
 
     n   = NM_PTRARRAY_LEN(strv);
-    res = (const char **) (nm_utils_strv_dup(strv, n, FALSE) ?: g_new0(char *, 1));
+    res = (const char **) (nm_strv_dup(strv, n, FALSE) ?: g_new0(char *, 1));
     nmtst_rand_perm(NULL, res, res, sizeof(char *), n);
     return res;
 }
@@ -1238,7 +1238,7 @@ _nmtst_main_loop_quit_on_notify(GObject *object, GParamSpec *pspec, gpointer use
 
     g_main_loop_quit(loop);
 }
-#define nmtst_main_loop_quit_on_notify ((GCallback) _nmtst_main_loop_quit_on_notify)
+#define nmtst_main_loop_quit_on_notify (G_CALLBACK(_nmtst_main_loop_quit_on_notify))
 
 #define nmtst_main_context_iterate_until_full(context, timeout_msec, poll_msec, condition)      \
     ({                                                                                          \
@@ -1458,6 +1458,19 @@ next:;
 
 /*****************************************************************************/
 
+/* uses an expression statement to copy and return @arg. The use is for functions
+ * like nmtst_inet4_from_string(), which return a static (thread-local) variable.
+ * If you use such a statement twice, the result will be overwritten. The macro
+ * prevents that. */
+#define NMTST_COPY(arg)           \
+    ({                            \
+        typeof(arg) _arg = (arg); \
+                                  \
+        _arg;                     \
+    })
+
+/*****************************************************************************/
+
 #define __define_nmtst_static(NUM, SIZE)                                   \
     static inline const char *nmtst_static_##SIZE##_##NUM(const char *str) \
     {                                                                      \
@@ -1475,9 +1488,9 @@ __define_nmtst_static(01, 1024) __define_nmtst_static(02, 1024) __define_nmtst_s
 
 #if defined(__NM_UTILS_H__) || defined(NM_UTILS_H)
 
-    #define NMTST_UUID_INIT(uuid)                                          \
-        gs_free char *    _nmtst_hidden_##uuid = nm_utils_uuid_generate(); \
-        const char *const uuid                 = _nmtst_hidden_##uuid
+#define NMTST_UUID_INIT(uuid)                                          \
+    gs_free char *    _nmtst_hidden_##uuid = nm_utils_uuid_generate(); \
+    const char *const uuid                 = _nmtst_hidden_##uuid
 
     static inline const char *nmtst_uuid_generate(void)
 {
@@ -1819,13 +1832,13 @@ _nmtst_assert_resolve_relative_path_equals(const char *f1,
 
 #ifdef __NETWORKMANAGER_LOGGING_H__
 
-    #define NMTST_EXPECT_NM(level, msg) NMTST_EXPECT("NetworkManager", level, msg)
+#define NMTST_EXPECT_NM(level, msg) NMTST_EXPECT("NetworkManager", level, msg)
 
-    #define NMTST_EXPECT_NM_ERROR(msg) NMTST_EXPECT_NM(G_LOG_LEVEL_MESSAGE, "*<error> [*] " msg)
-    #define NMTST_EXPECT_NM_WARN(msg)  NMTST_EXPECT_NM(G_LOG_LEVEL_MESSAGE, "*<warn>  [*] " msg)
-    #define NMTST_EXPECT_NM_INFO(msg)  NMTST_EXPECT_NM(G_LOG_LEVEL_INFO, "*<info>  [*] " msg)
-    #define NMTST_EXPECT_NM_DEBUG(msg) NMTST_EXPECT_NM(G_LOG_LEVEL_DEBUG, "*<debug> [*] " msg)
-    #define NMTST_EXPECT_NM_TRACE(msg) NMTST_EXPECT_NM(G_LOG_LEVEL_DEBUG, "*<trace> [*] " msg)
+#define NMTST_EXPECT_NM_ERROR(msg) NMTST_EXPECT_NM(G_LOG_LEVEL_MESSAGE, "*<error> [*] " msg)
+#define NMTST_EXPECT_NM_WARN(msg)  NMTST_EXPECT_NM(G_LOG_LEVEL_MESSAGE, "*<warn>  [*] " msg)
+#define NMTST_EXPECT_NM_INFO(msg)  NMTST_EXPECT_NM(G_LOG_LEVEL_INFO, "*<info>  [*] " msg)
+#define NMTST_EXPECT_NM_DEBUG(msg) NMTST_EXPECT_NM(G_LOG_LEVEL_DEBUG, "*<debug> [*] " msg)
+#define NMTST_EXPECT_NM_TRACE(msg) NMTST_EXPECT_NM(G_LOG_LEVEL_DEBUG, "*<trace> [*] " msg)
 
 static inline void
 nmtst_init_with_logging(int *argc, char ***argv, const char *log_level, const char *log_domains)
@@ -1982,16 +1995,38 @@ nmtst_assert_route_attribute_boolean(NMIPRoute *route, const char *name, gboolea
 #if (defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__)) \
     || (defined(NM_CONNECTION_H))
 
+#define nmtst_connection_assert_setting(connection, gtype)        \
+    ({                                                            \
+        const GType _gtype = (gtype);                             \
+        gpointer    _ptr;                                         \
+                                                                  \
+        _ptr = nm_connection_get_setting((connection), (_gtype)); \
+        g_assert(NM_IS_SETTING(_ptr));                            \
+        g_assert(G_OBJECT_TYPE(_ptr) == _gtype);                  \
+        _ptr;                                                     \
+    })
+
+#define nmtst_connection_assert_no_setting(connection, gtype)     \
+    G_STMT_START                                                  \
+    {                                                             \
+        const GType _gtype = (gtype);                             \
+        gpointer    _ptr;                                         \
+                                                                  \
+        _ptr = nm_connection_get_setting((connection), (_gtype)); \
+        g_assert(!_ptr);                                          \
+    }                                                             \
+    G_STMT_END
+
 static inline NMConnection *
 nmtst_clone_connection(NMConnection *connection)
 {
     g_assert(NM_IS_CONNECTION(connection));
 
-    #if defined(__NM_SIMPLE_CONNECTION_H__)
+#if defined(__NM_SIMPLE_CONNECTION_H__)
     return nm_simple_connection_new_clone(connection);
-    #else
+#else
     return nm_connection_duplicate(connection);
-    #endif
+#endif
 }
 
 static inline NMConnection *
@@ -2015,11 +2050,11 @@ nmtst_create_minimal_connection(const char *          id,
     if (type) {
         GType type_g;
 
-    #if defined(__NM_SIMPLE_CONNECTION_H__)
+#if defined(__NM_SIMPLE_CONNECTION_H__)
         type_g = nm_setting_lookup_type(type);
-    #else
+#else
         type_g = nm_connection_lookup_setting_type(type);
-    #endif
+#endif
 
         g_assert(type_g != G_TYPE_INVALID);
 
@@ -2027,11 +2062,11 @@ nmtst_create_minimal_connection(const char *          id,
         g_assert(NM_IS_SETTING(s_base));
     }
 
-    #if defined(__NM_SIMPLE_CONNECTION_H__)
+#if defined(__NM_SIMPLE_CONNECTION_H__)
     con = nm_simple_connection_new();
-    #else
+#else
     con = nm_connection_new();
-    #endif
+#endif
 
     g_assert(con);
 
@@ -2096,8 +2131,8 @@ _nmtst_connection_normalize(NMConnection *connection, ...)
 
     return was_modified;
 }
-    #define nmtst_connection_normalize(connection, ...) \
-        _nmtst_connection_normalize(connection, ##__VA_ARGS__, NULL)
+#define nmtst_connection_normalize(connection, ...) \
+    _nmtst_connection_normalize(connection, ##__VA_ARGS__, NULL)
 
 static inline NMConnection *
 _nmtst_connection_duplicate_and_normalize(NMConnection *connection, ...)
@@ -2112,8 +2147,8 @@ _nmtst_connection_duplicate_and_normalize(NMConnection *connection, ...)
 
     return connection;
 }
-    #define nmtst_connection_duplicate_and_normalize(connection, ...) \
-        _nmtst_connection_duplicate_and_normalize(connection, ##__VA_ARGS__, NULL)
+#define nmtst_connection_duplicate_and_normalize(connection, ...) \
+    _nmtst_connection_duplicate_and_normalize(connection, ##__VA_ARGS__, NULL)
 
 static inline void
 nmtst_assert_connection_equals(NMConnection *a,
@@ -2152,7 +2187,7 @@ nmtst_assert_connection_equals(NMConnection *a,
             }
         }
 
-    #ifdef __NM_KEYFILE_INTERNAL_H__
+#ifdef __NM_KEYFILE_INTERNAL_H__
         {
             nm_auto_unref_keyfile GKeyFile *kf_a = NULL, *kf_b = NULL;
             gs_free char *                  str_a = NULL, *str_b = NULL;
@@ -2174,7 +2209,7 @@ nmtst_assert_connection_equals(NMConnection *a,
                         "the difference*):\n%s",
                         str_b);
         }
-    #endif
+#endif
     }
     g_assert(compare);
     g_assert(!out_settings);
@@ -2308,8 +2343,8 @@ nmtst_assert_setting_verifies(NMSetting *setting)
     g_assert(success);
 }
 
-    #if defined(__NM_SIMPLE_CONNECTION_H__) && NM_CHECK_VERSION(1, 10, 0) \
-        && (!defined(NM_VERSION_MAX_ALLOWED) || NM_VERSION_MAX_ALLOWED >= NM_VERSION_1_10)
+#if defined(__NM_SIMPLE_CONNECTION_H__) && NM_CHECK_VERSION(1, 10, 0) \
+    && (!defined(NM_VERSION_MAX_ALLOWED) || NM_VERSION_MAX_ALLOWED >= NM_VERSION_1_10)
 static inline void
 _nmtst_assert_connection_has_settings(NMConnection *connection,
                                       gboolean      has_at_least,
@@ -2363,13 +2398,13 @@ _nmtst_assert_connection_has_settings(NMConnection *connection,
                 has_str);
     }
 }
-        #define nmtst_assert_connection_has_settings(connection, ...) \
-            _nmtst_assert_connection_has_settings((connection), TRUE, TRUE, __VA_ARGS__, NULL)
-        #define nmtst_assert_connection_has_settings_at_least(connection, ...) \
-            _nmtst_assert_connection_has_settings((connection), TRUE, FALSE, __VA_ARGS__, NULL)
-        #define nmtst_assert_connection_has_settings_at_most(connection, ...) \
-            _nmtst_assert_connection_has_settings((connection), FALSE, TRUE, __VA_ARGS__, NULL)
-    #endif
+#define nmtst_assert_connection_has_settings(connection, ...) \
+    _nmtst_assert_connection_has_settings((connection), TRUE, TRUE, __VA_ARGS__, NULL)
+#define nmtst_assert_connection_has_settings_at_least(connection, ...) \
+    _nmtst_assert_connection_has_settings((connection), TRUE, FALSE, __VA_ARGS__, NULL)
+#define nmtst_assert_connection_has_settings_at_most(connection, ...) \
+    _nmtst_assert_connection_has_settings((connection), FALSE, TRUE, __VA_ARGS__, NULL)
+#endif
 
 static inline void
 nmtst_assert_setting_verify_fails(NMSetting *setting,
@@ -2485,8 +2520,8 @@ nmtst_assert_hwaddr_equals(gconstpointer hwaddr1,
                 hwaddr1_len);
     }
 }
-    #define nmtst_assert_hwaddr_equals(hwaddr1, hwaddr1_len, expected) \
-        nmtst_assert_hwaddr_equals(hwaddr1, hwaddr1_len, expected, __FILE__, __LINE__)
+#define nmtst_assert_hwaddr_equals(hwaddr1, hwaddr1_len, expected) \
+    nmtst_assert_hwaddr_equals(hwaddr1, hwaddr1_len, expected, __FILE__, __LINE__)
 #endif
 
 #if defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__) \
@@ -2547,89 +2582,89 @@ _nmtst_variant_new_vardict(int dummy, ...)
 
     return g_variant_builder_end(&builder);
 }
-    #define nmtst_variant_new_vardict(...) _nmtst_variant_new_vardict(0, __VA_ARGS__, NULL)
-
-    #define nmtst_assert_variant_is_of_type(variant, type)     \
-        G_STMT_START                                           \
-        {                                                      \
-            GVariant *_variantx = (variant);                   \
-                                                               \
-            g_assert(_variantx);                               \
-            g_assert(g_variant_is_of_type(_variantx, (type))); \
-        }                                                      \
-        G_STMT_END
-
-    #define nmtst_assert_variant_uint32(variant, val)                         \
-        G_STMT_START                                                          \
-        {                                                                     \
-            GVariant *_variant = (variant);                                   \
-                                                                              \
-            nmtst_assert_variant_is_of_type(_variant, G_VARIANT_TYPE_UINT32); \
-            g_assert_cmpint(g_variant_get_uint32(_variant), ==, (val));       \
-        }                                                                     \
-        G_STMT_END
-
-    #define nmtst_assert_variant_string(variant, str)                         \
-        G_STMT_START                                                          \
-        {                                                                     \
-            gsize       _l;                                                   \
-            GVariant *  _variant = (variant);                                 \
-            const char *_str     = (str);                                     \
+#define nmtst_variant_new_vardict(...) _nmtst_variant_new_vardict(0, __VA_ARGS__, NULL)
+
+#define nmtst_assert_variant_is_of_type(variant, type)     \
+    G_STMT_START                                           \
+    {                                                      \
+        GVariant *_variantx = (variant);                   \
+                                                           \
+        g_assert(_variantx);                               \
+        g_assert(g_variant_is_of_type(_variantx, (type))); \
+    }                                                      \
+    G_STMT_END
+
+#define nmtst_assert_variant_uint32(variant, val)                         \
+    G_STMT_START                                                          \
+    {                                                                     \
+        GVariant *_variant = (variant);                                   \
+                                                                          \
+        nmtst_assert_variant_is_of_type(_variant, G_VARIANT_TYPE_UINT32); \
+        g_assert_cmpint(g_variant_get_uint32(_variant), ==, (val));       \
+    }                                                                     \
+    G_STMT_END
+
+#define nmtst_assert_variant_string(variant, str)                         \
+    G_STMT_START                                                          \
+    {                                                                     \
+        gsize       _l;                                                   \
+        GVariant *  _variant = (variant);                                 \
+        const char *_str     = (str);                                     \
+                                                                          \
+        nmtst_assert_variant_is_of_type(_variant, G_VARIANT_TYPE_STRING); \
+        g_assert(_str);                                                   \
+        g_assert_cmpstr(g_variant_get_string(_variant, &_l), ==, _str);   \
+        g_assert_cmpint(_l, ==, strlen(_str));                            \
+    }                                                                     \
+    G_STMT_END
+
+#ifdef __NM_SHARED_UTILS_H__
+#define _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len)                      \
+    G_STMT_START                                                                         \
+    {                                                                                    \
+        if (memcmp(_ptr2, _ptr, _len) != 0) {                                            \
+            gs_free char *_x1 = NULL;                                                    \
+            gs_free char *_x2 = NULL;                                                    \
+            const char *  _xx1;                                                          \
+            const char *  _xx2;                                                          \
+                                                                                         \
+            _xx1 = nm_utils_buf_utf8safe_escape(_ptr,                                    \
+                                                _len,                                    \
+                                                NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, \
+                                                &_x1);                                   \
+            _xx2 = nm_utils_buf_utf8safe_escape(_ptr2,                                   \
+                                                _len,                                    \
+                                                NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, \
+                                                &_x2);                                   \
+            g_assert_cmpstr(_xx1, ==, _xx2);                                             \
+            g_assert_not_reached();                                                      \
+        }                                                                                \
+    }                                                                                    \
+    G_STMT_END
+#else
+#define _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len) \
+    G_STMT_START {}                                                 \
+    G_STMT_END
+#endif
+
+#define nmtst_assert_variant_bytestring(variant, ptr, len)                    \
+    G_STMT_START                                                              \
+    {                                                                         \
+        GVariant *    _variant = (variant);                                   \
+        gconstpointer _ptr     = (ptr);                                       \
+        gconstpointer _ptr2;                                                  \
+        gsize         _len = (len);                                           \
+        gsize         _len2;                                                  \
                                                                               \
-            nmtst_assert_variant_is_of_type(_variant, G_VARIANT_TYPE_STRING); \
-            g_assert(_str);                                                   \
-            g_assert_cmpstr(g_variant_get_string(_variant, &_l), ==, _str);   \
-            g_assert_cmpint(_l, ==, strlen(_str));                            \
+        nmtst_assert_variant_is_of_type(_variant, G_VARIANT_TYPE_BYTESTRING); \
+        _ptr2 = g_variant_get_fixed_array(_variant, &_len2, 1);               \
+        g_assert_cmpint(_len2, ==, _len);                                     \
+        if (_len != 0 && _ptr) {                                              \
+            _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len);      \
+            g_assert_cmpmem(_ptr2, _len2, _ptr, _len);                        \
         }                                                                     \
-        G_STMT_END
-
-    #ifdef __NM_SHARED_UTILS_H__
-        #define _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len)                      \
-            G_STMT_START                                                                         \
-            {                                                                                    \
-                if (memcmp(_ptr2, _ptr, _len) != 0) {                                            \
-                    gs_free char *_x1 = NULL;                                                    \
-                    gs_free char *_x2 = NULL;                                                    \
-                    const char *  _xx1;                                                          \
-                    const char *  _xx2;                                                          \
-                                                                                                 \
-                    _xx1 = nm_utils_buf_utf8safe_escape(_ptr,                                    \
-                                                        _len,                                    \
-                                                        NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, \
-                                                        &_x1);                                   \
-                    _xx2 = nm_utils_buf_utf8safe_escape(_ptr2,                                   \
-                                                        _len,                                    \
-                                                        NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, \
-                                                        &_x2);                                   \
-                    g_assert_cmpstr(_xx1, ==, _xx2);                                             \
-                    g_assert_not_reached();                                                      \
-                }                                                                                \
-            }                                                                                    \
-            G_STMT_END
-    #else
-        #define _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len) \
-            G_STMT_START {}                                                 \
-            G_STMT_END
-    #endif
-
-    #define nmtst_assert_variant_bytestring(variant, ptr, len)                    \
-        G_STMT_START                                                              \
-        {                                                                         \
-            GVariant *    _variant = (variant);                                   \
-            gconstpointer _ptr     = (ptr);                                       \
-            gconstpointer _ptr2;                                                  \
-            gsize         _len = (len);                                           \
-            gsize         _len2;                                                  \
-                                                                                  \
-            nmtst_assert_variant_is_of_type(_variant, G_VARIANT_TYPE_BYTESTRING); \
-            _ptr2 = g_variant_get_fixed_array(_variant, &_len2, 1);               \
-            g_assert_cmpint(_len2, ==, _len);                                     \
-            if (_len != 0 && _ptr) {                                              \
-                _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len);      \
-                g_assert_cmpmem(_ptr2, _len2, _ptr, _len);                        \
-            }                                                                     \
-        }                                                                         \
-        G_STMT_END
+    }                                                                         \
+    G_STMT_END
 
 typedef enum {
     NMTST_VARIANT_EDITOR_CONNECTION,
@@ -2637,120 +2672,117 @@ typedef enum {
     NMTST_VARIANT_EDITOR_PROPERTY
 } NmtstVariantEditorPhase;
 
-    #define NMTST_VARIANT_EDITOR(__connection_variant, __code)                         \
-        G_STMT_START                                                                   \
-        {                                                                              \
-            GVariantIter            __connection_iter, *__setting_iter;                \
-            GVariantBuilder         __connection_builder, __setting_builder;           \
-            const char *            __cur_setting_name, *__cur_property_name;          \
-            GVariant *              __property_val;                                    \
-            NmtstVariantEditorPhase __phase;                                           \
-                                                                                       \
-            g_variant_builder_init(&__connection_builder, NM_VARIANT_TYPE_CONNECTION); \
-            g_variant_iter_init(&__connection_iter, __connection_variant);             \
-                                                                                       \
-            __phase             = NMTST_VARIANT_EDITOR_CONNECTION;                     \
-            __cur_setting_name  = NULL;                                                \
-            __cur_property_name = NULL;                                                \
-            __code;                                                                    \
-            while (g_variant_iter_next(&__connection_iter,                             \
-                                       "{&sa{sv}}",                                    \
-                                       &__cur_setting_name,                            \
-                                       &__setting_iter)) {                             \
-                g_variant_builder_init(&__setting_builder, NM_VARIANT_TYPE_SETTING);   \
-                __phase             = NMTST_VARIANT_EDITOR_SETTING;                    \
-                __cur_property_name = NULL;                                            \
-                __code;                                                                \
-                                                                                       \
-                while (__cur_setting_name                                              \
-                       && g_variant_iter_next(__setting_iter,                          \
-                                              "{&sv}",                                 \
-                                              &__cur_property_name,                    \
-                                              &__property_val)) {                      \
-                    __phase = NMTST_VARIANT_EDITOR_PROPERTY;                           \
-                    __code;                                                            \
-                                                                                       \
-                    if (__cur_property_name) {                                         \
-                        g_variant_builder_add(&__setting_builder,                      \
-                                              "{sv}",                                  \
-                                              __cur_property_name,                     \
-                                              __property_val);                         \
-                    }                                                                  \
-                    g_variant_unref(__property_val);                                   \
-                }                                                                      \
-                                                                                       \
-                if (__cur_setting_name)                                                \
-                    g_variant_builder_add(&__connection_builder,                       \
-                                          "{sa{sv}}",                                  \
-                                          __cur_setting_name,                          \
-                                          &__setting_builder);                         \
-                else                                                                   \
-                    g_variant_builder_clear(&__setting_builder);                       \
-                g_variant_iter_free(__setting_iter);                                   \
-            }                                                                          \
-                                                                                       \
-            g_variant_unref(__connection_variant);                                     \
-                                                                                       \
-            __connection_variant = g_variant_builder_end(&__connection_builder);       \
-        }                                                                              \
-        G_STMT_END;
-
-    #define NMTST_VARIANT_ADD_SETTING(__setting_name, __setting_variant) \
-        G_STMT_START                                                     \
-        {                                                                \
-            if (__phase == NMTST_VARIANT_EDITOR_CONNECTION)              \
-                g_variant_builder_add(&__connection_builder,             \
-                                      "{s@a{sv}}",                       \
-                                      __setting_name,                    \
-                                      __setting_variant);                \
-        }                                                                \
-        G_STMT_END
-
-    #define NMTST_VARIANT_DROP_SETTING(__setting_name)                           \
-        G_STMT_START                                                             \
-        {                                                                        \
-            if (__phase == NMTST_VARIANT_EDITOR_SETTING && __cur_setting_name) { \
-                if (!strcmp(__cur_setting_name, __setting_name))                 \
-                    __cur_setting_name = NULL;                                   \
-            }                                                                    \
-        }                                                                        \
-        G_STMT_END
-
-    #define NMTST_VARIANT_ADD_PROPERTY(__setting_name, __property_name, __format_string, __value) \
-        G_STMT_START                                                                              \
-        {                                                                                         \
-            if (__phase == NMTST_VARIANT_EDITOR_SETTING) {                                        \
-                if (!strcmp(__cur_setting_name, __setting_name)) {                                \
-                    g_variant_builder_add(&__setting_builder,                                     \
-                                          "{sv}",                                                 \
-                                          __property_name,                                        \
-                                          g_variant_new(__format_string, __value));               \
-                }                                                                                 \
-            }                                                                                     \
-        }                                                                                         \
-        G_STMT_END
-
-    #define NMTST_VARIANT_DROP_PROPERTY(__setting_name, __property_name)           \
-        G_STMT_START                                                               \
-        {                                                                          \
-            if (__phase == NMTST_VARIANT_EDITOR_PROPERTY && __cur_property_name) { \
-                if (!strcmp(__cur_setting_name, __setting_name)                    \
-                    && !strcmp(__cur_property_name, __property_name))              \
-                    __cur_property_name = NULL;                                    \
+#define NMTST_VARIANT_EDITOR(__connection_variant, __code)                         \
+    G_STMT_START                                                                   \
+    {                                                                              \
+        GVariantIter            __connection_iter, *__setting_iter;                \
+        GVariantBuilder         __connection_builder, __setting_builder;           \
+        const char *            __cur_setting_name, *__cur_property_name;          \
+        GVariant *              __property_val;                                    \
+        NmtstVariantEditorPhase __phase;                                           \
+                                                                                   \
+        g_variant_builder_init(&__connection_builder, NM_VARIANT_TYPE_CONNECTION); \
+        g_variant_iter_init(&__connection_iter, __connection_variant);             \
+                                                                                   \
+        __phase             = NMTST_VARIANT_EDITOR_CONNECTION;                     \
+        __cur_setting_name  = NULL;                                                \
+        __cur_property_name = NULL;                                                \
+        __code;                                                                    \
+        while (g_variant_iter_next(&__connection_iter,                             \
+                                   "{&sa{sv}}",                                    \
+                                   &__cur_setting_name,                            \
+                                   &__setting_iter)) {                             \
+            g_variant_builder_init(&__setting_builder, NM_VARIANT_TYPE_SETTING);   \
+            __phase             = NMTST_VARIANT_EDITOR_SETTING;                    \
+            __cur_property_name = NULL;                                            \
+            __code;                                                                \
+                                                                                   \
+            while (__cur_setting_name                                              \
+                   && g_variant_iter_next(__setting_iter,                          \
+                                          "{&sv}",                                 \
+                                          &__cur_property_name,                    \
+                                          &__property_val)) {                      \
+                __phase = NMTST_VARIANT_EDITOR_PROPERTY;                           \
+                __code;                                                            \
+                                                                                   \
+                if (__cur_property_name) {                                         \
+                    g_variant_builder_add(&__setting_builder,                      \
+                                          "{sv}",                                  \
+                                          __cur_property_name,                     \
+                                          __property_val);                         \
+                }                                                                  \
+                g_variant_unref(__property_val);                                   \
             }                                                                      \
+                                                                                   \
+            if (__cur_setting_name)                                                \
+                g_variant_builder_add(&__connection_builder,                       \
+                                      "{sa{sv}}",                                  \
+                                      __cur_setting_name,                          \
+                                      &__setting_builder);                         \
+            else                                                                   \
+                g_variant_builder_clear(&__setting_builder);                       \
+            g_variant_iter_free(__setting_iter);                                   \
         }                                                                          \
-        G_STMT_END
-
-    #define NMTST_VARIANT_CHANGE_PROPERTY(__setting_name,                                          \
-                                          __property_name,                                         \
-                                          __format_string,                                         \
-                                          __value)                                                 \
-        G_STMT_START                                                                               \
-        {                                                                                          \
-            NMTST_VARIANT_DROP_PROPERTY(__setting_name, __property_name);                          \
-            NMTST_VARIANT_ADD_PROPERTY(__setting_name, __property_name, __format_string, __value); \
-        }                                                                                          \
-        G_STMT_END
+                                                                                   \
+        g_variant_unref(__connection_variant);                                     \
+                                                                                   \
+        __connection_variant = g_variant_builder_end(&__connection_builder);       \
+    }                                                                              \
+    G_STMT_END;
+
+#define NMTST_VARIANT_ADD_SETTING(__setting_name, __setting_variant) \
+    G_STMT_START                                                     \
+    {                                                                \
+        if (__phase == NMTST_VARIANT_EDITOR_CONNECTION)              \
+            g_variant_builder_add(&__connection_builder,             \
+                                  "{s@a{sv}}",                       \
+                                  __setting_name,                    \
+                                  __setting_variant);                \
+    }                                                                \
+    G_STMT_END
+
+#define NMTST_VARIANT_DROP_SETTING(__setting_name)                           \
+    G_STMT_START                                                             \
+    {                                                                        \
+        if (__phase == NMTST_VARIANT_EDITOR_SETTING && __cur_setting_name) { \
+            if (!strcmp(__cur_setting_name, __setting_name))                 \
+                __cur_setting_name = NULL;                                   \
+        }                                                                    \
+    }                                                                        \
+    G_STMT_END
+
+#define NMTST_VARIANT_ADD_PROPERTY(__setting_name, __property_name, __format_string, __value) \
+    G_STMT_START                                                                              \
+    {                                                                                         \
+        if (__phase == NMTST_VARIANT_EDITOR_SETTING) {                                        \
+            if (!strcmp(__cur_setting_name, __setting_name)) {                                \
+                g_variant_builder_add(&__setting_builder,                                     \
+                                      "{sv}",                                                 \
+                                      __property_name,                                        \
+                                      g_variant_new(__format_string, __value));               \
+            }                                                                                 \
+        }                                                                                     \
+    }                                                                                         \
+    G_STMT_END
+
+#define NMTST_VARIANT_DROP_PROPERTY(__setting_name, __property_name)           \
+    G_STMT_START                                                               \
+    {                                                                          \
+        if (__phase == NMTST_VARIANT_EDITOR_PROPERTY && __cur_property_name) { \
+            if (!strcmp(__cur_setting_name, __setting_name)                    \
+                && !strcmp(__cur_property_name, __property_name))              \
+                __cur_property_name = NULL;                                    \
+        }                                                                      \
+    }                                                                          \
+    G_STMT_END
+
+#define NMTST_VARIANT_CHANGE_PROPERTY(__setting_name, __property_name, __format_string, __value) \
+    G_STMT_START                                                                                 \
+    {                                                                                            \
+        NMTST_VARIANT_DROP_PROPERTY(__setting_name, __property_name);                            \
+        NMTST_VARIANT_ADD_PROPERTY(__setting_name, __property_name, __format_string, __value);   \
+    }                                                                                            \
+    G_STMT_END
 
 #endif /* __NM_CONNECTION_H__ */
 
@@ -2857,4 +2889,20 @@ nmtst_ip_address_new(int addr_family, const char *str)
 
 /*****************************************************************************/
 
+#define nmtst_gbytes_from_arr(...)           \
+    ({                                       \
+        const guint8 _arr[] = {__VA_ARGS__}; \
+                                             \
+        g_bytes_new(_arr, sizeof(_arr));     \
+    })
+
+#define nmtst_gbytes_from_str(str)       \
+    ({                                   \
+        const char *const _str = (str);  \
+                                         \
+        g_bytes_new(_str, strlen(_str)); \
+    })
+
+/*****************************************************************************/
+
 #endif /* __NM_TEST_UTILS_H__ */
diff --git a/src/libnm-glib-aux/nm-uuid.c b/src/libnm-glib-aux/nm-uuid.c
index 2c6e218a..e7f67c70 100644
--- a/src/libnm-glib-aux/nm-uuid.c
+++ b/src/libnm-glib-aux/nm-uuid.c
@@ -9,6 +9,13 @@
 
 /*****************************************************************************/
 
+const NMUuid nm_uuid_ns_zero =
+    NM_UUID_INIT(00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00);
+
+/* arbitrarily chosen namespace UUID for nm_uuid_generate_from_strings() */
+const NMUuid nm_uuid_ns_1 =
+    NM_UUID_INIT(b4, 25, e9, fb, 75, 98, 44, b4, 9e, 3b, 5a, 2e, 3a, aa, 49, 05);
+
 char *
 nm_uuid_unparse_case(const NMUuid *uuid, char out_str[static 37], gboolean upper_case)
 {
@@ -171,7 +178,7 @@ nm_uuid_is_valid_nmlegacy(const char *str)
     }
 
     /* While we accept here bogus strings as UUIDs, they must contain only
-     * hexdigits and '-', and they must be eithr 36 or 40 chars long. */
+     * hexdigits and '-', and they must be either 36 or 40 chars long. */
 
     if ((num_dashes == 4) && (p - str == 36))
         return TRUE;
@@ -234,16 +241,20 @@ nm_uuid_is_valid_nm(const char *str,
             nm_assert(strlen(str) < G_N_ELEMENTS(str_lower));
 
             /* normalize first to lower-case. */
-            g_strlcpy(str_lower, str, sizeof(str_lower));
-            for (i = 0; str_lower[i]; i++)
-                str_lower[i] = g_ascii_tolower(str_lower[i]);
+            for (i = 0; str[i]; i++) {
+                nm_assert(i < G_N_ELEMENTS(str_lower));
+                str_lower[i] = g_ascii_tolower(str[i]);
+            }
+            nm_assert(i < G_N_ELEMENTS(str_lower));
+            str_lower[i] = '\0';
 
             /* The namespace UUID is chosen randomly. */
-            nm_uuid_generate_from_string(&uuid,
-                                         str_lower,
-                                         -1,
-                                         NM_UUID_TYPE_VERSION5,
-                                         "4e72f709-ca95-4405-9053-1f43294a618c");
+            nm_uuid_generate_from_string(
+                &uuid,
+                str_lower,
+                -1,
+                NM_UUID_TYPE_VERSION5,
+                &NM_UUID_INIT(4e, 72, f7, 09, ca, 95, 44, 05, 90, 53, 1f, 43, 29, 4a, 61, 8c));
             nm_uuid_unparse(&uuid, out_normalized_str);
         }
         return TRUE;
@@ -299,11 +310,11 @@ nm_uuid_generate_random_str(char buf[static 37])
  * Returns: the input @uuid. This function cannot fail.
  **/
 NMUuid *
-nm_uuid_generate_from_string(NMUuid *    uuid,
-                             const char *s,
-                             gssize      slen,
-                             NMUuidType  uuid_type,
-                             gpointer    type_args)
+nm_uuid_generate_from_string(NMUuid *      uuid,
+                             const char *  s,
+                             gssize        slen,
+                             NMUuidType    uuid_type,
+                             const NMUuid *type_args)
 {
     g_return_val_if_fail(uuid, FALSE);
     g_return_val_if_fail(slen == 0 || s, FALSE);
@@ -313,26 +324,20 @@ nm_uuid_generate_from_string(NMUuid *    uuid,
 
     switch (uuid_type) {
     case NM_UUID_TYPE_LEGACY:
-        g_return_val_if_fail(!type_args, NULL);
+        nm_assert(!type_args);
         nm_crypto_md5_hash(NULL, 0, (guint8 *) s, slen, (guint8 *) uuid, sizeof(*uuid));
         break;
     case NM_UUID_TYPE_VERSION3:
     case NM_UUID_TYPE_VERSION5:
     {
-        NMUuid ns_uuid;
-
-        if (type_args) {
-            /* type_args can be a name space UUID. Interpret it as (char *) */
-            if (!nm_uuid_parse(type_args, &ns_uuid))
-                g_return_val_if_reached(NULL);
-        } else
-            ns_uuid = (NMUuid){};
+        if (!type_args)
+            type_args = &nm_uuid_ns_zero;
 
         if (uuid_type == NM_UUID_TYPE_VERSION3) {
             nm_crypto_md5_hash((guint8 *) s,
                                slen,
-                               (guint8 *) &ns_uuid,
-                               sizeof(ns_uuid),
+                               (guint8 *) type_args,
+                               sizeof(*type_args),
                                (guint8 *) uuid,
                                sizeof(*uuid));
         } else {
@@ -343,7 +348,7 @@ nm_uuid_generate_from_string(NMUuid *    uuid,
             } digest;
 
             sum = g_checksum_new(G_CHECKSUM_SHA1);
-            g_checksum_update(sum, (guchar *) &ns_uuid, sizeof(ns_uuid));
+            g_checksum_update(sum, (guchar *) type_args, sizeof(*type_args));
             g_checksum_update(sum, (guchar *) s, slen);
             nm_utils_checksum_get_digest(sum, digest.sha1);
 
@@ -377,10 +382,10 @@ nm_uuid_generate_from_string(NMUuid *    uuid,
  * object's #NMSettingConnection:id: property
  **/
 char *
-nm_uuid_generate_from_string_str(const char *s,
-                                 gssize      slen,
-                                 NMUuidType  uuid_type,
-                                 gpointer    type_args)
+nm_uuid_generate_from_string_str(const char *  s,
+                                 gssize        slen,
+                                 NMUuidType    uuid_type,
+                                 const NMUuid *type_args)
 {
     NMUuid uuid;
 
@@ -405,7 +410,7 @@ char *
 nm_uuid_generate_from_strings(const char *string1, ...)
 {
     if (!string1)
-        return nm_uuid_generate_from_string_str(NULL, 0, NM_UUID_TYPE_VERSION3, NM_UUID_NS1);
+        return nm_uuid_generate_from_string_str(NULL, 0, NM_UUID_TYPE_VERSION3, &nm_uuid_ns_1);
 
     {
         nm_auto_str_buf NMStrBuf str = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE);
@@ -425,6 +430,6 @@ nm_uuid_generate_from_strings(const char *string1, ...)
         return nm_uuid_generate_from_string_str(nm_str_buf_get_str_unsafe(&str),
                                                 str.len,
                                                 NM_UUID_TYPE_VERSION3,
-                                                NM_UUID_NS1);
+                                                &nm_uuid_ns_1);
     }
 }
diff --git a/src/libnm-glib-aux/nm-uuid.h b/src/libnm-glib-aux/nm-uuid.h
index 10302bd8..504ec789 100644
--- a/src/libnm-glib-aux/nm-uuid.h
+++ b/src/libnm-glib-aux/nm-uuid.h
@@ -7,6 +7,28 @@ typedef struct _NMUuid {
     guint8 uuid[16];
 } NMUuid;
 
+#define NM_UUID_INIT_ZERO() ((NMUuid){.uuid = {0}})
+
+#define NM_UUID_INIT(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) \
+    ((NMUuid){                                                                             \
+        .uuid = {(0x##a0),                                                                 \
+                 (0x##a1),                                                                 \
+                 (0x##a2),                                                                 \
+                 (0x##a3),                                                                 \
+                 (0x##a4),                                                                 \
+                 (0x##a5),                                                                 \
+                 (0x##a6),                                                                 \
+                 (0x##a7),                                                                 \
+                 (0x##a8),                                                                 \
+                 (0x##a9),                                                                 \
+                 (0x##a10),                                                                \
+                 (0x##a11),                                                                \
+                 (0x##a12),                                                                \
+                 (0x##a13),                                                                \
+                 (0x##a14),                                                                \
+                 (0x##a15)},                                                               \
+    })
+
 char *nm_uuid_unparse_case(const NMUuid *uuid, char out_str[static 37], gboolean upper_case);
 
 static inline char *
@@ -73,25 +95,30 @@ char *nm_uuid_generate_random_str(char buf[static 37]);
 
 /*****************************************************************************/
 
+extern const NMUuid nm_uuid_ns_zero;
+extern const NMUuid nm_uuid_ns_1;
+
+#define NM_UUID_NS_ZERO "00000000-0000-0000-0000-000000000000"
+#define NM_UUID_NS_1    "b425e9fb-7598-44b4-9e3b-5a2e3aaa4905"
+
+/*****************************************************************************/
+
 typedef enum {
     NM_UUID_TYPE_LEGACY   = 0,
     NM_UUID_TYPE_VERSION3 = 3,
     NM_UUID_TYPE_VERSION5 = 5,
 } NMUuidType;
 
-NMUuid *nm_uuid_generate_from_string(NMUuid *    uuid,
-                                     const char *s,
-                                     gssize      slen,
-                                     NMUuidType  uuid_type,
-                                     gpointer    type_args);
-
-char *nm_uuid_generate_from_string_str(const char *s,
-                                       gssize      slen,
-                                       NMUuidType  uuid_type,
-                                       gpointer    type_args);
+NMUuid *nm_uuid_generate_from_string(NMUuid *      uuid,
+                                     const char *  s,
+                                     gssize        slen,
+                                     NMUuidType    uuid_type,
+                                     const NMUuid *type_args);
 
-/* arbitrarily chosen namespace UUID for nm_uuid_generate_from_strings() */
-#define NM_UUID_NS1 "b425e9fb-7598-44b4-9e3b-5a2e3aaa4905"
+char *nm_uuid_generate_from_string_str(const char *  s,
+                                       gssize        slen,
+                                       NMUuidType    uuid_type,
+                                       const NMUuid *type_args);
 
 char *nm_uuid_generate_from_strings(const char *string1, ...) G_GNUC_NULL_TERMINATED;
 
diff --git a/src/libnm-glib-aux/nm-value-type.h b/src/libnm-glib-aux/nm-value-type.h
index f1cce480..0addeec6 100644
--- a/src/libnm-glib-aux/nm-value-type.h
+++ b/src/libnm-glib-aux/nm-value-type.h
@@ -7,13 +7,27 @@
 #define __NM_VALUE_TYPE_H__
 
 typedef enum _nm_packed {
+    NM_VALUE_TYPE_NONE   = 0,
     NM_VALUE_TYPE_UNSPEC = 1,
     NM_VALUE_TYPE_BOOL   = 2,
     NM_VALUE_TYPE_INT32  = 3,
     NM_VALUE_TYPE_INT    = 4,
     NM_VALUE_TYPE_INT64  = 5,
-    NM_VALUE_TYPE_UINT64 = 6,
-    NM_VALUE_TYPE_STRING = 7,
+    NM_VALUE_TYPE_UINT32 = 6,
+    NM_VALUE_TYPE_UINT   = 7,
+    NM_VALUE_TYPE_UINT64 = 8,
+
+    /* Flags are for G_TYPE_FLAGS. That is, internally they are tracked
+     * as a guint, they have a g_param_spec_flags() property and they are
+     * serialized on D-Bus as "u". */
+    NM_VALUE_TYPE_FLAGS = 9,
+
+    /* G_TYPE_ENUM */
+    NM_VALUE_TYPE_ENUM = 10,
+
+    NM_VALUE_TYPE_STRING = 11,
+
+    NM_VALUE_TYPE_BYTES = 12,
 } NMValueType;
 
 /*****************************************************************************/
@@ -35,37 +49,37 @@ typedef union {
 
 } NMValueTypUnion;
 
-    /* Set the NMValueTypUnion. You can also assign the member directly.
+/* Set the NMValueTypUnion. You can also assign the member directly.
  * The only purpose of this is that it also returns a pointer to the
  * union. So, you can do
  *
  *   ptr = NM_VALUE_TYP_UNION_SET (&value_typ_union_storage, v_bool, TRUE);
  */
-    #define NM_VALUE_TYP_UNION_SET(_arg, _type, _val) \
-        ({                                            \
-            NMValueTypUnion *const _arg2 = (_arg);    \
-                                                      \
-            *_arg2 = (NMValueTypUnion){               \
-                ._type = (_val),                      \
-            };                                        \
-            _arg2;                                    \
-        })
+#define NM_VALUE_TYP_UNION_SET(_arg, _type, _val) \
+    ({                                            \
+        NMValueTypUnion *const _arg2 = (_arg);    \
+                                                  \
+        *_arg2 = (NMValueTypUnion){               \
+            ._type = (_val),                      \
+        };                                        \
+        _arg2;                                    \
+    })
 
 typedef struct {
     bool            has;
     NMValueTypUnion val;
 } NMValueTypUnioMaybe;
 
-    #define NM_VALUE_TYP_UNIO_MAYBE_SET(_arg, _type, _val) \
-        ({                                                 \
-            NMValueTypUnioMaybe *const _arg2 = (_arg);     \
-                                                           \
-            *_arg2 = (NMValueTypUnioMaybe){                \
-                .has       = TRUE,                         \
-                .val._type = (_val),                       \
-            };                                             \
-            _arg2;                                         \
-        })
+#define NM_VALUE_TYP_UNIO_MAYBE_SET(_arg, _type, _val) \
+    ({                                                 \
+        NMValueTypUnioMaybe *const _arg2 = (_arg);     \
+                                                       \
+        *_arg2 = (NMValueTypUnioMaybe){                \
+            .has       = TRUE,                         \
+            .val._type = (_val),                       \
+        };                                             \
+        _arg2;                                         \
+    })
 
 /*****************************************************************************/
 
@@ -80,16 +94,27 @@ nm_value_type_cmp(NMValueType value_type, gconstpointer p_a, gconstpointer p_b)
         NM_CMP_DIRECT(*((const gint32 *) p_a), *((const gint32 *) p_b));
         return 0;
     case NM_VALUE_TYPE_INT:
+    case NM_VALUE_TYPE_ENUM:
         NM_CMP_DIRECT(*((const int *) p_a), *((const int *) p_b));
         return 0;
     case NM_VALUE_TYPE_INT64:
         NM_CMP_DIRECT(*((const gint64 *) p_a), *((const gint64 *) p_b));
         return 0;
+    case NM_VALUE_TYPE_UINT32:
+        NM_CMP_DIRECT(*((const guint32 *) p_a), *((const guint32 *) p_b));
+        return 0;
+    case NM_VALUE_TYPE_UINT:
+    case NM_VALUE_TYPE_FLAGS:
+        NM_CMP_DIRECT(*((const guint *) p_a), *((const guint *) p_b));
+        return 0;
     case NM_VALUE_TYPE_UINT64:
         NM_CMP_DIRECT(*((const guint64 *) p_a), *((const guint64 *) p_b));
         return 0;
     case NM_VALUE_TYPE_STRING:
         return nm_strcmp0(*((const char *const *) p_a), *((const char *const *) p_b));
+    case NM_VALUE_TYPE_BYTES:
+        return nm_g_bytes_equal0(*((const GBytes *const *) p_a), *((const GBytes *const *) p_b));
+    case NM_VALUE_TYPE_NONE:
     case NM_VALUE_TYPE_UNSPEC:
         break;
     }
@@ -114,21 +139,39 @@ nm_value_type_copy(NMValueType value_type, gpointer dst, gconstpointer src)
         (*((gint32 *) dst) = *((const gint32 *) src));
         return;
     case NM_VALUE_TYPE_INT:
+    case NM_VALUE_TYPE_ENUM:
         (*((int *) dst) = *((const int *) src));
         return;
     case NM_VALUE_TYPE_INT64:
         (*((gint64 *) dst) = *((const gint64 *) src));
         return;
+    case NM_VALUE_TYPE_UINT32:
+        (*((guint32 *) dst) = *((const guint32 *) src));
+        return;
+    case NM_VALUE_TYPE_UINT:
+    case NM_VALUE_TYPE_FLAGS:
+        (*((guint *) dst) = *((const guint *) src));
+        return;
     case NM_VALUE_TYPE_UINT64:
         (*((guint64 *) dst) = *((const guint64 *) src));
         return;
     case NM_VALUE_TYPE_STRING:
         /* self assignment safe! */
         if (*((char **) dst) != *((const char *const *) src)) {
-            g_free(*((char **) dst));
+            _nm_unused char *old = *((char **) dst);
+
             *((char **) dst) = g_strdup(*((const char *const *) src));
         }
         return;
+    case NM_VALUE_TYPE_BYTES:
+        /* self assignment safe! */
+        if (*((GBytes **) dst) != *((const GBytes *const *) src)) {
+            _nm_unused gs_unref_bytes GBytes *old = *((GBytes **) dst);
+
+            *((GBytes **) dst) = g_bytes_ref(*((GBytes *const *) src));
+        }
+        return;
+    case NM_VALUE_TYPE_NONE:
     case NM_VALUE_TYPE_UNSPEC:
         break;
     }
@@ -151,12 +194,16 @@ nm_value_type_get_from_variant(NMValueType value_type,
     case NM_VALUE_TYPE_INT64:
         *((gint64 *) dst) = g_variant_get_int64(variant);
         return;
+    case NM_VALUE_TYPE_UINT32:
+        *((guint32 *) dst) = g_variant_get_uint32(variant);
+        return;
     case NM_VALUE_TYPE_UINT64:
         *((guint64 *) dst) = g_variant_get_uint64(variant);
         return;
     case NM_VALUE_TYPE_STRING:
         if (clone) {
-            g_free(*((char **) dst));
+            _nm_unused gs_free char *old = *((char **) dst);
+
             *((char **) dst) = g_variant_dup_string(variant, NULL);
         } else {
             /* we don't clone the string, nor free the previous value. */
@@ -164,11 +211,16 @@ nm_value_type_get_from_variant(NMValueType value_type,
         }
         return;
 
+    case NM_VALUE_TYPE_BYTES:
     case NM_VALUE_TYPE_INT:
-        /* "int" also does not have a define variant type, because it's not
-         * clear how many bits we would need. */
+    case NM_VALUE_TYPE_UINT:
+    case NM_VALUE_TYPE_ENUM:
+    case NM_VALUE_TYPE_FLAGS:
+        /* These types don't have a defined variant type, because it's not
+         * clear how many bits we would need or how to handle the type. */
 
         /* fall-through */
+    case NM_VALUE_TYPE_NONE:
     case NM_VALUE_TYPE_UNSPEC:
         break;
     }
@@ -178,7 +230,8 @@ nm_value_type_get_from_variant(NMValueType value_type,
 static inline GVariant *
 nm_value_type_to_variant(NMValueType value_type, gconstpointer src)
 {
-    const char *v_string;
+    const char *  v_string;
+    const GBytes *v_bytes;
 
     switch (value_type) {
     case NM_VALUE_TYPE_BOOL:
@@ -187,17 +240,26 @@ nm_value_type_to_variant(NMValueType value_type, gconstpointer src)
         return g_variant_new_int32(*((const gint32 *) src));
     case NM_VALUE_TYPE_INT64:
         return g_variant_new_int64(*((const gint64 *) src));
+    case NM_VALUE_TYPE_UINT32:
+        return g_variant_new_uint32(*((const guint32 *) src));
     case NM_VALUE_TYPE_UINT64:
         return g_variant_new_uint64(*((const guint64 *) src));
     case NM_VALUE_TYPE_STRING:
         v_string = *((const char *const *) src);
         return v_string ? g_variant_new_string(v_string) : NULL;
+    case NM_VALUE_TYPE_BYTES:
+        v_bytes = *((const GBytes *const *) src);
+        return v_bytes ? nm_g_bytes_to_variant_ay(v_bytes) : NULL;
 
     case NM_VALUE_TYPE_INT:
-        /* "int" also does not have a define variant type, because it's not
-         * clear how many bits we would need. */
+    case NM_VALUE_TYPE_UINT:
+    case NM_VALUE_TYPE_ENUM:
+    case NM_VALUE_TYPE_FLAGS:
+        /* These types don't have a defined variant type, because it's not
+         * clear how many bits we would need or how to handle the type. */
 
         /* fall-through */
+    case NM_VALUE_TYPE_NONE:
     case NM_VALUE_TYPE_UNSPEC:
         break;
     }
@@ -215,16 +277,24 @@ nm_value_type_get_variant_type(NMValueType value_type)
         return G_VARIANT_TYPE_INT32;
     case NM_VALUE_TYPE_INT64:
         return G_VARIANT_TYPE_INT64;
+    case NM_VALUE_TYPE_UINT32:
+        return G_VARIANT_TYPE_UINT32;
     case NM_VALUE_TYPE_UINT64:
         return G_VARIANT_TYPE_UINT64;
     case NM_VALUE_TYPE_STRING:
         return G_VARIANT_TYPE_STRING;
+    case NM_VALUE_TYPE_BYTES:
+        return G_VARIANT_TYPE_BYTESTRING;
 
     case NM_VALUE_TYPE_INT:
-        /* "int" also does not have a define variant type, because it's not
-         * clear how many bits we would need. */
+    case NM_VALUE_TYPE_UINT:
+    case NM_VALUE_TYPE_ENUM:
+    case NM_VALUE_TYPE_FLAGS:
+        /* These types don't have a defined variant type, because it's not
+         * clear how many bits we would need or how to handle the type. */
 
         /* fall-through */
+    case NM_VALUE_TYPE_NONE:
     case NM_VALUE_TYPE_UNSPEC:
         break;
     }
@@ -232,7 +302,7 @@ nm_value_type_get_variant_type(NMValueType value_type)
     return NULL;
 }
 
-    /*****************************************************************************/
+/*****************************************************************************/
 
 #endif /* NM_VALUE_TYPE_DEFINE_FUNCTIONS */
 
diff --git a/src/libnm-glib-aux/tests/test-shared-general.c b/src/libnm-glib-aux/tests/test-shared-general.c
index 4a7b6790..9674f228 100644
--- a/src/libnm-glib-aux/tests/test-shared-general.c
+++ b/src/libnm-glib-aux/tests/test-shared-general.c
@@ -31,6 +31,31 @@ G_STATIC_ASSERT(4 == _nm_alignof(NMIPAddr));
 /*****************************************************************************/
 
 static void
+test_nm_static_assert(void)
+{
+    int                                v1[NM_STATIC_ASSERT_EXPR_1(1)];
+    typeof(NM_STATIC_ASSERT_EXPR_1(1)) v_int;
+    int *                              p_int;
+
+    G_STATIC_ASSERT(sizeof(v1) == sizeof(int));
+    G_STATIC_ASSERT(NM_STATIC_ASSERT_EXPR_1(1) == 1);
+    G_STATIC_ASSERT(NM_STATIC_ASSERT_EXPR_1(NM_STATIC_ASSERT_EXPR_1(1)) == 1);
+    G_STATIC_ASSERT(NM_STATIC_ASSERT_EXPR_1(NM_STATIC_ASSERT_EXPR_1(NM_STATIC_ASSERT_EXPR_1(1)))
+                    == 1);
+
+    g_assert(NM_STATIC_ASSERT_EXPR_1(2) == 1);
+
+    p_int = &v_int;
+    g_assert(&v_int == p_int);
+
+    (void) NM_STATIC_ASSERT_EXPR_1(2 > 1);
+
+    NM_STATIC_ASSERT_EXPR_VOID(2 > 1);
+}
+
+/*****************************************************************************/
+
+static void
 test_gpid(void)
 {
     const int *int_ptr;
@@ -390,8 +415,8 @@ test_strv_cmp(void)
         _strv_cmp_fuzz_input((a1), _l1, &_a1_free_shallow, &_a1_free_deep, &_a1, &_a1x);            \
         _strv_cmp_fuzz_input((a2), _l2, &_a2_free_shallow, &_a2_free_deep, &_a2, &_a2x);            \
                                                                                                     \
-        _c1 = nm_utils_strv_cmp_n(_a1, _l1, _a2, _l2);                                              \
-        _c2 = nm_utils_strv_cmp_n(_a2, _l2, _a1, _l1);                                              \
+        _c1 = nm_strv_cmp_n(_a1, _l1, _a2, _l2);                                                    \
+        _c2 = nm_strv_cmp_n(_a2, _l2, _a1, _l1);                                                    \
         if (equal) {                                                                                \
             g_assert_cmpint(_c1, ==, 0);                                                            \
             g_assert_cmpint(_c2, ==, 0);                                                            \
@@ -402,8 +427,8 @@ test_strv_cmp(void)
                                                                                                     \
         /* Compare with self. _strv_cmp_fuzz_input() randomly swapped the arguments (_a1 and _a1x).
          * Either way, the arrays must compare equal to their semantically equal alternative. */ \
-        g_assert_cmpint(nm_utils_strv_cmp_n(_a1, _l1, _a1x, _l1), ==, 0);                           \
-        g_assert_cmpint(nm_utils_strv_cmp_n(_a2, _l2, _a2x, _l2), ==, 0);                           \
+        g_assert_cmpint(nm_strv_cmp_n(_a1, _l1, _a1x, _l1), ==, 0);                                 \
+        g_assert_cmpint(nm_strv_cmp_n(_a2, _l2, _a2x, _l2), ==, 0);                                 \
                                                                                                     \
         _strv_cmp_free_deep(_a1_free_deep, _l1);                                                    \
         _strv_cmp_free_deep(_a2_free_deep, _l2);                                                    \
@@ -1006,10 +1031,10 @@ again:
         else
             g_assert(!data);
 
-        g_assert(nm_utils_strv_cmp_n((const char *const *) strv->pdata,
-                                     strv->len,
-                                     (const char *const *) strv2->pdata,
-                                     strv2->len)
+        g_assert(nm_strv_cmp_n((const char *const *) strv->pdata,
+                               strv->len,
+                               (const char *const *) strv2->pdata,
+                               strv2->len)
                  == 0);
     }
 }
@@ -1097,15 +1122,14 @@ test_strv_dup_packed(void)
         g_assert(NM_PTRARRAY_LEN(strv_src) == strv_len);
 
         strv_cpy =
-            nm_utils_strv_dup_packed(strv_src,
-                                     nmtst_get_rand_bool() ? (gssize) strv_len : (gssize) -1);
+            nm_strv_dup_packed(strv_src, nmtst_get_rand_bool() ? (gssize) strv_len : (gssize) -1);
         if (strv_len == 0)
             g_assert(!strv_cpy);
         else
             g_assert(strv_cpy);
         g_assert(NM_PTRARRAY_LEN(strv_cpy) == strv_len);
         if (strv_cpy)
-            g_assert(nm_utils_strv_equal(strv_cpy, strv_src));
+            g_assert(nm_strv_equal(strv_cpy, strv_src));
     }
 }
 
@@ -1395,6 +1419,7 @@ main(int argc, char **argv)
 {
     nmtst_init(&argc, &argv, TRUE);
 
+    g_test_add_func("/general/test_nm_static_assert", test_nm_static_assert);
     g_test_add_func("/general/test_gpid", test_gpid);
     g_test_add_func("/general/test_monotonic_timestamp", test_monotonic_timestamp);
     g_test_add_func("/general/test_nmhash", test_nmhash);