summary refs log tree commit diff
path: root/shared
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2016-08-26 02:18:32 +0200
committerMichael Biebl <biebl@debian.org>2016-08-26 02:18:32 +0200
commit7514efc2f38c9ace4557d4e69d68e7d380389030 (patch)
tree7fb00fda86cfcc2ca377f191633a7cfdbfea7ca3 /shared
parentd6201f5d8daada3d64a0a3e0038e14eebec683ce (diff)
Imported Upstream version 1.4.0 upstream/1.4.0
Diffstat (limited to 'shared')
-rw-r--r--shared/Makefile.am20
-rw-r--r--shared/Makefile.in34
-rw-r--r--shared/nm-common-macros.h17
-rw-r--r--shared/nm-default.h75
-rw-r--r--shared/nm-dispatcher-api.h61
-rw-r--r--shared/nm-test-libnm-utils.h2
-rw-r--r--shared/nm-utils/gsystem-local-alloc.h (renamed from shared/gsystem-local-alloc.h)0
-rw-r--r--shared/nm-utils/nm-glib.h (renamed from shared/nm-glib.h)65
-rw-r--r--shared/nm-utils/nm-macros-internal.h (renamed from shared/nm-macros-internal.h)80
-rw-r--r--shared/nm-utils/nm-shared-utils.c (renamed from shared/nm-shared-utils.c)0
-rw-r--r--shared/nm-utils/nm-shared-utils.h (renamed from shared/nm-shared-utils.h)0
-rw-r--r--shared/nm-utils/nm-test-utils.h (renamed from shared/nm-test-utils.h)294
-rw-r--r--shared/nm-utils/nm-vpn-editor-plugin-call.h188
-rw-r--r--shared/nm-utils/nm-vpn-plugin-macros.h61
-rw-r--r--shared/nm-utils/nm-vpn-plugin-utils.c130
-rw-r--r--shared/nm-utils/nm-vpn-plugin-utils.h42
-rw-r--r--shared/nm-version-macros.h11
-rw-r--r--shared/nm-version-macros.h.in7
18 files changed, 772 insertions, 315 deletions
diff --git a/shared/Makefile.am b/shared/Makefile.am
index c6ede00b..adf101bf 100644
--- a/shared/Makefile.am
+++ b/shared/Makefile.am
@@ -1,15 +1,21 @@
 EXTRA_DIST = \
-     gsystem-local-alloc.h \
+     nm-utils/gsystem-local-alloc.h \
+     nm-utils/nm-glib.h \
+     nm-utils/nm-macros-internal.h \
+     nm-utils/nm-shared-utils.c \
+     nm-utils/nm-shared-utils.h \
+     nm-utils/nm-test-utils.h \
+     nm-utils/nm-vpn-editor-plugin-call.h \
+     nm-utils/nm-vpn-plugin-macros.h \
+     nm-utils/nm-vpn-plugin-utils.c \
+     nm-utils/nm-vpn-plugin-utils.h \
      nm-common-macros.h \
      nm-dbus-compat.h \
      nm-default.h \
-     nm-glib.h \
-     nm-macros-internal.h \
-     nm-shared-utils.c \
-     nm-shared-utils.h \
+     nm-dispatcher-api.h \
      nm-test-libnm-utils.h \
-     nm-test-utils.h \
      nm-test-utils-impl.c \
-     nm-version-macros.h.in
+     nm-version-macros.h.in \
+     $(NULL)
 
 CLEANFILES=nm-version.h
diff --git a/shared/Makefile.in b/shared/Makefile.in
index 26f46bb4..3e98aec6 100644
--- a/shared/Makefile.in
+++ b/shared/Makefile.in
@@ -89,8 +89,9 @@ build_triplet = @build@
 host_triplet = @host@
 subdir = shared
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
-	$(top_srcdir)/m4/compiler_warnings.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/attributes.m4 \
+	$(top_srcdir)/m4/ax_lib_readline.m4 \
+	$(top_srcdir)/m4/compiler_options.m4 \
 	$(top_srcdir)/m4/gettext.m4 \
 	$(top_srcdir)/m4/gnome-code-coverage.m4 \
 	$(top_srcdir)/m4/gtk-doc.m4 $(top_srcdir)/m4/iconv.m4 \
@@ -166,6 +167,7 @@ DHCLIENT_PATH = @DHCLIENT_PATH@
 DHCPCD_PATH = @DHCPCD_PATH@
 DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@
 DLLTOOL = @DLLTOOL@
+DL_LIBS = @DL_LIBS@
 DNSMASQ_PATH = @DNSMASQ_PATH@
 DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@
 DSYMUTIL = @DSYMUTIL@
@@ -222,13 +224,14 @@ INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@
 INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
 INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@
 IPTABLES_PATH = @IPTABLES_PATH@
+JANSSON_CFLAGS = @JANSSON_CFLAGS@
+JANSSON_LIBS = @JANSSON_LIBS@
 KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@
 LCOV = @LCOV@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
 LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@
 LIBAUDIT_LIBS = @LIBAUDIT_LIBS@
-LIBDL = @LIBDL@
 LIBICONV = @LIBICONV@
 LIBINTL = @LIBINTL@
 LIBM = @LIBM@
@@ -240,6 +243,8 @@ LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
 LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@
+LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@
 LIBTEAMDCTL_CFLAGS = @LIBTEAMDCTL_CFLAGS@
 LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@
 LIBTOOL = @LIBTOOL@
@@ -300,6 +305,8 @@ QT_CFLAGS = @QT_CFLAGS@
 QT_LIBS = @QT_LIBS@
 RANLIB = @RANLIB@
 READLINE_LIBS = @READLINE_LIBS@
+SANITIZERS = @SANITIZERS@
+SANITIZER_ENV = @SANITIZER_ENV@
 SED = @SED@
 SELINUX_CFLAGS = @SELINUX_CFLAGS@
 SELINUX_LIBS = @SELINUX_LIBS@
@@ -335,6 +342,7 @@ ac_ct_AR = @ac_ct_AR@
 ac_ct_CC = @ac_ct_CC@
 ac_ct_CXX = @ac_ct_CXX@
 ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_RANLIB = @ac_ct_RANLIB@
 am__include = @am__include@
 am__leading_dot = @am__leading_dot@
 am__quote = @am__quote@
@@ -397,18 +405,24 @@ with_netconfig = @with_netconfig@
 with_resolvconf = @with_resolvconf@
 with_valgrind = @with_valgrind@
 EXTRA_DIST = \
-     gsystem-local-alloc.h \
+     nm-utils/gsystem-local-alloc.h \
+     nm-utils/nm-glib.h \
+     nm-utils/nm-macros-internal.h \
+     nm-utils/nm-shared-utils.c \
+     nm-utils/nm-shared-utils.h \
+     nm-utils/nm-test-utils.h \
+     nm-utils/nm-vpn-editor-plugin-call.h \
+     nm-utils/nm-vpn-plugin-macros.h \
+     nm-utils/nm-vpn-plugin-utils.c \
+     nm-utils/nm-vpn-plugin-utils.h \
      nm-common-macros.h \
      nm-dbus-compat.h \
      nm-default.h \
-     nm-glib.h \
-     nm-macros-internal.h \
-     nm-shared-utils.c \
-     nm-shared-utils.h \
+     nm-dispatcher-api.h \
      nm-test-libnm-utils.h \
-     nm-test-utils.h \
      nm-test-utils-impl.c \
-     nm-version-macros.h.in
+     nm-version-macros.h.in \
+     $(NULL)
 
 CLEANFILES = nm-version.h
 all: all-am
diff --git a/shared/nm-common-macros.h b/shared/nm-common-macros.h
index 922117c3..6e0769cc 100644
--- a/shared/nm-common-macros.h
+++ b/shared/nm-common-macros.h
@@ -37,6 +37,23 @@
 #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_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);
+}
 
 /******************************************************************************/
 
diff --git a/shared/nm-default.h b/shared/nm-default.h
index aeb977a9..e3e3ea44 100644
--- a/shared/nm-default.h
+++ b/shared/nm-default.h
@@ -53,12 +53,79 @@
 #define NM_VERSION_MIN_REQUIRED  NM_VERSION_0_9_8
 
 #include <stdlib.h>
+#include <glib.h>
+
+/*****************************************************************************/
+
+#ifndef NM_MORE_ASSERTS
+#define NM_MORE_ASSERTS 0
+#endif
+
+#if NM_MORE_ASSERTS == 0
+
+/* glib assertions (g_return_*(), g_assert*()) contain a textual representation
+ * of the checked statement. This part of the assertion blows up the size of the
+ * binary. Unless we compile a debug-build with NM_MORE_ASSERTS, drop these
+ * parts. Note that the failed assertion still prints the file and line where the
+ * assertion fails. That shall suffice. */
+
+static inline void
+_nm_g_return_if_fail_warning (const char *log_domain,
+                              const char *file,
+                              int line)
+{
+	char file_buf[256 + 15];
+
+	g_snprintf (file_buf, sizeof (file_buf), "((%s:%d))", file, 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_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_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
+
+#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
+
+#endif
+
+/*****************************************************************************/
+
+#include "nm-utils/nm-macros-internal.h"
+#include "nm-utils/nm-shared-utils.h"
 
-#include "nm-glib.h"
 #include "nm-version.h"
-#include "gsystem-local-alloc.h"
-#include "nm-macros-internal.h"
-#include "nm-shared-utils.h"
 
 /*****************************************************************************/
 
diff --git a/shared/nm-dispatcher-api.h b/shared/nm-dispatcher-api.h
new file mode 100644
index 00000000..b1f28e71
--- /dev/null
+++ b/shared/nm-dispatcher-api.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2008 - 2012 Red Hat, Inc.
+ */
+
+#define NMD_SCRIPT_DIR_DEFAULT  NMCONFDIR "/dispatcher.d"
+#define NMD_SCRIPT_DIR_PRE_UP   NMD_SCRIPT_DIR_DEFAULT "/pre-up.d"
+#define NMD_SCRIPT_DIR_PRE_DOWN NMD_SCRIPT_DIR_DEFAULT "/pre-down.d"
+#define NMD_SCRIPT_DIR_NO_WAIT  NMD_SCRIPT_DIR_DEFAULT "/no-wait.d"
+
+#define NM_DISPATCHER_DBUS_SERVICE   "org.freedesktop.nm_dispatcher"
+#define NM_DISPATCHER_DBUS_INTERFACE "org.freedesktop.nm_dispatcher"
+#define NM_DISPATCHER_DBUS_PATH      "/org/freedesktop/nm_dispatcher"
+
+#define NMD_CONNECTION_PROPS_PATH         "path"
+#define NMD_CONNECTION_PROPS_FILENAME     "filename"
+#define NMD_CONNECTION_PROPS_EXTERNAL     "external"
+
+#define NMD_DEVICE_PROPS_INTERFACE        "interface"
+#define NMD_DEVICE_PROPS_IP_INTERFACE     "ip-interface"
+#define NMD_DEVICE_PROPS_TYPE             "type"
+#define NMD_DEVICE_PROPS_STATE            "state"
+#define NMD_DEVICE_PROPS_PATH             "path"
+
+/* Actions */
+#define NMD_ACTION_HOSTNAME     "hostname"
+#define NMD_ACTION_PRE_UP       "pre-up"
+#define NMD_ACTION_UP           "up"
+#define NMD_ACTION_PRE_DOWN     "pre-down"
+#define NMD_ACTION_DOWN         "down"
+#define NMD_ACTION_VPN_PRE_UP   "vpn-pre-up"
+#define NMD_ACTION_VPN_UP       "vpn-up"
+#define NMD_ACTION_VPN_PRE_DOWN "vpn-pre-down"
+#define NMD_ACTION_VPN_DOWN     "vpn-down"
+#define NMD_ACTION_DHCP4_CHANGE "dhcp4-change"
+#define NMD_ACTION_DHCP6_CHANGE "dhcp6-change"
+#define NMD_ACTION_CONNECTIVITY_CHANGE "connectivity-change"
+
+typedef enum {
+	DISPATCH_RESULT_UNKNOWN = 0,
+	DISPATCH_RESULT_SUCCESS = 1,
+	DISPATCH_RESULT_EXEC_FAILED = 2,
+	DISPATCH_RESULT_FAILED = 3,
+	DISPATCH_RESULT_TIMEOUT = 4,
+} DispatchResult;
+
diff --git a/shared/nm-test-libnm-utils.h b/shared/nm-test-libnm-utils.h
index 8d111003..192c089e 100644
--- a/shared/nm-test-libnm-utils.h
+++ b/shared/nm-test-libnm-utils.h
@@ -20,7 +20,7 @@
 
 #include "NetworkManager.h"
 
-#include "nm-test-utils.h"
+#include "nm-utils/nm-test-utils.h"
 
 /*****************************************************************************/
 
diff --git a/shared/gsystem-local-alloc.h b/shared/nm-utils/gsystem-local-alloc.h
index 51b62519..51b62519 100644
--- a/shared/gsystem-local-alloc.h
+++ b/shared/nm-utils/gsystem-local-alloc.h
diff --git a/shared/nm-glib.h b/shared/nm-utils/nm-glib.h
index 5f8ebc7f..824a08ca 100644
--- a/shared/nm-glib.h
+++ b/shared/nm-utils/nm-glib.h
@@ -24,6 +24,8 @@
 #include <gio/gio.h>
 #include <string.h>
 
+#include "gsystem-local-alloc.h"
+
 #ifdef __clang__
 
 #undef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
@@ -311,14 +313,14 @@ _g_key_file_save_to_file (GKeyFile     *key_file,
 
 #if GLIB_CHECK_VERSION (2, 36, 0)
 #define g_credentials_get_unix_pid(creds, error) \
-	G_GNUC_EXTENSION ({ \
+	({ \
 		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) \
-	G_GNUC_EXTENSION ({ \
+	({ \
 		struct ucred *native_creds; \
 		 \
 		native_creds = g_credentials_get_native ((creds), G_CREDENTIALS_TYPE_LINUX_UCRED); \
@@ -355,12 +357,12 @@ _nm_g_hash_table_get_keys_as_array (GHashTable *hash_table,
 #endif
 #if !GLIB_CHECK_VERSION(2, 40, 0)
 #define g_hash_table_get_keys_as_array(hash_table, length) \
-	G_GNUC_EXTENSION ({ \
+	({ \
 		_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_EXTENSION ({ \
+	({ \
 		G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
 			(g_hash_table_get_keys_as_array) ((hash_table), (length)); \
 		G_GNUC_END_IGNORE_DEPRECATIONS \
@@ -392,4 +394,59 @@ g_steal_pointer (gpointer pp)
   (0 ? (*(pp)) : (g_steal_pointer) (pp))
 #endif
 
+
+static inline gboolean
+_nm_g_strv_contains (const gchar * const *strv,
+                     const gchar         *str)
+{
+#if !GLIB_CHECK_VERSION(2, 44, 0)
+	g_return_val_if_fail (strv != NULL, FALSE);
+	g_return_val_if_fail (str != NULL, FALSE);
+
+	for (; *strv != NULL; strv++) {
+		if (g_str_equal (str, *strv))
+			return TRUE;
+	}
+
+	return FALSE;
+#else
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+	return g_strv_contains (strv, str);
+	G_GNUC_END_IGNORE_DEPRECATIONS
+#endif
+}
+#define g_strv_contains _nm_g_strv_contains
+
+static inline GVariant *
+_nm_g_variant_new_take_string (gchar *string)
+{
+#if !GLIB_CHECK_VERSION(2, 36, 0)
+	GVariant *value;
+
+	g_return_val_if_fail (string != NULL, NULL);
+	g_return_val_if_fail (g_utf8_validate (string, -1, NULL), NULL);
+
+	value = g_variant_new_string (string);
+	g_free (string);
+	return value;
+#elif !GLIB_CHECK_VERSION(2, 38, 0)
+	GVariant *value;
+	GBytes *bytes;
+
+	g_return_val_if_fail (string != NULL, NULL);
+	g_return_val_if_fail (g_utf8_validate (string, -1, NULL), NULL);
+
+	bytes = g_bytes_new_take (string, strlen (string) + 1);
+	value = g_variant_new_from_bytes (G_VARIANT_TYPE_STRING, bytes, TRUE);
+	g_bytes_unref (bytes);
+
+	return value;
+#else
+	G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+	return g_variant_new_take_string (string);
+	G_GNUC_END_IGNORE_DEPRECATIONS
+#endif
+}
+#define g_variant_new_take_string _nm_g_variant_new_take_string
+
 #endif  /* __NM_GLIB_H__ */
diff --git a/shared/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h
index fe27b761..73075c68 100644
--- a/shared/nm-macros-internal.h
+++ b/shared/nm-utils/nm-macros-internal.h
@@ -24,10 +24,15 @@
 
 #include <stdlib.h>
 
+#include "nm-glib.h"
+
 /********************************************************/
 
 #define _nm_packed __attribute__ ((packed))
 #define _nm_unused __attribute__ ((unused))
+#define _nm_pure   __attribute__ ((pure))
+#define _nm_const  __attribute__ ((const))
+#define _nm_printf(a,b) __attribute__ ((__format__ (__printf__, a, b)))
 
 #define nm_auto(fcn) __attribute__ ((cleanup(fcn)))
 
@@ -305,6 +310,22 @@ _NM_IN_STRSET_streq (const char *x, const char *s)
 
 /*****************************************************************************/
 
+/* glib/C provides the following kind of assertions:
+ *   - assert() -- disable with NDEBUG
+ *   - g_return_if_fail() -- disable with G_DISABLE_CHECKS
+ *   - g_assert() -- disable with G_DISABLE_ASSERT
+ * but they are all enabled by default and usually even production builds have
+ * these kind of assertions enabled. It also means, that disabling assertions
+ * is an untested configuration, and might have bugs.
+ *
+ * Add our own assertion macro nm_assert(), which is disabled by default and must
+ * be explicitly enabled. They are useful for more expensive checks or checks that
+ * depend less on runtime conditions (that is, are generally expected to be true). */
+
+#ifndef NM_MORE_ASSERTS
+#define NM_MORE_ASSERTS 0
+#endif
+
 #if NM_MORE_ASSERTS
 #define nm_assert(cond) G_STMT_START { g_assert (cond); } G_STMT_END
 #define nm_assert_not_reached() G_STMT_START { g_assert_not_reached (); } G_STMT_END
@@ -473,6 +494,36 @@ nm_strstrip (char *str)
 	return str ? g_strstrip (str) : NULL;
 }
 
+/* g_ptr_array_sort()'s compare function takes pointers to the
+ * value. Thus, you cannot use strcmp directly. You can use
+ * nm_strcmp_p().
+ *
+ * Like strcmp(), this function is not forgiving to accept %NULL. */
+static inline int
+nm_strcmp_p (gconstpointer a, gconstpointer b)
+{
+	const char *s1 = *((const char **) a);
+	const char *s2 = *((const char **) b);
+
+	return strcmp (s1, s2);
+}
+
+/* like nm_strcmp_p(), suitable for g_ptr_array_sort_with_data().
+ * g_ptr_array_sort() just casts nm_strcmp_p() to a function of different
+ * signature. I guess, in glib there are knowledgeable people that ensure
+ * that this additional argument doesn't cause problems due to different ABI
+ * for every architecture that glib supports.
+ * For NetworkManager, we'd rather avoid such stunts.
+ **/
+static inline int
+nm_strcmp_p_with_data (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+	const char *s1 = *((const char **) a);
+	const char *s2 = *((const char **) b);
+
+	return strcmp (s1, s2);
+}
+
 /*****************************************************************************/
 
 static inline guint
@@ -489,6 +540,35 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro) {
 }
 /*****************************************************************************/
 
+/* if @str is NULL, return "(null)". Otherwise, allocate a buffer using
+ * alloca() of size @bufsize and fill it with @str. @str will be quoted with
+ * single quote, and in case @str is too long, the final quote will be '^'. */
+#define nm_strquote_a(bufsize, str) \
+	({ \
+		G_STATIC_ASSERT ((bufsize) >= 6); \
+		const gsize _BUFSIZE = (bufsize); \
+		const char *const _s = (str); \
+		char *_r; \
+		gsize _l; \
+		gboolean _truncated; \
+		\
+		nm_assert (_BUFSIZE >= 6); \
+		\
+		if (_s) { \
+			_l = strlen (_s) + 3; \
+			if ((_truncated = (_BUFSIZE < _l))) \
+				_l = _BUFSIZE; \
+			\
+			_r = g_alloca (_l); \
+			_r[0] = '\''; \
+			memcpy (&_r[1], _s, _l - 3); \
+			_r[_l - 2] = _truncated ? '^' : '\''; \
+			_r[_l - 1] = '\0'; \
+		} else \
+			_r = "(null)"; \
+		_r; \
+	})
+
 #define nm_sprintf_buf(buf, format, ...) ({ \
 		char * _buf = (buf); \
 		\
diff --git a/shared/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c
index 38f6529d..38f6529d 100644
--- a/shared/nm-shared-utils.c
+++ b/shared/nm-utils/nm-shared-utils.c
diff --git a/shared/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h
index cfa8f994..cfa8f994 100644
--- a/shared/nm-shared-utils.h
+++ b/shared/nm-utils/nm-shared-utils.h
diff --git a/shared/nm-test-utils.h b/shared/nm-utils/nm-test-utils.h
index b792a69c..dba41c4b 100644
--- a/shared/nm-test-utils.h
+++ b/shared/nm-utils/nm-test-utils.h
@@ -92,6 +92,11 @@
 
 #include "nm-default.h"
 
+#if defined(NM_ASSERT_NO_MSG) && NM_ASSERT_NO_MSG
+#undef g_return_if_fail_warning
+#undef g_assertion_message_expr
+#endif
+
 #include <arpa/inet.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -101,12 +106,10 @@
 
 #include "nm-utils.h"
 
-#ifdef __NETWORKMANAGER_LOGGING_H__
-/* We are running tests under src/. Let's include some files by default.
- * They are useful, and affect how nm-test-utils.h itself behaves. */
-#include "NetworkManagerUtils.h"
-#include "nm-keyfile-internal.h"
-#endif
+/*******************************************************************************/
+
+#define NMTST_G_RETURN_MSG_S(expr) "*: assertion '"NM_ASSERT_G_RETURN_EXPR(expr)"' failed"
+#define NMTST_G_RETURN_MSG(expr)   NMTST_G_RETURN_MSG_S(#expr)
 
 /*******************************************************************************/
 
@@ -153,13 +156,11 @@
 			g_assert_not_reached (); \
 	} G_STMT_END
 
-inline static void
-_nmtst_assert_success (gboolean success, GError *error, const char *file, int line)
-{
-	if (!success || error)
-		g_error ("(%s:%d) FAILURE success=%d, error=%s", file, line, success, error ? error->message : "(no error)");
-}
-#define nmtst_assert_success(success, error) _nmtst_assert_success ((success), (error), __FILE__, __LINE__)
+#define nmtst_assert_success(success, error) \
+	G_STMT_START { \
+		g_assert_no_error (error); \
+		g_assert ((success)); \
+	} G_STMT_END
 
 #define nmtst_assert_no_success(success, error) \
 	G_STMT_START { \
@@ -512,7 +513,7 @@ __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_
 
 	if (!__nmtst_internal.assert_logging) {
 		gboolean success = TRUE;
-#ifdef __NETWORKMANAGER_LOGGING_H__
+#ifdef _NMTST_INSIDE_CORE
 		success = nm_logging_setup (log_level, log_domains, NULL, NULL);
 		*out_set_logging = TRUE;
 #endif
@@ -529,7 +530,7 @@ __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_
 		 * This transforms g_test_expect_message() into a NOP, but we also have to relax
 		 * g_log_set_always_fatal(), which was set by g_test_init(). */
 		g_log_set_always_fatal (G_LOG_FATAL_MASK);
-#ifdef __NETWORKMANAGER_LOGGING_H__
+#ifdef _NMTST_INSIDE_CORE
 		if (c_log_domains || c_log_level) {
 			/* Normally, tests with assert_logging do not overwrite the logging level/domains because
 			 * the logging statements are part of the assertions. But if the test is run with
@@ -590,27 +591,7 @@ __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_
 #endif
 }
 
-#ifdef __NETWORKMANAGER_LOGGING_H__
-inline static void
-nmtst_init_with_logging (int *argc, char ***argv, const char *log_level, const char *log_domains)
-{
-	__nmtst_init (argc, argv, FALSE, log_level, log_domains, NULL);
-}
-inline static void
-nmtst_init_assert_logging (int *argc, char ***argv, const char *log_level, const char *log_domains)
-{
-	gboolean set_logging;
-
-	__nmtst_init (argc, argv, TRUE, NULL, NULL, &set_logging);
-
-	if (!set_logging) {
-		gboolean success;
-
-		success = nm_logging_setup (log_level, log_domains, NULL, NULL);
-		g_assert (success);
-	}
-}
-#else
+#ifndef _NMTST_INSIDE_CORE
 inline static void
 nmtst_init (int *argc, char ***argv, gboolean assert_logging)
 {
@@ -1177,247 +1158,6 @@ _nmtst_assert_resolve_relative_path_equals (const char *f1, const char *f2, cons
 
 /*******************************************************************************/
 
-#ifdef __NETWORKMANAGER_PLATFORM_H__
-
-inline static NMPlatformIP4Address *
-nmtst_platform_ip4_address (const char *address, const char *peer_address, guint plen)
-{
-	static NMPlatformIP4Address addr;
-
-	g_assert (plen <= 32);
-
-	memset (&addr, 0, sizeof (addr));
-	addr.address = nmtst_inet4_from_string (address);
-	if (peer_address)
-		addr.peer_address = nmtst_inet4_from_string (peer_address);
-	else
-		addr.peer_address = addr.address;
-	addr.plen = plen;
-
-	return &addr;
-}
-
-inline static NMPlatformIP4Address *
-nmtst_platform_ip4_address_full (const char *address, const char *peer_address, guint plen,
-                                 int ifindex, NMIPConfigSource source, guint32 timestamp,
-                                 guint32 lifetime, guint32 preferred, guint32 flags,
-                                 const char *label)
-{
-	NMPlatformIP4Address *addr = nmtst_platform_ip4_address (address, peer_address, plen);
-
-	G_STATIC_ASSERT (IFNAMSIZ == sizeof (addr->label));
-	g_assert (!label || strlen (label) < IFNAMSIZ);
-
-	addr->ifindex = ifindex;
-	addr->source = source;
-	addr->timestamp = timestamp;
-	addr->lifetime = lifetime;
-	addr->preferred = preferred;
-	addr->n_ifa_flags = flags;
-	if (label)
-		g_strlcpy (addr->label, label, sizeof (addr->label));
-
-	return addr;
-}
-
-inline static NMPlatformIP6Address *
-nmtst_platform_ip6_address (const char *address, const char *peer_address, guint plen)
-{
-	static NMPlatformIP6Address addr;
-
-	g_assert (plen <= 128);
-
-	memset (&addr, 0, sizeof (addr));
-	addr.address = *nmtst_inet6_from_string (address);
-	addr.peer_address = *nmtst_inet6_from_string (peer_address);
-	addr.plen = plen;
-
-	return &addr;
-}
-
-inline static NMPlatformIP6Address *
-nmtst_platform_ip6_address_full (const char *address, const char *peer_address, guint plen,
-                                 int ifindex, NMIPConfigSource source, guint32 timestamp,
-                                 guint32 lifetime, guint32 preferred, guint32 flags)
-{
-	NMPlatformIP6Address *addr = nmtst_platform_ip6_address (address, peer_address, plen);
-
-	addr->ifindex = ifindex;
-	addr->source = source;
-	addr->timestamp = timestamp;
-	addr->lifetime = lifetime;
-	addr->preferred = preferred;
-	addr->n_ifa_flags = flags;
-
-	return addr;
-}
-
-inline static NMPlatformIP4Route *
-nmtst_platform_ip4_route (const char *network, guint plen, const char *gateway)
-{
-	static NMPlatformIP4Route route;
-
-	g_assert (plen <= 32);
-
-	memset (&route, 0, sizeof (route));
-	route.network = nmtst_inet4_from_string (network);
-	route.plen = plen;
-	route.gateway = nmtst_inet4_from_string (gateway);
-
-	return &route;
-}
-
-inline static NMPlatformIP4Route *
-nmtst_platform_ip4_route_full (const char *network, guint plen, const char *gateway,
-                               int ifindex, NMIPConfigSource source,
-                               guint metric, guint mss,
-                               guint8 scope,
-                               const char *pref_src)
-{
-	NMPlatformIP4Route *route = nmtst_platform_ip4_route (network, plen, gateway);
-
-	route->ifindex = ifindex;
-	route->source = source;
-	route->metric = metric;
-	route->mss = mss;
-	route->scope_inv = nm_platform_route_scope_inv (scope);
-	route->pref_src = nmtst_inet4_from_string (pref_src);
-
-	return route;
-}
-
-inline static NMPlatformIP6Route *
-nmtst_platform_ip6_route (const char *network, guint plen, const char *gateway)
-{
-	static NMPlatformIP6Route route;
-
-	nm_assert (plen <= 128);
-
-	memset (&route, 0, sizeof (route));
-	route.network = *nmtst_inet6_from_string (network);
-	route.plen = plen;
-	route.gateway = *nmtst_inet6_from_string (gateway);
-
-	return &route;
-}
-
-inline static NMPlatformIP6Route *
-nmtst_platform_ip6_route_full (const char *network, guint plen, const char *gateway,
-                               int ifindex, NMIPConfigSource source,
-                               guint metric, guint mss)
-{
-	NMPlatformIP6Route *route = nmtst_platform_ip6_route (network, plen, gateway);
-
-	route->ifindex = ifindex;
-	route->source = source;
-	route->metric = metric;
-	route->mss = mss;
-
-	return route;
-}
-
-inline static int
-_nmtst_platform_ip4_routes_equal_sort (gconstpointer a, gconstpointer b, gpointer user_data)
-{
-	return nm_platform_ip4_route_cmp ((const NMPlatformIP4Route *) a, (const NMPlatformIP4Route *) b);
-}
-
-inline static void
-nmtst_platform_ip4_routes_equal (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, gsize len, gboolean ignore_order)
-{
-	gsize i;
-	gs_free const NMPlatformIP4Route *c_a = NULL, *c_b = NULL;
-
-	g_assert (a);
-	g_assert (b);
-
-	if (ignore_order) {
-		a = c_a = g_memdup (a, sizeof (NMPlatformIP4Route) * len);
-		b = c_b = g_memdup (b, sizeof (NMPlatformIP4Route) * len);
-		g_qsort_with_data (c_a, len, sizeof (NMPlatformIP4Route), _nmtst_platform_ip4_routes_equal_sort, NULL);
-		g_qsort_with_data (c_b, len, sizeof (NMPlatformIP4Route), _nmtst_platform_ip4_routes_equal_sort, NULL);
-	}
-
-	for (i = 0; i < len; i++) {
-		if (nm_platform_ip4_route_cmp (&a[i], &b[i]) != 0) {
-			char buf[sizeof (_nm_utils_to_string_buffer)];
-
-			g_error ("Error comparing IPv4 route[%lu]: %s vs %s", (long unsigned) i,
-			         nm_platform_ip4_route_to_string (&a[i], NULL, 0),
-			         nm_platform_ip4_route_to_string (&b[i], buf, sizeof (buf)));
-			g_assert_not_reached ();
-		}
-	}
-}
-
-inline static int
-_nmtst_platform_ip6_routes_equal_sort (gconstpointer a, gconstpointer b, gpointer user_data)
-{
-	return nm_platform_ip6_route_cmp ((const NMPlatformIP6Route *) a, (const NMPlatformIP6Route *) b);
-}
-
-inline static void
-nmtst_platform_ip6_routes_equal (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, gsize len, gboolean ignore_order)
-{
-	gsize i;
-	gs_free const NMPlatformIP6Route *c_a = NULL, *c_b = NULL;
-
-	g_assert (a);
-	g_assert (b);
-
-	if (ignore_order) {
-		a = c_a = g_memdup (a, sizeof (NMPlatformIP6Route) * len);
-		b = c_b = g_memdup (b, sizeof (NMPlatformIP6Route) * len);
-		g_qsort_with_data (c_a, len, sizeof (NMPlatformIP6Route), _nmtst_platform_ip6_routes_equal_sort, NULL);
-		g_qsort_with_data (c_b, len, sizeof (NMPlatformIP6Route), _nmtst_platform_ip6_routes_equal_sort, NULL);
-	}
-
-	for (i = 0; i < len; i++) {
-		if (nm_platform_ip6_route_cmp (&a[i], &b[i]) != 0) {
-			char buf[sizeof (_nm_utils_to_string_buffer)];
-
-			g_error ("Error comparing IPv6 route[%lu]: %s vs %s", (long unsigned) i,
-			         nm_platform_ip6_route_to_string (&a[i], NULL, 0),
-			         nm_platform_ip6_route_to_string (&b[i], buf, sizeof (buf)));
-			g_assert_not_reached ();
-		}
-	}
-}
-
-#endif
-
-
-#ifdef __NETWORKMANAGER_IP4_CONFIG_H__
-
-inline static NMIP4Config *
-nmtst_ip4_config_clone (NMIP4Config *config)
-{
-	NMIP4Config *copy = nm_ip4_config_new (-1);
-
-	g_assert (copy);
-	g_assert (config);
-	nm_ip4_config_replace (copy, config, NULL);
-	return copy;
-}
-
-#endif
-
-
-#ifdef __NETWORKMANAGER_IP6_CONFIG_H__
-
-inline static NMIP6Config *
-nmtst_ip6_config_clone (NMIP6Config *config)
-{
-	NMIP6Config *copy = nm_ip6_config_new (-1);
-
-	g_assert (copy);
-	g_assert (config);
-	nm_ip6_config_replace (copy, config, NULL);
-	return copy;
-}
-
-#endif
-
 #ifdef NM_SETTING_IP_CONFIG_H
 inline static void
 nmtst_setting_ip_config_add_address (NMSettingIPConfig *s_ip,
diff --git a/shared/nm-utils/nm-vpn-editor-plugin-call.h b/shared/nm-utils/nm-vpn-editor-plugin-call.h
new file mode 100644
index 00000000..78d041df
--- /dev/null
+++ b/shared/nm-utils/nm-vpn-editor-plugin-call.h
@@ -0,0 +1,188 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2016 Red Hat, Inc.
+ */
+
+#ifndef __NM_VPN_EDITOR_PLUGIN_CALL_H__
+#define __NM_VPN_EDITOR_PLUGIN_CALL_H__
+
+/* This header is an internal, header-only file that can be copied to
+ * other projects to call well-known service functions on VPN plugins.
+ *
+ * This uses the NMVpnEditorPluginVT and allows a user (nm-applet)
+ * to directly communicate with a VPN plugin using API that is newer
+ * then the current libnm version. That is, it allows to call to a VPN
+ * plugin bypassing libnm. */
+
+#include <NetworkManager.h>
+
+/* we make use of other internal header files, you need those too. */
+#include "nm-macros-internal.h"
+
+/*****************************************************************************/
+
+/**
+ * NMVpnEditorPluginServiceFlags:
+ * @NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_NONE: no flags
+ * @NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_CAN_ADD: whether the plugin can
+ *   add a new connection for the given service-type.
+ **/
+typedef enum { /*< skip >*/
+	NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_NONE     = 0x00,
+	NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_CAN_ADD  = 0x01,
+} NMVpnEditorPluginServiceFlags;
+
+struct _NMVpnEditorPluginVT {
+	gboolean (*fcn_get_service_info) (NMVpnEditorPlugin *plugin,
+	                                  const char *service_type,
+	                                  char **out_short_name,
+	                                  char **out_pretty_name,
+	                                  char **out_description,
+	                                  NMVpnEditorPluginServiceFlags *out_flags);
+	char **(*fcn_get_service_add_details) (NMVpnEditorPlugin *plugin,
+	                                       const char *service_name);
+	gboolean (*fcn_get_service_add_detail) (NMVpnEditorPlugin *plugin,
+	                                        const char *service_type,
+	                                        const char *add_detail,
+	                                        char **out_pretty_name,
+	                                        char **out_description,
+	                                        char **out_add_detail_key,
+	                                        char **out_add_detail_val,
+	                                        guint *out_flags);
+};
+
+/*****************************************************************************
+ * Call
+ *
+ * The following wrap the calling of generic functions for a VPN plugin.
+ * They are used by callers (for example nm-connection-editor).
+ *****************************************************************************/
+
+static inline gboolean
+nm_vpn_editor_plugin_get_service_info (NMVpnEditorPlugin *plugin,
+                                       const char *service_type,
+                                       char **out_short_name,
+                                       char **out_pretty_name,
+                                       char **out_description,
+                                       NMVpnEditorPluginServiceFlags *out_flags)
+{
+	NMVpnEditorPluginVT vt;
+	gs_free char *short_name_local = NULL;
+	gs_free char *pretty_name_local = NULL;
+	gs_free char *description_local = NULL;
+	guint flags_local = 0;
+
+	g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (plugin), FALSE);
+	g_return_val_if_fail (service_type, FALSE);
+
+	nm_vpn_editor_plugin_get_vt (plugin, &vt, sizeof (vt));
+	if (   !vt.fcn_get_service_info
+	    || !vt.fcn_get_service_info (plugin,
+	                                 service_type,
+	                                 out_short_name  ? &short_name_local : NULL,
+	                                 out_pretty_name ? &pretty_name_local : NULL,
+	                                 out_description ? &description_local : NULL,
+	                                 out_flags       ? &flags_local : NULL))
+		return FALSE;
+	NM_SET_OUT (out_short_name, g_steal_pointer (&short_name_local));
+	NM_SET_OUT (out_pretty_name, g_steal_pointer (&pretty_name_local));
+	NM_SET_OUT (out_description, g_steal_pointer (&description_local));
+	NM_SET_OUT (out_flags, flags_local);
+	return TRUE;
+}
+
+static inline char **
+nm_vpn_editor_plugin_get_service_add_details (NMVpnEditorPlugin *plugin,
+                                              const char *service_name)
+{
+	NMVpnEditorPluginVT vt;
+	char **details = NULL;
+
+	g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (plugin), NULL);
+	g_return_val_if_fail (service_name, NULL);
+
+	nm_vpn_editor_plugin_get_vt (plugin, &vt, sizeof (vt));
+	if (vt.fcn_get_service_add_details)
+		details = vt.fcn_get_service_add_details (plugin, service_name);
+	if (!details)
+		return g_new0 (char *, 1);
+	return details;
+}
+
+static inline gboolean
+nm_vpn_editor_plugin_get_service_add_detail (NMVpnEditorPlugin *plugin,
+                                             const char *service_type,
+                                             const char *add_detail,
+                                             char **out_pretty_name,
+                                             char **out_description,
+                                             char **out_add_detail_key,
+                                             char **out_add_detail_val,
+                                             guint *out_flags)
+{
+	NMVpnEditorPluginVT vt;
+	gs_free char *pretty_name_local = NULL;
+	gs_free char *description_local = NULL;
+	gs_free char *add_detail_key_local = NULL;
+	gs_free char *add_detail_val_local = NULL;
+	guint flags_local = 0;
+
+	g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (plugin), FALSE);
+	g_return_val_if_fail (service_type, FALSE);
+	g_return_val_if_fail (add_detail, FALSE);
+
+	nm_vpn_editor_plugin_get_vt (plugin, &vt, sizeof (vt));
+	if (   !vt.fcn_get_service_add_detail
+	    || !vt.fcn_get_service_add_detail (plugin,
+	                                       service_type,
+	                                       add_detail,
+	                                       out_pretty_name    ? &pretty_name_local : NULL,
+	                                       out_description    ? &description_local : NULL,
+	                                       out_add_detail_key ? &add_detail_key_local : NULL,
+	                                       out_add_detail_val ? &add_detail_val_local : NULL,
+	                                       out_flags          ? &flags_local : NULL))
+		return FALSE;
+	NM_SET_OUT (out_pretty_name, g_steal_pointer (&pretty_name_local));
+	NM_SET_OUT (out_description, g_steal_pointer (&description_local));
+	NM_SET_OUT (out_add_detail_key, g_steal_pointer (&add_detail_key_local));
+	NM_SET_OUT (out_add_detail_val, g_steal_pointer (&add_detail_val_local));
+	NM_SET_OUT (out_flags, flags_local);
+	return TRUE;
+}
+
+/*****************************************************************************
+ * Implementation
+ *
+ * The following glue code can be used to implement calls in a VPN plugin.
+ *****************************************************************************/
+
+#define NM_VPN_EDITOR_PLUGIN_VT_DEFINE(vt_name, get_vt, ...) \
+static const NMVpnEditorPluginVT vt_name = { \
+		__VA_ARGS__ \
+	}; \
+static const NMVpnEditorPluginVT * \
+get_vt (NMVpnEditorPlugin *plugin, \
+        gsize *out_vt_size) \
+{ \
+	nm_assert (NM_IS_VPN_EDITOR_PLUGIN (plugin)); \
+	nm_assert (out_vt_size); \
+	\
+	*out_vt_size = sizeof (vt_name); \
+	return &vt_name; \
+}
+
+#endif /* __NM_VPN_EDITOR_PLUGIN_CALL_H__ */
diff --git a/shared/nm-utils/nm-vpn-plugin-macros.h b/shared/nm-utils/nm-vpn-plugin-macros.h
new file mode 100644
index 00000000..06f5b286
--- /dev/null
+++ b/shared/nm-utils/nm-vpn-plugin-macros.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2016 Red Hat, Inc.
+ */
+
+#ifndef __NM_VPN_PLUGIN_MACROS_H__
+#define __NM_VPN_PLUGIN_MACROS_H__
+
+#include <syslog.h>
+
+static inline const char *
+nm_utils_syslog_to_str (int syslog_level)
+{
+	/* Maps the levels the same way as NetworkManager's nm-logging.c does */
+	if (syslog_level >= LOG_DEBUG)
+		return "<trace>";
+	if (syslog_level >= LOG_INFO)
+		return "<debug>";
+	if (syslog_level >= LOG_NOTICE)
+		return "<info>";
+	if (syslog_level >= LOG_WARNING)
+		return "<warn>";
+	return "<error>";
+}
+
+/*****************************************************************************/
+
+/* possibly missing defines from newer libnm API. */
+
+#ifndef NM_VPN_PLUGIN_CONFIG_PROXY_PAC
+#define NM_VPN_PLUGIN_CONFIG_PROXY_PAC "pac"
+#endif
+
+#ifndef NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES
+#define NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES "preserve-routes"
+#endif
+
+#ifndef NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES
+#define NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES "preserve-routes"
+#endif
+
+/*****************************************************************************/
+
+#endif /* __NM_VPN_PLUGIN_MACROS_H__ */
+
diff --git a/shared/nm-utils/nm-vpn-plugin-utils.c b/shared/nm-utils/nm-vpn-plugin-utils.c
new file mode 100644
index 00000000..772aa39a
--- /dev/null
+++ b/shared/nm-utils/nm-vpn-plugin-utils.c
@@ -0,0 +1,130 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2016 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-vpn-plugin-utils.h"
+
+#include <dlfcn.h>
+
+/*****************************************************************************/
+
+NMVpnEditor *
+nm_vpn_plugin_utils_load_editor (const char *module_name,
+                                 const char *factory_name,
+                                 NMVpnPluginUtilsEditorFactory editor_factory,
+                                 NMVpnEditorPlugin *editor_plugin,
+                                 NMConnection *connection,
+                                 gpointer user_data,
+                                 GError **error)
+
+{
+	static struct {
+		gpointer factory;
+		void *dl_module;
+		char *module_name;
+		char *factory_name;
+	} cached = { 0 };
+	NMVpnEditor *editor;
+
+	g_return_val_if_fail (module_name && g_path_is_absolute (module_name), NULL);
+	g_return_val_if_fail (factory_name && factory_name[0], NULL);
+	g_return_val_if_fail (editor_factory, NULL);
+	g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (editor_plugin), NULL);
+	g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
+	g_return_val_if_fail (!error || !*error, NULL);
+
+	/* we really expect this function to be called with unchanging @module_name
+	 * and @factory_name. And we only want to load the module once, hence it would
+	 * be more complicated to accept changing @module_name/@factory_name arguments.
+	 *
+	 * The reason for only loading once is that due to glib types, we cannot create a
+	 * certain type-name more then once, so loading the same module or another version
+	 * of the same module will fail horribly as both try to create a GType with the same
+	 * name.
+	 *
+	 * Only support loading once, any future calls will reuse the handle. To simplify
+	 * that, we enforce that the @factory_name and @module_name is the same. */
+	if (cached.factory) {
+		g_return_val_if_fail (cached.dl_module, NULL);
+		g_return_val_if_fail (cached.factory_name && nm_streq0 (cached.factory_name, factory_name), NULL);
+		g_return_val_if_fail (cached.module_name && nm_streq0 (cached.module_name, module_name), NULL);
+	} else {
+		gpointer factory;
+		void *dl_module;
+
+		dl_module = dlopen (module_name, RTLD_LAZY | RTLD_LOCAL);
+		if (!dl_module) {
+			if (!g_file_test (module_name, G_FILE_TEST_EXISTS)) {
+				g_set_error (error,
+				             G_FILE_ERROR,
+				             G_FILE_ERROR_NOENT,
+				             _("missing plugin file \"%s\""), module_name);
+				return NULL;
+			}
+			g_set_error (error,
+			             NM_CONNECTION_ERROR,
+			             NM_CONNECTION_ERROR_FAILED,
+			             _("cannot load editor plugin: %s"), dlerror ());
+			return NULL;
+		}
+
+		factory = dlsym (dl_module, factory_name);
+		if (!factory) {
+			g_set_error (error,
+			             NM_CONNECTION_ERROR,
+			             NM_CONNECTION_ERROR_FAILED,
+			             _("cannot load factory %s from plugin: %s"),
+			             factory_name, dlerror ());
+			dlclose (dl_module);
+			return NULL;
+		}
+
+		/* we cannot ever unload the module because it creates glib types, which
+		 * cannot be unregistered.
+		 *
+		 * Thus we just leak the dl_module handle indefinitely. */
+		cached.factory = factory;
+		cached.dl_module = dl_module;
+		cached.module_name = g_strdup (module_name);
+		cached.factory_name = g_strdup (factory_name);
+	}
+
+	editor = editor_factory (cached.factory,
+	                         editor_plugin,
+	                         connection,
+	                         user_data,
+	                         error);
+	if (!editor) {
+		if (error && !*error ) {
+			g_set_error_literal (error,
+			                     NM_CONNECTION_ERROR,
+			                     NM_CONNECTION_ERROR_FAILED,
+			                     _("unknown error creating editor instance"));
+			g_return_val_if_reached (NULL);
+		}
+		return NULL;
+	}
+
+	g_return_val_if_fail (NM_IS_VPN_EDITOR (editor), NULL);
+	return editor;
+}
+
diff --git a/shared/nm-utils/nm-vpn-plugin-utils.h b/shared/nm-utils/nm-vpn-plugin-utils.h
new file mode 100644
index 00000000..f3928d1e
--- /dev/null
+++ b/shared/nm-utils/nm-vpn-plugin-utils.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2016 Red Hat, Inc.
+ */
+
+#ifndef __NM_VPN_PLUGIN_UTILS_H__
+#define __NM_VPN_PLUGIN_UTILS_H__
+
+#include <NetworkManager.h>
+
+typedef NMVpnEditor *(NMVpnPluginUtilsEditorFactory) (gpointer factory,
+                                                      NMVpnEditorPlugin *editor_plugin,
+                                                      NMConnection *connection,
+                                                      gpointer user_data,
+                                                      GError **error);
+
+NMVpnEditor *nm_vpn_plugin_utils_load_editor (const char *module_name,
+                                              const char *factory_name,
+                                              NMVpnPluginUtilsEditorFactory editor_factory,
+                                              NMVpnEditorPlugin *editor_plugin,
+                                              NMConnection *connection,
+                                              gpointer user_data,
+                                              GError **error);
+
+#endif /* __NM_VPN_PLUGIN_UTILS_H__ */
+
diff --git a/shared/nm-version-macros.h b/shared/nm-version-macros.h
index e8bd4f84..3c3b1732 100644
--- a/shared/nm-version-macros.h
+++ b/shared/nm-version-macros.h
@@ -37,7 +37,7 @@
  * Evaluates to the minor version number of NetworkManager which this source
  * is compiled against.
  */
-#define NM_MINOR_VERSION (2)
+#define NM_MINOR_VERSION (4)
 
 /**
  * NM_MICRO_VERSION:
@@ -45,7 +45,7 @@
  * Evaluates to the micro version number of NetworkManager which this source
  * compiled against.
  */
-#define NM_MICRO_VERSION (4)
+#define NM_MICRO_VERSION (0)
 
 /**
  * NM_CHECK_VERSION:
@@ -68,12 +68,9 @@
 #define NM_VERSION_0_9_10 (NM_ENCODE_VERSION (0, 9, 10))
 #define NM_VERSION_1_0    (NM_ENCODE_VERSION (1, 0, 0))
 #define NM_VERSION_1_2    (NM_ENCODE_VERSION (1, 2, 0))
-#define NM_VERSION_1_2_2  (NM_ENCODE_VERSION (1, 2, 2))
-#define NM_VERSION_1_2_4  (NM_ENCODE_VERSION (1, 2, 4))
-#define NM_VERSION_1_2_6  (NM_ENCODE_VERSION (1, 2, 6))
 #define NM_VERSION_1_4    (NM_ENCODE_VERSION (1, 4, 0))
 
-#define NM_VERSION_CUR_STABLE  NM_VERSION_1_2_4
-#define NM_VERSION_NEXT_STABLE NM_VERSION_1_2_6
+#define NM_VERSION_CUR_STABLE  NM_VERSION_1_2
+#define NM_VERSION_NEXT_STABLE NM_VERSION_1_4
 
 #endif  /* __NM_VERSION_MACROS_H__ */
diff --git a/shared/nm-version-macros.h.in b/shared/nm-version-macros.h.in
index 71f66fef..d67aab4c 100644
--- a/shared/nm-version-macros.h.in
+++ b/shared/nm-version-macros.h.in
@@ -68,12 +68,9 @@
 #define NM_VERSION_0_9_10 (NM_ENCODE_VERSION (0, 9, 10))
 #define NM_VERSION_1_0    (NM_ENCODE_VERSION (1, 0, 0))
 #define NM_VERSION_1_2    (NM_ENCODE_VERSION (1, 2, 0))
-#define NM_VERSION_1_2_2  (NM_ENCODE_VERSION (1, 2, 2))
-#define NM_VERSION_1_2_4  (NM_ENCODE_VERSION (1, 2, 4))
-#define NM_VERSION_1_2_6  (NM_ENCODE_VERSION (1, 2, 6))
 #define NM_VERSION_1_4    (NM_ENCODE_VERSION (1, 4, 0))
 
-#define NM_VERSION_CUR_STABLE  NM_VERSION_1_2_4
-#define NM_VERSION_NEXT_STABLE NM_VERSION_1_2_6
+#define NM_VERSION_CUR_STABLE  NM_VERSION_1_2
+#define NM_VERSION_NEXT_STABLE NM_VERSION_1_4
 
 #endif  /* __NM_VERSION_MACROS_H__ */