about summary refs log tree commit diff
path: root/src/settings/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/settings/plugins')
-rw-r--r--src/settings/plugins/ibft/meson.build48
-rw-r--r--src/settings/plugins/ibft/tests/meson.build22
-rw-r--r--src/settings/plugins/ibft/tests/test-ibft.c2
-rw-r--r--src/settings/plugins/ifcfg-rh/meson.build77
-rw-r--r--src/settings/plugins/ifcfg-rh/nm-inotify-helper.c2
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c134
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c162
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c66
-rw-r--r--src/settings/plugins/ifcfg-rh/shvar.c4
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/meson.build22
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected1
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected2
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc16
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write.cexpected16
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-12
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-22
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-32
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-42
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c195
-rw-r--r--src/settings/plugins/ifnet/nms-ifnet-connection-parser.c2912
-rw-r--r--src/settings/plugins/ifnet/nms-ifnet-connection-parser.h55
-rw-r--r--src/settings/plugins/ifnet/nms-ifnet-connection.c233
-rw-r--r--src/settings/plugins/ifnet/nms-ifnet-connection.h46
-rw-r--r--src/settings/plugins/ifnet/nms-ifnet-net-parser.c734
-rw-r--r--src/settings/plugins/ifnet/nms-ifnet-net-parser.h42
-rw-r--r--src/settings/plugins/ifnet/nms-ifnet-net-utils.c830
-rw-r--r--src/settings/plugins/ifnet/nms-ifnet-net-utils.h71
-rw-r--r--src/settings/plugins/ifnet/nms-ifnet-plugin.c524
-rw-r--r--src/settings/plugins/ifnet/nms-ifnet-plugin.h38
-rw-r--r--src/settings/plugins/ifnet/nms-ifnet-wpa-parser.c584
-rw-r--r--src/settings/plugins/ifnet/nms-ifnet-wpa-parser.h41
-rw-r--r--src/settings/plugins/ifnet/tests/net158
-rw-r--r--src/settings/plugins/ifnet/tests/net.all864
-rw-r--r--src/settings/plugins/ifnet/tests/nm-system-settings.conf5
-rw-r--r--src/settings/plugins/ifnet/tests/test-ifnet.c396
-rw-r--r--src/settings/plugins/ifnet/tests/test_ca_cert.pem27
-rw-r--r--src/settings/plugins/ifnet/tests/wpa_supplicant.conf70
-rw-r--r--src/settings/plugins/ifupdown/meson.build53
-rw-r--r--src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c6
-rw-r--r--src/settings/plugins/ifupdown/tests/meson.build17
-rw-r--r--src/settings/plugins/ifupdown/tests/test-ifupdown.c2
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-plugin.c2
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection10
-rw-r--r--src/settings/plugins/keyfile/tests/meson.build21
-rw-r--r--src/settings/plugins/keyfile/tests/test-keyfile.c88
-rw-r--r--src/settings/plugins/meson.build15
46 files changed, 7889 insertions, 732 deletions
diff --git a/src/settings/plugins/ibft/meson.build b/src/settings/plugins/ibft/meson.build
deleted file mode 100644
index da9f5566..00000000
--- a/src/settings/plugins/ibft/meson.build
+++ /dev/null
@@ -1,48 +0,0 @@
-name = 'nm-settings-plugin-ibft'
-
-cflags = [
-  '-DSBINDIR="@0@"'.format(nm_sbindir),
-  '-DSYSCONFDIR="@0@"'.format(nm_sysconfdir)
-]
-
-libnms_ibft_core = static_library(
-  'nms-ibft-core',
-  'nms-ibft-reader.c',
-  dependencies: nm_dep,
-  c_args: cflags
-)
-
-sources = files(
-  'nms-ibft-connection.c',
-  'nms-ibft-plugin.c'
-)
-
-libnm_settings_plugin_ibft = shared_module(
-  name,
-  sources: sources,
-  dependencies: nm_dep,
-  c_args: cflags,
-  link_with: libnms_ibft_core,
-  link_args: ldflags_linker_script_settings,
-  link_depends: linker_script_settings,
-  install: true,
-  install_dir: nm_pkglibdir
-)
-
-core_plugins += libnm_settings_plugin_ibft
-
-# FIXME: check_so_symbols replacement
-'''
-run_target(
-  'check-local-symbols-settings-ibft',
-  command: [check_so_symbols, libnm_settings_plugin_ibft.full_path()],
-  depends: libnm_settings_plugin_ibft
-)
-
-check-local-symbols-settings-ibft: src/settings/plugins/ibft/libnm-settings-plugin-ibft.la
-  $(call check_so_symbols,$(builddir)/src/settings/plugins/ibft/.libs/libnm-settings-plugin-ibft.so)
-'''
-
-if enable_tests
-  subdir('tests')
-endif
diff --git a/src/settings/plugins/ibft/tests/meson.build b/src/settings/plugins/ibft/tests/meson.build
deleted file mode 100644
index 7a9445dd..00000000
--- a/src/settings/plugins/ibft/tests/meson.build
+++ /dev/null
@@ -1,22 +0,0 @@
-test_unit = 'test-ibft'
-
-test_ibft_dir = meson.current_source_dir()
-
-cflags = [
-  '-DTEST_IBFT_DIR="@0@"'.format(test_ibft_dir),
-  '-DTEST_SCRATCH_DIR="@0@"'.format(test_ibft_dir)
-]
-
-exe = executable(
-  test_unit,
-  test_unit + '.c',
-  dependencies: test_nm_dep,
-  c_args: cflags,
-  link_with: libnms_ibft_core
-)
-
-test(
-  'ibft/' + test_unit,
-  test_script,
-  args: test_args + [exe.full_path()]
-)
diff --git a/src/settings/plugins/ibft/tests/test-ibft.c b/src/settings/plugins/ibft/tests/test-ibft.c
index fd2ec61b..72d1a7db 100644
--- a/src/settings/plugins/ibft/tests/test-ibft.c
+++ b/src/settings/plugins/ibft/tests/test-ibft.c
@@ -181,7 +181,7 @@ test_read_ibft_malformed (gconstpointer user_data)
 
 	g_assert (g_file_test (iscsiadm_path, G_FILE_TEST_EXISTS));
 
-	NMTST_EXPECT_NM_WARN ("*malformed iscsiadm record*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*malformed iscsiadm record*");
 
 	success = nms_ibft_reader_load_blocks (iscsiadm_path, &blocks, &error);
 	g_assert_no_error (error);
diff --git a/src/settings/plugins/ifcfg-rh/meson.build b/src/settings/plugins/ifcfg-rh/meson.build
deleted file mode 100644
index fdf308be..00000000
--- a/src/settings/plugins/ifcfg-rh/meson.build
+++ /dev/null
@@ -1,77 +0,0 @@
-install_data(
-  'nm-ifcfg-rh.conf',
-  install_dir: dbus_conf_dir
-)
-
-cflags = [
-  '-DSBINDIR="@0@"'.format(nm_sbindir),
-  '-DSYSCONFDIR="@0@"'.format(nm_sysconfdir)
-]
-
-name = 'nmdbus-ifcfg-rh'
-
-dbus_sources = gnome.gdbus_codegen(
-  name,
-  'nm-ifcfg-rh.xml',
-  interface_prefix: 'com.redhat',
-  namespace: 'NMDBus'
-)
-
-libnmdbus_ifcfg_rh = static_library(
-  name,
-  sources: dbus_sources,
-  dependencies: glib_dep,
-  c_args: cflags
-)
-
-sources = files(
-  'nm-inotify-helper.c',
-  'nms-ifcfg-rh-reader.c',
-  'nms-ifcfg-rh-utils.c',
-  'nms-ifcfg-rh-writer.c',
-  'shvar.c'
-)
-
-deps = [
-  crypto_dep,
-  nm_dep
-]
-
-libnms_ifcfg_rh_core = static_library(
-  'nms-ifcfg-rh-core',
-  sources: sources,
-  dependencies: deps,
-  c_args: cflags
-)
-
-sources = [dbus_sources] + files('nms-ifcfg-rh-connection.c')
-
-libnm_settings_plugin_ifcfg_rh = shared_module(
-  'nm-settings-plugin-ifcfg-rh',
-  sources: sources,
-  dependencies: deps,
-  c_args: cflags,
-  link_with: [libnms_ifcfg_rh_core],
-  link_args: ldflags_linker_script_settings,
-  link_depends: linker_script_settings,
-  install: true,
-  install_dir: nm_pkglibdir
-)
-
-core_plugins += libnm_settings_plugin_ifcfg_rh
-
-# FIXME: check_so_symbols replacement
-'''
-run_target(
-  'check-local-symbols-settings-ifcfg-rh',
-  command: [check_so_symbols, libnm_settings_plugin_ifcfg_rh.full_path()],
-  depends: libnm_settings_plugin_ifcfg_rh
-)
-
-check-local-symbols-settings-ifcfg-rh: src/settings/plugins/ifcfg-rh/libnm-settings-plugin-ifcfg-rh.la
-  $(call check_so_symbols,$(builddir)/src/settings/plugins/ifcfg-rh/.libs/libnm-settings-plugin-ifcfg-rh.so)
-'''
-
-if enable_tests
-  subdir('tests')
-endif
diff --git a/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c
index 2863df64..97417db9 100644
--- a/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c
+++ b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c
@@ -172,7 +172,7 @@ nm_inotify_helper_init (NMInotifyHelper *self)
 {
 	NMInotifyHelperPrivate *priv = NM_INOTIFY_HELPER_GET_PRIVATE (self);
 
-	priv->wd_refs = g_hash_table_new (nm_direct_hash, NULL);
+	priv->wd_refs = g_hash_table_new (g_direct_hash, g_direct_equal);
 }
 
 static void
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c
index c7207297..0743fc9f 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c
@@ -37,6 +37,7 @@
 #include "settings/nm-settings-plugin.h"
 #include "nm-config.h"
 #include "NetworkManagerUtils.h"
+#include "nm-exported-object.h"
 
 #include "nms-ifcfg-rh-connection.h"
 #include "nms-ifcfg-rh-common.h"
@@ -45,10 +46,10 @@
 #include "nms-ifcfg-rh-utils.h"
 #include "shvar.h"
 
-#define IFCFGRH1_BUS_NAME                               "com.redhat.ifcfgrh1"
-#define IFCFGRH1_OBJECT_PATH                            "/com/redhat/ifcfgrh1"
-#define IFCFGRH1_IFACE1_NAME                            "com.redhat.ifcfgrh1"
-#define IFCFGRH1_IFACE1_METHOD_GET_IFCFG_DETAILS        "GetIfcfgDetails"
+#include "settings/plugins/ifcfg-rh/nmdbus-ifcfg-rh.h"
+
+#define IFCFGRH1_DBUS_SERVICE_NAME "com.redhat.ifcfgrh1"
+#define IFCFGRH1_DBUS_OBJECT_PATH "/com/redhat/ifcfgrh1"
 
 /*****************************************************************************/
 
@@ -57,9 +58,9 @@ typedef struct {
 
 	struct {
 		GDBusConnection *connection;
+		GDBusInterfaceSkeleton *interface;
 		GCancellable *cancellable;
 		gulong signal_id;
-		guint regist_id;
 	} dbus;
 
 	GHashTable *connections;  /* uuid::connection */
@@ -326,21 +327,21 @@ update_connection (SettingsPluginIfcfg *self,
 
 			if (new_unmanaged || new_unrecognized) {
 				if (!old_unmanaged && !old_unrecognized) {
-					/* ref connection first, because we put it into priv->connections below.
-					 * Emitting signal-removed might otherwise delete it. */
 					g_object_ref (connection_by_uuid);
-
 					/* Unexport the connection by telling the settings service it's
 					 * been removed.
 					 */
 					nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection_by_uuid));
+					/* Remove the path so that claim_connection() doesn't complain later when
+					 * interface gets managed and connection is re-added. */
+					nm_connection_set_path (NM_CONNECTION (connection_by_uuid), NULL);
 
 					/* signal_remove() will end up removing the connection from our hash,
 					 * so add it back now.
 					 */
 					g_hash_table_insert (priv->connections,
 					                     g_strdup (nm_connection_get_uuid (NM_CONNECTION (connection_by_uuid))),
-					                     connection_by_uuid /* we took reference above and pass it on */);
+					                     connection_by_uuid);
 				}
 			} else {
 				if (old_unmanaged /* && !new_unmanaged */) {
@@ -372,9 +373,7 @@ update_connection (SettingsPluginIfcfg *self,
 			_LOGI ("add connection "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
 		else
 			_LOGI ("new connection "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new));
-		g_hash_table_insert (priv->connections,
-		                     g_strdup (uuid),
-		                     connection_new /* take reference */);
+		g_hash_table_insert (priv->connections, g_strdup (uuid), connection_new);
 
 		g_signal_connect (connection_new, NM_SETTINGS_CONNECTION_REMOVED,
 		                  G_CALLBACK (connection_removed_cb),
@@ -517,7 +516,7 @@ read_connections (SettingsPluginIfcfg *plugin)
 		return;
 	}
 
-	alive_connections = g_hash_table_new (nm_direct_hash, NULL);
+	alive_connections = g_hash_table_new (NULL, NULL);
 
 	filenames = g_ptr_array_new_with_free_func (g_free);
 	while ((item = g_dir_read_name (dir))) {
@@ -750,7 +749,7 @@ impl_ifcfgrh_get_ifcfg_details (SettingsPluginIfcfg *plugin,
 		return;
 	}
 
-	path = nm_dbus_object_get_path (NM_DBUS_OBJECT (connection));
+	path = nm_connection_get_path (NM_CONNECTION (connection));
 	if (!path) {
 		g_dbus_method_invocation_return_error (context,
 		                                       NM_SETTINGS_ERROR,
@@ -769,15 +768,15 @@ static void
 _dbus_clear (SettingsPluginIfcfg *self)
 {
 	SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self);
-	guint id;
 
 	nm_clear_g_signal_handler (priv->dbus.connection, &priv->dbus.signal_id);
 
 	nm_clear_g_cancellable (&priv->dbus.cancellable);
 
-	if ((id = nm_steal_int (&priv->dbus.regist_id))) {
-		if (!g_dbus_connection_unregister_object (priv->dbus.connection, id))
-			_LOGW ("dbus: unexpected failure to unregister object");
+	if (priv->dbus.interface) {
+		g_dbus_interface_skeleton_unexport (priv->dbus.interface);
+		nm_exported_object_skeleton_release (priv->dbus.interface);
+		priv->dbus.interface = NULL;
 	}
 
 	g_clear_object (&priv->dbus.connection);
@@ -789,56 +788,13 @@ _dbus_connection_closed (GDBusConnection *connection,
                          GError          *error,
                          gpointer         user_data)
 {
-	_LOGW ("dbus: %s bus closed", IFCFGRH1_BUS_NAME);
+	_LOGW ("dbus: %s bus closed", IFCFGRH1_DBUS_SERVICE_NAME);
 	_dbus_clear (SETTINGS_PLUGIN_IFCFG (user_data));
 
 	/* Retry or recover? */
 }
 
 static void
-_method_call (GDBusConnection *connection,
-              const char *sender,
-              const char *object_path,
-              const char *interface_name,
-              const char *method_name,
-              GVariant *parameters,
-              GDBusMethodInvocation *invocation,
-              gpointer user_data)
-{
-	SettingsPluginIfcfg *self = SETTINGS_PLUGIN_IFCFG (user_data);
-	const char *ifcfg;
-
-	if (   !nm_streq (interface_name, IFCFGRH1_IFACE1_NAME)
-	    || !nm_streq (method_name, IFCFGRH1_IFACE1_METHOD_GET_IFCFG_DETAILS)) {
-		g_dbus_method_invocation_return_error (invocation,
-		                                       G_DBUS_ERROR,
-		                                       G_DBUS_ERROR_UNKNOWN_METHOD,
-		                                       "Unknown method %s",
-		                                       method_name);
-		return;
-	}
-
-	g_variant_get (parameters, "(&s)", &ifcfg);
-	impl_ifcfgrh_get_ifcfg_details (self, invocation, ifcfg);
-}
-
-static GDBusInterfaceInfo *const interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO (
-	IFCFGRH1_BUS_NAME,
-	.methods = NM_DEFINE_GDBUS_METHOD_INFOS (
-		NM_DEFINE_GDBUS_METHOD_INFO (
-			IFCFGRH1_IFACE1_METHOD_GET_IFCFG_DETAILS,
-			.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-				NM_DEFINE_GDBUS_ARG_INFO ("ifcfg", "s"),
-			),
-			.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-				NM_DEFINE_GDBUS_ARG_INFO ("uuid", "s"),
-				NM_DEFINE_GDBUS_ARG_INFO ("path", "o"),
-			),
-		),
-	),
-);
-
-static void
 _dbus_request_name_done (GObject *source_object,
                          GAsyncResult *res,
                          gpointer user_data)
@@ -874,27 +830,36 @@ _dbus_request_name_done (GObject *source_object,
 	}
 
 	{
-		static const GDBusInterfaceVTable interface_vtable = {
-			.method_call = _method_call,
+		GType skeleton_type = NMDBUS_TYPE_IFCFGRH1_SKELETON;
+		gs_free char *method_name_get_ifcfg_details = NULL;
+		NMExportedObjectDBusMethodImpl methods[] = {
+			{
+				.method_name = (method_name_get_ifcfg_details = nm_exported_object_skeletonify_method_name ("GetIfcfgDetails")),
+				.impl = G_CALLBACK (impl_ifcfgrh_get_ifcfg_details),
+			},
 		};
 
-		priv->dbus.regist_id = g_dbus_connection_register_object (connection,
-		                                                          IFCFGRH1_OBJECT_PATH,
-		                                                          interface_info,
-		                                                          NM_UNCONST_PTR (GDBusInterfaceVTable, &interface_vtable),
-		                                                          self,
-		                                                          NULL,
-		                                                          &error);
-		if (!priv->dbus.regist_id) {
-			_LOGW ("dbus: couldn't register D-Bus service: %s", error->message);
+		priv->dbus.interface = nm_exported_object_skeleton_create (skeleton_type,
+		                                                           g_type_class_peek (SETTINGS_TYPE_PLUGIN_IFCFG),
+		                                                           methods,
+		                                                           G_N_ELEMENTS (methods),
+		                                                           (GObject *) self);
+
+		if (!g_dbus_interface_skeleton_export (priv->dbus.interface,
+		                                       priv->dbus.connection,
+		                                       IFCFGRH1_DBUS_OBJECT_PATH,
+		                                       &error)) {
+			nm_exported_object_skeleton_release (priv->dbus.interface);
+			priv->dbus.interface = NULL;
+			_LOGW ("dbus: failed exporting interface: %s", error->message);
 			_dbus_clear (self);
 			return;
 		}
 	}
 
 	_LOGD ("dbus: aquired D-Bus service %s and exported %s object",
-	       IFCFGRH1_BUS_NAME,
-	       IFCFGRH1_OBJECT_PATH);
+	       IFCFGRH1_DBUS_SERVICE_NAME,
+	       IFCFGRH1_DBUS_OBJECT_PATH);
 }
 
 static void
@@ -935,7 +900,7 @@ _dbus_create_done (GObject *source_object,
 	                        DBUS_INTERFACE_DBUS,
 	                        "RequestName",
 	                        g_variant_new ("(su)",
-	                                       IFCFGRH1_BUS_NAME,
+	                                       IFCFGRH1_DBUS_SERVICE_NAME,
 	                                       DBUS_NAME_FLAG_DO_NOT_QUEUE),
 	                        G_VARIANT_TYPE ("(u)"),
 	                        G_DBUS_CALL_FLAGS_NONE,
@@ -952,7 +917,7 @@ _dbus_setup (SettingsPluginIfcfg *self)
 	gs_free char *address = NULL;
 	gs_free_error GError *error = NULL;
 
-	_dbus_clear (self);
+	g_return_if_fail (!priv->dbus.connection);
 
 	address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
 	if (address == NULL) {
@@ -978,22 +943,17 @@ config_changed_cb (NMConfig *config,
                    NMConfigData *old_data,
                    SettingsPluginIfcfg *self)
 {
-	SettingsPluginIfcfgPrivate *priv;
-
 	/* If the dbus connection for some reason is borked the D-Bus service
 	 * won't be offered.
 	 *
 	 * On SIGHUP and SIGUSR1 try to re-connect to D-Bus. So in the unlikely
 	 * event that the D-Bus conneciton is broken, that allows for recovery
 	 * without need for restarting NetworkManager. */
-	if (!NM_FLAGS_ANY (changes,   NM_CONFIG_CHANGE_CAUSE_SIGHUP
-	                            | NM_CONFIG_CHANGE_CAUSE_SIGUSR1))
-		return;
-
-	priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self);
-	if (   !priv->dbus.connection
-	    && !priv->dbus.cancellable)
-		_dbus_setup (self);
+	if (NM_FLAGS_ANY (changes,   NM_CONFIG_CHANGE_CAUSE_SIGHUP
+	                           | NM_CONFIG_CHANGE_CAUSE_SIGUSR1)) {
+		if (!SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self)->dbus.connection)
+			_dbus_setup (self);
+	}
 }
 
 /*****************************************************************************/
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
index 6ef3f660..c91cd253 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
@@ -181,7 +181,7 @@ make_connection_setting (const char *file,
 	const char *v;
 	gs_free char *stable_id = NULL;
 	const char *const *iter;
-	int vint64, i_val;
+	int vint64;
 
 	ifcfg_name = utils_get_ifcfg_name (file, TRUE);
 	if (!ifcfg_name)
@@ -338,13 +338,6 @@ make_connection_setting (const char *file,
 	vint64 = svGetValueInt64 (ifcfg, "AUTH_RETRIES", 10, -1, G_MAXINT32, -1);
 	g_object_set (s_con, NM_SETTING_CONNECTION_AUTH_RETRIES, (gint) vint64, NULL);
 
-	i_val = NM_SETTING_CONNECTION_MDNS_DEFAULT;
-	if (!svGetValueEnum (ifcfg, "MDNS",
-	                     nm_setting_connection_mdns_get_type (),
-	                     &i_val, NULL))
-		PARSE_WARNING ("invalid MDNS setting");
-	g_object_set (s_con, NM_SETTING_CONNECTION_MDNS, i_val, NULL);
-
 	return NM_SETTING (s_con);
 }
 
@@ -934,7 +927,7 @@ next:
 			                                                    : ""));
 			break;
 		case PARSE_LINE_TYPE_FLAG:
-			/* NOTE: the flag (for "onlink") only allows to explictly set "TRUE".
+			/* XXX: the flag (for "onlink") only allows to explictly set "TRUE".
 			 * There is no way to express an explicit "FALSE" setting
 			 * of this attribute, hence, the file format cannot encode
 			 * that configuration. */
@@ -1345,7 +1338,29 @@ make_ip4_setting (shvarFile *ifcfg,
 	} else if (!g_ascii_strcasecmp (v, "autoip")) {
 		method = NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL;
 	} else if (!g_ascii_strcasecmp (v, "shared")) {
-		method = NM_SETTING_IP4_CONFIG_METHOD_SHARED;
+		int idx;
+
+		g_object_set (s_ip4,
+		              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_SHARED,
+		              NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default,
+		              NULL);
+		/* 1 IP address is allowed for shared connections. Read it. */
+		if (is_any_ip4_address_defined (ifcfg, &idx)) {
+			guint32 gw;
+			NMIPAddress *addr = NULL;
+
+			if (!read_full_ip4_address (ifcfg, idx, NULL, &addr, NULL, error))
+				return NULL;
+			if (!read_ip4_address (ifcfg, "GATEWAY", NULL, &gw, error))
+				return NULL;
+			(void) nm_setting_ip_config_add_address (s_ip4, addr);
+			nm_ip_address_unref (addr);
+			if (never_default)
+				PARSE_WARNING ("GATEWAY will be ignored when DEFROUTE is disabled");
+			gateway = g_strdup (nm_utils_inet4_ntop (gw, inet_buf));
+			g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL);
+		}
+		return g_steal_pointer (&s_ip4);
 	} else {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "Unknown BOOTPROTO '%s'", v);
@@ -1372,7 +1387,7 @@ make_ip4_setting (shvarFile *ifcfg,
 	              NM_SETTING_IP_CONFIG_ROUTE_TABLE, (guint) route_table,
 	              NULL);
 
-	if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED))
+	if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0)
 		return g_steal_pointer (&s_ip4);
 
 	/* Handle DHCP settings */
@@ -1449,47 +1464,39 @@ make_ip4_setting (shvarFile *ifcfg,
 	if (gateway && never_default)
 		PARSE_WARNING ("GATEWAY will be ignored when DEFROUTE is disabled");
 
-	/* We used to skip saving a lot of unused properties for the ipv4 shared method.
-	 * We want now to persist them but... unfortunately loading DNS or DOMAIN options
-	 * would cause a fail in the ipv4 verify() function. As we don't want any regression
-	 * in the unlikely event that someone has a working ifcfg file for an IPv4 shared ip
-	 * connection with a crafted "DNS" entry... don't load it. So we will avoid failing
-	 * the connection) */
-	if (!nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) {
-		/* DNS servers
-		 * Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting())
-		 */
-		for (i = 1; i <= 10; i++) {
-			char tag[256];
-
-			numbered_tag (tag, "DNS", i);
-			nm_clear_g_free (&value);
-			v = svGetValueStr (ifcfg, tag, &value);
-			if (v) {
-				if (nm_utils_ipaddr_valid (AF_INET, v)) {
-					if (!nm_setting_ip_config_add_dns (s_ip4, v))
-						PARSE_WARNING ("duplicate DNS server %s", tag);
-				} else if (nm_utils_ipaddr_valid (AF_INET6, v)) {
-					/* Ignore IPv6 addresses */
-				} else {
-					PARSE_WARNING ("invalid DNS server address %s", v);
-					return NULL;
-				}
-			}
-		}
+	/* DNS servers
+	 * Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting())
+	 */
+	for (i = 1; i <= 10; i++) {
+		char tag[256];
 
-		/* DNS searches */
+		numbered_tag (tag, "DNS", i);
 		nm_clear_g_free (&value);
-		v = svGetValueStr (ifcfg, "DOMAIN", &value);
+		v = svGetValueStr (ifcfg, tag, &value);
 		if (v) {
-			gs_free const char **searches = NULL;
+			if (nm_utils_ipaddr_valid (AF_INET, v)) {
+				if (!nm_setting_ip_config_add_dns (s_ip4, v))
+					PARSE_WARNING ("duplicate DNS server %s", tag);
+			} else if (nm_utils_ipaddr_valid (AF_INET6, v)) {
+				/* Ignore IPv6 addresses */
+			} else {
+				PARSE_WARNING ("invalid DNS server address %s", v);
+				return NULL;
+			}
+		}
+	}
 
-			searches = nm_utils_strsplit_set (v, " ");
-			if (searches) {
-				for (item = searches; *item; item++) {
-					if (!nm_setting_ip_config_add_dns_search (s_ip4, *item))
-						PARSE_WARNING ("duplicate DNS domain '%s'", *item);
-				}
+	/* DNS searches */
+	nm_clear_g_free (&value);
+	v = svGetValueStr (ifcfg, "DOMAIN", &value);
+	if (v) {
+		gs_free const char **searches = NULL;
+
+		searches = nm_utils_strsplit_set (v, " ");
+		if (searches) {
+			for (item = searches; *item; item++) {
+				if (!nm_setting_ip_config_add_dns_search (s_ip4, *item))
+					PARSE_WARNING ("duplicate DNS domain '%s'", *item);
 			}
 		}
 	}
@@ -1538,8 +1545,7 @@ make_ip4_setting (shvarFile *ifcfg,
 	}
 
 	/* Legacy value NM used for a while but is incorrect (rh #459370) */
-	if (   !nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)
-	    && !nm_setting_ip_config_get_num_dns_searches (s_ip4)) {
+	if (!nm_setting_ip_config_get_num_dns_searches (s_ip4)) {
 		nm_clear_g_free (&value);
 		v = svGetValueStr (ifcfg, "SEARCH", &value);
 		if (v) {
@@ -1555,14 +1561,10 @@ make_ip4_setting (shvarFile *ifcfg,
 		}
 	}
 
-	timeout = svGetValueInt64 (ifcfg, "ACD_TIMEOUT", 10, -1, NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX, -2);
-	if (timeout == -2) {
-		timeout = svGetValueInt64 (ifcfg, "ARPING_WAIT", 10, -1,
-		                           NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX / 1000, -1);
-		if (timeout > 0)
-			timeout *= 1000;
-	}
-	g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DAD_TIMEOUT, (gint) timeout, NULL);
+	timeout = svGetValueInt64 (ifcfg, "ARPING_WAIT", 10, -1,
+	                           NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX / 1000, -1);
+	g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DAD_TIMEOUT,
+	              (gint) (timeout <= 0 ? timeout : timeout * 1000), NULL);
 
 	return g_steal_pointer (&s_ip4);
 }
@@ -1640,7 +1642,7 @@ read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *file
 			                            read_defroute ? &gateway : NULL,
 			                            &err);
 			if (ok) {
-				nm_ip_address_set_attribute (addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL, g_variant_new_string (device));
+				nm_ip_address_set_attribute (addr, "label", g_variant_new_string (device));
 				if (!nm_setting_ip_config_add_address (s_ip4, addr))
 					PARSE_WARNING ("duplicate IP4 address in alias file %s", item);
 				if (nm_streq0 (nm_setting_ip_config_get_method (s_ip4), NM_SETTING_IP4_CONFIG_METHOD_DISABLED))
@@ -1999,15 +2001,11 @@ make_tc_setting (shvarFile *ifcfg)
 			break;
 
 		qdisc = nm_utils_tc_qdisc_from_str (value, &local);
-		if (!qdisc) {
-			PARSE_WARNING ("ignoring bad tc qdisc: '%s': %s", value, local->message);
-			continue;
-		}
+		if (!qdisc)
+			PARSE_WARNING ("ignoring bad qdisc: '%s': %s", value, local->message);
 
 		if (!nm_setting_tc_config_add_qdisc (s_tc, qdisc))
-			PARSE_WARNING ("duplicate tc qdisc");
-
-		nm_tc_qdisc_unref (qdisc);
+			PARSE_WARNING ("duplicate qdisc");
 	}
 
 	for (i = 1;; i++) {
@@ -2021,15 +2019,11 @@ make_tc_setting (shvarFile *ifcfg)
 			break;
 
 		tfilter = nm_utils_tc_tfilter_from_str (value, &local);
-		if (!tfilter) {
-			PARSE_WARNING ("ignoring bad tc filter: '%s': %s", value, local->message);
-			continue;
-		}
+		if (!tfilter)
+			PARSE_WARNING ("ignoring bad tfilter: '%s': %s", value, local->message);
 
 		if (!nm_setting_tc_config_add_tfilter (s_tc, tfilter))
-			PARSE_WARNING ("duplicate tc filter");
-
-		nm_tc_tfilter_unref (tfilter);
+			PARSE_WARNING ("duplicate filter");
 	}
 
 	if (   nm_setting_tc_config_get_num_qdiscs (s_tc) > 0
@@ -3558,13 +3552,6 @@ make_wpa_setting (shvarFile *ifcfg,
 		return NULL;
 	g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PMF, i_val, NULL);
 
-	i_val = NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT;
-	if (!svGetValueEnum (ifcfg, "FILS",
-	                     nm_setting_wireless_security_fils_get_type (),
-	                     &i_val, error))
-		return NULL;
-	g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_FILS, i_val, NULL);
-
 	nm_clear_g_free (&value);
 	v = svGetValueStr (ifcfg, "SECURITYMODE", &value);
 	if (NM_IN_STRSET (v, NULL, "open"))
@@ -5334,8 +5321,6 @@ connection_from_file_full (const char *filename,
 	g_return_val_if_fail (filename != NULL, NULL);
 	g_return_val_if_fail (out_unhandled && !*out_unhandled, NULL);
 
-	NM_SET_OUT (out_ignore_error, FALSE);
-
 	/* Non-NULL only for unit tests; normally use /etc/sysconfig/network */
 	if (!network_file)
 		network_file = SYSCONFDIR "/sysconfig/network";
@@ -5356,7 +5341,6 @@ connection_from_file_full (const char *filename,
 	if (!svGetValueBoolean (parsed, "NM_CONTROLLED", TRUE)) {
 		connection = create_unhandled_connection (filename, parsed, "unmanaged", out_unhandled);
 		if (!connection) {
-			NM_SET_OUT (out_ignore_error, TRUE);
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
 			             "NM_CONTROLLED was false but device was not uniquely identified; device will be managed");
 		}
@@ -5366,7 +5350,8 @@ connection_from_file_full (const char *filename,
 	/* iBFT is handled by the iBFT settings plugin */
 	bootproto = svGetValueStr_cp (parsed, "BOOTPROTO");
 	if (bootproto && !g_ascii_strcasecmp (bootproto, "ibft")) {
-		NM_SET_OUT (out_ignore_error, TRUE);
+		if (out_ignore_error)
+			*out_ignore_error = TRUE;
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 		             "Ignoring iBFT configuration");
 		g_free (bootproto);
@@ -5412,7 +5397,8 @@ connection_from_file_full (const char *filename,
 		char *device;
 
 		if ((tmp = svGetValueStr_cp (parsed, "IPV6TUNNELIPV4"))) {
-			NM_SET_OUT (out_ignore_error, TRUE);
+			if (out_ignore_error)
+				*out_ignore_error = TRUE;
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "Ignoring unsupported connection due to IPV6TUNNELIPV4");
 			return NULL;
@@ -5426,7 +5412,8 @@ connection_from_file_full (const char *filename,
 		}
 
 		if (!strcmp (device, "lo")) {
-			NM_SET_OUT (out_ignore_error, TRUE);
+			if (out_ignore_error)
+				*out_ignore_error = TRUE;
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "Ignoring loopback device config.");
 			g_free (device);
@@ -5473,7 +5460,8 @@ connection_from_file_full (const char *filename,
 					memcpy (p_path, IFUP_PATH_PREFIX, NM_STRLEN (IFUP_PATH_PREFIX));
 					if (access (p_path, X_OK) == 0) {
 						/* for all other types, this is not something we want to handle. */
-						NM_SET_OUT (out_ignore_error, TRUE);
+						if (out_ignore_error)
+							*out_ignore_error = TRUE;
 						g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 						             "Ignore script for unknown device type which has a matching %s script",
 						             p_path);
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
index 8584772e..e9dd08b7 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
@@ -148,7 +148,16 @@ write_secrets (shvarFile *ifcfg,
 	/* we purge all existing secrets. */
 	svUnsetAll (keyfile, SV_KEY_TYPE_ANY);
 
-	secrets_keys = nm_utils_strdict_get_keys (secrets, TRUE, &secrets_keys_n);
+	/* sort the keys. */
+	secrets_keys = (const char **) g_hash_table_get_keys_as_array (secrets, &secrets_keys_n);
+	if (secrets_keys_n > 1) {
+		g_qsort_with_data (secrets_keys,
+		                   secrets_keys_n,
+		                   sizeof (const char *),
+		                   nm_strcmp_p_with_data,
+		                   NULL);
+	}
+
 	for (i = 0; i < secrets_keys_n; i++) {
 		const char *k = secrets_keys[i];
 		const char *v = g_hash_table_lookup (secrets, k);
@@ -785,13 +794,6 @@ write_wireless_security_setting (NMConnection *connection,
 		                nm_setting_wireless_security_get_pmf (s_wsec));
 	}
 
-	if (nm_setting_wireless_security_get_fils (s_wsec) == NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT)
-		svUnsetValue (ifcfg, "FILS");
-	else {
-		svSetValueEnum (ifcfg, "FILS", nm_setting_wireless_security_fils_get_type (),
-		                nm_setting_wireless_security_get_fils (s_wsec));
-	}
-
 	return TRUE;
 }
 
@@ -897,16 +899,14 @@ write_wireless_setting (NMConnection *connection,
 	}
 
 	mode = nm_setting_wireless_get_mode (s_wireless);
-	if (!mode)
-		svUnsetValue(ifcfg, "MODE");
-	else if (nm_streq (mode, NM_SETTING_WIRELESS_MODE_INFRA))
+	if (!mode || !strcmp (mode, "infrastructure")) {
 		svSetValueStr (ifcfg, "MODE", "Managed");
-	else if (nm_streq (mode, NM_SETTING_WIRELESS_MODE_ADHOC)) {
+	} else if (!strcmp (mode, "adhoc")) {
 		svSetValueStr (ifcfg, "MODE", "Ad-Hoc");
 		adhoc = TRUE;
-	} else if (nm_streq (mode, NM_SETTING_WIRELESS_MODE_AP))
+	} else if (!strcmp (mode, "ap")) {
 		svSetValueStr (ifcfg, "MODE", "Ap");
-	else {
+	} else {
 		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
 		             "Invalid mode '%s' in '%s' setting",
 		             mode, NM_SETTING_WIRELESS_SETTING_NAME);
@@ -1728,7 +1728,6 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
 	GString *str;
 	const char *master, *master_iface = NULL, *type;
 	gint vint;
-	NMSettingConnectionMdns mdns;
 	guint32 vuint32;
 	const char *tmp;
 
@@ -1750,7 +1749,9 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
 
 	/* Only save the value for master connections */
 	type = nm_setting_connection_get_connection_type (s_con);
-	if (_nm_connection_type_is_master (type)) {
+	if (   !g_strcmp0 (type, NM_SETTING_BOND_SETTING_NAME)
+	    || !g_strcmp0 (type, NM_SETTING_TEAM_SETTING_NAME)
+	    || !g_strcmp0 (type, NM_SETTING_BRIDGE_SETTING_NAME)) {
 		NMSettingConnectionAutoconnectSlaves autoconnect_slaves;
 		autoconnect_slaves = nm_setting_connection_get_autoconnect_slaves (s_con);
 		svSetValueStr (ifcfg, "AUTOCONNECT_SLAVES",
@@ -1887,13 +1888,6 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
 
 	vint = nm_setting_connection_get_auth_retries (s_con);
 	svSetValueInt64_cond (ifcfg, "AUTH_RETRIES", vint >= 0, vint);
-
-	mdns = nm_setting_connection_get_mdns (s_con);
-	if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) {
-		svSetValueEnum (ifcfg, "MDNS", nm_setting_connection_mdns_get_type (),
-		                mdns);
-	} else
-		svUnsetValue (ifcfg, "MDNS");
 }
 
 static char *
@@ -2287,7 +2281,7 @@ write_ip4_setting (NMConnection *connection,
 		if (i > 0) {
 			GVariant *label;
 
-			label = nm_ip_address_get_attribute (addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL);
+			label = nm_ip_address_get_attribute (addr, "label");
 			if (label)
 				continue;
 		}
@@ -2417,15 +2411,12 @@ write_ip4_setting (NMConnection *connection,
 	NM_SET_OUT (out_route_content, write_route_file (s_ip4));
 
 	timeout = nm_setting_ip_config_get_dad_timeout (s_ip4);
-	if (timeout < 0) {
-		svUnsetValue (ifcfg, "ACD_TIMEOUT");
+	if (timeout < 0)
 		svUnsetValue (ifcfg, "ARPING_WAIT");
-	} else if (timeout == 0) {
-		svSetValueStr (ifcfg, "ACD_TIMEOUT", "0");
+	else if (timeout == 0)
 		svSetValueStr (ifcfg, "ARPING_WAIT", "0");
-	} else {
-		svSetValueInt64 (ifcfg, "ACD_TIMEOUT", timeout);
-		/* Round the value up to next integer for initscripts */
+	else {
+		/* Round the value up to next integer */
 		svSetValueInt64 (ifcfg, "ARPING_WAIT", (timeout - 1) / 1000 + 1);
 	}
 
@@ -2493,7 +2484,7 @@ write_ip4_aliases (NMConnection *connection, const char *base_ifcfg_path)
 
 		addr = nm_setting_ip_config_get_address (s_ip4, i);
 
-		label_var = nm_ip_address_get_attribute (addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL);
+		label_var = nm_ip_address_get_attribute (addr, "label");
 		if (!label_var)
 			continue;
 		label = g_variant_get_string (label_var, NULL);
@@ -2996,7 +2987,7 @@ do_write_to_disk (NMConnection *connection,
 {
 	/* From here on, we persist data to disk. Before, it was all in-memory
 	 * only. But we loaded the ifcfg files from disk, and managled our
-	 * new settings (in-memory). */
+	 * new settings (in-momory). */
 
 	if (!svWriteFile (ifcfg, 0644, error))
 		return FALSE;
@@ -3147,10 +3138,10 @@ nms_ifcfg_rh_writer_write_connection (NMConnection *connection,
 	 * does not yet allow to inject the configuration. */
 	if (out_reread || out_reread_same) {
 		if (!do_write_reread (connection,
-		                      svFileGetName (ifcfg),
-		                      out_reread,
-		                      out_reread_same,
-		                      &local)) {
+		                         svFileGetName (ifcfg),
+		                         out_reread,
+		                         out_reread_same,
+		                         &local)) {
 			_LOGW ("write: failure to re-read connection \"%s\": %s",
 			       svFileGetName (ifcfg), local->message);
 			g_clear_error (&local);
@@ -3197,3 +3188,4 @@ nms_ifcfg_rh_writer_can_write_connection (NMConnection *connection, GError **err
 	             NM_PRINT_FMT_QUOTE_STRING (type));
 	return FALSE;
 }
+
diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c
index 9120b870..2b64f3fc 100644
--- a/src/settings/plugins/ifcfg-rh/shvar.c
+++ b/src/settings/plugins/ifcfg-rh/shvar.c
@@ -39,7 +39,7 @@
 #include "nm-core-internal.h"
 #include "nm-core-utils.h"
 #include "nm-utils/nm-enum-utils.h"
-#include "c-list/src/c-list.h"
+#include "nm-utils/c-list.h"
 
 /*****************************************************************************/
 
@@ -1278,7 +1278,7 @@ svSetValueEnum (shvarFile *s, const char *key, GType gtype, int value)
 {
 	gs_free char *v = NULL;
 
-	v = _nm_utils_enum_to_str_full (gtype, value, " ", NULL);
+	v = _nm_utils_enum_to_str_full (gtype, value, " ");
 	return svSetValueStr (s, key, v);
 }
 
diff --git a/src/settings/plugins/ifcfg-rh/tests/meson.build b/src/settings/plugins/ifcfg-rh/tests/meson.build
deleted file mode 100644
index 3596b642..00000000
--- a/src/settings/plugins/ifcfg-rh/tests/meson.build
+++ /dev/null
@@ -1,22 +0,0 @@
-test_unit = 'test-ifcfg-rh'
-
-test_ifcfg_dir = meson.current_source_dir()
-
-cflags = [
-  '-DTEST_IFCFG_DIR="@0@"'.format(test_ifcfg_dir),
-  '-DTEST_SCRATCH_DIR="@0@"'.format(test_ifcfg_dir)
-]
-
-exe = executable(
-  test_unit,
-  test_unit + '.c',
-  dependencies: test_nm_dep,
-  c_args: cflags,
-  link_with: libnms_ifcfg_rh_core
-)
-
-test(
-  'ifcfg-rh/' + test_unit,
-  test_script,
-  args: test_args + [exe.full_path()]
-)
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected
index cf325f35..026993b8 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected
@@ -1,4 +1,5 @@
 ESSID="Test SSID"
+MODE=Managed
 SSID_HIDDEN=yes
 MAC_ADDRESS_RANDOMIZATION=default
 TYPE=Wireless
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected
index cd8fc96f..c0e47c48 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected
@@ -14,8 +14,6 @@ DNS2=4.2.2.2
 DOMAIN="foobar.com lab.foobar.com"
 DEFROUTE=yes
 IPV4_FAILURE_FATAL=no
-ACD_TIMEOUT=400
-ARPING_WAIT=1
 IPV6INIT=no
 NAME="Test Write Wired Static Routes"
 UUID=${UUID}
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc
deleted file mode 100644
index d0a3c254..00000000
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc
+++ /dev/null
@@ -1,16 +0,0 @@
-TYPE=Ethernet
-DEVICE=eth0
-HWADDR=00:11:22:33:44:55
-BOOTPROTO=none
-ONBOOT=yes
-DNS1=4.2.2.1
-DNS2=4.2.2.2
-IPADDR=192.168.1.5
-PREFIX=24
-NETMASK=255.255.255.0
-GATEWAY=192.168.1.1
-IPV6INIT=no
-QDISC1="root fq_codel"
-FILTER1="parent 1234: matchall action simple sdata Hello"
-NAME=ethernet-tc
-UUID=a42c8d4e-11a2-4144-92d2-5cbce8c6b2c4
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write.cexpected
deleted file mode 100644
index a67ca598..00000000
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write.cexpected
+++ /dev/null
@@ -1,16 +0,0 @@
-TYPE=Ethernet
-PROXY_METHOD=none
-BROWSER_ONLY=no
-QDISC1="parent 2468:2 pfifo_fast"
-FILTER1="parent 1234: matchall action simple sdata Hello"
-BOOTPROTO=none
-IPADDR=1.1.1.3
-PREFIX=24
-GATEWAY=1.1.1.1
-DEFROUTE=yes
-IPV4_FAILURE_FATAL=no
-IPV6INIT=no
-NAME="Test Write TC config"
-UUID=${UUID}
-DEVICE=eth0
-ONBOOT=yes
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-1 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-1
index db09afdb..1bc3d524 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-1
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-1
@@ -10,5 +10,3 @@ PREFIX1=16
 IPADDR2=3.3.3.3
 PREFIX2=8
 GATEWAY=1.1.1.1
-ACD_TIMEOUT=2000
-ARPING_WAIT=1
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-2
index 6972e279..d7273e36 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-2
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-2
@@ -9,5 +9,3 @@ IPADDR2=9.8.7.6
 PREFIX2=16
 IPADDR3=3.3.3.3
 PREFIX3=8
-ACD_TIMEOUT=2000
-ARPING_WAIT=1
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-3 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-3
index d9065994..f2457bd2 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-3
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-3
@@ -9,5 +9,3 @@ IPADDR3=9.8.7.6
 PREFIX3=16
 IPADDR4=3.3.3.3
 PREFIX4=8
-ACD_TIMEOUT=2000
-ARPING_WAIT=1
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-4 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-4
index 935267f7..e6b77141 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-4
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv4-manual-4
@@ -9,5 +9,3 @@ IPADDR1=9.8.7.6
 PREFIX1=16
 IPADDR2=3.3.3.3
 PREFIX2=8
-ACD_TIMEOUT=2000
-ARPING_WAIT=1
diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
index 57bd96e9..6bf27556 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -24,7 +24,6 @@
 #include <stdarg.h>
 #include <unistd.h>
 #include <string.h>
-#include <linux/pkt_sched.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <sys/socket.h>
@@ -606,7 +605,8 @@ test_read_miscellaneous_variables (void)
 	int mac_blacklist_num, i;
 	guint64 expected_timestamp = 0;
 
-	NMTST_EXPECT_NM_WARN ("*invalid MAC in HWADDR_BLACKLIST 'XX:aa:invalid'*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*invalid MAC in HWADDR_BLACKLIST 'XX:aa:invalid'*");
 	connection = _connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-misc-variables",
 	                                    NULL, TYPE_ETHERNET, NULL);
 	g_test_assert_expected_messages ();
@@ -859,7 +859,8 @@ test_read_wired_static_no_prefix (gconstpointer user_data)
 	file = g_strdup_printf (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-wired-static-no-prefix-%u", expected_prefix);
 	expected_id = g_strdup_printf ("System test-wired-static-no-prefix-%u", expected_prefix);
 
-	NMTST_EXPECT_NM_WARN ("*missing PREFIX, assuming*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*missing PREFIX, assuming*");
 	connection = _connection_from_file (file, NULL, TYPE_ETHERNET, NULL);
 	g_test_assert_expected_messages ();
 
@@ -1080,7 +1081,8 @@ test_read_wired_global_gateway_ignore (void)
 	NMSettingIPConfig *s_ip4;
 	char *unmanaged = NULL;
 
-	NMTST_EXPECT_NM_WARN ("*ignoring GATEWAY (/etc/sysconfig/network) for * because the connection has no static addresses");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*ignoring GATEWAY (/etc/sysconfig/network) for * because the connection has no static addresses");
 	connection = _connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-global-gateway-ignore",
 	                                    TEST_IFCFG_DIR"/network-scripts/network-test-wired-global-gateway-ignore",
 	                                    TYPE_ETHERNET, &unmanaged);
@@ -1474,7 +1476,6 @@ test_read_wired_ipv4_manual (gconstpointer data)
 	s_ip4 = nm_connection_get_setting_ip4_config (connection);
 	g_assert (s_ip4);
 	g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
-	g_assert_cmpint (nm_setting_ip_config_get_dad_timeout (s_ip4), ==, 2000);
 
 	/* IP addresses */
 	g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 3);
@@ -1512,7 +1513,8 @@ test_read_wired_ipv6_manual (void)
 	NMIPAddress *ip6_addr;
 	NMIPRoute *ip6_route;
 
-	NMTST_EXPECT_NM_WARN ("*ignoring manual default route*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*ignoring manual default route*");
 	connection = _connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-ipv6-manual",
 	                                    NULL, TYPE_ETHERNET, &unmanaged);
 	g_test_assert_expected_messages ();
@@ -1895,7 +1897,8 @@ test_read_write_802_1X_subj_matches (void)
 	gs_unref_object NMConnection *reread = NULL;
 	NMSetting8021x *s_8021x;
 
-	NMTST_EXPECT_NM_WARN ("*missing IEEE_8021X_CA_CERT*peap*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*missing IEEE_8021X_CA_CERT*peap*");
 	connection = _connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-802-1X-subj-matches",
 	                                    NULL, TYPE_ETHERNET, NULL);
 	g_test_assert_expected_messages ();
@@ -1916,14 +1919,16 @@ test_read_write_802_1X_subj_matches (void)
 	g_assert_cmpstr (nm_setting_802_1x_get_phase2_altsubject_match (s_8021x, 0), ==, "x.yourdomain.tld");
 	g_assert_cmpstr (nm_setting_802_1x_get_phase2_altsubject_match (s_8021x, 1), ==, "y.yourdomain.tld");
 
-	NMTST_EXPECT_NM_WARN ("*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!");
 	_writer_new_connec_exp (connection,
 	                        TEST_SCRATCH_DIR "/network-scripts/",
 	                        TEST_IFCFG_DIR "/network-scripts/ifcfg-System_test-wired-802-1X-subj-matches.cexpected",
 	                        &testfile);
 	g_test_assert_expected_messages ();
 
-	NMTST_EXPECT_NM_WARN ("*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!");
 	reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL);
 	g_test_assert_expected_messages ();
 
@@ -2074,7 +2079,7 @@ test_read_wired_aliases_good (gconstpointer test_data)
 		g_assert (j < expected_num_addresses);
 
 		g_assert_cmpint (nm_ip_address_get_prefix (ip4_addr), ==, 24);
-		label = nm_ip_address_get_attribute (ip4_addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL);
+		label = nm_ip_address_get_attribute (ip4_addr, "label");
 		if (expected_label[j])
 			g_assert_cmpstr (g_variant_get_string (label, NULL), ==, expected_label[j]);
 		else
@@ -2126,7 +2131,7 @@ test_read_wired_aliases_bad (const char *base, const char *expected_id)
 	g_assert (ip4_addr != NULL);
 	g_assert_cmpstr (nm_ip_address_get_address (ip4_addr), ==, "192.168.1.5");
 	g_assert_cmpint (nm_ip_address_get_prefix (ip4_addr), ==, 24);
-	g_assert (nm_ip_address_get_attribute (ip4_addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL) == NULL);
+	g_assert (nm_ip_address_get_attribute (ip4_addr, "label") == NULL);
 
 	/* Gateway */
 	g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "192.168.1.1");
@@ -2137,14 +2142,16 @@ test_read_wired_aliases_bad (const char *base, const char *expected_id)
 static void
 test_read_wired_aliases_bad_1 (void)
 {
-	NMTST_EXPECT_NM_WARN ("*aliasem1:1*has no DEVICE*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*aliasem1:1*has no DEVICE*");
 	test_read_wired_aliases_bad (TEST_IFCFG_DIR "/network-scripts/ifcfg-aliasem1", "System aliasem1");
 }
 
 static void
 test_read_wired_aliases_bad_2 (void)
 {
-	NMTST_EXPECT_NM_WARN ("*aliasem2:1*has invalid DEVICE*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*aliasem2:1*has invalid DEVICE*");
 	test_read_wired_aliases_bad (TEST_IFCFG_DIR "/network-scripts/ifcfg-aliasem2", "System aliasem2");
 }
 
@@ -3515,6 +3522,7 @@ test_write_wifi_hidden (void)
 
 	g_object_set (s_wifi,
 	              NM_SETTING_WIRELESS_SSID, ssid,
+	              NM_SETTING_WIRELESS_MODE, "infrastructure",
 	              NM_SETTING_WIRELESS_HIDDEN, TRUE,
 	              NULL);
 
@@ -4766,7 +4774,6 @@ test_write_wired_static_routes (void)
 	g_object_set (s_ip4,
 	              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
 	              NM_SETTING_IP_CONFIG_GATEWAY, "1.1.1.1",
-	              NM_SETTING_IP_CONFIG_DAD_TIMEOUT, 400,
 	              NULL);
 
 	addr = nm_ip_address_new (AF_INET, "1.1.1.3", 24, &error);
@@ -5134,7 +5141,7 @@ test_write_wired_aliases (void)
 		addr = nm_ip_address_new (AF_INET, ip[i], 24, &error);
 		g_assert_no_error (error);
 		if (label[i])
-			nm_ip_address_set_attribute (addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL, g_variant_new_string (label[i]));
+			nm_ip_address_set_attribute (addr, "label", g_variant_new_string (label[i]));
 		nm_setting_ip_config_add_address (s_ip4, addr);
 		nm_ip_address_unref (addr);
 	}
@@ -5193,9 +5200,9 @@ test_write_wired_aliases (void)
 		else {
 			g_assert_cmpint (nm_ip_address_get_prefix (addr), ==, 24);
 			if (label[j])
-				g_assert_cmpstr (g_variant_get_string (nm_ip_address_get_attribute (addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL), NULL), ==, label[j]);
+				g_assert_cmpstr (g_variant_get_string (nm_ip_address_get_attribute (addr, "label"), NULL), ==, label[j]);
 			else
-				g_assert (nm_ip_address_get_attribute (addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL) == NULL);
+				g_assert (nm_ip_address_get_attribute (addr, "label") == NULL);
 			ip[j] = NULL;
 		}
 	}
@@ -6278,9 +6285,7 @@ test_write_wifi_wpa_eap_tls (void)
 	s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
 	nm_connection_add_setting (connection, NM_SETTING (s_wsec));
 
-	g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap",
-	              NM_SETTING_WIRELESS_SECURITY_FILS, (int) NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED,
-	              NULL);
+	g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", NULL);
 	nm_setting_wireless_security_add_proto (s_wsec, "wpa");
 	nm_setting_wireless_security_add_pairwise (s_wsec, "tkip");
 	nm_setting_wireless_security_add_group (s_wsec, "tkip");
@@ -7028,7 +7033,7 @@ test_write_wired_ctc_dhcp (void)
 	                        TEST_SCRATCH_DIR "/network-scripts/",
 	                        &testfile);
 
-	/* Ensure the CTCPROT item gets written out as its own option */
+	/* Ensure the CTCPROT item gets written out as it's own option */
 	ifcfg = _svOpenFile (testfile);
 
 	_svGetValue_check (ifcfg, "CTCPROT", "0");
@@ -7708,7 +7713,8 @@ test_read_vlan_reorder_hdr_1 (void)
 	NMConnection *connection;
 	NMSettingVlan *s_vlan;
 
-	NMTST_EXPECT_NM_WARN ("*REORDER_HDR key is deprecated, use VLAN_FLAGS*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*REORDER_HDR key is deprecated, use VLAN_FLAGS*");
 	connection = _connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-vlan-reorder-hdr-1",
 	                                        NULL, TYPE_ETHERNET, NULL);
 	g_test_assert_expected_messages ();
@@ -8502,7 +8508,8 @@ test_read_dcb_bad_booleans (void)
 {
 	gs_free_error GError *error = NULL;
 
-	NMTST_EXPECT_NM_WARN ("*invalid DCB_PG_STRICT value*not all 0s and 1s*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*invalid DCB_PG_STRICT value*not all 0s and 1s*");
 	_connection_from_file_fail (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-booleans",
 	                            NULL, TYPE_ETHERNET, &error);
 	g_test_assert_expected_messages ();
@@ -8516,7 +8523,8 @@ test_read_dcb_short_booleans (void)
 {
 	gs_free_error GError *error = NULL;
 
-	NMTST_EXPECT_NM_WARN ("*DCB_PG_STRICT value*8 characters*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*DCB_PG_STRICT value*8 characters*");
 	_connection_from_file_fail (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-booleans",
 	                            NULL, TYPE_ETHERNET, &error);
 	g_test_assert_expected_messages ();
@@ -8530,7 +8538,8 @@ test_read_dcb_bad_uints (void)
 {
 	gs_free_error GError *error = NULL;
 
-	NMTST_EXPECT_NM_WARN ("*invalid DCB_PG_UP2TC value*not 0 - 7*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*invalid DCB_PG_UP2TC value*not 0 - 7*");
 	_connection_from_file_fail (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-uints",
 	                            NULL, TYPE_ETHERNET, &error);
 	g_test_assert_expected_messages ();
@@ -8544,7 +8553,8 @@ test_read_dcb_short_uints (void)
 {
 	gs_free_error GError *error = NULL;
 
-	NMTST_EXPECT_NM_WARN ("*DCB_PG_UP2TC value*8 characters*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*DCB_PG_UP2TC value*8 characters*");
 	_connection_from_file_fail (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-uints",
 	                            NULL, TYPE_ETHERNET, &error);
 	g_test_assert_expected_messages ();
@@ -8558,7 +8568,8 @@ test_read_dcb_bad_percent (void)
 {
 	gs_free_error GError *error = NULL;
 
-	NMTST_EXPECT_NM_WARN ("*invalid DCB_PG_PCT percentage value*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*invalid DCB_PG_PCT percentage value*");
 	_connection_from_file_fail (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-bad-percent",
 	                            NULL, TYPE_ETHERNET, &error);
 	g_test_assert_expected_messages ();
@@ -8572,7 +8583,8 @@ test_read_dcb_short_percent (void)
 {
 	gs_free_error GError *error = NULL;
 
-	NMTST_EXPECT_NM_WARN ("*invalid DCB_PG_PCT percentage list value*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*invalid DCB_PG_PCT percentage list value*");
 	_connection_from_file_fail (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-short-percent",
 	                            NULL, TYPE_ETHERNET, &error);
 	g_test_assert_expected_messages ();
@@ -8586,7 +8598,8 @@ test_read_dcb_pgpct_not_100 (void)
 {
 	gs_free_error GError *error = NULL;
 
-	NMTST_EXPECT_NM_WARN ("*DCB_PG_PCT percentages do not equal 100*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*DCB_PG_PCT percentages do not equal 100*");
 	_connection_from_file_fail (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dcb-pgpct-not-100",
 	                            NULL, TYPE_ETHERNET, &error);
 	g_test_assert_expected_messages ();
@@ -8707,7 +8720,7 @@ test_read_team_master_invalid (gconstpointer user_data)
 	NMSettingConnection *s_con;
 	NMSettingTeam *s_team;
 
-	NMTST_EXPECT_NM_WARN ("*ignoring invalid team configuration*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*ignoring invalid team configuration*");
 	connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL);
 	g_test_assert_expected_messages ();
 
@@ -9632,125 +9645,6 @@ test_utils_ignore (void)
 	do_test_utils_ignored ("ignored-augtmp", "ifcfg-FooBar" AUGTMP_TAG, TRUE);
 }
 
-static void
-test_tc_read (void)
-{
-	NMConnection *connection;
-	NMSettingTCConfig *s_tc;
-	NMTCQdisc *qdisc;
-	NMTCTfilter *filter;
-	char *str;
-
-	connection = _connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-tc",
-	                                    NULL, TYPE_ETHERNET,NULL);
-
-	g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, "eth0");
-
-	s_tc = nm_connection_get_setting_tc_config (connection);
-	g_assert (s_tc);
-
-	g_assert_cmpint (nm_setting_tc_config_get_num_qdiscs (s_tc), ==, 1);
-	qdisc = nm_setting_tc_config_get_qdisc (s_tc, 0);
-	g_assert (qdisc);
-	g_assert_cmpint (nm_tc_qdisc_get_parent (qdisc), ==, TC_H_ROOT);
-	g_assert_cmpint (nm_tc_qdisc_get_handle (qdisc), ==, TC_H_UNSPEC);
-	g_assert_cmpstr (nm_tc_qdisc_get_kind (qdisc), ==, "fq_codel");
-
-	g_assert_cmpint (nm_setting_tc_config_get_num_tfilters (s_tc), ==, 1);
-	filter = nm_setting_tc_config_get_tfilter (s_tc, 0);
-	g_assert (filter);
-	str = nm_utils_tc_tfilter_to_str (filter, NULL);
-	g_assert_cmpstr (str, ==, "parent 1234: matchall action simple sdata Hello");
-	g_free (str);
-
-	g_object_unref (connection);
-}
-
-static void
-test_tc_write (void)
-{
-	nmtst_auto_unlinkfile char *testfile = NULL;
-	gs_unref_object NMConnection *connection = NULL;
-	gs_unref_object NMConnection *reread = NULL;
-	NMSettingConnection *s_con;
-	NMSettingIPConfig *s_ip4;
-	NMSettingIPConfig *s_ip6;
-	NMSettingWired *s_wired;
-	NMSettingTCConfig *s_tc;
-	NMTCQdisc *qdisc;
-	NMTCTfilter *tfilter;
-	NMIPAddress *addr;
-	GError *error = NULL;
-
-	connection = nm_simple_connection_new ();
-
-	/* Connection setting */
-	s_con = (NMSettingConnection *) nm_setting_connection_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_con));
-
-	g_object_set (s_con,
-	              NM_SETTING_CONNECTION_ID, "Test Write TC config",
-	              NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_a (),
-	              NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
-	              NM_SETTING_CONNECTION_INTERFACE_NAME, "eth0",
-	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
-	              NULL);
-
-	/* Wired setting */
-	s_wired = (NMSettingWired *) nm_setting_wired_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_wired));
-
-	/* IP4 setting */
-	s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_ip4));
-
-	g_object_set (s_ip4,
-	              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
-	              NM_SETTING_IP_CONFIG_GATEWAY, "1.1.1.1",
-	              NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE,
-	              NULL);
-
-	addr = nm_ip_address_new (AF_INET, "1.1.1.3", 24, &error);
-	g_assert_no_error (error);
-	nm_setting_ip_config_add_address (s_ip4, addr);
-	nm_ip_address_unref (addr);
-
-	/* IP6 setting */
-	s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_ip6));
-
-	g_object_set (s_ip6,
-	              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
-	              NULL);
-
-	/* TC setting */
-	s_tc = (NMSettingTCConfig *) nm_setting_tc_config_new ();
-	nm_connection_add_setting (connection, NM_SETTING (s_tc));
-
-	qdisc = nm_tc_qdisc_new ("pfifo_fast", TC_H_MAKE (0x2468 << 16, 0x2), &error);
-	g_assert_no_error (error);
-	nm_setting_tc_config_add_qdisc (s_tc, qdisc);
-	nm_tc_qdisc_unref (qdisc);
-
-	tfilter = nm_utils_tc_tfilter_from_str ("parent 1234: matchall action simple sdata Hello", &error);
-	g_assert_no_error (error);
-	nm_setting_tc_config_add_tfilter (s_tc, tfilter);
-	nm_tc_tfilter_unref (tfilter);
-
-	nm_connection_add_setting (connection, nm_setting_proxy_new ());
-
-	nmtst_assert_connection_verifies_without_normalization (connection);
-
-	_writer_new_connec_exp (connection,
-	                        TEST_SCRATCH_DIR "/network-scripts/",
-	                        TEST_IFCFG_DIR "/network-scripts/ifcfg-test-tc-write.cexpected",
-	                        &testfile);
-
-	reread = _connection_from_file (testfile, NULL, TYPE_BOND, NULL);
-
-	nmtst_assert_connection_equals (connection, TRUE, reread, FALSE);
-}
-
 /*****************************************************************************/
 
 #define TPATH "/settings/plugins/ifcfg-rh/"
@@ -10033,8 +9927,5 @@ int main (int argc, char **argv)
 	g_test_add_func (TPATH "utils/path", test_utils_path);
 	g_test_add_func (TPATH "utils/ignore", test_utils_ignore);
 
-	g_test_add_func (TPATH "tc/read", test_tc_read);
-	g_test_add_func (TPATH "tc/write", test_tc_write);
-
 	return g_test_run ();
 }
diff --git a/src/settings/plugins/ifnet/nms-ifnet-connection-parser.c b/src/settings/plugins/ifnet/nms-ifnet-connection-parser.c
new file mode 100644
index 00000000..ed0a757f
--- /dev/null
+++ b/src/settings/plugins/ifnet/nms-ifnet-connection-parser.c
@@ -0,0 +1,2912 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Mu Qiao <qiaomuf@gmail.com>
+ *
+ * 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) 1999-2010 Gentoo Foundation, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nms-ifnet-connection-parser.h"
+
+#include <string.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "settings/nm-settings-plugin.h"
+#include "nm-core-internal.h"
+#include "NetworkManagerUtils.h"
+#include "nm-meta-setting.h"
+
+#include "nms-ifnet-net-utils.h"
+#include "nms-ifnet-wpa-parser.h"
+#include "nms-ifnet-connection.h"
+
+static char *
+connection_id_from_ifnet_name (const char *conn_name)
+{
+	int name_len = strlen (conn_name);
+
+	/* Convert a hex-encoded conn_name (only used for wifi SSIDs) to human-readable one */
+	if ((name_len > 2) && (g_str_has_prefix (conn_name, "0x"))) {
+		GBytes *bytes = nm_utils_hexstr2bin (conn_name);
+		char *buf;
+
+		if (bytes) {
+			buf = g_strndup (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes));
+			g_bytes_unref (bytes);
+			return buf;
+		}
+	}
+
+	return g_strdup (conn_name);
+}
+
+static gboolean eap_simple_reader (const char *eap_method,
+                                   const char *ssid,
+                                   NMSetting8021x *s_8021x,
+                                   gboolean phase2,
+                                   const char *basepath,
+                                   GError **error);
+
+static gboolean eap_tls_reader (const char *eap_method,
+                                const char *ssid,
+                                NMSetting8021x *s_8021x,
+                                gboolean phase2,
+                                const char *basepath,
+                                GError **error);
+
+static gboolean eap_peap_reader (const char *eap_method,
+                                 const char *ssid,
+                                 NMSetting8021x *s_8021x,
+                                 gboolean phase2,
+                                 const char *basepath,
+                                 GError **error);
+
+static gboolean eap_ttls_reader (const char *eap_method,
+                                 const char *ssid,
+                                 NMSetting8021x *s_8021x,
+                                 gboolean phase2,
+                                 const char *basepath,
+                                 GError **error);
+
+typedef struct {
+	const char *method;
+	 gboolean (*reader) (const char *eap_method,
+	                     const char *ssid,
+	                     NMSetting8021x *s_8021x,
+	                     gboolean phase2,
+	                     const char *basepath,
+	                     GError **error);
+	gboolean wifi_phase2_only;
+} EAPReader;
+
+static EAPReader eap_readers[] = {
+	{"md5", eap_simple_reader, TRUE},
+	{"pwd", eap_simple_reader, TRUE},
+	{"pap", eap_simple_reader, TRUE},
+	{"chap", eap_simple_reader, TRUE},
+	{"mschap", eap_simple_reader, TRUE},
+	{"mschapv2", eap_simple_reader, TRUE},
+	{"leap", eap_simple_reader, TRUE},
+	{"tls", eap_tls_reader, FALSE},
+	{"peap", eap_peap_reader, FALSE},
+	{"ttls", eap_ttls_reader, FALSE},
+	{NULL, NULL}
+};
+
+/* reading identity and password */
+static gboolean
+eap_simple_reader (const char *eap_method,
+                   const char *ssid,
+                   NMSetting8021x *s_8021x,
+                   gboolean phase2,
+                   const char *basepath,
+                   GError **error)
+{
+	const char *value;
+
+	/* identity */
+	value = wpa_get_value (ssid, "identity");
+	if (!value) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing IEEE_8021X_IDENTITY for EAP method '%s'.",
+			     eap_method);
+		return FALSE;
+	}
+	g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
+
+	/* password */
+	value = wpa_get_value (ssid, "password");
+	if (!value) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing IEEE_8021X_PASSWORD for EAP method '%s'.",
+			     eap_method);
+		return FALSE;
+	}
+
+	g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD, value, NULL);
+
+	return TRUE;
+}
+
+static char *
+get_cert (const char *ssid, const char *key, const char *basepath)
+{
+	const char *orig;
+
+	/* If it's a relative path, convert to absolute using 'basepath' */
+	orig = wpa_get_value (ssid, key);
+	if (g_path_is_absolute (orig))
+		return g_strdup (orig);
+	return g_strdup_printf ("%s/%s", basepath, orig);
+}
+
+static gboolean
+eap_tls_reader (const char *eap_method,
+                const char *ssid,
+                NMSetting8021x *s_8021x,
+                gboolean phase2,
+                const char *basepath,
+                GError **error)
+{
+	const char *value;
+	char *ca_cert = NULL;
+	char *client_cert = NULL;
+	char *privkey = NULL;
+	const char *privkey_password = NULL;
+	gboolean success = FALSE;
+	NMSetting8021xCKFormat privkey_format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
+
+	/* identity */
+	value = wpa_get_value (ssid, "identity");
+	if (!value) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing IEEE_8021X_IDENTITY for EAP method '%s'.",
+			     eap_method);
+		return FALSE;
+	}
+	g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
+
+	/* ca cert */
+	ca_cert = get_cert (ssid, phase2 ? "ca_cert2" : "ca_cert", basepath);
+	if (ca_cert) {
+		if (phase2) {
+			if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x,
+								   ca_cert,
+								   NM_SETTING_802_1X_CK_SCHEME_PATH,
+								   NULL, error))
+				goto done;
+		} else {
+			if (!nm_setting_802_1x_set_ca_cert (s_8021x,
+							    ca_cert,
+							    NM_SETTING_802_1X_CK_SCHEME_PATH,
+							    NULL, error))
+				goto done;
+		}
+	} else {
+		nm_log_warn (LOGD_SETTINGS, "    missing %s for EAP method '%s'; this is insecure!",
+		             phase2 ? "IEEE_8021X_INNER_CA_CERT" :
+		             "IEEE_8021X_CA_CERT", eap_method);
+	}
+
+	/* Private key password */
+	privkey_password = wpa_get_value (ssid,
+					  phase2 ? "private_key2_passwd" :
+					  "private_key_passwd");
+
+	if (!privkey_password) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing %s for EAP method '%s'.",
+			     phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD" :
+			     "IEEE_8021X_PRIVATE_KEY_PASSWORD", eap_method);
+		goto done;
+	}
+
+	/* The private key itself */
+	privkey = get_cert (ssid, phase2 ? "private_key2" : "private_key", basepath);
+	if (!privkey) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing %s for EAP method '%s'.",
+			     phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" :
+			     "IEEE_8021X_PRIVATE_KEY", eap_method);
+		goto done;
+	}
+
+	if (phase2) {
+		if (!nm_setting_802_1x_set_phase2_private_key (s_8021x,
+							       privkey,
+							       privkey_password,
+							       NM_SETTING_802_1X_CK_SCHEME_PATH,
+							       &privkey_format,
+							       error))
+			goto done;
+	} else {
+		if (!nm_setting_802_1x_set_private_key (s_8021x,
+							privkey,
+							privkey_password,
+							NM_SETTING_802_1X_CK_SCHEME_PATH,
+							&privkey_format, error))
+			goto done;
+	}
+
+	/* Only set the client certificate if the private key is not PKCS#12 format,
+	 * as NM (due to supplicant restrictions) requires.  If the key was PKCS#12,
+	 * then nm_setting_802_1x_set_private_key() already set the client certificate
+	 * to the same value as the private key.
+	 */
+	if (privkey_format == NM_SETTING_802_1X_CK_FORMAT_RAW_KEY
+	    || privkey_format == NM_SETTING_802_1X_CK_FORMAT_X509) {
+		client_cert = get_cert (ssid, phase2 ? "client_cert2" : "client_cert", basepath);
+		if (!client_cert) {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				     "Missing %s for EAP method '%s'.",
+				     phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" :
+				     "IEEE_8021X_CLIENT_CERT", eap_method);
+			goto done;
+		}
+
+		if (phase2) {
+			if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x,
+								       client_cert,
+								       NM_SETTING_802_1X_CK_SCHEME_PATH,
+								       NULL,
+								       error))
+				goto done;
+		} else {
+			if (!nm_setting_802_1x_set_client_cert (s_8021x,
+								client_cert,
+								NM_SETTING_802_1X_CK_SCHEME_PATH,
+								NULL, error))
+				goto done;
+		}
+	}
+
+	success = TRUE;
+
+done:
+	g_free (ca_cert);
+	g_free (client_cert);
+	g_free (privkey);
+	return success;
+}
+
+static gboolean
+eap_peap_reader (const char *eap_method,
+                 const char *ssid,
+                 NMSetting8021x *s_8021x,
+                 gboolean phase2,
+                 const char *basepath,
+                 GError **error)
+{
+	char *ca_cert = NULL;
+	const char *inner_auth = NULL;
+	const char *peapver = NULL;
+	char **list = NULL, **iter, *lower;
+	gboolean success = FALSE;
+
+	ca_cert = get_cert (ssid, "ca_cert", basepath);
+	if (ca_cert) {
+		if (!nm_setting_802_1x_set_ca_cert (s_8021x,
+						    ca_cert,
+						    NM_SETTING_802_1X_CK_SCHEME_PATH,
+						    NULL, error))
+			goto done;
+	} else {
+		nm_log_warn (LOGD_SETTINGS, "    missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!",
+		             eap_method);
+	}
+
+	peapver = wpa_get_value (ssid, "phase1");
+	/* peap version, default is automatic */
+	if (peapver && strstr (peapver, "peapver")) {
+		if (strstr (peapver, "peapver=0"))
+			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER,
+				      "0", NULL);
+		else if (strstr (peapver, "peapver=1"))
+			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER,
+				      "1", NULL);
+		else {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				     "Unknown IEEE_8021X_PEAP_VERSION value '%s'",
+				     peapver);
+			goto done;
+		}
+	}
+
+	/* peaplabel */
+	if (peapver && strstr (peapver, "peaplabel=1"))
+		g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1",
+			      NULL);
+
+	inner_auth = wpa_get_value (ssid, "phase2");
+	if (!inner_auth) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing IEEE_8021X_INNER_AUTH_METHODS.");
+		goto done;
+	}
+	/* Handle options for the inner auth method */
+	list = g_strsplit (inner_auth, " ", 0);
+	for (iter = list; iter && *iter; iter++) {
+		gchar *pos = NULL;
+
+		if (!strlen (*iter))
+			continue;
+
+		if (!(pos = strstr (*iter, "MSCHAPV2"))
+		    || !(pos = strstr (*iter, "MD5"))
+		    || !(pos = strstr (*iter, "GTC"))) {
+			if (!eap_simple_reader (pos, ssid, s_8021x, TRUE, basepath, error))
+				goto done;
+		} else if (!(pos = strstr (*iter, "TLS"))) {
+			if (!eap_tls_reader (pos, ssid, s_8021x, TRUE, basepath, error))
+				goto done;
+		} else {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				     "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
+				     *iter);
+			goto done;
+		}
+
+		pos = strchr (*iter, '=');
+		if (pos && *pos) {
+			pos++;
+			lower = g_ascii_strdown (pos, -1);
+			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower,
+				      NULL);
+			g_free (lower);
+		} else {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				     "No IEEE_8021X_INNER_AUTH_METHOD.");
+			goto done;
+		}
+		break;
+	}
+
+	if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "No valid IEEE_8021X_INNER_AUTH_METHODS found.");
+		goto done;
+	}
+
+	success = TRUE;
+
+done:
+	g_free (ca_cert);
+	if (list)
+		g_strfreev (list);
+	return success;
+}
+
+static gboolean
+eap_ttls_reader (const char *eap_method,
+                 const char *ssid,
+                 NMSetting8021x *s_8021x,
+                 gboolean phase2,
+                 const char *basepath,
+                 GError **error)
+{
+	gboolean success = FALSE;
+	const char *anon_ident = NULL;
+	char *ca_cert = NULL;
+	const char *tmp;
+	char **list = NULL, **iter, *inner_auth = NULL;
+
+	/* ca cert */
+	ca_cert = get_cert (ssid, "ca_cert", basepath);
+	if (ca_cert) {
+		if (!nm_setting_802_1x_set_ca_cert (s_8021x,
+						    ca_cert,
+						    NM_SETTING_802_1X_CK_SCHEME_PATH,
+						    NULL, error))
+			goto done;
+	} else {
+		nm_log_warn (LOGD_SETTINGS, "    missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!",
+		             eap_method);
+	}
+
+	/* anonymous indentity for tls */
+	anon_ident = wpa_get_value (ssid, "anonymous_identity");
+	if (anon_ident && strlen (anon_ident))
+		g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY,
+			      anon_ident, NULL);
+
+	tmp = wpa_get_value (ssid, "phase2");
+	if (!tmp) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing IEEE_8021X_INNER_AUTH_METHODS.");
+		goto done;
+	}
+
+	/* Handle options for the inner auth method */
+	inner_auth = g_ascii_strdown (tmp, -1);
+	list = g_strsplit (inner_auth, " ", 0);
+	for (iter = list; iter && *iter; iter++) {
+		gchar *pos = NULL;
+
+		if (!strlen (*iter))
+			continue;
+		if ((pos = strstr (*iter, "mschapv2")) != NULL
+		    || (pos = strstr (*iter, "mschap")) != NULL
+		    || (pos = strstr (*iter, "pap")) != NULL
+		    || (pos = strstr (*iter, "chap")) != NULL) {
+			if (!eap_simple_reader (pos, ssid, s_8021x, TRUE, basepath, error))
+				goto done;
+			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH,
+				      pos, NULL);
+		} else if ((pos = strstr (*iter, "tls")) != NULL) {
+			if (!eap_tls_reader (pos, ssid, s_8021x, TRUE, basepath, error))
+				goto done;
+			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP,
+				      "tls", NULL);
+		} else if ((pos = strstr (*iter, "mschapv2")) != NULL
+			   || (pos = strstr (*iter, "md5")) != NULL) {
+			if (!eap_simple_reader (pos, ssid, s_8021x, TRUE, basepath, error)) {
+				nm_log_warn (LOGD_SETTINGS, "SIMPLE ERROR");
+				goto done;
+			}
+			g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP,
+				      pos, NULL);
+		} else {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				     "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
+				     *iter);
+			goto done;
+		}
+		break;
+	}
+
+	success = TRUE;
+done:
+	g_free (ca_cert);
+	if (list)
+		g_strfreev (list);
+	g_free (inner_auth);
+	return success;
+}
+
+/* type is already decided by net_parser, this function is just used to
+ * doing tansformation*/
+static const gchar *
+guess_connection_type (const char *conn_name)
+{
+	const gchar *type = ifnet_get_data (conn_name, "type");
+	const gchar *ret_type = NULL;
+
+	if (!g_strcmp0 (type, "ppp"))
+		ret_type = NM_SETTING_PPPOE_SETTING_NAME;
+
+	if (!g_strcmp0 (type, "wireless"))
+		ret_type = NM_SETTING_WIRELESS_SETTING_NAME;
+
+	if (!ret_type)
+		ret_type = NM_SETTING_WIRED_SETTING_NAME;
+
+	nm_log_info (LOGD_SETTINGS, "guessed connection type (%s) = %s", conn_name, ret_type);
+	return ret_type;
+}
+
+/* Reading mac address for setting connection option.
+ * Unmanaged device mac address is required by NetworkManager*/
+static gboolean
+read_mac_address (const char *conn_name, const char **mac, GError **error)
+{
+	const char *value = ifnet_get_data (conn_name, "mac");
+
+	if (!value || !strlen (value))
+		return TRUE;
+
+	if (!nm_utils_hwaddr_valid (value, ETH_ALEN)) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+		             "The MAC address '%s' was invalid.", value);
+		return FALSE;
+	}
+
+	*mac = value;
+	return TRUE;
+}
+
+static gboolean
+make_wired_connection_setting (NMConnection *connection,
+                               const char *conn_name,
+                               GError **error)
+{
+	const char *mac = NULL;
+	NMSettingWired *s_wired = NULL;
+	const char *value = NULL;
+
+	s_wired = NM_SETTING_WIRED (nm_setting_wired_new ());
+
+	/* mtu_xxx */
+	value = ifnet_get_data (conn_name, "mtu");
+	if (value) {
+		long int mtu;
+
+		errno = 0;
+		mtu = strtol (value, NULL, 10);
+		if (errno || mtu < 0 || mtu > 65535) {
+			nm_log_warn (LOGD_SETTINGS, "    invalid MTU '%s' for %s", value, conn_name);
+		} else
+			g_object_set (s_wired, NM_SETTING_WIRED_MTU,
+				      (guint32) mtu, NULL);
+	}
+
+	if (!read_mac_address (conn_name, &mac, error)) {
+		g_object_unref (s_wired);
+		return FALSE;
+	}
+
+	if (mac)
+		g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac, NULL);
+	nm_connection_add_setting (connection, NM_SETTING (s_wired));
+
+	return TRUE;
+}
+
+/* add NM_SETTING_IP_CONFIG_DHCP_HOSTNAME,
+ * NM_SETTING_IP_CONFIG_DHCP_CLIENT_ID in future*/
+static gboolean
+make_ip4_setting (NMConnection *connection,
+                  const char *conn_name,
+                  GError **error)
+{
+
+	NMSettingIPConfig *ip4_setting =
+	    NM_SETTING_IP_CONFIG (nm_setting_ip4_config_new ());
+	const char *value, *method = NULL;
+	gboolean is_static_block = is_static_ip4 (conn_name);
+	ip_block *iblock = NULL;
+
+	/* set dhcp options (dhcp_xxx) */
+	value = ifnet_get_data (conn_name, "dhcp");
+	g_object_set (ip4_setting, NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, value
+		      && strstr (value, "nodns") ? TRUE : FALSE,
+		      NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, value
+		      && strstr (value, "nogateway") ? TRUE : FALSE, NULL);
+
+	if (!is_static_block) {
+		method = ifnet_get_data (conn_name, "config");
+		if (!method){
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+						 "Unknown config for %s", conn_name);
+			g_object_unref (ip4_setting);
+			return FALSE;
+		}
+		if (strstr (method, "dhcp"))
+			g_object_set (ip4_setting,
+						  NM_SETTING_IP_CONFIG_METHOD,
+						  NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+						  NM_SETTING_IP_CONFIG_NEVER_DEFAULT, FALSE, NULL);
+		else if (strstr (method, "autoip")) {
+			g_object_set (ip4_setting,
+						  NM_SETTING_IP_CONFIG_METHOD,
+						  NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL,
+						  NM_SETTING_IP_CONFIG_NEVER_DEFAULT, FALSE, NULL);
+			nm_connection_add_setting (connection, NM_SETTING (ip4_setting));
+			return TRUE;
+		} else if (strstr (method, "shared")) {
+			g_object_set (ip4_setting,
+						  NM_SETTING_IP_CONFIG_METHOD,
+						  NM_SETTING_IP4_CONFIG_METHOD_SHARED,
+						  NM_SETTING_IP_CONFIG_NEVER_DEFAULT, FALSE, NULL);
+			nm_connection_add_setting (connection, NM_SETTING (ip4_setting));
+			return TRUE;
+		} else {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+						 "Unknown config for %s", conn_name);
+			g_object_unref (ip4_setting);
+			return FALSE;
+		}
+		nm_log_info (LOGD_SETTINGS, "Using %s method for %s", method, conn_name);
+	}else {
+		iblock = convert_ip4_config_block (conn_name);
+		if (!iblock) {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				     "Ifnet plugin: can't aquire ip configuration for %s",
+				     conn_name);
+			g_object_unref (ip4_setting);
+			return FALSE;
+		}
+		/************** add all ip settings to the connection**********/
+		while (iblock) {
+			ip_block *current_iblock;
+			NMIPAddress *ip4_addr;
+			GError *local = NULL;
+
+			ip4_addr = nm_ip_address_new (AF_INET, iblock->ip, iblock->prefix, &local);
+			if (iblock->next_hop)
+				g_object_set (ip4_setting,
+					      NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES,
+					      TRUE, NULL);
+
+			if (ip4_addr) {
+				if (!nm_setting_ip_config_add_address (ip4_setting, ip4_addr))
+					nm_log_warn (LOGD_SETTINGS, "ignoring duplicate IP4 address");
+				nm_ip_address_unref (ip4_addr);
+			} else {
+				nm_log_warn (LOGD_SETTINGS, "    ignoring invalid address entry: %s", local->message);
+				g_clear_error (&local);
+			}
+
+			current_iblock = iblock;
+			iblock = iblock->next;
+			destroy_ip_block (current_iblock);
+
+		}
+		g_object_set (ip4_setting,
+		              NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+		              NM_SETTING_IP_CONFIG_NEVER_DEFAULT, !has_default_ip4_route (conn_name),
+		              NULL);
+	}
+
+	/* add dhcp hostname and client id */
+	if (!is_static_block && strstr (method, "dhcp")) {
+		gchar *dhcp_hostname, *client_id;
+
+		get_dhcp_hostname_and_client_id (&dhcp_hostname, &client_id);
+		if (dhcp_hostname) {
+			g_object_set (ip4_setting,
+				      NM_SETTING_IP_CONFIG_DHCP_HOSTNAME,
+				      dhcp_hostname, NULL);
+			nm_log_info (LOGD_SETTINGS, "DHCP hostname: %s", dhcp_hostname);
+			g_free (dhcp_hostname);
+		}
+		if (client_id) {
+			g_object_set (ip4_setting,
+				      NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID,
+				      client_id, NULL);
+			nm_log_info (LOGD_SETTINGS, "DHCP client id: %s", client_id);
+			g_free (client_id);
+		}
+	}
+
+	/* add all IPv4 dns servers, IPv6 servers will be ignored */
+	set_ip4_dns_servers (ip4_setting, conn_name);
+
+	/* DNS searches */
+	value = ifnet_get_data (conn_name, "dns_search");
+	if (value) {
+		gs_free char *stripped = g_strdup (value);
+		char **searches = NULL;
+
+		strip_string (stripped, '"');
+
+		searches = g_strsplit (stripped, " ", 0);
+		if (searches) {
+			char **item;
+
+			for (item = searches; *item; item++) {
+				if (strlen (*item)) {
+					if (!nm_setting_ip_config_add_dns_search (ip4_setting, *item))
+						nm_log_warn (LOGD_SETTINGS, "    duplicate DNS domain '%s'", *item);
+				}
+			}
+			g_strfreev (searches);
+		}
+	}
+
+	/* static routes */
+	iblock = convert_ip4_routes_block (conn_name);
+	while (iblock) {
+		ip_block *current_iblock = iblock;
+		const char *metric_str;
+		char *stripped;
+		gint64 metric;
+		NMIPRoute *route;
+		GError *local = NULL;
+
+		if ((metric_str = ifnet_get_data (conn_name, "metric")) != NULL) {
+			metric = _nm_utils_ascii_str_to_int64 (metric_str, 10, 0, G_MAXUINT32, -1);
+		} else {
+			metric_str = ifnet_get_global_data ("metric");
+			if (metric_str) {
+				stripped = g_strdup (metric_str);
+				strip_string (stripped, '"');
+				metric = _nm_utils_ascii_str_to_int64 (metric_str, 10, 0, G_MAXUINT32, -1);
+				g_free (stripped);
+			} else
+				metric = -1;
+		}
+
+		route = nm_ip_route_new (AF_INET, iblock->ip, iblock->prefix, iblock->next_hop, metric, &local);
+		if (route) {
+			if (nm_setting_ip_config_add_route (ip4_setting, route))
+				nm_log_info (LOGD_SETTINGS, "new IP4 route:%s\n", iblock->ip);
+			else
+				nm_log_warn (LOGD_SETTINGS, "duplicate IP4 route");
+			nm_ip_route_unref (route);
+		} else {
+			nm_log_warn (LOGD_SETTINGS, "    ignoring invalid route entry: %s", local->message);
+			g_clear_error (&local);
+		}
+
+		current_iblock = iblock;
+		iblock = iblock->next;
+		destroy_ip_block (current_iblock);
+	}
+
+	/* Finally add setting to connection */
+	nm_connection_add_setting (connection, NM_SETTING (ip4_setting));
+
+	return TRUE;
+}
+
+static gboolean
+make_ip6_setting (NMConnection *connection,
+                  const char *conn_name,
+                  GError **error)
+{
+	NMSettingIPConfig *s_ip6 = NULL;
+	gboolean is_static_block = is_static_ip6 (conn_name);
+
+	// used to disable IPv6
+	gboolean ipv6_enabled = FALSE;
+	gchar *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
+	const char *value;
+	ip_block *iblock;
+	gboolean never_default = !has_default_ip6_route (conn_name);
+
+	s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new ();
+
+	value = ifnet_get_data (conn_name, "enable_ipv6");
+	if (value && is_true (value))
+		ipv6_enabled = TRUE;
+
+	//FIXME Handle other methods that NM supports in future
+	// Currently only Manual and DHCP are supported
+	if (!ipv6_enabled) {
+		g_object_set (s_ip6,
+			      NM_SETTING_IP_CONFIG_METHOD,
+			      NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL);
+		goto done;
+	} else if (!is_static_block) {
+		// config_eth* contains "dhcp6"
+		method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
+		never_default = FALSE;
+	}
+	// else if (!has_ip6_address(conn_name))
+	// doesn't have "dhcp6" && doesn't have any ipv6 address
+	// method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL;
+	else
+		// doesn't have "dhcp6" && has at least one ipv6 address
+		method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
+	nm_log_info (LOGD_SETTINGS, "IPv6 for %s enabled, using %s", conn_name, method);
+
+	g_object_set (s_ip6,
+		      NM_SETTING_IP_CONFIG_METHOD, method,
+		      NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, FALSE,
+		      NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, FALSE,
+		      NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default, NULL);
+
+	/* Make manual settings */
+	if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
+		ip_block *current_iblock;
+
+		iblock = convert_ip6_config_block (conn_name);
+		if (!iblock) {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				     "Ifnet plugin: can't aquire ip6 configuration for %s",
+				     conn_name);
+			goto error;
+		}
+		/* add all IPv6 addresses */
+		while (iblock) {
+			NMIPAddress *ip6_addr;
+			GError *local = NULL;
+
+			ip6_addr = nm_ip_address_new (AF_INET6, iblock->ip, iblock->prefix, &local);
+			if (ip6_addr) {
+				if (nm_setting_ip_config_add_address (s_ip6, ip6_addr)) {
+					nm_log_info (LOGD_SETTINGS, "ipv6 addresses count: %d",
+					             nm_setting_ip_config_get_num_addresses (s_ip6));
+				} else {
+					nm_log_warn (LOGD_SETTINGS, "ignoring duplicate IP6 address");
+				}
+				nm_ip_address_unref (ip6_addr);
+			} else {
+				nm_log_warn (LOGD_SETTINGS, "    ignoring invalid address entry: %s", local->message);
+				g_clear_error (&local);
+			}
+
+			current_iblock = iblock;
+			iblock = iblock->next;
+			destroy_ip_block (current_iblock);
+		}
+
+	} else if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) {
+		/* - autoconf or DHCPv6 stuff goes here */
+	}
+	// DNS Servers, set NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS TRUE here
+	set_ip6_dns_servers (s_ip6, conn_name);
+
+	/* DNS searches ('DOMAIN' key) are read by make_ip4_setting() and included in NMSettingIPConfig */
+
+	// Add routes
+	iblock = convert_ip6_routes_block (conn_name);
+	if (iblock)
+		g_object_set (s_ip6, NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES,
+			      TRUE, NULL);
+	/* Add all IPv6 routes */
+	while (iblock) {
+		ip_block *current_iblock = iblock;
+		const char *metric_str;
+		char *stripped;
+		gint64 metric;
+		NMIPRoute *route;
+		GError *local = NULL;
+
+		/* metric is not per routes configuration right now
+		 * global metric is also supported (metric="x") */
+		if ((metric_str = ifnet_get_data (conn_name, "metric")) != NULL)
+			metric = _nm_utils_ascii_str_to_int64 (metric_str, 10, 0, G_MAXUINT32, -1);
+		else {
+			metric_str = ifnet_get_global_data ("metric");
+			if (metric_str) {
+				stripped = g_strdup (metric_str);
+				strip_string (stripped, '"');
+				metric = _nm_utils_ascii_str_to_int64 (metric_str, 10, 0, G_MAXUINT32, -1);
+				g_free (stripped);
+			} else
+				metric = 1;
+		}
+
+		route = nm_ip_route_new (AF_INET6, iblock->ip, iblock->prefix, iblock->next_hop, metric, &local);
+		if (route) {
+			if (nm_setting_ip_config_add_route (s_ip6, route))
+				nm_log_info (LOGD_SETTINGS, "    new IP6 route");
+			else
+				nm_log_warn (LOGD_SETTINGS, "    duplicate IP6 route");
+			nm_ip_route_unref (route);
+		} else {
+			nm_log_warn (LOGD_SETTINGS, "    ignoring invalid route entry: %s", local->message);
+			g_clear_error (&local);
+		}
+
+		current_iblock = iblock;
+		iblock = iblock->next;
+		destroy_ip_block (current_iblock);
+	}
+
+done:
+	nm_connection_add_setting (connection, NM_SETTING (s_ip6));
+	return TRUE;
+
+error:
+	g_object_unref (s_ip6);
+	nm_log_warn (LOGD_SETTINGS, "    Ignore IPv6 for %s", conn_name);
+	return FALSE;
+}
+
+static NMSetting *
+make_wireless_connection_setting (const char *conn_name,
+                                  NMSetting8021x **s_8021x,
+                                  GError **error)
+{
+	const char *mac = NULL;
+	NMSettingWireless *wireless_setting = NULL;
+	gboolean adhoc = FALSE;
+	const char *value;
+	const char *type;
+
+	/* PPP over WIFI is not supported yet */
+	g_return_val_if_fail (conn_name != NULL
+			      && strcmp (ifnet_get_data (conn_name, "type"),
+					 "ppp") != 0, NULL);
+	type = ifnet_get_data (conn_name, "type");
+	if (strcmp (type, "ppp") == 0) {
+		nm_log_warn (LOGD_SETTINGS, "PPP over WIFI is not supported yet");
+		return NULL;
+	}
+
+	wireless_setting = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
+	if (read_mac_address (conn_name, &mac, error)) {
+		if (mac) {
+			g_object_set (wireless_setting,
+				      NM_SETTING_WIRELESS_MAC_ADDRESS, mac,
+				      NULL);
+		}
+	} else {
+		g_object_unref (wireless_setting);
+		return NULL;
+	}
+
+	/* handle ssid (hex and ascii) */
+	if (conn_name) {
+		GBytes *bytes;
+		gsize ssid_len = 0, value_len = strlen (conn_name);
+
+		ssid_len = value_len;
+		if ((value_len > 2) && (g_str_has_prefix (conn_name, "0x"))) {
+			/* Hex representation */
+			if (value_len % 2) {
+				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+					     "Invalid SSID '%s' size (looks like hex but length not multiple of 2)",
+					     conn_name);
+				goto error;
+			}
+
+			bytes = nm_utils_hexstr2bin (conn_name);
+			if (!bytes) {
+				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				             "Invalid SSID '%s' (looks like hex SSID but isn't)",
+				             conn_name);
+				goto error;
+			}
+		} else
+			bytes = g_bytes_new (conn_name, value_len);
+
+		ssid_len = g_bytes_get_size (bytes);
+		if (ssid_len > 32 || ssid_len == 0) {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				     "Invalid SSID '%s' (size %zu not between 1 and 32 inclusive)",
+				     conn_name, ssid_len);
+			goto error;
+		}
+
+		g_object_set (wireless_setting, NM_SETTING_WIRELESS_SSID, bytes, NULL);
+		g_bytes_unref (bytes);
+	} else {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing SSID");
+		goto error;
+	}
+
+	/* mode=0: infrastructure
+	 * mode=1: adhoc */
+	value = wpa_get_value (conn_name, "mode");
+	if (value)
+		adhoc = strcmp (value, "1") == 0 ? TRUE : FALSE;
+
+	if (exist_ssid (conn_name)) {
+		const char *mode = adhoc ? "adhoc" : "infrastructure";
+
+		g_object_set (wireless_setting, NM_SETTING_WIRELESS_MODE, mode,
+			      NULL);
+		nm_log_info (LOGD_SETTINGS, "Using mode: %s", mode);
+	}
+
+	/* BSSID setting */
+	value = wpa_get_value (conn_name, "bssid");
+	if (value) {
+		if (!nm_utils_hwaddr_valid (value, ETH_ALEN)) {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+						 "Invalid BSSID '%s'", value);
+			goto error;
+		}
+
+		g_object_set (wireless_setting, NM_SETTING_WIRELESS_BSSID,
+			      value, NULL);
+
+	}
+
+	/* mtu_ssid="xx" */
+	value = ifnet_get_data (conn_name, "mtu");
+	if (value) {
+		long int mtu;
+
+		errno = 0;
+		mtu = strtol (value, NULL, 10);
+		if (errno || mtu < 0 || mtu > 50000) {
+			nm_log_warn (LOGD_SETTINGS, "    invalid MTU '%s' for %s", value, conn_name);
+		} else
+			g_object_set (wireless_setting, NM_SETTING_WIRELESS_MTU,
+				      (guint32) mtu, NULL);
+
+	}
+
+	nm_log_info (LOGD_SETTINGS, "wireless_setting added for %s", conn_name);
+	return NM_SETTING (wireless_setting);
+error:
+	if (wireless_setting)
+		g_object_unref (wireless_setting);
+	return NULL;
+
+}
+
+static NMSettingWirelessSecurity *
+make_leap_setting (const char *ssid, GError **error)
+{
+	NMSettingWirelessSecurity *wsec;
+	const char *value;
+
+	wsec =
+	    NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
+
+	value = wpa_get_value (ssid, "password");
+	if (value && strlen (value))
+		g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD,
+			      value, NULL);
+
+	value = wpa_get_value (ssid, "identity");
+	if (!value || !strlen (value)) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing LEAP identity");
+		goto error;
+	}
+	g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, value,
+		      NULL);
+
+	g_object_set (wsec,
+		      NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
+		      NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", NULL);
+
+	return wsec;
+error:
+	if (wsec)
+		g_object_unref (wsec);
+	return NULL;
+}
+
+static gboolean
+add_one_wep_key (const char *ssid,
+                 const char *key,
+                 int key_idx,
+                 NMSettingWirelessSecurity *s_wsec,
+                 GError **error)
+{
+	const char *value;
+	char *converted = NULL;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail (ssid != NULL, FALSE);
+	g_return_val_if_fail (key != NULL, FALSE);
+	g_return_val_if_fail (key_idx >= 0 && key_idx <= 3, FALSE);
+	g_return_val_if_fail (s_wsec != NULL, FALSE);
+
+	value = wpa_get_value (ssid, key);
+	if (!value)
+		return TRUE;
+
+	/* Validate keys */
+	if (strlen (value) == 10 || strlen (value) == 26) {
+		/* Hexadecimal WEP key */
+		if (!is_hex (value)) {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			             "Invalid hexadecimal WEP key.");
+			goto out;
+		}
+		converted = g_strdup (value);
+	} else if (value[0] == '"'
+		   && (strlen (value) == 7 || strlen (value) == 15)) {
+		/* ASCII passphrase */
+		char *tmp = g_strdup (value);
+		char *p = strip_string (tmp, '"');
+
+		if (!is_ascii (p)) {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			             "Invalid ASCII WEP passphrase.");
+			g_free (tmp);
+			goto out;
+
+		}
+
+		converted = nm_utils_bin2hexstr (tmp, strlen (tmp), -1);
+		g_free (tmp);
+	} else {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Invalid WEP key length. Key: %s", value);
+		goto out;
+	}
+
+	if (converted) {
+		nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, converted);
+		g_free (converted);
+		success = TRUE;
+	}
+
+out:
+	return success;
+}
+
+static gboolean
+add_wep_keys (const char *ssid,
+              NMSettingWirelessSecurity *s_wsec,
+              GError **error)
+{
+	if (!add_one_wep_key (ssid, "wep_key0", 0, s_wsec, error))
+		return FALSE;
+	if (!add_one_wep_key (ssid, "wep_key1", 1, s_wsec, error))
+		return FALSE;
+	if (!add_one_wep_key (ssid, "wep_key2", 2, s_wsec, error))
+		return FALSE;
+	if (!add_one_wep_key (ssid, "wep_key3", 3, s_wsec, error))
+		return FALSE;
+	return TRUE;
+
+}
+
+static NMSettingWirelessSecurity *
+make_wep_setting (const char *ssid, GError **error)
+{
+	const char *auth_alg, *value;
+	int default_key_idx = 0;
+	NMSettingWirelessSecurity *s_wireless_sec;
+
+	s_wireless_sec =
+	    NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
+	g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
+		      "none", NULL);
+
+	/* default key index */
+	value = wpa_get_value (ssid, "wep_tx_keyidx");
+	if (value) {
+		default_key_idx = atoi (value);
+		if (default_key_idx >= 0 && default_key_idx <= 3) {
+			g_object_set (s_wireless_sec,
+				      NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX,
+				      default_key_idx, NULL);
+			nm_log_info (LOGD_SETTINGS, "Default key index: %d", default_key_idx);
+		} else {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				     "Invalid default WEP key '%s'", value);
+			goto error;
+		}
+	}
+
+	if (!add_wep_keys (ssid, s_wireless_sec, error))
+		goto error;
+
+	/* If there's a default key, ensure that key exists */
+	if ((default_key_idx == 1)
+	    && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 1)) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Default WEP key index was 2, but no valid KEY2 exists.");
+		goto error;
+	} else if ((default_key_idx == 2)
+		   && !nm_setting_wireless_security_get_wep_key (s_wireless_sec,
+								 2)) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Default WEP key index was 3, but no valid KEY3 exists.");
+		goto error;
+	} else if ((default_key_idx == 3)
+		   && !nm_setting_wireless_security_get_wep_key (s_wireless_sec,
+								 3)) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Default WEP key index was 4, but no valid KEY4 exists.");
+		goto error;
+	}
+
+	/* authentication algorithms */
+	auth_alg = wpa_get_value (ssid, "auth_alg");
+	if (auth_alg) {
+		if (strcmp (auth_alg, "OPEN") == 0) {
+			g_object_set (s_wireless_sec,
+				      NM_SETTING_WIRELESS_SECURITY_AUTH_ALG,
+				      "open", NULL);
+			nm_log_info (LOGD_SETTINGS, "WEP: Use open system authentication");
+		} else if (strcmp (auth_alg, "SHARED") == 0) {
+			g_object_set (s_wireless_sec,
+				      NM_SETTING_WIRELESS_SECURITY_AUTH_ALG,
+				      "shared", NULL);
+			nm_log_info (LOGD_SETTINGS, "WEP: Use shared system authentication");
+		} else {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				     "Invalid WEP authentication algorithm '%s'",
+				     auth_alg);
+			goto error;
+		}
+
+	}
+
+	if (!nm_setting_wireless_security_get_wep_key (s_wireless_sec, 0)
+	    && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 1)
+	    && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 2)
+	    && !nm_setting_wireless_security_get_wep_key (s_wireless_sec, 3)
+	    && !nm_setting_wireless_security_get_wep_tx_keyidx (s_wireless_sec)) {
+		if (auth_alg && !strcmp (auth_alg, "shared")) {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				     "WEP Shared Key authentication is invalid for "
+				     "unencrypted connections.");
+			goto error;
+		}
+		/* Unencrypted */
+		g_object_unref (s_wireless_sec);
+		s_wireless_sec = NULL;
+	}
+	return s_wireless_sec;
+
+error:
+	if (s_wireless_sec)
+		g_object_unref (s_wireless_sec);
+	return NULL;
+}
+
+static char *
+parse_wpa_psk (const char *psk, GError **error)
+{
+	char *hashed = NULL;
+	gboolean quoted = FALSE;
+
+	if (!psk) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing WPA_PSK for WPA-PSK key management");
+		return NULL;
+	}
+
+	/* Passphrase must be between 10 and 66 characters in length because WPA
+	 * hex keys are exactly 64 characters (no quoting), and WPA passphrases
+	 * are between 8 and 63 characters (inclusive), plus optional quoting if
+	 * the passphrase contains spaces.
+	 */
+
+	if (psk[0] == '"' && psk[strlen (psk) - 1] == '"')
+		quoted = TRUE;
+	if (!quoted && (strlen (psk) == 64)) {
+		/* Verify the hex PSK; 64 digits */
+		if (!is_hex (psk)) {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			             "Invalid WPA_PSK (contains non-hexadecimal characters)");
+			goto out;
+		}
+		hashed = g_strdup (psk);
+	} else {
+		char *stripped = g_strdup (psk);
+
+		strip_string (stripped, '"');
+
+		/* Length check */
+		if (strlen (stripped) < 8 || strlen (stripped) > 63) {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				     "Invalid WPA_PSK (passphrases must be between "
+				     "8 and 63 characters long (inclusive))");
+			g_free (stripped);
+			goto out;
+		}
+
+		hashed = g_strdup (stripped);
+		g_free (stripped);
+	}
+
+	if (!hashed) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Invalid WPA_PSK (doesn't look like a passphrase or hex key)");
+		goto out;
+	}
+
+out:
+	return hashed;
+}
+
+static gboolean
+fill_wpa_ciphers (const char *ssid,
+                  NMSettingWirelessSecurity *wsec,
+                  gboolean group,
+                  gboolean adhoc)
+{
+	const char *value;
+	char **list = NULL, **iter;
+	int i = 0;
+
+	value = wpa_get_value (ssid, group ? "group" : "pairwise");
+	if (!value)
+		return TRUE;
+
+	list = g_strsplit_set (value, " ", 0);
+	for (iter = list; iter && *iter; iter++, i++) {
+		/* Ad-Hoc configurations cannot have pairwise ciphers, and can only
+		 * have one group cipher.  Ignore any additional group ciphers and
+		 * any pairwise ciphers specified.
+		 */
+		if (adhoc) {
+			if (group && (i > 0)) {
+				nm_log_warn (LOGD_SETTINGS, "    ignoring group cipher '%s' (only one group cipher allowed in Ad-Hoc mode)",
+				             *iter);
+				continue;
+			} else if (!group) {
+				nm_log_warn (LOGD_SETTINGS, "    ignoring pairwise cipher '%s' (pairwise not used in Ad-Hoc mode)",
+				             *iter);
+				continue;
+			}
+		}
+
+		if (!strcmp (*iter, "CCMP")) {
+			if (group)
+				nm_setting_wireless_security_add_group (wsec,
+									"ccmp");
+			else
+				nm_setting_wireless_security_add_pairwise (wsec,
+									   "ccmp");
+		} else if (!strcmp (*iter, "TKIP")) {
+			if (group)
+				nm_setting_wireless_security_add_group (wsec,
+									"tkip");
+			else
+				nm_setting_wireless_security_add_pairwise (wsec,
+									   "tkip");
+		} else if (group && !strcmp (*iter, "WEP104"))
+			nm_setting_wireless_security_add_group (wsec, "wep104");
+		else if (group && !strcmp (*iter, "WEP40"))
+			nm_setting_wireless_security_add_group (wsec, "wep40");
+		else {
+			nm_log_warn (LOGD_SETTINGS, "    ignoring invalid %s cipher '%s'",
+			             group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE",
+			             *iter);
+		}
+	}
+
+	if (list)
+		g_strfreev (list);
+	return TRUE;
+}
+
+static NMSetting8021x *
+fill_8021x (const char *ssid,
+            const char *key_mgmt,
+            gboolean wifi,
+            const char *basepath,
+            GError **error)
+{
+	NMSetting8021x *s_8021x;
+	const char *value;
+	char **list, **iter;
+
+	value = wpa_get_value (ssid, "eap");
+	if (!value) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing IEEE_8021X_EAP_METHODS for key management '%s'",
+			     key_mgmt);
+		return NULL;
+	}
+
+	list = g_strsplit (value, " ", 0);
+
+	s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
+	/* Validate and handle each EAP method */
+	for (iter = list; iter && *iter; iter++) {
+		EAPReader *eap = &eap_readers[0];
+		gboolean found = FALSE;
+		char *lower = NULL;
+
+		lower = g_ascii_strdown (*iter, -1);
+		while (eap->method) {
+			if (strcmp (eap->method, lower))
+				goto next;
+
+			/* Some EAP methods don't provide keying material, thus they
+			 * cannot be used with WiFi unless they are an inner method
+			 * used with TTLS or PEAP or whatever.
+			 */
+			if (wifi && eap->wifi_phase2_only) {
+				nm_log_warn (LOGD_SETTINGS, "    ignored invalid IEEE_8021X_EAP_METHOD '%s'; not allowed for wifi.",
+				             lower);
+				goto next;
+			}
+
+			/* Parse EAP method specific options */
+			if (!(*eap->reader) (lower, ssid, s_8021x, FALSE, basepath, error)) {
+				g_free (lower);
+				goto error;
+			}
+			nm_setting_802_1x_add_eap_method (s_8021x, lower);
+			found = TRUE;
+			break;
+
+		next:
+			eap++;
+		}
+
+		if (!found) {
+			nm_log_warn (LOGD_SETTINGS, "    ignored unknown IEEE_8021X_EAP_METHOD '%s'.", lower);
+		}
+		g_free (lower);
+	}
+	g_strfreev (list);
+
+	if (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 0) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "No valid EAP methods found in IEEE_8021X_EAP_METHODS.");
+		goto error;
+	}
+
+	return s_8021x;
+
+error:
+	g_object_unref (s_8021x);
+	return NULL;
+}
+
+static NMSettingWirelessSecurity *
+make_wpa_setting (const char *ssid,
+                  const char *basepath,
+                  NMSetting8021x **s_8021x,
+                  GError **error)
+{
+	NMSettingWirelessSecurity *wsec;
+	const char *value;
+	char *lower;
+	gboolean adhoc = FALSE;
+
+	if (!exist_ssid (ssid)) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "No security info found for ssid: %s", ssid);
+		return NULL;
+	}
+
+	wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
+
+	/* mode=1: adhoc
+	 * mode=0: infrastructure */
+	value = wpa_get_value (ssid, "mode");
+	if (value)
+		adhoc = strcmp (value, "1") == 0 ? TRUE : FALSE;
+
+	/* Pairwise and Group ciphers */
+	fill_wpa_ciphers (ssid, wsec, FALSE, adhoc);
+	fill_wpa_ciphers (ssid, wsec, TRUE, adhoc);
+
+	/* WPA and/or RSN */
+	if (adhoc) {
+		/* Ad-Hoc mode only supports WPA proto for now */
+		nm_setting_wireless_security_add_proto (wsec, "wpa");
+	} else {
+		nm_setting_wireless_security_add_proto (wsec, "wpa");
+		nm_setting_wireless_security_add_proto (wsec, "rsn");
+
+	}
+
+	value = wpa_get_value (ssid, "key_mgmt");
+	if (!strcmp (value, "WPA-PSK")) {
+		char *psk = parse_wpa_psk (wpa_get_value (ssid, "psk"), error);
+
+		if (!psk)
+			goto error;
+		g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK, psk,
+			      NULL);
+		g_free (psk);
+
+		if (adhoc)
+			g_object_set (wsec,
+				      NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
+				      "wpa-none", NULL);
+		else
+			g_object_set (wsec,
+				      NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
+				      "wpa-psk", NULL);
+	} else if (!strcmp (value, "WPA-EAP") || !strcmp (value, "IEEE8021X")) {
+		if (adhoc) {
+			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+				     "Ad-Hoc mode cannot be used with KEY_MGMT type '%s'",
+				     value);
+			goto error;
+		}
+		*s_8021x = fill_8021x (ssid, value, TRUE, basepath, error);
+		if (!*s_8021x)
+			goto error;
+
+		lower = g_ascii_strdown (value, -1);
+		g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
+			      lower, NULL);
+		g_free (lower);
+	} else {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Unknown wireless KEY_MGMT type '%s'", value);
+		goto error;
+	}
+	return wsec;
+error:
+	if (wsec)
+		g_object_unref (wsec);
+	return NULL;
+}
+
+static NMSettingWirelessSecurity *
+make_wireless_security_setting (const char *conn_name,
+                                const char *basepath,
+                                NMSetting8021x **s_8021x,
+                                GError ** error)
+{
+	NMSettingWirelessSecurity *wsec = NULL;
+	const char *ssid;
+	gboolean adhoc = FALSE;
+	const char *value;
+
+	g_return_val_if_fail (conn_name != NULL
+			      && strcmp (ifnet_get_data (conn_name, "type"),
+					 "ppp") != 0, NULL);
+	nm_log_info (LOGD_SETTINGS, "updating wireless security settings (%s).", conn_name);
+
+	ssid = conn_name;
+	value = wpa_get_value (ssid, "mode");
+	if (value)
+		adhoc = strcmp (value, "1") == 0 ? TRUE : FALSE;
+
+	value = wpa_get_value (ssid, "key_mgmt");
+	if (!adhoc && g_strcmp0 (value, "IEEE8021X") == 0) {
+		value = wpa_get_value (ssid, "eap");
+		if (value && strcasecmp (value, "LEAP") == 0) {
+			wsec = make_leap_setting (ssid, error);
+			if (wsec == NULL)
+				goto error;
+		}
+	} else if (g_strcmp0 (value, "WPA-PSK") == 0 || g_strcmp0 (value, "WPA-EAP") == 0) {
+		wsec = make_wpa_setting (ssid, basepath, s_8021x, error);
+		if (wsec == NULL)
+			goto error;
+	}
+	if (!wsec) {
+		wsec = make_wep_setting (ssid, error);
+		if (wsec == NULL)
+			goto error;
+	}
+	return wsec;
+
+error:
+	g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+		     "Can't handle security information for ssid: %s",
+		     conn_name);
+	return NULL;
+}
+
+/* Currently only support username and password */
+static gboolean
+make_pppoe_connection_setting (NMConnection *connection,
+                               const char *conn_name,
+                               GError **error)
+{
+	NMSettingPppoe *s_pppoe;
+	NMSettingPpp *s_ppp;
+	const char *value;
+
+	s_pppoe = NM_SETTING_PPPOE (nm_setting_pppoe_new ());
+
+	/* username */
+	value = ifnet_get_data (conn_name, "username");
+	if (!value) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "ppp requires at lease a username");
+		return FALSE;
+	}
+	g_object_set (s_pppoe, NM_SETTING_PPPOE_USERNAME, value, NULL);
+
+	/* password */
+	value = ifnet_get_data (conn_name, "password");
+	if (!value) {
+		value = "";
+	}
+
+	g_object_set (s_pppoe, NM_SETTING_PPPOE_PASSWORD, value, NULL);
+	nm_connection_add_setting (connection, NM_SETTING (s_pppoe));
+
+	/* PPP setting */
+	s_ppp = (NMSettingPpp *) nm_setting_ppp_new ();
+	nm_connection_add_setting (connection, NM_SETTING (s_ppp));
+
+	return TRUE;
+}
+
+NMConnection *
+ifnet_update_connection_from_config_block (const char *conn_name,
+                                           const char *basepath,
+                                           GError **error)
+{
+	const gchar *type = NULL;
+	NMConnection *connection = NULL;
+	NMSettingConnection *setting = NULL;
+	NMSetting8021x *s_8021x = NULL;
+	NMSettingWirelessSecurity *wsec = NULL;
+	gboolean auto_conn = TRUE;
+	const char *value = NULL;
+	gchar *id, *uuid;
+	gboolean success = FALSE;
+
+	connection = nm_simple_connection_new ();
+	setting = nm_connection_get_setting_connection (connection);
+	if (!setting) {
+		setting = NM_SETTING_CONNECTION (nm_setting_connection_new ());
+		g_assert (setting);
+		nm_connection_add_setting (connection, NM_SETTING (setting));
+	}
+
+	type = guess_connection_type (conn_name);
+	value = ifnet_get_data (conn_name, "auto");
+	if (value && !strcmp (value, "false"))
+		auto_conn = FALSE;
+
+	/* Try to read UUID from the ifnet block, otherwise generate UUID from
+	 * the connection ID.
+	 */
+	id = connection_id_from_ifnet_name (conn_name);
+	uuid = g_strdup (ifnet_get_data (conn_name, "uuid"));
+	if (!uuid)
+		uuid = nm_utils_uuid_generate_from_string (id, -1, NM_UTILS_UUID_TYPE_LEGACY, NULL);
+
+	g_object_set (setting,
+	              NM_SETTING_CONNECTION_TYPE, type,
+	              NM_SETTING_CONNECTION_ID, id,
+	              NM_SETTING_CONNECTION_UUID, uuid,
+	              NM_SETTING_CONNECTION_INTERFACE_NAME, conn_name,
+	              NM_SETTING_CONNECTION_READ_ONLY, FALSE,
+	              NM_SETTING_CONNECTION_AUTOCONNECT, auto_conn,
+	              NULL);
+	nm_log_info (LOGD_SETTINGS, "name:%s, id:%s, uuid: %s", conn_name, id, uuid);
+	g_free (id);
+	g_free (uuid);
+
+	if (!strcmp (NM_SETTING_WIRED_SETTING_NAME, type)
+	    || !strcmp (NM_SETTING_PPPOE_SETTING_NAME, type)) {
+		/* wired setting */
+		if (!make_wired_connection_setting (connection, conn_name, error))
+			goto error;
+
+		/* pppoe setting */
+		if (!strcmp (NM_SETTING_PPPOE_SETTING_NAME, type)) {
+			if (!make_pppoe_connection_setting (connection, conn_name, error))
+				goto error;
+		}
+	} else if (!strcmp (NM_SETTING_WIRELESS_SETTING_NAME, type)) {
+		/* wireless setting */
+		NMSetting *wireless_setting;
+
+		wireless_setting = make_wireless_connection_setting (conn_name, &s_8021x, error);
+		if (!wireless_setting)
+			goto error;
+		nm_connection_add_setting (connection, wireless_setting);
+
+		/* wireless security setting */
+		if (wpa_get_value (conn_name, "ssid")) {
+			wsec = make_wireless_security_setting (conn_name, basepath, &s_8021x, error);
+			if (!wsec)
+				goto error;
+			nm_connection_add_setting (connection, NM_SETTING (wsec));
+			if (s_8021x)
+				nm_connection_add_setting (connection, NM_SETTING (s_8021x));
+		}
+	} else
+		goto error;
+
+	/* IPv4 setting */
+	if (!make_ip4_setting (connection, conn_name, error))
+		goto error;
+
+	/* IPv6 setting */
+	if (!make_ip6_setting (connection, conn_name, error))
+		goto error;
+
+	if (nm_connection_verify (connection, error)) {
+		nm_log_info (LOGD_SETTINGS, "Connection verified %s:%d", conn_name, success);
+	} else {
+		goto error;
+	}
+
+	return connection;
+error:
+	g_object_unref (connection);
+	return NULL;
+}
+
+typedef struct Setting8021xSchemeVtable {
+	const NMSetting8021xSchemeVtable *vtable;
+	const char *ifnet_key;
+} Setting8021xSchemeVtable;
+
+static const Setting8021xSchemeVtable setting_8021x_scheme_vtable[] = {
+	[NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT] = {
+		.vtable                 = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT],
+		.ifnet_key              = "ca_cert",
+	},
+	[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT] = {
+		.vtable                 = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT],
+		.ifnet_key              = "ca_cert2",
+	},
+	[NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT] = {
+		.vtable                 = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT],
+		.ifnet_key              = "client_cert",
+	},
+	[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT] = {
+		.vtable                 = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT],
+		.ifnet_key              = "client_cert2",
+	},
+	[NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY] = {
+		.vtable                 = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY],
+		.ifnet_key              = "private_key",
+	},
+	[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY] = {
+		.vtable                 = &nm_setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY],
+		.ifnet_key              = "private_key2",
+	},
+};
+
+static gboolean
+write_object (NMSetting8021x *s_8021x,
+              const char *conn_name,
+              GBytes *override_data,
+              const Setting8021xSchemeVtable *objtype,
+              GError **error)
+{
+	NMSetting8021xCKScheme scheme;
+	const char *path = NULL;
+	GBytes *blob = NULL;
+
+	g_return_val_if_fail (conn_name != NULL, FALSE);
+	g_return_val_if_fail (objtype != NULL, FALSE);
+	if (override_data)
+		/* if given explicit data to save, always use that instead of asking
+		 * the setting what to do.
+		 */
+		blob = override_data;
+	else {
+		scheme = (*(objtype->vtable->scheme_func)) (s_8021x);
+		switch (scheme) {
+		case NM_SETTING_802_1X_CK_SCHEME_BLOB:
+			blob = (*(objtype->vtable->blob_func)) (s_8021x);
+			break;
+		case NM_SETTING_802_1X_CK_SCHEME_PATH:
+			path = (*(objtype->vtable->path_func)) (s_8021x);
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* If the object path was specified, prefer that over any raw cert data that
+	 * may have been sent.
+	 */
+	if (path) {
+		wpa_set_data (conn_name, (gchar *) objtype->ifnet_key,
+		              (gchar *) path);
+		return TRUE;
+	}
+
+	/* does not support writing encryption data now */
+	if (blob)
+		nm_log_warn (LOGD_SETTINGS, "    Currently we do not support cert writing.");
+
+	return TRUE;
+}
+
+static gboolean
+write_8021x_certs (NMSetting8021x *s_8021x,
+                   gboolean phase2,
+                   const char *conn_name,
+                   GError **error)
+{
+	char *password = NULL;
+	const Setting8021xSchemeVtable *otype = NULL;
+	gboolean is_pkcs12 = FALSE, success = FALSE;
+	GBytes *blob = NULL;
+	GBytes *enc_key = NULL;
+	gchar *generated_pw = NULL;
+
+	/* CA certificate */
+	otype = phase2
+	        ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT]
+	        : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT];
+
+	if (!write_object (s_8021x, conn_name, NULL, otype, error))
+		return FALSE;
+
+	/* Private key */
+	if (phase2) {
+		if (nm_setting_802_1x_get_phase2_private_key_scheme (s_8021x) !=
+		    NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) {
+			if (nm_setting_802_1x_get_phase2_private_key_format
+			    (s_8021x) == NM_SETTING_802_1X_CK_FORMAT_PKCS12)
+				is_pkcs12 = TRUE;
+		}
+		password = (char *)
+		    nm_setting_802_1x_get_phase2_private_key_password (s_8021x);
+	} else {
+		if (nm_setting_802_1x_get_private_key_scheme (s_8021x) !=
+		    NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) {
+			if (nm_setting_802_1x_get_private_key_format (s_8021x)
+			    == NM_SETTING_802_1X_CK_FORMAT_PKCS12)
+				is_pkcs12 = TRUE;
+		}
+		password = (char *)
+		    nm_setting_802_1x_get_private_key_password (s_8021x);
+	}
+
+	otype = phase2
+	        ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY]
+	        : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY];
+
+	if ((*(otype->vtable->scheme_func)) (s_8021x) ==
+	    NM_SETTING_802_1X_CK_SCHEME_BLOB)
+		blob = (*(otype->vtable->blob_func)) (s_8021x);
+
+	/* Only do the private key re-encrypt dance if we got the raw key data, which
+	 * by definition will be unencrypted.  If we're given a direct path to the
+	 * private key file, it'll be encrypted, so we don't need to re-encrypt.
+	 */
+	if (blob && !is_pkcs12) {
+		GByteArray *tmp_enc_key;
+
+		/* Encrypt the unencrypted private key with the fake password */
+		tmp_enc_key =
+		    nm_utils_rsa_key_encrypt (g_bytes_get_data (blob, NULL), g_bytes_get_size (blob),
+		                              password, &generated_pw, error);
+		if (!tmp_enc_key)
+			goto out;
+
+		enc_key = g_byte_array_free_to_bytes (tmp_enc_key);
+
+		if (generated_pw)
+			password = generated_pw;
+	}
+
+	/* Save the private key */
+	if (!write_object
+	    (s_8021x, conn_name, enc_key ? enc_key : blob, otype, error))
+		goto out;
+
+	if (phase2)
+		wpa_set_data (conn_name, "private_key2_passwd", password);
+	else
+		wpa_set_data (conn_name, "private_key_passwd", password);
+
+	/* Client certificate */
+	if (is_pkcs12) {
+		wpa_set_data (conn_name,
+		              phase2 ? "client_cert2" : "client_cert", NULL);
+	} else {
+		otype = phase2
+		        ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT]
+		        : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT];
+
+		/* Save the client certificate */
+		if (!write_object (s_8021x, conn_name, NULL, otype, error))
+			goto out;
+	}
+
+	success = TRUE;
+out:
+	if (generated_pw) {
+		memset (generated_pw, 0, strlen (generated_pw));
+		g_free (generated_pw);
+	}
+	if (enc_key) {
+		memset ((gpointer) g_bytes_get_data (enc_key, NULL), 0, g_bytes_get_size (enc_key));
+		g_bytes_unref (enc_key);
+	}
+	return success;
+}
+
+static gboolean
+write_8021x_setting (NMConnection *connection,
+                     const char *conn_name,
+                     gboolean wired,
+                     GError **error)
+{
+	NMSetting8021x *s_8021x;
+	const char *value;
+	char *tmp = NULL;
+	gboolean success = FALSE;
+	GString *phase2_auth;
+	GString *phase1;
+
+	s_8021x = nm_connection_get_setting_802_1x (connection);
+	if (!s_8021x) {
+		return TRUE;
+	}
+
+	nm_log_info (LOGD_SETTINGS, "Adding 8021x setting for %s", conn_name);
+
+	/* If wired, write KEY_MGMT */
+	if (wired)
+		wpa_set_data (conn_name, "key_mgmt", "IEEE8021X");
+
+	/* EAP method */
+	if (nm_setting_802_1x_get_num_eap_methods (s_8021x)) {
+		value = nm_setting_802_1x_get_eap_method (s_8021x, 0);
+		if (value)
+			tmp = g_ascii_strup (value, -1);
+	}
+	wpa_set_data (conn_name, "eap", tmp ? tmp : NULL);
+	g_free (tmp);
+
+	wpa_set_data (conn_name, "identity",
+		      (gchar *) nm_setting_802_1x_get_identity (s_8021x));
+
+	wpa_set_data (conn_name, "anonymous_identity", (gchar *)
+		      nm_setting_802_1x_get_anonymous_identity (s_8021x));
+
+	wpa_set_data (conn_name, "password",
+		      (gchar *) nm_setting_802_1x_get_password (s_8021x));
+
+	phase1 = g_string_new (NULL);
+
+	/* PEAP version */
+	wpa_set_data (conn_name, "phase1", NULL);
+	value = nm_setting_802_1x_get_phase1_peapver (s_8021x);
+	if (value && (!strcmp (value, "0") || !strcmp (value, "1")))
+		g_string_append_printf (phase1, "peapver=%s ", value);
+
+	/* PEAP label */
+	value = nm_setting_802_1x_get_phase1_peaplabel (s_8021x);
+	if (value && !strcmp (value, "1"))
+		g_string_append_printf (phase1, "peaplabel=%s ", value);
+	if (phase1->len) {
+		tmp = g_strstrip (g_strdup (phase1->str));
+		wpa_set_data (conn_name, "phase1", tmp);
+		g_free (tmp);
+	}
+
+	/* Phase2 auth methods */
+	wpa_set_data (conn_name, "phase2", NULL);
+	phase2_auth = g_string_new (NULL);
+
+	value = nm_setting_802_1x_get_phase2_auth (s_8021x);
+	if (value) {
+		tmp = g_ascii_strup (value, -1);
+		g_string_append_printf (phase2_auth, "auth=%s ", tmp);
+		g_free (tmp);
+	}
+
+	/* Phase2 auth heap */
+	value = nm_setting_802_1x_get_phase2_autheap (s_8021x);
+	if (value) {
+		tmp = g_ascii_strup (value, -1);
+		g_string_append_printf (phase2_auth, "autheap=%s ", tmp);
+		g_free (tmp);
+	}
+	tmp = g_strstrip (g_strdup (phase2_auth->str));
+	wpa_set_data (conn_name, "phase2", phase2_auth->len ? tmp : NULL);
+	g_free (tmp);
+
+	g_string_free (phase2_auth, TRUE);
+	g_string_free (phase1, TRUE);
+
+	success = write_8021x_certs (s_8021x, FALSE, conn_name, error);
+	if (success) {
+		/* phase2/inner certs */
+		success = write_8021x_certs (s_8021x, TRUE, conn_name, error);
+	}
+
+	return success;
+}
+
+static gboolean
+write_wireless_security_setting (NMConnection * connection,
+				 gchar * conn_name,
+				 gboolean adhoc,
+				 gboolean * no_8021x, GError ** error)
+{
+	NMSettingWirelessSecurity *s_wsec;
+	const char *key_mgmt, *auth_alg, *key, *cipher, *psk;
+	gboolean wep = FALSE, wpa = FALSE;
+	char *tmp;
+	guint32 i, num;
+	GString *str;
+
+	s_wsec = nm_connection_get_setting_wireless_security (connection);
+	if (!s_wsec) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing '%s' setting",
+			     NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
+		return FALSE;
+	}
+
+	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
+	g_assert (key_mgmt);
+
+	auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
+
+	if (!strcmp (key_mgmt, "none")) {
+		wpa_set_data (conn_name, "key_mgmt", "NONE");
+		wep = TRUE;
+		*no_8021x = TRUE;
+	} else if (!strcmp (key_mgmt, "wpa-none")
+		   || !strcmp (key_mgmt, "wpa-psk")) {
+		wpa_set_data (conn_name, "key_mgmt", "WPA-PSK");
+		wpa = TRUE;
+		*no_8021x = TRUE;
+	} else if (!strcmp (key_mgmt, "ieee8021x")) {
+		wpa_set_data (conn_name, "key_mgmt", "IEEE8021X");
+	} else if (!strcmp (key_mgmt, "wpa-eap")) {
+		wpa_set_data (conn_name, "key_mgmt", "WPA-EAP");
+		wpa = TRUE;
+	} else
+		nm_log_warn (LOGD_SETTINGS, "Unknown key_mgmt: %s", key_mgmt);
+
+	if (auth_alg) {
+		if (!strcmp (auth_alg, "shared"))
+			wpa_set_data (conn_name, "auth_alg", "SHARED");
+		else if (!strcmp (auth_alg, "open"))
+			wpa_set_data (conn_name, "auth_alg", "OPEN");
+		else if (!strcmp (auth_alg, "leap")) {
+			wpa_set_data (conn_name, "auth_alg", "LEAP");
+			wpa_set_data (conn_name, "eap", "LEAP");
+			wpa_set_data (conn_name, "identity", (gchar *)
+				      nm_setting_wireless_security_get_leap_username
+				      (s_wsec));
+			wpa_set_data (conn_name, "password", (gchar *)
+				      nm_setting_wireless_security_get_leap_password
+				      (s_wsec));
+			*no_8021x = TRUE;
+		}
+	} else
+		wpa_set_data (conn_name, "auth_alg", NULL);
+
+	/* Default WEP TX key index */
+	if (wep) {
+		tmp =
+		    g_strdup_printf ("%d",
+				     nm_setting_wireless_security_get_wep_tx_keyidx
+				     (s_wsec));
+		wpa_set_data (conn_name, "wep_tx_keyidx", tmp);
+		g_free (tmp);
+	} else
+		wpa_set_data (conn_name, "wep_tx_keyidx", NULL);
+
+	/* WEP keys */
+	for (i = 0; i < 4; i++) {
+		int length;
+
+		key = nm_setting_wireless_security_get_wep_key (s_wsec, i);
+		if (!key)
+			continue;
+		tmp = g_strdup_printf ("wep_key%d", i);
+		length = strlen (key);
+		if (length == 10 || length == 26 || length == 58)
+			wpa_set_data (conn_name, tmp, (gchar *) key);
+		else {
+			gchar *tmp_key = g_strdup_printf ("\"%s\"", key);
+
+			wpa_set_data (conn_name, tmp, tmp_key);
+			g_free (tmp_key);
+		}
+		g_free (tmp);
+	}
+
+	/* WPA Pairwise ciphers */
+	wpa_set_data (conn_name, "pairwise", NULL);
+	str = g_string_new (NULL);
+	num = nm_setting_wireless_security_get_num_pairwise (s_wsec);
+	for (i = 0; i < num; i++) {
+		if (i > 0)
+			g_string_append_c (str, ' ');
+		cipher = nm_setting_wireless_security_get_pairwise (s_wsec, i);
+		tmp = g_ascii_strup (cipher, -1);
+		g_string_append (str, tmp);
+		g_free (tmp);
+	}
+	if (strlen (str->str))
+		wpa_set_data (conn_name, "pairwise", str->str);
+	g_string_free (str, TRUE);
+
+	/* WPA Group ciphers */
+	wpa_set_data (conn_name, "group", NULL);
+	str = g_string_new (NULL);
+	num = nm_setting_wireless_security_get_num_groups (s_wsec);
+	for (i = 0; i < num; i++) {
+		if (i > 0)
+			g_string_append_c (str, ' ');
+		cipher = nm_setting_wireless_security_get_group (s_wsec, i);
+		tmp = g_ascii_strup (cipher, -1);
+		g_string_append (str, tmp);
+		g_free (tmp);
+	}
+	if (strlen (str->str))
+		wpa_set_data (conn_name, "group", str->str);
+	g_string_free (str, TRUE);
+
+	/* WPA Passphrase */
+	if (wpa) {
+		GString *quoted = NULL;
+
+		psk = nm_setting_wireless_security_get_psk (s_wsec);
+		if (psk && (strlen (psk) != 64)) {
+			quoted = g_string_sized_new (strlen (psk) + 2);
+			g_string_append_c (quoted, '"');
+			g_string_append (quoted, psk);
+			g_string_append_c (quoted, '"');
+		}
+		/* psk will be lost here if we don't check it for NULL */
+		if (psk)
+			wpa_set_data (conn_name, "psk",
+					  quoted ? quoted->str : (gchar *) psk);
+		if (quoted)
+			g_string_free (quoted, TRUE);
+	} else
+		wpa_set_data (conn_name, "psk", NULL);
+
+	return TRUE;
+}
+
+/* remove old ssid and add new one*/
+static void
+update_wireless_ssid (NMConnection *connection,
+                      const char *conn_name,
+                      const char *ssid,
+                      gboolean hex)
+{
+	if(strcmp (conn_name, ssid)){
+		ifnet_delete_network (conn_name);
+		wpa_delete_security (conn_name);
+	}
+
+	ifnet_add_network (ssid, "wireless");
+	wpa_add_security (ssid);
+}
+
+static gboolean
+write_wireless_setting (NMConnection *connection,
+                        const char *conn_name,
+                        gboolean *no_8021x,
+                        const char **out_new_name,
+                        GError **error)
+{
+	NMSettingWireless *s_wireless;
+	GBytes *ssid;
+	const guint8 *ssid_data;
+	gsize ssid_len;
+	const char *mac, *bssid, *mode;
+	char buf[33];
+	guint32 mtu, i;
+	gboolean adhoc = FALSE, hex_ssid = FALSE;
+	gchar *ssid_str, *tmp;
+
+	s_wireless = nm_connection_get_setting_wireless (connection);
+	if (!s_wireless) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing '%s' setting",
+			     NM_SETTING_WIRELESS_SETTING_NAME);
+		return FALSE;
+	}
+
+	ssid = nm_setting_wireless_get_ssid (s_wireless);
+	if (!ssid) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing SSID in '%s' setting",
+			     NM_SETTING_WIRELESS_SETTING_NAME);
+		return FALSE;
+	}
+	ssid_data = g_bytes_get_data (ssid, &ssid_len);
+	if (!ssid_len || ssid_len > 32) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Invalid SSID in '%s' setting",
+			     NM_SETTING_WIRELESS_SETTING_NAME);
+		return FALSE;
+	}
+
+	/* If the SSID contains any non-alnum characters, we need to use
+	 * the hex notation of the SSID instead. (Because openrc doesn't
+	 * support these characters, see bug #356337)
+	 */
+	for (i = 0; i < ssid_len; i++) {
+		if (!g_ascii_isalnum (ssid_data[i])) {
+			hex_ssid = TRUE;
+			break;
+		}
+	}
+
+	if (hex_ssid) {
+		GString *str;
+
+		/* Hex SSIDs don't get quoted */
+		str = g_string_sized_new (ssid_len * 2 + 3);
+		g_string_append (str, "0x");
+		for (i = 0; i < ssid_len; i++)
+			g_string_append_printf (str, "%02X", ssid_data[i]);
+		update_wireless_ssid (connection, conn_name, str->str, hex_ssid);
+		ssid_str = g_string_free (str, FALSE);
+	} else {
+		/* Printable SSIDs get quoted */
+		memset (buf, 0, sizeof (buf));
+		memcpy (buf, ssid_data, ssid_len);
+		g_strstrip (buf);
+		update_wireless_ssid (connection, conn_name, buf, hex_ssid);
+		ssid_str = g_strdup (buf);
+	}
+
+	ifnet_set_data (ssid_str, "mac", NULL);
+	mac = nm_setting_wireless_get_mac_address (s_wireless);
+	if (mac)
+		ifnet_set_data (ssid_str, "mac", mac);
+
+	ifnet_set_data (ssid_str, "mtu", NULL);
+	mtu = nm_setting_wireless_get_mtu (s_wireless);
+	if (mtu) {
+		tmp = g_strdup_printf ("%u", mtu);
+		ifnet_set_data (ssid_str, "mtu", tmp);
+		g_free (tmp);
+	}
+
+	ifnet_set_data (ssid_str, "mode", NULL);
+	mode = nm_setting_wireless_get_mode (s_wireless);
+	if (!mode || !strcmp (mode, "infrastructure")) {
+		wpa_set_data (ssid_str, "mode", "0");
+	} else if (!strcmp (mode, "adhoc")) {
+		wpa_set_data (ssid_str, "mode", "1");
+		adhoc = TRUE;
+	} else {
+		nm_log_warn (LOGD_SETTINGS, "Invalid mode '%s' in '%s' setting",
+		             mode, NM_SETTING_WIRELESS_SETTING_NAME);
+		return FALSE;
+	}
+
+	wpa_set_data (ssid_str, "bssid", NULL);
+	bssid = nm_setting_wireless_get_bssid (s_wireless);
+	if (bssid)
+		wpa_set_data (ssid_str, "bssid", bssid);
+
+	if (nm_connection_get_setting_wireless_security (connection)) {
+		if (!write_wireless_security_setting
+		    (connection, ssid_str, adhoc, no_8021x, error))
+			return FALSE;
+	} else
+		wpa_delete_security (ssid_str);
+
+	if (out_new_name)
+		*out_new_name = ifnet_get_data (ssid_str, "name");
+	g_free (ssid_str);
+	return TRUE;
+}
+
+static gboolean
+write_wired_setting (NMConnection *connection,
+                     const char *conn_name,
+                     GError **error)
+{
+	NMSettingWired *s_wired;
+	const char *mac;
+	char *tmp;
+	guint32 mtu;
+
+	s_wired = nm_connection_get_setting_wired (connection);
+	if (!s_wired) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing '%s' setting",
+			     NM_SETTING_WIRED_SETTING_NAME);
+		return FALSE;
+	}
+
+	ifnet_set_data (conn_name, "mac", NULL);
+	mac = nm_setting_wired_get_mac_address (s_wired);
+	if (mac)
+		ifnet_set_data (conn_name, "mac", mac);
+
+	ifnet_set_data (conn_name, "mtu", NULL);
+	mtu = nm_setting_wired_get_mtu (s_wired);
+	if (mtu) {
+		tmp = g_strdup_printf ("%u", mtu);
+		ifnet_set_data (conn_name, "mtu", tmp);
+		g_free (tmp);
+	}
+	//FIXME may add connection type in future
+	//ifnet_set_data (conn_name, "TYPE", TYPE_ETHERNET);
+
+	return TRUE;
+}
+
+static gboolean
+write_ip4_setting (NMConnection *connection, const char *conn_name, GError **error)
+{
+	NMSettingIPConfig *s_ip4;
+	const char *value;
+	guint32 i, num;
+	GString *searches;
+	GString *ips;
+	GString *routes;
+	GString *dns;
+	gboolean success = FALSE;
+
+	s_ip4 = nm_connection_get_setting_ip4_config (connection);
+	if (!s_ip4) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing '%s' setting",
+			     NM_SETTING_IP4_CONFIG_SETTING_NAME);
+		return FALSE;
+	}
+	routes = g_string_new (NULL);
+
+	value = nm_setting_ip_config_get_method (s_ip4);
+	g_assert (value);
+	if (!strcmp (value, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
+
+		num = nm_setting_ip_config_get_num_addresses (s_ip4);
+		ips = g_string_new (NULL);
+		/* IPv4 addresses */
+		for (i = 0; i < num; i++) {
+			NMIPAddress *addr;
+
+			addr = nm_setting_ip_config_get_address (s_ip4, i);
+
+			g_string_append_printf (ips, "\"%s/%u",
+			                        nm_ip_address_get_address (addr),
+			                        nm_ip_address_get_prefix (addr));
+
+			/* only the first gateway will be written */
+			if (i == 0 && nm_setting_ip_config_get_gateway (s_ip4)) {
+				g_string_append_printf (routes,
+				                        "\"default via %s\" ",
+				                        nm_setting_ip_config_get_gateway (s_ip4));
+			}
+		}
+		ifnet_set_data (conn_name, "config", ips->str);
+		g_string_free (ips, TRUE);
+	} else if (!strcmp (value, NM_SETTING_IP4_CONFIG_METHOD_SHARED))
+		ifnet_set_data (conn_name, "config", "shared");
+	else if (!strcmp (value, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL))
+		ifnet_set_data (conn_name, "config", "autoip");
+	else
+		ifnet_set_data (conn_name, "config", "dhcp");
+
+	/* DNS Servers */
+	num = nm_setting_ip_config_get_num_dns (s_ip4);
+	if (num > 0) {
+		dns = g_string_new (NULL);
+		for (i = 0; i < num; i++) {
+			const char *ip;
+
+			ip = nm_setting_ip_config_get_dns (s_ip4, i);
+			g_string_append_printf (dns, " %s", ip);
+		}
+		ifnet_set_data (conn_name, "dns_servers", dns->str);
+		g_string_free (dns, TRUE);
+	} else
+		ifnet_set_data (conn_name, "dns_servers", NULL);
+
+	/* DNS Searches */
+	num = nm_setting_ip_config_get_num_dns_searches (s_ip4);
+	if (num > 0) {
+		searches = g_string_new (NULL);
+		for (i = 0; i < num; i++) {
+			if (i > 0)
+				g_string_append_c (searches, ' ');
+			g_string_append (searches,
+					 nm_setting_ip_config_get_dns_search
+					 (s_ip4, i));
+		}
+		ifnet_set_data (conn_name, "dns_search", searches->str);
+		g_string_free (searches, TRUE);
+	} else
+		ifnet_set_data (conn_name, "dns_search", NULL);
+	/* FIXME Will be implemented when configuration supports it
+	   if (!strcmp(value, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
+	   value = nm_setting_ip_config_get_dhcp_hostname(s_ip4);
+	   if (value)
+	   ifnet_set_data(conn_name, "DHCP_HOSTNAME", value,
+	   FALSE);
+
+	   value = nm_setting_ip_config_get_dhcp_client_id(s_ip4);
+	   if (value)
+	   ifnet_set_data(conn_name, "DHCP_CLIENT_ID", value,
+	   FALSE);
+	   }
+	 */
+
+	/* Static routes */
+	num = nm_setting_ip_config_get_num_routes (s_ip4);
+	if (num > 0) {
+		for (i = 0; i < num; i++) {
+			NMIPRoute *route;
+			const char *next_hop;
+
+			route = nm_setting_ip_config_get_route (s_ip4, i);
+
+			next_hop = nm_ip_route_get_next_hop (route);
+			if (!next_hop)
+				next_hop = "0.0.0.0";
+
+			g_string_append_printf (routes, "\"%s/%u via %s\" ",
+			                        nm_ip_route_get_dest (route),
+			                        nm_ip_route_get_prefix (route),
+			                        next_hop);
+		}
+	}
+	if (routes->len > 0)
+		ifnet_set_data (conn_name, "routes", routes->str);
+	else
+		ifnet_set_data (conn_name, "routes", NULL);
+	g_string_free (routes, TRUE);
+
+	success = TRUE;
+
+	return success;
+}
+
+static void
+write_route6_file (NMSettingIPConfig *s_ip6, const char *conn_name)
+{
+	NMIPRoute *route;
+	const char *next_hop;
+	guint32 i, num;
+	GString *routes_string;
+	const char *old_routes;
+
+	g_return_if_fail (s_ip6 != NULL);
+	num = nm_setting_ip_config_get_num_routes (s_ip6);
+	if (num == 0)
+		return;
+
+	old_routes = ifnet_get_data (conn_name, "routes");
+	routes_string = g_string_new (old_routes);
+	if (old_routes)
+		g_string_append (routes_string, "\" ");
+	for (i = 0; i < num; i++) {
+		route = nm_setting_ip_config_get_route (s_ip6, i);
+
+		next_hop = nm_ip_route_get_next_hop (route);
+		if (!next_hop)
+			next_hop = "::";
+
+		g_string_append_printf (routes_string, "\"%s/%u via %s\" ",
+		                        nm_ip_route_get_dest (route),
+		                        nm_ip_route_get_prefix (route),
+		                        next_hop);
+	}
+	if (num > 0)
+		ifnet_set_data (conn_name, "routes", routes_string->str);
+	g_string_free (routes_string, TRUE);
+}
+
+static gboolean
+write_ip6_setting (NMConnection *connection, const char *conn_name, GError **error)
+{
+	NMSettingIPConfig *s_ip6;
+	const char *value;
+	guint32 i, num;
+	GString *searches;
+	NMIPAddress *addr;
+
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
+	if (!s_ip6) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing '%s' setting",
+			     NM_SETTING_IP6_CONFIG_SETTING_NAME);
+		return FALSE;
+	}
+
+	value = nm_setting_ip_config_get_method (s_ip6);
+	g_assert (value);
+	if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) {
+		ifnet_set_data (conn_name, "enable_ipv6", "false");
+		return TRUE;
+	} else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
+		/* nothing to do now */
+	} else {
+		// if (!strcmp(value, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) {
+		const char *config = ifnet_get_data (conn_name, "config");
+		gchar *tmp;
+
+		if (!config)
+			tmp = g_strdup_printf ("dhcp6");
+		else
+			tmp = g_strdup_printf ("%s\" \"dhcp6\"", config);
+		ifnet_set_data (conn_name, "config", tmp);
+		g_free (tmp);
+	}
+	/* else if (!strcmp(value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
+	   } else if (!strcmp(value, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) {
+	   } else if (!strcmp(value, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) {
+	   } */
+
+	/* Remember to set IPv6 enabled */
+	ifnet_set_data (conn_name, "enable_ipv6", "true");
+
+	if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
+		const char *config = ifnet_get_data (conn_name, "config");
+		gchar *tmp;
+		GString *ip_str;
+
+		if (!config)
+			config = "";
+		num = nm_setting_ip_config_get_num_addresses (s_ip6);
+
+		/* IPv6 addresses */
+		ip_str = g_string_new (NULL);
+		for (i = 0; i < num; i++) {
+			addr = nm_setting_ip_config_get_address (s_ip6, i);
+
+			g_string_append_printf (ip_str, "\"%s/%u\"",
+			                        nm_ip_address_get_address (addr),
+			                        nm_ip_address_get_prefix (addr));
+		}
+		tmp = g_strdup_printf ("%s\" %s", config, ip_str->str);
+		ifnet_set_data (conn_name, "config", tmp);
+		g_free (tmp);
+		g_string_free (ip_str, TRUE);
+	}
+
+	/* DNS Servers */
+	num = nm_setting_ip_config_get_num_dns (s_ip6);
+	if (num > 0) {
+		const char *dns_servers = ifnet_get_data (conn_name, "dns_servers");
+		gchar *tmp;
+		GString *dns_string = g_string_new (NULL);
+		const char *dns;
+
+		if (!dns_servers)
+			dns_servers = "";
+		for (i = 0; i < num; i++) {
+			dns = nm_setting_ip_config_get_dns (s_ip6, i);
+
+			if (!strstr (dns_servers, dns))
+				g_string_append_printf (dns_string, "%s ", dns);
+		}
+		tmp = g_strdup_printf ("%s %s", dns_servers, dns_string->str);
+		ifnet_set_data (conn_name, "dns_servers", tmp);
+		g_free (tmp);
+		g_string_free (dns_string, TRUE);
+
+	} else
+		/* DNS Searches */
+		num = nm_setting_ip_config_get_num_dns_searches (s_ip6);
+	if (num > 0) {
+		const char *ip4_domains;
+
+		ip4_domains = ifnet_get_data (conn_name, "dns_search");
+		if (!ip4_domains)
+			ip4_domains = "";
+		searches = g_string_new (ip4_domains);
+		for (i = 0; i < num; i++) {
+			const gchar *search = NULL;
+
+			search =
+			    nm_setting_ip_config_get_dns_search (s_ip6, i);
+			if (search && !strstr (searches->str, search)) {
+				if (searches->len > 0)
+					g_string_append_c (searches, ' ');
+				g_string_append (searches, search);
+			}
+		}
+		ifnet_set_data (conn_name, "dns_search", searches->str);
+		g_string_free (searches, TRUE);
+	}
+
+	write_route6_file (s_ip6, conn_name);
+	return TRUE;
+}
+
+static gboolean
+write_pppoe_setting (const char *conn_name, NMSettingPppoe * s_pppoe)
+{
+	const gchar *value;
+
+	value = nm_setting_pppoe_get_username (s_pppoe);
+	if (!value) {
+		return FALSE;
+	}
+	ifnet_set_data (conn_name, "username", (gchar *) value);
+
+	value = nm_setting_pppoe_get_password (s_pppoe);
+	/* password could be NULL here */
+	if (value) {
+		ifnet_set_data (conn_name, "password", (gchar *) value);
+	}
+	return TRUE;
+}
+
+gboolean
+ifnet_update_parsers_by_connection (NMConnection *connection,
+                                    const char *conn_name,
+                                    const char *config_file,
+                                    const char *wpa_file,
+                                    gchar **out_new_name,
+                                    gchar **out_backup,
+                                    GError **error)
+{
+	NMSettingConnection *s_con;
+	NMSettingIPConfig *s_ip6;
+	gboolean success = FALSE;
+	const char *type;
+	gboolean no_8021x = FALSE;
+	gboolean wired = FALSE, pppoe = TRUE;
+	const char *new_name = NULL;
+
+	if (!ifnet_can_write_connection (connection, error))
+		return FALSE;
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+
+	type = nm_setting_connection_get_connection_type (s_con);
+	if (!type) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+			     "Missing connection type!");
+		goto out;
+	}
+
+	if (!strcmp (type, NM_SETTING_WIRED_SETTING_NAME)) {
+		/* Writing wired setting */
+		if (!write_wired_setting (connection, conn_name, error))
+			goto out;
+		wired = TRUE;
+		no_8021x = TRUE;
+	} else if (!strcmp (type, NM_SETTING_WIRELESS_SETTING_NAME)) {
+		/* Writing wireless setting */
+		if (!write_wireless_setting (connection, conn_name, &no_8021x, &new_name, error))
+			goto out;
+	} else if (!strcmp (type, NM_SETTING_PPPOE_SETTING_NAME)) {
+		NMSettingPppoe *s_pppoe;
+
+		/* Writing pppoe setting */
+		s_pppoe = nm_connection_get_setting_pppoe (connection);
+		if (!write_pppoe_setting (conn_name, s_pppoe))
+			goto out;
+		pppoe = TRUE;
+		wired = TRUE;
+		no_8021x = TRUE;
+	} else {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_NOT_SUPPORTED,
+			     "Can't write connection type '%s'", type);
+		goto out;
+	}
+
+	/* connection name may have been updated; use it when writing out
+	 * the rest of the settings.
+	 */
+	if (new_name)
+		conn_name = new_name;
+
+	//FIXME wired connection doesn't support 8021x now
+	if (!no_8021x) {
+		if (!write_8021x_setting (connection, conn_name, wired, error))
+			goto out;
+	}
+
+	/* IPv4 Setting */
+	if (!write_ip4_setting (connection, conn_name, error))
+		goto out;
+
+	s_ip6 = nm_connection_get_setting_ip6_config (connection);
+	if (s_ip6) {
+		/* IPv6 Setting */
+		if (!write_ip6_setting (connection, conn_name, error))
+			goto out;
+	}
+
+	/* Connection Setting */
+	ifnet_set_data (conn_name, "auto",
+	                nm_setting_connection_get_autoconnect (s_con) ? "true" : "false");
+	ifnet_set_data (conn_name, "uuid", nm_connection_get_uuid (connection));
+
+	/* Write changes to disk */
+	success = ifnet_flush_to_file (config_file, out_backup);
+	if (success)
+		wpa_flush_to_file (wpa_file);
+
+	if (out_new_name)
+		*out_new_name = g_strdup (conn_name);
+
+out:
+	return success;
+}
+
+gboolean
+ifnet_delete_connection_in_parsers (const char *conn_name,
+                                    const char *config_file,
+                                    const char *wpa_file,
+                                    gchar **out_backup)
+{
+	gboolean result = FALSE;
+
+	ifnet_delete_network (conn_name);
+	result = ifnet_flush_to_file (config_file, out_backup);
+	if (result) {
+		/* connection may not have security information
+		 * so simply ignore the return value*/
+		wpa_delete_security (conn_name);
+		wpa_flush_to_file (wpa_file);
+	}
+
+	return result;
+}
+
+static void
+check_unsupported_secrets (NMSetting  *setting,
+                           const char *key,
+                           const GValue *value,
+                           GParamFlags flags,
+                           gpointer user_data)
+{
+	gboolean *unsupported_secret = user_data;
+
+	if (flags & NM_SETTING_PARAM_SECRET) {
+		NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+
+		if (!nm_setting_get_secret_flags (setting, key, &secret_flags, NULL))
+			g_return_if_reached ();
+		if (secret_flags != NM_SETTING_SECRET_FLAG_NONE)
+			*unsupported_secret = TRUE;
+	}
+}
+
+gboolean
+ifnet_can_write_connection (NMConnection *connection, GError **error)
+{
+	NMSettingConnection *s_con;
+	gboolean has_unsupported_secrets = FALSE;
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+
+	/* If the connection is not available for all users, ignore
+	 * it as this plugin only deals with System Connections */
+	if (nm_setting_connection_get_num_permissions (s_con)) {
+		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_NOT_SUPPORTED,
+		                     "The ifnet plugin does not support non-system-wide connections.");
+		return FALSE;
+	}
+
+	/* Only support wired, wifi, and PPPoE */
+	if (   !nm_connection_is_type (connection, NM_SETTING_WIRED_SETTING_NAME)
+	    && !nm_connection_is_type (connection, NM_SETTING_WIRELESS_SETTING_NAME)
+	    && !nm_connection_is_type (connection, NM_SETTING_PPPOE_SETTING_NAME)) {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_NOT_SUPPORTED,
+		             "The ifnet plugin cannot write the connection '%s' (type '%s')",
+		             nm_connection_get_id (connection),
+		             nm_setting_connection_get_connection_type (s_con));
+		return FALSE;
+	}
+
+	/* If the connection has flagged secrets, ignore
+	 * it as this plugin does not deal with user agent service */
+	nm_connection_for_each_setting_value (connection,
+	                                      check_unsupported_secrets,
+	                                      &has_unsupported_secrets);
+	if (has_unsupported_secrets) {
+		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_NOT_SUPPORTED,
+		                     "The ifnet plugin only supports persistent system secrets.");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+/* get the available wired name(eth*). */
+static gchar *
+get_wired_name (void)
+{
+	int i = 0;
+
+	for (; i < 256; i++) {
+		gchar *conn_name = g_strdup_printf ("eth%d", i);
+
+		if (!ifnet_has_network (conn_name)) {
+			return conn_name;
+		} else
+			g_free (conn_name);
+	}
+	return NULL;
+}
+
+/* get the available pppoe name(ppp*). */
+static gchar *
+get_ppp_name (void)
+{
+	int i = 0;
+
+	for (; i < 256; i++) {
+		gchar *conn_name = g_strdup_printf ("ppp%d", i);
+
+		if (!ifnet_has_network (conn_name)) {
+			return conn_name;
+		} else
+			g_free (conn_name);
+	}
+	return NULL;
+}
+
+/* get wireless ssid */
+static gchar *
+get_wireless_name (NMConnection * connection)
+{
+	NMSettingWireless *s_wireless;
+	GBytes *ssid;
+	const guint8 *ssid_data;
+	gsize ssid_len;
+	gboolean hex_ssid = FALSE;
+	gchar *result = NULL;
+	char buf[33];
+	int i = 0;
+
+	s_wireless = nm_connection_get_setting_wireless (connection);
+	if (!s_wireless)
+		return NULL;
+
+	ssid = nm_setting_wireless_get_ssid (s_wireless);
+	ssid_data = g_bytes_get_data (ssid, &ssid_len);
+	if (!ssid_len || ssid_len > 32) {
+		return NULL;
+	}
+
+	for (i = 0; i < ssid_len; i++) {
+		if (!g_ascii_isprint (ssid_data[i])) {
+			hex_ssid = TRUE;
+			break;
+		}
+	}
+
+	if (hex_ssid) {
+		GString *str;
+
+		str = g_string_sized_new (ssid_len * 2 + 3);
+		g_string_append (str, "0x");
+		for (i = 0; i < ssid_len; i++)
+			g_string_append_printf (str, "%02X", ssid_data[i]);
+		result = g_strdup (str->str);
+		g_string_free (str, TRUE);
+	} else {
+		memset (buf, 0, sizeof (buf));
+		memcpy (buf, ssid_data, ssid_len);
+		result = g_strdup_printf ("%s", buf);
+		g_strstrip (result);
+	}
+
+	return result;
+}
+
+gboolean
+ifnet_add_new_connection (NMConnection *connection,
+                          const char *config_file,
+                          const char *wpa_file,
+                          gchar **out_new_name,
+                          gchar **out_backup,
+                          GError **error)
+{
+	NMSettingConnection *s_con;
+	gboolean success = FALSE;
+	const char *type;
+	gchar *new_type, *new_name = NULL;
+
+	if (!ifnet_can_write_connection (connection, error))
+		return FALSE;
+
+	s_con = nm_connection_get_setting_connection (connection);
+	g_assert (s_con);
+	type = nm_setting_connection_get_connection_type (s_con);
+	g_assert (type);
+
+	nm_log_info (LOGD_SETTINGS, "Adding %s connection", type);
+
+	/* get name and type
+	 * Wireless type: wireless
+	 * Wired type: wired
+	 * PPPoE type: ppp*/
+	if (!strcmp (type, NM_SETTING_WIRED_SETTING_NAME)) {
+		new_name = get_wired_name ();
+		if (!new_name)
+			goto out;
+		new_type = "wired";
+	} else if (!strcmp (type, NM_SETTING_WIRELESS_SETTING_NAME)) {
+		new_name = get_wireless_name (connection);
+		new_type = "wireless";
+	} else if (!strcmp (type, NM_SETTING_PPPOE_SETTING_NAME)) {
+		new_name = get_ppp_name ();
+		if (!new_name)
+			goto out;
+		new_type = "ppp";
+	} else {
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_NOT_SUPPORTED,
+			     "Can't write connection type '%s'", type);
+		goto out;
+	}
+
+	if (ifnet_add_network (new_name, new_type)) {
+		success = ifnet_update_parsers_by_connection (connection,
+		                                              new_name,
+		                                              config_file,
+		                                              wpa_file,
+		                                              NULL,
+		                                              out_backup,
+		                                              error);
+	}
+
+	nm_log_info (LOGD_SETTINGS, "Added new connection: %s, result: %s",
+	             new_name, success ? "success" : "fail");
+
+out:
+	if (!success || !out_new_name)
+		g_free (new_name);
+	else if (out_new_name)
+		*out_new_name = new_name;
+	return success;
+}
+
diff --git a/src/settings/plugins/ifnet/nms-ifnet-connection-parser.h b/src/settings/plugins/ifnet/nms-ifnet-connection-parser.h
new file mode 100644
index 00000000..51bc34b9
--- /dev/null
+++ b/src/settings/plugins/ifnet/nms-ifnet-connection-parser.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* 
+ * Mu Qiao <qiaomuf@gmail.com>
+ *
+ * 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) 1999-2010 Gentoo Foundation, Inc.
+ */
+
+#ifndef _CONNECTION_PARSER_H
+#define _CONNECTION_PARSER_H
+
+#include "nm-connection.h"
+
+#include "nms-ifnet-net-parser.h"
+
+gboolean ifnet_can_write_connection (NMConnection *connection, GError **error);
+
+NMConnection *ifnet_update_connection_from_config_block (const char *conn_name,
+                                                         const char *basepath,
+                                                         GError **error);
+
+/* nm_conn_name is used to update nm_ifnet_connection's priv data */
+gboolean ifnet_update_parsers_by_connection (NMConnection *connection,
+                                             const char *conn_name,
+                                             const char *config_file,
+                                             const char *wpa_file,
+                                             gchar **out_new_name,
+                                             gchar **out_backup,
+                                             GError **error);
+
+gboolean ifnet_delete_connection_in_parsers (const char *conn_name,
+                                             const char *config_file,
+                                             const char *wpa_file,
+                                             gchar **out_backup);
+
+gboolean ifnet_add_new_connection (NMConnection *connection,
+                                   const char *config_file,
+                                   const char *wpa_file,
+                                   gchar **out_new_name,
+                                   gchar **out_backup,
+                                   GError ** error);
+#endif
diff --git a/src/settings/plugins/ifnet/nms-ifnet-connection.c b/src/settings/plugins/ifnet/nms-ifnet-connection.c
new file mode 100644
index 00000000..ce0b3f2b
--- /dev/null
+++ b/src/settings/plugins/ifnet/nms-ifnet-connection.c
@@ -0,0 +1,233 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Mu Qiao <qiaomuf@gmail.com>
+ *
+ * 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) 1999-2010 Gentoo Foundation, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nms-ifnet-connection.h"
+
+#include <string.h>
+#include <glib/gstdio.h>
+
+#include "nm-dbus-interface.h"
+#include "nm-utils.h"
+#include "nm-setting-wireless-security.h"
+#include "settings/nm-settings-connection.h"
+#include "settings/nm-settings-plugin.h"
+
+#include "nms-ifnet-connection-parser.h"
+#include "nms-ifnet-net-parser.h"
+#include "nms-ifnet-net-utils.h"
+#include "nms-ifnet-wpa-parser.h"
+#include "nms-ifnet-plugin.h"
+
+/*****************************************************************************/
+
+enum {
+	IFNET_SETUP_MONITORS,
+	IFNET_CANCEL_MONITORS,
+	IFNET_LAST_SIGNAL
+};
+
+static guint signals[IFNET_LAST_SIGNAL] = { 0 };
+
+typedef struct {
+	gchar *conn_name;
+	NMSettingsPlugin *config;
+} NMIfnetConnectionPrivate;
+
+struct _NMIfnetConnection {
+	NMSettingsConnection parent;
+	NMIfnetConnectionPrivate _priv;
+};
+
+struct _NMIfnetConnectionClass {
+	NMSettingsConnectionClass parent;
+};
+
+G_DEFINE_TYPE (NMIfnetConnection, nm_ifnet_connection, NM_TYPE_SETTINGS_CONNECTION)
+
+#define NM_IFNET_CONNECTION_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMIfnetConnection, NM_IS_IFNET_CONNECTION)
+
+/*****************************************************************************/
+
+const char *
+nm_ifnet_connection_get_conn_name (NMIfnetConnection *connection)
+{
+	return NM_IFNET_CONNECTION_GET_PRIVATE (connection)->conn_name;
+}
+
+static gboolean
+commit_changes (NMSettingsConnection *connection,
+                NMConnection *new_connection,
+                NMSettingsConnectionCommitReason commit_reason,
+                NMConnection **out_reread_connection,
+                char **out_logmsg_change,
+                GError **error)
+{
+	NMIfnetConnectionPrivate *priv = NM_IFNET_CONNECTION_GET_PRIVATE ((NMIfnetConnection *) connection);
+	char *new_name = NULL;
+	gboolean success = FALSE;
+	gboolean added = FALSE;
+
+	nm_assert (out_reread_connection && !*out_reread_connection);
+	nm_assert (!out_logmsg_change || !*out_logmsg_change);
+
+	g_signal_emit (connection, signals[IFNET_CANCEL_MONITORS], 0);
+
+	if (priv->conn_name) {
+		success = ifnet_update_parsers_by_connection (new_connection,
+		                                              priv->conn_name,
+		                                              CONF_NET_FILE,
+		                                              WPA_SUPPLICANT_CONF,
+		                                              &new_name,
+		                                              NULL,
+		                                              error);
+	} else {
+		added = TRUE;
+		success = ifnet_add_new_connection (new_connection,
+		                                    CONF_NET_FILE,
+		                                    WPA_SUPPLICANT_CONF,
+		                                    &new_name,
+		                                    NULL,
+		                                    error);
+	}
+
+	g_assert (!!success == (new_name != NULL));
+	if (success) {
+		g_free (priv->conn_name);
+		priv->conn_name = new_name;
+	}
+
+	reload_parsers ();
+
+	g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0);
+
+	if (success) {
+		NM_SET_OUT (out_logmsg_change,
+		            g_strdup_printf ("ifcfg-rh: %s %s",
+		                             added ? "persist" : "updated",
+		                             new_name));
+	}
+	return success;
+}
+
+static gboolean
+delete (NMSettingsConnection *connection,
+        GError **error)
+{
+	NMIfnetConnectionPrivate *priv = NM_IFNET_CONNECTION_GET_PRIVATE ((NMIfnetConnection *) connection);
+
+	/* Only connections which exist in /etc/conf.d/net will have a conn_name */
+	if (priv->conn_name) {
+		g_signal_emit (connection, signals[IFNET_CANCEL_MONITORS], 0);
+
+		if (!ifnet_delete_connection_in_parsers (priv->conn_name, CONF_NET_FILE, WPA_SUPPLICANT_CONF, NULL)) {
+			nm_log_warn (LOGD_SETTINGS, "Failed to delete %s", priv->conn_name);
+			reload_parsers ();
+			/* let's not return an error. */
+		}
+
+		g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0);
+	}
+
+	return TRUE;
+}
+
+/*****************************************************************************/
+
+static void
+nm_ifnet_connection_init (NMIfnetConnection * connection)
+{
+}
+
+NMIfnetConnection *
+nm_ifnet_connection_new (NMConnection *source, const char *conn_name)
+{
+	NMConnection *tmp;
+	GObject *object;
+	GError *error = NULL;
+	gboolean update_unsaved = TRUE;
+
+	g_return_val_if_fail (source || conn_name, NULL);
+
+	if (source)
+		tmp = g_object_ref (source);
+	else {
+		tmp = ifnet_update_connection_from_config_block (conn_name, NULL, &error);
+		if (!tmp) {
+			nm_log_warn (LOGD_SETTINGS, "Could not read connection '%s': %s",
+			             conn_name, error->message);
+			g_error_free (error);
+			return NULL;
+		}
+
+		/* If we just read the connection from disk, it's clearly not Unsaved */
+		update_unsaved = FALSE;
+	}
+
+	object = (GObject *) g_object_new (NM_TYPE_IFNET_CONNECTION, NULL);
+
+	NM_IFNET_CONNECTION_GET_PRIVATE ((NMIfnetConnection *) object)->conn_name = g_strdup (conn_name);
+	if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (object),
+	                                    tmp,
+	                                    update_unsaved
+	                                      ? NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED
+	                                      : NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP_SAVED,
+	                                    NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE,
+	                                    NULL,
+	                                    NULL)) {
+		g_object_unref (object);
+		return NULL;
+	}
+	g_object_unref (tmp);
+
+	return NM_IFNET_CONNECTION (object);
+}
+
+static void
+finalize (GObject * object)
+{
+	g_free (NM_IFNET_CONNECTION_GET_PRIVATE ((NMIfnetConnection *) object)->conn_name);
+	G_OBJECT_CLASS (nm_ifnet_connection_parent_class)->finalize (object);
+}
+
+static void
+nm_ifnet_connection_class_init (NMIfnetConnectionClass * ifnet_connection_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (ifnet_connection_class);
+	NMSettingsConnectionClass *settings_class = NM_SETTINGS_CONNECTION_CLASS (ifnet_connection_class);
+
+	object_class->finalize = finalize;
+
+	settings_class->delete = delete;
+	settings_class->commit_changes = commit_changes;
+
+	signals[IFNET_SETUP_MONITORS] =
+	    g_signal_new ("ifnet_setup_monitors",
+	                  G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST,
+	                  0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
+	                  G_TYPE_NONE, 0);
+	signals[IFNET_CANCEL_MONITORS] =
+	    g_signal_new ("ifnet_cancel_monitors",
+	                  G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST,
+	                  0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
+	                  G_TYPE_NONE, 0);
+}
diff --git a/src/settings/plugins/ifnet/nms-ifnet-connection.h b/src/settings/plugins/ifnet/nms-ifnet-connection.h
new file mode 100644
index 00000000..1bc06644
--- /dev/null
+++ b/src/settings/plugins/ifnet/nms-ifnet-connection.h
@@ -0,0 +1,46 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Mu Qiao <qiaomuf@gmail.com>
+ *
+ * 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) 1999-2010 Gentoo Foundation, Inc.
+ */
+
+#ifndef __NETWORKMANAGER_IFNET_CONNECTION_H__
+#define __NETWORKMANAGER_IFNET_CONNECTION_H__
+
+#include "settings/nm-settings-connection.h"
+
+#include "nms-ifnet-net-parser.h"
+
+#define NM_TYPE_IFNET_CONNECTION            (nm_ifnet_connection_get_type ())
+#define NM_IFNET_CONNECTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IFNET_CONNECTION, NMIfnetConnection))
+#define NM_IFNET_CONNECTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_IFNET_CONNECTION, NMIfnetConnectionClass))
+#define NM_IS_IFNET_CONNECTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_IFNET_CONNECTION))
+#define NM_IS_IFNET_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_IFNET_CONNECTION))
+#define NM_IFNET_CONNECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_IFNET_CONNECTION, NMIfnetConnectionClass))
+
+typedef struct _NMIfnetConnection NMIfnetConnection;
+typedef struct _NMIfnetConnectionClass NMIfnetConnectionClass;
+
+GType nm_ifnet_connection_get_type (void);
+
+NMIfnetConnection *nm_ifnet_connection_new (NMConnection *source,
+                                            const char *conn_name);
+
+const char *nm_ifnet_connection_get_conn_name (NMIfnetConnection *connection);
+
+#endif /* __NETWORKMANAGER_IFNET_CONNECTION_H__ */
diff --git a/src/settings/plugins/ifnet/nms-ifnet-net-parser.c b/src/settings/plugins/ifnet/nms-ifnet-net-parser.c
new file mode 100644
index 00000000..d3e47219
--- /dev/null
+++ b/src/settings/plugins/ifnet/nms-ifnet-net-parser.c
@@ -0,0 +1,734 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Mu Qiao <qiaomuf@gmail.com>
+ *
+ * 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) 1999-2010 Gentoo Foundation, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nms-ifnet-net-parser.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "settings/nm-settings-plugin.h"
+#include "platform/nm-platform.h"
+
+#include "nms-ifnet-plugin.h"
+#include "nms-ifnet-net-utils.h"
+
+/* Save all the connection information */
+static GHashTable *conn_table;
+
+/* Save global settings which are used for writing*/
+static GHashTable *global_settings_table;
+
+/* Save functions */
+static GList *functions_list;
+
+/* Used to decide whether to write changes to file*/
+static gboolean net_parser_data_changed = FALSE;
+
+static GHashTable *
+add_new_connection_config (const gchar * type, const gchar * name)
+{
+	GHashTable *new_conn;
+	gchar *new_name;
+
+	if (!name)
+		return NULL;
+
+	/* Return existing connection */
+	if ((new_conn = g_hash_table_lookup (conn_table, name)) != NULL)
+		return new_conn;
+	new_conn = g_hash_table_new (nm_str_hash, g_str_equal);
+	new_name = g_strdup (name);
+	g_hash_table_insert (new_conn, g_strdup ("name"), new_name);
+	g_hash_table_insert (new_conn, g_strdup ("type"), g_strdup (type));
+	g_hash_table_insert (conn_table, new_name, new_conn);
+	return new_conn;
+}
+
+gboolean
+ifnet_add_network (const char *name, const char *type)
+{
+	if (ifnet_has_network (name))
+		return TRUE;
+	if (add_new_connection_config (type, name)) {
+		nm_log_info (LOGD_SETTINGS, "Adding network for %s", name);
+		net_parser_data_changed = TRUE;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+gboolean
+ifnet_has_network (const char *conn_name)
+{
+	return g_hash_table_lookup (conn_table, conn_name) != NULL;
+}
+
+static GHashTable *
+get_connection_config (const char *name)
+{
+	return g_hash_table_lookup (conn_table, name);
+}
+
+/* Ignored name won't be treated as wireless ssid */
+static gchar *ignore_name[] = {
+	"vlan", "bond", "atm", "ath", "ippp", "vpn", "tap", "tun", "1",
+	"br", "nas", "6to4", "timeout", "kvm", "force", NULL
+};
+
+static gboolean
+ignore_connection_name (const char *name)
+{
+	gboolean result = FALSE;
+	guint i = 0;
+
+	/* check ignore_name list */
+	while (ignore_name[i] != NULL) {
+		if (g_ascii_strncasecmp
+		    (name, ignore_name[i], strlen (ignore_name[i])) == 0) {
+			return TRUE;
+		}
+		i++;
+	}
+	/* Ignore mac address based configuration */
+	if (strlen (name) == 12 && is_hex (name))
+		result = TRUE;
+	return result;
+}
+
+static gboolean
+is_global_setting (char *key)
+{
+	static gchar *global_settings[] = { "wpa_supplicant_", NULL };
+	int i;
+
+	for (i = 0; global_settings[i] != NULL; i++) {
+		if (strstr (key, global_settings[i]))
+			return 1;
+	}
+	return 0;
+}
+
+/* Parse a complete line */
+/* Connection type is determined here */
+static void
+init_block_by_line (gchar * buf)
+{
+	gchar **key_value;
+	gchar *pos;
+	gchar *data;
+	gchar *tmp;
+	GHashTable *conn;
+
+	key_value = g_strsplit (buf, "=", 2);
+	if (g_strv_length (key_value) != 2) {
+		nm_log_warn (LOGD_SETTINGS, "Can't handle this line: %s\n", buf);
+		g_strfreev (key_value);
+		return;
+	}
+	pos = g_strrstr (key_value[0], "_");
+	if (pos == NULL || is_global_setting (key_value[0])) {
+		/* global data */
+		data = g_strdup (key_value[1]);
+		tmp = strip_string (data, '"');
+		strip_string (tmp, '\'');
+		nm_log_info (LOGD_SETTINGS, "global:%s-%s\n", key_value[0], tmp);
+		g_hash_table_insert (global_settings_table, g_strdup (key_value[0]), g_strdup (tmp));
+		g_strfreev (key_value);
+		g_free (data);
+		return;
+	}
+	*pos++ = '\0';
+	if ((conn = get_connection_config (pos)) == NULL) {
+		if (g_ascii_strncasecmp (pos, "eth", 3) == 0
+		    && strlen (pos) == 4)
+			/* wired connection */
+			conn = add_new_connection_config ("wired", pos);
+		else if (g_ascii_strncasecmp (pos, "ppp", 3) == 0
+			 && strlen (pos) == 4)
+			/* pppoe connection */
+			conn = add_new_connection_config ("ppp", pos);
+		else if (ignore_connection_name (pos)) {
+			/* ignored connection */
+			conn = add_new_connection_config ("ignore", pos);
+		} else {
+			int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, pos);
+
+			if (ifindex && nm_platform_link_get_type (NM_PLATFORM_GET, ifindex) != NM_LINK_TYPE_WIFI)
+				/* wired connection */
+				conn = add_new_connection_config ("wired", pos);
+			else
+				/* wireless connection */
+				conn = add_new_connection_config ("wireless", pos);
+		}
+	}
+	data = g_strdup (key_value[1]);
+	tmp = strip_string (data, '"');
+	strip_string (tmp, '\'');
+	if (conn)
+		g_hash_table_insert (conn, strip_string (g_strdup (key_value[0]), ' '),
+				     g_strdup (tmp));
+	g_free (data);
+	g_strfreev (key_value);
+}
+
+static void
+destroy_connection_config (GHashTable * conn)
+{
+	gpointer key, value;
+	GHashTableIter iter;
+
+	g_hash_table_iter_init (&iter, conn);
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		g_free (key);
+		g_free (value);
+	}
+
+	g_hash_table_destroy (conn);
+}
+
+static void
+strip_function (GIOChannel * channel, gchar * line)
+{
+
+	int counter = 0;
+	gchar *p, *tmp;
+	gboolean begin = FALSE;
+	GString *function_str = g_string_new (line);
+
+	g_string_append (function_str, "\n");
+	while (1) {
+		p = line;
+		while (*p != '\0') {
+			if (*p == '{') {
+				counter++;
+				begin = TRUE;
+			} else if (*p == '}')
+				counter--;
+			p++;
+		}
+		if (begin && counter == 0) {
+			g_free (line);
+			goto done;
+		}
+		while (1) {
+			g_free (line);
+			if (g_io_channel_read_line
+			    (channel, &line, NULL, NULL,
+			     NULL) == G_IO_STATUS_EOF)
+				goto done;
+			g_string_append (function_str, line);
+			tmp = g_strdup (line);
+			g_strstrip (tmp);
+			if (tmp[0] != '#' && tmp[0] != '\0') {
+				g_free (tmp);
+				break;
+			} else
+				g_free (tmp);
+		}
+	}
+done:
+	functions_list =
+	    g_list_append (functions_list, g_strdup (function_str->str));
+	g_string_free (function_str, TRUE);
+}
+
+static gboolean
+is_function (gchar * line)
+{
+	static gchar *func_names[] =
+	    { "preup", "predown", "postup", "postdown", "failup", "faildown",
+		NULL,
+	};
+	int i;
+
+	for (i = 0; func_names[i]; i++) {
+		if (g_str_has_prefix (line, func_names[i])) {
+			nm_log_info (LOGD_SETTINGS, "Ignoring function: %s", func_names[i]);
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+static void
+append_line (GString *buf, gchar* line)
+{
+	gchar *pos = NULL;
+
+	if ((pos = strchr (line, '#')) != NULL)
+		*pos = '\0';
+	g_strstrip (line);
+
+	if (line[0] != '\0')
+		g_string_append_printf (buf, " %s", line);
+	g_free (line);
+}
+
+gboolean
+ifnet_init (gchar * config_file)
+{
+	GIOChannel *channel = NULL;
+	gchar *line;
+
+	/* Handle multiple lines with brackets */
+	gboolean complete = TRUE;
+
+	gboolean openrc_style = TRUE;
+
+	/* line buffer */
+	GString *buf;
+
+	net_parser_data_changed = FALSE;
+
+	conn_table = g_hash_table_new (nm_str_hash, g_str_equal);
+	global_settings_table = g_hash_table_new (nm_str_hash, g_str_equal);
+	functions_list = NULL;
+
+	if (g_file_test (config_file, G_FILE_TEST_IS_REGULAR))
+		channel = g_io_channel_new_file (config_file, "r", NULL);
+	if (channel == NULL) {
+		nm_log_warn (LOGD_SETTINGS, "Can't open %s", config_file);
+		return FALSE;
+	}
+
+	buf = g_string_new (NULL);
+	while (g_io_channel_read_line
+	       (channel, &line, NULL, NULL, NULL) != G_IO_STATUS_EOF) {
+		g_strstrip (line);
+		/* convert multiple lines to a complete line and
+		 * pass it to init_block_by_line() */
+		if (is_function (line)) {
+			strip_function (channel, line);
+			continue;
+		}
+
+		// New openrc style, bash arrays are not allowed. We only care about '"'
+		if (openrc_style && line[0] != '#' && line[0] != '\0'
+				&& !strchr (line, '(') && !strchr (line, ')')) {
+			gchar *tmp = line;
+
+			while ((tmp = strchr (tmp, '"')) != NULL) {
+				complete = !complete;
+				++tmp;
+			}
+
+			append_line (buf, line);
+			// Add "(separator) for routes. It will be easier for later parsing
+			if (strstr (buf->str, "via"))
+				g_string_append_printf (buf, "\"");
+
+			if (!complete)
+				continue;
+
+			strip_string (buf->str, '"');
+
+			init_block_by_line (buf->str);
+			g_string_free (buf, TRUE);
+			buf = g_string_new (NULL);
+		}
+		// Old bash arrays for baselayout-1, to be deleted
+		else if (line[0] != '#' && line[0] != '\0') {
+			if (!complete) {
+				complete =
+				    g_strrstr (line,
+					       ")") == NULL ? FALSE : TRUE;
+
+				append_line (buf, line);
+				if (!complete) {
+					openrc_style = FALSE;
+					continue;
+				}
+				else {
+					openrc_style = TRUE;
+				}
+			} else {
+				complete =
+				    (g_strrstr (line, "(") != NULL
+				     && g_strrstr (line, ")") != NULL)
+				    || g_strrstr (line, "(") == NULL;
+
+				append_line (buf, line);
+				if (!complete)
+				{
+					openrc_style = FALSE;
+					continue;
+				} else {
+					openrc_style = TRUE;
+				}
+			}
+			init_block_by_line (buf->str);
+			g_string_free (buf, TRUE);
+			buf = g_string_new (NULL);
+		} else
+			/* Blank line or comment line */
+			g_free (line);
+	}
+
+	g_string_free (buf, TRUE);
+	g_io_channel_shutdown (channel, FALSE, NULL);
+	g_io_channel_unref (channel);
+	return TRUE;
+}
+
+const char *
+ifnet_get_data (const char *conn_name, const char *key)
+{
+	GHashTable *conn;
+
+	g_return_val_if_fail (conn_name && key, NULL);
+
+	conn = g_hash_table_lookup (conn_table, conn_name);
+
+	if (conn)
+		return g_hash_table_lookup (conn, key);
+	return NULL;
+}
+
+/* format ip values for comparison */
+static gchar*
+format_ip_for_comparison (const gchar * value)
+{
+	gchar **ipset;
+	guint length, i;
+	GString *formated_string = g_string_new (NULL);
+	gchar *formatted = NULL;
+
+	ipset = g_strsplit (value, "\"", 0);
+	length = g_strv_length (ipset);
+
+	for (i = 0; i < length; i++)
+	{
+		strip_string (ipset[i], ' ');
+		if (ipset[i][0] != '\0')
+			g_string_append_printf (formated_string,
+						"%s ", ipset[i]);
+	}
+	formatted = g_strdup (formated_string->str);
+	formatted[formated_string->len - 1] = '\0';
+
+	g_string_free (formated_string, TRUE);
+	g_strfreev (ipset);
+
+	return formatted;
+}
+
+void
+ifnet_set_data (const char *conn_name, const char *key, const char *value)
+{
+	gpointer old_key = NULL, old_value = NULL;
+	GHashTable *conn = g_hash_table_lookup (conn_table, conn_name);
+	gchar * stripped = NULL;
+
+	if (!conn) {
+		nm_log_warn (LOGD_SETTINGS, "%s does not exist!", conn_name);
+		return;
+	}
+	if (value){
+		stripped = g_strdup (value);
+		strip_string (stripped, '"');
+	}
+	/* Remove existing key value pair */
+	if (g_hash_table_lookup_extended (conn, key, &old_key, &old_value)) {
+
+		/* This ugly hack is due to baselayout compatibility. We have to
+		 * deal with different ip format. So sometimes we have the same ips
+		 * but different strings.
+		 */
+		if (stripped &&
+			(!strcmp (key, "config")
+			|| !strcmp (key, "routes")
+			|| !strcmp (key, "pppd")
+			|| !strcmp (key, "chat")))
+		{
+			gchar *old_ips = format_ip_for_comparison (old_value);
+			gchar *new_ips = format_ip_for_comparison (value);
+			if(!strcmp (old_ips, new_ips))
+			{
+				g_free (stripped);
+				g_free (old_ips);
+				g_free (new_ips);
+				return;
+			}
+			g_free (old_ips);
+			g_free (new_ips);
+		}
+
+		if (stripped && !strcmp (old_value, stripped)) {
+			g_free (stripped);
+			return;
+		}
+		g_hash_table_remove (conn, old_key);
+		g_free (old_key);
+		g_free (old_value);
+	} else if (!value)
+		return;
+	if (stripped)
+		g_hash_table_insert (conn, g_strdup (key), stripped);
+	net_parser_data_changed = TRUE;
+}
+
+// Remember to free return value
+const char *
+ifnet_get_global_data (const gchar * key)
+{
+	return g_hash_table_lookup (global_settings_table, key);
+}
+
+// Return names of legal connections
+GList *
+ifnet_get_connection_names (void)
+{
+	GList *names = g_hash_table_get_keys (conn_table);
+	GList *iter, *result = NULL;
+
+	for (iter = names; iter; iter = iter->next) {
+		if (!ignore_connection_name (iter->data))
+			result = g_list_prepend (result, iter->data);
+	}
+
+	g_list_free (names);
+	return g_list_reverse (result);
+}
+
+/* format IP and route for writing */
+static void
+format_ips (gchar * value, gchar ** out_line, gchar * key, gchar * name)
+{
+	gchar **ipset;
+	guint length, i;
+	GString *formated_string = g_string_new (NULL);
+
+	strip_string (value, '(');
+	strip_string (value, ')');
+	strip_string (value, '"');
+	ipset = g_strsplit (value, "\"", 0);
+	length = g_strv_length (ipset);
+
+	//only one line
+	if (length < 2) {
+		*out_line =
+		    g_strdup_printf ("%s_%s=\"%s\"\n", key, name, value);
+		goto done;
+	}
+	// Multiple lines
+	g_string_append_printf (formated_string, "%s_%s=\"\n", key, name);
+	for (i = 0; i < length; i++)
+	{
+		strip_string (ipset[i], ' ');
+		if (ipset[i][0] != '\0')
+			g_string_append_printf (formated_string,
+						"%s\n", ipset[i]);
+	}
+	g_string_append (formated_string, "\"\n");
+	*out_line = g_strdup (formated_string->str);
+done:
+	g_string_free (formated_string, TRUE);
+	g_strfreev (ipset);
+}
+
+gboolean
+ifnet_flush_to_file (const char *config_file, gchar **out_backup)
+{
+	GIOChannel *channel;
+	GError *error = NULL;
+	gpointer key, value, name, network;
+	GHashTableIter iter, iter_network;
+	GList *list_iter;
+	gchar *out_line = NULL;
+	gsize bytes_written;
+	gboolean result = FALSE;
+	gchar *backup;
+
+	if (!net_parser_data_changed)
+		return TRUE;
+	if (!conn_table || !global_settings_table)
+		return FALSE;
+
+	backup = backup_file (config_file);
+
+	channel = g_io_channel_new_file (config_file, "w", NULL);
+	if (!channel) {
+		nm_log_warn (LOGD_SETTINGS, "Can't open file %s for writing", config_file);
+		g_free (backup);
+		return FALSE;
+	}
+	g_hash_table_iter_init (&iter, global_settings_table);
+	nm_log_info (LOGD_SETTINGS, "Writing to %s", config_file);
+	g_io_channel_write_chars (channel,
+				  "#Generated by NetworkManager\n"
+				  "###### Global Configuration ######\n",
+				  -1, &bytes_written, &error);
+	if (error)
+		goto done;
+
+	/* Writing global data */
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		out_line =
+		    g_strdup_printf ("%s=\"%s\"\n", (gchar *) key, (gchar *) value);
+		g_io_channel_write_chars (channel, out_line, -1,
+					  &bytes_written, &error);
+		if (bytes_written == 0 || error)
+			goto done;
+		g_free (out_line);
+	}
+
+	/* Writing connection data */
+	g_io_channel_write_chars (channel,
+				  "\n###### Connection Configuration ######\n",
+				  -1, &bytes_written, &error);
+	if (error)
+		goto done;
+
+	g_hash_table_iter_init (&iter, conn_table);
+	while (g_hash_table_iter_next (&iter, &name, &network)) {
+		g_hash_table_iter_init (&iter_network, (GHashTable *) network);
+		g_io_channel_write_chars (channel,
+					  "#----------------------------------\n",
+					  -1, &bytes_written, &error);
+		if (error)
+			goto done;
+
+		while (g_hash_table_iter_next (&iter_network, &key, &value)) {
+			if (!g_str_has_prefix ((gchar *) key, "name")
+			    && !g_str_has_prefix ((gchar *) key, "type")) {
+				/* These keys contain brackets */
+				if (strcmp
+				    ((gchar *) key,
+				     "config") == 0
+				    || strcmp ((gchar *) key,
+					       "routes") == 0
+				    || strcmp ((gchar *) key,
+					       "pppd") == 0
+				    || strcmp ((gchar *) key, "chat") == 0)
+					format_ips (value, &out_line, (gchar *)
+						    key, (gchar *)
+						    name);
+				else
+					out_line =
+					    g_strdup_printf
+					    ("%s_%s=\"%s\"\n",
+					     (gchar *) key,
+					     (gchar *) name, (gchar *) value);
+				g_io_channel_write_chars (channel, out_line, -1, &bytes_written, &error);
+				if (bytes_written == 0 || error)
+					goto done;
+				g_free (out_line);
+			}
+		}
+	}
+
+	/* Writing reserved functions */
+	if (functions_list) {
+		g_io_channel_write_chars (channel,
+					  "\n###### Reserved Functions ######\n",
+					  -1, &bytes_written, &error);
+		if (error)
+			goto done;
+
+		/* Writing functions */
+		for (list_iter = functions_list; list_iter;
+		     list_iter = g_list_next (list_iter)) {
+			out_line =
+			    g_strdup_printf ("%s\n", (gchar *) list_iter->data);
+			g_io_channel_write_chars (channel, out_line, -1,
+						  &bytes_written, &error);
+			if (bytes_written == 0 || error)
+				goto done;
+			g_free (out_line);
+		}
+	}
+
+	g_io_channel_flush (channel, &error);
+	if (error)
+		goto done;
+	result = TRUE;
+	net_parser_data_changed = FALSE;
+
+done:
+	if (error) {
+		nm_log_warn (LOGD_SETTINGS, "Error writing the configuration file: %s", error->message);
+		g_error_free (error);
+	}
+
+	if (result && out_backup)
+		*out_backup = backup;
+	else
+		g_free (backup);
+
+	g_io_channel_shutdown (channel, FALSE, NULL);
+	g_io_channel_unref (channel);
+	return result;
+}
+
+gboolean
+ifnet_delete_network (const char *conn_name)
+{
+	GHashTable *network = NULL;
+
+	g_return_val_if_fail (conn_table != NULL && conn_name != NULL, FALSE);
+	nm_log_info (LOGD_SETTINGS, "Deleting network for %s", conn_name);
+	network = g_hash_table_lookup (conn_table, conn_name);
+	if (!network)
+		return FALSE;
+	g_hash_table_remove (conn_table, conn_name);
+	destroy_connection_config (network);
+	net_parser_data_changed = TRUE;
+	return TRUE;
+}
+
+void
+ifnet_destroy (void)
+{
+	GHashTableIter iter;
+	gpointer key;
+	gpointer value;
+	GList *list_iter;
+
+	/* Destroy connection setting */
+	if (conn_table) {
+		g_hash_table_iter_init (&iter, conn_table);
+		while (g_hash_table_iter_next (&iter, &key, &value)) {
+			destroy_connection_config ((GHashTable *)
+						   value);
+		}
+		g_hash_table_destroy (conn_table);
+		conn_table = NULL;
+	}
+
+	/* Destroy global data */
+	if (global_settings_table) {
+		g_hash_table_iter_init (&iter, global_settings_table);
+		while (g_hash_table_iter_next (&iter, &key, &value)) {
+			g_free (key);
+			g_free (value);
+		}
+		g_hash_table_destroy (global_settings_table);
+		global_settings_table = NULL;
+	}
+	for (list_iter = functions_list; list_iter;
+	     list_iter = g_list_next (list_iter))
+		g_free (list_iter->data);
+	g_list_free (functions_list);
+}
diff --git a/src/settings/plugins/ifnet/nms-ifnet-net-parser.h b/src/settings/plugins/ifnet/nms-ifnet-net-parser.h
new file mode 100644
index 00000000..31fc9ead
--- /dev/null
+++ b/src/settings/plugins/ifnet/nms-ifnet-net-parser.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Mu Qiao <qiaomuf@gmail.com>
+ *
+ * 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) 1999-2010 Gentoo Foundation, Inc.
+ */
+
+#ifndef _NET_PARSER_H
+#define _NET_PARSER_H
+
+#define CONF_NET_FILE SYSCONFDIR "/conf.d/net"
+
+gboolean ifnet_init (gchar * config_file);
+void ifnet_destroy (void);
+
+/* Reader functions */
+GList *ifnet_get_connection_names (void);
+const char *ifnet_get_data (const char *conn_name, const char *key);
+const char *ifnet_get_global_data (const char *key);
+gboolean ifnet_has_network (const char *conn_name);
+
+/* Writer functions */
+gboolean ifnet_flush_to_file (const char *config_file, gchar **out_backup);
+void ifnet_set_data (const char *conn_name, const char *key, const char *value);
+gboolean ifnet_add_network (const char *name, const char *type);
+gboolean ifnet_delete_network (const char *conn_name);
+
+#endif
diff --git a/src/settings/plugins/ifnet/nms-ifnet-net-utils.c b/src/settings/plugins/ifnet/nms-ifnet-net-utils.c
new file mode 100644
index 00000000..6531a238
--- /dev/null
+++ b/src/settings/plugins/ifnet/nms-ifnet-net-utils.c
@@ -0,0 +1,830 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Mu Qiao <qiaomuf@gmail.com>
+ *
+ * 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) 1999-2010 Gentoo Foundation, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nms-ifnet-net-utils.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "nm-utils.h"
+#include "NetworkManagerUtils.h"
+#include "settings/nm-settings-plugin.h"
+#include "nm-config.h"
+#include "dhcp/nm-dhcp-manager.h"
+
+#include "nms-ifnet-wpa-parser.h"
+#include "nms-ifnet-net-parser.h"
+
+/* emit heading and tailing blank space, tab, character t */
+gchar *
+strip_string (gchar * str, gchar t)
+{
+	gchar *ret = str;
+	gint length = 0;
+	guint i = 0;
+
+	while (ret[i] != '\0'
+	       && (ret[i] == '\t' || ret[i] == ' ' || ret[i] == t)) {
+		length++;
+		i++;
+	}
+	i = 0;
+	while (ret[i + length] != '\0') {
+		ret[i] = ret[i + length];
+		i++;
+	}
+	ret[i] = '\0';
+	length = strlen (ret);
+	while ((length - 1) >= 0
+	       && (ret[length - 1] == ' ' || ret[length - 1] == '\n'
+		   || ret[length - 1] == '\t' || ret[length - 1] == t))
+		length--;
+	ret[length] = '\0';
+	return ret;
+}
+
+gboolean
+is_hex (const char *value)
+{
+	const char *p = value;
+
+	if (!p)
+		return FALSE;
+	while (*p) {
+		if (!g_ascii_isxdigit (*p++))
+			return FALSE;
+	}
+	return TRUE;
+}
+
+gboolean
+is_ascii (const char *value)
+{
+	const char *p = value;
+
+	while (*p) {
+		if (!g_ascii_isprint (*p++))
+			return FALSE;
+	}
+	return TRUE;
+
+}
+
+gboolean
+is_true (const char *str)
+{
+	if (!g_ascii_strcasecmp (str, "yes")
+	    || !g_ascii_strcasecmp (str, "true"))
+		return TRUE;
+	return FALSE;
+}
+
+static char *
+find_default_gateway_str (char *str)
+{
+	char *tmp;
+
+	if ((tmp = strstr (str, "default via ")) != NULL) {
+		return tmp + strlen ("default via ");
+	} else if ((tmp = strstr (str, "default gw ")) != NULL) {
+		return tmp + strlen ("default gw ");
+	}
+	return NULL;
+}
+
+static char *
+find_gateway_str (char *str)
+{
+	char *tmp;
+
+	if ((tmp = strstr (str, "via ")) != NULL) {
+		return tmp + strlen ("via ");
+	} else if ((tmp = strstr (str, "gw ")) != NULL) {
+		return tmp + strlen ("gw ");
+	}
+	return NULL;
+}
+
+gboolean
+reload_parsers (void)
+{
+	ifnet_destroy ();
+	wpa_parser_destroy ();
+	if (!ifnet_init (CONF_NET_FILE))
+		return FALSE;
+	wpa_parser_init (WPA_SUPPLICANT_CONF);
+	return TRUE;
+}
+
+gboolean
+is_static_ip4 (const char *conn_name)
+{
+	const char *data = ifnet_get_data (conn_name, "config");
+	const char *dhcp6;
+
+	if (!data)
+		return FALSE;
+	if (!strcmp (data, "shared"))
+		return FALSE;
+	if (!strcmp (data, "autoip"))
+		return FALSE;
+	dhcp6 = strstr (data, "dhcp6");
+	if (dhcp6) {
+		gchar *dhcp4;
+
+		if (strstr (data, "dhcp "))
+			return FALSE;
+		dhcp4 = strstr (data, "dhcp");
+		if (!dhcp4)
+			return TRUE;
+		if (dhcp4[4] == '\0')
+			return FALSE;
+		return TRUE;
+	}
+	return strstr (data, "dhcp") == NULL ? TRUE : FALSE;
+}
+
+gboolean
+is_static_ip6 (const char *conn_name)
+{
+	const char *data = ifnet_get_data (conn_name, "config");
+
+	if (!data)
+		return TRUE;
+	return strstr (data, "dhcp6") == NULL ? TRUE : FALSE;
+}
+
+gboolean
+is_ip4_address (const char *in_address)
+{
+	const char *pattern =
+	    "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.((\\{\\d{1,3}\\.\\.\\d{1,3}\\})|\\d{1,3})$";
+	gchar *address = g_strdup (in_address);
+	gboolean result = FALSE;
+	gchar *tmp;
+	GRegex *regex = g_regex_new (pattern, 0, 0, NULL);
+	GMatchInfo *match_info = NULL;
+
+	if (!address)
+		goto done;
+	g_strstrip (address);
+	if ((tmp = strstr (address, "/")) != NULL)
+		*tmp = '\0';
+	if ((tmp = strstr (address, " ")) != NULL)
+		*tmp = '\0';
+	g_regex_match (regex, address, 0, &match_info);
+	result = g_match_info_matches (match_info);
+done:
+	if (match_info)
+		g_match_info_free (match_info);
+	g_regex_unref (regex);
+	g_free (address);
+	return result;
+}
+
+gboolean
+is_ip6_address (const char *in_address)
+{
+	struct in6_addr tmp_ip6_addr;
+	gchar *tmp, *address;
+	gboolean result = FALSE;
+
+	if (!in_address)
+		return FALSE;
+	address = g_strdup (in_address);
+	g_strstrip (address);
+	if ((tmp = strchr (address, '/')) != NULL)
+		*tmp = '\0';
+	if (inet_pton (AF_INET6, address, &tmp_ip6_addr))
+		result = TRUE;
+	g_free (address);
+	return result;
+
+}
+
+// 'c' is only used for openrc style
+static gchar **
+split_addresses_by_char (const gchar *addresses, const gchar *c)
+{
+	gchar **ipset;
+
+	if (addresses == NULL)
+		return NULL;
+
+	if (strchr (addresses, '(') != NULL) { // old baselayout style
+		gchar *tmp = g_strdup (addresses);
+		strip_string (tmp, '(');
+		strip_string (tmp, ')');
+		strip_string (tmp, '"');
+		strip_string (tmp, '\'');
+		ipset = g_strsplit (tmp, "\" \"", 0);
+		g_free(tmp);
+	} else { // openrc style
+		if (strstr (addresses, "netmask"))
+			// There is only one ip address if "netmask" is specified.
+			// '\n' is not used in config so there will be only one split.
+			ipset = g_strsplit (addresses, "\n", 0);
+		else
+			ipset = g_strsplit (addresses, c, 0);
+	}
+
+	return ipset;
+}
+
+static gchar **
+split_addresses (const gchar* addresses)
+{
+	// " " is only used by openrc style
+	return split_addresses_by_char (addresses, " ");
+}
+
+static gchar **
+split_routes (const gchar* routes)
+{
+	// "\"" is only used by openrc style
+	return split_addresses_by_char (routes, "\"");
+}
+
+gboolean
+has_ip6_address (const char *conn_name)
+{
+	gchar **ipset;
+	guint length;
+	guint i;
+
+	g_return_val_if_fail (conn_name != NULL, FALSE);
+	ipset = split_addresses (ifnet_get_data (conn_name, "config"));
+	length = ipset ? g_strv_length (ipset) : 0;
+	for (i = 0; i < length; i++) {
+		if (!is_ip6_address (ipset[i]))
+			continue;
+		else {
+			g_strfreev (ipset);
+			return TRUE;
+		}
+
+	}
+	g_strfreev (ipset);
+	return FALSE;
+}
+
+gboolean
+has_default_route (const char *conn_name, gboolean (*check_fn) (const char *))
+{
+	char *routes = NULL, *end, *tmp;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail (conn_name != NULL, FALSE);
+
+	routes = g_strdup (ifnet_get_data (conn_name, "routes"));
+	if (!routes)
+		return FALSE;
+	tmp = find_default_gateway_str (routes);
+	if (tmp) {
+		g_strstrip (tmp);
+		if ((end = strstr (tmp, "\"")) != NULL)
+			*end = '\0';
+		if (check_fn (tmp))
+			success = TRUE;
+	}
+
+	g_free (routes);
+	return success;
+}
+
+static ip_block *
+create_ip4_block (gchar * ip)
+{
+	ip_block *iblock = g_slice_new0 (ip_block);
+	guint32 tmp_ip4_addr;
+	int i;
+	guint length;
+	gchar **ip_mask;
+
+	/* prefix format */
+	if (strstr (ip, "/")) {
+		gchar *prefix;
+
+		ip_mask = g_strsplit (ip, "/", 0);
+		length = g_strv_length (ip_mask);
+		if (!nm_utils_ipaddr_valid (AF_INET, ip_mask[0]))
+			goto error;
+		iblock->ip = g_strdup (ip_mask[0]);
+		prefix = ip_mask[1];
+		i = 0;
+		while (i < length && g_ascii_isdigit (prefix[i]))
+			i++;
+		prefix[i] = '\0';
+		iblock->prefix = (guint32) atoi (ip_mask[1]);
+	} else if (strstr (ip, "netmask")) {
+		ip_mask = g_strsplit (ip, " ", 0);
+		length = g_strv_length (ip_mask);
+		if (!nm_utils_ipaddr_valid (AF_INET, ip_mask[0]))
+			goto error;
+		iblock->ip = g_strdup (ip_mask[0]);
+		i = 0;
+		while (i < length && !strstr (ip_mask[++i], "netmask")) ;
+		while (i < length && ip_mask[++i][0] == '\0') ;
+		if (i >= length)
+			goto error;
+		if (!inet_pton (AF_INET, ip_mask[i], &tmp_ip4_addr))
+			goto error;
+		iblock->prefix = nm_utils_ip4_netmask_to_prefix (tmp_ip4_addr);
+	} else {
+		g_slice_free (ip_block, iblock);
+		if (!is_ip6_address (ip) && !strstr (ip, "dhcp"))
+			nm_log_warn (LOGD_SETTINGS, "Can't handle ipv4 address: %s, missing netmask or prefix", ip);
+		return NULL;
+	}
+	if (iblock->prefix == 0 || iblock->prefix > 32) {
+		nm_log_warn (LOGD_SETTINGS, "Can't handle ipv4 address: %s, invalid prefix", ip);
+		goto error;
+	}
+	g_strfreev (ip_mask);
+	return iblock;
+error:
+	if (!is_ip6_address (ip))
+		nm_log_warn (LOGD_SETTINGS, "Can't handle IPv4 address: %s", ip);
+	g_strfreev (ip_mask);
+	g_free (iblock->ip);
+	g_slice_free (ip_block, iblock);
+	return NULL;
+}
+
+static ip_block *
+create_ip_block (gchar * ip)
+{
+	ip_block *iblock = g_slice_new0 (ip_block);
+	gchar *dup_ip = g_strdup (ip);
+	gchar *prefix = NULL;
+
+	if ((prefix = strstr (dup_ip, "/")) != NULL) {
+		*prefix = '\0';
+		prefix++;
+	}
+	if (!nm_utils_ipaddr_valid (AF_INET6, dup_ip))
+		goto error;
+	iblock->ip = dup_ip;
+	if (prefix) {
+		errno = 0;
+		iblock->prefix = strtol (prefix, NULL, 10);
+		if (errno || iblock->prefix <= 0 || iblock->prefix > 128) {
+			goto error;
+		}
+	} else
+		iblock->prefix = 64;
+	return iblock;
+error:
+	if (!is_ip4_address (ip))
+		nm_log_warn (LOGD_SETTINGS, "Can't handle IPv6 address: %s", ip);
+	g_slice_free (ip_block, iblock);
+	g_free (dup_ip);
+	return NULL;
+}
+
+static char *
+get_ip4_gateway (gchar * gateway)
+{
+	gchar *tmp, *split;
+
+	if (!gateway)
+		return NULL;
+	tmp = find_gateway_str (gateway);
+	if (!tmp) {
+		nm_log_warn (LOGD_SETTINGS, "Couldn't obtain gateway in \"%s\"", gateway);
+		return NULL;
+	}
+	tmp = g_strdup (tmp);
+	strip_string (tmp, ' ');
+	strip_string (tmp, '"');
+
+	// Only one gateway is selected
+	if ((split = strstr (tmp, "\"")) != NULL)
+		*split = '\0';
+
+	if (!nm_utils_ipaddr_valid (AF_INET, tmp))
+		goto error;
+	return tmp;
+error:
+	if (!is_ip6_address (tmp))
+		nm_log_warn (LOGD_SETTINGS, "Can't handle IPv4 gateway: %s", tmp);
+	g_free (tmp);
+	return NULL;
+}
+
+static char *
+get_ip6_next_hop (gchar * next_hop)
+{
+	gchar *tmp;
+
+	if (!next_hop)
+		return NULL;
+	tmp = find_gateway_str (next_hop);
+	if (!tmp) {
+		nm_log_warn (LOGD_SETTINGS, "Couldn't obtain next_hop in \"%s\"", next_hop);
+		return NULL;
+	}
+	tmp = g_strdup (tmp);
+	strip_string (tmp, ' ');
+	strip_string (tmp, '"');
+	g_strstrip (tmp);
+	if (!nm_utils_ipaddr_valid (AF_INET6, tmp))
+		goto error;
+	return tmp;
+error:
+	if (!is_ip4_address (tmp))
+		nm_log_warn (LOGD_SETTINGS, "Can't handle IPv6 next_hop: %s", tmp);
+	g_free (tmp);
+
+	return NULL;
+}
+
+ip_block *
+convert_ip4_config_block (const char *conn_name)
+{
+	gchar **ipset;
+	guint length;
+	guint i;
+	gchar *ip;
+	char *def_gateway = NULL;
+	const char *routes;
+	ip_block *start = NULL, *current = NULL, *iblock = NULL;
+
+	g_return_val_if_fail (conn_name != NULL, NULL);
+
+	ipset = split_addresses (ifnet_get_data (conn_name, "config"));
+	length = ipset ? g_strv_length (ipset) : 0;
+
+	routes = ifnet_get_data (conn_name, "routes");
+	if (routes)
+		def_gateway = get_ip4_gateway (strstr (routes, "default"));
+
+	for (i = 0; i < length; i++) {
+		ip = ipset[i];
+		ip = strip_string (ip, '"');
+		iblock = create_ip4_block (ip);
+		if (iblock == NULL)
+			continue;
+		if (!iblock->next_hop && def_gateway != NULL)
+			iblock->next_hop = g_strdup (def_gateway);
+		if (start == NULL)
+			start = current = iblock;
+		else {
+			current->next = iblock;
+			current = iblock;
+		}
+	}
+	g_strfreev (ipset);
+	g_free (def_gateway);
+	return start;
+}
+
+ip_block *
+convert_ip6_config_block (const char *conn_name)
+{
+	gchar **ipset;
+	guint length;
+	guint i;
+	gchar *ip;
+	ip_block *start = NULL, *current = NULL, *iblock = NULL;
+
+	g_return_val_if_fail (conn_name != NULL, NULL);
+	ipset = split_addresses (ifnet_get_data (conn_name, "config"));
+	length = ipset ? g_strv_length (ipset) : 0;
+	for (i = 0; i < length; i++) {
+		ip = ipset[i];
+		ip = strip_string (ip, '"');
+		iblock = create_ip_block (ip);
+		if (iblock == NULL)
+			continue;
+		if (start == NULL)
+			start = current = iblock;
+		else {
+			current->next = iblock;
+			current = iblock;
+		}
+	}
+	g_strfreev (ipset);
+	return start;
+}
+
+ip_block *
+convert_ip4_routes_block (const char *conn_name)
+{
+	gchar **ipset;
+	guint length;
+	guint i;
+	gchar *ip;
+	ip_block *start = NULL, *current = NULL, *iblock = NULL;
+
+	g_return_val_if_fail (conn_name != NULL, NULL);
+
+	ipset = split_routes (ifnet_get_data (conn_name, "routes"));
+	length = ipset ? g_strv_length (ipset) : 0;
+	for (i = 0; i < length; i++) {
+		ip = ipset[i];
+		if (find_default_gateway_str (ip) || strstr (ip, "::")
+		    || !find_gateway_str (ip))
+			continue;
+		ip = strip_string (ip, '"');
+		iblock = create_ip4_block (ip);
+		if (iblock == NULL)
+			continue;
+		iblock->next_hop = get_ip4_gateway (ip);
+		if (start == NULL)
+			start = current = iblock;
+		else {
+			current->next = iblock;
+			current = iblock;
+		}
+	}
+	g_strfreev (ipset);
+	return start;
+}
+
+ip_block *
+convert_ip6_routes_block (const char *conn_name)
+{
+	gchar **ipset;
+	guint length;
+	guint i;
+	gchar *ip, *tmp_addr;
+	ip_block *start = NULL, *current = NULL, *iblock = NULL;
+
+	g_return_val_if_fail (conn_name != NULL, NULL);
+	ipset = split_routes (ifnet_get_data (conn_name, "routes"));
+	length = ipset ? g_strv_length (ipset) : 0;
+	for (i = 0; i < length; i++) {
+		ip = ipset[i];
+		ip = strip_string (ip, '"');
+		if (ip[0] == '\0')
+			continue;
+		if ((tmp_addr = find_default_gateway_str (ip)) != NULL) {
+			if (!is_ip6_address (tmp_addr))
+				continue;
+			else {
+				iblock = g_slice_new0 (ip_block);
+				iblock->ip = g_strdup ("::");
+				iblock->prefix = 128;
+			}
+		} else
+			iblock = create_ip_block (ip);
+		if (iblock == NULL)
+			continue;
+		iblock->next_hop = get_ip6_next_hop (ip);
+		if (iblock->next_hop == NULL) {
+			destroy_ip_block (iblock);
+			continue;
+		}
+		if (start == NULL)
+			start = current = iblock;
+		else {
+			current->next = iblock;
+			current = iblock;
+		}
+	}
+	g_strfreev (ipset);
+	return start;
+}
+
+void
+destroy_ip_block (ip_block * iblock)
+{
+	g_free (iblock->ip);
+	g_free (iblock->next_hop);
+	g_slice_free (ip_block, iblock);
+}
+
+void
+set_ip4_dns_servers (NMSettingIPConfig *s_ip4, const char *conn_name)
+{
+	const char *dns_servers;
+	gchar **server_list, *stripped;
+	guint length, i;
+	guint32 tmp_ip4_addr;
+
+	dns_servers = ifnet_get_data (conn_name, "dns_servers");
+	if (!dns_servers)
+		return;
+	stripped = g_strdup (dns_servers);
+	strip_string (stripped, '"');
+	server_list = g_strsplit (stripped, " ", 0);
+	g_free (stripped);
+
+	length = g_strv_length (server_list);
+	if (length)
+		g_object_set (s_ip4, NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS,
+			      TRUE, NULL);
+	for (i = 0; i < length; i++) {
+		g_strstrip (server_list[i]);
+		if (server_list[i][0] == '\0')
+			continue;
+		if (!inet_pton (AF_INET, server_list[i], &tmp_ip4_addr)) {
+			if (!is_ip6_address (server_list[i]))
+				nm_log_warn (LOGD_SETTINGS, "ignored dns: %s\n", server_list[i]);
+			continue;
+		}
+		if (!nm_setting_ip_config_add_dns (s_ip4, server_list[i]))
+			nm_log_warn (LOGD_SETTINGS, "warning: duplicate DNS server %s", server_list[i]);
+	}
+	g_strfreev (server_list);
+}
+
+void
+set_ip6_dns_servers (NMSettingIPConfig *s_ip6, const char *conn_name)
+{
+	const char *dns_servers;
+	gchar **server_list, *stripped;
+	guint length, i;
+	struct in6_addr tmp_ip6_addr;
+
+	dns_servers = ifnet_get_data (conn_name, "dns_servers");
+	if (!dns_servers)
+		return;
+
+	stripped = g_strdup (dns_servers);
+	strip_string (stripped, '"');
+	server_list = g_strsplit (stripped, " ", 0);
+	g_free (stripped);
+
+	length = g_strv_length (server_list);
+	if (length)
+		g_object_set (s_ip6, NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS,
+			      TRUE, NULL);
+	for (i = 0; i < length; i++) {
+		g_strstrip (server_list[i]);
+		if (server_list[i][0] == '\0')
+			continue;
+		if (!inet_pton (AF_INET6, server_list[i], &tmp_ip6_addr)) {
+			if (is_ip6_address (server_list[i]))
+				nm_log_warn (LOGD_SETTINGS, "ignored dns: %s\n", server_list[i]);
+			continue;
+		}
+		if (!nm_setting_ip_config_add_dns (s_ip6, server_list[i]))
+			nm_log_warn (LOGD_SETTINGS, "warning: duplicate DNS server %s", server_list[i]);
+	}
+	g_strfreev (server_list);
+}
+
+gboolean
+is_managed (const char *conn_name)
+{
+	gchar *config;
+
+	g_return_val_if_fail (conn_name != NULL, FALSE);
+	config = (gchar *) ifnet_get_data (conn_name, "managed");
+	if (!config)
+		return TRUE;
+	if (strcmp (config, "false") == 0)
+		return FALSE;
+	return TRUE;
+}
+
+static char *
+_has_prefix_impl (char *str, const char *prefix, gsize prefix_len)
+{
+	if (!g_str_has_prefix (str, prefix))
+		return NULL;
+	str += prefix_len;
+	if (!g_ascii_isspace (str[0]))
+		return NULL;
+	do {
+		str++;
+	} while (g_ascii_isspace (str[0]));
+	return str;
+}
+#define _has_prefix(STR, PREFIX) _has_prefix_impl (STR, PREFIX, NM_STRLEN (PREFIX))
+
+void
+get_dhcp_hostname_and_client_id (char **hostname, char **client_id)
+{
+	const char *dhcp_client;
+	const gchar *dhcpcd_conf = SYSCONFDIR "/dhcpcd.conf";
+	const gchar *dhclient_conf = SYSCONFDIR "/dhcp/dhclient.conf";
+	gchar *line = NULL, *tmp = NULL, *contents = NULL, *tmp1;
+	gchar **all_lines;
+	guint line_num, i;
+	gboolean use_dhclient = FALSE;
+
+	*hostname = NULL;
+	*client_id = NULL;
+	dhcp_client = nm_dhcp_manager_get_config (nm_dhcp_manager_get ());
+	if (dhcp_client) {
+		if (!strcmp (dhcp_client, "dhclient")) {
+			g_file_get_contents (dhclient_conf, &contents, NULL,
+			                     NULL);
+			use_dhclient = TRUE;
+		} else if (!strcmp (dhcp_client, "dhcpcd")) {
+			g_file_get_contents (dhcpcd_conf, &contents, NULL,
+			                     NULL);
+		}
+	} else {
+		if (g_file_test (dhclient_conf, G_FILE_TEST_IS_REGULAR)) {
+			g_file_get_contents (dhclient_conf, &contents, NULL,
+			                     NULL);
+			use_dhclient = TRUE;
+		} else if (g_file_test (dhcpcd_conf, G_FILE_TEST_IS_REGULAR)) {
+			g_file_get_contents (dhcpcd_conf, &contents, NULL,
+			                     NULL);
+		}
+	}
+	if (!contents)
+		return;
+	all_lines = g_strsplit (contents, "\n", 0);
+	line_num = g_strv_length (all_lines);
+	for (i = 0; i < line_num; i++) {
+		line = all_lines[i];
+		g_strstrip (line);
+		if (line[0] == '#' || line[0] == '\0')
+			continue;
+		if (!use_dhclient) {
+			// dhcpcd.conf
+			if ((tmp = _has_prefix (line, "hostname"))) {
+				if (tmp[0] != '\0') {
+					g_free (*hostname);
+					*hostname = g_strdup (tmp);
+				} else
+					nm_log_info (LOGD_SETTINGS, "dhcpcd hostname not defined, ignoring");
+			} else if ((tmp = _has_prefix (line, "clientid"))) {
+				if (tmp[0] != '\0') {
+					g_free (*client_id);
+					*client_id = g_strdup (tmp);
+				} else
+					nm_log_info (LOGD_SETTINGS, "dhcpcd clientid not defined, ignoring");
+			}
+		} else {
+			// dhclient.conf
+			if ((tmp1 = _has_prefix (line, "send"))) {
+				if ((tmp = _has_prefix (tmp1, "host-name"))) {
+					strip_string (tmp, ';');
+					strip_string (tmp, '"');
+					if (tmp[0] != '\0') {
+						g_free (*hostname);
+						*hostname = g_strdup (tmp);
+					} else
+						nm_log_info (LOGD_SETTINGS, "dhclient hostname not defined, ignoring");
+				} else if ((tmp = _has_prefix (tmp1, "dhcp-client-identifier"))) {
+					strip_string (tmp, ';');
+					if (tmp[0] != '\0') {
+						g_free (*client_id);
+						*client_id = g_strdup (tmp);
+					} else
+						nm_log_info (LOGD_SETTINGS, "dhclient clientid not defined, ignoring");
+				}
+			}
+		}
+	}
+	g_strfreev (all_lines);
+	g_free (contents);
+}
+
+gchar *backup_file (const gchar* target)
+{
+	GFile *source, *backup;
+	gchar* backup_path;
+	GError *error = NULL;
+
+	source = g_file_new_for_path (target);
+
+	if (!g_file_query_exists (source, NULL)) {
+		g_object_unref (source);
+		return NULL;
+	}
+
+	backup_path = g_strdup_printf ("%s.bak", target);
+	backup = g_file_new_for_path (backup_path);
+
+	if (!g_file_copy (source, backup, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &error)) {
+		nm_log_warn (LOGD_SETTINGS, "Backup failed: %s", error->message);
+		g_free (backup_path);
+		backup_path = NULL;
+		g_error_free (error);
+	}
+
+	g_object_unref (source);
+	g_object_unref (backup);
+
+	return backup_path;
+}
diff --git a/src/settings/plugins/ifnet/nms-ifnet-net-utils.h b/src/settings/plugins/ifnet/nms-ifnet-net-utils.h
new file mode 100644
index 00000000..cc273aa7
--- /dev/null
+++ b/src/settings/plugins/ifnet/nms-ifnet-net-utils.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Mu Qiao <qiaomuf@gmail.com>
+ *
+ * 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) 1999-2010 Gentoo Foundation, Inc.
+ */
+
+#ifndef _IFNET_UTILS_H
+#define _IFNET_UTILS_H
+
+#define IFNET_PLUGIN_NAME "SettingsPlugin-Ifnet"
+
+#include <arpa/inet.h>
+
+#include "nm-setting-ip6-config.h"
+#include "nm-setting-ip4-config.h"
+
+#include "nms-ifnet-net-parser.h"
+
+#define has_default_ip4_route(conn_name) has_default_route((conn_name), &is_ip4_address)
+#define has_default_ip6_route(conn_name) has_default_route((conn_name), &is_ip6_address)
+
+typedef struct _ip_block {
+	char *ip;
+	guint32 prefix;
+	char *next_hop;
+	struct _ip_block *next;
+} ip_block;
+
+gboolean is_static_ip4 (const char *conn_name);
+gboolean is_static_ip6 (const char *conn_name);
+gboolean is_ip4_address (const char *in_address);
+gboolean is_ip6_address (const char *in_address);
+gboolean has_ip6_address (const char *conn_name);
+gboolean has_default_route (const char *conn_name, gboolean (*check_fn) (const char *));
+gboolean reload_parsers (void);
+
+ip_block *convert_ip4_config_block (const char *conn_name);
+ip_block *convert_ip6_config_block (const char *conn_name);
+ip_block *convert_ip4_routes_block (const char *conn_name);
+ip_block *convert_ip6_routes_block (const char *conn_name);
+void destroy_ip_block (ip_block * iblock);
+
+void set_ip4_dns_servers (NMSettingIPConfig * s_ip4, const char *conn_name);
+void set_ip6_dns_servers (NMSettingIPConfig * s_ip6, const char *conn_name);
+
+gchar *strip_string (gchar *str, gchar t);
+gboolean is_managed (const char *conn_name);
+
+gboolean is_hex (const char *value);
+gboolean is_ascii (const char *value);
+gboolean is_true (const char *str);
+
+void get_dhcp_hostname_and_client_id (char **hostname, char **client_id);
+
+gchar *backup_file (const gchar* target);
+#endif
diff --git a/src/settings/plugins/ifnet/nms-ifnet-plugin.c b/src/settings/plugins/ifnet/nms-ifnet-plugin.c
new file mode 100644
index 00000000..8332358f
--- /dev/null
+++ b/src/settings/plugins/ifnet/nms-ifnet-plugin.c
@@ -0,0 +1,524 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service (ifnet)
+ *
+ * Mu Qiao <qiaomuf@gmail.com>
+ *
+ * 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) 1999-2010 Gentoo Foundation, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nms-ifnet-plugin.h"
+
+#include <string.h>
+#include <gmodule.h>
+
+#include "nm-utils.h"
+#include "nm-setting-connection.h"
+#include "nm-dbus-interface.h"
+#include "settings/nm-settings-plugin.h"
+#include "nm-config.h"
+#include "NetworkManagerUtils.h"
+
+#include "nms-ifnet-connection.h"
+#include "nms-ifnet-net-utils.h"
+#include "nms-ifnet-net-parser.h"
+#include "nms-ifnet-wpa-parser.h"
+#include "nms-ifnet-connection-parser.h"
+
+#define IFNET_PLUGIN_NAME_PRINT "ifnet"
+#define IFNET_PLUGIN_INFO "(C) 1999-2010 Gentoo Foundation, Inc. To report bugs please use bugs.gentoo.org with [networkmanager] or [qiaomuf] prefix."
+#define IFNET_MANAGE_WELL_KNOWN_DEFAULT TRUE
+
+/*****************************************************************************/
+
+typedef void (*FileChangedFn) (gpointer user_data);
+
+typedef struct {
+	FileChangedFn callback;
+	gpointer user_data;
+} FileMonitorInfo;
+
+/*****************************************************************************/
+
+typedef struct {
+	GHashTable *connections;  /* uuid::connection */
+	gboolean unmanaged_well_known;
+
+	GFileMonitor *net_monitor;
+	GFileMonitor *wpa_monitor;
+} SettingsPluginIfnetPrivate;
+
+struct _SettingsPluginIfnet {
+	GObject parent;
+	SettingsPluginIfnetPrivate _priv;
+};
+
+struct _SettingsPluginIfnetClass {
+	GObjectClass parent;
+};
+
+static void settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface);
+
+G_DEFINE_TYPE_EXTENDED (SettingsPluginIfnet, settings_plugin_ifnet, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN,
+                                               settings_plugin_interface_init))
+
+#define SETTINGS_PLUGIN_IFNET_GET_PRIVATE(self) _NM_GET_PRIVATE (self, SettingsPluginIfnet, SETTINGS_IS_PLUGIN_IFNET)
+
+/*****************************************************************************/
+
+static SettingsPluginIfnet *settings_plugin_ifnet_get (void);
+
+NM_DEFINE_SINGLETON_GETTER (SettingsPluginIfnet, settings_plugin_ifnet_get, SETTINGS_TYPE_PLUGIN_IFNET);
+
+/*****************************************************************************/
+
+static void reload_connections (NMSettingsPlugin *config);
+
+/*****************************************************************************/
+
+static gboolean
+is_managed_plugin (void)
+{
+	return nm_config_data_get_value_boolean (NM_CONFIG_GET_DATA_ORIG,
+	                                         NM_CONFIG_KEYFILE_GROUP_IFNET, NM_CONFIG_KEYFILE_KEY_IFNET_MANAGED,
+	                                         IFNET_MANAGE_WELL_KNOWN_DEFAULT);
+}
+
+static void
+file_changed (GFileMonitor * monitor,
+              GFile * file,
+              GFile * other_file,
+              GFileMonitorEvent event_type, gpointer user_data)
+{
+	FileMonitorInfo *info;
+
+	switch (event_type) {
+	case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+		info = (FileMonitorInfo *) user_data;
+		info->callback (info->user_data);
+		break;
+	default:
+		break;
+	}
+}
+
+static GFileMonitor *
+monitor_file_changes (const char *filename,
+                      FileChangedFn callback, gpointer user_data)
+{
+	GFile *file;
+	GFileMonitor *monitor;
+	FileMonitorInfo *info;
+	GError **error = NULL;
+
+	if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+		return NULL;
+	file = g_file_new_for_path (filename);
+	monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, error);
+	g_object_unref (file);
+
+	if (monitor) {
+		info = g_new0 (FileMonitorInfo, 1);
+		info->callback = callback;
+		info->user_data = user_data;
+		g_object_weak_ref (G_OBJECT (monitor), (GWeakNotify) g_free,
+		                   info);
+		g_signal_connect (monitor, "changed", G_CALLBACK (file_changed),
+		                  info);
+	} else {
+		nm_log_warn (LOGD_SETTINGS, "Monitoring %s failed, error: %s", filename,
+		             error == NULL ? "nothing" : (*error)->message);
+	}
+
+	return monitor;
+}
+
+static void
+setup_monitors (NMIfnetConnection *connection, gpointer user_data)
+{
+	SettingsPluginIfnet *self = SETTINGS_PLUGIN_IFNET (user_data);
+	SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self);
+
+	if (!nm_config_get_monitor_connection_files (nm_config_get ()))
+		return;
+
+	if (priv->net_monitor || priv->wpa_monitor)
+		return;
+
+	priv->net_monitor = monitor_file_changes (CONF_NET_FILE,
+	                                          (FileChangedFn) reload_connections,
+	                                          user_data);
+	priv->wpa_monitor = monitor_file_changes (WPA_SUPPLICANT_CONF,
+	                                          (FileChangedFn) reload_connections,
+	                                          user_data);
+}
+
+static void
+cancel_monitors (NMIfnetConnection *connection, gpointer user_data)
+{
+	SettingsPluginIfnet *self = SETTINGS_PLUGIN_IFNET (user_data);
+	SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self);
+
+	if (priv->net_monitor) {
+		g_file_monitor_cancel (priv->net_monitor);
+		g_clear_object (&priv->net_monitor);
+	}
+	if (priv->wpa_monitor) {
+		g_file_monitor_cancel (priv->wpa_monitor);
+		g_clear_object (&priv->wpa_monitor);
+	}
+}
+
+static void
+connection_removed_cb (NMSettingsConnection *obj, gpointer user_data)
+{
+	g_hash_table_remove (SETTINGS_PLUGIN_IFNET_GET_PRIVATE ((SettingsPluginIfnet *) user_data)->connections,
+	                     nm_connection_get_uuid (NM_CONNECTION (obj)));
+}
+
+static void
+track_new_connection (SettingsPluginIfnet *self, NMIfnetConnection *connection)
+{
+	g_hash_table_insert (SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self)->connections,
+	                     g_strdup (nm_connection_get_uuid (NM_CONNECTION (connection))),
+	                     g_object_ref (connection));
+	g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED,
+	                  G_CALLBACK (connection_removed_cb),
+	                  self);
+}
+
+static void
+reload_connections (NMSettingsPlugin *config)
+{
+	SettingsPluginIfnet *self = SETTINGS_PLUGIN_IFNET (config);
+	SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self);
+	GList *conn_names = NULL, *n_iter = NULL;
+	gboolean auto_refresh;
+	GError *error = NULL;
+
+	/* save names for removing unused connections */
+	GHashTable *new_connections = NULL;
+	GHashTableIter iter;
+	const char *uuid;
+	NMSettingsConnection *candidate;
+
+	if (priv->unmanaged_well_known)
+		return;
+
+	if (!reload_parsers ())
+		return;
+
+	nm_log_info (LOGD_SETTINGS, "Loading connections");
+
+	auto_refresh = nm_config_data_get_value_boolean (NM_CONFIG_GET_DATA_ORIG,
+	                                                 NM_CONFIG_KEYFILE_GROUP_IFNET, NM_CONFIG_KEYFILE_KEY_IFNET_AUTO_REFRESH,
+	                                                 FALSE);
+
+	new_connections = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref);
+
+	/* Reread on-disk data and refresh in-memory connections from it */
+	conn_names = ifnet_get_connection_names ();
+	for (n_iter = conn_names; n_iter; n_iter = g_list_next (n_iter)) {
+		NMIfnetConnection *new;
+		NMIfnetConnection *old;
+		const char *conn_name = n_iter->data;
+
+		/* read the new connection */
+		new = nm_ifnet_connection_new (NULL, conn_name);
+		if (!new)
+			continue;
+
+		g_signal_connect (G_OBJECT (new), "ifnet_setup_monitors",
+		                  G_CALLBACK (setup_monitors), config);
+		g_signal_connect (G_OBJECT (new), "ifnet_cancel_monitors",
+		                  G_CALLBACK (cancel_monitors), config);
+
+		old = g_hash_table_lookup (priv->connections,
+		                           nm_connection_get_uuid (NM_CONNECTION (new)));
+		if (old && new) {
+			if (auto_refresh) {
+				/* If connection has changed, remove the old one and add the
+				 * new one to force a disconnect/reconnect with new settings
+				 */
+				if (!nm_connection_compare (NM_CONNECTION (old),
+				                            NM_CONNECTION (new),
+				                            NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
+				                              NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) {
+					nm_log_info (LOGD_SETTINGS, "Auto refreshing %s", conn_name);
+
+					nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (old));
+					track_new_connection (self, new);
+					if (is_managed_plugin () && is_managed (conn_name))
+						g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, new);
+				}
+			} else {
+				/* Update existing connection with new settings */
+				if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (old),
+				                                    NM_CONNECTION (new),
+				                                    NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP_SAVED,
+				                                    NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE,
+				                                    "ifnet-update",
+				                                    &error)) {
+					/* Shouldn't ever get here as 'new' was verified by the reader already
+					 * and the UUID did not change. */
+					g_assert_not_reached ();
+				}
+				g_assert_no_error (error);
+				nm_log_info (LOGD_SETTINGS, "Connection %s updated",
+				             nm_connection_get_id (NM_CONNECTION (new)));
+			}
+			g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED);
+		} else if (new) {
+			track_new_connection (self, new);
+			if (is_managed_plugin () && is_managed (conn_name))
+				g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, new);
+		}
+
+		/* Track all valid connections so we can remove deleted ones later */
+		g_hash_table_insert (new_connections,
+		                     (gpointer) nm_connection_get_uuid (NM_CONNECTION (new)),
+		                     new);
+	}
+
+	/* remove deleted/unused connections */
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, (gpointer) &uuid, (gpointer) &candidate)) {
+		/* only saved connections (which have a conn_name) get removed; unsaved
+		 * ones obviously don't exist in /etc/conf.d/net yet and shouldn't get
+		 * blown away by net file changes.
+		 */
+		if (   nm_ifnet_connection_get_conn_name (NM_IFNET_CONNECTION (candidate))
+		    && !g_hash_table_lookup (new_connections, uuid)) {
+			nm_settings_connection_signal_remove (candidate);
+			g_hash_table_iter_remove (&iter);
+		}
+	}
+	g_hash_table_destroy (new_connections);
+	g_list_free (conn_names);
+}
+
+static NMSettingsConnection *
+add_connection (NMSettingsPlugin *config,
+                NMConnection *source,
+                gboolean save_to_disk,
+                GError **error)
+{
+	SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE ((SettingsPluginIfnet *) config);
+	NMIfnetConnection *new = NULL;
+
+	/* Ensure we reject attempts to add the connection long before we're
+	 * asked to write it to disk.
+	 */
+	if (!ifnet_can_write_connection (source, error))
+		goto out;
+
+	if (save_to_disk) {
+		if (!ifnet_add_new_connection (source, CONF_NET_FILE, WPA_SUPPLICANT_CONF, NULL, NULL, error))
+			goto out;
+		reload_connections (config);
+		new = g_hash_table_lookup (priv->connections, nm_connection_get_uuid (source));
+	} else {
+		new = nm_ifnet_connection_new (source, NULL);
+		if (new) {
+			track_new_connection (SETTINGS_PLUGIN_IFNET (config), new);
+			/* track_new_connection refs 'new' */
+			g_object_unref (new);
+		}
+	}
+
+out:
+	if (!new && error && !*error) {
+		g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+		                     "The ifnet plugin cannot add the connection (unknown error).");
+	}
+	return (NMSettingsConnection *) new;
+}
+
+static void
+check_unmanaged (gpointer key, gpointer data, gpointer user_data)
+{
+	NMIfnetConnection *connection = NM_IFNET_CONNECTION (data);
+	GSList **list = (GSList **) user_data;
+	const char *mac, *conn_name;
+	char *unmanaged_spec;
+	GSList *iter;
+
+	conn_name = nm_ifnet_connection_get_conn_name (connection);
+
+	if (!conn_name || is_managed (conn_name))
+		return;
+
+	nm_log_info (LOGD_SETTINGS, "Checking unmanaged: %s", conn_name);
+	mac = ifnet_get_data (conn_name, "mac");
+	if (mac)
+		unmanaged_spec = g_strdup_printf ("mac:%s", mac);
+	else
+		unmanaged_spec = g_strdup_printf ("interface-name:%s", conn_name);
+
+	/* Just return if the unmanaged spec is already in the list */
+	for (iter = *list; iter; iter = g_slist_next (iter)) {
+		if (g_str_equal (iter->data, unmanaged_spec)) {
+			g_free (unmanaged_spec);
+			return;
+		}
+	}
+
+	nm_log_info (LOGD_SETTINGS, "Add unmanaged: %s", unmanaged_spec);
+	*list = g_slist_prepend (*list, unmanaged_spec);
+}
+
+static GSList *
+get_unmanaged_specs (NMSettingsPlugin * config)
+{
+	SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE ((SettingsPluginIfnet *) config);
+	GSList *list = NULL;
+
+	nm_log_info (LOGD_SETTINGS, "getting unmanaged specs...");
+	g_hash_table_foreach (priv->connections, check_unmanaged, &list);
+	return list;
+}
+
+static GSList *
+get_connections (NMSettingsPlugin *config)
+{
+	SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE ((SettingsPluginIfnet *) config);
+	GSList *connections = NULL;
+	GHashTableIter iter;
+	NMIfnetConnection *connection;
+
+	nm_log_info (LOGD_SETTINGS, "(%p) ... get_connections.", config);
+
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &connection)) {
+		const char *conn_name = nm_ifnet_connection_get_conn_name (connection);
+
+		if (!conn_name || (!priv->unmanaged_well_known && is_managed (conn_name)))
+			connections = g_slist_prepend (connections, connection);
+	}
+	nm_log_info (LOGD_SETTINGS, "(%p) connections count: %d",
+	             config, g_slist_length (connections));
+	return connections;
+}
+
+/*****************************************************************************/
+
+static void
+get_property (GObject * object, guint prop_id, GValue * value,
+              GParamSpec * pspec)
+{
+	switch (prop_id) {
+	case NM_SETTINGS_PLUGIN_PROP_NAME:
+		g_value_set_string (value, IFNET_PLUGIN_NAME_PRINT);
+		break;
+	case NM_SETTINGS_PLUGIN_PROP_INFO:
+		g_value_set_string (value, IFNET_PLUGIN_INFO);
+		break;
+	case NM_SETTINGS_PLUGIN_PROP_CAPABILITIES:
+		g_value_set_uint (value,
+		                  NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+/*****************************************************************************/
+
+static void
+init (NMSettingsPlugin *config)
+{
+	SettingsPluginIfnet *self = SETTINGS_PLUGIN_IFNET (config);
+	SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self);
+
+	nm_log_info (LOGD_SETTINGS, "Initializing!");
+
+	priv->connections = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref);
+	priv->unmanaged_well_known = !is_managed_plugin ();
+	nm_log_info (LOGD_SETTINGS, "management mode: %s",
+	             priv->unmanaged_well_known ? "unmanaged" : "managed");
+
+	setup_monitors (NULL, config);
+	reload_connections (config);
+
+	nm_log_info (LOGD_SETTINGS, "Initialzation complete!");
+}
+
+/*****************************************************************************/
+
+static void
+settings_plugin_ifnet_init (SettingsPluginIfnet * plugin)
+{
+}
+
+static void
+dispose (GObject * object)
+{
+	SettingsPluginIfnet *plugin = SETTINGS_PLUGIN_IFNET (object);
+	SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE ((SettingsPluginIfnet *) plugin);
+
+	cancel_monitors (NULL, object);
+	if (priv->connections) {
+		g_hash_table_destroy (priv->connections);
+		priv->connections = NULL;
+	}
+
+	ifnet_destroy ();
+	wpa_parser_destroy ();
+	G_OBJECT_CLASS (settings_plugin_ifnet_parent_class)->dispose (object);
+}
+
+static void
+settings_plugin_ifnet_class_init (SettingsPluginIfnetClass * req_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (req_class);
+
+	object_class->dispose = dispose;
+	object_class->get_property = get_property;
+
+	g_object_class_override_property (object_class,
+	                                  NM_SETTINGS_PLUGIN_PROP_NAME,
+	                                  NM_SETTINGS_PLUGIN_NAME);
+
+	g_object_class_override_property (object_class,
+	                                  NM_SETTINGS_PLUGIN_PROP_INFO,
+	                                  NM_SETTINGS_PLUGIN_INFO);
+
+	g_object_class_override_property (object_class,
+	                                  NM_SETTINGS_PLUGIN_PROP_CAPABILITIES,
+	                                  NM_SETTINGS_PLUGIN_CAPABILITIES);
+}
+
+static void
+settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface)
+{
+	plugin_iface->init = init;
+	plugin_iface->get_connections = get_connections;
+	plugin_iface->get_unmanaged_specs = get_unmanaged_specs;
+	plugin_iface->add_connection = add_connection;
+	plugin_iface->reload_connections = reload_connections;
+}
+
+/*****************************************************************************/
+
+G_MODULE_EXPORT GObject *
+nm_settings_plugin_factory (void)
+{
+	return G_OBJECT (g_object_ref (settings_plugin_ifnet_get ()));
+}
diff --git a/src/settings/plugins/ifnet/nms-ifnet-plugin.h b/src/settings/plugins/ifnet/nms-ifnet-plugin.h
new file mode 100644
index 00000000..f006e7e4
--- /dev/null
+++ b/src/settings/plugins/ifnet/nms-ifnet-plugin.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service (ifnet)
+ *
+ * Mu Qiao <qiaomuf@gmail.com>
+ *
+ * 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) 1999-2010 Gentoo Foundation, Inc.
+ */
+
+#ifndef _PLUGIN_H_
+#define _PLUGIN_H_
+
+#define SETTINGS_TYPE_PLUGIN_IFNET            (settings_plugin_ifnet_get_type ())
+#define SETTINGS_PLUGIN_IFNET(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SETTINGS_TYPE_PLUGIN_IFNET, SettingsPluginIfnet))
+#define SETTINGS_PLUGIN_IFNET_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SETTINGS_TYPE_PLUGIN_IFNET, SettingsPluginIfnetClass))
+#define SETTINGS_IS_PLUGIN_IFNET(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SETTINGS_TYPE_PLUGIN_IFNET))
+#define SETTINGS_IS_PLUGIN_IFNET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SETTINGS_TYPE_PLUGIN_IFNET))
+#define SETTINGS_PLUGIN_IFNET_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SETTINGS_TYPE_PLUGIN_IFNET, SettingsPluginIfnetClass))
+
+typedef struct _SettingsPluginIfnet SettingsPluginIfnet;
+typedef struct _SettingsPluginIfnetClass SettingsPluginIfnetClass;
+
+GType settings_plugin_ifnet_get_type (void);
+
+#endif
diff --git a/src/settings/plugins/ifnet/nms-ifnet-wpa-parser.c b/src/settings/plugins/ifnet/nms-ifnet-wpa-parser.c
new file mode 100644
index 00000000..2b62e886
--- /dev/null
+++ b/src/settings/plugins/ifnet/nms-ifnet-wpa-parser.c
@@ -0,0 +1,584 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Mu Qiao <qiaomuf@gmail.com>
+ *
+ * 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) 1999-2010 Gentoo Foundation, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nms-ifnet-wpa-parser.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "nm-utils/nm-hash-utils.h"
+#include "settings/nm-settings-plugin.h"
+
+#include "nms-ifnet-net-parser.h"
+#include "nms-ifnet-net-utils.h"
+
+/* Security information */
+static GHashTable *wsec_table = NULL;
+
+/* Global information used for writing */
+static GHashTable *wsec_global_table = NULL;
+
+static gboolean wpa_parser_data_changed = FALSE;
+
+static long
+wpa_get_long (GHashTable *table, const char *key)
+{
+	return atol (g_hash_table_lookup (table, key));
+}
+
+static void
+destroy_security (GHashTable * network)
+{
+	gpointer key, value;
+	GHashTableIter iter;
+
+	g_return_if_fail (network);
+	g_hash_table_iter_init (&iter, network);
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		g_free (key);
+		g_free (value);
+	}
+
+	g_hash_table_destroy (network);
+}
+
+static GHashTable *
+add_security (GHashTable *security)
+{
+	GHashTable *oldsecurity;
+	const char *ssid, *value;
+	char *ssid_key;
+	gboolean is_hex_ssid;
+
+	/* Every security information should have a ssid */
+	ssid = g_hash_table_lookup (security, "ssid");
+	if (!ssid) {
+		destroy_security (security);
+		return NULL;
+	}
+
+	/* Hex format begins with " */
+	is_hex_ssid = (ssid[0] != '"');
+	if ((value = g_hash_table_lookup (security, "disabled")) != NULL) {
+		if (strcmp (value, "1") == 0) {
+			destroy_security (security);
+			return NULL;
+		}
+	}
+
+	/* Default priority is 1 */
+	if (g_hash_table_lookup (security, "priority") == NULL)
+		g_hash_table_insert (security, g_strdup ("priority"),
+				     g_strdup ("1"));
+
+	oldsecurity = g_hash_table_lookup (wsec_table, ssid);
+	/* Security with lower priority will be ignored */
+	if (oldsecurity != NULL) {
+		if (wpa_get_long (oldsecurity, "priority") >=
+		    wpa_get_long (security, "priority")) {
+			destroy_security (security);
+			return NULL;
+		} else {
+			g_hash_table_remove (wsec_table, ssid);
+			destroy_security (oldsecurity);
+		}
+	}
+
+	/* format ssid */
+	ssid_key =
+	    is_hex_ssid ? g_strdup_printf ("0x%s",
+					   ssid) :
+	    strip_string (g_strdup (ssid), '"');
+	g_hash_table_insert (wsec_table, ssid_key, security);
+	return security;
+}
+
+static void
+add_key_value (GHashTable * network, gchar * line)
+{
+	gpointer orig_key, orig_value;
+	gchar **key_value;
+
+	if (g_str_has_prefix (line, "network={"))
+		line += 9;
+	strip_string (line, '{');
+	strip_string (line, '}');
+	if (line[0] == '\0')
+		return;
+	key_value = g_strsplit (line, "=", 2);
+	if (g_strv_length (key_value) != 2) {
+		g_strfreev (key_value);
+		return;
+	}
+	g_strstrip (key_value[0]);
+	g_strstrip (key_value[1]);
+
+	/* Reserve quotes for psk, wep_key, ssid
+	 * Quotes will determine whether they are hex format */
+	if (strcmp (key_value[0], "psk") != 0
+	    && !g_str_has_prefix (key_value[0], "wep_key")
+	    && strcmp (key_value[0], "ssid") != 0)
+		strip_string (key_value[1], '"');
+
+	/* This sucks */
+	if (g_hash_table_lookup_extended (network, key_value[0], &orig_key, &orig_value)) {
+		g_hash_table_remove (network, orig_key);
+		g_free (orig_key);
+		g_free (orig_value);
+	}
+
+	g_hash_table_insert (network, g_strdup (key_value[0]),
+			     g_strdup (key_value[1]));
+	g_strfreev (key_value);
+}
+
+static void
+add_one_wep_key (GHashTable * table, int key_num, gchar * one_wep_key)
+{
+	if (one_wep_key[0] == 's') {
+		//asc key
+		g_hash_table_insert (table,
+				     g_strdup_printf ("wep_key%d", key_num - 1),
+				     g_strdup_printf ("\"%s\"",
+						      one_wep_key + 2));
+	} else {
+		gchar buf[30];
+		int i = 0, j = 0;
+
+		//hex key
+		while (one_wep_key[i] != '\0') {
+			if (one_wep_key[i] != '-')
+				buf[j++] = one_wep_key[i];
+			i++;
+		}
+		buf[j] = '\0';
+		g_hash_table_insert (table,
+				     g_strdup_printf ("wep_key%d", key_num - 1),
+				     g_strdup (buf));
+
+	}
+}
+
+/* Reading wep security information from /etc/conf.d/net.
+ * This should not be used in future, use wpa_supplicant instead. */
+static void
+add_keys_from_net (void)
+{
+	GList *names = ifnet_get_connection_names ();
+	GList *iter = names;
+	gchar *wep_keys = "(\\[([1-4])\\]\\s+(s:\\w{5}|s:\\w{13}|"
+	    "([\\da-fA-F]{4}\\-){2}[\\da-fA-F]{2}|"
+	    "([\\da-fA-F]{4}\\-){6}[\\da-fA-F]{2})\\s+)";
+	gchar *key_method =
+	    "\\s+key\\s+\\[([1-4])\\]\\s+enc\\s+(open|restricted)";
+	GRegex *regex_keys = g_regex_new (wep_keys, 0, 0, NULL);
+	GRegex *regex_method = g_regex_new (key_method, 0, 0, NULL);
+	GMatchInfo *keys_info;
+	GMatchInfo *method_info;
+
+	while (iter) {
+		gchar *conn_name = iter->data;
+		GHashTable *table;
+		const char *key_str;
+
+		if ((key_str = ifnet_get_data (conn_name, "key")) == NULL) {
+			iter = g_list_next (iter);
+			continue;
+		}
+
+		wpa_add_security (conn_name);
+		table = _get_hash_table (conn_name);
+		/* Give lowest priority */
+		wpa_set_data (conn_name, "priority", "0");
+		g_regex_match (regex_keys, key_str, 0, &keys_info);
+		/* add wep keys */
+		while (g_match_info_matches (keys_info)) {
+			gchar *key_num = g_match_info_fetch (keys_info, 2);
+			gchar *one_wep_key = g_match_info_fetch (keys_info, 3);
+
+			add_one_wep_key (table, atoi (key_num), one_wep_key);
+			g_free (key_num);
+			g_free (one_wep_key);
+			g_match_info_next (keys_info, NULL);
+		}
+		g_match_info_free (keys_info);
+
+		g_regex_match (regex_method, key_str, 0, &method_info);
+		/* set default key index and auth alg */
+		if (g_match_info_matches (method_info)) {
+			gchar *default_idx =
+			    g_match_info_fetch (method_info, 1);
+			gchar *method = g_match_info_fetch (method_info, 2);
+
+			default_idx[0]--;
+			g_hash_table_insert (table, g_strdup ("wep_tx_keyidx"),
+					     default_idx);
+			g_hash_table_insert (table, g_strdup ("auth_alg"),
+					     g_ascii_strup (method, -1));
+		}
+		g_match_info_free (method_info);
+		add_security (table);
+		iter = g_list_next (iter);
+	}
+	g_list_free (names);
+	g_regex_unref (regex_keys);
+	g_regex_unref (regex_method);
+}
+
+static void
+add_global_data (gchar * line)
+{
+	gchar **key_value;
+
+	g_strstrip (line);
+	key_value = g_strsplit (line, "=", 2);
+	if (g_strv_length (key_value) != 2) {
+		nm_log_warn (LOGD_SETTINGS, "Can't handle this line: %s\n", line);
+		g_strfreev (key_value);
+		return;
+	}
+	g_hash_table_insert (wsec_global_table,
+			     g_strdup (g_strstrip (key_value[0])),
+			     g_strdup (g_strstrip (key_value[1])));
+	g_strfreev (key_value);
+}
+
+void
+wpa_parser_init (const char *wpa_supplicant_conf)
+{
+	GIOChannel *channel = NULL;
+	gchar *line;
+	gboolean complete = FALSE;
+
+	wpa_parser_data_changed = FALSE;
+	wsec_table = g_hash_table_new (nm_str_hash, g_str_equal);
+	wsec_global_table = g_hash_table_new (nm_str_hash, g_str_equal);
+
+	if (g_file_test (wpa_supplicant_conf, G_FILE_TEST_IS_REGULAR))
+		channel =
+		    g_io_channel_new_file (wpa_supplicant_conf, "r", NULL);
+	if (channel == NULL) {
+		nm_log_warn (LOGD_SETTINGS, "Can't open %s for wireless security",
+		             wpa_supplicant_conf);
+		return;
+	}
+
+	while (g_io_channel_read_line (channel, &line, NULL, NULL, NULL)
+	       != G_IO_STATUS_EOF) {
+		g_strstrip (line);
+		if (line[0] != '#' && line[0] != '\0') {
+			if (strstr (line, "network={") == NULL) {
+				add_global_data (line);
+				g_free (line);
+				continue;
+			} else {
+				GHashTable *network =
+				    g_hash_table_new (nm_str_hash, g_str_equal);
+
+				do {
+					gchar *quote_start, *quote_end = NULL, *comment;
+
+					if (line[0] == '#' || line[0] == '\0') {
+						g_free (line);
+						continue;
+					}
+					/* ignore inline comments unless inside
+					   a double-quoted string */
+					if ((quote_start = strchr (line, '"')) != NULL)
+						quote_end = strrchr (quote_start + 1, '"');
+					if ((comment = strchr ((quote_end != NULL) ?
+					                       quote_end : line, '#')) != NULL)
+						*comment = '\0';
+					if (strstr (line, "}") != NULL)
+						complete = TRUE;
+					add_key_value (network, line);
+					g_free (line);
+				} while (complete == FALSE
+					 &&
+					 g_io_channel_read_line
+					 (channel, &line, NULL,
+					  NULL, NULL) != G_IO_STATUS_EOF);
+				add_security (network);
+				//EOF in inner loop
+				if (complete == FALSE) {
+					g_free (line);
+					break;
+				}
+				complete = FALSE;
+			}
+		} else
+			g_free (line);
+	}
+
+	g_io_channel_shutdown (channel, FALSE, NULL);
+	g_io_channel_unref (channel);
+
+	add_keys_from_net ();
+}
+
+const char *
+wpa_get_value (const char *ssid, const char *key)
+{
+	GHashTable *target = g_hash_table_lookup (wsec_table, ssid);
+
+	if (target)
+		return g_hash_table_lookup (target, key);
+	return NULL;
+}
+
+gboolean
+exist_ssid (const char *ssid)
+{
+	return g_hash_table_lookup (wsec_table, ssid) != NULL;
+}
+
+GHashTable *
+_get_hash_table (const char *ssid)
+{
+	return g_hash_table_lookup (wsec_table, ssid);
+}
+
+static gchar *quoted_keys[] =
+    { "identity", "cert", "private", "phase", "password", NULL };
+
+/* tell whether the key needs quotes when writing is performed */
+static gboolean
+need_quote (gchar * key)
+{
+	int i = 0;
+
+	while (quoted_keys[i] != NULL) {
+		if (strstr (key, quoted_keys[i]))
+			return TRUE;
+		i++;
+	}
+	return FALSE;
+}
+
+gboolean
+wpa_flush_to_file (const char *config_file)
+{
+	GIOChannel *channel;
+	GError *error = NULL;
+	gpointer key, value, ssid, security;
+	GHashTableIter iter, iter_security;
+	gchar *out_line;
+	gsize bytes_written;
+	gboolean result = FALSE;
+
+	if (!wpa_parser_data_changed)
+		return TRUE;
+	if (!wsec_table || !wsec_global_table)
+		return FALSE;
+
+	backup_file (config_file);
+
+	channel = g_io_channel_new_file (config_file, "w", NULL);
+	if (!channel) {
+		nm_log_warn (LOGD_SETTINGS, "Can't open file %s for writing", config_file);
+		return FALSE;
+	}
+	g_hash_table_iter_init (&iter, wsec_global_table);
+	nm_log_info (LOGD_SETTINGS, "Writing to %s", config_file);
+	g_io_channel_write_chars (channel,
+				  "#Generated by NetworkManager\n"
+				  "###### Global Configuration ######\n",
+				  -1, &bytes_written, &error);
+	if (error)
+		goto done;
+
+	/* Writing global information */
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		out_line =
+		    g_strdup_printf ("%s=%s\n", (gchar *) key, (gchar *) value);
+		g_io_channel_write_chars (channel, out_line, -1, &bytes_written,
+					  &error);
+		if (bytes_written == 0 || error)
+			break;
+		g_free (out_line);
+	}
+	if (error)
+		goto done;
+	g_io_channel_write_chars (channel,
+				  "\n###### Security Configuration ######\n",
+				  -1, &bytes_written, &error);
+	if (error)
+		goto done;
+
+	g_hash_table_iter_init (&iter, wsec_table);
+	/* Writing security */
+	while (g_hash_table_iter_next (&iter, &ssid, &security)) {
+		g_hash_table_iter_init (&iter_security,
+					(GHashTable *) security);
+		g_io_channel_write_chars (channel, "network={\n", -1,
+					  &bytes_written, &error);
+		if (error)
+			goto done;
+		while (g_hash_table_iter_next (&iter_security, &key, &value)) {
+			out_line =
+			    g_strdup_printf (need_quote ((gchar *) key) ?
+					     "\t%s=\"%s\"\n" : "\t%s=%s\n",
+					     (gchar *) key, (gchar *) value);
+			g_io_channel_write_chars (channel, out_line, -1,
+						  &bytes_written, &error);
+			if (bytes_written == 0 || error)
+				goto done;
+			g_free (out_line);
+		}
+		g_io_channel_write_chars (channel, "}\n\n", -1, &bytes_written, &error);
+
+	}
+	g_io_channel_flush (channel, &error);
+	if (error)
+		goto done;
+
+	wpa_parser_data_changed = FALSE;
+	result = TRUE;
+done:
+	if (error) {
+		nm_log_warn (LOGD_SETTINGS, "Error writing WPA configuration: %s", error->message);
+		g_error_free (error);
+	}
+	g_io_channel_shutdown (channel, FALSE, NULL);
+	g_io_channel_unref (channel);
+	return result;
+}
+
+/* If value is NULL, this method will delete old key value pair */
+void
+wpa_set_data (const char *ssid, const char *key, const char *value)
+{
+	gpointer old_key = NULL, old_value = NULL;
+	GHashTable *security = g_hash_table_lookup (wsec_table, ssid);
+	gchar * stripped = NULL;
+
+	g_return_if_fail (security != NULL);
+
+	if (value){
+		stripped = g_strdup(value);
+		if (strcmp (key, "ssid") != 0 && strcmp (key, "psk") != 0
+			&& !g_str_has_prefix (key, "wep_key"))
+			strip_string (stripped, '"');
+	}
+
+	/* Remove old key value pairs */
+	if (g_hash_table_lookup_extended
+	    (security, key, &old_key, &old_value)) {
+		if (stripped && !strcmp(old_value, stripped)){
+			g_free (stripped);
+			return;
+		}
+		g_hash_table_remove (security, old_key);
+		g_free (old_key);
+		g_free (old_value);
+	} else if (!value)
+		return;
+
+	/* Add new key value */
+	if (stripped)
+		g_hash_table_insert (security, g_strdup (key), stripped);
+	wpa_parser_data_changed = TRUE;
+}
+
+gboolean
+wpa_has_security (const char *ssid)
+{
+	return g_hash_table_lookup (wsec_table, ssid) != NULL;
+}
+
+gboolean
+wpa_add_security (const char *ssid)
+{
+	if (wpa_has_security (ssid))
+		return TRUE;
+	else {
+		GHashTable *security =
+		    g_hash_table_new (nm_str_hash, g_str_equal);
+		gchar *ssid_i;
+
+		nm_log_info (LOGD_SETTINGS, "Adding security for %s", ssid);
+		if (g_str_has_prefix (ssid, "0x")) {
+			/* hex ssid */
+			ssid_i = g_strdup (ssid + 2);
+		} else {
+			/* ascii ssid requires quotes */
+			ssid_i = g_strdup_printf ("\"%s\"", ssid);
+		}
+		g_hash_table_insert (security, strdup ("ssid"), ssid_i);
+		g_hash_table_insert (security, strdup ("priority"),
+				     strdup ("1"));
+		g_hash_table_insert (wsec_table, g_strdup (ssid), security);
+		wpa_parser_data_changed = TRUE;
+		return TRUE;
+	}
+}
+
+gboolean
+wpa_delete_security (const char *ssid)
+{
+	gpointer old_key, old_value;
+
+	g_return_val_if_fail (wsec_table != NULL && ssid != NULL, FALSE);
+	nm_log_info (LOGD_SETTINGS, "Deleting security for %s", ssid);
+	if (!g_hash_table_lookup_extended
+	    (wsec_table, ssid, &old_key, &old_value))
+		return FALSE;
+	g_hash_table_remove (wsec_table, old_key);
+	g_free (old_key);
+	destroy_security ((GHashTable *) old_value);
+	wpa_parser_data_changed = TRUE;
+	return TRUE;
+
+}
+
+void
+wpa_parser_destroy (void)
+{
+	GHashTableIter iter;
+	gpointer key;
+	gpointer value;
+
+	/* Destroy security */
+	if (wsec_table) {
+		g_hash_table_iter_init (&iter, wsec_table);
+		while (g_hash_table_iter_next (&iter, &key, &value)) {
+			destroy_security ((GHashTable *) value);
+			g_free (key);
+		}
+
+		g_hash_table_destroy (wsec_table);
+		wsec_table = NULL;
+	}
+
+	/* Destroy global data */
+	if (wsec_global_table) {
+		g_hash_table_iter_init (&iter, wsec_global_table);
+		while (g_hash_table_iter_next (&iter, &key, &value)) {
+			g_free (key);
+			g_free (value);
+		}
+
+		g_hash_table_destroy (wsec_global_table);
+		wsec_global_table = NULL;
+	}
+}
diff --git a/src/settings/plugins/ifnet/nms-ifnet-wpa-parser.h b/src/settings/plugins/ifnet/nms-ifnet-wpa-parser.h
new file mode 100644
index 00000000..d096f468
--- /dev/null
+++ b/src/settings/plugins/ifnet/nms-ifnet-wpa-parser.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * Mu Qiao <qiaomuf@gmail.com>
+ *
+ * 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) 1999-2010 Gentoo Foundation, Inc.
+ */
+
+#ifndef _WPA_PARSER_H
+#define _WPA_PARSER_H
+
+#define WPA_SUPPLICANT_CONF SYSCONFDIR "/wpa_supplicant/wpa_supplicant.conf"
+
+void wpa_parser_init (const char *wpa_supplicant_conf);
+void wpa_parser_destroy (void);
+
+/* reader functions */
+const char *wpa_get_value (const char *ssid, const char *key);
+gboolean exist_ssid (const char *ssid);
+GHashTable *_get_hash_table (const char *ssid);
+gboolean wpa_has_security (const char *ssid);
+
+/* writer functions */
+gboolean wpa_flush_to_file (const char *config_file);
+void wpa_set_data (const char *ssid, const char *key, const char *value);
+gboolean wpa_add_security (const char *ssid);
+gboolean wpa_delete_security (const char *ssid);
+#endif
diff --git a/src/settings/plugins/ifnet/tests/net b/src/settings/plugins/ifnet/tests/net
new file mode 100644
index 00000000..a5ac9ca2
--- /dev/null
+++ b/src/settings/plugins/ifnet/tests/net
@@ -0,0 +1,158 @@
+# This blank configuration will automatically use DHCP for any net.*
+# scripts in /etc/init.d.  To create a more complete configuration,
+# please review /etc/conf.d/net.example and save your configuration
+# in /etc/conf.d/net (this file :]!).
+
+modules="!wpa_supplicant"
+
+config_eth0=(
+"202.117.16.121    netmask    255.255.255.0 brd 202.117.16.255"
+"192.168.4.121/24"
+"dhcp6"
+)
+routes_eth0=( "default via     202.117.16.1" 
+		"192.168.4.0/24 via 192.168.4.1")
+dns_servers_eth0="202.117.0.20    202.117.0.21"
+dns_search_eth0="p12.edu.cn p13.edu.cn"
+
+config_eth1=(
+	"dhcp"
+)
+enable_ipv6_eth1="true"
+routes_eth1=( "default via 202.117.16.1" )
+dns_servers_eth1="202.117.0.20 202.117.0.21"
+config_eth2=(
+"202.117.16.1211    netmask    255.255.255.0 brd 202.117.16.255"
+"192.168.4.121/24"
+"4321:0:1:2:3:4:567:89ab/64"
+)
+routes_eth2=("default via  4321:0:1:2:3:4:567:89ab")
+enable_ipv6_eth2="true"
+config_eth3=("nufjlsjlll")
+managed_eth4="false"
+routes_eth4=("default via 4321:0:1:2:3:4:567:89ab")
+config_eth5=("dhcp")
+
+config_eth7=( "dhcp" )
+auto_eth7="true"
+
+# missing config_eth8
+auto_eth8="true"
+
+#new openrc style
+config_eth9="202.117.16.10/24 202.117.17.10/24"
+routes_eth9="default via 202.117.16.1
+10.0.0.0/8 via 192.168.0.1
+"
+config_eth10="202.117.16.2 netmask 255.255.255.0"
+routes_eth10="10.0.0.0/8 via 192.168.0.1"
+
+config_myxjtu2=("202.117.16.121/24 brd 202.117.16.255")
+routes_myxjtu2=("default via 202.117.16.1")
+dns_servers_myxjtu2="202.117.0.20 202.117.0.21"
+#key_myxjtu2="[1] s:xjtud key [1] enc restricted"
+#key_eth6="[1] aaaa-4444-3d [2] s:xjtudlc key [1] enc open"
+
+
+username_ppp0='user'
+password_ppp0='password'
+
+config_qiaomuf=("dhcp")
+
+config_1xtest=("dhcp")
+
+config_0xab3ace=("dhcp")
+
+modules=( "iproute2" )
+	config_kvm0=( "null" )
+	config_kvm1=( "null" )
+
+	tuntap_kvm0="tap"
+	tuntap_kvm1="tap"
+	tunctl_kvm0="-u user"
+	tunctl_kvm1="-u user"
+
+bridge_br0="eth0 kvm0 kvm1"
+config_br0=( "192.168.1.10/24" )
+	brctl_br0=( "setfd 0")
+	dhcp_eth1="nosendhost nontp -I"
+
+predown() {
+	# The default in the script is to test for NFS root and disallow
+	# downing interfaces in that case.  Note that if you specify a
+	# predown() function you will override that logic.  Here it is, in
+	# case you still want it...
+	if is_net_fs /; then
+		eerror "root filesystem is network mounted -- can't stop ${IFACE}"
+		return 1
+	fi
+
+	# Remember to return 0 on success
+	return 0
+}
+
+postup() {
+	# This function could be used, for example, to register with a
+	# dynamic DNS service.  Another possibility would be to
+	# send/receive mail once the interface is brought up.
+
+	# Here is an example that allows the use of iproute rules
+	# which have been configured using the rules_eth0 variable.
+	#rules_eth0=" \
+	#	'from 24.80.102.112/32 to 192.168.1.0/24 table localnet priority 100' \
+	#	'from 216.113.223.51/32 to 192.168.1.0/24 table localnet priority 100' \
+	#"
+	eval set -- \$rules_${IFVAR}
+	if [ $# != 0 ]; then
+		einfo "Adding IP policy routing rules"
+		eindent
+		# Ensure that the kernel supports policy routing
+		if ! ip rule list | grep -q "^"; then
+			eerror "You need to enable IP Policy Routing (CONFIG_IP_MULTIPLE_TABLES)"
+			eerror "in your kernel to use ip rules"
+		else
+			for x; do
+				ebegin "${x}"
+				ip rule add ${x}
+				eend $?
+			done
+		fi
+		eoutdent
+		# Flush the cache
+		ip route flush cache dev "${IFACE}"
+	fi
+
+}
+
+postdown() {
+	# Enable Wake-On-LAN for every interface except for lo
+	# Probably a good idea to set ifdown="no" in /etc/conf.d/net
+	# as well ;)
+	[ "${IFACE}" != "lo" ] && ethtool -s "${IFACE}" wol g
+
+	Automatically erase any ip rules created in the example postup above
+	if interface_exists "${IFACE}"; then
+		# Remove any rules for this interface
+		local rule
+		ip rule list | grep " iif ${IFACE}[ ]*" | {
+			while read rule; do
+				rule="${rule#*:}"	
+				ip rule del ${rule}
+			done
+		}
+		# Flush the route cache
+		ip route flush cache dev "${IFACE}"
+	fi
+
+	# Return 0 always
+	return 0
+}
+
+failup() {
+       # This function is mostly here for completeness... I haven't
+       # thought of anything nifty to do with it yet ;-)
+}
+
+faildown() 
+{}
+
diff --git a/src/settings/plugins/ifnet/tests/net.all b/src/settings/plugins/ifnet/tests/net.all
new file mode 100644
index 00000000..285a4cdf
--- /dev/null
+++ b/src/settings/plugins/ifnet/tests/net.all
@@ -0,0 +1,864 @@
+##############################################################################
+# QUICK-START
+#
+# The quickest start is if you want to use DHCP.
+# In that case, everything should work out of the box, no configuration
+# necessary, though the startup script will warn you that you haven't
+# specified anything.
+
+# WARNING :- some examples have a mixture of IPv4 (ie 192.168.0.1) and IPv6
+# (ie 4321:0:1:2:3:4:567:89ab) internet addresses. They only work if you have
+# the relevant kernel option enabled. So if you don't have an IPv6 enabled
+# kernel then remove the IPv6 address from your config.
+
+# If you want to use a static address or use DHCP explicitly, jump
+# down to the section labelled INTERFACE HANDLERS.
+#
+# If you want to do anything more fancy, you should take the time to
+# read through the rest of this file.
+
+##############################################################################
+# MODULES
+#
+# We now support modular networking scripts which means we can easily
+# add support for new interface types and modules while keeping
+# compatability with existing ones.
+# 
+# Modules load by default if the package they need is installed.  If
+# you specify a module here that doesn't have it's package installed
+# then you get an error stating which package you need to install.
+# Ideally, you only use the modules setting when you have two or more
+# packages installed that supply the same service.
+#
+# In other words, you probably should DO NOTHING HERE...
+
+# Prefer ifconfig over iproute2
+modules=( "ifconfig" )
+
+# You can also specify other modules for an interface
+# In this case we prefer udhcpc over dhcpcd
+modules_eth0=( "udhcpc" )
+
+# You can also specify which modules not to use - for example you may be
+# using a supplicant or linux-wlan-ng to control wireless configuration but
+# you still want to configure network settings per ESSID associated with.
+modules=( "!iwconfig" "!wpa_supplicant" )
+# IMPORTANT: If you need the above, please disable modules in that order
+
+
+##############################################################################
+# INTERFACE HANDLERS
+# 
+# We provide two interface handlers presently: ifconfig and iproute2.
+# You need one of these to do any kind of network configuration.
+# For ifconfig support, emerge sys-apps/net-tools
+# For iproute2 support, emerge sys-apps/iproute2
+
+# If you don't specify an interface then we prefer iproute2 if it's installed
+# To prefer ifconfig over iproute2
+modules=( "ifconfig" )
+
+# For a static configuration, use something like this
+# (They all do exactly the same thing btw)
+config_eth0=( "192.168.0.2/24" )
+config_eth0=( "192.168.0.2 netmask 255.255.255.0" )
+
+# We can also specify a broadcast
+config_eth0=( "192.168.0.2/24 brd 192.168.0.255" )
+config_eth0=( "192.168.0.2 netmask 255.255.255.0 broadcast 192.168.0.255" )
+
+# If you need more than one address, you can use something like this
+# NOTE: ifconfig creates an aliased device for each extra IPv4 address
+#       (eth0:1, eth0:2, etc)
+#       iproute2 does not do this as there is no need to
+config_eth0=(
+	"192.168.0.2/24"
+	"192.168.0.3/24"
+	"192.168.0.4/24"
+)
+# Or you can use sequence expressions
+config_eth0=( "192.168.0.{2..4}/24" )
+# which does the same as above. Be careful though as if you use this and
+# fallbacks, you have to ensure that both end up with the same number of
+# values otherwise your fallback won't work correctly.
+
+# You can also use IPv6 addresses
+# (you should always specify a prefix length with IPv6 here)
+config_eth0=(
+	"192.168.0.2/24"
+	"4321:0:1:2:3:4:567:89ab/64"
+	"4321:0:1:2:3:4:567:89ac/64"
+)
+
+# If you wish to keep existing addresses + routing and the interface is up,
+# you can specify a noop (no operation). If the interface is down or there
+# are no addresses assigned, then we move onto the next step (default dhcp)
+# This is useful when configuring your interface with a kernel command line
+# or similar
+config_eth0=( "noop" "192.168.0.2/24" )
+
+# If you don't want ANY address (only useful when calling for advanced stuff)
+config_eth0=( "null" )
+
+# Here's how to do routing if you need it
+routes_eth0=(
+	"default via 192.168.0.1"		# IPv4 default route
+	"10.0.0.0/8 via 192.168.0.1"		# IPv4 subnet route
+	"::/0"					# IPv6 unicast
+)
+
+# If a specified module fails (like dhcp - see below), you can specify a
+# fallback like so
+fallback_eth0=( "192.168.0.2 netmask 255.255.255.0" )
+fallback_route_eth0=( "default via 192.168.0.1" )
+
+# NOTE: fallback entry must match the entry location in config_eth0
+# As such you can only have one fallback route.
+
+# Some users may need to alter the MTU - here's how
+mtu_eth0="1500"
+
+# Each module described below can set a default base metric, lower is
+# preferred over higher. This is so we can prefer a wired route over a
+# wireless route automaticaly. You can override this by setting
+metric_eth0="100"
+# or on a global basis
+metric="100"
+# The only downside of the global setting is that you have to ensure that
+# there are no conflicting routes yourself. For users with large routing
+# tables you may have to set a global metric as the due to a simple read of
+# the routing table taking over a minute at a time.
+
+##############################################################################
+# OPTIONAL MODULES
+
+# INTERFACE RENAMING
+# There is no consistent device renaming scheme for Linux.
+# The preferred way of naming devices is via the kernel module directly or
+# by using udev (http://www.reactivated.net/udevrules.php)
+
+# If you are unable to write udev rules, then we do provide a way of renaming
+# the interface based on it's MAC address, but it is not optimal.
+# Here is how to rename an interface whose MAC address is 00:11:22:33:44:55
+# to foo1
+rename_001122334455="foo1"
+
+# You can also do this based on current device name - although this is not
+# recommended. Here we rename eth1 to foo2.
+rename_eth1="foo2"
+
+#-----------------------------------------------------------------------------
+# WIRELESS (802.11 support)
+# Wireless can be provided by iwconfig or wpa_supplicant
+
+# iwconfig
+# emerge net-wireless/wireless-tools
+# Wireless options are held in /etc/conf.d/wireless - but could be here too
+# Consult the sample file /etc/conf.d/wireless.example for instructions
+# iwconfig is the default
+
+# wpa_supplicant
+# emerge net-wireless/wpa-supplicant
+# Wireless options are held in /etc/wpa_supplicant.conf
+# Consult the sample file /etc/wpa_supplicant.conf.example for instructions
+# To choose wpa_supplicant over iwconfig
+modules=( "wpa_supplicant" )
+# To configure wpa_supplicant
+wpa_supplicant_eth0="-Dwext" # For generic wireless
+wpa_supplicant_ath0="-Dmadwifi" # For Atheros based cards
+# Consult wpa_supplicant for more drivers
+# By default don't wait for wpa_suppliant to associate and authenticate.
+# If you would like to, so can specify how long in seconds
+associate_timeout_eth0=60
+# A value of 0 means wait forever.
+
+# GENERIC WIRELESS OPTIONS
+# PLEASE READ THE INSTRUCTIONS IN /etc/conf.d/wireless.example FOR
+# HOW TO USE THIS ESSID VARIABLE
+# You can also override any settings found here per ESSID - which is very
+# handy if you use different networks a lot
+config_ESSID=( "dhcp" )
+dhcpcd_ESSID="-t 5"
+
+# Setting name/domain server causes /etc/resolv.conf to be overwritten
+# Note that if DHCP is used, and you want this to take precedence then
+ set dhcp_ESSID="nodns"
+dns_servers_ESSID=( "192.168.0.1" "192.168.0.2" )
+dns_domain_ESSID="some.domain"
+dns_search_ESSID="search.this.domain search.that.domain"
+# Please check the man page for resolv.conf for more information
+# as domain and search are mutually exclusive.
+
+# You can also override any settings found here per MAC address of the AP
+# in case you use Access Points with the same ESSID but need different
+# networking configs. Below is an example - of course you use the same
+# method with other variables
+mac_config_001122334455=( "dhcp" )
+mac_dhcpcd_001122334455="-t 10"
+mac_dns_servers_001122334455=( "192.168.0.1" "192.168.0.2" )
+
+# When an interface has been associated with an Access Point, a global
+# variable called ESSID is set to the Access Point's ESSID for use in the
+# pre/post user functions below (although it's not available in preup as you
+# won't have associated then)
+
+# If you're using anything else to configure wireless on your interface AND
+# you have installed any of the above packages, you need to disable them
+modules=( "!iwconfig" "!wpa_supplicant" )
+
+#-----------------------------------------------------------------------------
+# DHCP
+# DHCP can be provided by dhclient, dhcpcd, pump or udhcpc.
+#
+# dhclient: emerge net-misc/dhcp
+# dhcpcd:   emerge net-misc/dhcpcd
+# pump:     emerge net-misc/pump
+# udhcpc:   emerge net-misc/udhcp
+
+# If you have more than one DHCP client installed, you need to specify which
+# one to use - otherwise we default to dhcpcd if available.
+modules=( "dhclient" ) # to select dhclient over dhcpcd
+#
+# Notes:
+# - All clients send the current hostname to the DHCP server by default
+# - dhcpcd does not daemonize when the lease time is infinite
+# - udhcp-0.9.3-r3 and earlier do not support getting NTP servers 
+# - pump does not support getting NIS servers
+# - DHCP tends to erase any existing device information - so add
+#   static addresses after dhcp if you need them
+# - dhclient and udhcpc can set other resolv.conf options such as "option"
+#   and "sortlist"- see the System module for more details
+
+# Regardless of which DHCP client you prefer, you configure them the
+# same way using one of following depending on which interface modules
+# you're using.
+config_eth0=( "dhcp" )
+
+# For passing custom options to dhcpcd use something like the following.  This
+# example reduces the timeout for retrieving an address from 60 seconds (the
+# default) to 10 seconds.
+dhcpcd_eth0="-t 10"
+
+# dhclient, udhcpc and pump don't have many runtime options
+# You can pass options to them in a similar manner to dhcpcd though
+dhclient_eth0="..."
+udhcpc_eth0="..."
+pump_eth0="..."
+
+# GENERIC DHCP OPTIONS
+# Set generic DHCP options like so
+dhcp_eth0="release nodns nontp nonis nogateway nosendhost"
+
+# This tells the dhcp client to release it's lease when it stops, not to
+# overwrite dns, ntp and nis settings, not to set a default route and not to
+# send the current hostname to the dhcp server and when it starts.
+# You can use any combination of the above options - the default is not to
+# use any of them.
+
+#-----------------------------------------------------------------------------
+# For APIPA support, emerge net-misc/iputils or net-analyzer/arping
+
+# APIPA is a module that tries to find a free address in the range
+# 169.254.0.0-169.254.255.255 by arping a random address in that range on the
+# interface. If no reply is found then we assign that address to the interface
+
+# This is only useful for LANs where there is no DHCP server and you don't
+# connect directly to the internet.
+config_eth0=( "dhcp" )
+fallback_eth0=( "apipa" )
+
+#-----------------------------------------------------------------------------
+# ARPING Gateway configuration 
+# and
+# Automatic Private IP Addressing (APIPA)
+# For arpingnet / apipa support, emerge net-misc/iputils or net-analyzer/arping
+#
+# This is a module that tries to find a gateway IP. If it exists then we use
+# that gateways configuration for our own. For the configuration variables
+# simply ensure that each octet is zero padded and the dots are removed.
+# Below is an example.
+#
+gateways_eth0="192.168.0.1 10.0.0.1"
+config_192168000001=( "192.168.0.2/24" )
+routes_192168000001=( "default via 192.168.0.1" )
+dns_servers_192168000001=( "192.168.0.1" )
+config_010000000001=( "10.0.0.254/8" )
+routes_010000000001=( "default via 10.0.0.1" )
+dns_servers_010000000001=( "10.0.0.1" )
+
+# We can also specify a specific MAC address for each gateway if different
+# networks have the same gateway.
+gateways_eth0="192.168.0.1,00:11:22:AA:BB:CC 10.0.0.1,33:44:55:DD:EE:FF"
+config_192168000001_001122AABBCC=( "192.168.0.2/24" )
+routes_192168000001_001122AABBCC=( "default via 192.168.0.1" )
+dns_servers_192168000001_001122AABBCC=( "192.168.0.1" )
+config_010000000001_334455DDEEFF=( "10.0.0.254/8" )
+routes_010000000001_334455DDEEFF=( "default via 10.0.0.1" )
+dns_servers_010000000001_334455DDEEFF=( "10.0.0.1" )
+
+# If we don't find any gateways (or there are none configured) then we try and
+# use APIPA to find a free address in the range 169.254.0.0-169.254.255.255
+# by arping a random address in that range on the interface. If no reply is
+# found then we assign that address to the interface.
+
+# This is only useful for LANs where there is no DHCP server.
+config_eth0=( "arping" )
+
+# or if no DHCP server can be found
+config_eth0=( "dhcp" )
+fallback_eth0=( "arping" )
+
+# NOTE: We default to sleeping for 1 second the first time we attempt an
+# arping to give the interface time to settle on the LAN. This appears to
+# be a good default for most instances, but if not you can alter it here.
+arping_sleep=5
+arping_sleep_lan=7
+
+# NOTE: We default to waiting 3 seconds to get an arping response. You can
+# change the default wait like so.
+arping_wait=3
+arping_wait_lan=2
+
+#-----------------------------------------------------------------------------
+# VLAN (802.1q support)
+# For VLAN support, emerge net-misc/vconfig
+
+# Specify the VLAN numbers for the interface like so
+# Please ensure your VLAN IDs are NOT zero-padded
+vlans_eth0="1 2"
+
+# You may not want to assign an IP to the physical interface, but we still
+# need it up.
+config_eth0=( "null" )
+
+# You can also configure the VLAN - see for vconfig man page for more details
+vconfig_eth0=( "set_name_type VLAN_PLUS_VID_NO_PAD" )
+vconfig_vlan1=( "set_flag 1" "set_egress_map 2 6" )
+config_vlan1=( "172.16.3.1 netmask 255.255.254.0" )
+config_vlan2=( "172.16.2.1 netmask 255.255.254.0" )
+
+# NOTE: Vlans can be configured with a . in their interface names
+# When configuring vlans with this name type, you need to replace . with a _
+config_eth0.1=( "dhcp" ) - does not work
+config_eth0_1=( "dhcp" ) - does work
+
+# NOTE: Vlans are controlled by their physical interface and not per vlan
+# This means you do not need to create init scripts in /etc/init.d for each
+# vlan, you must need to create one for the physical interface.
+# If you wish to control the configuration of each vlan through a separate
+# script, or wish to rename the vlan interface to something that vconfig
+# cannot then you need to do this.
+vlan_start_eth0="no"
+
+# If you do the above then you may want to depend on eth0 like so
+ RC_NEED_vlan1="net.eth0"
+# NOTE: depend functions only work in /etc/conf.d/net
+# and not in profile configs such as /etc/conf.d/net.foo
+
+#-----------------------------------------------------------------------------
+# Bonding
+# For link bonding/trunking emerge net-misc/ifenslave
+
+# To bond interfaces together
+slaves_bond0="eth0 eth1 eth2"
+config_bond0=( "null" ) # You may not want to assign an IP to the bond
+
+# If any of the slaves require extra configuration - for example wireless or
+# ppp devices - we need to depend function on the bonded interfaces
+RC_NEED_bond0="net.eth0 net.eth1"
+
+
+#-----------------------------------------------------------------------------
+# Classical IP over ATM 
+# For CLIP support emerge net-dialup/linux-atm
+
+# Ensure that you have /etc/atmsigd.conf setup correctly
+# Now setup each clip interface like so
+clip_atm0=( "peer_ip [if.]vpi.vci [opts]" ... )
+#  where "peer_ip" is the IP address of a PVC peer (in case of an ATM connection
+#  with your ISP, your only peer is usually the ISP gateway closest to you),
+#  "if" is the number of the ATM interface which will carry the PVC, "vpi.vci"
+#  is the ATM VC address, and "opts" may optionally specify VC parameters like
+#  qos, pcr, and the like (see "atmarp -s" for further reference). Please also
+#  note quoting: it is meant to distinguish the VCs you want to create. You may,
+#  in example, create an atm0 interface to more peers, like this:
+clip_atm0=( "1.1.1.254 0.8.35" "1.1.1.253 1.8.35" )
+
+#  By default, the PVC will use the LLC/SNAP encapsulation. If you rather need a
+#  null encapsulation (aka "VC mode"), please add the keyword "null" to opts.
+
+
+#-----------------------------------------------------------------------------
+# PPP
+# For PPP support, emerge net-dialup/ppp
+# PPP is used for most dialup connections, including ADSL.
+# The older ADSL module is documented below, but you are encouraged to try
+# this module first.
+#
+# You need to create the PPP net script yourself. Make it like so
+#ln -s net.lo /etc/init.d/net.ppp0
+#
+# We have to instruct ppp0 to actually use ppp
+config_ppp0=( "ppp" )
+#
+# Each PPP interface requires an interface to use as a "Link"
+link_ppp0="/dev/ttyS0" 		# Most PPP links will use a serial port
+link_ppp0="eth0"       		# PPPoE requires an ethernet interface
+link_ppp0="[itf.]vpi.vci"		# PPPoA requires the ATM VC's address
+link_ppp0="/dev/null"			# ISDN links should have this
+link_ppp0="pty 'your_link_command'"	# PPP links over ssh, rsh, etc
+#
+# Here you should specify what pppd plugins you want to use
+# Available plugins are: pppoe, pppoa, capi, dhcpc, minconn, radius,
+#			 radattr, radrealms and winbind 
+plugins_ppp0=(
+	"pppoe"				# Required plugin for PPPoE
+	"pppoa vc-encaps"		# Required plugin for PPPoA with an option
+	"capi"				# Required plugin for ISDN
+)
+#
+# PPP requires at least a username. You can optionally set a password here too
+# If you don't, then it will use the password specified in /etc/ppp/*-secrets
+# against the specified username
+username_ppp0='user'
+password_ppp0='password'
+# NOTE: You can set a blank password like so
+password_ppp0=
+#
+# The PPP daemon has many options you can specify - although there are many
+# and may seem daunting, it is recommended that you read the pppd man page
+# before enabling any of them
+pppd_ppp0=(
+	"maxfail 0"	# WARNING: It's not recommended you use this
+			# if you don't specify maxfail then we assume 0
+	"updetach" 	# If not set, "/etc/init.d/net.ppp0 start" will return
+			# immediately,  without waiting the link to come up
+			# for the first time.
+			# Do not use it for dial-on-demand links!
+	"debug" 	# Enables syslog debugging
+	"noauth"	# Do not require the peer to authenticate itself
+	"defaultroute"	# Make this PPP interface the default route
+	"usepeerdns"	# Use the DNS settings provided by PPP
+
+# On demand options
+	"demand"		# Enable dial on demand
+	"idle 30"		# Link goes down after 30 seconds of inactivity
+	"10.112.112.112:10.112.112.113"	# Phony IP addresses
+	"ipcp-accept-remote"	# Accept the peers idea of remote address
+	"ipcp-accept-local"	# Accept the peers idea of local address
+	"holdoff 3" 	# Wait 3 seconds after link dies before re-starting
+
+# Dead peer detection
+	"lcp-echo-interval 15"	# Send a LCP echo every 15 seconds
+	"lcp-echo-failure 3"	# Make peer dead after 3 consective
+				# echo-requests
+	
+# Compression options - use these to completely disable compression
+#	noaccomp noccp nobsdcomp nodeflate nopcomp novj novjccomp
+
+# Dial-up settings
+	"lock"				# Lock serial port
+	"115200"			# Set the serial port baud rate
+	"modem crtscts"			# Enable hardware flow control
+	"192.168.0.1:192.168.0.2"	# Local and remote IP addresses
+)
+#
+# Dial-up PPP users need to specify at least one telephone number
+phone_number_ppp0=( "12345689" ) # Maximum 2 phone numbers are supported
+# They will also need a chat script - here's a good one
+chat_ppp0=(
+#	'ABORT' 'BUSY'
+#	'ABORT' 'ERROR'
+#	'ABORT' 'NO ANSWER'
+#	'ABORT' 'NO CARRIER'
+#	'ABORT' 'NO DIALTONE'
+#	'ABORT' 'Invalid Login'
+#	'ABORT' 'Login incorrect'
+#	'TIMEOUT' '5'
+#	'' 'ATZ'
+#	'OK' 'AT' # Put your modem initialization string here
+#	'OK' 'ATDT\T'
+#	'TIMEOUT' '60'
+#	'CONNECT' ''
+#	'TIMEOUT' '5'
+#	'~--' ''
+)
+
+# If the link require extra configuration - for example wireless or
+# RFC 268 bridge - we need to depend on the bridge so they get
+# configured correctly.
+RC_NEED_ppp0="net.nas0"
+
+#WARNING: if MTU of the PPP interface is less than 1500 and you use this
+#machine as a router, you should add the following rule to your firewall
+#
+#iptables -I FORWARD 1 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
+
+#-----------------------------------------------------------------------------
+# ADSL
+# For ADSL support, emerge net-dialup/rp-pppoe
+# WARNING: This ADSL module is being deprecated in favour of the PPP module
+# above.
+# You should make the following settings and also put your
+# username/password information in /etc/ppp/pap-secrets
+
+# Configure the interface to use ADSL
+config_eth0=( "adsl" )
+
+# You probably won't need to edit /etc/ppp/pppoe.conf if you set this
+adsl_user_eth0="my-adsl-username"
+
+#-----------------------------------------------------------------------------
+# ISDN
+# For ISDN support, emerge net-dialup/isdn4k-utils
+# You should make the following settings and also put your
+# username/password information in /etc/ppp/pap-secrets
+
+# Configure the interface to use ISDN
+config_ippp0=( "dhcp" )
+# It's important to specify dhcp if you need it!
+config_ippp0=( "192.168.0.1/24" )
+# Otherwise, you can use a static IP
+
+# NOTE: The interface name must be either ippp or isdn followed by a number
+
+# You may need this option to set the default route
+ipppd_eth0="defaultroute"
+
+#-----------------------------------------------------------------------------
+# MAC changer
+# To set a specific MAC address
+mac_eth0="00:11:22:33:44:55"
+
+# For changing MAC addresses using the below, emerge net-analyzer/macchanger
+# - to randomize the last 3 bytes only
+mac_eth0="random-ending"
+# - to randomize between the same physical type of connection (e.g. fibre,
+# copper, wireless) , all vendors
+mac_eth0="random-samekind"
+# - to randomize between any physical type of connection (e.g. fibre, copper,
+# wireless) , all vendors
+mac_eth0="random-anykind"
+# - full randomization - WARNING: some MAC addresses generated by this may NOT
+# act as expected
+mac_eth0="random-full"
+# custom - passes all parameters directly to net-analyzer/macchanger
+mac_eth0="some custom set of parameters"
+
+# You can also set other options based on the MAC address of your network card
+# Handy if you use different docking stations with laptops
+config_001122334455=( "dhcp" )
+
+#-----------------------------------------------------------------------------
+# TUN/TAP
+# For TUN/TAP support emerge net-misc/openvpn or sys-apps/usermode-utilities
+#
+# You must specify if we're a tun or tap device. Then you can give it any
+# name you like - such as vpn
+tuntap_vpn="tun"
+config_vpn=( "192.168.0.1/24")
+
+# Or stick wit the generic names - like tap0
+tuntap_tap0="tap"
+config_tap0=( "192.168.0.1/24")
+
+# For passing custom options to tunctl use something like the following.  This
+# example sets the owner to adm
+tunctl_tun1="-u adm"
+# When using openvpn, there are no options
+
+#-----------------------------------------------------------------------------
+# Bridging (802.1d)
+# For bridging support emerge net-misc/bridge-utils
+
+# To add ports to bridge br0
+bridge_br0="eth0 eth1"
+# or dynamically add them when the interface comes up
+bridge_add_eth0="br0"
+bridge_add_eth1="br0"
+
+# You need to configure the ports to null values so dhcp does not get started 
+config_eth0=( "null" )
+config_eth1=( "null" )
+
+# Finally give the bridge an address - dhcp or a static IP
+config_br0=( "dhcp" ) # may not work when adding ports dynamically
+config_br0=( "192.168.0.1/24" )
+
+# If any of the ports require extra configuration - for example wireless or
+# ppp devices - we need to depend on them like so.
+RC_NEED_br0="net.eth0 net.eth1"
+
+# Below is an example of configuring the bridge
+# Consult "man brctl" for more details
+brctl_br0=( "setfd 0" "sethello 0" "stp off" )
+
+#-----------------------------------------------------------------------------
+# RFC 2684 Bridge Support 
+# For RFC 2684 bridge support emerge net-misc/br2684ctl
+
+# Interface names have to be of the form nas0, nas1, nas2, etc.
+# You have to specify a VPI and VCI for the interface like so
+br2684ctl_nas0="-a 0.38" # UK VPI and VCI
+
+# You may want to configure the encapsulation method as well by adding the -e
+# option to the command above (may need to be before the -a command)
+# -e 0 # LLC (default)
+# -e 1 # VC mux
+
+# Then you can configure the interface as normal
+config_nas0=( "192.168.0.1/24" )
+
+#-----------------------------------------------------------------------------
+# Tunnelling
+# WARNING: For tunnelling it is highly recommended that you
+# emerge sys-apps/iproute2
+#
+# For GRE tunnels
+iptunnel_vpn0="mode gre remote 207.170.82.1 key 0xffffffff ttl 255"
+
+# For IPIP tunnels
+iptunnel_vpn0="mode ipip remote 207.170.82.2 ttl 255"
+
+# To configure the interface
+config_vpn0=( "192.168.0.2 pointopoint 192.168.1.2" )	# ifconfig style
+config_vpn0=( "192.168.0.2 peer 192.168.1.1" )		# iproute2 style
+
+# 6to4 Tunnels allow IPv6 to work over IPv4 addresses, provided you
+# have a non-private address configured on an interface.
+ link_6to4="eth0"		# Interface to base it's addresses on
+ config_6to4=( "ip6to4" )
+# You may want to depend on eth0 like so
+RC_NEED_6to4="net.eth0"
+# To ensure that eth0 is configured before 6to4. Of course, the tunnel could be
+# any name and this also works for any configured interface.
+# NOTE: If you're not using iproute2 then your 6to4 tunnel has to be called
+# sit0 - otherwise use a different name like 6to4 in the example above.
+
+
+#-----------------------------------------------------------------------------
+# System
+# For configuring system specifics such as domain, dns, ntp and nis servers
+# It's rare that you would need todo this, but you can anyway.
+# This is most benefit to wireless users who don't use DHCP so they can change
+# their configs based on ESSID. See wireless.example for more details
+
+# To use dns settings such as these, dns_servers_eth0 must be set!
+# If you omit the _eth0 suffix, then it applies to all interfaces unless
+# overridden by the interface suffix.
+dns_domain_eth0="your.domain"
+dns_servers_eth0="192.168.0.2 192.168.0.3"
+dns_search_eth0="this.domain that.domain"
+dns_options_eth0=( "timeout 1" "rotate" )
+dns_sortlist_eth0="130.155.160.0/255.255.240.0 130.155.0.0"
+# See the man page for resolv.conf for details about the options and sortlist
+# directives
+
+ntp_servers_eth0="192.168.0.2 192.168.0.3"
+
+nis_domain_eth0="domain"
+nis_servers_eth0="192.168.0.2 192.168.0.3"
+
+# NOTE: Setting any of these will stamp on the files in question. So if you
+# don't specify dns_servers but you do specify dns_domain then no nameservers
+# will be listed in /etc/resolv.conf even if there were any there to start
+# with.
+# If this is an issue for you then maybe you should look into a resolv.conf
+# manager like resolvconf-gentoo to manage this file for you. All packages
+# that baselayout supports use resolvconf-gentoo if installed.
+
+#-----------------------------------------------------------------------------
+# Cable in/out detection
+# Sometimes the cable is in, others it's out. Obviously you don't want to
+# restart net.eth0 every time when you plug it in either.
+#
+# netplug is a package that detects this and requires no extra configuration
+# on your part.
+# emerge sys-apps/netplug
+# or
+# emerge sys-apps/ifplugd
+# and you're done :)
+
+# By default we don't wait for netplug/ifplugd to configure the interface.
+# If you would like it to wait so that other services now that network is up
+# then you can specify a timeout here.
+plug_timeout="10"
+# A value of 0 means wait forever.
+
+# If you don't want to use netplug on a specific interface but you have it
+# installed, you can disable it for that interface via the modules statement
+modules_eth0=( "!netplug" )
+# You can do the same for ifplugd
+#
+# You can disable them both with the generic plug
+modules_eth0=( "!plug" )
+
+# To use specific ifplugd options, fex specifying wireless mode
+ifplugd_eth0="--api-mode=wlan"
+# man ifplugd for more options
+
+##############################################################################
+# ADVANCED CONFIGURATION
+# 
+# Four functions can be defined which will be called surrounding the
+# start/stop operations.  The functions are called with the interface
+# name first so that one function can control multiple adapters. An extra two
+# functions can be defined when an interface fails to start or stop.
+#
+# The return values for the preup and predown functions should be 0
+# (success) to indicate that configuration or deconfiguration of the
+# interface can continue.  If preup returns a non-zero value, then
+# interface configuration will be aborted.  If predown returns a
+# non-zero value, then the interface will not be allowed to continue
+# deconfiguration.
+#
+# The return values for the postup, postdown, failup and faildown functions are
+# ignored since there's nothing to do if they indicate failure.
+#
+# ${IFACE} is set to the interface being brought up/down
+# ${IFVAR} is ${IFACE} converted to variable name bash allows
+
+#preup() {
+#	# Test for link on the interface prior to bringing it up.  This
+#	# only works on some network adapters and requires the mii-diag
+#	# package to be installed.
+#	if mii-tool "${IFACE}" 2> /dev/null | grep -q 'no link'; then
+#		ewarn "No link on ${IFACE}, aborting configuration"
+#		return 1
+#	fi 
+#
+#	# Test for link on the interface prior to bringing it up.  This
+#	# only works on some network adapters and requires the ethtool
+#	# package to be installed.
+#	if ethtool "${IFACE}" | grep -q 'Link detected: no'; then
+#		ewarn "No link on ${IFACE}, aborting configuration"
+#		return 1
+#	fi
+#
+#
+#	# Remember to return 0 on success
+#	return 0
+#}
+
+#predown() {
+#	# The default in the script is to test for NFS root and disallow
+#	# downing interfaces in that case.  Note that if you specify a
+#	# predown() function you will override that logic.  Here it is, in
+#	# case you still want it...
+#	if is_net_fs /; then
+#		eerror "root filesystem is network mounted -- can't stop ${IFACE}"
+#		return 1
+#	fi
+#
+#	# Remember to return 0 on success
+#	return 0
+#}
+
+#postup() {
+#	# This function could be used, for example, to register with a
+#	# dynamic DNS service.  Another possibility would be to
+#	# send/receive mail once the interface is brought up.
+
+#	# Here is an example that allows the use of iproute rules
+#	# which have been configured using the rules_eth0 variable.
+#	#rules_eth0=(
+#	#	"from 24.80.102.112/32 to 192.168.1.0/24 table localnet priority 100"
+#	#	"from 216.113.223.51/32 to 192.168.1.0/24 table localnet priority 100"
+#	#)
+#	local x="rules_${IFVAR}[@]"
+#	local -a rules=( "${!x}" )
+#	if [[ -n ${rules} ]] ; then
+#		einfo "Adding IP policy routing rules"
+#		eindent
+#		# Ensure that the kernel supports policy routing
+#		if ! ip rule list | grep -q "^" ; then
+#			eerror "You need to enable IP Policy Routing (CONFIG_IP_MULTIPLE_TABLES)"
+#			eerror "in your kernel to use ip rules"
+#		else
+#			for x in "${rules[@]}" ; do
+#				ebegin "${x}"
+#				ip rule add ${x} dev "${IFACE}"
+#				eend $?
+#			done
+#		fi
+#		eoutdent
+#		# Flush the cache
+#		ip route flush cache dev "${IFACE}"
+#	fi
+
+#}
+
+#postdown() {
+#	# Enable Wake-On-LAN for every interface except for lo
+#	# Probably a good idea to set RC_DOWN_INTERFACE="no" in /etc/conf.d/rc
+#	# as well ;)
+#	[[ ${IFACE} != "lo" ]] && ethtool -s "${IFACE}" wol g
+
+#	Automatically erase any ip rules created in the example postup above
+#	if interface_exists "${IFACE}" ; then
+#		# Remove any rules for this interface
+#		local rule
+#		ip rule list | grep " iif ${IFACE}[ ]*" | {
+#			while read rule ; do
+#				rule="${rule#*:}"	
+#				ip rule del ${rule}
+#			done
+#		}
+#		# Flush the route cache
+#		ip route flush cache dev "${IFACE}"
+#	fi
+
+#	# Return 0 always
+#	return 0
+#}
+
+#failup() {
+#       # This function is mostly here for completeness... I haven't
+#       # thought of anything nifty to do with it yet ;-)
+#}
+
+#faildown() {
+#       # This function is mostly here for completeness... I haven't
+#       # thought of anything nifty to do with it yet ;-)
+#}
+
+##############################################################################
+# FORCING MODULES
+# The Big Fat Warning :- If you use module forcing do not complain to us or
+# file bugs about it not working!
+#
+# Loading modules is a slow affair - we have to check each one for the following
+# 1) Code sanity
+# 2) Has the required package been emerged?
+# 3) Has it modified anything?
+# 4) Have all the dependant modules been loaded?
+
+# Then we have to strip out the conflicting modules based on user preference
+# and default configuration and sort them into the correct order.
+# Finally we check the end result for dependencies.
+
+# This, of course, takes valuable CPU time so we provide module forcing as a
+# means to speed things up. We still do *some* checking but not much.
+
+# It is essential that you force modules in the correct order and supply all
+# the modules you need. You must always supply an interface module - we
+# supply ifconfig or iproute2.
+
+# The Big Fat Warning :- If you use module forcing do not complain to us or
+# file bugs about it not working!
+
+# Now that we've warned you twice, here's how to do it
+modules_force=( "ifconfig" )
+modules_force=( "iproute2" "dhcpcd" )
+
+# We can also apply this to a specific interface
+modules_force_eth1=( "iproute2" )
+
+# The below will not work
+modules_force=( "dhcpcd" )
+# No interface (ifconfig/iproute2)
+modules_force=( "ifconfig" "essidnet" "iwconfig" )
+# Although it will not crash, essidnet will not work as it has to come after
+# iwconfig
+modules_force=( "iproute2" "ifconfig" )
+# The interface will be setup twice which will cause problems
diff --git a/src/settings/plugins/ifnet/tests/nm-system-settings.conf b/src/settings/plugins/ifnet/tests/nm-system-settings.conf
new file mode 100644
index 00000000..39bc87b8
--- /dev/null
+++ b/src/settings/plugins/ifnet/tests/nm-system-settings.conf
@@ -0,0 +1,5 @@
+[main]
+plugins=ifnet,keyfile
+
+[ifnet]
+managed=false
diff --git a/src/settings/plugins/ifnet/tests/test-ifnet.c b/src/settings/plugins/ifnet/tests/test-ifnet.c
new file mode 100644
index 00000000..68f2b928
--- /dev/null
+++ b/src/settings/plugins/ifnet/tests/test-ifnet.c
@@ -0,0 +1,396 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service (ifnet)
+ *
+ * Mu Qiao <qiaomuf@gmail.com>
+ *
+ * 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) 1999-2010 Gentoo Foundation, Inc.
+ */
+
+#include "nm-default.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "nm-utils.h"
+
+#include "platform/nm-linux-platform.h"
+#include "dhcp/nm-dhcp-manager.h"
+
+#include "settings/plugins/ifnet/nms-ifnet-net-parser.h"
+#include "settings/plugins/ifnet/nms-ifnet-net-utils.h"
+#include "settings/plugins/ifnet/nms-ifnet-wpa-parser.h"
+#include "settings/plugins/ifnet/nms-ifnet-connection-parser.h"
+
+#include "nm-test-utils-core.h"
+
+/* Fake config handling; the values it returns don't matter, so this
+ * is easier than forcing it to read our own config file, etc.
+ */
+NMDhcpManager *
+nm_dhcp_manager_get (void)
+{
+	return NULL;
+}
+
+const char *
+nm_dhcp_manager_get_config (NMDhcpManager *dhcp_manager)
+{
+	return "dhclient";
+}
+
+static void
+test_getdata (void)
+{
+	g_assert (ifnet_get_data ("eth1", "config") &&
+	          strcmp (ifnet_get_data ("eth1", "config"), "( \"dhcp\" )") == 0);
+	g_assert (ifnet_get_data ("ppp0", "username") &&
+	          strcmp (ifnet_get_data ("ppp0", "username"), "user") == 0);
+	g_assert (ifnet_get_data ("ppp0", "password") &&
+	          strcmp (ifnet_get_data ("ppp0", "password"), "password") == 0);
+	g_assert (ifnet_get_global_data ("modules") &&
+	          strcmp ("!wpa_supplicant", ifnet_get_global_data ("modules")) == 0);
+}
+
+static void
+test_is_static (void)
+{
+	g_assert (!is_static_ip4 ("eth1"));
+	g_assert (is_static_ip4 ("eth0"));
+	g_assert (!is_static_ip6 ("eth0"));
+}
+
+static void
+test_has_default_route (void)
+{
+	g_assert (has_default_ip4_route ("eth0"));
+	g_assert (has_default_ip6_route ("eth4"));
+	g_assert (!has_default_ip4_route ("eth5") &&
+	          !has_default_ip6_route ("eth5"));
+}
+
+static void
+test_has_ip6_address (void)
+{
+	g_assert (has_ip6_address ("eth2"));
+	g_assert (!has_ip6_address ("eth0"));
+}
+
+static void
+test_is_ip4_address (void)
+{
+	gchar *address1 = "192.168.4.232/24";
+	gchar *address2 = "192.168.100.{1..254}/24";
+	gchar *address3 = "192.168.4.2555/24";
+
+	g_assert (is_ip4_address (address1));
+	g_assert (is_ip4_address (address2));
+	g_assert (!is_ip4_address (address3));
+}
+
+static void
+test_is_ip6_address (void)
+{
+	gchar *address1 = "4321:0:1:2:3:4:567:89ac/24";
+
+	g_assert (is_ip6_address (address1));
+}
+
+static void
+check_ip_block (ip_block * iblock, gchar * ip, guint32 prefix, gchar * gateway)
+{
+	g_assert_cmpstr (ip, ==, iblock->ip);
+	g_assert (prefix == iblock->prefix);
+	g_assert_cmpstr (gateway, ==, iblock->next_hop);
+}
+
+static void
+test_convert_ipv4_config_block (void)
+{
+	ip_block *iblock = convert_ip4_config_block ("eth0");
+	ip_block *tmp = iblock;
+
+	g_assert (iblock != NULL);
+	check_ip_block (iblock, "202.117.16.121", 24, "202.117.16.1");
+	iblock = iblock->next;
+	destroy_ip_block (tmp);
+	g_assert (iblock != NULL);
+	check_ip_block (iblock, "192.168.4.121", 24, "202.117.16.1");
+	destroy_ip_block (iblock);
+
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*Can't handle IPv4 address*202.117.16.1211*");
+	iblock = convert_ip4_config_block ("eth2");
+	g_test_assert_expected_messages ();
+	g_assert (iblock != NULL && iblock->next == NULL);
+	check_ip_block (iblock, "192.168.4.121", 24, NULL);
+	destroy_ip_block (iblock);
+
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*missing netmask or prefix*");
+	iblock = convert_ip4_config_block ("eth3");
+	g_assert (iblock == NULL);
+}
+
+static void
+test_convert_ipv4_routes_block (void)
+{
+	ip_block *iblock = convert_ip4_routes_block ("eth0");
+	ip_block *tmp = iblock;
+
+	g_assert (iblock != NULL);
+	check_ip_block (iblock, "192.168.4.0", 24, "192.168.4.1");
+	iblock = iblock->next;
+	destroy_ip_block (tmp);
+	g_assert (iblock == NULL);
+
+	iblock = convert_ip4_routes_block ("eth9");
+	tmp = iblock;
+
+	g_assert (iblock != NULL);
+	check_ip_block (iblock, "10.0.0.0", 8, "192.168.0.1");
+	iblock = iblock->next;
+	destroy_ip_block (tmp);
+	g_assert (iblock == NULL);
+}
+
+static void
+test_wpa_parser (void)
+{
+	const char *value;
+
+	g_assert (exist_ssid ("example"));
+
+	g_assert (exist_ssid ("static-wep-test"));
+	value = wpa_get_value ("static-wep-test", "key_mgmt");
+	g_assert_cmpstr (value, ==, "NONE");
+	value = wpa_get_value ("static-wep-test", "wep_key0");
+	g_assert_cmpstr (value, ==, "\"abcde\"");
+
+	g_assert (exist_ssid ("leap-example"));
+
+	value = wpa_get_value ("test-with-hash-in-psk", "psk");
+	g_assert_cmpstr (value, ==, "\"xjtudlc3731###asdfasdfasdf\"");
+}
+
+static void
+test_strip_string (void)
+{
+	gchar *str = "( \"default via     202.117.16.1\" )";
+	gchar *result = g_strdup (str);
+	gchar *result_b = result;
+
+	result = strip_string (result, '(');
+	result = strip_string (result, ')');
+	result = strip_string (result, '"');
+	g_assert_cmpstr (result, ==, "default via     202.117.16.1");
+	g_free (result_b);
+}
+
+static void
+test_is_unmanaged (void)
+{
+	g_assert (is_managed ("eth0"));
+	g_assert (!is_managed ("eth4"));
+}
+
+static void
+test_new_connection (void)
+{
+	GError *error = NULL;
+	NMConnection *connection;
+
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*Can't handle IPv4 address*202.117.16.1211*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*Can't handle IPv6 address*202.117.16.1211*");
+	connection = ifnet_update_connection_from_config_block ("eth2", NULL, &error);
+	g_test_assert_expected_messages ();
+	g_assert (connection != NULL);
+	g_object_unref (connection);
+
+	connection = ifnet_update_connection_from_config_block ("qiaomuf", NULL, &error);
+	g_assert (connection != NULL);
+	g_object_unref (connection);
+
+	connection = ifnet_update_connection_from_config_block ("myxjtu2", NULL, &error);
+	g_assert (connection != NULL);
+	g_object_unref (connection);
+
+	connection = ifnet_update_connection_from_config_block ("eth9", NULL, &error);
+	g_assert (connection != NULL);
+	g_object_unref (connection);
+
+	connection = ifnet_update_connection_from_config_block ("eth10", NULL, &error);
+	g_assert (connection != NULL);
+	g_object_unref (connection);
+}
+
+static void
+kill_backup (char **path)
+{
+	if (*path) {
+		unlink (*path);
+		g_free (*path);
+		*path = NULL;
+	}
+}
+
+#define NET_GEN_NAME "net.generate"
+#define SUP_GEN_NAME "wpa_supplicant.conf.generate"
+
+static void
+test_update_connection (void)
+{
+	GError *error = NULL;
+	NMConnection *connection;
+	gboolean success;
+	char *backup = NULL;
+	char *basepath = TEST_IFNET_DIR;
+
+	connection = ifnet_update_connection_from_config_block ("eth0", basepath, &error);
+	g_assert (connection != NULL);
+
+	success = ifnet_update_parsers_by_connection (connection, "eth0",
+	                                              NET_GEN_NAME,
+	                                              SUP_GEN_NAME,
+	                                              NULL,
+	                                              &backup,
+	                                              &error);
+	kill_backup (&backup);
+	g_assert (success);
+	g_object_unref (connection);
+
+	connection = ifnet_update_connection_from_config_block ("0xab3ace", basepath, &error);
+	g_assert (connection != NULL);
+
+	success = ifnet_update_parsers_by_connection (connection, "0xab3ace",
+	                                              NET_GEN_NAME,
+	                                              SUP_GEN_NAME,
+	                                              NULL,
+	                                              &backup,
+	                                              &error);
+	kill_backup (&backup);
+	g_assert (success);
+	g_object_unref (connection);
+
+	unlink (NET_GEN_NAME);
+	unlink (SUP_GEN_NAME);
+}
+
+static void
+test_add_connection (void)
+{
+	NMConnection *connection;
+	char *backup = NULL;
+	const char *basepath = TEST_IFNET_DIR;
+
+	connection = ifnet_update_connection_from_config_block ("eth0", basepath, NULL);
+	g_assert (ifnet_add_new_connection (connection, NET_GEN_NAME, SUP_GEN_NAME, NULL, &backup, NULL));
+	kill_backup (&backup);
+	g_object_unref (connection);
+
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*Can't handle ipv4 address: brd, missing netmask or prefix*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*Can't handle ipv4 address: 202.117.16.255, missing netmask or prefix*");
+	connection = ifnet_update_connection_from_config_block ("myxjtu2", basepath, NULL);
+	g_test_assert_expected_messages ();
+	g_assert (ifnet_add_new_connection (connection, NET_GEN_NAME, SUP_GEN_NAME, NULL, &backup, NULL));
+	kill_backup (&backup);
+	g_object_unref (connection);
+
+	unlink (NET_GEN_NAME);
+	unlink (SUP_GEN_NAME);
+}
+
+static void
+test_delete_connection (void)
+{
+	GError *error = NULL;
+	NMConnection *connection;
+	char *backup = NULL;
+
+	connection = ifnet_update_connection_from_config_block ("eth7", NULL, &error);
+	g_assert (connection != NULL);
+	g_assert (ifnet_delete_connection_in_parsers ("eth7", NET_GEN_NAME, SUP_GEN_NAME, &backup));
+	kill_backup (&backup);
+	g_object_unref (connection);
+
+	connection = ifnet_update_connection_from_config_block ("qiaomuf", NULL, &error);
+	g_assert (connection != NULL);
+	g_assert (ifnet_delete_connection_in_parsers ("qiaomuf", NET_GEN_NAME, SUP_GEN_NAME, &backup));
+	kill_backup (&backup);
+	g_object_unref (connection);
+
+	unlink (NET_GEN_NAME);
+	unlink (SUP_GEN_NAME);
+}
+
+static void
+test_missing_config (void)
+{
+	gs_free_error GError *error = NULL;
+	NMConnection *connection;
+
+	connection = ifnet_update_connection_from_config_block ("eth8", NULL, &error);
+	g_assert_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
+	g_assert (connection == NULL && error != NULL);
+}
+
+NMTST_DEFINE ();
+
+#define TPATH "/settings/plugins/ifnet/"
+
+int
+main (int argc, char **argv)
+{
+	int ret;
+
+	nm_linux_platform_setup ();
+
+	nmtst_init_assert_logging (&argc, &argv, "WARN", "DEFAULT");
+
+	ifnet_init (TEST_IFNET_DIR "/net");
+	wpa_parser_init (TEST_IFNET_DIR "/wpa_supplicant.conf");
+
+	g_test_add_func (TPATH "strip-string", test_strip_string);
+	g_test_add_func (TPATH "is-static", test_is_static);
+	g_test_add_func (TPATH "has-ip6-address", test_has_ip6_address);
+	g_test_add_func (TPATH "has-default-route", test_has_default_route);
+	g_test_add_func (TPATH "get-data", test_getdata);
+	g_test_add_func (TPATH "is-ip4-address", test_is_ip4_address);
+	g_test_add_func (TPATH "is-ip6-address", test_is_ip6_address);
+	g_test_add_func (TPATH "convert-ip4-config", test_convert_ipv4_config_block);
+	g_test_add_func (TPATH "convert-ip4-routes", test_convert_ipv4_routes_block);
+	g_test_add_func (TPATH "is-unmanaged", test_is_unmanaged);
+	g_test_add_func (TPATH "wpa-parser", test_wpa_parser);
+	g_test_add_func (TPATH "new-connection", test_new_connection);
+	g_test_add_func (TPATH "update-connection", test_update_connection);
+	g_test_add_func (TPATH "add-connection", test_add_connection);
+	g_test_add_func (TPATH "delete-connection", test_delete_connection);
+	g_test_add_func (TPATH "missing-config", test_missing_config);
+
+	ret = g_test_run ();
+
+	ifnet_destroy ();
+	wpa_parser_destroy ();
+
+	return ret;
+}
diff --git a/src/settings/plugins/ifnet/tests/test_ca_cert.pem b/src/settings/plugins/ifnet/tests/test_ca_cert.pem
new file mode 100644
index 00000000..ef1be20d
--- /dev/null
+++ b/src/settings/plugins/ifnet/tests/test_ca_cert.pem
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEjzCCA3egAwIBAgIJAOvnZPt59yIZMA0GCSqGSIb3DQEBBQUAMIGLMQswCQYD
+VQQGEwJVUzESMBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcw
+FQYDVQQKEw5NeSBDb21wYW55IEx0ZDEQMA4GA1UECxMHVGVzdGluZzENMAsGA1UE
+AxMEdGVzdDEcMBoGCSqGSIb3DQEJARYNdGVzdEB0ZXN0LmNvbTAeFw0wOTAzMTAx
+NTEyMTRaFw0xOTAzMDgxNTEyMTRaMIGLMQswCQYDVQQGEwJVUzESMBAGA1UECBMJ
+QmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5NeSBDb21wYW55
+IEx0ZDEQMA4GA1UECxMHVGVzdGluZzENMAsGA1UEAxMEdGVzdDEcMBoGCSqGSIb3
+DQEJARYNdGVzdEB0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAKot9j+/+CX1/gZLgJHIXCRgCItKLGnf7qGbgqB9T2ACBqR0jllKWwDKrcWU
+xjXNIc+GF9Wnv+lX6G0Okn4Zt3/uRNobL+2b/yOF7M3Td3/9W873zdkQQX930YZc
+Rr8uxdRPP5bxiCgtcw632y21sSEbG9mjccAUnV/0jdvfmMNj0i8gN6E0fMBiJ9S3
+FkxX/KFvt9JWE9CtoyL7ki7UIDq+6vj7Gd5N0B3dOa1y+rRHZzKlJPcSXQSEYUS4
+HmKDwiKSVahft8c4tDn7KPi0vex91hlgZVd3usL2E/Vq7o5D9FAZ5kZY0AdFXwdm
+J4lO4Mj7ac7GE4vNERNcXVIX59sCAwEAAaOB8zCB8DAdBgNVHQ4EFgQUuDU3Mr7P
+T3n1e3Sy8hBauoDFahAwgcAGA1UdIwSBuDCBtYAUuDU3Mr7PT3n1e3Sy8hBauoDF
+ahChgZGkgY4wgYsxCzAJBgNVBAYTAlVTMRIwEAYDVQQIEwlCZXJrc2hpcmUxEDAO
+BgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15IENvbXBhbnkgTHRkMRAwDgYDVQQL
+EwdUZXN0aW5nMQ0wCwYDVQQDEwR0ZXN0MRwwGgYJKoZIhvcNAQkBFg10ZXN0QHRl
+c3QuY29tggkA6+dk+3n3IhkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOC
+AQEAVRG4aALIvCXCiKfe7K+iJxjBVRDFPEf7JWA9LGgbFOn6pNvbxonrR+0BETdc
+JV1ET4ct2xsE7QNFIkp9GKRC+6J32zCo8qtLCD5+v436r8TUG2/t2JRMkb9I2XVT
+p7RJoot6M0Ltf8KNQUPYh756xmKZ4USfQUwc58MOSDGY8VWEXJOYij9Pf0e0c52t
+qiCEjXH7uXiS8Pgq9TYm7AkWSOrglYhSa83x0f8mtT8Q15nBESIHZ6o8FAS2bBgn
+B0BkrKRjtBUkuJG3vTox+bYINh2Gxi1JZHWSV1tN5z3hd4VFcKqanW5OgQwToBqp
+3nniskIjbH0xjgZf/nVMyLnjxg==
+-----END CERTIFICATE-----
diff --git a/src/settings/plugins/ifnet/tests/wpa_supplicant.conf b/src/settings/plugins/ifnet/tests/wpa_supplicant.conf
new file mode 100644
index 00000000..917d495d
--- /dev/null
+++ b/src/settings/plugins/ifnet/tests/wpa_supplicant.conf
@@ -0,0 +1,70 @@
+# Only WPA-PSK is used. Any valid cipher combination is accepted.
+network={
+	ssid="example"
+	proto=WPA
+	key_mgmt=WPA-PSK
+	pairwise=CCMP TKIP
+	group=CCMP TKIP WEP104 WEP40
+	psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb
+	priority=2
+}
+
+# LEAP with dynamic WEP keys
+network={
+	ssid="leap-example"
+	key_mgmt=IEEE8021X
+	eap=LEAP
+	identity="user"
+	password="foobar"
+}
+
+# Shared WEP key connection (no WPA, no IEEE 802.1X)
+network={
+	ssid="static-wep-test"
+	key_mgmt=NONE
+	wep_key0="abcde"
+	wep_key1=0102030405
+	wep_key2="1234567890123"
+	wep_tx_keyidx=0
+	priority=5
+}
+
+# Wildcard match for SSID (plaintext APs only). This example select any
+# open AP regardless of its SSID.
+network={
+	key_mgmt=NONE
+}
+
+network={
+  ssid="myxjtu2"
+  scan_ssid=1
+  key_mgmt=WPA-PSK
+  psk="xjtudlc3731"
+  disabled=0
+  key_mgmt=NONE
+  wep_key0="12345"
+  wep_key1=1234567890
+  wep_key2="zxcvb"
+  wep_tx_keyidx=1
+  auth_alg=OPEN
+  mode=1
+}
+
+network={
+	ssid=ab3ace
+	key_mgmt=WPA-EAP
+	eap=TTLS
+	identity="user@example.com"
+	anonymous_identity="anonymous@example.com"
+	password="foobar"
+	ca_cert="test_ca_cert.pem"
+	phase2="auth=CHAP"
+	priority=20
+}
+
+network={
+  ssid="test-with-hash-in-psk"
+  key_mgmt=WPA-PSK
+  psk="xjtudlc3731###asdfasdfasdf"
+}
+
diff --git a/src/settings/plugins/ifupdown/meson.build b/src/settings/plugins/ifupdown/meson.build
deleted file mode 100644
index 87b5bea2..00000000
--- a/src/settings/plugins/ifupdown/meson.build
+++ /dev/null
@@ -1,53 +0,0 @@
-sources = files(
-  'nms-ifupdown-interface-parser.c',
-  'nms-ifupdown-parser.c'
-)
-
-deps = [
-  libudev_dep,
-  nm_dep
-]
-
-cflags = '-DSYSCONFDIR="@0@"'.format(nm_sysconfdir)
-
-libnms_ifupdown_core = static_library(
-  'nms-ifupdown-core',
-  sources: sources,
-  dependencies: deps,
-  c_args: cflags
-)
-
-sources = files(
-  'nms-ifupdown-connection.c',
-  'nms-ifupdown-plugin.c'
-)
-
-libnm_settings_plugin_ifupdown = shared_module(
-  'nm-settings-plugin-ifupdown',
-  sources: sources,
-  dependencies: deps,
-  c_args: cflags,
-  link_with: libnms_ifupdown_core,
-  link_args: ldflags_linker_script_settings,
-  link_depends: linker_script_settings,
-  install: true,
-  install_dir: nm_pkglibdir
-)
-
-core_plugins += libnm_settings_plugin_ifupdown
-
-# FIXME: check_so_symbols replacement
-'''
-run_target(
-  'check-local-symbols-settings-ifupdown',
-  command: [check_so_symbols, libnm_settings_plugin_ifupdown.full_path()],
-  depends: libnm_settings_plugin_ifupdown
-)
-
-check-local-symbols-settings-ifupdown: src/settings/plugins/ifupdown/libnm-settings-plugin-ifupdown.la
-  $(call check_so_symbols,$(builddir)/src/settings/plugins/ifupdown/.libs/libnm-settings-plugin-ifupdown.so)
-'''
-
-if enable_tests
-  subdir('tests')
-endif
diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c
index 014998a6..8421afc2 100644
--- a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c
+++ b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c
@@ -129,8 +129,8 @@ _recursive_ifparser (const char *eni_file, int quiet)
 
 	while (!feof(inp))
 	{
-		char *token[128]; /* 255 chars can only be split into 127 tokens */
-		char value[255];  /* large enough to join previously split tokens */
+		char *token[128];	/* 255 chars can only be split into 127 tokens */
+		char value[255];	/* large enough to join previously split tokens */
 		char *safeptr;
 		int toknum;
 		int len = 0;
@@ -169,7 +169,7 @@ _recursive_ifparser (const char *eni_file, int quiet)
 			continue;
 		}
 
-#define SPACES " \t"
+#define SPACES	" \t"
 		/* tokenize input; */
 		for (toknum = 0, token[toknum] = strtok_r(line, SPACES, &safeptr);
 		     token[toknum] != NULL;
diff --git a/src/settings/plugins/ifupdown/tests/meson.build b/src/settings/plugins/ifupdown/tests/meson.build
deleted file mode 100644
index 7f210034..00000000
--- a/src/settings/plugins/ifupdown/tests/meson.build
+++ /dev/null
@@ -1,17 +0,0 @@
-test_unit = 'test-ifupdown'
-
-cflags = '-DTEST_ENI_DIR="@0@"'.format(meson.current_source_dir())
-
-exe = executable(
-  test_unit,
-  test_unit + '.c',
-  dependencies: test_nm_dep,
-  c_args: cflags,
-  link_with: libnms_ifupdown_core
-)
-
-test(
-  'ifupdown/' + test_unit,
-  test_script,
-  args: test_args + [exe.full_path()]
-)
diff --git a/src/settings/plugins/ifupdown/tests/test-ifupdown.c b/src/settings/plugins/ifupdown/tests/test-ifupdown.c
index 56515438..d037b8a6 100644
--- a/src/settings/plugins/ifupdown/tests/test-ifupdown.c
+++ b/src/settings/plugins/ifupdown/tests/test-ifupdown.c
@@ -168,7 +168,7 @@ dump_blocks (void)
 	for (n = ifparser_getfirst (); n != NULL; n = n->next) {
 		if_data *m;
 
-		// each block start with its type & name
+		// each block start with its type & name 
 		// (single quotes used to show typ & name baoundaries)
 		g_print("'%s' '%s'\n", n->type, n->name);
 
diff --git a/src/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/settings/plugins/keyfile/nms-keyfile-plugin.c
index df2c05b7..e6299d1e 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-plugin.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-plugin.c
@@ -436,7 +436,7 @@ read_connections (NMSettingsPlugin *config)
 		return;
 	}
 
-	alive_connections = g_hash_table_new (nm_direct_hash, NULL);
+	alive_connections = g_hash_table_new (NULL, NULL);
 
 	filenames = g_ptr_array_new_with_free_func (g_free);
 	while ((item = g_dir_read_name (dir))) {
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection
index 1e62f4b3..5cb4d726 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection
@@ -15,7 +15,7 @@ mtu=1400
 
 [ipv4]
 method=manual
-dns=4.2.2.1;bogus;4.2.2.2;
+dns=4.2.2.1;4.2.2.2;
 addresses1=192.168.0.5;24;192.168.0.1;
 addresses2=1.2.3.4;16;1.2.1.1;
 address=2.3.4.5/24,2.3.4.6
@@ -26,21 +26,15 @@ routes1=1.2.3.0/24,2.3.4.8,99
 route=5.6.7.8/32
 routes2=1.1.1.2/12,
 routes3=1.1.1.3/13,,
-routes7=1.1.1.7/17,0.0.0.0
 routes4=1.1.1.4/14,2.2.2.4
-address30=1.2.3.130/24
 routes5=1.1.1.5/15,2.2.2.5,
 routes6=1.1.1.6/16,2.2.2.6,0
+routes7=1.1.1.7/17,0.0.0.0
 routes8=1.1.1.8/18,0.0.0.0,
 routes9=1.1.1.9/19,0.0.0.0,0
-route10=1.1.1.10/21,,0
 routes10=1.1.1.10/20,,0
 routes11=1.1.1.11/21,,21
 routes11_options=cwnd=10,lock-cwnd=true,mtu=1430,src=7.7.7.7
-address30=1.2.3.30/24
-addresses30=1.2.3.30/25
-addresses31=1.2.3.31/25
-address31=1.2.3.31/24
 ignore-auto-routes=false
 ignore-auto-dns=false
 
diff --git a/src/settings/plugins/keyfile/tests/meson.build b/src/settings/plugins/keyfile/tests/meson.build
deleted file mode 100644
index 54b4ee0d..00000000
--- a/src/settings/plugins/keyfile/tests/meson.build
+++ /dev/null
@@ -1,21 +0,0 @@
-test_unit = 'test-keyfile'
-
-test_keyfiles_dir = join_paths(meson.current_source_dir(), 'keyfiles')
-
-cflags = [
-  '-DTEST_KEYFILES_DIR="@0@"'.format(test_keyfiles_dir),
-  '-DTEST_SCRATCH_DIR="@0@"'.format(test_keyfiles_dir)
-]
-
-exe = executable(
-  test_unit,
-  test_unit + '.c',
-  dependencies: test_nm_dep,
-  c_args: cflags
-)
-
-test(
-  'keyfile/' + test_unit,
-  test_script,
-  args: test_args + [exe.full_path()]
-)
diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c
index b46475e8..f27efddd 100644
--- a/src/settings/plugins/keyfile/tests/test-keyfile.c
+++ b/src/settings/plugins/keyfile/tests/test-keyfile.c
@@ -231,21 +231,34 @@ test_read_valid_wired_connection (void)
 	char expected_mac_address[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
 	gboolean success;
 
-	NMTST_EXPECT_NM_INFO ("*ipv4.addresses:*semicolon at the end*addresses1*");
-	NMTST_EXPECT_NM_INFO ("*ipv4.addresses:*semicolon at the end*addresses2*");
-	NMTST_EXPECT_NM_WARN ("*missing prefix length*address4*");
-	NMTST_EXPECT_NM_WARN ("*missing prefix length*address5*");
-	NMTST_EXPECT_NM_WARN ("*ipv4.dns: ignoring invalid DNS server IPv4 address 'bogus'*");
-	NMTST_EXPECT_NM_INFO ("*ipv4.routes*semicolon at the end*routes2*");
-	NMTST_EXPECT_NM_INFO ("*ipv4.routes*semicolon at the end*routes3*");
-	NMTST_EXPECT_NM_INFO ("*ipv4.routes*semicolon at the end*routes5*");
-	NMTST_EXPECT_NM_INFO ("*ipv4.routes*semicolon at the end*routes8*");
-	NMTST_EXPECT_NM_WARN ("*missing prefix length*address4*");
-	NMTST_EXPECT_NM_INFO ("*ipv6.address*semicolon at the end*address5*");
-	NMTST_EXPECT_NM_WARN ("*missing prefix length*address5*");
-	NMTST_EXPECT_NM_INFO ("*ipv6.address*semicolon at the end*address7*");
-	NMTST_EXPECT_NM_INFO ("*ipv6.routes*semicolon at the end*routes1*");
-	NMTST_EXPECT_NM_INFO ("*ipv6.route*semicolon at the end*route6*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
+	                       "*ipv4.addresses:*semicolon at the end*addresses1*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
+	                       "*ipv4.addresses:*semicolon at the end*addresses2*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*missing prefix length*address4*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*missing prefix length*address5*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
+	                       "*ipv4.routes*semicolon at the end*routes2*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
+	                       "*ipv4.routes*semicolon at the end*routes3*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
+	                       "*ipv4.routes*semicolon at the end*routes5*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
+	                       "*ipv4.routes*semicolon at the end*routes8*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*missing prefix length*address4*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
+	                       "*ipv6.address*semicolon at the end*address5*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*missing prefix length*address5*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
+	                       "*ipv6.address*semicolon at the end*address7*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
+	                       "*ipv6.routes*semicolon at the end*routes1*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
+	                       "*ipv6.route*semicolon at the end*route6*");
 	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection", &error);
 	g_assert_no_error (error);
 	g_test_assert_expected_messages ();
@@ -281,23 +294,19 @@ test_read_valid_wired_connection (void)
 	g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip4, 1), ==, "4.2.2.2");
 
 	/* IPv4 addresses */
-	g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 10);
+	g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 6);
 	check_ip_address (s_ip4, 0, "2.3.4.5", 24);
 	check_ip_address (s_ip4, 1, "192.168.0.5", 24);
 	check_ip_address (s_ip4, 2, "1.2.3.4", 16);
 	check_ip_address (s_ip4, 3, "3.4.5.6", 16);
 	check_ip_address (s_ip4, 4, "4.5.6.7", 24);
 	check_ip_address (s_ip4, 5, "5.6.7.8", 24);
-	check_ip_address (s_ip4, 6, "1.2.3.30", 24);
-	check_ip_address (s_ip4, 7, "1.2.3.30", 25);
-	check_ip_address (s_ip4, 8, "1.2.3.31", 24);
-	check_ip_address (s_ip4, 9, "1.2.3.31", 25);
 
 	/* IPv4 gateway */
 	g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "2.3.4.6");
 
 	/* IPv4 routes */
-	g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 13);
+	g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 12);
 	check_ip_route (s_ip4, 0, "5.6.7.8", 32, NULL, -1);
 	check_ip_route (s_ip4, 1, "1.2.3.0", 24, "2.3.4.8", 99);
 	check_ip_route (s_ip4, 2, "1.1.1.2", 12, NULL, -1);
@@ -308,12 +317,11 @@ test_read_valid_wired_connection (void)
 	check_ip_route (s_ip4, 7, "1.1.1.7", 17, NULL, -1);
 	check_ip_route (s_ip4, 8, "1.1.1.8", 18, NULL, -1);
 	check_ip_route (s_ip4, 9, "1.1.1.9", 19, NULL, 0);
-	check_ip_route (s_ip4, 10, "1.1.1.10", 21, NULL, 0);
-	check_ip_route (s_ip4, 11, "1.1.1.10", 20, NULL, 0);
-	check_ip_route (s_ip4, 12, "1.1.1.11", 21, NULL, 21);
+	check_ip_route (s_ip4, 10, "1.1.1.10", 20, NULL, 0);
+	check_ip_route (s_ip4, 11, "1.1.1.11", 21, NULL, 21);
 
 	/* Route attributes */
-	route = nm_setting_ip_config_get_route (s_ip4, 12);
+	route = nm_setting_ip_config_get_route (s_ip4, 11);
 	g_assert (route);
 
 	nmtst_assert_route_attribute_uint32  (route, NM_IP_ROUTE_ATTRIBUTE_CWND, 10);
@@ -641,9 +649,12 @@ test_read_wired_mac_case (void)
 	char expected_mac_address[ETH_ALEN] = { 0x00, 0x11, 0xaa, 0xbb, 0xcc, 0x55 };
 	gboolean success;
 
-	NMTST_EXPECT_NM_INFO ("*ipv4.addresses*semicolon at the end*addresses1*");
-	NMTST_EXPECT_NM_INFO ("*ipv4.addresses*semicolon at the end*addresses2*");
-	NMTST_EXPECT_NM_INFO ("*ipv6.routes*semicolon at the end*routes1*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
+	                       "*ipv4.addresses*semicolon at the end*addresses1*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
+	                       "*ipv4.addresses*semicolon at the end*addresses2*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_INFO,
+	                       "*ipv6.routes*semicolon at the end*routes1*");
 	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection_MAC_Case", NULL);
 	g_test_assert_expected_messages ();
 	g_assert (connection);
@@ -1404,8 +1415,10 @@ test_read_wired_8021x_tls_blob_connection (void)
 	gboolean success;
 	GBytes *blob;
 
-	NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.client-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
-	NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.private-key: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*<warn> * keyfile: 802-1x.client-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*<warn> * keyfile: 802-1x.private-key: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
 	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Blob", &error);
 	g_assert_no_error (error);
 	g_assert (connection);
@@ -1434,7 +1447,8 @@ test_read_wired_8021x_tls_blob_connection (void)
 	g_assert_cmpint (nm_setting_802_1x_get_ca_cert_scheme (s_8021x), ==, NM_SETTING_802_1X_CK_SCHEME_BLOB);
 
 	/* Make sure it's not a path, since it's a blob */
-	NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH));
+	g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL,
+	                       NMTST_G_RETURN_MSG (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH));
 	tmp = nm_setting_802_1x_get_ca_cert_path (s_8021x);
 	g_test_assert_expected_messages ();
 	g_assert (tmp == NULL);
@@ -1462,7 +1476,8 @@ test_read_wired_8021x_tls_bad_path_connection (void)
 	char *tmp2;
 	gboolean success;
 
-	NMTST_EXPECT_NM_WARN ("*does not exist*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*does not exist*");
 	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Path_Missing", &error);
 	g_test_assert_expected_messages ();
 	g_assert_no_error (error);
@@ -1515,9 +1530,12 @@ test_read_wired_8021x_tls_old_connection (void)
 	const char *tmp;
 	gboolean success;
 
-	NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.ca-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/CA/eaptest_ca_cert.pem' does not exist*");
-	NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.client-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
-	NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.private-key: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*<warn> * keyfile: 802-1x.ca-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/CA/eaptest_ca_cert.pem' does not exist*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*<warn> * keyfile: 802-1x.client-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
+	g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
+	                       "*<warn> * keyfile: 802-1x.private-key: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*");
 	connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Old", &error);
 	g_assert_no_error (error);
 	g_assert (connection);
diff --git a/src/settings/plugins/meson.build b/src/settings/plugins/meson.build
deleted file mode 100644
index a1aa7823..00000000
--- a/src/settings/plugins/meson.build
+++ /dev/null
@@ -1,15 +0,0 @@
-if enable_ibft
-  subdir('ibft')
-endif
-
-if enable_ifcfg_rh
-  subdir('ifcfg-rh')
-endif
-
-if enable_ifupdown
-  subdir('ifupdown')
-endif
-
-if enable_tests
-  subdir('keyfile/tests')
-endif