summary refs log tree commit diff
path: root/libnm-core/nm-libnm-core-intern
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2020-06-28 18:58:14 +0200
committerMichael Biebl <biebl@debian.org>2020-06-28 18:58:14 +0200
commita54ac63bbf9b2c71026ac9028a8ffaf186cf3c82 (patch)
tree6a32883bd916c4096357b35298beff6db8bcd0b5 /libnm-core/nm-libnm-core-intern
parent45e8e1149027529194982212c804c0468aa01d98 (diff)
New upstream version 1.25.90 upstream/1.25.90
Diffstat (limited to 'libnm-core/nm-libnm-core-intern')
-rw-r--r--libnm-core/nm-libnm-core-intern/README.md21
-rw-r--r--libnm-core/nm-libnm-core-intern/nm-auth-subject.c446
-rw-r--r--libnm-core/nm-libnm-core-intern/nm-auth-subject.h56
-rw-r--r--libnm-core/nm-libnm-core-intern/nm-common-macros.h61
-rw-r--r--libnm-core/nm-libnm-core-intern/nm-ethtool-utils.c276
-rw-r--r--libnm-core/nm-libnm-core-intern/nm-ethtool-utils.h163
-rw-r--r--libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c180
-rw-r--r--libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h115
8 files changed, 1318 insertions, 0 deletions
diff --git a/libnm-core/nm-libnm-core-intern/README.md b/libnm-core/nm-libnm-core-intern/README.md
new file mode 100644
index 00000000..2dcc3c80
--- /dev/null
+++ b/libnm-core/nm-libnm-core-intern/README.md
@@ -0,0 +1,21 @@
+nm-libnm-core-intern is a static library that:
+
+ - uses parts of "libnm-core", that are public API of "libnm"
+ - that is statically linked into libnm-core (and thus libnm
+   and NetworkManager).
+ - that can also be statically linked into other users of libnm.
+
+Basically, it is a static library with utility functions that extends
+libnm-core (the part that is public API of libnm), but it is used
+by libnm-core.
+
+That means:
+
+  - you can use it everywhere where you either statically link
+    with libnm-core, or dynamically link with libnm.
+  - you can even use it inside of libnm-core itself. This is the difference
+    between nm-libnm-core-intern and nm-libnm-core-aux.
+
+Also, since nm-libnm-core-intern itself only uses public (stable)
+API of libnm, you theoretically can copy the sources into your
+own source tree.
diff --git a/libnm-core/nm-libnm-core-intern/nm-auth-subject.c b/libnm-core/nm-libnm-core-intern/nm-auth-subject.c
new file mode 100644
index 00000000..15c2d652
--- /dev/null
+++ b/libnm-core/nm-libnm-core-intern/nm-auth-subject.c
@@ -0,0 +1,446 @@
+// SPDX-License-Identifier: LGPL-2.1+
+/*
+ * Copyright (C) 2013 - 2014 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nm-auth-subject
+ * @short_description: Encapsulates authentication information about a requestor
+ *
+ * #NMAuthSubject encpasulates identifying information about an entity that
+ * makes requests, like process identifier and user UID.
+ */
+
+#include "nm-default.h"
+
+#include "nm-auth-subject.h"
+
+#include <stdlib.h>
+
+enum {
+	PROP_0,
+	PROP_SUBJECT_TYPE,
+	PROP_UNIX_PROCESS_DBUS_SENDER,
+	PROP_UNIX_PROCESS_PID,
+	PROP_UNIX_PROCESS_UID,
+	PROP_UNIX_SESSION_ID,
+
+	PROP_LAST,
+};
+
+typedef struct {
+	NMAuthSubjectType subject_type;
+	struct {
+		gulong pid;
+		gulong uid;
+		guint64 start_time;
+		char *dbus_sender;
+	} unix_process;
+
+	struct {
+		char *id;
+	} unix_session;
+} NMAuthSubjectPrivate;
+
+struct _NMAuthSubject {
+	GObject parent;
+	NMAuthSubjectPrivate _priv;
+};
+
+struct _NMAuthSubjectClass {
+	GObjectClass parent;
+};
+
+G_DEFINE_TYPE (NMAuthSubject, nm_auth_subject, G_TYPE_OBJECT)
+
+#define NM_AUTH_SUBJECT_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMAuthSubject, NM_IS_AUTH_SUBJECT)
+
+/*****************************************************************************/
+
+#define CHECK_SUBJECT(self, error_value) \
+	NMAuthSubjectPrivate *priv; \
+	g_return_val_if_fail (NM_IS_AUTH_SUBJECT (self), error_value); \
+	priv = NM_AUTH_SUBJECT_GET_PRIVATE (self); \
+
+#define CHECK_SUBJECT_TYPED(self, expected_subject_type, error_value) \
+	CHECK_SUBJECT (self, error_value); \
+	g_return_val_if_fail (priv->subject_type == (expected_subject_type), error_value);
+
+const char *
+nm_auth_subject_to_string (NMAuthSubject *self, char *buf, gsize buf_len)
+{
+	CHECK_SUBJECT (self, NULL);
+
+	switch (priv->subject_type) {
+	case NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS:
+		g_snprintf (buf, buf_len, "unix-process[pid=%lu, uid=%lu, start=%llu]",
+		            (unsigned long) priv->unix_process.pid,
+		            (unsigned long) priv->unix_process.uid,
+		            (unsigned long long) priv->unix_process.start_time);
+		break;
+	case NM_AUTH_SUBJECT_TYPE_INTERNAL:
+		g_strlcpy (buf, "internal", buf_len);
+		break;
+	case NM_AUTH_SUBJECT_TYPE_UNIX_SESSION:
+		g_snprintf (buf, buf_len, "unix-session[id=%s]",
+		            priv->unix_session.id);
+		break;
+	default:
+		g_strlcpy (buf, "invalid", buf_len);
+		break;
+	}
+	return buf;
+}
+
+/* returns a floating variant */
+GVariant *
+nm_auth_subject_unix_to_polkit_gvariant (NMAuthSubject *self)
+{
+	GVariantBuilder builder;
+	CHECK_SUBJECT (self, NULL);
+
+	switch (priv->subject_type) {
+
+	case NM_AUTH_SUBJECT_TYPE_UNIX_SESSION:
+		g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+		g_variant_builder_add (&builder, "{sv}", "session-id",
+		                       g_variant_new_string (priv->unix_session.id));
+		return g_variant_new ("(sa{sv})", "unix-session", &builder);
+
+	case NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS:
+		g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+		g_variant_builder_add (&builder, "{sv}", "pid",
+		                       g_variant_new_uint32 (priv->unix_process.pid));
+		g_variant_builder_add (&builder, "{sv}", "start-time",
+		                       g_variant_new_uint64 (priv->unix_process.start_time));
+		g_variant_builder_add (&builder, "{sv}", "uid",
+		                       g_variant_new_int32 (priv->unix_process.uid));
+		return g_variant_new ("(sa{sv})", "unix-process", &builder);
+
+	default:
+		g_return_val_if_reached (NULL);
+	}
+}
+
+NMAuthSubjectType
+nm_auth_subject_get_subject_type (NMAuthSubject *subject)
+{
+	CHECK_SUBJECT (subject, NM_AUTH_SUBJECT_TYPE_INVALID);
+
+	return priv->subject_type;
+}
+
+gulong
+nm_auth_subject_get_unix_process_pid (NMAuthSubject *subject)
+{
+	CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, G_MAXULONG);
+
+	return priv->unix_process.pid;
+}
+
+gulong
+nm_auth_subject_get_unix_process_uid (NMAuthSubject *subject)
+{
+	CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, G_MAXULONG);
+
+	return priv->unix_process.uid;
+}
+
+const char *
+nm_auth_subject_get_unix_process_dbus_sender (NMAuthSubject *subject)
+{
+	CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, NULL);
+
+	return priv->unix_process.dbus_sender;
+}
+
+const char *
+nm_auth_subject_get_unix_session_id (NMAuthSubject *subject)
+{
+	CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_SESSION, NULL);
+
+	return priv->unix_session.id;
+}
+
+/*****************************************************************************/
+
+/**
+ * nm_auth_subject_new_internal():
+ *
+ * Creates a new auth subject representing the NetworkManager process itself.
+ *
+ * Returns: the new #NMAuthSubject
+ */
+NMAuthSubject *
+nm_auth_subject_new_internal (void)
+{
+	return NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT,
+                                          NM_AUTH_SUBJECT_SUBJECT_TYPE, (int) NM_AUTH_SUBJECT_TYPE_INTERNAL,
+                                          NULL));
+}
+
+/**
+ * nm_auth_subject_new_unix_session():
+ *
+ * Creates a new auth subject representing a given unix session.
+ *
+ * Returns: the new #NMAuthSubject
+ */
+NMAuthSubject *
+nm_auth_subject_new_unix_session (const char *session_id)
+{
+	return NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT,
+	                                      NM_AUTH_SUBJECT_SUBJECT_TYPE, (int) NM_AUTH_SUBJECT_TYPE_UNIX_SESSION,
+	                                      NM_AUTH_SUBJECT_UNIX_SESSION_ID, session_id,
+	                                      NULL));
+}
+
+/**
+ * nm_auth_subject_new_unix_process():
+ *
+ * Creates a new auth subject representing a given unix process.
+ *
+ * Returns: the new #NMAuthSubject
+ */
+NMAuthSubject *
+nm_auth_subject_new_unix_process (const char *dbus_sender, gulong pid, gulong uid)
+{
+	return NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT,
+	                                      NM_AUTH_SUBJECT_SUBJECT_TYPE, (int) NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS,
+	                                      NM_AUTH_SUBJECT_UNIX_PROCESS_DBUS_SENDER, dbus_sender,
+	                                      NM_AUTH_SUBJECT_UNIX_PROCESS_PID, pid,
+	                                      NM_AUTH_SUBJECT_UNIX_PROCESS_UID, uid,
+	                                      NULL));
+}
+
+/**
+ * nm_auth_subject_new_unix_process_self():
+ *
+ * Creates a new auth subject representing the current executing process.
+ *
+ * Returns: the new #NMAuthSubject
+ */
+NMAuthSubject *
+nm_auth_subject_new_unix_process_self (void)
+{
+	return nm_auth_subject_new_unix_process (NULL, getpid(), getuid());
+}
+
+/*****************************************************************************/
+
+static void
+get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_SUBJECT_TYPE:
+		g_value_set_int (value, priv->subject_type);
+		break;
+	case PROP_UNIX_PROCESS_DBUS_SENDER:
+		g_value_set_string (value, priv->unix_process.dbus_sender);
+		break;
+	case PROP_UNIX_PROCESS_PID:
+		g_value_set_ulong (value, priv->unix_process.pid);
+		break;
+	case PROP_UNIX_PROCESS_UID:
+		g_value_set_ulong (value, priv->unix_process.uid);
+		break;
+	case PROP_UNIX_SESSION_ID:
+		g_value_set_string (value, priv->unix_session.id);
+		break;
+	default:
+		 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		 break;
+	}
+}
+
+static void
+set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object);
+	NMAuthSubjectType subject_type;
+	int i;
+	const char *str;
+	gulong id;
+
+	switch (prop_id) {
+	case PROP_SUBJECT_TYPE:
+		/* construct-only */
+		i = g_value_get_int (value);
+		g_return_if_fail (NM_IN_SET (i,
+		                             (int) NM_AUTH_SUBJECT_TYPE_INTERNAL,
+		                             (int) NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS,
+		                             (int) NM_AUTH_SUBJECT_TYPE_UNIX_SESSION));
+		subject_type = i;
+		priv->subject_type |= subject_type;
+		g_return_if_fail (priv->subject_type == subject_type);
+		break;
+	case PROP_UNIX_PROCESS_DBUS_SENDER:
+		/* construct-only */
+		if ((str = g_value_get_string (value))) {
+			priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
+			g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS);
+			priv->unix_process.dbus_sender = g_strdup (str);
+		}
+		break;
+	case PROP_UNIX_PROCESS_PID:
+		/* construct-only */
+		if ((id = g_value_get_ulong (value)) != G_MAXULONG) {
+			priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
+			g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS);
+			priv->unix_process.pid = id;
+		}
+		break;
+	case PROP_UNIX_PROCESS_UID:
+		/* construct-only */
+		if ((id = g_value_get_ulong (value)) != G_MAXULONG) {
+			priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
+			g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS);
+			priv->unix_process.uid = id;
+		}
+		break;
+	case PROP_UNIX_SESSION_ID:
+		/* construct-only */
+		if ((str = g_value_get_string (value))) {
+			priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_SESSION;
+			g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_SESSION);
+			priv->unix_session.id = g_strdup (str);
+		}
+		break;
+	default:
+		 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		 break;
+	}
+}
+
+static void
+_clear_private (NMAuthSubject *self)
+{
+	NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (self);
+
+	priv->subject_type = NM_AUTH_SUBJECT_TYPE_INVALID;
+	priv->unix_process.pid = G_MAXULONG;
+	priv->unix_process.uid = G_MAXULONG;
+	nm_clear_g_free (&priv->unix_process.dbus_sender);
+
+	nm_clear_g_free (&priv->unix_session.id);
+}
+
+static void
+nm_auth_subject_init (NMAuthSubject *self)
+{
+	_clear_private (self);
+}
+
+static void
+constructed (GObject *object)
+{
+	NMAuthSubject *self = NM_AUTH_SUBJECT (object);
+	NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (self);
+
+	/* validate that the created instance. */
+
+	switch (priv->subject_type) {
+	case NM_AUTH_SUBJECT_TYPE_INTERNAL:
+		priv->unix_process.pid = G_MAXULONG;
+		priv->unix_process.uid = 0;  /* internal uses 'root' user */
+		return;
+	case NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS:
+		/* Ensure pid and uid to be representable as int32.
+		 * DBUS treats them as uint32, polkit library as int. */
+		if (priv->unix_process.pid > MIN (G_MAXINT, G_MAXINT32))
+			break;
+		if (priv->unix_process.uid > MIN (G_MAXINT, G_MAXINT32)) {
+			/* for uid==-1, libpolkit-gobject-1 detects the user based on the process id.
+			 * Don't bother and require the user id as parameter. */
+			break;
+		}
+
+		priv->unix_process.start_time = nm_utils_get_start_time_for_pid (priv->unix_process.pid, NULL, NULL);
+
+		if (!priv->unix_process.start_time) {
+			/* Is the process already gone? Then fail creation of the auth subject
+			 * by clearing the type. */
+			if (kill (priv->unix_process.pid, 0) != 0)
+				_clear_private (self);
+
+			/* Otherwise, although we didn't detect a start_time, the process is still around.
+			 * That could be due to procfs mounted with hidepid. So just accept the request.
+			 *
+			 * Polkit on the other side, will accept 0 and try to lookup /proc/$PID/stat
+			 * itself (and if it fails to do so, assume a start-time of 0 and proceed).
+			 * The only combination that would fail here, is when NM is able to read the
+			 * start-time, but polkit is not. */
+		}
+		return;
+	case NM_AUTH_SUBJECT_TYPE_UNIX_SESSION:
+		return;
+	default:
+		break;
+	}
+
+	_clear_private (self);
+	g_return_if_reached ();
+}
+
+static void
+finalize (GObject *object)
+{
+	_clear_private ((NMAuthSubject *) object);
+
+	G_OBJECT_CLASS (nm_auth_subject_parent_class)->finalize (object);
+}
+
+static void
+nm_auth_subject_class_init (NMAuthSubjectClass *config_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (config_class);
+
+	object_class->get_property = get_property;
+	object_class->set_property = set_property;
+	object_class->constructed = constructed;
+	object_class->finalize = finalize;
+
+	g_object_class_install_property
+	    (object_class, PROP_SUBJECT_TYPE,
+	     g_param_spec_int (NM_AUTH_SUBJECT_SUBJECT_TYPE, "", "",
+	                       NM_AUTH_SUBJECT_TYPE_INVALID,
+	                       NM_AUTH_SUBJECT_TYPE_UNIX_SESSION,
+	                       NM_AUTH_SUBJECT_TYPE_INVALID,
+	                       G_PARAM_READWRITE |
+	                       G_PARAM_CONSTRUCT_ONLY |
+	                       G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property
+	    (object_class, PROP_UNIX_PROCESS_DBUS_SENDER,
+	     g_param_spec_string (NM_AUTH_SUBJECT_UNIX_PROCESS_DBUS_SENDER, "", "",
+	                          NULL,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT_ONLY |
+	                          G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property
+	     (object_class, PROP_UNIX_PROCESS_PID,
+	      g_param_spec_ulong (NM_AUTH_SUBJECT_UNIX_PROCESS_PID, "", "",
+	                          0, G_MAXULONG, G_MAXULONG,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT_ONLY |
+	                          G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property
+	     (object_class, PROP_UNIX_PROCESS_UID,
+	      g_param_spec_ulong (NM_AUTH_SUBJECT_UNIX_PROCESS_UID, "", "",
+	                          0, G_MAXULONG, G_MAXULONG,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT_ONLY |
+	                          G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property
+	     (object_class, PROP_UNIX_SESSION_ID,
+	      g_param_spec_string (NM_AUTH_SUBJECT_UNIX_SESSION_ID, "", "",
+	                           NULL,
+	                           G_PARAM_READWRITE |
+	                           G_PARAM_CONSTRUCT_ONLY |
+	                           G_PARAM_STATIC_STRINGS));
+}
diff --git a/libnm-core/nm-libnm-core-intern/nm-auth-subject.h b/libnm-core/nm-libnm-core-intern/nm-auth-subject.h
new file mode 100644
index 00000000..fc37b8e2
--- /dev/null
+++ b/libnm-core/nm-libnm-core-intern/nm-auth-subject.h
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: LGPL-2.1+
+/*
+ * Copyright (C) 2013 Red Hat, Inc.
+ */
+
+#ifndef __NETWORKMANAGER_AUTH_SUBJECT_H__
+#define __NETWORKMANAGER_AUTH_SUBJECT_H__
+
+#define NM_TYPE_AUTH_SUBJECT            (nm_auth_subject_get_type ())
+#define NM_AUTH_SUBJECT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_AUTH_SUBJECT, NMAuthSubject))
+#define NM_AUTH_SUBJECT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectClass))
+#define NM_IS_AUTH_SUBJECT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_AUTH_SUBJECT))
+#define NM_IS_AUTH_SUBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_AUTH_SUBJECT))
+#define NM_AUTH_SUBJECT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectClass))
+
+typedef enum {
+	NM_AUTH_SUBJECT_TYPE_INVALID      = 0,
+	NM_AUTH_SUBJECT_TYPE_INTERNAL     = 1,
+	NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS = 2,
+	NM_AUTH_SUBJECT_TYPE_UNIX_SESSION = 4,
+} NMAuthSubjectType;
+
+#define NM_AUTH_SUBJECT_SUBJECT_TYPE                           "subject-type"
+#define NM_AUTH_SUBJECT_UNIX_PROCESS_DBUS_SENDER               "unix-process-dbus-sender"
+#define NM_AUTH_SUBJECT_UNIX_PROCESS_PID                       "unix-process-pid"
+#define NM_AUTH_SUBJECT_UNIX_PROCESS_UID                       "unix-process-uid"
+#define NM_AUTH_SUBJECT_UNIX_SESSION_ID                        "unix-session-id"
+
+typedef struct _NMAuthSubjectClass NMAuthSubjectClass;
+typedef struct _NMAuthSubject NMAuthSubject;
+
+GType nm_auth_subject_get_type (void);
+
+NMAuthSubject *nm_auth_subject_new_internal (void);
+
+NMAuthSubject *nm_auth_subject_new_unix_session (const char *session_id);
+
+NMAuthSubject *nm_auth_subject_new_unix_process (const char *dbus_sender, gulong pid, gulong uid);
+
+NMAuthSubject *nm_auth_subject_new_unix_process_self (void);
+
+NMAuthSubjectType nm_auth_subject_get_subject_type (NMAuthSubject *subject);
+
+gulong nm_auth_subject_get_unix_process_pid (NMAuthSubject *subject);
+
+const char *nm_auth_subject_get_unix_process_dbus_sender (NMAuthSubject *subject);
+
+gulong nm_auth_subject_get_unix_process_uid (NMAuthSubject *subject);
+
+const char *nm_auth_subject_get_unix_session_id (NMAuthSubject *subject);
+
+const char *nm_auth_subject_to_string (NMAuthSubject *self, char *buf, gsize buf_len);
+
+GVariant *nm_auth_subject_unix_to_polkit_gvariant (NMAuthSubject *self);
+
+#endif /* __NETWORKMANAGER_AUTH_SUBJECT_H__ */
diff --git a/libnm-core/nm-libnm-core-intern/nm-common-macros.h b/libnm-core/nm-libnm-core-intern/nm-common-macros.h
new file mode 100644
index 00000000..fcfe6919
--- /dev/null
+++ b/libnm-core/nm-libnm-core-intern/nm-common-macros.h
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: LGPL-2.1+
+/*
+ * Copyright (C) 2016 Red Hat, Inc.
+ */
+
+#ifndef __NM_COMMON_MACROS_H__
+#define __NM_COMMON_MACROS_H__
+
+/*****************************************************************************/
+
+#define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK     "org.freedesktop.NetworkManager.enable-disable-network"
+#define NM_AUTH_PERMISSION_SLEEP_WAKE                 "org.freedesktop.NetworkManager.sleep-wake"
+#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI        "org.freedesktop.NetworkManager.enable-disable-wifi"
+#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN        "org.freedesktop.NetworkManager.enable-disable-wwan"
+#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX       "org.freedesktop.NetworkManager.enable-disable-wimax"
+#define NM_AUTH_PERMISSION_NETWORK_CONTROL            "org.freedesktop.NetworkManager.network-control"
+#define NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED       "org.freedesktop.NetworkManager.wifi.share.protected"
+#define NM_AUTH_PERMISSION_WIFI_SHARE_OPEN            "org.freedesktop.NetworkManager.wifi.share.open"
+#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM     "org.freedesktop.NetworkManager.settings.modify.system"
+#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN        "org.freedesktop.NetworkManager.settings.modify.own"
+#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME   "org.freedesktop.NetworkManager.settings.modify.hostname"
+#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS "org.freedesktop.NetworkManager.settings.modify.global-dns"
+#define NM_AUTH_PERMISSION_RELOAD                     "org.freedesktop.NetworkManager.reload"
+#define NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK        "org.freedesktop.NetworkManager.checkpoint-rollback"
+#define NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS  "org.freedesktop.NetworkManager.enable-disable-statistics"
+#define NM_AUTH_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK "org.freedesktop.NetworkManager.enable-disable-connectivity-check"
+#define NM_AUTH_PERMISSION_WIFI_SCAN                  "org.freedesktop.NetworkManager.wifi.scan"
+
+#define NM_CLONED_MAC_PRESERVE                          "preserve"
+#define NM_CLONED_MAC_PERMANENT                         "permanent"
+#define NM_CLONED_MAC_RANDOM                            "random"
+#define NM_CLONED_MAC_STABLE                            "stable"
+
+static inline gboolean
+NM_CLONED_MAC_IS_SPECIAL (const char *str)
+{
+	return NM_IN_STRSET (str,
+	                     NM_CLONED_MAC_PRESERVE,
+	                     NM_CLONED_MAC_PERMANENT,
+	                     NM_CLONED_MAC_RANDOM,
+	                     NM_CLONED_MAC_STABLE);
+}
+
+#define NM_IAID_MAC                "mac"
+#define NM_IAID_PERM_MAC           "perm-mac"
+#define NM_IAID_IFNAME             "ifname"
+#define NM_IAID_STABLE             "stable"
+
+#define NM_CONNECTION_MUD_URL_NONE "none"
+
+static inline gboolean
+NM_IAID_IS_SPECIAL (const char *str)
+{
+	return NM_IN_STRSET (str,
+	                     NM_IAID_MAC,
+	                     NM_IAID_PERM_MAC,
+	                     NM_IAID_IFNAME,
+	                     NM_IAID_STABLE);
+}
+
+#endif /* __NM_COMMON_MACROS_H__ */
diff --git a/libnm-core/nm-libnm-core-intern/nm-ethtool-utils.c b/libnm-core/nm-libnm-core-intern/nm-ethtool-utils.c
new file mode 100644
index 00000000..3e3c28d3
--- /dev/null
+++ b/libnm-core/nm-libnm-core-intern/nm-ethtool-utils.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: LGPL-2.1+
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-ethtool-utils.h"
+
+#include "nm-setting-ethtool.h"
+
+/*****************************************************************************/
+
+#define ETHT_DATA(xname) \
+	[NM_ETHTOOL_ID_##xname] = (&((const NMEthtoolData) { \
+	   .optname = NM_ETHTOOL_OPTNAME_##xname, \
+	   .id = NM_ETHTOOL_ID_##xname, \
+	}))
+
+const NMEthtoolData *const nm_ethtool_data[_NM_ETHTOOL_ID_NUM + 1] = {
+	/* indexed by NMEthtoolID */
+	ETHT_DATA (COALESCE_ADAPTIVE_RX),
+	ETHT_DATA (COALESCE_ADAPTIVE_TX),
+	ETHT_DATA (COALESCE_PKT_RATE_HIGH),
+	ETHT_DATA (COALESCE_PKT_RATE_LOW),
+	ETHT_DATA (COALESCE_RX_FRAMES),
+	ETHT_DATA (COALESCE_RX_FRAMES_HIGH),
+	ETHT_DATA (COALESCE_RX_FRAMES_IRQ),
+	ETHT_DATA (COALESCE_RX_FRAMES_LOW),
+	ETHT_DATA (COALESCE_RX_USECS),
+	ETHT_DATA (COALESCE_RX_USECS_HIGH),
+	ETHT_DATA (COALESCE_RX_USECS_IRQ),
+	ETHT_DATA (COALESCE_RX_USECS_LOW),
+	ETHT_DATA (COALESCE_SAMPLE_INTERVAL),
+	ETHT_DATA (COALESCE_STATS_BLOCK_USECS),
+	ETHT_DATA (COALESCE_TX_FRAMES),
+	ETHT_DATA (COALESCE_TX_FRAMES_HIGH),
+	ETHT_DATA (COALESCE_TX_FRAMES_IRQ),
+	ETHT_DATA (COALESCE_TX_FRAMES_LOW),
+	ETHT_DATA (COALESCE_TX_USECS),
+	ETHT_DATA (COALESCE_TX_USECS_HIGH),
+	ETHT_DATA (COALESCE_TX_USECS_IRQ),
+	ETHT_DATA (COALESCE_TX_USECS_LOW),
+	ETHT_DATA (FEATURE_ESP_HW_OFFLOAD),
+	ETHT_DATA (FEATURE_ESP_TX_CSUM_HW_OFFLOAD),
+	ETHT_DATA (FEATURE_FCOE_MTU),
+	ETHT_DATA (FEATURE_GRO),
+	ETHT_DATA (FEATURE_GSO),
+	ETHT_DATA (FEATURE_HIGHDMA),
+	ETHT_DATA (FEATURE_HW_TC_OFFLOAD),
+	ETHT_DATA (FEATURE_L2_FWD_OFFLOAD),
+	ETHT_DATA (FEATURE_LOOPBACK),
+	ETHT_DATA (FEATURE_LRO),
+	ETHT_DATA (FEATURE_NTUPLE),
+	ETHT_DATA (FEATURE_RX),
+	ETHT_DATA (FEATURE_RXHASH),
+	ETHT_DATA (FEATURE_RXVLAN),
+	ETHT_DATA (FEATURE_RX_ALL),
+	ETHT_DATA (FEATURE_RX_FCS),
+	ETHT_DATA (FEATURE_RX_GRO_HW),
+	ETHT_DATA (FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD),
+	ETHT_DATA (FEATURE_RX_VLAN_FILTER),
+	ETHT_DATA (FEATURE_RX_VLAN_STAG_FILTER),
+	ETHT_DATA (FEATURE_RX_VLAN_STAG_HW_PARSE),
+	ETHT_DATA (FEATURE_SG),
+	ETHT_DATA (FEATURE_TLS_HW_RECORD),
+	ETHT_DATA (FEATURE_TLS_HW_TX_OFFLOAD),
+	ETHT_DATA (FEATURE_TSO),
+	ETHT_DATA (FEATURE_TX),
+	ETHT_DATA (FEATURE_TXVLAN),
+	ETHT_DATA (FEATURE_TX_CHECKSUM_FCOE_CRC),
+	ETHT_DATA (FEATURE_TX_CHECKSUM_IPV4),
+	ETHT_DATA (FEATURE_TX_CHECKSUM_IPV6),
+	ETHT_DATA (FEATURE_TX_CHECKSUM_IP_GENERIC),
+	ETHT_DATA (FEATURE_TX_CHECKSUM_SCTP),
+	ETHT_DATA (FEATURE_TX_ESP_SEGMENTATION),
+	ETHT_DATA (FEATURE_TX_FCOE_SEGMENTATION),
+	ETHT_DATA (FEATURE_TX_GRE_CSUM_SEGMENTATION),
+	ETHT_DATA (FEATURE_TX_GRE_SEGMENTATION),
+	ETHT_DATA (FEATURE_TX_GSO_PARTIAL),
+	ETHT_DATA (FEATURE_TX_GSO_ROBUST),
+	ETHT_DATA (FEATURE_TX_IPXIP4_SEGMENTATION),
+	ETHT_DATA (FEATURE_TX_IPXIP6_SEGMENTATION),
+	ETHT_DATA (FEATURE_TX_NOCACHE_COPY),
+	ETHT_DATA (FEATURE_TX_SCATTER_GATHER),
+	ETHT_DATA (FEATURE_TX_SCATTER_GATHER_FRAGLIST),
+	ETHT_DATA (FEATURE_TX_SCTP_SEGMENTATION),
+	ETHT_DATA (FEATURE_TX_TCP6_SEGMENTATION),
+	ETHT_DATA (FEATURE_TX_TCP_ECN_SEGMENTATION),
+	ETHT_DATA (FEATURE_TX_TCP_MANGLEID_SEGMENTATION),
+	ETHT_DATA (FEATURE_TX_TCP_SEGMENTATION),
+	ETHT_DATA (FEATURE_TX_UDP_SEGMENTATION),
+	ETHT_DATA (FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION),
+	ETHT_DATA (FEATURE_TX_UDP_TNL_SEGMENTATION),
+	ETHT_DATA (FEATURE_TX_VLAN_STAG_HW_INSERT),
+	ETHT_DATA (RING_RX),
+	ETHT_DATA (RING_RX_JUMBO),
+	ETHT_DATA (RING_RX_MINI),
+	ETHT_DATA (RING_TX),
+	[_NM_ETHTOOL_ID_NUM] = NULL,
+};
+
+static const guint8 _by_name[_NM_ETHTOOL_ID_NUM] = {
+	/* sorted by optname. */
+	NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX,
+	NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX,
+	NM_ETHTOOL_ID_COALESCE_PKT_RATE_HIGH,
+	NM_ETHTOOL_ID_COALESCE_PKT_RATE_LOW,
+	NM_ETHTOOL_ID_COALESCE_RX_FRAMES,
+	NM_ETHTOOL_ID_COALESCE_RX_FRAMES_HIGH,
+	NM_ETHTOOL_ID_COALESCE_RX_FRAMES_IRQ,
+	NM_ETHTOOL_ID_COALESCE_RX_FRAMES_LOW,
+	NM_ETHTOOL_ID_COALESCE_RX_USECS,
+	NM_ETHTOOL_ID_COALESCE_RX_USECS_HIGH,
+	NM_ETHTOOL_ID_COALESCE_RX_USECS_IRQ,
+	NM_ETHTOOL_ID_COALESCE_RX_USECS_LOW,
+	NM_ETHTOOL_ID_COALESCE_SAMPLE_INTERVAL,
+	NM_ETHTOOL_ID_COALESCE_STATS_BLOCK_USECS,
+	NM_ETHTOOL_ID_COALESCE_TX_FRAMES,
+	NM_ETHTOOL_ID_COALESCE_TX_FRAMES_HIGH,
+	NM_ETHTOOL_ID_COALESCE_TX_FRAMES_IRQ,
+	NM_ETHTOOL_ID_COALESCE_TX_FRAMES_LOW,
+	NM_ETHTOOL_ID_COALESCE_TX_USECS,
+	NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH,
+	NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ,
+	NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW,
+	NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD,
+	NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD,
+	NM_ETHTOOL_ID_FEATURE_FCOE_MTU,
+	NM_ETHTOOL_ID_FEATURE_GRO,
+	NM_ETHTOOL_ID_FEATURE_GSO,
+	NM_ETHTOOL_ID_FEATURE_HIGHDMA,
+	NM_ETHTOOL_ID_FEATURE_HW_TC_OFFLOAD,
+	NM_ETHTOOL_ID_FEATURE_L2_FWD_OFFLOAD,
+	NM_ETHTOOL_ID_FEATURE_LOOPBACK,
+	NM_ETHTOOL_ID_FEATURE_LRO,
+	NM_ETHTOOL_ID_FEATURE_NTUPLE,
+	NM_ETHTOOL_ID_FEATURE_RX,
+	NM_ETHTOOL_ID_FEATURE_RX_ALL,
+	NM_ETHTOOL_ID_FEATURE_RX_FCS,
+	NM_ETHTOOL_ID_FEATURE_RX_GRO_HW,
+	NM_ETHTOOL_ID_FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD,
+	NM_ETHTOOL_ID_FEATURE_RX_VLAN_FILTER,
+	NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_FILTER,
+	NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_HW_PARSE,
+	NM_ETHTOOL_ID_FEATURE_RXHASH,
+	NM_ETHTOOL_ID_FEATURE_RXVLAN,
+	NM_ETHTOOL_ID_FEATURE_SG,
+	NM_ETHTOOL_ID_FEATURE_TLS_HW_RECORD,
+	NM_ETHTOOL_ID_FEATURE_TLS_HW_TX_OFFLOAD,
+	NM_ETHTOOL_ID_FEATURE_TSO,
+	NM_ETHTOOL_ID_FEATURE_TX,
+	NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_FCOE_CRC,
+	NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IP_GENERIC,
+	NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV4,
+	NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV6,
+	NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_SCTP,
+	NM_ETHTOOL_ID_FEATURE_TX_ESP_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_FCOE_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_GRE_CSUM_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_GRE_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_GSO_PARTIAL,
+	NM_ETHTOOL_ID_FEATURE_TX_GSO_ROBUST,
+	NM_ETHTOOL_ID_FEATURE_TX_IPXIP4_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_IPXIP6_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_NOCACHE_COPY,
+	NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER,
+	NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER_FRAGLIST,
+	NM_ETHTOOL_ID_FEATURE_TX_SCTP_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_TCP_ECN_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_TCP_MANGLEID_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_TCP_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_UDP_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT,
+	NM_ETHTOOL_ID_FEATURE_TXVLAN,
+	NM_ETHTOOL_ID_RING_RX,
+	NM_ETHTOOL_ID_RING_RX_JUMBO,
+	NM_ETHTOOL_ID_RING_RX_MINI,
+	NM_ETHTOOL_ID_RING_TX,
+};
+
+/*****************************************************************************/
+
+static void
+_ASSERT_data (void)
+{
+	int i;
+
+	if (!NM_MORE_ASSERT_ONCE (10))
+		return;
+
+	G_STATIC_ASSERT_EXPR (_NM_ETHTOOL_ID_FIRST == 0);
+	G_STATIC_ASSERT_EXPR (_NM_ETHTOOL_ID_LAST == _NM_ETHTOOL_ID_NUM - 1);
+	G_STATIC_ASSERT_EXPR (_NM_ETHTOOL_ID_NUM > 0);
+
+	nm_assert (NM_PTRARRAY_LEN (nm_ethtool_data) == _NM_ETHTOOL_ID_NUM);
+	nm_assert (G_N_ELEMENTS (_by_name)           == _NM_ETHTOOL_ID_NUM);
+	nm_assert (G_N_ELEMENTS (nm_ethtool_data)    == _NM_ETHTOOL_ID_NUM + 1);
+
+	for (i = 0; i < _NM_ETHTOOL_ID_NUM; i++) {
+		const NMEthtoolData *d = nm_ethtool_data[i];
+
+		nm_assert (d);
+		nm_assert (d->id == (NMEthtoolID) i);
+		nm_assert (d->optname && d->optname[0]);
+	}
+
+	for (i = 0; i < _NM_ETHTOOL_ID_NUM; i++) {
+		NMEthtoolID id = _by_name[i];
+		const NMEthtoolData *d;
+
+		nm_assert (id >= 0);
+		nm_assert (id < _NM_ETHTOOL_ID_NUM);
+
+		d = nm_ethtool_data[id];
+		if (i > 0) {
+			/* since we assert that all optnames are sorted strictly monotonically increasing,
+			 * it also follows that there are no duplicates in the _by_name.
+			 * It also follows, that all names in nm_ethtool_data are unique. */
+			if (strcmp (nm_ethtool_data[_by_name[i - 1]]->optname, d->optname) >= 0) {
+				g_error ("nm_ethtool_data is not sorted asciibetically: %u/%s should be after %u/%s",
+				         i - 1, nm_ethtool_data[_by_name[i - 1]]->optname,
+				         i, d->optname);
+			}
+		}
+	}
+}
+
+static int
+_by_name_cmp (gconstpointer a,
+              gconstpointer b,
+              gpointer user_data)
+{
+	const guint8 *p_id = a;
+	const char *optname = b;
+
+	nm_assert (p_id && p_id >= _by_name && p_id <= &_by_name[_NM_ETHTOOL_ID_NUM]);
+	nm_assert (*p_id < _NM_ETHTOOL_ID_NUM);
+
+	return strcmp (nm_ethtool_data[*p_id]->optname, optname);
+}
+
+const NMEthtoolData *
+nm_ethtool_data_get_by_optname (const char *optname)
+{
+	gssize idx;
+
+	if (!optname)
+		return NULL;
+
+	_ASSERT_data ();
+
+	idx = nm_utils_array_find_binary_search ((gconstpointer *) _by_name,
+	                                         sizeof (_by_name[0]),
+	                                         _NM_ETHTOOL_ID_NUM,
+	                                         optname,
+	                                         _by_name_cmp,
+	                                         NULL);
+	return (idx < 0) ? NULL : nm_ethtool_data[_by_name[idx]];
+}
+
+NMEthtoolType
+nm_ethtool_id_to_type (NMEthtoolID id)
+{
+	if (nm_ethtool_id_is_coalesce (id))
+		return NM_ETHTOOL_TYPE_COALESCE;
+	if (nm_ethtool_id_is_feature (id))
+		return NM_ETHTOOL_TYPE_FEATURE;
+	if (nm_ethtool_id_is_ring (id))
+		return NM_ETHTOOL_TYPE_RING;
+
+	return NM_ETHTOOL_TYPE_UNKNOWN;
+}
diff --git a/libnm-core/nm-libnm-core-intern/nm-ethtool-utils.h b/libnm-core/nm-libnm-core-intern/nm-ethtool-utils.h
new file mode 100644
index 00000000..cf971edb
--- /dev/null
+++ b/libnm-core/nm-libnm-core-intern/nm-ethtool-utils.h
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: LGPL-2.1+
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ */
+
+#ifndef __NM_ETHTOOL_UTILS_H__
+#define __NM_ETHTOOL_UTILS_H__
+
+/*****************************************************************************/
+
+typedef enum {
+	NM_ETHTOOL_ID_UNKNOWN = -1,
+
+	_NM_ETHTOOL_ID_FIRST = 0,
+
+	_NM_ETHTOOL_ID_COALESCE_FIRST = _NM_ETHTOOL_ID_FIRST,
+	NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX = _NM_ETHTOOL_ID_COALESCE_FIRST,
+	NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX,
+	NM_ETHTOOL_ID_COALESCE_PKT_RATE_HIGH,
+	NM_ETHTOOL_ID_COALESCE_PKT_RATE_LOW,
+	NM_ETHTOOL_ID_COALESCE_RX_FRAMES,
+	NM_ETHTOOL_ID_COALESCE_RX_FRAMES_HIGH,
+	NM_ETHTOOL_ID_COALESCE_RX_FRAMES_IRQ,
+	NM_ETHTOOL_ID_COALESCE_RX_FRAMES_LOW,
+	NM_ETHTOOL_ID_COALESCE_RX_USECS,
+	NM_ETHTOOL_ID_COALESCE_RX_USECS_HIGH,
+	NM_ETHTOOL_ID_COALESCE_RX_USECS_IRQ,
+	NM_ETHTOOL_ID_COALESCE_RX_USECS_LOW,
+	NM_ETHTOOL_ID_COALESCE_SAMPLE_INTERVAL,
+	NM_ETHTOOL_ID_COALESCE_STATS_BLOCK_USECS,
+	NM_ETHTOOL_ID_COALESCE_TX_FRAMES,
+	NM_ETHTOOL_ID_COALESCE_TX_FRAMES_HIGH,
+	NM_ETHTOOL_ID_COALESCE_TX_FRAMES_IRQ,
+	NM_ETHTOOL_ID_COALESCE_TX_FRAMES_LOW,
+	NM_ETHTOOL_ID_COALESCE_TX_USECS,
+	NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH,
+	NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ,
+	NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW,
+	_NM_ETHTOOL_ID_COALESCE_LAST = NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW,
+
+	_NM_ETHTOOL_ID_FEATURE_FIRST = _NM_ETHTOOL_ID_COALESCE_LAST + 1,
+	NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD = _NM_ETHTOOL_ID_FEATURE_FIRST,
+	NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD,
+	NM_ETHTOOL_ID_FEATURE_FCOE_MTU,
+	NM_ETHTOOL_ID_FEATURE_GRO,
+	NM_ETHTOOL_ID_FEATURE_GSO,
+	NM_ETHTOOL_ID_FEATURE_HIGHDMA,
+	NM_ETHTOOL_ID_FEATURE_HW_TC_OFFLOAD,
+	NM_ETHTOOL_ID_FEATURE_L2_FWD_OFFLOAD,
+	NM_ETHTOOL_ID_FEATURE_LOOPBACK,
+	NM_ETHTOOL_ID_FEATURE_LRO,
+	NM_ETHTOOL_ID_FEATURE_NTUPLE,
+	NM_ETHTOOL_ID_FEATURE_RX,
+	NM_ETHTOOL_ID_FEATURE_RXHASH,
+	NM_ETHTOOL_ID_FEATURE_RXVLAN,
+	NM_ETHTOOL_ID_FEATURE_RX_ALL,
+	NM_ETHTOOL_ID_FEATURE_RX_FCS,
+	NM_ETHTOOL_ID_FEATURE_RX_GRO_HW,
+	NM_ETHTOOL_ID_FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD,
+	NM_ETHTOOL_ID_FEATURE_RX_VLAN_FILTER,
+	NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_FILTER,
+	NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_HW_PARSE,
+	NM_ETHTOOL_ID_FEATURE_SG,
+	NM_ETHTOOL_ID_FEATURE_TLS_HW_RECORD,
+	NM_ETHTOOL_ID_FEATURE_TLS_HW_TX_OFFLOAD,
+	NM_ETHTOOL_ID_FEATURE_TSO,
+	NM_ETHTOOL_ID_FEATURE_TX,
+	NM_ETHTOOL_ID_FEATURE_TXVLAN,
+	NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_FCOE_CRC,
+	NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV4,
+	NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV6,
+	NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IP_GENERIC,
+	NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_SCTP,
+	NM_ETHTOOL_ID_FEATURE_TX_ESP_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_FCOE_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_GRE_CSUM_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_GRE_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_GSO_PARTIAL,
+	NM_ETHTOOL_ID_FEATURE_TX_GSO_ROBUST,
+	NM_ETHTOOL_ID_FEATURE_TX_IPXIP4_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_IPXIP6_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_NOCACHE_COPY,
+	NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER,
+	NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER_FRAGLIST,
+	NM_ETHTOOL_ID_FEATURE_TX_SCTP_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_TCP_ECN_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_TCP_MANGLEID_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_TCP_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_UDP_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION,
+	NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT,
+	_NM_ETHTOOL_ID_FEATURE_LAST = NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT,
+
+	_NM_ETHTOOL_ID_RING_FIRST = _NM_ETHTOOL_ID_FEATURE_LAST + 1,
+	NM_ETHTOOL_ID_RING_RX = _NM_ETHTOOL_ID_RING_FIRST,
+	NM_ETHTOOL_ID_RING_RX_JUMBO,
+	NM_ETHTOOL_ID_RING_RX_MINI,
+	NM_ETHTOOL_ID_RING_TX,
+	_NM_ETHTOOL_ID_RING_LAST = NM_ETHTOOL_ID_RING_TX,
+
+	_NM_ETHTOOL_ID_LAST = _NM_ETHTOOL_ID_RING_LAST,
+
+	_NM_ETHTOOL_ID_COALESCE_NUM = (_NM_ETHTOOL_ID_COALESCE_LAST - _NM_ETHTOOL_ID_COALESCE_FIRST + 1),
+	_NM_ETHTOOL_ID_FEATURE_NUM = (_NM_ETHTOOL_ID_FEATURE_LAST - _NM_ETHTOOL_ID_FEATURE_FIRST + 1),
+	_NM_ETHTOOL_ID_RING_NUM = (_NM_ETHTOOL_ID_RING_LAST - _NM_ETHTOOL_ID_RING_FIRST + 1),
+	_NM_ETHTOOL_ID_NUM = (_NM_ETHTOOL_ID_LAST - _NM_ETHTOOL_ID_FIRST + 1),
+} NMEthtoolID;
+
+#define _NM_ETHTOOL_ID_FEATURE_AS_IDX(ethtool_id)  ((ethtool_id) - _NM_ETHTOOL_ID_FEATURE_FIRST)
+#define _NM_ETHTOOL_ID_COALESCE_AS_IDX(ethtool_id) ((ethtool_id) - _NM_ETHTOOL_ID_COALESCE_FIRST)
+
+typedef enum {
+	NM_ETHTOOL_TYPE_UNKNOWN,
+	NM_ETHTOOL_TYPE_COALESCE,
+	NM_ETHTOOL_TYPE_FEATURE,
+	NM_ETHTOOL_TYPE_RING,
+} NMEthtoolType;
+
+typedef struct {
+	const char *optname;
+	NMEthtoolID id;
+} NMEthtoolData;
+
+extern const NMEthtoolData *const nm_ethtool_data[_NM_ETHTOOL_ID_NUM + 1];
+
+const NMEthtoolData *nm_ethtool_data_get_by_optname (const char *optname);
+
+NMEthtoolType nm_ethtool_id_to_type (NMEthtoolID id);
+
+/****************************************************************************/
+
+static inline NMEthtoolID
+nm_ethtool_id_get_by_name (const char *optname)
+{
+	const NMEthtoolData *d;
+
+	d = nm_ethtool_data_get_by_optname (optname);
+	return d ? d->id : NM_ETHTOOL_ID_UNKNOWN;
+}
+
+static inline gboolean
+nm_ethtool_id_is_feature (NMEthtoolID id)
+{
+	return id >= _NM_ETHTOOL_ID_FEATURE_FIRST && id <= _NM_ETHTOOL_ID_FEATURE_LAST;
+}
+
+static inline gboolean
+nm_ethtool_id_is_coalesce (NMEthtoolID id)
+{
+	return id >= _NM_ETHTOOL_ID_COALESCE_FIRST && id <= _NM_ETHTOOL_ID_COALESCE_LAST;
+}
+
+static inline gboolean
+nm_ethtool_id_is_ring (NMEthtoolID id)
+{
+	return id >= _NM_ETHTOOL_ID_RING_FIRST && id <= _NM_ETHTOOL_ID_RING_LAST;
+}
+
+/****************************************************************************/
+
+#endif /* __NM_ETHTOOL_UTILS_H__ */
diff --git a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c
new file mode 100644
index 00000000..df2f2e77
--- /dev/null
+++ b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: LGPL-2.1+
+
+#include "nm-default.h"
+
+#include "nm-libnm-core-utils.h"
+
+#include "nm-common-macros.h"
+
+/*****************************************************************************/
+
+gboolean
+nm_utils_vlan_priority_map_parse_str (NMVlanPriorityMap map_type,
+                                      const char *str,
+                                      gboolean allow_wildcard_to,
+                                      guint32 *out_from,
+                                      guint32 *out_to,
+                                      gboolean *out_has_wildcard_to)
+{
+	const char *s2;
+	gint64 v1, v2;
+
+	nm_assert (str);
+
+	s2 = strchr (str, ':');
+
+	if (!s2) {
+		if (!allow_wildcard_to)
+			return FALSE;
+		v1 = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXUINT32, -1);
+		v2 = -1;
+	} else {
+		gs_free char *s1_free = NULL;
+		gsize s1_len = (s2 - str);
+
+		s2 = nm_str_skip_leading_spaces (&s2[1]);
+		if (   s2[0] == '\0'
+		    || (   s2[0] == '*'
+		        && NM_STRCHAR_ALL (&s2[1], ch, g_ascii_isspace (ch)))) {
+			if (!allow_wildcard_to)
+				return FALSE;
+			v2 = -1;
+		} else {
+			v2 = _nm_utils_ascii_str_to_int64 (s2, 10, 0, G_MAXUINT32, -1);
+			if (   v2 < 0
+			    || (guint32) v2 > nm_utils_vlan_priority_map_get_max_prio (map_type, FALSE))
+				return FALSE;
+		}
+
+		v1 = _nm_utils_ascii_str_to_int64 (nm_strndup_a (100, str, s1_len, &s1_free),
+		                                   10, 0, G_MAXUINT32, -1);
+	}
+
+	if (   v1 < 0
+	    || (guint32) v1 > nm_utils_vlan_priority_map_get_max_prio (map_type, TRUE))
+		return FALSE;
+
+	NM_SET_OUT (out_from, v1);
+	NM_SET_OUT (out_to,   v2 < 0
+	                    ? 0u
+	                    : (guint) v2);
+	NM_SET_OUT (out_has_wildcard_to, v2 < 0);
+	return TRUE;
+}
+
+/*****************************************************************************/
+
+const char *const nm_auth_permission_names_by_idx[NM_CLIENT_PERMISSION_LAST] = {
+	[NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK - 1]               = NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK,
+	[NM_CLIENT_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK - 1] = NM_AUTH_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK,
+	[NM_CLIENT_PERMISSION_ENABLE_DISABLE_NETWORK - 1]            = NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK,
+	[NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS - 1]         = NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS,
+	[NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIFI - 1]               = NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI,
+	[NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIMAX - 1]              = NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX,
+	[NM_CLIENT_PERMISSION_ENABLE_DISABLE_WWAN - 1]               = NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN,
+	[NM_CLIENT_PERMISSION_NETWORK_CONTROL - 1]                   = NM_AUTH_PERMISSION_NETWORK_CONTROL,
+	[NM_CLIENT_PERMISSION_RELOAD - 1]                            = NM_AUTH_PERMISSION_RELOAD,
+	[NM_CLIENT_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS - 1]        = NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS,
+	[NM_CLIENT_PERMISSION_SETTINGS_MODIFY_HOSTNAME - 1]          = NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME,
+	[NM_CLIENT_PERMISSION_SETTINGS_MODIFY_OWN - 1]               = NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN,
+	[NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM - 1]            = NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM,
+	[NM_CLIENT_PERMISSION_SLEEP_WAKE - 1]                        = NM_AUTH_PERMISSION_SLEEP_WAKE,
+	[NM_CLIENT_PERMISSION_WIFI_SCAN - 1]                         = NM_AUTH_PERMISSION_WIFI_SCAN,
+	[NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN - 1]                   = NM_AUTH_PERMISSION_WIFI_SHARE_OPEN,
+	[NM_CLIENT_PERMISSION_WIFI_SHARE_PROTECTED - 1]              = NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED,
+};
+
+const NMClientPermission nm_auth_permission_sorted[NM_CLIENT_PERMISSION_LAST] = {
+	NM_CLIENT_PERMISSION_CHECKPOINT_ROLLBACK,
+	NM_CLIENT_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK,
+	NM_CLIENT_PERMISSION_ENABLE_DISABLE_NETWORK,
+	NM_CLIENT_PERMISSION_ENABLE_DISABLE_STATISTICS,
+	NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIFI,
+	NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIMAX,
+	NM_CLIENT_PERMISSION_ENABLE_DISABLE_WWAN,
+	NM_CLIENT_PERMISSION_NETWORK_CONTROL,
+	NM_CLIENT_PERMISSION_RELOAD,
+	NM_CLIENT_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS,
+	NM_CLIENT_PERMISSION_SETTINGS_MODIFY_HOSTNAME,
+	NM_CLIENT_PERMISSION_SETTINGS_MODIFY_OWN,
+	NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM,
+	NM_CLIENT_PERMISSION_SLEEP_WAKE,
+	NM_CLIENT_PERMISSION_WIFI_SCAN,
+	NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN,
+	NM_CLIENT_PERMISSION_WIFI_SHARE_PROTECTED,
+};
+
+const char *
+nm_auth_permission_to_string (NMClientPermission permission)
+{
+	if (permission < 1)
+		return NULL;
+	if (permission > NM_CLIENT_PERMISSION_LAST)
+		return NULL;
+	return nm_auth_permission_names_by_idx[permission - 1];
+}
+
+#define AUTH_PERMISSION_PREFIX "org.freedesktop.NetworkManager."
+
+static int
+_nm_auth_permission_from_string_cmp (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+	const NMClientPermission *const p = a;
+	const char *const needle = b;
+	const char *ss = nm_auth_permission_names_by_idx[*p - 1];
+
+	nm_assert (NM_STR_HAS_PREFIX (ss, AUTH_PERMISSION_PREFIX));
+	nm_assert (ss[NM_STRLEN (AUTH_PERMISSION_PREFIX)] != '\0');
+
+	return strcmp (&ss[NM_STRLEN (AUTH_PERMISSION_PREFIX)], needle);
+}
+
+NMClientPermission
+nm_auth_permission_from_string (const char *str)
+{
+	gssize idx;
+
+	if (!str)
+		return NM_CLIENT_PERMISSION_NONE;
+
+	if (!NM_STR_HAS_PREFIX (str, AUTH_PERMISSION_PREFIX))
+		return NM_CLIENT_PERMISSION_NONE;
+	idx = nm_utils_array_find_binary_search (nm_auth_permission_sorted,
+	                                         sizeof (nm_auth_permission_sorted[0]),
+	                                         G_N_ELEMENTS (nm_auth_permission_sorted),
+	                                         &str[NM_STRLEN (AUTH_PERMISSION_PREFIX)],
+	                                         _nm_auth_permission_from_string_cmp,
+	                                         NULL);
+	if (idx < 0)
+		return NM_CLIENT_PERMISSION_NONE;
+	return nm_auth_permission_sorted[idx];
+}
+
+/*****************************************************************************/
+
+NMClientPermissionResult
+nm_client_permission_result_from_string (const char *nm)
+{
+	if (!nm)
+		return NM_CLIENT_PERMISSION_RESULT_UNKNOWN;
+	if (nm_streq (nm, "yes"))
+		return NM_CLIENT_PERMISSION_RESULT_YES;
+	if (nm_streq (nm, "no"))
+		return NM_CLIENT_PERMISSION_RESULT_NO;
+	if (nm_streq (nm, "auth"))
+		return NM_CLIENT_PERMISSION_RESULT_AUTH;
+	return NM_CLIENT_PERMISSION_RESULT_UNKNOWN;
+}
+
+const char *
+nm_client_permission_result_to_string (NMClientPermissionResult permission)
+{
+	switch (permission) {
+	case NM_CLIENT_PERMISSION_RESULT_YES:     return "yes";
+	case NM_CLIENT_PERMISSION_RESULT_NO:      return "no";
+	case NM_CLIENT_PERMISSION_RESULT_AUTH:    return "auth";
+	case NM_CLIENT_PERMISSION_RESULT_UNKNOWN: return "unknown";
+	}
+	nm_assert_not_reached ();
+	return NULL;
+}
diff --git a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h
new file mode 100644
index 00000000..a35a5e15
--- /dev/null
+++ b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: LGPL-2.1+
+
+#ifndef __NM_LIBNM_SHARED_UTILS_H__
+#define __NM_LIBNM_SHARED_UTILS_H__
+
+/****************************************************************************/
+
+#include "nm-setting-bridge.h"
+#include "nm-setting-connection.h"
+#include "nm-setting-ip-config.h"
+#include "nm-setting-ip4-config.h"
+#include "nm-setting-ip6-config.h"
+#include "nm-setting-sriov.h"
+#include "nm-setting-team.h"
+#include "nm-setting-vlan.h"
+#include "nm-setting-wireguard.h"
+
+/****************************************************************************/
+
+#define nm_auto_unref_ip_address nm_auto (_nm_ip_address_unref)
+NM_AUTO_DEFINE_FCN0 (NMIPAddress *, _nm_ip_address_unref, nm_ip_address_unref)
+
+#define nm_auto_unref_ip_route nm_auto (_nm_auto_unref_ip_route)
+NM_AUTO_DEFINE_FCN0 (NMIPRoute *, _nm_auto_unref_ip_route, nm_ip_route_unref)
+
+#define nm_auto_unref_ip_routing_rule nm_auto(_nm_auto_unref_ip_routing_rule)
+NM_AUTO_DEFINE_FCN0 (NMIPRoutingRule *, _nm_auto_unref_ip_routing_rule, nm_ip_routing_rule_unref)
+
+#define nm_auto_unref_sriov_vf nm_auto (_nm_auto_unref_sriov_vf)
+NM_AUTO_DEFINE_FCN0 (NMSriovVF *, _nm_auto_unref_sriov_vf, nm_sriov_vf_unref)
+
+#define nm_auto_unref_tc_qdisc nm_auto (_nm_auto_unref_tc_qdisc)
+NM_AUTO_DEFINE_FCN0 (NMTCQdisc *, _nm_auto_unref_tc_qdisc, nm_tc_qdisc_unref)
+
+#define nm_auto_unref_tc_tfilter nm_auto (_nm_auto_unref_tc_tfilter)
+NM_AUTO_DEFINE_FCN0 (NMTCTfilter *, _nm_auto_unref_tc_tfilter, nm_tc_tfilter_unref)
+
+#define nm_auto_unref_bridge_vlan nm_auto (_nm_auto_unref_bridge_vlan)
+NM_AUTO_DEFINE_FCN0 (NMBridgeVlan *, _nm_auto_unref_bridge_vlan, nm_bridge_vlan_unref)
+
+#define nm_auto_unref_team_link_watcher nm_auto (_nm_auto_unref_team_link_watcher)
+NM_AUTO_DEFINE_FCN0 (NMTeamLinkWatcher *, _nm_auto_unref_team_link_watcher, nm_team_link_watcher_unref)
+
+#define nm_auto_unref_wgpeer nm_auto (_nm_auto_unref_wgpeer)
+NM_AUTO_DEFINE_FCN0 (NMWireGuardPeer *, _nm_auto_unref_wgpeer, nm_wireguard_peer_unref)
+
+/****************************************************************************/
+
+static inline guint32
+nm_utils_vlan_priority_map_get_max_prio (NMVlanPriorityMap map, gboolean from)
+{
+	if (map == NM_VLAN_INGRESS_MAP) {
+		return   from
+		       ? 7u /* MAX_8021P_PRIO */
+		       : (guint32) G_MAXUINT32 /* MAX_SKB_PRIO */;
+	}
+	nm_assert (map == NM_VLAN_EGRESS_MAP);
+	return   from
+	       ? (guint32) G_MAXUINT32 /* MAX_SKB_PRIO */
+	       : 7u /* MAX_8021P_PRIO */;
+}
+
+gboolean nm_utils_vlan_priority_map_parse_str (NMVlanPriorityMap map_type,
+                                               const char *str,
+                                               gboolean allow_wildcard_to,
+                                               guint32 *out_from,
+                                               guint32 *out_to,
+                                               gboolean *out_has_wildcard_to);
+
+/*****************************************************************************/
+
+static inline int
+nm_setting_ip_config_get_addr_family (NMSettingIPConfig *s_ip)
+{
+	if (NM_IS_SETTING_IP4_CONFIG (s_ip))
+		return AF_INET;
+	if (NM_IS_SETTING_IP6_CONFIG (s_ip))
+		return AF_INET6;
+	g_return_val_if_reached (AF_UNSPEC);
+}
+
+/*****************************************************************************/
+
+/* The maximum MTU for infiniband.
+ *
+ * This is both in transport-mode "datagram" and "connected"
+ * and they both have the same maximum define.
+ *
+ * Note that in the past, MTU in "datagram" mode was restricted
+ * to 2044 bytes. That is no longer the case and we accept large
+ * MTUs.
+ *
+ * This define is the maxiumum for the MTU in a connection profile (the
+ * setting). Whether large MTUs can be configured later (at activation time)
+ * depends on other factors. */
+#define NM_INFINIBAND_MAX_MTU ((guint) 65520)
+
+/*****************************************************************************/
+
+#define _NM_CAPABILITY_MAX NM_CAPABILITY_OVS
+
+/*****************************************************************************/
+
+extern const char *const nm_auth_permission_names_by_idx[NM_CLIENT_PERMISSION_LAST];
+extern const NMClientPermission nm_auth_permission_sorted[NM_CLIENT_PERMISSION_LAST];
+
+const char *nm_auth_permission_to_string (NMClientPermission permission);
+NMClientPermission nm_auth_permission_from_string (const char *str);
+
+/*****************************************************************************/
+
+NMClientPermissionResult nm_client_permission_result_from_string (const char *nm);
+const char *nm_client_permission_result_to_string (NMClientPermissionResult permission);
+
+#endif /* __NM_LIBNM_SHARED_UTILS_H__ */