summary refs log tree commit diff
path: root/libnm-core
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2015-08-28 01:13:48 +0200
committerMichael Biebl <biebl@debian.org>2015-08-28 01:13:48 +0200
commit81836c2d44802b4cca833d7775dd627e0797a7e2 (patch)
tree91154e6cefc0465306603f51ec0010d9963bbea4 /libnm-core
parent50a58f0fabd8a34c1b6108a107e08abe3c1ccd24 (diff)
Imported Upstream version 1.0.6 upstream/1.0.6
Diffstat (limited to 'libnm-core')
-rw-r--r--libnm-core/nm-connection.c3
-rw-r--r--libnm-core/nm-core-enum-types.c46
-rw-r--r--libnm-core/nm-core-enum-types.h4
-rw-r--r--libnm-core/nm-core-internal.h2
-rw-r--r--libnm-core/nm-dbus-interface.h21
-rw-r--r--libnm-core/nm-setting-connection.c60
-rw-r--r--libnm-core/nm-setting-connection.h3
-rw-r--r--libnm-core/nm-setting-ip-config.c11
-rw-r--r--libnm-core/nm-setting-vlan.c2
-rw-r--r--libnm-core/nm-setting-wired.c120
-rw-r--r--libnm-core/nm-setting-wired.h37
-rw-r--r--libnm-core/nm-utils.c220
-rw-r--r--libnm-core/nm-utils.h10
-rw-r--r--libnm-core/nm-version.h28
-rw-r--r--libnm-core/nm-version.h.in26
-rw-r--r--libnm-core/tests/Makefile.am15
-rw-r--r--libnm-core/tests/Makefile.in42
-rw-r--r--libnm-core/tests/nm-core-tests-enum-types.c74
-rw-r--r--libnm-core/tests/nm-core-tests-enum-types.h23
-rw-r--r--libnm-core/tests/test-general-enums.h46
-rw-r--r--libnm-core/tests/test-general.c168
21 files changed, 927 insertions, 34 deletions
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c
index acdc8b89..8f226582 100644
--- a/libnm-core/nm-connection.c
+++ b/libnm-core/nm-connection.c
@@ -1498,7 +1498,8 @@ nm_connection_get_uuid (NMConnection *connection)
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
 
 	s_con = nm_connection_get_setting_connection (connection);
-	g_return_val_if_fail (s_con != NULL, NULL);
+	if (!s_con)
+		return NULL;
 
 	return nm_setting_connection_get_uuid (s_con);
 }
diff --git a/libnm-core/nm-core-enum-types.c b/libnm-core/nm-core-enum-types.c
index cfb264cf..a9e4266a 100644
--- a/libnm-core/nm-core-enum-types.c
+++ b/libnm-core/nm-core-enum-types.c
@@ -413,6 +413,28 @@ nm_device_state_reason_get_type (void)
   return g_define_type_id__volatile;
 }
 GType
+nm_metered_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_METERED_UNKNOWN, "NM_METERED_UNKNOWN", "unknown" },
+        { NM_METERED_YES, "NM_METERED_YES", "yes" },
+        { NM_METERED_NO, "NM_METERED_NO", "no" },
+        { NM_METERED_GUESS_YES, "NM_METERED_GUESS_YES", "guess-yes" },
+        { NM_METERED_GUESS_NO, "NM_METERED_GUESS_NO", "guess-no" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMMetered"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
 nm_active_connection_state_get_type (void)
 {
   static volatile gsize g_define_type_id__volatile = 0;
@@ -839,6 +861,30 @@ nm_vlan_flags_get_type (void)
   return g_define_type_id__volatile;
 }
 GType
+nm_setting_wired_wake_on_lan_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GFlagsValue values[] = {
+        { NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT, "NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT", "default" },
+        { NM_SETTING_WIRED_WAKE_ON_LAN_PHY, "NM_SETTING_WIRED_WAKE_ON_LAN_PHY", "phy" },
+        { NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST, "NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST", "unicast" },
+        { NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST, "NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST", "multicast" },
+        { NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST, "NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST", "broadcast" },
+        { NM_SETTING_WIRED_WAKE_ON_LAN_ARP, "NM_SETTING_WIRED_WAKE_ON_LAN_ARP", "arp" },
+        { NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC, "NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC", "magic" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_flags_register_static (g_intern_static_string ("NMSettingWiredWakeOnLan"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
 nm_wep_key_type_get_type (void)
 {
   static volatile gsize g_define_type_id__volatile = 0;
diff --git a/libnm-core/nm-core-enum-types.h b/libnm-core/nm-core-enum-types.h
index abc646b2..7e5c6df0 100644
--- a/libnm-core/nm-core-enum-types.h
+++ b/libnm-core/nm-core-enum-types.h
@@ -35,6 +35,8 @@ GType nm_device_state_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_DEVICE_STATE (nm_device_state_get_type ())
 GType nm_device_state_reason_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_DEVICE_STATE_REASON (nm_device_state_reason_get_type ())
+GType nm_metered_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_METERED (nm_metered_get_type ())
 GType nm_active_connection_state_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_ACTIVE_CONNECTION_STATE (nm_active_connection_state_get_type ())
 GType nm_secret_agent_get_secrets_flags_get_type (void) G_GNUC_CONST;
@@ -73,6 +75,8 @@ GType nm_vlan_priority_map_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_VLAN_PRIORITY_MAP (nm_vlan_priority_map_get_type ())
 GType nm_vlan_flags_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_VLAN_FLAGS (nm_vlan_flags_get_type ())
+GType nm_setting_wired_wake_on_lan_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_SETTING_WIRED_WAKE_ON_LAN (nm_setting_wired_wake_on_lan_get_type ())
 GType nm_wep_key_type_get_type (void) G_GNUC_CONST;
 #define NM_TYPE_WEP_KEY_TYPE (nm_wep_key_type_get_type ())
 GType nm_setting_secret_flags_get_type (void) G_GNUC_CONST;
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index dd5151e0..73a379c3 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -159,4 +159,6 @@ const char *nm_utils_bond_mode_int_to_string (int mode);
 
 gint64 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback);
 
+gboolean _nm_dbus_error_has_name (GError     *error,
+                                  const char *dbus_error_name);
 #endif
diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h
index ccc3b3a9..8c5cd3c4 100644
--- a/libnm-core/nm-dbus-interface.h
+++ b/libnm-core/nm-dbus-interface.h
@@ -403,7 +403,6 @@ typedef enum {
 	NM_DEVICE_STATE_FAILED       = 120
 } NMDeviceState;
 
-
 /**
  * NMDeviceStateReason:
  * @NM_DEVICE_STATE_REASON_NONE: No reason given
@@ -540,6 +539,26 @@ typedef enum {
 	NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED = 62,
 } NMDeviceStateReason;
 
+/**
+ * NMMetered:
+ * @NM_METERED_UNKNOWN:     The metered status is unknown
+ * @NM_METERED_YES:         Metered, the value was statically set
+ * @NM_METERED_NO:          Not metered, the value was statically set
+ * @NM_METERED_GUESS_YES:   Metered, the value was guessed
+ * @NM_METERED_GUESS_NO:    Not metered, the value was guessed
+ *
+ * (Corresponds to the NM_METERED type in nm-device.xml.)
+ *
+ * Since: 1.0.6
+ **/
+NM_AVAILABLE_IN_1_0_6
+typedef enum {
+	NM_METERED_UNKNOWN    = 0,
+	NM_METERED_YES        = 1,
+	NM_METERED_NO         = 2,
+	NM_METERED_GUESS_YES  = 3,
+	NM_METERED_GUESS_NO   = 4,
+} NMMetered;
 
 /**
  * NMActiveConnectionState:
diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c
index 07b3401d..28e590df 100644
--- a/libnm-core/nm-setting-connection.c
+++ b/libnm-core/nm-setting-connection.c
@@ -76,6 +76,7 @@ typedef struct {
 	char *zone;
 	GSList *secondaries; /* secondary connections to activate with the base connection */
 	guint gateway_ping_timeout;
+	NMMetered metered;
 } NMSettingConnectionPrivate;
 
 enum {
@@ -95,6 +96,7 @@ enum {
 	PROP_AUTOCONNECT_SLAVES,
 	PROP_SECONDARIES,
 	PROP_GATEWAY_PING_TIMEOUT,
+	PROP_METERED,
 
 	LAST_PROP
 };
@@ -760,6 +762,23 @@ nm_setting_connection_get_gateway_ping_timeout (NMSettingConnection *setting)
 	return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->gateway_ping_timeout;
 }
 
+/**
+ * nm_setting_connection_get_metered:
+ * @setting: the #NMSettingConnection
+ *
+ * Returns: the #NMSettingConnection:metered property of the setting.
+ *
+ * Since: 1.0.6
+ **/
+NMMetered
+nm_setting_connection_get_metered (NMSettingConnection *setting)
+{
+	g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting),
+	                      NM_METERED_UNKNOWN);
+
+	return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->metered;
+}
+
 static void
 _set_error_missing_base_setting (GError **error, const char *type)
 {
@@ -921,6 +940,18 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 		}
 	}
 
+	if (priv->metered != NM_METERED_UNKNOWN &&
+	    priv->metered != NM_METERED_YES &&
+	    priv->metered != NM_METERED_NO) {
+		g_set_error (error,
+		             NM_CONNECTION_ERROR,
+		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		             _("metered value %d is not valid"), priv->metered);
+		g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME,
+		                NM_SETTING_CONNECTION_METERED);
+		return FALSE;
+	}
+
 	/* *** errors above here should be always fatal, below NORMALIZABLE_ERROR *** */
 
 	if (!priv->uuid) {
@@ -1154,6 +1185,9 @@ set_property (GObject *object, guint prop_id,
 	case PROP_GATEWAY_PING_TIMEOUT:
 		priv->gateway_ping_timeout = g_value_get_uint (value);
 		break;
+	case PROP_METERED:
+		priv->metered = g_value_get_enum (value);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -1227,6 +1261,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_GATEWAY_PING_TIMEOUT:
 		g_value_set_uint (value, priv->gateway_ping_timeout);
 		break;
+	case PROP_METERED:
+		g_value_set_enum (value, priv->metered);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -1626,4 +1663,27 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class)
 		                    G_PARAM_READWRITE |
 		                    G_PARAM_CONSTRUCT |
 		                    G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * NMSettingConnection:metered:
+	 *
+	 * Whether the connection is metered.
+	 *
+	 * Since: 1.0.6
+	 **/
+	/* ---ifcfg-rh---
+	 * property: metered
+	 * variable: CONNECTION_METERED
+	 * values: yes,no,unknown
+	 * description: Whether the device is metered
+	 * example: CONNECTION_METERED=yes
+	 * ---end---
+	 */
+	g_object_class_install_property
+		(object_class, PROP_METERED,
+		 g_param_spec_enum (NM_SETTING_CONNECTION_METERED, "", "",
+		                    NM_TYPE_METERED,
+		                    NM_METERED_UNKNOWN,
+		                    G_PARAM_READWRITE |
+		                    G_PARAM_STATIC_STRINGS));
 }
diff --git a/libnm-core/nm-setting-connection.h b/libnm-core/nm-setting-connection.h
index ff89d200..24b5f6ac 100644
--- a/libnm-core/nm-setting-connection.h
+++ b/libnm-core/nm-setting-connection.h
@@ -59,6 +59,7 @@ G_BEGIN_DECLS
 #define NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES "autoconnect-slaves"
 #define NM_SETTING_CONNECTION_SECONDARIES    "secondaries"
 #define NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT "gateway-ping-timeout"
+#define NM_SETTING_CONNECTION_METERED        "metered"
 
 /* Types for property values */
 /**
@@ -142,6 +143,8 @@ void        nm_setting_connection_remove_secondary     (NMSettingConnection *set
 gboolean    nm_setting_connection_remove_secondary_by_value (NMSettingConnection *setting, const char *sec_uuid);
 
 guint32     nm_setting_connection_get_gateway_ping_timeout (NMSettingConnection *setting);
+NM_AVAILABLE_IN_1_0_6
+NMMetered   nm_setting_connection_get_metered (NMSettingConnection *setting);
 
 G_END_DECLS
 
diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c
index e6f0401a..4b73d5fd 100644
--- a/libnm-core/nm-setting-ip-config.c
+++ b/libnm-core/nm-setting-ip-config.c
@@ -53,10 +53,8 @@ canonicalize_ip (int family, const char *ip, gboolean null_any)
 	char addr_str[NM_UTILS_INET_ADDRSTRLEN];
 	int ret;
 
-	if (!ip) {
-		g_return_val_if_fail (null_any == TRUE, NULL);
+	if (!ip)
 		return NULL;
-	}
 
 	ret = inet_pton (family, ip, addr_bytes);
 	g_return_val_if_fail (ret == 1, NULL);
@@ -74,6 +72,11 @@ canonicalize_ip (int family, const char *ip, gboolean null_any)
 static gboolean
 valid_ip (int family, const char *ip, GError **error)
 {
+	if (!ip) {
+		g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
+		             family == AF_INET ? _("Missing IPv4 address") : _("Missing IPv6 address'"));
+		return FALSE;
+	}
 	if (!nm_utils_ipaddr_valid (family, ip)) {
 		g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED,
 		             family == AF_INET ? _("Invalid IPv4 address '%s'") : _("Invalid IPv6 address '%s"),
@@ -2012,7 +2015,7 @@ set_property (GObject *object, guint prop_id,
 		gateway = g_value_get_string (value);
 		g_return_if_fail (!gateway || nm_utils_ipaddr_valid (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), gateway));
 		g_free (priv->gateway);
-		priv->gateway = canonicalize_ip (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), gateway, TRUE);
+		priv->gateway = canonicalize_ip (NM_SETTING_IP_CONFIG_GET_FAMILY (setting), gateway, FALSE);
 		break;
 	case PROP_ROUTES:
 		g_ptr_array_unref (priv->routes);
diff --git a/libnm-core/nm-setting-vlan.c b/libnm-core/nm-setting-vlan.c
index f622ddcb..d904ad52 100644
--- a/libnm-core/nm-setting-vlan.c
+++ b/libnm-core/nm-setting-vlan.c
@@ -742,7 +742,7 @@ nm_setting_vlan_class_init (NMSettingVlanClass *setting_class)
 	 * property: flags
 	 * variable: VLAN_FLAGS, REORDER_HDR
 	 * values: "GVRP", "LOOSE_BINDING" for VLAN_FLAGS; 0 or 1 for REORDER_HDR
-	 * description: Parent interface of the VLAN.
+	 * description: VLAN flags.
 	 * ---end---
 	 */
 	g_object_class_install_property
diff --git a/libnm-core/nm-setting-wired.c b/libnm-core/nm-setting-wired.c
index 2a747940..3d0c5b64 100644
--- a/libnm-core/nm-setting-wired.c
+++ b/libnm-core/nm-setting-wired.c
@@ -30,6 +30,7 @@
 #include "nm-utils.h"
 #include "nm-utils-private.h"
 #include "nm-setting-private.h"
+#include "nm-macros-internal.h"
 
 /**
  * SECTION:nm-setting-wired
@@ -57,6 +58,8 @@ typedef struct {
 	char **s390_subchannels;
 	char *s390_nettype;
 	GHashTable *s390_options;
+	NMSettingWiredWakeOnLan wol;
+	char *wol_password;
 } NMSettingWiredPrivate;
 
 enum {
@@ -72,6 +75,8 @@ enum {
 	PROP_S390_SUBCHANNELS,
 	PROP_S390_NETTYPE,
 	PROP_S390_OPTIONS,
+	PROP_WAKE_ON_LAN,
+	PROP_WAKE_ON_LAN_PASSWORD,
 
 	LAST_PROP
 };
@@ -554,6 +559,43 @@ nm_setting_wired_get_valid_s390_options (NMSettingWired *setting)
 	return valid_s390_opts;
 }
 
+/**
+ * nm_setting_wired_get_wake_on_lan:
+ * @setting: the #NMSettingWired
+ *
+ * Returns the Wake-on-LAN options enabled for the connection
+ *
+ * Returns: the Wake-on-LAN options
+ *
+ * Since: 1.0.6
+ */
+NMSettingWiredWakeOnLan
+nm_setting_wired_get_wake_on_lan (NMSettingWired *setting)
+{
+	g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), NM_SETTING_WIRED_WAKE_ON_LAN_NONE);
+
+	return NM_SETTING_WIRED_GET_PRIVATE (setting)->wol;
+}
+
+/**
+ * nm_setting_wired_get_wake_on_lan_password:
+ * @setting: the #NMSettingWired
+ *
+ * Returns the Wake-on-LAN password. This only applies to
+ * %NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC.
+ *
+ * Returns: the Wake-on-LAN setting password, or %NULL if there is no password.
+ *
+ * Since: 1.0.6
+ */
+const char *
+nm_setting_wired_get_wake_on_lan_password (NMSettingWired *setting)
+{
+	g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), NULL);
+
+	return NM_SETTING_WIRED_GET_PRIVATE (setting)->wol_password;
+}
+
 static gboolean
 verify (NMSetting *setting, NMConnection *connection, GError **error)
 {
@@ -654,6 +696,34 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 		return FALSE;
 	}
 
+	if (   NM_FLAGS_HAS (priv->wol, NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT)
+	    && NM_FLAGS_ANY (priv->wol, NM_SETTING_WIRED_WAKE_ON_LAN_ALL)) {
+		g_set_error_literal (error,
+		                     NM_CONNECTION_ERROR,
+		                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		                     _("Wake-on-LAN mode 'default' is incompatible with other flags"));
+		g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_WAKE_ON_LAN);
+		return FALSE;
+	}
+
+	if (priv->wol_password && !NM_FLAGS_HAS (priv->wol, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)) {
+		g_set_error_literal (error,
+		                     NM_CONNECTION_ERROR,
+		                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		                     _("Wake-on-LAN password can only be used with magic packet mode"));
+		g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD);
+		return FALSE;
+	}
+
+	if (priv->wol_password && !nm_utils_hwaddr_valid (priv->wol_password, ETH_ALEN)) {
+		g_set_error_literal (error,
+		                     NM_CONNECTION_ERROR,
+		                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		                     _("is not a valid MAC address"));
+		g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD);
+		return FALSE;
+	}
+
 	return TRUE;
 }
 
@@ -693,6 +763,8 @@ finalize (GObject *object)
 	if (priv->s390_subchannels)
 		g_strfreev (priv->s390_subchannels);
 
+	g_free (priv->wol_password);
+
 	G_OBJECT_CLASS (nm_setting_wired_parent_class)->finalize (object);
 }
 
@@ -756,6 +828,13 @@ set_property (GObject *object, guint prop_id,
 		g_hash_table_unref (priv->s390_options);
 		priv->s390_options = _nm_utils_copy_strdict (g_value_get_boxed (value));
 		break;
+	case PROP_WAKE_ON_LAN:
+		priv->wol = g_value_get_uint (value);
+		break;
+	case PROP_WAKE_ON_LAN_PASSWORD:
+		g_free (priv->wol_password);
+		priv->wol_password = g_value_dup_string (value);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -803,6 +882,12 @@ get_property (GObject *object, guint prop_id,
 	case PROP_S390_OPTIONS:
 		g_value_take_boxed (value, _nm_utils_copy_strdict (priv->s390_options));
 		break;
+	case PROP_WAKE_ON_LAN:
+		g_value_set_uint (value, priv->wol);
+		break;
+	case PROP_WAKE_ON_LAN_PASSWORD:
+		g_value_set_string (value, priv->wol_password);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -1097,4 +1182,39 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class)
 	                                      G_VARIANT_TYPE ("a{ss}"),
 	                                      _nm_utils_strdict_to_dbus,
 	                                      _nm_utils_strdict_from_dbus);
+
+	/**
+	 * NMSettingWired:wake-on-lan:
+	 *
+	 * The #NMSettingWiredWakeOnLan options to enable. Not all devices support all options.
+	 * May be any combination of %NM_SETTING_WIRED_WAKE_ON_LAN_PHY,
+	 * %NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST, %NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST,
+	 * %NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST, %NM_SETTING_WIRED_WAKE_ON_LAN_ARP,
+	 * %NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC.
+	 *
+	 * Since: 1.0.6
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_WAKE_ON_LAN,
+		 g_param_spec_uint (NM_SETTING_WIRED_WAKE_ON_LAN, "", "",
+		                    0, G_MAXUINT32, NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT,
+		                    G_PARAM_CONSTRUCT |
+		                    G_PARAM_READWRITE |
+		                    G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * NMSettingWired:wake-on-lan-password:
+	 *
+	 * If specified, the password used with magic-packet-based
+	 * Wake-on-LAN, represented as an Ethernet MAC address.  If %NULL,
+	 * no password will be required.
+	 *
+	 * Since: 1.0.6
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_WAKE_ON_LAN_PASSWORD,
+		 g_param_spec_string (NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, "", "",
+		                      NULL,
+		                      G_PARAM_READWRITE |
+		                      G_PARAM_STATIC_STRINGS));
 }
diff --git a/libnm-core/nm-setting-wired.h b/libnm-core/nm-setting-wired.h
index 4189b689..44b7c4d0 100644
--- a/libnm-core/nm-setting-wired.h
+++ b/libnm-core/nm-setting-wired.h
@@ -40,6 +40,36 @@ G_BEGIN_DECLS
 
 #define NM_SETTING_WIRED_SETTING_NAME "802-3-ethernet"
 
+/**
+ * NMSettingWiredWakeOnLan:
+ * @NM_SETTING_WIRED_WAKE_ON_LAN_NONE: Wake-on-LAN disabled
+ * @NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT: Use the default value
+ * @NM_SETTING_WIRED_WAKE_ON_LAN_PHY: Wake on PHY activity
+ * @NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST: Wake on unicast messages
+ * @NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST: Wake on multicast messages
+ * @NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST: Wake on broadcast messages
+ * @NM_SETTING_WIRED_WAKE_ON_LAN_ARP: Wake on ARP
+ * @NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC: Wake on magic packet
+ * @NM_SETTING_WIRED_WAKE_ON_LAN_ALL: Wake on all events
+ *
+ * Options for #NMSettingWired:wake-on-lan. Note that not all options
+ * are supported by all devices.
+ *
+ * Since: 1.0.6
+ */
+typedef enum { /*< flags >*/
+	NM_SETTING_WIRED_WAKE_ON_LAN_NONE      = 0, /*< skip >*/
+	NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT   = (1 << 0),
+	NM_SETTING_WIRED_WAKE_ON_LAN_PHY       = (1 << 1),
+	NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST   = (1 << 2),
+	NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST = (1 << 3),
+	NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST = (1 << 4),
+	NM_SETTING_WIRED_WAKE_ON_LAN_ARP       = (1 << 5),
+	NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC     = (1 << 6),
+	_NM_SETTING_WIRED_WAKE_ON_LAN_LAST,    /*< skip >*/
+	NM_SETTING_WIRED_WAKE_ON_LAN_ALL       = (((_NM_SETTING_WIRED_WAKE_ON_LAN_LAST - 1) << 1) - 1 - NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) /*< skip >*/
+} NMSettingWiredWakeOnLan;
+
 #define NM_SETTING_WIRED_PORT "port"
 #define NM_SETTING_WIRED_SPEED "speed"
 #define NM_SETTING_WIRED_DUPLEX "duplex"
@@ -51,6 +81,8 @@ G_BEGIN_DECLS
 #define NM_SETTING_WIRED_S390_SUBCHANNELS "s390-subchannels"
 #define NM_SETTING_WIRED_S390_NETTYPE "s390-nettype"
 #define NM_SETTING_WIRED_S390_OPTIONS "s390-options"
+#define NM_SETTING_WIRED_WAKE_ON_LAN "wake-on-lan"
+#define NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD "wake-on-lan-password"
 
 struct _NMSettingWired {
 	NMSetting parent;
@@ -104,6 +136,11 @@ gboolean          nm_setting_wired_remove_s390_option   (NMSettingWired *setting
                                                          const char *key);
 const char **     nm_setting_wired_get_valid_s390_options (NMSettingWired *setting);
 
+NM_AVAILABLE_IN_1_0_6
+NMSettingWiredWakeOnLan  nm_setting_wired_get_wake_on_lan          (NMSettingWired *setting);
+NM_AVAILABLE_IN_1_0_6
+const char *             nm_setting_wired_get_wake_on_lan_password (NMSettingWired *setting);
+
 G_END_DECLS
 
 #endif /* __NM_SETTING_WIRED_H__ */
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index 14686ed1..66dd1c87 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -317,6 +317,21 @@ nm_utils_ssid_to_utf8 (const guint8 *ssid, gsize len)
 		                                     "UTF-8", e1, "?", NULL, NULL, NULL);
 	}
 
+	if (!converted) {
+		/* If there is still no converted string, the SSID probably
+		 * contains characters not valid in the current locale. Convert
+		 * the string to ASCII instead.
+		 */
+
+		/* Use the printable range of 0x20-0x7E */
+		gchar *valid_chars = " !\"#$%&'()*+,-./0123456789:;<=>?@"
+		                     "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"
+		                     "abcdefghijklmnopqrstuvwxyz{|}~";
+
+		converted = g_strndup ((const gchar *)ssid, len);
+		g_strcanon (converted, valid_chars, '?');
+	}
+
 	return converted;
 }
 
@@ -2677,6 +2692,61 @@ nm_utils_wifi_is_channel_valid (guint32 channel, const char *band)
 		return FALSE;
 }
 
+static const guint *
+_wifi_freqs (gboolean bg_band)
+{
+	static guint *freqs_2ghz = NULL;
+	static guint *freqs_5ghz = NULL;
+	guint *freqs;
+
+	freqs = bg_band ? freqs_2ghz : freqs_5ghz;
+	if (G_UNLIKELY (freqs == NULL)) {
+		struct cf_pair *table;
+		int i;
+
+		table = bg_band ? bg_table : a_table;
+		freqs = g_new0 (guint, bg_band ? G_N_ELEMENTS (bg_table) : G_N_ELEMENTS (a_table));
+		for (i = 0; table[i].chan; i++)
+			freqs[i] = table[i].freq;
+		freqs[i] = 0;
+		if (bg_band)
+			freqs_2ghz = freqs;
+		else
+			freqs_5ghz = freqs;
+	}
+	return freqs;
+}
+
+/**
+ * nm_utils_wifi_2ghz_freqs:
+ *
+ * Utility function to return 2.4 GHz Wi-Fi frequencies (802.11bg band).
+ *
+ * Returns: zero-terminated array of frequencies numbers (in MHz)
+ *
+ * Since: 1.0.6
+ **/
+const guint *
+nm_utils_wifi_2ghz_freqs (void)
+{
+	return _wifi_freqs (TRUE);
+}
+
+/**
+ * nm_utils_wifi_5ghz_freqs:
+ *
+ * Utility function to return 5 GHz Wi-Fi frequencies (802.11a band).
+ *
+ * Returns: zero-terminated array of frequencies numbers (in MHz)
+ *
+ * Since: 1.0.6
+ **/
+const guint *
+nm_utils_wifi_5ghz_freqs (void)
+{
+	return _wifi_freqs (FALSE);
+}
+
 /**
  * nm_utils_wifi_strength_bars:
  * @strength: the access point strength, from 0 to 100
@@ -3338,6 +3408,9 @@ nm_utils_ipaddr_valid (int family, const char *ip)
 
 	g_return_val_if_fail (family == AF_INET || family == AF_INET6 || family == AF_UNSPEC, FALSE);
 
+	if (!ip)
+		return FALSE;
+
 	if (family == AF_UNSPEC)
 		family = strchr (ip, ':') ? AF_INET6 : AF_INET;
 
@@ -3540,3 +3613,150 @@ _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 ma
 	return v;
 }
 
+/**
+ * _nm_dbus_error_has_name:
+ * @error: (allow-none): a #GError, or %NULL
+ * @dbus_error_name: a D-Bus error name
+ *
+ * Checks if @error is set and corresponds to the D-Bus error @dbus_error_name.
+ *
+ * Returns: %TRUE or %FALSE
+ */
+gboolean
+_nm_dbus_error_has_name (GError     *error,
+                         const char *dbus_error_name)
+{
+	gboolean has_name = FALSE;
+
+	if (error && g_dbus_error_is_remote_error (error)) {
+		char *error_name;
+
+		error_name = g_dbus_error_get_remote_error (error);
+		has_name = !g_strcmp0 (error_name, dbus_error_name);
+		g_free (error_name);
+	}
+
+	return has_name;
+}
+
+/**
+ * nm_utils_enum_to_str:
+ * @type: the %GType of the enum
+ * @value: the value to be translated
+ *
+ * Converts an enum value to its string representation. If the enum is a
+ * %G_TYPE_FLAGS the function returns a comma-separated list of matching values.
+ * If the enum is a %G_TYPE_ENUM and the given value is not valid the
+ * function returns %NULL.
+ *
+ * Returns: a newly allocated string or %NULL
+ *
+ * Since: 1.0.6
+ */
+char *nm_utils_enum_to_str (GType type, int value)
+{
+	GTypeClass *class;
+	char *ret;
+
+	class = g_type_class_ref (type);
+
+	if (G_IS_ENUM_CLASS (class)) {
+		GEnumValue *enum_value;
+
+		enum_value = g_enum_get_value (G_ENUM_CLASS (class), value);
+		ret = enum_value ? strdup (enum_value->value_nick) : NULL;
+	} else if (G_IS_FLAGS_CLASS (class)) {
+		GFlagsValue *flags_value;
+		GString *str = g_string_new ("");
+		gboolean first = TRUE;
+
+		while (value) {
+			flags_value = g_flags_get_first_value (G_FLAGS_CLASS (class), value);
+			if (!flags_value)
+				break;
+
+			if (!first)
+				g_string_append_c (str, ',');
+			g_string_append (str, flags_value->value_nick);
+
+			value &= ~flags_value->value;
+			first = FALSE;
+		}
+		ret = g_string_free (str, FALSE);
+	} else
+		g_return_val_if_reached (NULL);
+
+	g_type_class_unref (class);
+	return ret;
+}
+
+/**
+ * nm_utils_enum_from_str:
+ * @type: the %GType of the enum
+ * @str: the input string
+ * @out_value: (out) (allow-none) the output value
+ * @err_token: (out) (allow-none) location to store the first unrecognized token
+ *
+ * Converts a string to the matching enum value.
+ *
+ * If the enum is a %G_TYPE_FLAGS the function returns the logical OR of values
+ * matching the comma-separated tokens in the string; if an unknown token is found
+ * the function returns %FALSE and stores a pointer to a newly allocated string
+ * containing the unrecognized token in @err_token.
+ *
+ * Returns: %TRUE if the conversion was successful, %FALSE otherwise
+ *
+ * Since: 1.0.6
+ */
+gboolean nm_utils_enum_from_str (GType type, const char *str,
+                                 int *out_value, char **err_token)
+{
+	GTypeClass *class;
+	gboolean ret = FALSE;
+	int value = 0;
+	gs_free char *stripped = NULL;
+
+	g_return_val_if_fail (str, FALSE);
+	stripped = g_strstrip (strdup (str));
+	class = g_type_class_ref (type);
+
+	if (G_IS_ENUM_CLASS (class)) {
+		GEnumValue *enum_value;
+
+		enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (class), stripped);
+		if (enum_value) {
+			value = enum_value->value;
+			ret = TRUE;
+		}
+	} else if (G_IS_FLAGS_CLASS (class)) {
+		GFlagsValue *flags_value;
+		gs_strfreev char **strv = NULL;
+		int i;
+
+		strv = g_strsplit (stripped, ",", 0);
+		for (i = 0; strv[i]; i++) {
+			if (!strv[i][0])
+				continue;
+
+			flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (class), strv[i]);
+			if (!flags_value)
+				break;
+
+			value |= flags_value->value;
+		}
+
+		if (strv[i]) {
+			if (err_token)
+				*err_token = strdup (strv[i]);
+			value = 0;
+		} else
+			ret = TRUE;
+	} else
+		g_return_val_if_reached (FALSE);
+
+	if (out_value)
+		*out_value = value;
+
+	g_type_class_unref (class);
+	return ret;
+}
diff --git a/libnm-core/nm-utils.h b/libnm-core/nm-utils.h
index 8c22cfd1..d1f4bcf4 100644
--- a/libnm-core/nm-utils.h
+++ b/libnm-core/nm-utils.h
@@ -140,6 +140,10 @@ guint32 nm_utils_wifi_freq_to_channel (guint32 freq);
 guint32 nm_utils_wifi_channel_to_freq (guint32 channel, const char *band);
 guint32 nm_utils_wifi_find_next_channel (guint32 channel, int direction, char *band);
 gboolean nm_utils_wifi_is_channel_valid (guint32 channel, const char *band);
+NM_AVAILABLE_IN_1_0_6
+const guint *nm_utils_wifi_2ghz_freqs (void);
+NM_AVAILABLE_IN_1_0_6
+const guint *nm_utils_wifi_5ghz_freqs (void);
 
 const char *nm_utils_wifi_strength_bars (guint8 strength);
 
@@ -185,6 +189,12 @@ gboolean nm_utils_ipaddr_valid (int family, const char *ip);
 
 gboolean nm_utils_check_virtual_device_compatibility (GType virtual_type, GType other_type);
 
+NM_AVAILABLE_IN_1_0_6
+char *nm_utils_enum_to_str (GType type, int value);
+
+NM_AVAILABLE_IN_1_0_6
+gboolean nm_utils_enum_from_str (GType type, const char *str, int *out_value, char **err_token);
+
 G_END_DECLS
 
 #endif /* __NM_UTILS_H__ */
diff --git a/libnm-core/nm-version.h b/libnm-core/nm-version.h
index e36d921e..e26feca6 100644
--- a/libnm-core/nm-version.h
+++ b/libnm-core/nm-version.h
@@ -21,6 +21,8 @@
 #ifndef NM_VERSION_H
 #define NM_VERSION_H
 
+#include <glib.h>
+
 /**
  * NM_MAJOR_VERSION:
  *
@@ -43,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 (6)
 
 /**
  * NM_CHECK_VERSION:
@@ -69,9 +71,11 @@
 #define NM_VERSION_1_0    (NM_ENCODE_VERSION (1, 0, 0))
 #define NM_VERSION_1_0_2  (NM_ENCODE_VERSION (1, 0, 2))
 #define NM_VERSION_1_0_4  (NM_ENCODE_VERSION (1, 0, 4))
+#define NM_VERSION_1_0_6  (NM_ENCODE_VERSION (1, 0, 6))
+#define NM_VERSION_1_0_8  (NM_ENCODE_VERSION (1, 0, 8))
 
-#define NM_VERSION_CUR_STABLE  NM_VERSION_1_0_2
-#define NM_VERSION_NEXT_STABLE NM_VERSION_1_0_4
+#define NM_VERSION_CUR_STABLE  NM_VERSION_1_0_6
+#define NM_VERSION_NEXT_STABLE NM_VERSION_1_0_8
 
 #if !defined (NM_VERSION_MIN_REQUIRED) || (NM_VERSION_MIN_REQUIRED == 0)
 # undef NM_VERSION_MIN_REQUIRED
@@ -102,6 +106,12 @@
 # define NM_DEPRECATED_IN_0_9_10_FOR(f)
 #endif
 
+#if NM_VERSION_MAX_ALLOWED < NM_VERSION_0_9_10
+# define NM_AVAILABLE_IN_0_9_10         G_UNAVAILABLE(0.9,10)
+#else
+# define NM_AVAILABLE_IN_0_9_10
+#endif
+
 #if NM_VERSION_MIN_REQUIRED >= NM_VERSION_1_0
 # define NM_DEPRECATED_IN_1_0           G_DEPRECATED
 # define NM_DEPRECATED_IN_1_0_FOR(f)    G_DEPRECATED_FOR(f)
@@ -110,12 +120,6 @@
 # define NM_DEPRECATED_IN_1_0_FOR(f)
 #endif
 
-#if NM_VERSION_MAX_ALLOWED < NM_VERSION_0_9_10
-# define NM_AVAILABLE_IN_0_9_10         G_UNAVAILABLE(0.9,10)
-#else
-# define NM_AVAILABLE_IN_0_9_10
-#endif
-
 #if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_0
 # define NM_AVAILABLE_IN_1_0            G_UNAVAILABLE(1,0)
 #else
@@ -128,4 +132,10 @@
 # define NM_AVAILABLE_IN_1_0_4
 #endif
 
+#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_0_6
+# define NM_AVAILABLE_IN_1_0_6          G_UNAVAILABLE(1,0.6)
+#else
+# define NM_AVAILABLE_IN_1_0_6
+#endif
+
 #endif  /* NM_VERSION_H */
diff --git a/libnm-core/nm-version.h.in b/libnm-core/nm-version.h.in
index 9c9219e1..e00f4055 100644
--- a/libnm-core/nm-version.h.in
+++ b/libnm-core/nm-version.h.in
@@ -21,6 +21,8 @@
 #ifndef NM_VERSION_H
 #define NM_VERSION_H
 
+#include <glib.h>
+
 /**
  * NM_MAJOR_VERSION:
  *
@@ -69,9 +71,11 @@
 #define NM_VERSION_1_0    (NM_ENCODE_VERSION (1, 0, 0))
 #define NM_VERSION_1_0_2  (NM_ENCODE_VERSION (1, 0, 2))
 #define NM_VERSION_1_0_4  (NM_ENCODE_VERSION (1, 0, 4))
+#define NM_VERSION_1_0_6  (NM_ENCODE_VERSION (1, 0, 6))
+#define NM_VERSION_1_0_8  (NM_ENCODE_VERSION (1, 0, 8))
 
-#define NM_VERSION_CUR_STABLE  NM_VERSION_1_0_2
-#define NM_VERSION_NEXT_STABLE NM_VERSION_1_0_4
+#define NM_VERSION_CUR_STABLE  NM_VERSION_1_0_6
+#define NM_VERSION_NEXT_STABLE NM_VERSION_1_0_8
 
 #if !defined (NM_VERSION_MIN_REQUIRED) || (NM_VERSION_MIN_REQUIRED == 0)
 # undef NM_VERSION_MIN_REQUIRED
@@ -102,6 +106,12 @@
 # define NM_DEPRECATED_IN_0_9_10_FOR(f)
 #endif
 
+#if NM_VERSION_MAX_ALLOWED < NM_VERSION_0_9_10
+# define NM_AVAILABLE_IN_0_9_10         G_UNAVAILABLE(0.9,10)
+#else
+# define NM_AVAILABLE_IN_0_9_10
+#endif
+
 #if NM_VERSION_MIN_REQUIRED >= NM_VERSION_1_0
 # define NM_DEPRECATED_IN_1_0           G_DEPRECATED
 # define NM_DEPRECATED_IN_1_0_FOR(f)    G_DEPRECATED_FOR(f)
@@ -110,12 +120,6 @@
 # define NM_DEPRECATED_IN_1_0_FOR(f)
 #endif
 
-#if NM_VERSION_MAX_ALLOWED < NM_VERSION_0_9_10
-# define NM_AVAILABLE_IN_0_9_10         G_UNAVAILABLE(0.9,10)
-#else
-# define NM_AVAILABLE_IN_0_9_10
-#endif
-
 #if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_0
 # define NM_AVAILABLE_IN_1_0            G_UNAVAILABLE(1,0)
 #else
@@ -128,4 +132,10 @@
 # define NM_AVAILABLE_IN_1_0_4
 #endif
 
+#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_0_6
+# define NM_AVAILABLE_IN_1_0_6          G_UNAVAILABLE(1,0.6)
+#else
+# define NM_AVAILABLE_IN_1_0_6
+#endif
+
 #endif  /* NM_VERSION_H */
diff --git a/libnm-core/tests/Makefile.am b/libnm-core/tests/Makefile.am
index daa5825b..dd38b3d6 100644
--- a/libnm-core/tests/Makefile.am
+++ b/libnm-core/tests/Makefile.am
@@ -1,5 +1,14 @@
 if ENABLE_TESTS
 
+include $(GLIB_MAKEFILE)
+
+GLIB_GENERATED = nm-core-tests-enum-types.h nm-core-tests-enum-types.c
+nm_core_tests_enum_types_sources = test-general-enums.h
+GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM
+GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM
+
+BUILT_SOURCES = $(GLIB_GENERATED)
+
 certsdir = $(srcdir)/certs
 
 AM_CPPFLAGS = \
@@ -28,6 +37,12 @@ LDADD = \
 @VALGRIND_RULES@
 TESTS = $(noinst_PROGRAMS)
 
+test_general_SOURCES = \
+	test-general.c \
+	test-general-enums.h \
+	nm-core-tests-enum-types.c \
+	nm-core-tests-enum-types.h
+
 endif
 
 # test-cert.p12 created with:
diff --git a/libnm-core/tests/Makefile.in b/libnm-core/tests/Makefile.in
index edb6a50e..a37acbe2 100644
--- a/libnm-core/tests/Makefile.in
+++ b/libnm-core/tests/Makefile.in
@@ -134,8 +134,11 @@ test_crypto_LDADD = $(LDADD)
 @ENABLE_TESTS_TRUE@test_crypto_DEPENDENCIES =  \
 @ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-core/libnm-core.la \
 @ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1)
-test_general_SOURCES = test-general.c
-test_general_OBJECTS = test-general.$(OBJEXT)
+am__test_general_SOURCES_DIST = test-general.c test-general-enums.h \
+	nm-core-tests-enum-types.c nm-core-tests-enum-types.h
+@ENABLE_TESTS_TRUE@am_test_general_OBJECTS = test-general.$(OBJEXT) \
+@ENABLE_TESTS_TRUE@	nm-core-tests-enum-types.$(OBJEXT)
+test_general_OBJECTS = $(am_test_general_OBJECTS)
 test_general_LDADD = $(LDADD)
 @ENABLE_TESTS_TRUE@test_general_DEPENDENCIES =  \
 @ENABLE_TESTS_TRUE@	$(top_builddir)/libnm-core/libnm-core.la \
@@ -204,12 +207,13 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = test-compare.c test-crypto.c test-general.c test-keyfile.c \
-	test-secrets.c test-setting-8021x.c test-setting-dcb.c \
-	test-settings-defaults.c
-DIST_SOURCES = test-compare.c test-crypto.c test-general.c \
+SOURCES = test-compare.c test-crypto.c $(test_general_SOURCES) \
 	test-keyfile.c test-secrets.c test-setting-8021x.c \
 	test-setting-dcb.c test-settings-defaults.c
+DIST_SOURCES = test-compare.c test-crypto.c \
+	$(am__test_general_SOURCES_DIST) test-keyfile.c test-secrets.c \
+	test-setting-8021x.c test-setting-dcb.c \
+	test-settings-defaults.c
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -703,6 +707,11 @@ with_dhcpcd = @with_dhcpcd@
 with_netconfig = @with_netconfig@
 with_resolvconf = @with_resolvconf@
 with_valgrind = @with_valgrind@
+@ENABLE_TESTS_TRUE@GLIB_GENERATED = nm-core-tests-enum-types.h nm-core-tests-enum-types.c
+@ENABLE_TESTS_TRUE@nm_core_tests_enum_types_sources = test-general-enums.h
+@ENABLE_TESTS_TRUE@GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM
+@ENABLE_TESTS_TRUE@GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM
+@ENABLE_TESTS_TRUE@BUILT_SOURCES = $(GLIB_GENERATED)
 @ENABLE_TESTS_TRUE@certsdir = $(srcdir)/certs
 @ENABLE_TESTS_TRUE@AM_CPPFLAGS = \
 @ENABLE_TESTS_TRUE@	-I${top_srcdir}/include \
@@ -718,6 +727,12 @@ with_valgrind = @with_valgrind@
 @ENABLE_TESTS_TRUE@	$(GLIB_LIBS)
 
 @ENABLE_TESTS_TRUE@TESTS = $(noinst_PROGRAMS)
+@ENABLE_TESTS_TRUE@test_general_SOURCES = \
+@ENABLE_TESTS_TRUE@	test-general.c \
+@ENABLE_TESTS_TRUE@	test-general-enums.h \
+@ENABLE_TESTS_TRUE@	nm-core-tests-enum-types.c \
+@ENABLE_TESTS_TRUE@	nm-core-tests-enum-types.h
+
 
 # test-cert.p12 created with:
 #
@@ -746,7 +761,8 @@ EXTRA_DIST = \
 	certs/test-key-only-decrypted.pem   \
 	certs/test-key-only.pem
 
-all: all-am
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
 
 .SUFFIXES:
 .SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
@@ -827,6 +843,7 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-core-tests-enum-types.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-compare.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-crypto.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-general.Po@am__quote@
@@ -1159,10 +1176,12 @@ distdir: $(DISTFILES)
 	done
 check-am: all-am
 	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
-check: check-am
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
 all-am: Makefile $(PROGRAMS)
 installdirs:
-install: install-am
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
 install-exec: install-exec-am
 install-data: install-data-am
 uninstall: uninstall-am
@@ -1195,6 +1214,7 @@ distclean-generic:
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
 	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
 clean: clean-am
 
 clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
@@ -1266,7 +1286,7 @@ ps-am:
 
 uninstall-am:
 
-.MAKE: check-am install-am install-strip
+.MAKE: all check check-am install install-am install-strip
 
 .PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \
 	clean-generic clean-libtool clean-noinstPROGRAMS cscopelist-am \
@@ -1285,6 +1305,8 @@ uninstall-am:
 .PRECIOUS: Makefile
 
 
+@ENABLE_TESTS_TRUE@include $(GLIB_MAKEFILE)
+
 @ENABLE_TESTS_TRUE@@VALGRIND_RULES@
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/libnm-core/tests/nm-core-tests-enum-types.c b/libnm-core/tests/nm-core-tests-enum-types.c
new file mode 100644
index 00000000..80271e52
--- /dev/null
+++ b/libnm-core/tests/nm-core-tests-enum-types.c
@@ -0,0 +1,74 @@
+
+
+
+/* Generated by glib-mkenums. Do not edit */
+
+#include "nm-core-tests-enum-types.h"
+
+#include "test-general-enums.h"
+
+GType
+nm_test_general_bool_enum_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { NM_TEST_GENERAL_BOOL_ENUM_NO, "NM_TEST_GENERAL_BOOL_ENUM_NO", "no" },
+        { NM_TEST_GENERAL_BOOL_ENUM_YES, "NM_TEST_GENERAL_BOOL_ENUM_YES", "yes" },
+        { NM_TEST_GENERAL_BOOL_ENUM_MAYBE, "NM_TEST_GENERAL_BOOL_ENUM_MAYBE", "maybe" },
+        { NM_TEST_GENERAL_BOOL_ENUM_UNKNOWN, "NM_TEST_GENERAL_BOOL_ENUM_UNKNOWN", "unknown" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("NMTestGeneralBoolEnum"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_test_general_meta_flags_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GFlagsValue values[] = {
+        { NM_TEST_GENERAL_META_FLAGS_NONE, "NM_TEST_GENERAL_META_FLAGS_NONE", "none" },
+        { NM_TEST_GENERAL_META_FLAGS_FOO, "NM_TEST_GENERAL_META_FLAGS_FOO", "foo" },
+        { NM_TEST_GENERAL_META_FLAGS_BAR, "NM_TEST_GENERAL_META_FLAGS_BAR", "bar" },
+        { NM_TEST_GENERAL_META_FLAGS_BAZ, "NM_TEST_GENERAL_META_FLAGS_BAZ", "baz" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_flags_register_static (g_intern_static_string ("NMTestGeneralMetaFlags"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+GType
+nm_test_general_color_flags_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GFlagsValue values[] = {
+        { NM_TEST_GENERAL_COLOR_FLAGS_BLUE, "NM_TEST_GENERAL_COLOR_FLAGS_BLUE", "blue" },
+        { NM_TEST_GENERAL_COLOR_FLAGS_RED, "NM_TEST_GENERAL_COLOR_FLAGS_RED", "red" },
+        { NM_TEST_GENERAL_COLOR_FLAGS_GREEN, "NM_TEST_GENERAL_COLOR_FLAGS_GREEN", "green" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_flags_register_static (g_intern_static_string ("NMTestGeneralColorFlags"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+
+
+
diff --git a/libnm-core/tests/nm-core-tests-enum-types.h b/libnm-core/tests/nm-core-tests-enum-types.h
new file mode 100644
index 00000000..90257866
--- /dev/null
+++ b/libnm-core/tests/nm-core-tests-enum-types.h
@@ -0,0 +1,23 @@
+
+
+
+/* Generated by glib-mkenums. Do not edit */
+
+#ifndef __NM_CORE_TESTS_ENUM_TYPES_H__
+#define __NM_CORE_TESTS_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+GType nm_test_general_bool_enum_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_TEST_GENERAL_BOOL_ENUM (nm_test_general_bool_enum_get_type ())
+GType nm_test_general_meta_flags_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_TEST_GENERAL_META_FLAGS (nm_test_general_meta_flags_get_type ())
+GType nm_test_general_color_flags_get_type (void) G_GNUC_CONST;
+#define NM_TYPE_TEST_GENERAL_COLOR_FLAGS (nm_test_general_color_flags_get_type ())
+G_END_DECLS
+
+#endif /* __NM_CORE_TESTS_ENUM_TYPES_H__ */
+
+
+
diff --git a/libnm-core/tests/test-general-enums.h b/libnm-core/tests/test-general-enums.h
new file mode 100644
index 00000000..d06d6e39
--- /dev/null
+++ b/libnm-core/tests/test-general-enums.h
@@ -0,0 +1,46 @@
+/* -*- 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 2015 Red Hat, Inc.
+ */
+
+#ifndef _NM_TEST_GENERAL_ENUMS_H_
+#define _NM_TEST_GENERAL_ENUMS_H_
+
+typedef enum {
+	NM_TEST_GENERAL_BOOL_ENUM_NO       = 0,
+	NM_TEST_GENERAL_BOOL_ENUM_YES      = 1,
+	NM_TEST_GENERAL_BOOL_ENUM_MAYBE    = 2,
+	NM_TEST_GENERAL_BOOL_ENUM_UNKNOWN  = 3,
+	NM_TEST_GENERAL_BOOL_ENUM_INVALID  = 4, /*< skip >*/
+} NMTestGeneralBoolEnum;
+
+typedef enum {
+	NM_TEST_GENERAL_META_FLAGS_NONE    = 0,
+	NM_TEST_GENERAL_META_FLAGS_FOO     = (1 << 0),
+	NM_TEST_GENERAL_META_FLAGS_BAR     = (1 << 1),
+	NM_TEST_GENERAL_META_FLAGS_BAZ     = (1 << 2),
+} NMTestGeneralMetaFlags;
+
+typedef enum {  /*< flags >*/
+	NM_TEST_GENERAL_COLOR_FLAGS_WHITE  = 1, /*< skip >*/
+	NM_TEST_GENERAL_COLOR_FLAGS_BLUE   = 2,
+	NM_TEST_GENERAL_COLOR_FLAGS_RED    = 4,
+	NM_TEST_GENERAL_COLOR_FLAGS_GREEN  = 8,
+} NMTestGeneralColorFlags;
+
+#endif /* _NM_TEST_GENERAL_ENUMS_H_ */
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index bd144f38..e9483652 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -32,6 +32,7 @@
 #include "nm-setting-private.h"
 #include "nm-utils.h"
 #include "nm-core-internal.h"
+#include "nm-core-tests-enum-types.h"
 
 #include "nm-setting-8021x.h"
 #include "nm-setting-adsl.h"
@@ -62,6 +63,7 @@
 #include "nm-glib-compat.h"
 
 #include "nm-test-utils.h"
+#include "test-general-enums.h"
 
 static void
 vpn_check_func (const char *key, const char *value, gpointer user_data)
@@ -1969,6 +1971,7 @@ test_connection_diff_a_only (void)
 			{ NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES,   NM_SETTING_DIFF_RESULT_IN_A },
 			{ NM_SETTING_CONNECTION_SECONDARIES,          NM_SETTING_DIFF_RESULT_IN_A },
 			{ NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_CONNECTION_METERED,              NM_SETTING_DIFF_RESULT_IN_A },
 			{ NULL, NM_SETTING_DIFF_RESULT_UNKNOWN }
 		} },
 		{ NM_SETTING_WIRED_SETTING_NAME, {
@@ -1983,6 +1986,8 @@ test_connection_diff_a_only (void)
 			{ NM_SETTING_WIRED_S390_SUBCHANNELS,      NM_SETTING_DIFF_RESULT_IN_A },
 			{ NM_SETTING_WIRED_S390_NETTYPE,          NM_SETTING_DIFF_RESULT_IN_A },
 			{ NM_SETTING_WIRED_S390_OPTIONS,          NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_WIRED_WAKE_ON_LAN,           NM_SETTING_DIFF_RESULT_IN_A },
+			{ NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD,  NM_SETTING_DIFF_RESULT_IN_A },
 			{ NULL, NM_SETTING_DIFF_RESULT_UNKNOWN },
 		} },
 		{ NM_SETTING_IP4_CONFIG_SETTING_NAME, {
@@ -4448,6 +4453,166 @@ test_nm_utils_ptrarray_find_binary_search (void)
 
 /******************************************************************************/
 
+static int
+_test_nm_in_set_get (int *call_counter, gboolean allow_called, int value)
+{
+	g_assert (call_counter);
+	*call_counter += 1;
+	if (!allow_called)
+		g_assert_not_reached ();
+	return value;
+}
+
+static void
+_test_nm_in_set_assert (int *call_counter, int expected)
+{
+	g_assert (call_counter);
+	g_assert_cmpint (expected, ==, *call_counter);
+	*call_counter = 0;
+}
+
+static void
+test_nm_in_set (void)
+{
+	int call_counter = 0;
+
+#define G(x) _test_nm_in_set_get (&call_counter, TRUE,  x)
+#define N(x) _test_nm_in_set_get (&call_counter, FALSE,  x)
+#define _ASSERT(expected, expr) \
+	G_STMT_START { \
+		_test_nm_in_set_assert (&call_counter, 0); \
+		g_assert (expr); \
+		_test_nm_in_set_assert (&call_counter, (expected)); \
+	} G_STMT_END
+	_ASSERT (1, !NM_IN_SET (-1, G( 1)));
+	_ASSERT (1,  NM_IN_SET (-1, G(-1)));
+
+	_ASSERT (2, !NM_IN_SET (-1, G( 1), G( 2)));
+	_ASSERT (1,  NM_IN_SET (-1, G(-1), N( 2)));
+	_ASSERT (2,  NM_IN_SET (-1, G( 1), G(-1)));
+	_ASSERT (1,  NM_IN_SET (-1, G(-1), N(-1)));
+
+	_ASSERT (3, !NM_IN_SET (-1, G( 1), G( 2), G( 3)));
+	_ASSERT (1,  NM_IN_SET (-1, G(-1), N( 2), N( 3)));
+	_ASSERT (2,  NM_IN_SET (-1, G( 1), G(-1), N( 3)));
+	_ASSERT (3,  NM_IN_SET (-1, G( 1), G( 2), G(-1)));
+	_ASSERT (2,  NM_IN_SET (-1, G( 1), G(-1), N(-1)));
+	_ASSERT (1,  NM_IN_SET (-1, G(-1), N( 2), N(-1)));
+	_ASSERT (1,  NM_IN_SET (-1, G(-1), N(-1), N( 3)));
+	_ASSERT (1,  NM_IN_SET (-1, G(-1), N(-1), N(-1)));
+
+	_ASSERT (4, !NM_IN_SET (-1, G( 1), G( 2), G( 3), G( 4)));
+	_ASSERT (1,  NM_IN_SET (-1, G(-1), N( 2), N( 3), N( 4)));
+	_ASSERT (2,  NM_IN_SET (-1, G( 1), G(-1), N( 3), N( 4)));
+	_ASSERT (3,  NM_IN_SET (-1, G( 1), G( 2), G(-1), N( 4)));
+	_ASSERT (4,  NM_IN_SET (-1, G( 1), G( 2), G( 3), G(-1)));
+
+	_ASSERT (4,  NM_IN_SET (-1, G( 1), G( 2), G( 3), G(-1), G( 5)));
+
+	_ASSERT (1, !NM_IN_SET_SE (-1, G( 1)));
+	_ASSERT (1,  NM_IN_SET_SE (-1, G(-1)));
+
+	_ASSERT (2, !NM_IN_SET_SE (-1, G( 1), G( 2)));
+	_ASSERT (2,  NM_IN_SET_SE (-1, G(-1), G( 2)));
+	_ASSERT (2,  NM_IN_SET_SE (-1, G( 1), G(-1)));
+	_ASSERT (2,  NM_IN_SET_SE (-1, G(-1), G(-1)));
+
+	_ASSERT (3, !NM_IN_SET_SE (-1, G( 1), G( 2), G( 3)));
+	_ASSERT (3,  NM_IN_SET_SE (-1, G(-1), G( 2), G( 3)));
+	_ASSERT (3,  NM_IN_SET_SE (-1, G( 1), G(-1), G( 3)));
+	_ASSERT (3,  NM_IN_SET_SE (-1, G( 1), G( 2), G(-1)));
+	_ASSERT (3,  NM_IN_SET_SE (-1, G( 1), G(-1), G(-1)));
+	_ASSERT (3,  NM_IN_SET_SE (-1, G(-1), G( 2), G(-1)));
+	_ASSERT (3,  NM_IN_SET_SE (-1, G(-1), G(-1), G( 3)));
+	_ASSERT (3,  NM_IN_SET_SE (-1, G(-1), G(-1), G(-1)));
+
+	_ASSERT (4, !NM_IN_SET_SE (-1, G( 1), G( 2), G( 3), G( 4)));
+	_ASSERT (4,  NM_IN_SET_SE (-1, G(-1), G( 2), G( 3), G( 4)));
+	_ASSERT (4,  NM_IN_SET_SE (-1, G( 1), G(-1), G( 3), G( 4)));
+	_ASSERT (4,  NM_IN_SET_SE (-1, G( 1), G( 2), G(-1), G( 4)));
+	_ASSERT (4,  NM_IN_SET_SE (-1, G( 1), G( 2), G( 3), G(-1)));
+
+	_ASSERT (5,  NM_IN_SET_SE (-1, G( 1), G( 2), G( 3), G(-1), G( 5)));
+#undef G
+#undef N
+#undef _ASSERT
+}
+
+/******************************************************************************/
+
+static void
+test_nm_utils_enum_from_str_do (GType type, const char *str,
+                                gboolean exp_result, int exp_flags,
+                                const char *exp_err_token)
+{
+	int flags = 1;
+	char *err_token = NULL;
+	gboolean result;
+
+	result = nm_utils_enum_from_str (type, str, &flags, &err_token);
+
+	g_assert (result == exp_result);
+	g_assert_cmpint (flags, ==, exp_flags);
+	g_assert_cmpstr (err_token, ==, exp_err_token);
+
+	g_free (err_token);
+}
+
+static void
+test_nm_utils_enum_to_str_do (GType type, int flags, const char *exp_str)
+{
+	char *str;
+
+	str = nm_utils_enum_to_str (type, flags);
+	g_assert_cmpstr (str, ==, exp_str);
+	g_free (str);
+}
+
+static void test_nm_utils_enum (void)
+{
+	GType bool_enum = nm_test_general_bool_enum_get_type();
+	GType meta_flags = nm_test_general_meta_flags_get_type();
+	GType color_flags = nm_test_general_color_flags_get_type();
+
+	test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_YES, "yes");
+	test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_UNKNOWN, "unknown");
+	test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_INVALID, NULL);
+
+	test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_NONE, "");
+	test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_BAZ, "baz");
+	test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_FOO |
+	                                          NM_TEST_GENERAL_META_FLAGS_BAR |
+	                                          NM_TEST_GENERAL_META_FLAGS_BAZ, "foo,bar,baz");
+
+	test_nm_utils_enum_to_str_do (color_flags, NM_TEST_GENERAL_COLOR_FLAGS_RED, "red");
+	test_nm_utils_enum_to_str_do (color_flags, NM_TEST_GENERAL_COLOR_FLAGS_WHITE, "");
+	test_nm_utils_enum_to_str_do (color_flags, NM_TEST_GENERAL_COLOR_FLAGS_RED |
+	                                           NM_TEST_GENERAL_COLOR_FLAGS_GREEN, "red,green");
+
+	test_nm_utils_enum_from_str_do (bool_enum, "", FALSE, 0, NULL);
+	test_nm_utils_enum_from_str_do (bool_enum, " ", FALSE, 0, NULL);
+	test_nm_utils_enum_from_str_do (bool_enum, "invalid", FALSE, 0, NULL);
+	test_nm_utils_enum_from_str_do (bool_enum, "yes", TRUE, NM_TEST_GENERAL_BOOL_ENUM_YES, NULL);
+	test_nm_utils_enum_from_str_do (bool_enum, "no", TRUE, NM_TEST_GENERAL_BOOL_ENUM_NO, NULL);
+	test_nm_utils_enum_from_str_do (bool_enum, "yes,no", FALSE, 0, NULL);
+
+	test_nm_utils_enum_from_str_do (meta_flags, "", TRUE, 0, NULL);
+	test_nm_utils_enum_from_str_do (meta_flags, " ", TRUE, 0, NULL);
+	test_nm_utils_enum_from_str_do (meta_flags, "foo", TRUE, NM_TEST_GENERAL_META_FLAGS_FOO, NULL);
+	test_nm_utils_enum_from_str_do (meta_flags, "foo,baz", TRUE, NM_TEST_GENERAL_META_FLAGS_FOO |
+	                                                             NM_TEST_GENERAL_META_FLAGS_BAZ, NULL);
+	test_nm_utils_enum_from_str_do (meta_flags, "foo,,bar", TRUE, NM_TEST_GENERAL_META_FLAGS_FOO |
+	                                                              NM_TEST_GENERAL_META_FLAGS_BAR, NULL);
+	test_nm_utils_enum_from_str_do (meta_flags, "foo,baz,quux,bar", FALSE, 0, "quux");
+
+	test_nm_utils_enum_from_str_do (color_flags, "green", TRUE, NM_TEST_GENERAL_COLOR_FLAGS_GREEN, NULL);
+	test_nm_utils_enum_from_str_do (color_flags, "blue,red", TRUE, NM_TEST_GENERAL_COLOR_FLAGS_BLUE |
+	                                                               NM_TEST_GENERAL_COLOR_FLAGS_RED, NULL);
+	test_nm_utils_enum_from_str_do (color_flags, "blue,white", FALSE, 0, "white");
+}
+
+/******************************************************************************/
+
 NMTST_DEFINE ();
 
 int main (int argc, char **argv)
@@ -4455,6 +4620,7 @@ int main (int argc, char **argv)
 	nmtst_init (&argc, &argv, TRUE);
 
 	/* The tests */
+	g_test_add_func ("/core/general/test_nm_in_set", test_nm_in_set);
 	g_test_add_func ("/core/general/test_setting_vpn_items", test_setting_vpn_items);
 	g_test_add_func ("/core/general/test_setting_vpn_update_secrets", test_setting_vpn_update_secrets);
 	g_test_add_func ("/core/general/test_setting_vpn_modify_during_foreach", test_setting_vpn_modify_during_foreach);
@@ -4552,6 +4718,8 @@ int main (int argc, char **argv)
 	g_test_add_func ("/core/general/_glib_compat_g_ptr_array_insert", test_g_ptr_array_insert);
 	g_test_add_func ("/core/general/_nm_utils_ptrarray_find_binary_search", test_nm_utils_ptrarray_find_binary_search);
 
+	g_test_add_func ("/core/general/test_nm_utils_enum", test_nm_utils_enum);
+
 	return g_test_run ();
 }